tar -u adds all files regardless of mod date

Tim Kientzle kientzle at freebsd.org
Wed Sep 21 22:36:45 PDT 2005


Lowell Gilbert wrote:
> Gareth Bailey <gjbailey at gmail.com> writes:
> 
>>... If i then try to update modified files by doing this:
>>
>># tar -uf dir_b.tar /usr/dir_a/dir_b
>>
>>and I end up with dir_b.tar being 130MB (double size) which
>>should not be the case since no files have been modified in
>> /usr/dir_a/dir_b.

The attached patch should fix this problem for 6-STABLE and 7-CURRENT
systems.  If someone could try it for me and let me know if
it works for them, I'd greatly appreciate it.

5-STABLE is sufficiently different that the patch doesn't apply,
unfortunately.  It will take me a few days to figure out whether
it's best to work up a different patch for 5-STABLE or whether
I should MFC a lot of work from 6-STABLE to 5-STABLE.

The crux of the problem is that bsdtar compares files on disk
to files in the archive by pathname before it strips leading '/'
characters.  As a result, it tries to compare "/usr/dir_a" on disk
to "usr/dir_a" in the archive, which fails.

A temporary workaround is to not use absolute pathnames:

    cd / ; tar -uf dir_b.tar usr/dir_a/dir_b

Another workaround is to use -P both when creating and when
updating the archive.

The attached patch causes bsdtar to do all pathname editing
before it does the time comparison for -u.  I think that
correctly fixes this problem.

Tim

P.S. If you're testing this, do not use "touch" to update
timestamps.  If you do, you will get some very confusing
results because "touch" updates high-precision timestamps,
but the default tar format only stores whole seconds.
This seems hard to fix.
-------------- next part --------------
Index: write.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/tar/write.c,v
retrieving revision 1.41
diff -u -r1.41 write.c
--- write.c	8 May 2005 06:25:15 -0000	1.41
+++ write.c	22 Sep 2005 04:46:00 -0000
@@ -643,15 +643,12 @@
 			tree_descend(tree);
 
 		/*
-		 * In -u mode, we need to check whether this
-		 * is newer than what's already in the archive.
-		 * In all modes, we need to obey --newerXXX flags.
+		 * Write the entry.  Note that write_entry() handles
+		 * pathname editing and newness testing.
 		 */
-		if (new_enough(bsdtar, name, lst)) {
-			write_entry(bsdtar, a, lst, name,
-			    tree_current_pathlen(tree),
-			    tree_current_access_path(tree));
-		}
+		write_entry(bsdtar, a, lst, name,
+		    tree_current_pathlen(tree),
+		    tree_current_access_path(tree));
 	}
 	tree_close(tree);
 }
@@ -686,6 +683,13 @@
 	if (edit_pathname(bsdtar, entry))
 		goto abort;
 
+	/*
+	 * In -u mode, check that the file is newer than what's
+	 * already in the archive; in all modes, obey --newerXXX flags.
+	 */
+	if (!new_enough(bsdtar, archive_entry_pathname(entry), st))
+		goto abort;
+
 	if (!S_ISDIR(st->st_mode) && (st->st_nlink > 1))
 		lookup_hardlink(bsdtar, entry, st);
 
@@ -1235,10 +1239,6 @@
 	 */
 	if (bsdtar->archive_dir != NULL &&
 	    bsdtar->archive_dir->head != NULL) {
-		/* Ignore leading './' when comparing names. */
-		if (path[0] == '.' && path[1] == '/' && path[2] != '\0')
-			path += 2;
-
 		for (p = bsdtar->archive_dir->head; p != NULL; p = p->next) {
 			if (strcmp(path, p->name)==0)
 				return (p->mtime_sec < st->st_mtime ||


More information about the freebsd-questions mailing list