[project @ 1996-07-25 20:43:49 by partain]
[ghc-hetmet.git] / ghc / lib / cbits / openFile.lc
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1994
3 %
4 \subsection[openFile.lc]{openFile Runtime Support}
5
6 \begin{code}
7
8 #include "rtsdefs.h"
9 #include "stgio.h"
10
11 #ifdef HAVE_SYS_TYPES_H
12 #include <sys/types.h>
13 #endif
14
15 #ifdef HAVE_SYS_STAT_H
16 #include <sys/stat.h>
17 #endif
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #ifdef HAVE_FCNTL_H
24 #include <fcntl.h>
25 #endif
26
27 StgAddr
28 openFile(file, how)
29 StgByteArray file;
30 StgByteArray how;
31 {
32     FILE *fp;
33     int fd;
34     int oflags;
35     int exclusive;
36     int created = 0;
37     struct stat sb;
38
39     /*
40      * Since we aren't supposed to succeed when we're opening for writing and
41      * there's another writer, we can't just do an fopen() for "w" mode.
42      */
43
44     switch (how[0]) {
45     case 'a':
46         oflags = O_WRONLY | O_NOCTTY | O_APPEND;
47         exclusive = 1;
48         break;
49     case 'w':
50         oflags = O_WRONLY | O_NOCTTY;
51         exclusive = 1;
52         break;
53     case 'r':
54         oflags = how[1] == '+' ? O_RDWR | O_NOCTTY : O_RDONLY | O_NOCTTY;
55         exclusive = 0;
56         break;
57     default:
58         fprintf(stderr, "openFile: unknown mode `%s'\n", how);
59         EXIT(EXIT_FAILURE);
60     }
61
62     /* First try to open without creating */
63     while ((fd = open(file, oflags, 0666)) < 0) {
64         if (errno == ENOENT) {
65             if (how[0] == 'r' && how[1] == '\0') {
66                 /* For ReadMode, just bail out now */
67                 ghc_errtype = ERR_NOSUCHTHING;
68                 ghc_errstr = "file does not exist";
69                 return NULL;
70             }
71             /* Now try to create it */
72             while ((fd = open(file, oflags | O_CREAT | O_EXCL, 0666)) < 0) {
73                 if (errno == EEXIST) {
74                     /* Race detected; go back and open without creating it */
75                     break;
76                 } else if (errno != EINTR) {
77                     cvtErrno();
78                     switch (ghc_errno) {
79                     default:
80                         stdErrno();
81                         break;
82                     case GHC_ENOENT:
83                     case GHC_ENOTDIR:
84                         ghc_errtype = ERR_NOSUCHTHING;
85                         ghc_errstr = "no path to file";
86                         break;
87                     case GHC_EINVAL:
88                         ghc_errtype = ERR_PERMISSIONDENIED;
89                         ghc_errstr = "unsupported owner or group";
90                         break;
91                     }
92                     return NULL;
93                 }
94             }
95             if (fd >= 0) {
96                 created = 1;
97                 break;
98             }
99         } else if (errno != EINTR) {
100             cvtErrno();
101             switch (ghc_errno) {
102             default:
103                 stdErrno();
104                 break;
105             case GHC_ENOTDIR:
106                 ghc_errtype = ERR_NOSUCHTHING;
107                 ghc_errstr = "no path to file";
108                 break;
109             case GHC_EINVAL:
110                 ghc_errtype = ERR_PERMISSIONDENIED;
111                 ghc_errstr = "unsupported owner or group";
112                 break;
113             }
114             return NULL;
115         }
116     }
117
118     /* Make sure that we aren't looking at a directory */
119
120     while (fstat(fd, &sb) < 0) {
121         /* highly unlikely */
122         if (errno != EINTR) {
123             cvtErrno();
124             if (created)
125                 (void) unlink(file);
126             (void) close(fd);
127             return NULL;
128         }
129     }
130     if (S_ISDIR(sb.st_mode)) {
131         ghc_errtype = ERR_INAPPROPRIATETYPE;
132         ghc_errstr = "file is a directory";
133         /* We can't have created it in this case. */
134         (void) close(fd);
135
136         return NULL;
137     }
138     /* Use our own personal locking */
139
140     if (lockFile(fd, exclusive) < 0) {
141         cvtErrno();
142         switch (ghc_errno) {
143         default:
144             stdErrno();
145             break;
146         case GHC_EACCES:
147         case GHC_EAGAIN:
148             ghc_errtype = ERR_RESOURCEBUSY;
149             ghc_errstr = "file is locked";
150             break;
151         }
152         if (created)
153             (void) unlink(file);
154         (void) close(fd);
155         return NULL;
156     }
157
158     /*
159      * Write mode is supposed to truncate the file.  Unfortunately, our pal
160      * ftruncate() is non-POSIX, so we truncate with a second open, which may fail.
161      */
162
163     if (how[0] == 'w') {
164         int fd2;
165
166         oflags |= O_TRUNC;
167         while ((fd2 = open(file, oflags, 0666)) < 0) {
168             if (errno != EINTR) {
169                 cvtErrno();
170                 if (created)
171                     (void) unlink(file);
172                 (void) close(fd);
173                 switch (ghc_errno) {
174                 default:
175                     stdErrno();
176                     break;
177                 case GHC_EAGAIN:
178                     ghc_errtype = ERR_RESOURCEBUSY;
179                     ghc_errstr = "enforced lock prevents truncation";
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         close(fd2);
194     }
195     errno = 0;                  /* Just in case fdopen() is lame */
196     while ((fp = fdopen(fd, how)) == NULL) {
197         if (errno != EINTR) {
198             cvtErrno();
199             if (created)
200                 (void) unlink(file);
201             (void) close(fd);
202             return NULL;
203         }
204     }
205
206     return (StgAddr) fp;
207 }
208
209 \end{code}