From 25c4acaf79a2a8f76f4792ed2008c803e1427524 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Mon, 9 Jun 2008 13:44:06 +0000 Subject: [PATCH] Allowing to restore from image with pending changes --- xorriso/xorriso.c | 120 +++++++++++++++++++++++++--- xorriso/xorriso.h | 5 +- xorriso/xorriso_private.h | 10 +++ xorriso/xorriso_timestamp.h | 2 +- xorriso/xorrisoburn.c | 154 +++++++++++++++++++++++++++++++----- xorriso/xorrisoburn.h | 7 ++ 6 files changed, 264 insertions(+), 34 deletions(-) diff --git a/xorriso/xorriso.c b/xorriso/xorriso.c index 6eec16e2..9a508bab 100644 --- a/xorriso/xorriso.c +++ b/xorriso/xorriso.c @@ -1457,18 +1457,21 @@ int Sregex_string(char **handle, char *text, int flag) #endif /* Xorriso_sregex_externaL */ -#ifndef Xorriso_text_shellsafe_externaL +/* @param flag bit0= append to out_text rather than overwrite it +*/ char *Text_shellsafe(char *in_text, char *out_text, int flag) { - int l,i,w=0; + int l,i,ol= 0,w=0; + if(flag&1) + ol= w= strlen(out_text); /* enclose everything by hard quotes */ l= strlen(in_text); out_text[w++]= '\''; for(i=0;i5*SfileadrL) + if(w+7>5*SfileadrL+ol) goto overflow; /* escape hard quote within the text */ out_text[w++]= '\''; @@ -1491,11 +1494,6 @@ overflow:; } -#endif /* ! Xorriso_text_shellsafe_externaL */ - - - - #ifndef Xorriso_fileliste_externaL /* ??? ts A71006 : Is this compatible with mkisofs pathspecs ? @@ -2730,7 +2728,7 @@ int Permstack_pop(struct PermiteM **o, struct PermiteM *stopper, /* don't complain if it fails */ if(!(flag&2)) { utime_buffer.actime= m->stbuf.st_atime; - utime_buffer.modtime= m->stbuf.st_mtime;; + utime_buffer.modtime= m->stbuf.st_mtime; ret= utime(m->disk_path,&utime_buffer); if(ret==-1 && xorriso!=NULL) { sprintf(xorriso->info_text, @@ -6364,6 +6362,59 @@ int Xorriso_lsx_filev(struct XorrisO *xorriso, char *wd, } +/* @param flag bit0= path is a directory + bit2= recursion: do not reassure in mode 2 "tree" + bit3= this is for overwriting and not for plain removal +*/ +int Xorriso_reassure_restore(struct XorrisO *xorriso, char *path, int flag) +{ + int ret; + char sfe[5*SfileadrL]; + + while((xorriso->do_reassure==1 || (xorriso->do_reassure==2 && !(flag&4))) + && !xorriso->request_not_to_ask) { + /* ls -ld */ + Xorriso_lsx_filev(xorriso, xorriso->wdx, 1, &path, (off_t) 0, 1|2|8); + if(flag&1) /* du -s */ + Xorriso_lsx_filev(xorriso, xorriso->wdx, 1, &path, (off_t) 0, 2|4); + if(flag&8) + sprintf(xorriso->info_text, + "File exists. Remove ? n= keep old, y= remove, x= abort, @= stop asking\n"); + else + sprintf(xorriso->info_text, + "Remove above file ? n= keep it, y= remove it, x= abort, @= stop asking\n"); + Xorriso_info(xorriso, 4); + ret= Xorriso_request_confirmation(xorriso, 1|2|4|16); + if(ret<=0) + goto ex; + if(xorriso->request_to_abort) { + sprintf(xorriso->info_text, + "Removal operation aborted by user before file: %s", + Text_shellsafe(path, sfe, 0)); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); + ret= 3; goto ex; + } + if(ret==3) + continue; + if(ret==6) /* yes */ + break; + if(ret==4) { /* yes, do not ask again */ + xorriso->request_not_to_ask= 1; + break; + } + if(ret==1) { /* no */ + sprintf(xorriso->info_text, "Kept in existing state: %s", + Text_shellsafe(path, sfe, 0)); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); + ret= 3; goto ex; + } + } + ret= 1; +ex: + return(ret); +} + + /* @param flag >>> bit0= remove whole sub tree: rm -r bit1= remove empty directory: rmdir @@ -6507,6 +6558,8 @@ dir_not_removed:; if(xorriso->request_to_abort) {ret= 3; goto ex;} +#ifdef NIX + while((xorriso->do_reassure==1 || (xorriso->do_reassure==2 && !(flag&4))) && !xorriso->request_not_to_ask) { /* ls -ld */ @@ -6545,6 +6598,15 @@ dir_not_removed:; ret= 3; goto ex; } } + +#else /* NIX */ + + ret= Xorriso_reassure_restore(xorriso, path, (flag&(4|8)) | !!is_dir); + if(ret<=0 || ret==3) + goto ex; + +#endif /* ! NIX */ + if(is_dir) ret= rmdir(path); else @@ -7834,6 +7896,31 @@ int Xorriso_path_is_excluded(struct XorrisO *xorriso, char *path, int flag) return(ret); } + +int Xorriso_make_tmp_path(struct XorrisO *xorriso, char *orig_path, + char *tmp_path, int *fd, int flag) +{ + char *cpt; + + cpt= strrchr(orig_path, '/'); + if(cpt==NULL) + tmp_path[0]= 0; + else { + strncpy(tmp_path, orig_path, cpt+1-orig_path); + tmp_path[cpt+1-orig_path]= 0; + } + strcat(tmp_path, "_tmp_xorriso_restore_XXXXXX"); + *fd= mkstemp(tmp_path); + if(*fd==-1) { + strcpy(xorriso->info_text, "Cannot create temporary file : "); + Text_shellsafe(tmp_path, xorriso->info_text, 1); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); + return(0); + } + fchmod(*fd, S_IRUSR|S_IWUSR); + return(1); +} + /* ---------------------------- Options API ------------------------ */ @@ -8754,12 +8841,15 @@ int Xorriso_option_cpx(struct XorrisO *xorriso, int argc, char **argv, Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } + +/* <<< if(xorriso->volset_change_pending) { sprintf(xorriso->info_text, "-cp*x: Image changes pending. May not copy from image to disk.\n"); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); ret= 0; goto ex; } +*/ /* Perform copying */ Xorriso_pacifier_reset(xorriso, 0); @@ -8818,7 +8908,7 @@ problem_handler:; goto ex; } if(xorriso->pacifier_count>0) - Xorriso_pacifier_callback(xorriso, "files copied", xorriso->pacifier_count, + Xorriso_pacifier_callback(xorriso, "files restored",xorriso->pacifier_count, xorriso->pacifier_total, "", 1); ret= !was_failure; ex:; @@ -11685,7 +11775,7 @@ return: #ifdef NIX int arg_count; #endif - char *cmd, *original_cmd, cmd_data[2*SfileadrL], *arg1, *arg2; + char *cmd, *original_cmd, cmd_data[2*SfileadrL], *arg1, *arg2, type_text[5]; if(xorriso==NULL) return(0); @@ -12145,7 +12235,13 @@ next_command:; ret= Xorriso_option_temp_mem_limit(xorriso, arg1, 0); } else if(strcmp(cmd,"test")==0) { /* This option does not exist. */ - ; + (*idx)+= 2; + ret= Xorriso_restore_is_identical(xorriso, NULL, arg2, arg1, type_text, 2); + if(ret>=0) { + sprintf(xorriso->info_text, "ISO node and disk file are %s\n", + ret>0 ? ret==2 ? "suspicious" : "identical" : "different"); + Xorriso_info(xorriso, 0); + } } else if(strcmp(cmd,"toc")==0) { Xorriso_option_toc(xorriso, 0); diff --git a/xorriso/xorriso.h b/xorriso/xorriso.h index cc9f7331..625da066 100644 --- a/xorriso/xorriso.h +++ b/xorriso/xorriso.h @@ -233,7 +233,10 @@ int Xorriso_option_compare(struct XorrisO *xorriso, char *disk_path, int Xorriso_option_cpri( struct XorrisO *xorriso, int argc, char **argv, int *idx, int flag); -/* Option -cpx */ +/* Options -cpx , -cpax, -cp_rx , -cp_rax */ +/* @param flag bit0= recursive (-cp_rx, -cp_rax) + bit1= full property restore (-cpax, -cp_rax) +*/ int Xorriso_option_cpx(struct XorrisO *xorriso, int argc, char **argv, int *idx, int flag); diff --git a/xorriso/xorriso_private.h b/xorriso/xorriso_private.h index 877ff438..55b3c388 100644 --- a/xorriso/xorriso_private.h +++ b/xorriso/xorriso_private.h @@ -418,6 +418,16 @@ int Xorriso_lsx_filev(struct XorrisO *xorriso, char *wd, int Xorriso_rmx(struct XorrisO *xorriso, off_t boss_mem, char *path, int flag); +int Xorriso_make_tmp_path(struct XorrisO *xorriso, char *orig_path, + char *tmp_path, int *fd, int flag); + +/* @param flag bit0= path is a directory + bit2= recursion: do not reassure in mode 2 "tree" + bit3= this is for overwriting and not for plain removal +*/ +int Xorriso_reassure_restore(struct XorrisO *xorriso, char *path, int flag); + + int Sfile_str(char target[SfileadrL], char *source, int flag); double Sfile_microtime(int flag); diff --git a/xorriso/xorriso_timestamp.h b/xorriso/xorriso_timestamp.h index 9e8c9237..fc16f2a9 100644 --- a/xorriso/xorriso_timestamp.h +++ b/xorriso/xorriso_timestamp.h @@ -1 +1 @@ -#define Xorriso_timestamP "2008.06.06.103735" +#define Xorriso_timestamP "2008.06.09.134432" diff --git a/xorriso/xorrisoburn.c b/xorriso/xorrisoburn.c index 2a40ab91..b8dbee24 100644 --- a/xorriso/xorrisoburn.c +++ b/xorriso/xorrisoburn.c @@ -2436,6 +2436,72 @@ unsupported_type:; } +/* @param flag bit0= in_node is valid, do not resolve img_path + bit1= test mode: print DEBUG messages + @return <0 = error, 0 = not identical regular files , 1 = identical + 2 = potentially depending on unknown disk file (e.g. -cut_out) + and hitting an existing disk file object +*/ +int Xorriso_restore_is_identical(struct XorrisO *xorriso, void *in_node, + char *img_path, char *disk_path, + char type_text[5], int flag) +{ + int ret; + unsigned int fs_id; + dev_t dev_id; + ino_t ino_id; + uint32_t dummy; + IsoStream *stream; + IsoImage *volume; + IsoNode *node; + struct stat stbuf; + + memset(type_text, 0, 5); + if(flag&1) { + node= (IsoNode *) in_node; + } else { + ret= Xorriso_get_volume(xorriso, &volume, 0); + if(ret<=0) + return(-1); + ret= Xorriso_node_from_path(xorriso, volume, img_path, &node, 1); + if(ret<=0) + return(-1); + } + + ret= iso_node_get_old_image_lba(node, &dummy, 0); + if(ret!=0) + return(0); + if(!LIBISO_ISREG(node)) + return(0); + stream= iso_file_get_stream((IsoFile *) node); + memcpy(type_text, stream->class->type, 4); + iso_stream_get_id(stream, &fs_id, &dev_id, &ino_id); + if(flag&2) { + sprintf(xorriso->info_text, "%s : fs=%d dev=%.f ino=%.f (%s)", + img_path, fs_id, (double) dev_id, (double) ino_id, type_text); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); + } + ret= stat(disk_path, &stbuf); + if(ret==-1) + return(0); + if(flag&2) { + sprintf(xorriso->info_text, "%s : dev=%.f ino=%.f", + disk_path, (double) stbuf.st_dev, (double) stbuf.st_ino); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); + } + if(fs_id!=1) + return(2); + + /* >>> obtain underlying dev_t ino_t of type "cout" */; + + if(strcmp(type_text, "fsrc")!=0) + return(2); + if(stbuf.st_dev==dev_id && stbuf.st_ino==ino_id) + return(1); + return(0); +} + + /* @param flag bit0= minimal transfer: access permissions only bit1= keep directory open: keep owner, allow rwx for owner and push directory onto xorriso->perm_stack @@ -2575,13 +2641,14 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node, { int ret= 0, write_fd= -1, wanted, wret, open_flags; char *what= "[unknown filetype]", sfe[5*SfileadrL], sfe2[5*SfileadrL]; - char buf[32*1024]; - char *link_target; + char buf[32*1024], type_text[5], temp_path[SfileadrL]; + char *link_target, *open_path_pt; off_t todo, size, seek_ret; void *data_stream= NULL; mode_t mode; dev_t dev= 0; struct stat stbuf; + struct utimbuf utime_buffer; if(LIBISO_ISDIR(node)) { what= "directory"; @@ -2592,12 +2659,13 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node, /* >>> need to exploit node rather than img_path */ ret= Xorriso_iso_file_open(xorriso, img_path, &data_stream, 0); + if(ret<=0) goto ex; - open_flags= O_WRONLY|O_CREAT; + open_path_pt= disk_path; + ret= stat(open_path_pt, &stbuf); if(flag&2) { - ret= stat(disk_path, &stbuf); if(ret!=-1 && !S_ISREG(stbuf.st_mode)) { sprintf(xorriso->info_text, "Restore offset demanded. But filesystem path leads to non-data file %s", @@ -2605,20 +2673,42 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node, Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); goto cannot_restore; } + } else { + /* If source and target are the same disk file then do not copy content */ + ret= Xorriso_restore_is_identical(xorriso, (void *) node, img_path, + disk_path, type_text, 1); + if(ret<0) + goto ex; + if(ret==1) { + /* preliminarily emulate touch (might get overridden later) */ + utime_buffer.actime= stbuf.st_atime; + utime_buffer.modtime= time(0); + utime(disk_path,&utime_buffer); + goto restore_properties; + } + if(ret==2) { + /* Extract to temporary file and rename only after copying */ + ret= Xorriso_make_tmp_path(xorriso, disk_path, temp_path, &write_fd, 0); + if(ret<=0) + goto ex; + open_path_pt= temp_path; + } + } + if(write_fd==-1) { + open_flags= O_WRONLY|O_CREAT; + if(offset==0 || !(flag&2)) + open_flags|= O_EXCL; + write_fd= open(open_path_pt, open_flags, S_IRUSR|S_IWUSR); + if(write_fd==-1) + goto cannot_restore; } - if(offset==0 || !(flag&2)) - open_flags|= O_EXCL; - write_fd= open(disk_path, open_flags, S_IRUSR|S_IWUSR); - if(write_fd==-1) - goto cannot_restore; - if(flag&2) { todo= size= bytes; seek_ret= lseek(write_fd, offset, SEEK_SET); if(seek_ret == -1) { sprintf(xorriso->info_text, "Cannot address byte %.f in filesystem path %s", - (double) offset, Text_shellsafe(disk_path, sfe, 0)); + (double) offset, Text_shellsafe(open_path_pt, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); goto cannot_restore; } @@ -2637,7 +2727,7 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node, if(wret != ret) { sprintf(xorriso->info_text, "Cannot write all bytes to disk filesystem path %s", - Text_shellsafe(disk_path, sfe, 0)); + Text_shellsafe(open_path_pt, sfe, 0)); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); break; } @@ -2646,6 +2736,18 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node, write_fd= -1; Xorriso_iso_file_close(xorriso, &data_stream, 0); data_stream= NULL; + if(temp_path==open_path_pt) { + ret= rename(temp_path, disk_path); + if(ret==-1) { + sprintf(xorriso->info_text, + "Cannot rename temporary path %s to final disk path %s", + Text_shellsafe(temp_path, sfe, 0), + Text_shellsafe(disk_path, sfe2, 0)); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",0); + unlink(temp_path); + ret= 0; goto ex; + } + } ret= (todo==0); } else if(LIBISO_ISLNK(node)) { @@ -2727,6 +2829,8 @@ cannot_restore:; Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); ret= 0; goto ex; } + +restore_properties:; if((flag&8) || LIBISO_ISLNK(node)) ret= 1; else @@ -2741,20 +2845,30 @@ ex:; /* Handle overwrite situation in disk filesystem. + @param node intended source of overwriting or NULL @param flag bit4= return 3 on rejection by exclusion or user */ -int Xorriso_restore_overwrite(struct XorrisO *xorriso, char *img_path, +int Xorriso_restore_overwrite(struct XorrisO *xorriso, + IsoNode *node, char *img_path, char *path, char *nominal_path, struct stat *stbuf, int flag) { int ret; - char sfe[5*SfileadrL], sfe2[5*SfileadrL]; + char sfe[5*SfileadrL], sfe2[5*SfileadrL], type_text[5]; Xorriso_process_msg_queues(xorriso,0); if(xorriso->do_overwrite==1 || (xorriso->do_overwrite==2 && !S_ISDIR(stbuf->st_mode))) { - ret= Xorriso_rmx(xorriso, (off_t) 0, path, 1|8); + + ret= Xorriso_restore_is_identical(xorriso, (void *) node, img_path, + path, type_text, (node!=NULL)); + if(ret<0) + return(ret); + if(ret>0) /* will be handled properly by restore functions */ + ret= Xorriso_reassure_restore(xorriso, path, 8); + else + ret= Xorriso_rmx(xorriso, (off_t) 0, path, 8); if(ret<=0) return(ret); if(ret==3) { @@ -3055,11 +3169,11 @@ much_too_long:; target_is_dir= S_ISDIR(target_stbuf.st_mode); if(!(target_is_dir && (source_is_dir && !source_is_split))) { Xorriso_process_msg_queues(xorriso,0); - ret= Xorriso_restore_overwrite(xorriso, img_path, disk_path, disk_path, - &target_stbuf, 0); + ret= Xorriso_restore_overwrite(xorriso, node, img_path, disk_path, + disk_path, &target_stbuf, 0); if(ret<=0) goto was_problem; - stbuf_ret= -1; + stbuf_ret= -1; /* It might still exist but will be handled properly */ } } @@ -3218,11 +3332,11 @@ int Xorriso_restore(struct XorrisO *xorriso, if(stbuf_ret!=-1) { target_is_dir= S_ISDIR(target_stbuf.st_mode); if(!(target_is_dir && (source_is_dir && !source_is_split))) { - ret= Xorriso_restore_overwrite(xorriso, img_path, path, disk_path, + ret= Xorriso_restore_overwrite(xorriso, node, img_path, path, disk_path, &target_stbuf, flag&16); if(ret<=0 || ret==3) goto ex; - stbuf_ret= -1; /* now it is removed */ + stbuf_ret= -1; /* now it is removed (or can be handled properly) */ } } new_dir_made= 0; diff --git a/xorriso/xorrisoburn.h b/xorriso/xorrisoburn.h index c66db4a1..f933e398 100644 --- a/xorriso/xorrisoburn.h +++ b/xorriso/xorrisoburn.h @@ -246,5 +246,12 @@ int Xorriso_is_split(struct XorrisO *xorriso, char *path, void *node, int Xorriso_restore(struct XorrisO *xorriso, char *img_path, char *disk_path, int flag); + +/* @param flag bit0= in_node is valid, do not resolve img_path +*/ +int Xorriso_restore_is_identical(struct XorrisO *xorriso, void *in_node, + char *img_path, char *disk_path, + char type_text[5], int flag); + #endif /* Xorrisoburn_includeD */