diff options
author | simonm <unknown> | 1998-04-10 10:55:01 +0000 |
---|---|---|
committer | simonm <unknown> | 1998-04-10 10:55:01 +0000 |
commit | 3f9b5688990aa7c1170c8d995df69087b43dabeb (patch) | |
tree | 98ea8a0869cdea0562c94cfb68398ce451046176 /ghc/lib/std/cbits/openFile.c | |
parent | 1be6e009f6493080ea5d26cdc611279244163db1 (diff) | |
download | haskell-3f9b5688990aa7c1170c8d995df69087b43dabeb.tar.gz |
[project @ 1998-04-10 10:54:14 by simonm]
New Run-Time System Support, includes:
- New code generator
- Modifications to the mangler
- Unboxed Tuple support
- Various other minor changes.
Diffstat (limited to 'ghc/lib/std/cbits/openFile.c')
-rw-r--r-- | ghc/lib/std/cbits/openFile.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/ghc/lib/std/cbits/openFile.c b/ghc/lib/std/cbits/openFile.c new file mode 100644 index 0000000000..d203bbb1ff --- /dev/null +++ b/ghc/lib/std/cbits/openFile.c @@ -0,0 +1,214 @@ +/* + * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998 + * + * $Id: openFile.c,v 1.1 1998/04/10 10:54:42 simonm Exp $ + * + * openFile Runtime Support + */ + +#include "Rts.h" +#include "stgio.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +StgAddr +openFile(StgByteArray file, StgByteArray how) +{ + FILE *fp; + int fd; + int oflags; + int exclusive; + int created = 0; + struct stat sb; + + /* + * Since we aren't supposed to succeed when we're opening for writing and + * there's another writer, we can't just do an fopen() for "w" mode. + */ + + switch (how[0]) { + case 'a': + oflags = O_WRONLY | O_NOCTTY | O_APPEND; + exclusive = 1; + break; + case 'w': + oflags = O_WRONLY | O_NOCTTY; + exclusive = 1; + break; + case 'r': + oflags = how[1] == '+' ? O_RDWR | O_NOCTTY : O_RDONLY | O_NOCTTY; + exclusive = 0; + break; + default: + fprintf(stderr, "openFile: unknown mode `%s'\n", how); + exit(EXIT_FAILURE); + } + + /* First try to open without creating */ + while ((fd = open(file, oflags, 0666)) < 0) { + if (errno == ENOENT) { + if (how[0] == 'r' && how[1] == '\0') { + /* For ReadMode, just bail out now */ + ghc_errtype = ERR_NOSUCHTHING; + ghc_errstr = "file does not exist"; + return NULL; + } else { + /* If it is a dangling symlink, break off now, too. */ + struct stat st; + if ( lstat(file,&st) == 0) { + ghc_errtype = ERR_NOSUCHTHING; + ghc_errstr = "dangling symlink"; + return NULL; + } + } + /* Now try to create it */ + while ((fd = open(file, oflags | O_CREAT | O_EXCL, 0666)) < 0) { + if (errno == EEXIST) { + /* Race detected; go back and open without creating it */ + break; + } else if (errno != EINTR) { + cvtErrno(); + switch (ghc_errno) { + default: + stdErrno(); + break; + case GHC_ENOENT: + case GHC_ENOTDIR: + ghc_errtype = ERR_NOSUCHTHING; + ghc_errstr = "no path to file"; + break; + case GHC_EINVAL: + ghc_errtype = ERR_PERMISSIONDENIED; + ghc_errstr = "unsupported owner or group"; + break; + } + return NULL; + } + } + if (fd >= 0) { + created = 1; + break; + } + } else if (errno != EINTR) { + cvtErrno(); + switch (ghc_errno) { + default: + stdErrno(); + break; + case GHC_ENOTDIR: + ghc_errtype = ERR_NOSUCHTHING; + ghc_errstr = "no path to file"; + break; + case GHC_EINVAL: + ghc_errtype = ERR_PERMISSIONDENIED; + ghc_errstr = "unsupported owner or group"; + break; + } + return NULL; + } + } + + /* Make sure that we aren't looking at a directory */ + + while (fstat(fd, &sb) < 0) { + /* highly unlikely */ + if (errno != EINTR) { + cvtErrno(); + if (created) + (void) unlink(file); + (void) close(fd); + return NULL; + } + } + if (S_ISDIR(sb.st_mode)) { + ghc_errtype = ERR_INAPPROPRIATETYPE; + ghc_errstr = "file is a directory"; + /* We can't have created it in this case. */ + (void) close(fd); + + return NULL; + } + /* Use our own personal locking */ + + if (lockFile(fd, exclusive) < 0) { + cvtErrno(); + switch (ghc_errno) { + default: + stdErrno(); + break; + case GHC_EACCES: + case GHC_EAGAIN: + ghc_errtype = ERR_RESOURCEBUSY; + ghc_errstr = "file is locked"; + break; + } + if (created) + (void) unlink(file); + (void) close(fd); + return NULL; + } + + /* + * Write mode is supposed to truncate the file. Unfortunately, our pal + * ftruncate() is non-POSIX, so we truncate with a second open, which may fail. + */ + + if (how[0] == 'w') { + int fd2; + + oflags |= O_TRUNC; + while ((fd2 = open(file, oflags, 0666)) < 0) { + if (errno != EINTR) { + cvtErrno(); + if (created) + (void) unlink(file); + (void) close(fd); + switch (ghc_errno) { + default: + stdErrno(); + break; + case GHC_EAGAIN: + ghc_errtype = ERR_RESOURCEBUSY; + ghc_errstr = "enforced lock prevents truncation"; + break; + case GHC_ENOTDIR: + ghc_errtype = ERR_NOSUCHTHING; + ghc_errstr = "no path to file"; + break; + case GHC_EINVAL: + ghc_errtype = ERR_PERMISSIONDENIED; + ghc_errstr = "unsupported owner or group"; + break; + } + return NULL; + } + } + close(fd2); + } + errno = 0; /* Just in case fdopen() is lame */ + while ((fp = fdopen(fd, how)) == NULL) { + if (errno != EINTR) { + cvtErrno(); + if (created) + (void) unlink(file); + (void) close(fd); + return NULL; + } + } + + return (StgAddr) fp; +} |