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