]> err.no Git - moreutils/commitdiff
sponge: Ensure that output file permissions are always preserved if it already exists.
authorJoey Hess <joey@kitenet.net>
Mon, 13 Sep 2010 20:08:01 +0000 (16:08 -0400)
committerJoey Hess <joey@kitenet.net>
Mon, 13 Sep 2010 20:08:13 +0000 (16:08 -0400)
debian/changelog
sponge.c
sponge.docbook

index ae71b8c64669d64e9ef7fe4c45ad3bfbebe67b14..9705e4b678f456a97693d3b0bb1898cc1cb3f999 100644 (file)
@@ -3,6 +3,8 @@ moreutils (0.42) UNRELEASED; urgency=low
   * Typo. Closes: #596032
   * sponge: Guarantee that output file is always updated atomically,
     by renaming a temp file into place. Closes: #592144
+  * sponge: Ensure that output file permissions are always preserved
+    if it already exists.
 
  -- Joey Hess <joeyh@debian.org>  Wed, 08 Sep 2010 02:09:29 -0400
 
index f9a521d3df7e612ecb46703eed949c70db34b7ad..4d5a1f4bbf5c15df479f0373ff0351ddaa0a9414 100644 (file)
--- a/sponge.c
+++ b/sponge.c
@@ -262,7 +262,6 @@ int main (int argc, char **argv) {
        FILE *outfile, *tmpfile = 0;
        ssize_t i = 0;
        size_t mem_available = default_sponge_size();
-       struct stat statbuf;
 
        if (argc > 2 || (argc == 2 && strcmp(argv[1], "-h") == 0)) {
                usage();
@@ -309,41 +308,44 @@ int main (int argc, char **argv) {
        }
 
        if (outname) {
+               mode_t mode;
+               struct stat statbuf;
+               int exists = (lstat(outname, &statbuf) == 0);
+
+               /* Set temp file mode to match either
+                * the old file mode, or the default file
+                * mode for a newly created file. */
+               if (exists) {
+                       mode = statbuf.st_mode;
+               }
+               else {
+                       mode_t mask = umask(0);
+                       umask(mask);
+                       mode = 0666 & ~mask;
+               }
+               if (chmod(tmpname, mode) != 0) {
+                       perror("chmod");
+                       exit(1);
+               }
+
                /* If it's a regular file, or does not yet exist,
                 * attempt a fast rename of the temp file. */
-               if (((lstat(outname, &statbuf) == 0 &&
+               if (((exists &&
                      S_ISREG(statbuf.st_mode) &&
                      ! S_ISLNK(statbuf.st_mode)
-                    ) || errno == ENOENT) &&
+                    ) || ! exists) &&
                    rename(tmpname, outname) == 0) {
-                       tmpname=NULL;
-                       /* Fix renamed file mode to match either
-                        * the old file mode, or the default file
-                        * mode for a newly created file. */
-                       mode_t mode;
-                       if (errno != ENOENT) {
-                               mode = statbuf.st_mode;
-                       }
-                       else {
-                               mode_t mask = umask(0);
-                               umask(mask);
-                               mode = 0666 & ~mask;
-                       }
-                       if (chmod(outname, mode) != 0) {
-                               perror("chmod");
+                       tmpname=NULL; /* don't try to cleanup tmpname */
+               }
+               else {  
+                       /* Fall back to slow copy. */
+                       outfile = fopen(outname, "w");
+                       if (!outfile) {
+                               perror("error opening output file");
                                exit(1);
                        }
-                       return(0);
-               }
-                       
-               /* Fall back to slow copy. */
-               outfile = fopen(outname, "w");
-               if (!outfile) {
-                       perror("error opening output file");
-                       exit(1);
+                       copy_tmpfile(tmpfile, outfile, bufstart, bufsize);
                }
-               copy_tmpfile(tmpfile, outfile, bufstart, bufsize);
-               fclose(outfile);
        }
        else {
                copy_tmpfile(tmpfile, stdout, bufstart, bufsize);
index ab2c42da784447c724981e3bb2ca6f82dad8796f..04447e33fa4b16d2fcf44598bb744c1580466663 100644 (file)
@@ -58,8 +58,12 @@ USA
                        redirect, sponge soaks up all its input before
                        opening the output file. This allows constricting
                        pipelines that read from and write to
-                       the same file. It also creates the output file
-                       atomically by renaming a temp file into place.</para>
+                       the same file.</para>
+               <para>
+                       It also creates the output file
+                       atomically by renaming a temp file into place.
+                       If the output file is a special file or symlink,
+                       the data will be written to it.</para>
                <para>If no output file is specified, sponge outputs to
                        stdout.</para>