Hi Micah & devs , Please help me review this patch for bug20330 [https://savannah.gnu.org/bugs/index.php?20330].
I have tested this patch on Linux and windows, it works fine. (1) When rollback bytes is bigger than current file's length, it will begin downloading from offset 0. (2) Support large file system. Thanks! -------------- Xin Zou ------------------ diff -ru wget.orig/ChangeLog wget/ChangeLog --- wget.orig/ChangeLog 2008-12-31 12:39:02.000000000 +0800 +++ wget/ChangeLog 2009-01-06 12:43:50.000000000 +0800 @@ -1,3 +1,7 @@ +2009-01-06 Xin Zou <[email protected]> + + * configure.ac (AC_CHECK_FUNCS): Added check for truncate. + 2008-11-10 Micah Cowan <[email protected]> * MAILING-LIST: Mention Gmane, introduce subsections. diff -ru wget.orig/configure.ac wget/configure.ac --- wget.orig/configure.ac 2008-12-31 12:39:02.000000000 +0800 +++ wget/configure.ac 2009-01-06 12:45:11.000000000 +0800 @@ -198,7 +198,7 @@ AC_FUNC_MMAP AC_FUNC_FSEEKO AC_CHECK_FUNCS(strptime timegm snprintf vsnprintf vasprintf drand48) -AC_CHECK_FUNCS(strtoll usleep ftello sigblock sigsetjmp memrchr wcwidth mbtowc) +AC_CHECK_FUNCS(strtoll usleep ftello truncate sigblock sigsetjmp memrchr wcwidth mbtowc) if test x"$ENABLE_OPIE" = xyes; then AC_LIBOBJ([ftp-opie]) diff -ru wget.orig/src/ChangeLog wget/src/ChangeLog --- wget.orig/src/ChangeLog 2008-12-31 12:39:03.000000000 +0800 +++ wget/src/ChangeLog 2009-01-06 12:58:04.000000000 +0800 @@ -1,3 +1,9 @@ +2009-01-06 Xin Zou <[email protected]> + + * init.c, main.c, option.h, http.c, ftp.c: Add support for --rollback option + + * utils.h utils.c (truncate_file): Truncate files with specific length + 2008-11-13 Micah Cowan <[email protected]> * http.c (gethttp): Don't do anything when content-length >= our diff -ru wget.orig/src/ftp.c wget/src/ftp.c --- wget.orig/src/ftp.c 2008-12-31 12:39:03.000000000 +0800 +++ wget/src/ftp.c 2009-01-06 12:54:11.000000000 +0800 @@ -1187,10 +1187,24 @@ else if (opt.always_rest && stat (locf, &st) == 0 && S_ISREG (st.st_mode)) - /* When -c is used, continue from on-disk size. (Can't use - hstat.len even if count>1 because we don't want a failed - first attempt to clobber existing data.) */ - restval = st.st_size; + { + /* When -c is used, continue from on-disk size. (Can't use + hstat.len even if count>1 because we don't want a failed + first attempt to clobber existing data.) */ + if(!opt.rollback) + restval = st.st_size; + else + { + restval = (st.st_size-opt.rollback) > 0 ? (st.st_size-opt.rollback) : 0; + if(truncate_file (locf, restval)<0) + { + logprintf (LOG_NOTQUIET, + _("failed to truncate file: %s, ignore --rollback option\n"), + locf); + } + restval = st.st_size; + } + } else if (count > 1) restval = len; /* start where the previous run left off */ else diff -ru wget.orig/src/http.c wget/src/http.c --- wget.orig/src/http.c 2008-12-31 12:39:03.000000000 +0800 +++ wget/src/http.c 2009-01-06 12:54:11.000000000 +0800 @@ -2475,10 +2475,24 @@ && got_name && stat (hstat.local_file, &st) == 0 && S_ISREG (st.st_mode)) - /* When -c is used, continue from on-disk size. (Can't use - hstat.len even if count>1 because we don't want a failed - first attempt to clobber existing data.) */ - hstat.restval = st.st_size; + { + /* When -c is used, continue from on-disk size. (Can't use + hstat.len even if count>1 because we don't want a failed + first attempt to clobber existing data.) */ + if(!opt.rollback) + hstat.restval = st.st_size; + else + { + hstat.restval = (st.st_size-opt.rollback) > 0 ? (st.st_size-opt.rollback) : 0; + if(truncate_file (hstat.local_file, hstat.restval)<0) + { + logprintf (LOG_NOTQUIET, + _("failed to truncate file: %s, ignore --rollback option\n"), + hstat.local_file); + hstat.restval = st.st_size; + } + } + } else if (count > 1) /* otherwise, continue where the previous try left off */ hstat.restval = hstat.len; diff -ru wget.orig/src/init.c wget/src/init.c --- wget.orig/src/init.c 2008-12-31 12:39:03.000000000 +0800 +++ wget/src/init.c 2009-01-06 12:54:11.000000000 +0800 @@ -229,6 +229,7 @@ { "retrsymlinks", &opt.retr_symlinks, cmd_boolean }, { "retryconnrefused", &opt.retry_connrefused, cmd_boolean }, { "robots", &opt.use_robots, cmd_boolean }, + { "rollback", &opt.rollback, cmd_bytes }, { "savecookies", &opt.cookies_output, cmd_file }, { "saveheaders", &opt.save_headers, cmd_boolean }, #ifdef HAVE_SSL diff -ru wget.orig/src/main.c wget/src/main.c --- wget.orig/src/main.c 2008-12-31 12:39:03.000000000 +0800 +++ wget/src/main.c 2009-01-06 12:54:11.000000000 +0800 @@ -243,6 +243,7 @@ { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 }, { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 }, { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 }, + { "rollback", 0, OPT_VALUE, "rollback", -1 }, { "save-cookies", 0, OPT_VALUE, "savecookies", -1 }, { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 }, { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 }, @@ -438,6 +439,8 @@ N_("\ -c, --continue resume getting a partially-downloaded file.\n"), N_("\ + --rollback=BYTES rollback BYTES at a end of a file before resuming previous download.\n"), + N_("\ --progress=TYPE select progress gauge type.\n"), N_("\ -N, --timestamping don't re-retrieve files unless newer than\n\ @@ -1025,6 +1028,12 @@ exit (1); } #endif + if (!opt.always_rest && opt.rollback) + { + printf (_("Can't specify --rollback without --continue option.\n")); + print_usage(); + exit(1); + } if (opt.output_document) { if (opt.convert_links diff -ru wget.orig/src/options.h wget/src/options.h --- wget.orig/src/options.h 2008-12-31 12:39:03.000000000 +0800 +++ wget/src/options.h 2009-01-06 12:54:11.000000000 +0800 @@ -90,6 +90,7 @@ bool ask_passwd; /* Ask for password? */ bool always_rest; /* Always use REST. */ + wgint rollback; /* Rollback BYTES before resuming download */ char *ftp_user; /* FTP username */ char *ftp_passwd; /* FTP password */ bool netrc; /* Whether to read .netrc. */ diff -ru wget.orig/src/utils.c wget/src/utils.c --- wget.orig/src/utils.c 2008-12-31 12:39:03.000000000 +0800 +++ wget/src/utils.c 2009-01-06 12:54:11.000000000 +0800 @@ -52,6 +52,9 @@ #ifdef HAVE_SYS_UTIME_H # include <sys/utime.h> #endif +#ifdef WINDOWS +#include <io.h> +#endif #include <errno.h> #include <fcntl.h> #include <assert.h> @@ -668,6 +671,26 @@ return result; } +/* Truncate file to length bytes. On success, zero is returned, + On error, -1 is returned. */ +int truncate_file (const char *file, wgint length) +{ + struct_stat st; + int ret = -1; +#if defined(HAVE_TRUNCATE) + if (stat (file, &st) == 0 && S_ISREG (st.st_mode)) + ret = truncate (file, length); +#elif defined(WINDOWS) + if (stat (file, &st) == 0 && S_ISREG (st.st_mode)) + { + FILE *fp = fopen (file, "ab"); + ret = _chsize_s (_fileno(fp), 3); + fclose (fp); + } +#endif + return ret; +} + /* Like fnmatch, but performs a case-insensitive match. */ int diff -ru wget.orig/src/utils.h wget/src/utils.h --- wget.orig/src/utils.h 2008-12-31 12:39:03.000000000 +0800 +++ wget/src/utils.h 2009-01-06 12:54:11.000000000 +0800 @@ -86,6 +86,7 @@ FILE *unique_create (const char *, bool, char **); FILE *fopen_excl (const char *, bool); char *file_merge (const char *, const char *); +int truncate_file (const char *, wgint length); int fnmatch_nocase (const char *, const char *, int); bool acceptable (const char *);
