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