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