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