*** empty log message ***
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index 4c8d59f..40158fa 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -21,6 +21,8 @@
 
 #include "rsync.h"
 
+extern int csum_length;
+
 extern int verbose;
 extern int am_server;
 extern int always_checksum;
@@ -28,20 +30,38 @@ extern off_t total_size;
 
 extern int cvs_exclude;
 
+extern int recurse;
+
 extern int one_file_system;
 extern int make_backups;
 extern int preserve_links;
+extern int preserve_hard_links;
 extern int preserve_perms;
 extern int preserve_devices;
 extern int preserve_uid;
 extern int preserve_gid;
 extern int preserve_times;
+extern int relative_paths;
+extern int copy_links;
 
 static char **local_exclude_list = NULL;
 
 static void clean_fname(char *name);
 
 
+int link_stat(const char *Path, struct stat *Buffer) 
+{
+#if SUPPORT_LINKS
+    if (copy_links) {
+       return stat(Path, Buffer);
+    } else {
+       return lstat(Path, Buffer);
+    }
+#else
+    return stat(Path, Buffer);
+#endif
+}
+
 /*
   This function is used to check if a file should be included/excluded
   from the list of files based on its name and type etc
@@ -50,7 +70,7 @@ static int match_file_name(char *fname,struct stat *st)
 {
   if (check_exclude(fname,local_exclude_list)) {
     if (verbose > 2)
-      fprintf(stderr,"excluding file %s\n",fname);
+      fprintf(FERROR,"excluding file %s\n",fname);
     return 0;
   }
   return 1;
@@ -62,7 +82,7 @@ static dev_t filesystem_dev;
 static void set_filesystem(char *fname)
 {
   struct stat st;
-  if (lstat(fname,&st) != 0) return;
+  if (link_stat(fname,&st) != 0) return;
   filesystem_dev = st.st_dev;
 }
 
@@ -71,22 +91,21 @@ static void send_directory(int f,struct file_list *flist,char *dir);
 
 static char *flist_dir = NULL;
 
-#define FILE_VALID 1
-#define SAME_MODE (1<<1)
-#define SAME_DEV (1<<2)
-#define SAME_UID (1<<3)
-#define SAME_GID (1<<4)
-#define SAME_DIR (1<<5)
+extern void (*send_file_entry)(struct file_struct *file,int f);
+extern void (*receive_file_entry)(struct file_struct *file,
+                                 unsigned char flags,int f);
+
 
-static void send_file_entry(struct file_struct *file,int f)
+void send_file_entry_v11(struct file_struct *file,int f)
 {
   unsigned char flags;
+  static time_t last_time=0;
   static mode_t last_mode=0;
-  static dev_t last_dev=0;
+  static dev_t last_rdev=0;
   static uid_t last_uid=0;
   static gid_t last_gid=0;
-  static char lastdir[MAXPATHLEN]="";
-  char *p=NULL;
+  static char lastname[MAXPATHLEN]="";
+  int l1,l2;
 
   if (f == -1) return;
 
@@ -98,30 +117,37 @@ static void send_file_entry(struct file_struct *file,int f)
   flags = FILE_VALID;
 
   if (file->mode == last_mode) flags |= SAME_MODE;
-  if (file->dev == last_dev) flags |= SAME_DEV;
+  if (file->rdev == last_rdev) flags |= SAME_RDEV;
   if (file->uid == last_uid) flags |= SAME_UID;
   if (file->gid == last_gid) flags |= SAME_GID;
-    
-  if (strncmp(file->name,lastdir,strlen(lastdir)) == 0) {
-    flags |= SAME_DIR;
-    p = file->name + strlen(lastdir);
-  } else {
-    p = file->name;
-  }
+  if (file->modtime == last_time) flags |= SAME_TIME;
+
+  for (l1=0;lastname[l1] && file->name[l1] == lastname[l1];l1++) ;
+  l2 = strlen(file->name) - l1;
+
+  if (l1 > 0) flags |= SAME_NAME;
+  if (l2 > 255) flags |= LONG_NAME;
+
+  write_byte(f,flags);  
+  if (flags & SAME_NAME)
+    write_byte(f,l1);
+  if (flags & LONG_NAME)
+    write_int(f,l2);
+  else
+    write_byte(f,l2);
+  write_buf(f,file->name+l1,l2);
 
-  write_byte(f,flags);
-  write_byte(f,strlen(p));
-  write_buf(f,p,strlen(p));
-  write_int(f,(int)file->modtime);
   write_int(f,(int)file->length);
+  if (!(flags & SAME_TIME))
+    write_int(f,(int)file->modtime);
   if (!(flags & SAME_MODE))
     write_int(f,(int)file->mode);
   if (preserve_uid && !(flags & SAME_UID))
     write_int(f,(int)file->uid);
   if (preserve_gid && !(flags & SAME_GID))
     write_int(f,(int)file->gid);
-  if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_DEV))
-    write_int(f,(int)file->dev);
+  if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_RDEV))
+    write_int(f,(int)file->rdev);
 
 #if SUPPORT_LINKS
   if (preserve_links && S_ISLNK(file->mode)) {
@@ -130,89 +156,98 @@ static void send_file_entry(struct file_struct *file,int f)
   }
 #endif
 
+#if SUPPORT_HARD_LINKS
+  if (preserve_hard_links && S_ISREG(file->mode)) {
+    write_int(f,file->dev);
+    write_int(f,file->inode);
+  }
+#endif
+
   if (always_checksum) {
-    write_buf(f,file->sum,SUM_LENGTH);
+    write_buf(f,file->sum,csum_length);
   }       
 
   last_mode = file->mode;
-  last_dev = file->dev;
+  last_rdev = file->rdev;
   last_uid = file->uid;
   last_gid = file->gid;
-  p = strrchr(file->name,'/');
-  if (p) {
-    int l = (int)(p - file->name) + 1;
-    strncpy(lastdir,file->name,l);
-    lastdir[l] = 0;
-  } else {
-    strcpy(lastdir,"");
-  }
+  last_time = file->modtime;
+
+  strncpy(lastname,file->name,MAXPATHLEN-1);
+  lastname[MAXPATHLEN-1] = 0;
 }
 
 
 
-static void receive_file_entry(struct file_struct *file,
-                              unsigned char flags,int f)
+void receive_file_entry_v11(struct file_struct *file,
+                           unsigned char flags,int f)
 {
+  static time_t last_time=0;
   static mode_t last_mode=0;
-  static dev_t last_dev=0;
+  static dev_t last_rdev=0;
   static uid_t last_uid=0;
   static gid_t last_gid=0;
-  static char lastdir[MAXPATHLEN]="";
-  char *p=NULL;
-  int l1,l2;
+  static char lastname[MAXPATHLEN]="";
+  int l1=0,l2=0;
 
-  l1 = read_byte(f);
-  if (flags & SAME_DIR)
-    l2 = strlen(lastdir);
+  if (flags & SAME_NAME)
+    l1 = read_byte(f);
+  
+  if (flags & LONG_NAME)
+    l2 = read_int(f);
   else
-    l2 = 0;
+    l2 = read_byte(f);
+
+  bzero((char *)file,sizeof(*file));
 
   file->name = (char *)malloc(l1+l2+1);
-  if (!file->name) out_of_memory("receive_file_entry");
+  if (!file->name) out_of_memory("receive_file_entry 1");
 
-  strncpy(file->name,lastdir,l2);
-  read_buf(f,file->name+l2,l1);
+  strncpy(file->name,lastname,l1);
+  read_buf(f,file->name+l1,l2);
   file->name[l1+l2] = 0;
 
-  file->modtime = (time_t)read_int(f);
   file->length = (off_t)read_int(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);
   if (preserve_uid)
     file->uid = (flags & SAME_UID) ? last_uid : (uid_t)read_int(f);
   if (preserve_gid)
     file->gid = (flags & SAME_GID) ? last_gid : (gid_t)read_int(f);
   if (preserve_devices && IS_DEVICE(file->mode))
-    file->dev = (flags & SAME_DEV) ? last_dev : (dev_t)read_int(f);
+    file->rdev = (flags & SAME_RDEV) ? last_rdev : (dev_t)read_int(f);
 
-#if SUPPORT_LINKS
   if (preserve_links && S_ISLNK(file->mode)) {
     int l = read_int(f);
     file->link = (char *)malloc(l+1);
-    if (!file->link) out_of_memory("receive_file_entry");
+    if (!file->link) out_of_memory("receive_file_entry 2");
     read_buf(f,file->link,l);
     file->link[l] = 0;
   }
+
+#if SUPPORT_HARD_LINKS
+  if (preserve_hard_links && S_ISREG(file->mode)) {
+    file->dev = read_int(f);
+    file->inode = read_int(f);
+  }
 #endif
   
   if (always_checksum)
-    read_buf(f,file->sum,SUM_LENGTH);
+    read_buf(f,file->sum,csum_length);
   
   last_mode = file->mode;
-  last_dev = file->dev;
+  last_rdev = file->rdev;
   last_uid = file->uid;
   last_gid = file->gid;
-  p = strrchr(file->name,'/');
-  if (p) {
-    int l = (int)(p - file->name) + 1;
-    strncpy(lastdir,file->name,l);
-    lastdir[l] = 0;
-  } else {
-    strcpy(lastdir,"");
-  }
+  last_time = file->modtime;
+
+  strncpy(lastname,file->name,MAXPATHLEN-1);
+  lastname[MAXPATHLEN-1] = 0;
 }
 
 
-static struct file_struct *make_file(int recurse,char *fname)
+
+static struct file_struct *make_file(char *fname)
 {
   static struct file_struct file;
   struct stat st;
@@ -220,14 +255,14 @@ static struct file_struct *make_file(int recurse,char *fname)
 
   bzero(sum,SUM_LENGTH);
 
-  if (lstat(fname,&st) != 0) {
-    fprintf(stderr,"%s: %s\n",
+  if (link_stat(fname,&st) != 0) {
+    fprintf(FERROR,"%s: %s\n",
            fname,strerror(errno));
     return NULL;
   }
 
   if (S_ISDIR(st.st_mode) && !recurse) {
-    fprintf(stderr,"skipping directory %s\n",fname);
+    fprintf(FERROR,"skipping directory %s\n",fname);
     return NULL;
   }
 
@@ -238,7 +273,9 @@ static struct file_struct *make_file(int recurse,char *fname)
     return NULL;
 
   if (verbose > 2)
-    fprintf(stderr,"make_file(%s)\n",fname);
+    fprintf(FERROR,"make_file(%s)\n",fname);
+
+  bzero((char *)&file,sizeof(file));
 
   file.name = strdup(fname);
   file.modtime = st.st_mtime;
@@ -246,8 +283,10 @@ static struct file_struct *make_file(int recurse,char *fname)
   file.mode = st.st_mode;
   file.uid = st.st_uid;
   file.gid = st.st_gid;
+  file.dev = st.st_dev;
+  file.inode = st.st_ino;
 #ifdef HAVE_ST_RDEV
-  file.dev = st.st_rdev;
+  file.rdev = st.st_rdev;
 #endif
 
 #if SUPPORT_LINKS
@@ -255,7 +294,7 @@ static struct file_struct *make_file(int recurse,char *fname)
     int l;
     char lnk[MAXPATHLEN];
     if ((l=readlink(fname,lnk,MAXPATHLEN-1)) == -1) {
-      fprintf(stderr,"readlink %s : %s\n",fname,strerror(errno));
+      fprintf(FERROR,"readlink %s : %s\n",fname,strerror(errno));
       return NULL;
     }
     lnk[l] = 0;
@@ -280,25 +319,27 @@ static struct file_struct *make_file(int recurse,char *fname)
 
 
 
-static void send_file_name(int f,struct file_list *flist,
-                          int recurse,char *fname)
+static void send_file_name(int f,struct file_list *flist,char *fname)
 {
   struct file_struct *file;
 
-  file = make_file(recurse,fname);
+  file = make_file(fname);
 
   if (!file) return;  
   
   if (flist->count >= flist->malloced) {
-    flist->malloced += 100;
-    flist->files = (struct file_struct *)realloc(flist->files,
-                                                sizeof(flist->files[0])*
-                                                flist->malloced);
-    if (!flist->files)
-      out_of_memory("send_file_name");
+         if (flist->malloced < 100)
+                 flist->malloced += 100;
+         else
+                 flist->malloced *= 1.8;
+         flist->files = (struct file_struct *)realloc(flist->files,
+                                                      sizeof(flist->files[0])*
+                                                      flist->malloced);
+         if (!flist->files)
+                 out_of_memory("send_file_name");
   }
 
-  if (strcmp(file->name,".") && strcmp(file->name,"/")) {
+  if (strcmp(file->name,"/")) {
     flist->files[flist->count++] = *file;    
     send_file_entry(file,f);
   }
@@ -323,28 +364,40 @@ static void send_directory(int f,struct file_list *flist,char *dir)
 
   d = opendir(dir);
   if (!d) {
-    fprintf(stderr,"%s: %s\n",
+    fprintf(FERROR,"%s: %s\n",
            dir,strerror(errno));
     return;
   }
 
-  strcpy(fname,dir);
+  strncpy(fname,dir,MAXPATHLEN-1);
+  fname[MAXPATHLEN-1]=0;
   l = strlen(fname);
-  if (fname[l-1] != '/')
-    strcat(fname,"/");
+  if (fname[l-1] != '/') {
+        if (l == MAXPATHLEN-1) {
+              fprintf(FERROR,"skipping long-named directory %s\n",fname);
+              closedir(d);
+              return;
+        }
+         strcat(fname,"/");
+         l++;
+  }
   p = fname + strlen(fname);
 
   if (cvs_exclude) {
-    strcpy(p,".cvsignore");
-    local_exclude_list = make_exclude_list(fname,NULL,0);
+    if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN-1) {
+      strcpy(p,".cvsignore");
+      local_exclude_list = make_exclude_list(fname,NULL,0);
+    } else {
+      fprintf(FERROR,"cannot cvs-exclude in long-named directory %s\n",fname);
+    }
   }  
 
   for (di=readdir(d); di; di=readdir(d)) {
     if (strcmp(di->d_name,".")==0 ||
        strcmp(di->d_name,"..")==0)
       continue;
-    strcpy(p,di->d_name);
-    send_file_name(f,flist,1,fname);
+    strncpy(p,di->d_name,MAXPATHLEN-(l+1));
+    send_file_name(f,flist,fname);
   }
 
   closedir(d);
@@ -352,7 +405,7 @@ static void send_directory(int f,struct file_list *flist,char *dir)
 
 
 
-struct file_list *send_file_list(int f,int recurse,int argc,char *argv[])
+struct file_list *send_file_list(int f,int argc,char *argv[])
 {
   int i,l;
   struct stat st;
@@ -360,9 +413,9 @@ struct file_list *send_file_list(int f,int recurse,int argc,char *argv[])
   char dbuf[MAXPATHLEN];
   struct file_list *flist;
 
-  if (verbose && recurse) {
-    fprintf(am_server?stderr:stdout,"building file list ... ");
-    fflush(am_server?stderr:stdout);
+  if (verbose && recurse && !am_server && f != -1) {
+    fprintf(FINFO,"building file list ... ");
+    fflush(FINFO);
   }
 
   flist = (struct file_list *)malloc(sizeof(flist[0]));
@@ -378,57 +431,65 @@ struct file_list *send_file_list(int f,int recurse,int argc,char *argv[])
     char fname2[MAXPATHLEN];
     char *fname = fname2;
 
-    strcpy(fname,argv[i]);
+    strncpy(fname,argv[i],MAXPATHLEN-1);
+    fname[MAXPATHLEN-1] = 0;
 
     l = strlen(fname);
     if (l != 1 && fname[l-1] == '/') {
       strcat(fname,".");
     }
 
-    if (lstat(fname,&st) != 0) {
-      fprintf(stderr,"%s : %s\n",fname,strerror(errno));
+    if (link_stat(fname,&st) != 0) {
+      fprintf(FERROR,"%s : %s\n",fname,strerror(errno));
       continue;
     }
 
     if (S_ISDIR(st.st_mode) && !recurse) {
-      fprintf(stderr,"skipping directory %s\n",fname);
+      fprintf(FERROR,"skipping directory %s\n",fname);
       continue;
     }
 
     dir = NULL;
-    p = strrchr(fname,'/');
-    if (p) {
-      *p = 0;
-      dir = fname;
-      fname = p+1;      
+
+    if (!relative_paths) {
+           p = strrchr(fname,'/');
+           if (p) {
+                   *p = 0;
+                   if (p == fname) 
+                           dir = "/";
+                   else
+                           dir = fname;      
+                   fname = p+1;      
+           }
     }
+
     if (!*fname)
       fname = ".";
 
     if (dir && *dir) {
       if (getcwd(dbuf,MAXPATHLEN-1) == NULL) {
-       fprintf(stderr,"getwd : %s\n",strerror(errno));
-       exit(1);
+       fprintf(FERROR,"getwd : %s\n",strerror(errno));
+       exit_cleanup(1);
       }
       if (chdir(dir) != 0) {
-       fprintf(stderr,"chdir %s : %s\n",dir,strerror(errno));
+       fprintf(FERROR,"chdir %s : %s\n",dir,strerror(errno));
        continue;
       }
       flist_dir = dir;
       if (one_file_system)
        set_filesystem(fname);
-      send_file_name(f,flist,recurse,fname);
+      send_file_name(f,flist,fname);
       flist_dir = NULL;
       if (chdir(dbuf) != 0) {
-       fprintf(stderr,"chdir %s : %s\n",dbuf,strerror(errno));
-       exit(1);
+       fprintf(FERROR,"chdir %s : %s\n",dbuf,strerror(errno));
+       exit_cleanup(1);
       }
       continue;
     }
 
     if (one_file_system)
       set_filesystem(fname);
-    send_file_name(f,flist,recurse,fname);
+    send_file_name(f,flist,fname);
   }
 
   if (f != -1) {
@@ -436,10 +497,10 @@ struct file_list *send_file_list(int f,int recurse,int argc,char *argv[])
     write_flush(f);
   }
 
-  clean_flist(flist);
+  if (verbose && recurse && !am_server && f != -1)
+    fprintf(FINFO,"done\n");
 
-  if (verbose && recurse)
-    fprintf(am_server?stderr:stdout,"done\n");
+  clean_flist(flist);
 
   return flist;
 }
@@ -450,8 +511,10 @@ struct file_list *recv_file_list(int f)
   struct file_list *flist;
   unsigned char flags;
 
-  if (verbose > 2)
-    fprintf(stderr,"recv_file_list starting\n");
+  if (verbose && recurse && !am_server) {
+    fprintf(FINFO,"receiving file list ... ");
+    fflush(FINFO);
+  }
 
   flist = (struct file_list *)malloc(sizeof(flist[0]));
   if (!flist)
@@ -469,12 +532,15 @@ struct file_list *recv_file_list(int f)
     int i = flist->count;
 
     if (i >= flist->malloced) {
-      flist->malloced += 100;
-      flist->files =(struct file_struct *)realloc(flist->files,
-                                                 sizeof(flist->files[0])*
-                                                 flist->malloced);
-      if (!flist->files)
-       goto oom;
+         if (flist->malloced < 100)
+                 flist->malloced += 100;
+         else
+                 flist->malloced *= 1.8;
+         flist->files =(struct file_struct *)realloc(flist->files,
+                                                     sizeof(flist->files[0])*
+                                                     flist->malloced);
+         if (!flist->files)
+                 goto oom;
     }
 
     receive_file_entry(&flist->files[i],flags,f);
@@ -485,15 +551,19 @@ struct file_list *recv_file_list(int f)
     flist->count++;
 
     if (verbose > 2)
-      fprintf(stderr,"recv_file_name(%s)\n",flist->files[i].name);
+      fprintf(FERROR,"recv_file_name(%s)\n",flist->files[i].name);
   }
 
 
   if (verbose > 2)
-    fprintf(stderr,"received %d names\n",flist->count);
+    fprintf(FERROR,"received %d names\n",flist->count);
 
   clean_flist(flist);
 
+  if (verbose && recurse && !am_server) {
+    fprintf(FINFO,"done\n");
+  }
+
   return flist;
 
 oom:
@@ -502,7 +572,7 @@ oom:
 }
 
 
-static int flist_compare(struct file_struct *f1,struct file_struct *f2)
+int file_compare(struct file_struct *f1,struct file_struct *f2)
 {
   if (!f1->name && !f2->name) return 0;
   if (!f1->name) return -1;
@@ -513,20 +583,24 @@ static int flist_compare(struct file_struct *f1,struct file_struct *f2)
 
 int flist_find(struct file_list *flist,struct file_struct *f)
 {
-  int low=0,high=flist->count;
-
-  while (low != high) {
-    int mid = (low+high)/2;
-    int ret = flist_compare(&flist->files[mid],f);
-    if (ret == 0) return mid;
-    if (ret > 0) 
-      high=mid;
-    else
-      low=mid+1;
-  }
-  if (flist_compare(&flist->files[low],f) == 0)
-    return low;
-  return -1;
+       int low=0,high=flist->count-1;
+
+       if (flist->count <= 0) return -1;
+
+       while (low != high) {
+               int mid = (low+high)/2;
+               int ret = file_compare(&flist->files[flist_up(flist, mid)],f);
+               if (ret == 0) return flist_up(flist, mid);
+               if (ret > 0) {
+                       high=mid;
+               } else {
+                       low=mid+1;
+               }
+       }
+
+       if (file_compare(&flist->files[flist_up(flist,low)],f) == 0)
+               return flist_up(flist,low);
+       return -1;
 }
 
 
@@ -559,10 +633,9 @@ static void clean_fname(char *name)
 
     if (strncmp(p=name,"./",2) == 0) {      
       modified = 1;
-      while (*p) {
+      do {
        p[0] = p[2];
-       p++;
-      }
+      } while (*p++);
     }
 
     l = strlen(p=name);
@@ -591,17 +664,17 @@ void clean_flist(struct file_list *flist)
       
   qsort(flist->files,flist->count,
        sizeof(flist->files[0]),
-       (int (*)())flist_compare);
+       (int (*)())file_compare);
 
   for (i=1;i<flist->count;i++) {
     if (flist->files[i].name &&
        strcmp(flist->files[i].name,flist->files[i-1].name) == 0) {
       if (verbose > 1 && !am_server)
-       fprintf(stderr,"removing duplicate name %s from file list\n",
-               flist->files[i].name);
+       fprintf(FERROR,"removing duplicate name %s from file list %d\n",
+               flist->files[i-1].name,i-1);
       free(flist->files[i-1].name);
-      flist->files[i-1].name = NULL;
-    }
+      bzero((char *)&flist->files[i-1],sizeof(flist->files[i-1]));
+    } 
   }
 }