ash: [REDIR] Replace GPL noclobberopen code with the FreeBSD version
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 25 Jul 2017 15:47:48 +0000 (17:47 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 25 Jul 2017 15:47:48 +0000 (17:47 +0200)
Upstream commit:

    Date: Thu, 10 Mar 2011 16:52:13 +0800
    [REDIR] Replace GPL noclobberopen code with the FreeBSD version

    Replace noclobberopen() from bash with the FreeBSD code for noclobber
    opens.

    This also reduces code size by eliminating an unnecessary check.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
function                                             old     new   delta
changepath                                           192     194      +2
localcmd                                             366     364      -2
expmeta                                              521     517      -4
redirect                                            1210    1135     -75
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/3 up/down: 2/-81)             Total: -79 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c

index c353834a4a1859b5338262c8dbf6fdb0000d5556..b4b0d525374b308bd8cad75b6e463b60c0f8490c 100644 (file)
@@ -5174,68 +5174,6 @@ stoppedjobs(void)
 #define EMPTY -2                /* marks an unused slot in redirtab */
 #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
@@ -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 */