summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c81
1 files changed, 17 insertions, 64 deletions
diff --git a/shell/ash.c b/shell/ash.c
index c353834..b4b0d52 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5175,68 +5175,6 @@ stoppedjobs(void)
#define CLOSED -3 /* marks a slot of previously-closed fd */
/*
- * Open a file in noclobber mode.
- * The code was copied from bash.
- */
-static int
-noclobberopen(const char *fname)
-{
- int r, fd;
- struct stat finfo, finfo2;
-
- /*
- * If the file exists and is a regular file, return an error
- * immediately.
- */
- r = stat(fname, &finfo);
- if (r == 0 && S_ISREG(finfo.st_mode)) {
- errno = EEXIST;
- return -1;
- }
-
- /*
- * If the file was not present (r != 0), make sure we open it
- * exclusively so that if it is created before we open it, our open
- * will fail. Make sure that we do not truncate an existing file.
- * Note that we don't turn on O_EXCL unless the stat failed -- if the
- * file was not a regular file, we leave O_EXCL off.
- */
- if (r != 0)
- return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
- fd = open(fname, O_WRONLY|O_CREAT, 0666);
-
- /* If the open failed, return the file descriptor right away. */
- if (fd < 0)
- return fd;
-
- /*
- * OK, the open succeeded, but the file may have been changed from a
- * non-regular file to a regular file between the stat and the open.
- * We are assuming that the O_EXCL open handles the case where FILENAME
- * did not exist and is symlinked to an existing file between the stat
- * and open.
- */
-
- /*
- * If we can open it and fstat the file descriptor, and neither check
- * revealed that it was a regular file, and the file has not been
- * replaced, return the file descriptor.
- */
- if (fstat(fd, &finfo2) == 0
- && !S_ISREG(finfo2.st_mode)
- && finfo.st_dev == finfo2.st_dev
- && finfo.st_ino == finfo2.st_ino
- ) {
- return fd;
- }
-
- /* The file has been replaced. badness. */
- close(fd);
- errno = EEXIST;
- return -1;
-}
-
-/*
* Handle here documents. Normally we fork off a process to write the
* data to a pipe. If the document is short, we can stuff the data in
* the pipe without forking.
@@ -5280,6 +5218,7 @@ openhere(union node *redir)
static int
openredirect(union node *redir)
{
+ struct stat sb;
char *fname;
int f;
@@ -5319,9 +5258,23 @@ openredirect(union node *redir)
#endif
/* Take care of noclobber mode. */
if (Cflag) {
- f = noclobberopen(fname);
- if (f < 0)
+ if (stat(fname, &sb) < 0) {
+ f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
+ if (f < 0)
+ goto ecreate;
+ } else if (!S_ISREG(sb.st_mode)) {
+ f = open(fname, O_WRONLY, 0666);
+ if (f < 0)
+ goto ecreate;
+ if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
+ close(f);
+ errno = EEXIST;
+ goto ecreate;
+ }
+ } else {
+ errno = EEXIST;
goto ecreate;
+ }
break;
}
/* FALLTHROUGH */