Re: extension of mkisofs for incremental backups
On Mon, 2003-07-21 at 19:07, Patrick Ohly wrote:
> Hello everyone,
>
> I have updated the patch that adds -root and -old-root
> to mkisofs. It is now based on cdrtools 2.01a16,
I have updated the patch again to apply cleanly against
2.01a26pre. Patching the man page and a function prototype
caused conflicts while the rest applied still fine.
--
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 -r -c cdrtools-2.01a26pre/mkisofs/mkisofs.8 cdrtools-2.01a26pre-patched/mkisofs/mkisofs.8
*** cdrtools-2.01a26pre/mkisofs/mkisofs.8 Mon Dec 29 14:34:17 2003
--- cdrtools-2.01a26pre-patched/mkisofs/mkisofs.8 Sun Feb 15 17:08:58 2004
***************
*** 480,485 ****
--- 480,534 ----
.I \-graft\-points
has been specified.
.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 \-hide " glob
Hide
.I glob
diff -r -c cdrtools-2.01a26pre/mkisofs/mkisofs.c cdrtools-2.01a26pre-patched/mkisofs/mkisofs.c
*** cdrtools-2.01a26pre/mkisofs/mkisofs.c Wed Jan 7 00:23:46 2004
--- cdrtools-2.01a26pre-patched/mkisofs/mkisofs.c Sun Feb 15 17:10:08 2004
***************
*** 420,425 ****
--- 420,428 ----
#define OPTION_HFS_BLESS 2040
#define OPTION_HFS_PARMS 2041
+ #define OPTION_RELOC_ROOT 2042
+ #define OPTION_RELOC_OLD_ROOT 2043
+
#endif /* APPLE_HYB */
static int save_pname = 0;
***************
*** 481,486 ****
--- 484,493 ----
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},
***************
*** 1145,1150 ****
--- 1152,1159 ----
#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;
***************
*** 1521,1526 ****
--- 1530,1541 ----
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++;
***************
*** 2647,2652 ****
--- 2662,2673 ----
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) {
***************
*** 2764,2776 ****
short_name = NULL;
! if (node != NULL) {
char *pnt;
char *xpnt;
! *node = '\0';
! escstrcpy(graft_point, arg);
! *node = '=';
/*
* Remove unwanted "./" & "/" sequences from start...
--- 2785,2812 ----
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...
***************
*** 2785,2791 ****
strcpy(graft_point, xpnt);
} while (xpnt > graft_point);
! node = escstrcpy(nodename, ++node);
graft_dir = root;
xpnt = graft_point;
--- 2821,2831 ----
strcpy(graft_point, xpnt);
} while (xpnt > graft_point);
! if (node) {
! node = escstrcpy(nodename, ++node);
! } else {
! node = arg;
! }
graft_dir = root;
xpnt = graft_point;
***************
*** 2945,2951 ****
* 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
--- 2985,2992 ----
* 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 -r -c cdrtools-2.01a26pre/mkisofs/mkisofs.h cdrtools-2.01a26pre-patched/mkisofs/mkisofs.h
*** cdrtools-2.01a26pre/mkisofs/mkisofs.h Sun Dec 28 14:38:51 2003
--- cdrtools-2.01a26pre-patched/mkisofs/mkisofs.h Sun Feb 15 17:02:57 2004
***************
*** 496,502 ****
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 */
--- 496,502 ----
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 -r -c cdrtools-2.01a26pre/mkisofs/multi.c cdrtools-2.01a26pre-patched/mkisofs/multi.c
*** cdrtools-2.01a26pre/mkisofs/multi.c Wed Apr 30 00:18:10 2003
--- cdrtools-2.01a26pre-patched/mkisofs/multi.c Sun Feb 15 17:02:57 2004
***************
*** 1530,1538 ****
* 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;
--- 1530,1540 ----
* 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;
***************
*** 1544,1558 ****
--- 1546,1677 ----
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.
*/
***************
*** 1613,1619 ****
s_entry->whole_name,
s_entry, 1);
dflag = merge_previous_session(child,
! &odpnt->isorec);
if (dflag == -1) {
return (-1);
}
--- 1732,1739 ----
s_entry->whole_name,
s_entry, 1);
dflag = merge_previous_session(child,
! &odpnt->isorec,
! NULL, reloc_old_root );
if (dflag == -1) {
return (-1);
}
***************
*** 1623,1633 ****
}
}
! /*
! * 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);
}
--- 1743,1755 ----
}
}
! 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: