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.
This commit is contained in:
Andrew Tridgell
1998-04-17 06:07:23 +00:00
parent a16bbc3990
commit 3333ffbd43
3 changed files with 79 additions and 83 deletions

23
flist.c
View File

@@ -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);
}

136
rsync.c
View File

@@ -627,61 +627,50 @@ static void delete_one(struct file_struct *f)
}
static struct delete_list {
dev_t dev;
ino_t inode;
} *delete_list;
static int dlist_len, dlist_alloc_len;
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");
}
delete_list[dlist_len].dev = file->dev;
delete_list[dlist_len].inode = file->inode;
dlist_len++;
if (verbose > 3)
fprintf(FINFO,"added %s to delete list\n", f_name(file));
}
/* 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;
int i;
struct stat st;
if (j == 0) return 0;
if (link_stat(f_name(flist->files[j]), &st)) return 1;
name = strdup(f_name(flist->files[j]));
if (!name) {
fprintf(FERROR,"out of memory in delete_already_done");
exit_cleanup(1);
}
name[strlen(name)-2] = 0;
p = strrchr(name,'/');
if (!p) {
free(name);
return 0;
}
*p = 0;
strcat(name,"/.");
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);
for (i=0;i<dlist_len;i++) {
if (st.st_ino == delete_list[i].inode &&
st.st_dev == delete_list[i].dev)
return 1;
}
if (ret > 0) {
high=mid;
} else {
low=mid+1;
}
}
low = flist_up(flist, low);
if (strcmp(f_name(flist->files[low]),name) == 0) {
free(name);
return 1;
}
free(name);
return 0;
}
@@ -691,40 +680,45 @@ static int delete_already_done(struct file_list *flist,int j)
to match more closely what most people seem to expect of this option */
static void delete_files(struct file_list *flist)
{
struct file_list *local_file_list;
int i, j;
struct file_list *local_file_list;
int i, j;
char *name;
if (cvs_exclude)
add_cvs_excludes();
if (cvs_exclude)
add_cvs_excludes();
if (io_error) {
fprintf(FINFO,"IO error encountered - skipping file deletion\n");
return;
}
if (io_error) {
fprintf(FINFO,"IO error encountered - skipping file deletion\n");
return;
}
for (j=0;j<flist->count;j++) {
char *name = f_name(flist->files[j]);
for (j=0;j<flist->count;j++) {
if (!S_ISDIR(flist->files[j]->mode) ||
!(flist->files[j]->flags & FLAG_DELETE)) continue;
if (!S_ISDIR(flist->files[j]->mode)) continue;
if (delete_already_done(flist, j)) continue;
if (strlen(name)<2 || strcmp(name+strlen(name)-2,"/.")!=0) continue;
name = strdup(f_name(flist->files[j]));
if (delete_already_done(flist, j)) continue;
if (!(local_file_list = send_file_list(-1,1,&name))) {
free(name);
continue;
}
if (!(local_file_list = send_file_list(-1,1,&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;

View File

@@ -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;