[project @ 1998-11-26 09:17:22 by sof]
[ghc-hetmet.git] / ghc / lib / std / cbits / openFile.lc
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1994
3 %
4 \subsection[openFile.lc]{openFile Runtime Support}
5
6 \begin{code}
7
8 #include "rtsdefs.h"
9 #include "stgio.h"
10 #include "fileObject.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 IOFileObject*
29 openStdFile(fd,flags,rd)
30 StgInt fd;
31 StgInt flags;
32 StgInt rd;
33 {
34     IOFileObject* fo;
35
36     if ((fo = malloc(sizeof(IOFileObject))) == NULL)
37        return NULL;
38     fo->fd       = fd;
39     fo->buf      = NULL;
40     fo->bufWPtr  = 0;
41     fo->bufRPtr  = 0;
42     fo->flags   = flags | FILEOBJ_STD | ( rd ? FILEOBJ_READ : FILEOBJ_WRITE);
43     fo->connectedTo = NULL;
44     return fo;
45 }
46
47 #define OPENFILE_APPEND 0
48 #define OPENFILE_WRITE 1
49 #define OPENFILE_READ_ONLY 2
50 #define OPENFILE_READ_WRITE 3
51
52 IOFileObject*
53 openFile(file, how, binary, flags)
54 StgByteArray file;
55 StgInt how;
56 StgInt binary;
57 StgInt flags;
58 {
59     FILE *fp;
60     int fd;
61     int oflags;
62     int exclusive;
63     int created = 0;
64     struct stat sb;
65     IOFileObject* fo;
66
67     /*
68      * Since we aren't supposed to succeed when we're opening for writing and
69      * there's another writer, we can't just do an open() with O_WRONLY.
70      */
71
72     switch (how) {
73       case OPENFILE_APPEND:
74         oflags = O_WRONLY | O_NOCTTY | O_APPEND; 
75         exclusive = 1;
76         break;
77       case OPENFILE_WRITE:
78         oflags = O_WRONLY | O_NOCTTY;
79         exclusive = 1;
80         break;
81     case OPENFILE_READ_ONLY:
82         oflags = O_RDONLY | O_NOCTTY;
83         exclusive = 0;
84         break;
85     case OPENFILE_READ_WRITE:
86         oflags = O_RDWR | O_NOCTTY;
87         exclusive = 0;
88         break;
89     default:
90         fprintf(stderr, "openFile: unknown mode `%d'\n", how);
91         EXIT(EXIT_FAILURE);
92     }
93
94 #if HAVE_O_BINARY
95     if (binary) 
96       oflags |= O_BINARY;
97 #endif
98
99     /* First try to open without creating */
100     while ((fd = open(file, oflags, 0666)) < 0) {
101         if (errno == ENOENT) {
102             if ( how == OPENFILE_READ_ONLY ) {
103                 /* For ReadMode, just bail out now */
104                 ghc_errtype = ERR_NOSUCHTHING;
105                 ghc_errstr = "file does not exist";
106                 return NULL;
107             } else {
108                 /* If it is a dangling symlink, break off now, too. */
109                 struct stat st;
110                 if ( lstat(file,&st) == 0) {
111                    ghc_errtype = ERR_NOSUCHTHING;
112                    ghc_errstr = "dangling symlink";
113                    return NULL;
114                 }
115             }
116             /* Now try to create it */
117             while ((fd = open(file, oflags | O_CREAT | O_EXCL, 0666)) < 0) {
118                 if (errno == EEXIST) {
119                     /* Race detected; go back and open without creating it */
120                     break;
121                 } else if (errno != EINTR) {
122                     cvtErrno();
123                     switch (ghc_errno) {
124                     default:
125                         stdErrno();
126                         break;
127                     case GHC_ENOENT:
128                     case GHC_ENOTDIR:
129                         ghc_errtype = ERR_NOSUCHTHING;
130                         ghc_errstr = "no path to file";
131                         break;
132                     case GHC_EINVAL:
133                         ghc_errtype = ERR_PERMISSIONDENIED;
134                         ghc_errstr = "unsupported owner or group";
135                         break;
136                     }
137                     return NULL;
138                 }
139             }
140             if (fd >= 0) {
141                 created = 1;
142                 break;
143             }
144         } else if (errno != EINTR) {
145             cvtErrno();
146             switch (ghc_errno) {
147             default:
148                 stdErrno();
149                 break;
150             case GHC_ENOTDIR:
151                 ghc_errtype = ERR_NOSUCHTHING;
152                 ghc_errstr = "no path to file";
153                 break;
154             case GHC_EINVAL:
155                 ghc_errtype = ERR_PERMISSIONDENIED;
156                 ghc_errstr = "unsupported owner or group";
157                 break;
158             }
159             return NULL;
160         }
161     }
162
163     /* Make sure that we aren't looking at a directory */
164
165     while (fstat(fd, &sb) < 0) {
166         /* highly unlikely */
167         if (errno != EINTR) {
168             cvtErrno();
169             if (created)
170                 (void) unlink(file);
171             (void) close(fd);
172             return NULL;
173         }
174     }
175     if (S_ISDIR(sb.st_mode)) {
176         ghc_errtype = ERR_INAPPROPRIATETYPE;
177         ghc_errstr = "file is a directory";
178         /* We can't have created it in this case. */
179         (void) close(fd);
180
181         return NULL;
182     }
183     /* Use our own personal locking */
184
185     if (lockFile(fd, exclusive) < 0) {
186         cvtErrno();
187         switch (ghc_errno) {
188         default:
189             stdErrno();
190             break;
191         case GHC_EACCES:
192         case GHC_EAGAIN:
193             ghc_errtype = ERR_RESOURCEBUSY;
194             ghc_errstr = "file is locked";
195             break;
196         }
197         if (created)
198             (void) unlink(file);
199         (void) close(fd);
200         return NULL;
201     }
202
203     /*
204      * Write mode is supposed to truncate the file.  Unfortunately, our pal
205      * ftruncate() is non-POSIX, so we truncate with a second open, which may fail.
206      */
207
208     if ( how == OPENFILE_WRITE ) {
209         int fd2, oflags2;
210
211         oflags2 = oflags | O_TRUNC;
212         while ((fd2 = open(file, oflags2, 0666)) < 0) {
213             if (errno != EINTR) {
214                 cvtErrno();
215                 if (created)
216                     (void) unlink(file);
217                 (void) close(fd);
218                 switch (ghc_errno) {
219                 default:
220                     stdErrno();
221                     break;
222                 case GHC_EAGAIN:
223                     ghc_errtype = ERR_RESOURCEBUSY;
224                     ghc_errstr = "enforced lock prevents truncation";
225                     break;
226                 case GHC_ENOTDIR:
227                     ghc_errtype = ERR_NOSUCHTHING;
228                     ghc_errstr = "no path to file";
229                     break;
230                 case GHC_EINVAL:
231                     ghc_errtype = ERR_PERMISSIONDENIED;
232                     ghc_errstr = "unsupported owner or group";
233                     break;
234                 }
235                 return NULL;
236             }
237         }
238         close(fd2);
239     }
240
241     /* Allocate a IOFileObject to hold the information
242        we need to record per-handle for the various C stubs.
243        This chunk of memory is wrapped up inside a foreign object,
244        so it will be finalised and freed properly when we're
245        through with the handle.
246     */
247     if ((fo = malloc(sizeof(IOFileObject))) == NULL)
248        return NULL;
249
250     fo->fd       = fd;
251     fo->buf      = NULL;
252     fo->bufWPtr  = 0;
253     fo->bufRPtr  = 0;
254     fo->flags   = flags | ( (how == OPENFILE_READ_ONLY || how == OPENFILE_READ_WRITE) ? FILEOBJ_READ  : 0)
255                         | ( (how == OPENFILE_APPEND    || how == OPENFILE_READ_WRITE) ? FILEOBJ_WRITE : 0);
256     fo->connectedTo = NULL;
257     return fo;
258 }
259
260 /* `Lock' file descriptor and return file object. */
261 IOFileObject*
262 openFd(fd,oflags,flags)
263 StgInt fd;
264 StgInt oflags;
265 StgInt flags;
266 {
267     int exclusive;
268     FILE* fp;
269     IOFileObject* fo;
270
271     if (lockFile(fd, exclusive) < 0) {
272         cvtErrno();
273         switch (ghc_errno) {
274         default:
275             stdErrno();
276             break;
277         case GHC_EACCES:
278         case GHC_EAGAIN:
279             ghc_errtype = ERR_RESOURCEBUSY;
280             ghc_errstr = "file is locked";
281             break;
282         }
283         return NULL;
284     }
285
286     /* See openFileObject() comment */
287     if ((fo = malloc(sizeof(IOFileObject))) == NULL)
288        return NULL;
289     fo->fd      = fd;
290     fo->buf     = NULL;
291     fo->bufWPtr = 0;
292     fo->bufRPtr = 0;
293     fo->flags   = flags | ( oflags & O_RDONLY ? FILEOBJ_READ 
294                           : oflags & O_RDWR   ? FILEOBJ_READ 
295                           : 0)
296                         | ( oflags & O_WRONLY ? FILEOBJ_WRITE
297                           : oflags & O_RDWR   ? FILEOBJ_WRITE 
298                           : 0);
299     fo->connectedTo = NULL;
300     return fo;
301 }
302 \end{code}