From 3333ffbd431e6164fe29b096ab67ff0cfda35a56 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 17 Apr 1998 06:07:23 +0000 Subject: [PATCH] revamped the -delete code. The last few bugs with it revealed that it had a fundamental flaw in the way it detected duplicate deletion scanning (which is very important when -R is used). I now store inode/device numbers and use those to do the detection. This should be a much less fragile method. --- flist.c | 23 +++++----- rsync.c | 136 +++++++++++++++++++++++++++----------------------------- rsync.h | 3 +- 3 files changed, 79 insertions(+), 83 deletions(-) diff --git a/flist.c b/flist.c index 63b86633..86646bb5 100644 --- a/flist.c +++ b/flist.c @@ -134,7 +134,7 @@ static void clean_fname(char *name) -void send_file_entry(struct file_struct *file,int f) +void send_file_entry(struct file_struct *file,int f,unsigned base_flags) { unsigned char flags; static time_t last_time; @@ -155,7 +155,7 @@ void send_file_entry(struct file_struct *file,int f) fname = f_name(file); - flags = FILE_VALID; + flags = base_flags; if (file->mode == last_mode) flags |= SAME_MODE; if (file->rdev == last_rdev) flags |= SAME_RDEV; @@ -224,8 +224,8 @@ void send_file_entry(struct file_struct *file,int f) -void receive_file_entry(struct file_struct **fptr, - unsigned char flags,int f) +static void receive_file_entry(struct file_struct **fptr, + unsigned flags,int f) { static time_t last_time; static mode_t last_mode; @@ -280,6 +280,7 @@ void receive_file_entry(struct file_struct **fptr, if (!file->basename) out_of_memory("receive_file_entry 1"); + file->flags = flags; file->length = read_longint(f); file->modtime = (flags & SAME_TIME) ? last_time : (time_t)read_int(f); file->mode = (flags & SAME_MODE) ? last_mode : (mode_t)read_int(f); @@ -460,7 +461,7 @@ static struct file_struct *make_file(char *fname) static void send_file_name(int f,struct file_list *flist,char *fname, - int recursive) + int recursive, unsigned base_flags) { struct file_struct *file; @@ -482,7 +483,7 @@ static void send_file_name(int f,struct file_list *flist,char *fname, if (strcmp(file->basename,"")) { flist->files[flist->count++] = file; - send_file_entry(file,f); + send_file_entry(file,f,base_flags); } if (S_ISDIR(file->mode) && recursive) { @@ -541,7 +542,7 @@ static void send_directory(int f,struct file_list *flist,char *dir) strcmp(di->d_name,"..")==0) continue; strncpy(p,di->d_name,MAXPATHLEN-(l+1)); - send_file_name(f,flist,fname,recurse); + send_file_name(f,flist,fname,recurse,FLAG_DELETE); } closedir(d); @@ -616,7 +617,7 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) *p = '/'; for (p=fname+1; (p=strchr(p,'/')); p++) { *p = 0; - send_file_name(f, flist, fname, 0); + send_file_name(f, flist, fname, 0, 0); *p = '/'; } } else { @@ -641,7 +642,7 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) flist_dir = dir; if (one_file_system) set_filesystem(fname); - send_file_name(f,flist,fname,recurse); + send_file_name(f,flist,fname,recurse,FLAG_DELETE); flist_dir = NULL; if (chdir(dbuf) != 0) { fprintf(FERROR,"chdir %s : %s\n", @@ -653,11 +654,11 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) if (one_file_system) set_filesystem(fname); - send_file_name(f,flist,fname,recurse); + send_file_name(f,flist,fname,recurse,FLAG_DELETE); } if (f != -1) { - send_file_entry(NULL,f); + send_file_entry(NULL,f,0); write_flush(f); } diff --git a/rsync.c b/rsync.c index c1ce0b5c..5f0cef6c 100644 --- a/rsync.c +++ b/rsync.c @@ -627,61 +627,50 @@ static void delete_one(struct file_struct *f) } -/* yuck! This function wouldn't have been necessary if I had the sorting - algorithm right. Unfortunately fixing the sorting algorithm would introduce - a backward incompatibility as file list indexes are sent over the link. - - The aim is to see if a directory has already had the deletion algorithm applied - to it (due to recursion), and if so to skip it. The bisection is to - prevent this being an n^2 algorithm */ -static int delete_already_done(struct file_list *flist,int j) -{ - int low=0,high=j-1; - char *name; - char *p; - - if (j == 0) return 0; - name = strdup(f_name(flist->files[j])); +static struct delete_list { + dev_t dev; + ino_t inode; +} *delete_list; +static int dlist_len, dlist_alloc_len; - if (!name) { - fprintf(FERROR,"out of memory in delete_already_done"); - exit_cleanup(1); +static void add_delete_entry(struct file_struct *file) +{ + if (dlist_len == dlist_alloc_len) { + dlist_alloc_len += 1024; + if (!delete_list) { + delete_list = (struct delete_list *)malloc(sizeof(delete_list[0])*dlist_alloc_len); + } else { + delete_list = (struct delete_list *)realloc(delete_list, sizeof(delete_list[0])*dlist_alloc_len); + } + if (!delete_list) out_of_memory("add_delete_entry"); } - name[strlen(name)-2] = 0; + delete_list[dlist_len].dev = file->dev; + delete_list[dlist_len].inode = file->inode; + dlist_len++; - p = strrchr(name,'/'); - if (!p) { - free(name); - return 0; - } - *p = 0; - - strcat(name,"/."); + if (verbose > 3) + fprintf(FINFO,"added %s to delete list\n", f_name(file)); +} - while (low != high) { - int mid = (low+high)/2; - int ret = strcmp(f_name(flist->files[flist_up(flist, mid)]),name); - if (ret == 0) { - free(name); - return 1; - } - if (ret > 0) { - high=mid; - } else { - low=mid+1; - } - } +/* yuck! This function wouldn't have been necessary if I had the sorting + algorithm right. Unfortunately fixing the sorting algorithm would introduce + a backward incompatibility as file list indexes are sent over the link. +*/ +static int delete_already_done(struct file_list *flist,int j) +{ + int i; + struct stat st; - low = flist_up(flist, low); + if (link_stat(f_name(flist->files[j]), &st)) return 1; - if (strcmp(f_name(flist->files[low]),name) == 0) { - free(name); - return 1; + for (i=0;icount;j++) { - char *name = f_name(flist->files[j]); + if (io_error) { + fprintf(FINFO,"IO error encountered - skipping file deletion\n"); + return; + } - if (!S_ISDIR(flist->files[j]->mode)) continue; + for (j=0;jcount;j++) { + if (!S_ISDIR(flist->files[j]->mode) || + !(flist->files[j]->flags & FLAG_DELETE)) continue; - if (strlen(name)<2 || strcmp(name+strlen(name)-2,"/.")!=0) continue; + if (delete_already_done(flist, j)) continue; - if (delete_already_done(flist, j)) continue; + name = strdup(f_name(flist->files[j])); - if (!(local_file_list = send_file_list(-1,1,&name))) - continue; + if (!(local_file_list = send_file_list(-1,1,&name))) { + free(name); + continue; + } - if (verbose > 1) - fprintf(FINFO,"deleting in %s\n", name); + if (verbose > 1) + fprintf(FINFO,"deleting in %s\n", name); - for (i=local_file_list->count-1;i>=0;i--) { - if (!local_file_list->files[i]->basename) continue; - if (-1 == flist_find(flist,local_file_list->files[i])) { - delete_one(local_file_list->files[i]); - } - } - flist_free(local_file_list); - } + for (i=local_file_list->count-1;i>=0;i--) { + if (!local_file_list->files[i]->basename) continue; + if (S_ISDIR(local_file_list->files[i]->mode)) + add_delete_entry(local_file_list->files[i]); + if (-1 == flist_find(flist,local_file_list->files[i])) { + delete_one(local_file_list->files[i]); + } + } + flist_free(local_file_list); + free(name); + } } static char *cleanup_fname; diff --git a/rsync.h b/rsync.h index 9f517ade..13bc9dd7 100644 --- a/rsync.h +++ b/rsync.h @@ -28,7 +28,7 @@ #define CHAR_OFFSET 0 -#define FILE_VALID 1 +#define FLAG_DELETE (1<<0) #define SAME_MODE (1<<1) #define SAME_RDEV (1<<2) #define SAME_UID (1<<3) @@ -216,6 +216,7 @@ #endif struct file_struct { + unsigned flags; time_t modtime; off_t length; mode_t mode; -- 2.34.1