--- bzip2-1.0.2/bzip2.1.bak 2002-01-03 01:14:36.000000000 +0200 +++ bzip2-1.0.2/bzip2.1 2004-12-12 09:32:26.395901433 +0200 @@ -10,7 +10,7 @@ bzip2recover \- recovers data from damag .SH SYNOPSIS .ll +8 .B bzip2 -.RB [ " \-cdfkqstvzVL123456789 " ] +.RB [ " \-cdfkqstvzFVL123456789 " ] [ .I "filenames \&..." ] @@ -216,6 +216,17 @@ bzip2 normally declines to decompress fi correct magic header bytes. If forced (-f), however, it will pass such files through unmodified. This is how GNU gzip behaves. .TP +.B \-F --fsync +Do fsync() for output file before closing it so you don't end up with +corrupted output file (and possibly lost input file) if there's a system +malfunction / power outage. +NOTE: if environment variable +.I +TAR_WANTS_FSYNC +is set (when using +the appropriately patched tar) it enables fsync in bzip2. +Fsync is done only for regular files and block devices. +.TP .B \-k --keep Keep (don't delete) input files during compression or decompression. --- bzip2-1.0.3/bzip2.c.orig 2005-11-23 00:40:49.877757771 +0200 +++ bzip2-1.0.3/bzip2.c 2005-11-23 00:43:06.118059603 +0200 @@ -165,6 +165,7 @@ # include # include # include +# include # define PATH_SEP '/' # define MY_LSTAT lstat @@ -274,7 +275,7 @@ typedef int IntNative; Int32 verbosity; Bool keepInputFiles, smallMode, deleteOutputOnInterrupt; -Bool forceOverwrite, testFailsExist, unzFailsExist, noisy; +Bool forceOverwrite, testFailsExist, unzFailsExist, noisy, do_fsync; Int32 numFileNames, numFilesProcessed, blockSize100k; Int32 exitValue; @@ -400,6 +401,17 @@ void uInt64_toAscii ( char* outbuf, UInt outbuf[i] = buf[nBuf-i-1]; } +static +int try_fsync ( int fd ) +{ + struct stat fst; + + if (!do_fsync) return 0; + + if (fstat(fd, &fst) == -1) return -1; + if (!S_ISREG(fst.st_mode) && !S_ISBLK(fst.st_mode)) return 0; + return fsync(fd); +} /*---------------------------------------------------*/ /*--- Processing of complete files and streams ---*/ @@ -457,6 +469,7 @@ void compressStream ( FILE *stream, FILE if (ferror(zStream)) goto errhandler_io; ret = fflush ( zStream ); if (ret == EOF) goto errhandler_io; + if (try_fsync ( fileno ( zStream ) ) != 0 ) goto errhandler_io; if (zStream != stdout) { int fd = fileno ( zStream ); if (fd < 0) goto errhandler_io; @@ -586,6 +599,7 @@ Bool uncompressStream ( FILE *zStream, F if (ferror(stream)) goto errhandler_io; ret = fflush ( stream ); if (ret != 0) goto errhandler_io; + if (try_fsync ( fileno ( stream ) ) != 0 ) goto errhandler_io; if (stream != stdout) { ret = fclose ( stream ); outputHandleJustInCase = NULL; @@ -1144,12 +1158,17 @@ void applySavedTimeInfoToOutputFile ( Ch { # if BZ_UNIX IntNative retVal; - struct utimbuf uTimBuf; + struct timeval tvals[2]; - uTimBuf.actime = fileMetaInfo.st_atime; - uTimBuf.modtime = fileMetaInfo.st_mtime; + tvals[0].tv_sec = fileMetaInfo.st_atim.tv_sec; + tvals[0].tv_usec = (fileMetaInfo.st_atim.tv_nsec + 500) / 1000; + tvals[1].tv_sec = fileMetaInfo.st_mtim.tv_sec; + tvals[1].tv_usec = (fileMetaInfo.st_mtim.tv_nsec + 500) / 1000; - retVal = utime ( dstName, &uTimBuf ); + retVal = chmod ( dstName, fileMetaInfo.st_mode ); + ERROR_IF_NOT_ZERO ( retVal ); + + retVal = utimes ( dstName, tvals); ERROR_IF_NOT_ZERO ( retVal ); # endif } @@ -1729,6 +1748,7 @@ void usage ( Char *fullProgName ) " -d --decompress force decompression\n" " -z --compress force compression\n" " -k --keep keep (don't delete) input files\n" + " -F --fsync fsync files prior to closing\n" " -f --force overwrite existing output files\n" " -t --test test compressed file integrity\n" " -c --stdout output to standard out\n" @@ -1923,7 +1943,8 @@ IntNative main ( IntNative argc, Char *a addFlagsFromEnvVar ( &argList, "BZIP" ); for (i = 1; i <= argc-1; i++) APPEND_FILESPEC(argList, argv[i]); - + if (getenv("TAR_WANTS_FSYNC")) + do_fsync = True; /*-- Find the length of the longest filename --*/ longestFileName = 7; @@ -1983,6 +2004,7 @@ IntNative main ( IntNative argc, Char *a case '7': blockSize100k = 7; break; case '8': blockSize100k = 8; break; case '9': blockSize100k = 9; break; + case 'F': do_fsync = True; break; case 'V': case 'L': license(); break; case 'v': verbosity++; break; @@ -2010,6 +2032,7 @@ IntNative main ( IntNative argc, Char *a if (ISFLAG("--keep")) keepInputFiles = True; else if (ISFLAG("--small")) smallMode = True; else if (ISFLAG("--quiet")) noisy = False; else + if (ISFLAG("--fsync")) do_fsync = True; else if (ISFLAG("--version")) license(); else if (ISFLAG("--license")) license(); else if (ISFLAG("--exponential")) workFactor = 1; else