[project @ 1998-04-10 11:04:49 by simonm]
[ghc-hetmet.git] / ghc / lib / std / cbits / openFile.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: openFile.c,v 1.1 1998/04/10 10:54:42 simonm Exp $
5  *
6  * openFile Runtime Support
7  */
8
9 #include "Rts.h"
10 #include "stgio.h"
11
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15
16 #ifdef HAVE_SYS_STAT_H
17 #include <sys/stat.h>
18 #endif
19
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
23
24 #ifdef HAVE_FCNTL_H
25 #include <fcntl.h>
26 #endif
27
28 StgAddr
29 openFile(StgByteArray file, StgByteArray how)
30 {
31     FILE *fp;
32     int fd;
33     int oflags;
34     int exclusive;
35     int created = 0;
36     struct stat sb;
37
38     /*
39      * Since we aren't supposed to succeed when we're opening for writing and
40      * there's another writer, we can't just do an fopen() for "w" mode.
41      */
42
43     switch (how[0]) {
44     case 'a':
45         oflags = O_WRONLY | O_NOCTTY | O_APPEND;
46         exclusive = 1;
47         break;
48     case 'w':
49         oflags = O_WRONLY | O_NOCTTY;
50         exclusive = 1;
51         break;
52     case 'r':
53         oflags = how[1] == '+' ? O_RDWR | O_NOCTTY : O_RDONLY | O_NOCTTY;
54         exclusive = 0;
55         break;
56     default:
57         fprintf(stderr, "openFile: unknown mode `%s'\n", how);
58         exit(EXIT_FAILURE);
59     }
60
61     /* First try to open without creating */
62     while ((fd = open(file, oflags, 0666)) < 0) {
63         if (errno == ENOENT) {
64             if (how[0] == 'r' && how[1] == '\0') {
65                 /* For ReadMode, just bail out now */
66                 ghc_errtype = ERR_NOSUCHTHING;
67                 ghc_errstr = "file does not exist";
68                 return NULL;
69             } else {
70                 /* If it is a dangling symlink, break off now, too. */
71                 struct stat st;
72                 if ( lstat(file,&st) == 0) {
73                    ghc_errtype = ERR_NOSUCHTHING;
74                    ghc_errstr = "dangling symlink";
75                    return NULL;
76                 }
77             }
78             /* Now try to create it */
79             while ((fd = open(file, oflags | O_CREAT | O_EXCL, 0666)) < 0) {
80                 if (errno == EEXIST) {
81                     /* Race detected; go back and open without creating it */
82                     break;
83                 } else if (errno != EINTR) {
84                     cvtErrno();
85                     switch (ghc_errno) {
86                     default:
87                         stdErrno();
88                         break;
89                     case GHC_ENOENT:
90                     case GHC_ENOTDIR:
91                         ghc_errtype = ERR_NOSUCHTHING;
92                         ghc_errstr = "no path to file";
93                         break;
94                     case GHC_EINVAL:
95                         ghc_errtype = ERR_PERMISSIONDENIED;
96                         ghc_errstr = "unsupported owner or group";
97                         break;
98                     }
99                     return NULL;
100                 }
101             }
102             if (fd >= 0) {
103                 created = 1;
104                 break;
105             }
106         } else if (errno != EINTR) {
107             cvtErrno();
108             switch (ghc_errno) {
109             default:
110                 stdErrno();
111                 break;
112             case GHC_ENOTDIR:
113                 ghc_errtype = ERR_NOSUCHTHING;
114                 ghc_errstr = "no path to file";
115                 break;
116             case GHC_EINVAL:
117                 ghc_errtype = ERR_PERMISSIONDENIED;
118                 ghc_errstr = "unsupported owner or group";
119                 break;
120             }
121             return NULL;
122         }
123     }
124
125     /* Make sure that we aren't looking at a directory */
126
127     while (fstat(fd, &sb) < 0) {
128         /* highly unlikely */
129         if (errno != EINTR) {
130             cvtErrno();
131             if (created)
132                 (void) unlink(file);
133             (void) close(fd);
134             return NULL;
135         }
136     }
137     if (S_ISDIR(sb.st_mode)) {
138         ghc_errtype = ERR_INAPPROPRIATETYPE;
139         ghc_errstr = "file is a directory";
140         /* We can't have created it in this case. */
141         (void) close(fd);
142
143         return NULL;
144     }
145     /* Use our own personal locking */
146
147     if (lockFile(fd, exclusive) < 0) {
148         cvtErrno();
149         switch (ghc_errno) {
150         default:
151             stdErrno();
152             break;
153         case GHC_EACCES:
154         case GHC_EAGAIN:
155             ghc_errtype = ERR_RESOURCEBUSY;
156             ghc_errstr = "file is locked";
157             break;
158         }
159         if (created)
160             (void) unlink(file);
161         (void) close(fd);
162         return NULL;
163     }
164
165     /*
166      * Write mode is supposed to truncate the file.  Unfortunately, our pal
167      * ftruncate() is non-POSIX, so we truncate with a second open, which may fail.
168      */
169
170     if (how[0] == 'w') {
171         int fd2;
172
173         oflags |= O_TRUNC;
174         while ((fd2 = open(file, oflags, 0666)) < 0) {
175             if (errno != EINTR) {
176                 cvtErrno();
177                 if (created)
178                     (void) unlink(file);
179                 (void) close(fd);
180                 switch (ghc_errno) {
181                 default:
182                     stdErrno();
183                     break;
184                 case GHC_EAGAIN:
185                     ghc_errtype = ERR_RESOURCEBUSY;
186                     ghc_errstr = "enforced lock prevents truncation";
187                     break;
188                 case GHC_ENOTDIR:
189                     ghc_errtype = ERR_NOSUCHTHING;
190                     ghc_errstr = "no path to file";
191                     break;
192                 case GHC_EINVAL:
193                     ghc_errtype = ERR_PERMISSIONDENIED;
194                     ghc_errstr = "unsupported owner or group";
195                     break;
196                 }
197                 return NULL;
198             }
199         }
200         close(fd2);
201     }
202     errno = 0;                  /* Just in case fdopen() is lame */
203     while ((fp = fdopen(fd, how)) == NULL) {
204         if (errno != EINTR) {
205             cvtErrno();
206             if (created)
207                 (void) unlink(file);
208             (void) close(fd);
209             return NULL;
210         }
211     }
212
213     return (StgAddr) fp;
214 }