From: Paul Eggert Date: Tue, 24 Apr 2012 16:16:17 +0000 (-0700) Subject: gzip: port gzip -rf to ZFS X-Git-Tag: v1.5~5 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=e416d27cbfec019ef869ca950211aac28470ca7e;p=debian%2Fgzip gzip: port gzip -rf to ZFS Problem reported privately by Rich Burridge. * bootstrap.conf: Add savedir. * gzip.c: Include . (_D_EXACT_NAMELEN): Remove. (treat_dir): Use savedir rather than reading directory entries one at a time, to avoid revisiting an already-compressed file when using ZFS and the -rf flags are specified. * lib/.gitignore, m4/.gitignore: Ignore savedir-related files. --- diff --git a/bootstrap.conf b/bootstrap.conf index 8e66054..e5d14c2 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -49,6 +49,7 @@ perror printf-posix readme-release realloc-gnu +savedir stat-time sys_stat time diff --git a/gzip.c b/gzip.c index c5ef4fd..b792a47 100644 --- a/gzip.c +++ b/gzip.c @@ -88,9 +88,7 @@ static char const *const license_msg[] = { #endif #if !NO_DIR # include -# ifndef _D_EXACT_NAMLEN -# define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name) -# endif +# include #endif #ifdef CLOSEDIR_VOID @@ -1758,16 +1756,17 @@ local void copy_stat(ifstat) #if ! NO_DIR /* ======================================================================== - * Recurse through the given directory. This code is taken from ncompress. + * Recurse through the given directory. */ local void treat_dir (fd, dir) int fd; char *dir; { - struct dirent *dp; DIR *dirp; char nbuf[MAX_PATH_LEN]; - int len; + char *entries; + char const *entry; + size_t entrylen; dirp = fdopendir (fd); @@ -1776,29 +1775,21 @@ local void treat_dir (fd, dir) close (fd); return ; } - /* - ** WARNING: the following algorithm could occasionally cause - ** compress to produce error warnings of the form ".gz - ** already has .gz suffix - ignored". This occurs when the - ** .gz output file is inserted into the directory below - ** readdir's current pointer. - ** These warnings are harmless but annoying, so they are suppressed - ** with option -r (except when -v is on). An alternative - ** to allowing this would be to store the entire directory - ** list in memory, then compress the entries in the stored - ** list. Given the depth-first recursive algorithm used here, - ** this could use up a tremendous amount of memory. I don't - ** think it's worth it. -- Dave Mack - ** (An other alternative might be two passes to avoid depth-first.) - */ - while ((errno = 0, dp = readdir(dirp)) != NULL) { + entries = streamsavedir (dirp); + if (! entries) + progerror (dir); + if (closedir (dirp) != 0) + progerror (dir); + if (! entries) + return; - if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) { - continue; - } - len = strlen(dir); - if (len + _D_EXACT_NAMLEN (dp) + 1 < MAX_PATH_LEN - 1) { + for (entry = entries; *entry; entry += entrylen + 1) { + size_t len = strlen (dir); + entrylen = strlen (entry); + if (strequ (entry, ".") || strequ (entry, "..")) + continue; + if (len + entrylen < MAX_PATH_LEN - 2) { strcpy(nbuf,dir); if (len != 0 /* dir = "" means current dir on Amiga */ #ifdef PATH_SEP2 @@ -1810,18 +1801,15 @@ local void treat_dir (fd, dir) ) { nbuf[len++] = PATH_SEP; } - strcpy(nbuf+len, dp->d_name); + strcpy (nbuf + len, entry); treat_file(nbuf); } else { fprintf(stderr,"%s: %s/%s: pathname too long\n", - program_name, dir, dp->d_name); + program_name, dir, entry); exit_code = ERROR; } } - if (errno != 0) - progerror(dir); - if (CLOSEDIR(dirp) != 0) - progerror(dir); + free (entries); } #endif /* ! NO_DIR */ diff --git a/lib/.gitignore b/lib/.gitignore index 9820da1..0d8e8e5 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -233,3 +233,9 @@ /xsize.h /yesno.c /yesno.h +/dirent--.h +/dirent-safer.h +/opendir-safer.c +/readdir.c +/savedir.c +/savedir.h diff --git a/m4/.gitignore b/m4/.gitignore index b3b29dc..005e2c1 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -157,3 +157,6 @@ /xgetcwd.m4 /xsize.m4 /yesno.m4 +/dirent-safer.m4 +/readdir.m4 +/savedir.m4