2 * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
4 * $Id: openFile.c,v 1.6 1999/02/04 12:13:15 sof Exp $
6 * openFile Runtime Support
9 /* We use lstat, which is sadly not POSIX */
10 #define NON_POSIX_SOURCE
14 #include "fileObject.h"
16 #ifdef HAVE_SYS_TYPES_H
17 #include <sys/types.h>
20 #ifdef HAVE_SYS_STAT_H
32 #ifdef mingw32_TARGET_OS
37 openStdFile(fd,flags,rd)
44 if ((fo = malloc(sizeof(IOFileObject))) == NULL)
50 fo->flags = flags | FILEOBJ_STD | ( rd ? FILEOBJ_READ : FILEOBJ_WRITE);
51 fo->connectedTo = NULL;
55 #define OPENFILE_APPEND 0
56 #define OPENFILE_WRITE 1
57 #define OPENFILE_READ_ONLY 2
58 #define OPENFILE_READ_WRITE 3
61 openFile(file, how, binary, flags)
76 * Since we aren't supposed to succeed when we're opening for writing and
77 * there's another writer, we can't just do an open() with O_WRONLY.
82 oflags = O_WRONLY | O_NOCTTY | O_APPEND;
86 oflags = O_WRONLY | O_NOCTTY;
89 case OPENFILE_READ_ONLY:
90 oflags = O_RDONLY | O_NOCTTY;
93 case OPENFILE_READ_WRITE:
94 oflags = O_RDWR | O_NOCTTY;
98 fprintf(stderr, "openFile: unknown mode `%d'\n", how);
107 /* First try to open without creating */
108 while ((fd = open(file, oflags, 0666)) < 0) {
109 if (errno == ENOENT) {
110 if ( how == OPENFILE_READ_ONLY ) {
111 /* For ReadMode, just bail out now */
112 ghc_errtype = ERR_NOSUCHTHING;
113 ghc_errstr = "file does not exist";
116 /* If it is a dangling symlink, break off now, too. */
117 #ifndef mingw32_TARGET_OS
119 if ( lstat(file,&st) == 0) {
120 ghc_errtype = ERR_NOSUCHTHING;
121 ghc_errstr = "dangling symlink";
126 /* Now try to create it */
127 while ((fd = open(file, oflags | O_CREAT | O_EXCL, 0666)) < 0) {
128 if (errno == EEXIST) {
129 /* Race detected; go back and open without creating it */
131 } else if (errno != EINTR) {
139 ghc_errtype = ERR_NOSUCHTHING;
140 ghc_errstr = "no path to file";
143 ghc_errtype = ERR_PERMISSIONDENIED;
144 ghc_errstr = "unsupported owner or group";
154 } else if (errno != EINTR) {
161 ghc_errtype = ERR_NOSUCHTHING;
162 ghc_errstr = "no path to file";
165 ghc_errtype = ERR_PERMISSIONDENIED;
166 ghc_errstr = "unsupported owner or group";
173 /* Make sure that we aren't looking at a directory */
175 while (fstat(fd, &sb) < 0) {
176 /* highly unlikely */
177 if (errno != EINTR) {
185 if (S_ISDIR(sb.st_mode)) {
186 ghc_errtype = ERR_INAPPROPRIATETYPE;
187 ghc_errstr = "file is a directory";
188 /* We can't have created it in this case. */
193 /* Use our own personal locking */
195 if (lockFile(fd, for_writing, 1/*enforce single-writer, if needs be.*/) < 0) {
203 ghc_errtype = ERR_RESOURCEBUSY;
204 ghc_errstr = "file is locked";
214 * Write mode is supposed to truncate the file. Unfortunately, our pal
215 * ftruncate() is non-POSIX, so we truncate with a second open, which may fail.
218 if ( how == OPENFILE_WRITE ) {
221 oflags2 = oflags | O_TRUNC;
222 while ((fd2 = open(file, oflags2, 0666)) < 0) {
223 if (errno != EINTR) {
233 ghc_errtype = ERR_RESOURCEBUSY;
234 ghc_errstr = "enforced lock prevents truncation";
237 ghc_errtype = ERR_NOSUCHTHING;
238 ghc_errstr = "no path to file";
241 ghc_errtype = ERR_PERMISSIONDENIED;
242 ghc_errstr = "unsupported owner or group";
251 /* Allocate a IOFileObject to hold the information
252 we need to record per-handle for the various C stubs.
253 This chunk of memory is wrapped up inside a foreign object,
254 so it will be finalised and freed properly when we're
255 through with the handle.
257 if ((fo = malloc(sizeof(IOFileObject))) == NULL)
264 fo->flags = flags | ( (how == OPENFILE_READ_ONLY || how == OPENFILE_READ_WRITE) ? FILEOBJ_READ : 0)
265 | ( (how == OPENFILE_APPEND || how == OPENFILE_READ_WRITE) ? FILEOBJ_WRITE : 0);
266 fo->connectedTo = NULL;
270 /* `Lock' file descriptor and return file object. */
272 openFd(fd,oflags,flags)
281 for_writing = ( ((oflags & O_WRONLY) || (oflags & O_RDWR)) ? 1 : 0);
283 if (lockFile(fd, for_writing, 1/* enforce single-writer */ ) < 0) {
291 ghc_errtype = ERR_RESOURCEBUSY;
292 ghc_errstr = "file is locked";
298 /* See openFileObject() comment */
299 if ((fo = malloc(sizeof(IOFileObject))) == NULL)
305 fo->flags = flags | ( oflags & O_RDONLY ? FILEOBJ_READ
306 : oflags & O_RDWR ? FILEOBJ_READ
308 | ( oflags & O_WRONLY ? FILEOBJ_WRITE
309 : oflags & O_RDWR ? FILEOBJ_WRITE
311 fo->connectedTo = NULL;