From: jeg@ced.berkeley.edu (James Ganong)
Subject: more on tar-1.11.1 incremental dumps
Organization: GNUs Not Usenet
Distribution: gnu
Date: Mon, 9 Nov 1992 02:01:08 GMT

i sent in a patch for tar-1.11.1/gnu.c which i have repeated below.

one of the effects of the bug was to backup more directories
than strictly necessary, which was a good thing because it
mooted another bug that cause some dirs that should be backed up to get 
skipped.

so if you use my first fix you probably want to use something
like the second fix i am sending you in this note also.

here is my first patch:

------- gnu.c -------
162,172c162,170
< 		strp=buf;
< 		dev=atol(strp);
< 		while(isdigit(*strp))
< 			strp++;
< 		ino=atol(strp);
< 		while(isspace(*strp))
< 			strp++;
< 		while(isdigit(*strp))
< 			strp++;
< 		strp++;
< 		add_dir(un_quote_string(strp),dev,ino,(char *)0);
---
> 		{
> 			unsigned long t,u;
> 			char scratch[1000];
> 
> 			sscanf(buf, "%lu %lu %s", &t, &u, scratch);
> 			dev=t;
> 			ino=u;
> 		add_dir(un_quote_string(scratch),dev,ino,(char *)0);
> 		}

with just this patch in place the following test
winds up with the file d/e/hi not being restored.

# set up the test data

rm -r d
mkdir d
mkdir d/d
mkdir d/e
echo hi > d/d/hi

# do a level 0 backup

rm date0
tar -cvf tar0 -g date0 d

sleep 2
mv d/d/hi d/e

# do a level 1 backup
cp date0 date1
tar -cvf tar1 -g date1 d

# now simulate loosing it all
rm -r d

# do the restore

tar -xvf tar0 -G

tar -xvf tar1 -G



#end of test case

after this test case is run d/e/hi does not exist
and wish i did.

i think the problem is that tar is not backup up the contents
of the dir d/e when it is doing the level 1 backup:
tar -cvf tar1 -g date1 d
+ tar -cvf tar1 -g date1 d
d/
d/d/
d/e/


tar-1.11.1 DOES backup the contents
of the dir d/e, but i think for the wrong reasons, because
it backs up the contents of ALL the directories.

tar -cvf tar1 -g date1 d
tar: directory d/d has been renamed.
tar: directory d/e has been renamed.
d/
d/d/
d/e/
d/e/hi

you can see the problem with the following test case with tar-1.11.1

# set up the test data

rm -r d
mkdir d
mkdir d/d
mkdir d/e
mkdir d/f
echo hi > d/d/hi
echo goodbye > d/f/bye

# do a level 0 backup

rm date0
tar -cvf tar0 -g date0 d

sleep 2
mv d/d/hi d/e

# do a level 1 backup
cp date0 date1
tar -cvf tar1 -g date1 d

# now simulate loosing it all
rm -r d

# do the restore

tar -xvf tar0 -G

tar -xvf tar1 -G




# end of test case

the problem is that dir d/f gets backed up in the level 1 backup even though
nothing about it has changed:

tar -cvf tar1 -g date1 d
tar: directory d/d has been renamed.
tar: directory d/e has been renamed.
tar: directory d/f has been renamed.
d/
d/d/
d/e/
d/f/
d/e/hi
d/f/bye

i noticed that when tar is deciding to incrementally dump a dir (or not
it only looks at the inode number and device, not at the date.
here is my patch to address this.  (along with my first patch,
apply it to tar-1.11.1/gnu.c)  note that i don't really know what
is going on here, so please look at it carefully before using it.


*** gnu.c.orig	Sun Nov  8 17:53:14 1992
--- gnu.c	Sun Nov  8 17:53:27 1992
***************
*** 159,176 ****
  		strp= &buf[strlen(buf)];
  		if(strp[-1]=='\n')
  			strp[-1]='\0';
! 		strp=buf;
! 		dev=atol(strp);
! 		while(isdigit(*strp))
! 			strp++;
! 		ino=atol(strp);
! 		while(isspace(*strp))
! 			strp++;
! 		while(isdigit(*strp))
! 			strp++;
! 		strp++;
! 		add_dir(un_quote_string(strp),dev,ino,(char *)0);
! 	}
  	fclose(fp);
  }
  
--- 159,174 ----
  		strp= &buf[strlen(buf)];
  		if(strp[-1]=='\n')
  			strp[-1]='\0';
! 		{
! 		  unsigned long t,u;
! 		  char scratch[1000];
!        
! 		  sscanf(buf, "%lu %lu %s", &t, &u, scratch);
! 		  dev=t;
! 		  ino=u;
! 		  add_dir(un_quote_string(scratch),dev,ino,(char *)0);
! 		}
! 	      }
  	fclose(fp);
  }
  
***************
*** 377,391 ****
  					if(   dp->dev!=hs.st_dev
   					   || dp->ino!=hs.st_ino) {
  					   	if(f_verbose)
! 							msg("directory %s has been renamed.",namebuf);
  						dp->allnew=1;
  						dp->dev=hs.st_dev;
  						dp->ino=hs.st_ino;
  					}
  					dp->dir_text="";
  				} else {
  					if(f_verbose)
! 						msg("Directory %s is new",namebuf);
  					add_dir(namebuf,hs.st_dev,hs.st_ino,"");
  					dp=get_dir(namebuf);
  					dp->allnew=1;
--- 375,398 ----
  					if(   dp->dev!=hs.st_dev
   					   || dp->ino!=hs.st_ino) {
  					   	if(f_verbose)
! 						  msg("%s is a new dir reusing an old dir name.",namebuf);
  						dp->allnew=1;
  						dp->dev=hs.st_dev;
  						dp->ino=hs.st_ino;
+ 
+ 					      } else if (f_new_files &&
+ 							 new_time>hs.st_mtime &&
+ 							 new_time>hs.st_mtime &&
+ 							 (f_new_files>1 || new_time>hs.st_ctime)) {
+ 						if (f_verbose) {
+ 						  msg("dir %s has been changed since previous .",namebuf);
+ 						}
+ 						dp->allnew=1;
  					}
  					dp->dir_text="";
  				} else {
  					if(f_verbose)
! 					  msg("%s is a new dir name",namebuf);
  					add_dir(namebuf,hs.st_dev,hs.st_ino,"");
  					dp=get_dir(namebuf);
  					dp->allnew=1;

Newsgroups: gnu.utils.bug