Compare commits

...

4 Commits

Author SHA1 Message Date
rsync-bugs
1f1b3b8ee7 preparing for release of 1.7.4 1998-04-17 06:49:05 +00:00
Andrew Tridgell
5806b30f0f this is a little test script to test some of rsyncs features
(contributed by Phil Hands)
1998-04-17 06:08:59 +00:00
Andrew Tridgell
3333ffbd43 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.
1998-04-17 06:07:23 +00:00
Andrew Tridgell
a16bbc3990 a few code cleanups 1998-04-13 07:26:37 +00:00
7 changed files with 180 additions and 122 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);
}

82
hlink.c
View File

@@ -31,10 +31,10 @@ static int hlink_compare(struct file_struct *f1,struct file_struct *f2)
if (!S_ISREG(f2->mode)) return 1;
if (f1->dev != f2->dev)
return (int)(f1->dev - f2->dev);
return (int)(f1->dev>f2->dev?1:-1);
if (f1->inode != f2->inode)
return (f1->inode - f2->inode);
return (int)(f1->inode>f2->inode?1:-1);
return file_compare(&f1,&f2);
}
@@ -103,47 +103,55 @@ int check_hard_link(struct file_struct *file)
}
#if SUPPORT_HARD_LINKS
static void hard_link_one(int i)
{
struct stat st1,st2;
if (link_stat(f_name(&hlink_list[i-1]),&st1) != 0) return;
if (link_stat(f_name(&hlink_list[i]),&st2) != 0) {
if (do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
fprintf(FINFO,"link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i-1]),strerror(errno));
return;
}
} else {
if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino) return;
if (do_unlink(f_name(&hlink_list[i])) != 0 ||
do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
fprintf(FINFO,"link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i-1]),strerror(errno));
return;
}
}
if (verbose > 0)
fprintf(FINFO,"%s => %s\n",
f_name(&hlink_list[i]),f_name(&hlink_list[i-1]));
}
#endif
/* create any hard links in the flist */
void do_hard_links(struct file_list *flist)
{
#if SUPPORT_HARD_LINKS
int i;
int i;
if (!hlink_list) return;
if (!hlink_list) return;
for (i=1;i<hlink_count;i++) {
if (S_ISREG(hlink_list[i].mode) &&
S_ISREG(hlink_list[i-1].mode) &&
hlink_list[i].basename && hlink_list[i-1].basename &&
hlink_list[i].dev == hlink_list[i-1].dev &&
hlink_list[i].inode == hlink_list[i-1].inode) {
struct stat st1,st2;
if (link_stat(f_name(&hlink_list[i-1]),&st1) != 0) continue;
if (link_stat(f_name(&hlink_list[i]),&st2) != 0) {
if (do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
fprintf(FINFO,"link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i-1]),strerror(errno));
continue;
for (i=1;i<hlink_count;i++) {
if (S_ISREG(hlink_list[i].mode) &&
S_ISREG(hlink_list[i-1].mode) &&
hlink_list[i].basename && hlink_list[i-1].basename &&
hlink_list[i].dev == hlink_list[i-1].dev &&
hlink_list[i].inode == hlink_list[i-1].inode) {
hard_link_one(i);
}
}
} else {
if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino) continue;
if (do_unlink(f_name(&hlink_list[i])) != 0 ||
do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
fprintf(FINFO,"link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i-1]),strerror(errno));
continue;
}
}
if (verbose > 0)
fprintf(FINFO,"%s => %s\n",
f_name(&hlink_list[i]),f_name(&hlink_list[i-1]));
}
}
#endif
}

View File

@@ -56,7 +56,7 @@ static tag *tag_table;
static int compare_targets(struct target *t1,struct target *t2)
{
return(t1->t - t2->t);
return((int)t1->t - (int)t2->t);
}

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;

54
test.sh Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/sh -e
# This is a simple test script that tests a few rsync
# features to make sure I haven't broken them before a release. Thanks
# to Phil Hands for writing this
export PATH=.:$PATH
TMP=/tmp/rsync-test.$$
F1=README
mkdir $TMP
pause() {
echo ... press enter to continue
read
}
echo "Test 1 basic operation"
rsync -av testin/ ${TMP}/rsync
diff -ur testin/ ${TMP}/rsync
pause
echo "Test 2 - one file"
rm ${TMP}/rsync/${F1}
rsync -av testin/ ${TMP}/rsync
diff -ur testin/ ${TMP}/rsync
pause
echo "Test 3 - extra data"
echo "extra line" >> ${TMP}/rsync/${F1}
rsync -av testin/ ${TMP}/rsync
diff -ur testin/ ${TMP}/rsync
pause
echo "Test 4 - --delete"
cp testin/${F1} ${TMP}/rsync/f1
rsync --delete -av testin/ ${TMP}/rsync
diff -ur testin/ ${TMP}/rsync
pause
echo "Test 5 (uses ssh, so will fail if you don't have it) "
rm -rf ${TMP}/rsync
rsync -av -e ssh testin/ localhost:${TMP}/rsync
diff -ur testin/ ${TMP}/rsync
pause
echo "Test 6 (uses ssh, so will fail if you don't have it) "
mv ${TMP}/rsync/${F1} ${TMP}/rsync/f1
rsync --delete -av -e ssh testin/ localhost:${TMP}/rsync
diff -ur testin/ ${TMP}/rsync
pause
rm -rf ${TMP}
echo Tests Completed

View File

@@ -1 +1 @@
#define VERSION "1.7.3"
#define VERSION "1.7.4"