[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: extension of mkisofs for incremental backups



On Sun, 2004-02-29 at 22:04, Joerg Schilling wrote:
> >From: Patrick Ohly <Patrick.Ohly@gmx.de>
> 
> >> The patch to the man page indserts things disordered
> 
> >Where would you like me to insert the description of
> >the new options?
> 
> A while ago, I did try to have the options in alphabetical order.
> This seems to be the best when a command as soooo many options.

In some cases mkisofs deviates from this rule, and I think it
makes sense: f.i. -output-charset directly follows -input-charset,
-force-rr is next to -no-rr, etc.

I'd like to follow that pattern and add -root in alphabetical
order followed by -old-root.

> >> Calling 'cstyle -v' gives this:
> 
> >Do you have a URL where I can download cstyle?
> >I cannot find it on freshmeat, a google search
> >brought up many misleading hits and Debian's package
> >search page is currently unreachable.
> 
> # cstyle - check for some common stylistic errors. 
> # 
> #       cstyle is a sort of "lint" for C coding style. 
> #       It attempts to check for the style used in the 
> #       kernel, sometimes known as "Bill Joy Normal Form". 
> 
> This is a program written by Bill Shannon (the inventor
> of the vnode interface that also was the base for the NFS
> rpc interface.

I have been unable to find a homepage of Bill Shannon
or cstyle, although he turns  up in some Google hits,
mostly related to his current work on Java for Sun.

Reformatting automatically with e.g. astyle changes too
much (or I didn't get the options right). Therefore I
fixed the places that you mentioned manually. Please
be patient if I didn't get all of them right and perhaps
consider making cstyle available on your web site if you
expect patches to be cstyle-clean (especially the correct
line continuation isn't clear to me).

Regarding evaluating the patch: you can fairly easily
conclude that it doesn't break anything by assuming
reloc_old_root == NULL in multi.c (the default when
no -old-root is used). Then it is obvious that the
new code is completely inactive and the same code as
without the patch is executed.

-root on the other hand is just a few lines of code
that adds the root as prefix and then relies on the old
-graft-point code to do the work.

By now I'd consider the code well-tested, too. Errors
that were found recently were all in the core
mkisofs code, not in the patch itself. I'll be happy
to help if further problems arise.

Attached is the modified patch, this time against
2.01a26.

-- 
Bye, Patrick Ohly
--  
Patrick.Ohly@gmx.de
patrick@core.de (MakeCD related mails)
http://home.pages.de/~ohly/
http://makecd.core.de/ (MakeCD home page)
diff -c -r cdrtools-2.01a26/mkisofs/mkisofs.8 cdrtools-2.01a26-patched/mkisofs/mkisofs.8
*** cdrtools-2.01a26/mkisofs/mkisofs.8	Tue Mar  2 22:05:37 2004
--- cdrtools-2.01a26-patched/mkisofs/mkisofs.8	Tue Mar  2 22:19:53 2004
***************
*** 922,927 ****
--- 922,976 ----
  This violates the ISO9660 standard, but it happens to work on many systems.
  Use with caution.
  .TP
+ .BI \-root " dir
+ Moves all files and directories into
+ .I dir
+ in the image. This is essentially the
+ same as using 
+ .B -graft-points
+ and adding
+ .I dir
+ in front of every pathspec, but is easier to use.
+ 
+ .I dir
+ may actually be several levels deep. It is
+ created with the same permissions as other graft points.
+ .TP
+ .BI \-old-root " dir
+ This option is necessary when writing a multisession
+ image and the previous (or even older) session was written with
+ .BI -root " dir.
+ Using a directory name not found in the previous session
+ causes
+ .B mkisofs
+ to abort with an error.
+ 
+ Without this option,
+ .B mkisofs
+ would not be able to find unmodified files and would
+ be forced to write their data into the image once more.
+ 
+ .B \-root
+ and
+ .B \-old-root
+ are meant to be used together to do incremental backups.
+ The initial session would e.g. use:
+ mkisofs \-root backup_1 <dirs>.
+ The next incremental backup with mkisofs \-root backup_2
+ \-old-root backup_1 <dirs>
+ would take another snapshot of these directories. The first
+ snapshot would be found in backup_1, the second one in
+ backup_2, but only modified or new files need to be written
+ into the second session.
+ 
+ Without these options, new files would be added and old ones would be
+ preserved. But old ones would be overwritten if the file was
+ modified. Recovering the files by copying the whole directory back
+ from CD would also restore files that were deleted
+ intentionally. Accessing several older versions of a file requires
+ support by the operating system to choose which sessions are to be
+ mounted.
+ .TP
  .BI \-sort " sort file
  Sort file locations on the media. Sorting is controlled by a file that
  contains pairs of filenames and sorting offset weighting.
diff -c -r cdrtools-2.01a26/mkisofs/mkisofs.c cdrtools-2.01a26-patched/mkisofs/mkisofs.c
*** cdrtools-2.01a26/mkisofs/mkisofs.c	Tue Mar  2 22:05:37 2004
--- cdrtools-2.01a26-patched/mkisofs/mkisofs.c	Tue Mar  2 22:38:50 2004
***************
*** 422,427 ****
--- 422,430 ----
  
  #define OPTION_CHRP_BOOT		2042
  
+ #define	OPTION_RELOC_ROOT		2042
+ #define	OPTION_RELOC_OLD_ROOT	2043
+ 
  #endif	/* APPLE_HYB */
  
  static int	save_pname = 0;
***************
*** 483,488 ****
--- 486,495 ----
  	ONE_DASH},
  	{{"graft-points", no_argument, NULL, OPTION_USE_GRAFT},
  	'\0', NULL, "Allow to use graft points for filenames", ONE_DASH},
+ 	{{"root", required_argument, NULL, OPTION_RELOC_ROOT},
+ 	'\0', "DIR", "Set root directory for all new files and directories", ONE_DASH},
+ 	{{"old-root", required_argument, NULL, OPTION_RELOC_OLD_ROOT},
+ 	'\0', "DIR", "Set root directory in previous session that is searched for files", ONE_DASH},
  	{{"help", no_argument, NULL, OPTION_HELP},
  	'\0', NULL, "Print option help", ONE_DASH},
  	{{"hide", required_argument, NULL, OPTION_I_HIDE},
***************
*** 1149,1154 ****
--- 1156,1163 ----
  #endif
  	struct stat	statbuf;
  	char		*merge_image = NULL;
+ 	char		*reloc_root = NULL;
+ 	char		*reloc_old_root = NULL;
  	struct iso_directory_record *mrootp = NULL;
  	struct output_fragment *opnt;
  	int		longind;
***************
*** 1525,1530 ****
--- 1534,1545 ----
  		case 'M':
  			merge_image = optarg;
  			break;
+ 		case OPTION_RELOC_ROOT:
+ 			reloc_root = optarg;
+ 			break;
+ 		case OPTION_RELOC_OLD_ROOT:
+ 			reloc_old_root = optarg;
+ 			break;
  		case 'N':
  			omit_version_number++;
  			warn_violate++;
***************
*** 2666,2671 ****
--- 2681,2692 ----
  
  	memset(&de, 0, sizeof (de));
  
+ 	/*
+ 	 * PO:
+ 	 * Isn't root NULL at this time anyway?
+ 	 * I think it is created by the first call to
+ 	 * find_or_create_directory() below.
+ 	 */
  	de.filedir = root;	/* We need this to bootstrap */
  
  	if (cdrecord_data != NULL && merge_image == NULL) {
***************
*** 2783,2795 ****
  
  		short_name = NULL;
  
! 		if (node != NULL) {
  			char		*pnt;
  			char		*xpnt;
  
! 			*node = '\0';
! 			escstrcpy(graft_point, arg);
! 			*node = '=';
  
  			/*
  			 * Remove unwanted "./" & "/" sequences from start...
--- 2804,2831 ----
  
  		short_name = NULL;
  
! 		if (node != NULL || reloc_root) {
  			char		*pnt;
  			char		*xpnt;
+ 			size_t    len;
+ 
+ 			/* insert -root prefix */
+ 			if (reloc_root != NULL) {
+ 				strcpy(graft_point, reloc_root);
+ 				len = strlen(graft_point);
+ 				if (graft_point[len] != '/') {
+ 					graft_point[len] = '/';
+ 					len++;
+ 				}
+ 			} else {
+ 				len = 0;
+ 			}
  
! 			if (node) {
! 				*node = '\0';
! 				escstrcpy(graft_point + len, arg);
! 				*node = '=';
! 			}
  
  			/*
  			 * Remove unwanted "./" & "/" sequences from start...
***************
*** 2804,2810 ****
  				strcpy(graft_point, xpnt);
  			} while (xpnt > graft_point);
  
! 			node = escstrcpy(nodename, ++node);
  
  			graft_dir = root;
  			xpnt = graft_point;
--- 2840,2850 ----
  				strcpy(graft_point, xpnt);
  			} while (xpnt > graft_point);
  
! 			if (node) {
! 				node = escstrcpy(nodename, ++node);
! 			} else {
! 				node = arg;
! 			}
  
  			graft_dir = root;
  			xpnt = graft_point;
***************
*** 2964,2970 ****
  	 * side, since we may need to create some additional directories.
  	 */
  	if (merge_image != NULL) {
! 		if (merge_previous_session(root, mrootp) < 0) {
  #ifdef	USE_LIBSCHILY
  			comerrno(EX_BAD, "Cannot merge previous session.\n");
  #else
--- 3004,3011 ----
  	 * side, since we may need to create some additional directories.
  	 */
  	if (merge_image != NULL) {
! 		if (merge_previous_session(root, mrootp,
! 											reloc_root, reloc_old_root) < 0) {
  #ifdef	USE_LIBSCHILY
  			comerrno(EX_BAD, "Cannot merge previous session.\n");
  #else
diff -c -r cdrtools-2.01a26/mkisofs/mkisofs.h cdrtools-2.01a26-patched/mkisofs/mkisofs.h
*** cdrtools-2.01a26/mkisofs/mkisofs.h	Tue Mar  2 22:05:37 2004
--- cdrtools-2.01a26-patched/mkisofs/mkisofs.h	Tue Mar  2 22:31:30 2004
***************
*** 497,503 ****
  				struct directory_entry * dpnt));
  extern int	rr_flags	__PR((struct iso_directory_record *idr));
  extern int merge_previous_session __PR((struct directory *,
! 				struct iso_directory_record *));
  extern int get_session_start __PR((int *));
  
  /* joliet.c */
--- 497,503 ----
  				struct directory_entry * dpnt));
  extern int	rr_flags	__PR((struct iso_directory_record *idr));
  extern int merge_previous_session __PR((struct directory *,
! 				struct iso_directory_record *, char *, char *));
  extern int get_session_start __PR((int *));
  
  /* joliet.c */
diff -c -r cdrtools-2.01a26/mkisofs/multi.c cdrtools-2.01a26-patched/mkisofs/multi.c
*** cdrtools-2.01a26/mkisofs/multi.c	Tue Mar  2 22:05:37 2004
--- cdrtools-2.01a26-patched/mkisofs/multi.c	Tue Mar  2 22:48:17 2004
***************
*** 1545,1553 ****
   * directory entries, so that we can determine how large each directory is.
   */
  int
! merge_previous_session(this_dir, mrootp)
  	struct directory *this_dir;
  	struct iso_directory_record *mrootp;
  {
  	struct directory_entry **orig_contents = NULL;
  	struct directory_entry *odpnt = NULL;
--- 1545,1555 ----
   * directory entries, so that we can determine how large each directory is.
   */
  int
! merge_previous_session(this_dir, mrootp, reloc_root, reloc_old_root)
  	struct directory *this_dir;
  	struct iso_directory_record *mrootp;
+ 	char *reloc_root;
+ 	char *reloc_old_root;
  {
  	struct directory_entry **orig_contents = NULL;
  	struct directory_entry *odpnt = NULL;
***************
*** 1559,1573 ****
--- 1561,1694 ----
  			lstatbuf;
  	int		retcode;
  
+ 	/* skip leading slash */
+ 	while (reloc_old_root && reloc_old_root[0] == PATH_SEPARATOR) {
+ 		reloc_old_root++;
+ 	}
+ 	while (reloc_root && reloc_root[0] == PATH_SEPARATOR) {
+ 		reloc_root++;
+ 	}
+ 
  	/*
  	 * Parse the same directory in the image that we are merging for
  	 * multisession stuff.
  	 */
  	orig_contents = read_merging_directory(mrootp, &n_orig);
  	if (orig_contents == NULL) {
+ 		if (reloc_old_root) {
+ #ifdef	USE_LIBSCHILY
+ 			comerrno(EX_BAD, "Reading old session failed, cannot execute -old-root.\n");
+ #else
+ 			fprintf(stderr, "Reading old session failed, cannot execute -old-root.\n");
+ #endif
+ 			return (-1);
+ 		}
  		return (0);
  	}
  
+ 	if (reloc_old_root && reloc_old_root[0]) {
+ 		struct directory_entry **new_orig_contents = orig_contents;
+ 		int		new_n_orig = n_orig;
+ 
+ 		/* decend until we reach the original root */
+ 		while (reloc_old_root[0]) {
+ 			int i;
+ 			char *next;
+ 			int last;
+ 
+ 			for (next = reloc_old_root; *next && *next != PATH_SEPARATOR; next++);
+ 			if (*next) {
+ 				last = 0;
+ 				*next = 0;
+ 				next++;
+ 			} else {
+ 				last = 1;
+ 			}
+ 			while (*next == PATH_SEPARATOR) {
+ 				next++;
+ 			}
+ 
+ 			for (i = 0; i < new_n_orig; i++) {
+ 				struct iso_directory_record subroot;
+ 
+ 				if (new_orig_contents[i]->name != NULL &&
+ 					 strcmp(new_orig_contents[i]->name, reloc_old_root) != 0) {
+ 					/* Not the same name continue */
+ 					continue;
+ 				}
+ 				/*
+ 				 * enter directory, free old one only if not the top level,
+ 				 * which is still needed
+ 				 */
+ 				subroot = new_orig_contents[i]->isorec;
+ 				if (new_orig_contents != orig_contents) {
+ 					free_mdinfo(new_orig_contents, new_n_orig);
+ 				}
+ 				new_orig_contents = read_merging_directory(&subroot, &new_n_orig);
+ 
+ 				if (!new_orig_contents) {
+ #ifdef	USE_LIBSCHILY
+ 					comerrno(EX_BAD, "Reading directory %s in old session failed, cannot execute -old-root.\n", reloc_old_root);
+ #else
+ 					fprintf(stderr, "Reading directory %s in old session failed, cannot execute -old-root.\n", reloc_old_root);
+ #endif
+ 					return (-1);
+ 				}
+ 
+ 				i = -1;
+ 				break;
+ 			}
+ 
+ 			if (i == new_n_orig) {
+ #ifdef	USE_LIBSCHILY
+ 				comerrno(EX_BAD, "-old-root (sub)directory %s not found in old session.\n", reloc_old_root);
+ #else
+ 				fprintf(stderr, "-old-root (sub)directory %s not found in old session.\n", reloc_old_root);
+ #endif
+ 				return (-1);
+ 			}
+ 
+ 			/* restore string, proceed to next sub directory */
+ 			if (!last) {
+ 				reloc_old_root[strlen(reloc_old_root)] = PATH_SEPARATOR;
+ 			}
+ 			reloc_old_root = next;
+ 		}
+ 
+ 		/*
+ 		 * preserve the old session, skipping those dirs/files that are found again
+ 		 * in the new root
+ 		 */
+ 		for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
+ 			status = stat_filter(s_entry->whole_name, &statbuf);
+ 			lstatus = lstat_filter(s_entry->whole_name, &lstatbuf);
+ 
+ 			/*
+ 			 * check_prev_session() will search for s_entry and remove it from
+ 			 * orig_contents if found
+ 			 */
+ 			retcode = check_prev_session(orig_contents, n_orig, s_entry,
+ 			    &statbuf, &lstatbuf, NULL);
+ 			if (retcode == -1)
+ 				return (-1);
+ 		}
+ 		merge_remaining_entries(this_dir, orig_contents, n_orig);
+ 
+ 		/* use new directory */
+ 		free_mdinfo(orig_contents, n_orig);
+ 		orig_contents = new_orig_contents;
+ 		n_orig = new_n_orig;
+ 
+ 		if (reloc_root && reloc_root[0]) {
+ 			/* also decend into new root before searching for files */
+ 			this_dir = find_or_create_directory(this_dir, reloc_root, NULL, TRUE);
+ 			if (!this_dir) {
+ 				return (-1);
+ 			}
+ 		}
+ 	}
+ 
+ 
  	/*
  	 * Now we scan the directory itself, and look at what is inside of it.
  	 */
***************
*** 1628,1634 ****
  					s_entry->whole_name,
  					s_entry, 1);
  				dflag = merge_previous_session(child,
! 					&odpnt->isorec);
  				if (dflag == -1) {
  					return (-1);
  				}
--- 1749,1756 ----
  					s_entry->whole_name,
  					s_entry, 1);
  				dflag = merge_previous_session(child,
! 					&odpnt->isorec,
! 					NULL, reloc_old_root);
  				if (dflag == -1) {
  					return (-1);
  				}
***************
*** 1638,1648 ****
  		}
  	}
  
! 	/*
! 	 * Whatever is left over, are things which are no longer in the tree on
! 	 * disk. We need to also merge these into the tree.
! 	 */
! 	merge_remaining_entries(this_dir, orig_contents, n_orig);
  	free_mdinfo(orig_contents, n_orig);
  	return (1);
  }
--- 1760,1772 ----
  		}
  	}
  
! 	if (!reloc_old_root) {
! 		/*
! 		 * Whatever is left over, are things which are no longer in the tree on
! 		 * disk. We need to also merge these into the tree.
! 		 */
! 		merge_remaining_entries(this_dir, orig_contents, n_orig);
! 	}
  	free_mdinfo(orig_contents, n_orig);
  	return (1);
  }

Reply to: