]> granicus.if.org Git - xz/commitdiff
xz: Always close the file before trying to delete it.
authorLasse Collin <lasse.collin@tukaani.org>
Mon, 2 Nov 2015 13:19:10 +0000 (15:19 +0200)
committerLasse Collin <lasse.collin@tukaani.org>
Mon, 2 Nov 2015 13:19:10 +0000 (15:19 +0200)
unlink() can return EBUSY in errno for open files on some
operating systems and file systems.

src/xz/file_io.c

index e5a29925d97645718a87f82b55903324595ddf6c..69cf6326a1cdba176b23846dc311cbc1dadd4947 100644 (file)
@@ -760,23 +760,22 @@ io_close_src(file_pair *pair, bool success)
 #endif
 
        if (pair->src_fd != STDIN_FILENO && pair->src_fd != -1) {
-#ifdef TUKLIB_DOSLIKE
+               // Close the file before possibly unlinking it. On DOS-like
+               // systems this is always required since unlinking will fail
+               // if the file is open. On POSIX systems it usually works
+               // to unlink open files, but in some cases it doesn't and
+               // one gets EBUSY in errno.
+               //
+               // xz 5.2.2 and older unlinked the file before closing it
+               // (except on DOS-like systems). The old code didn't handle
+               // EBUSY and could fail e.g. on some CIFS shares. The
+               // advantage of unlinking before closing is negligible
+               // (avoids a race between close() and stat()/lstat() and
+               // unlink()), so let's keep this simple.
                (void)close(pair->src_fd);
-#endif
 
-               // If we are going to unlink(), do it before closing the file.
-               // This way there's no risk that someone replaces the file and
-               // happens to get same inode number, which would make us
-               // unlink() wrong file.
-               //
-               // NOTE: DOS-like systems are an exception to this, because
-               // they don't allow unlinking files that are open. *sigh*
                if (success && !opt_keep_original)
                        io_unlink(pair->src_name, &pair->src_st);
-
-#ifndef TUKLIB_DOSLIKE
-               (void)close(pair->src_fd);
-#endif
        }
 
        return;