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