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