4b92aca8b5883e134262fac56a2f8c8122bb08b7
[ghc-hetmet.git] / ghc / lib / std / 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             } else {
71                 /* If it is a dangling symlink, break off now, too. */
72                 struct stat st;
73                 if ( lstat(file,&st) == 0) {
74                    ghc_errtype = ERR_NOSUCHTHING;
75                    ghc_errstr = "dangling symlink";
76                    return NULL;
77                 }
78             }
79             /* Now try to create it */
80             while ((fd = open(file, oflags | O_CREAT | O_EXCL, 0666)) < 0) {
81                 if (errno == EEXIST) {
82                     /* Race detected; go back and open without creating it */
83                     break;
84                 } else if (errno != EINTR) {
85                     cvtErrno();
86                     switch (ghc_errno) {
87                     default:
88                         stdErrno();
89                         break;
90                     case GHC_ENOENT:
91                     case GHC_ENOTDIR:
92                         ghc_errtype = ERR_NOSUCHTHING;
93                         ghc_errstr = "no path to file";
94                         break;
95                     case GHC_EINVAL:
96                         ghc_errtype = ERR_PERMISSIONDENIED;
97                         ghc_errstr = "unsupported owner or group";
98                         break;
99                     }
100                     return NULL;
101                 }
102             }
103             if (fd >= 0) {
104                 created = 1;
105                 break;
106             }
107         } else if (errno != EINTR) {
108             cvtErrno();
109             switch (ghc_errno) {
110             default:
111                 stdErrno();
112                 break;
113             case GHC_ENOTDIR:
114                 ghc_errtype = ERR_NOSUCHTHING;
115                 ghc_errstr = "no path to file";
116                 break;
117             case GHC_EINVAL:
118                 ghc_errtype = ERR_PERMISSIONDENIED;
119                 ghc_errstr = "unsupported owner or group";
120                 break;
121             }
122             return NULL;
123         }
124     }
125
126     /* Make sure that we aren't looking at a directory */
127
128     while (fstat(fd, &sb) < 0) {
129         /* highly unlikely */
130         if (errno != EINTR) {
131             cvtErrno();
132             if (created)
133                 (void) unlink(file);
134             (void) close(fd);
135             return NULL;
136         }
137     }
138     if (S_ISDIR(sb.st_mode)) {
139         ghc_errtype = ERR_INAPPROPRIATETYPE;
140         ghc_errstr = "file is a directory";
141         /* We can't have created it in this case. */
142         (void) close(fd);
143
144         return NULL;
145     }
146     /* Use our own personal locking */
147
148     if (lockFile(fd, exclusive) < 0) {
149         cvtErrno();
150         switch (ghc_errno) {
151         default:
152             stdErrno();
153             break;
154         case GHC_EACCES:
155         case GHC_EAGAIN:
156             ghc_errtype = ERR_RESOURCEBUSY;
157             ghc_errstr = "file is locked";
158             break;
159         }
160         if (created)
161             (void) unlink(file);
162         (void) close(fd);
163         return NULL;
164     }
165
166     /*
167      * Write mode is supposed to truncate the file.  Unfortunately, our pal
168      * ftruncate() is non-POSIX, so we truncate with a second open, which may fail.
169      */
170
171     if (how[0] == 'w') {
172         int fd2;
173
174         oflags |= O_TRUNC;
175         while ((fd2 = open(file, oflags, 0666)) < 0) {
176             if (errno != EINTR) {
177                 cvtErrno();
178                 if (created)
179                     (void) unlink(file);
180                 (void) close(fd);
181                 switch (ghc_errno) {
182                 default:
183                     stdErrno();
184                     break;
185                 case GHC_EAGAIN:
186                     ghc_errtype = ERR_RESOURCEBUSY;
187                     ghc_errstr = "enforced lock prevents truncation";
188                     break;
189                 case GHC_ENOTDIR:
190                     ghc_errtype = ERR_NOSUCHTHING;
191                     ghc_errstr = "no path to file";
192                     break;
193                 case GHC_EINVAL:
194                     ghc_errtype = ERR_PERMISSIONDENIED;
195                     ghc_errstr = "unsupported owner or group";
196                     break;
197                 }
198                 return NULL;
199             }
200         }
201         close(fd2);
202     }
203     errno = 0;                  /* Just in case fdopen() is lame */
204     while ((fp = fdopen(fd, how)) == NULL) {
205         if (errno != EINTR) {
206             cvtErrno();
207             if (created)
208                 (void) unlink(file);
209             (void) close(fd);
210             return NULL;
211         }
212     }
213
214     return (StgAddr) fp;
215 }
216
217 \end{code}