- check for sys/select.h
[rsync/rsync.git] / flist.c
1 /* 
2    Copyright (C) Andrew Tridgell 1996
3    Copyright (C) Paul Mackerras 1996
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /* generate and receive file lists */
21
22 #include "rsync.h"
23
24 extern int csum_length;
25
26 extern int verbose;
27 extern int am_server;
28 extern int always_checksum;
29 extern off_t total_size;
30
31 extern int cvs_exclude;
32
33 extern int recurse;
34
35 extern int one_file_system;
36 extern int make_backups;
37 extern int preserve_links;
38 extern int preserve_hard_links;
39 extern int preserve_perms;
40 extern int preserve_devices;
41 extern int preserve_uid;
42 extern int preserve_gid;
43 extern int preserve_times;
44
45 static char **local_exclude_list = NULL;
46
47 static void clean_fname(char *name);
48
49
50 /*
51   This function is used to check if a file should be included/excluded
52   from the list of files based on its name and type etc
53  */
54 static int match_file_name(char *fname,struct stat *st)
55 {
56   if (check_exclude(fname,local_exclude_list)) {
57     if (verbose > 2)
58       fprintf(FERROR,"excluding file %s\n",fname);
59     return 0;
60   }
61   return 1;
62 }
63
64 /* used by the one_file_system code */
65 static dev_t filesystem_dev;
66
67 static void set_filesystem(char *fname)
68 {
69   struct stat st;
70   if (lstat(fname,&st) != 0) return;
71   filesystem_dev = st.st_dev;
72 }
73
74
75 static void send_directory(int f,struct file_list *flist,char *dir);
76
77 static char *flist_dir = NULL;
78
79 extern void (*send_file_entry)(struct file_struct *file,int f);
80 extern void (*receive_file_entry)(struct file_struct *file,
81                                   unsigned char flags,int f);
82
83
84 void send_file_entry_v11(struct file_struct *file,int f)
85 {
86   unsigned char flags;
87   static time_t last_time=0;
88   static mode_t last_mode=0;
89   static dev_t last_rdev=0;
90   static uid_t last_uid=0;
91   static gid_t last_gid=0;
92   static char lastname[MAXPATHLEN]="";
93   int l1,l2;
94
95   if (f == -1) return;
96
97   if (!file) {
98     write_byte(f,0);
99     return;
100   }
101
102   flags = FILE_VALID;
103
104   if (file->mode == last_mode) flags |= SAME_MODE;
105   if (file->rdev == last_rdev) flags |= SAME_RDEV;
106   if (file->uid == last_uid) flags |= SAME_UID;
107   if (file->gid == last_gid) flags |= SAME_GID;
108   if (file->modtime == last_time) flags |= SAME_TIME;
109
110   for (l1=0;lastname[l1] && file->name[l1] == lastname[l1];l1++) ;
111   l2 = strlen(file->name) - l1;
112
113   if (l1 > 0) flags |= SAME_NAME;
114   if (l2 > 255) flags |= LONG_NAME;
115
116   write_byte(f,flags);  
117   if (flags & SAME_NAME)
118     write_byte(f,l1);
119   if (flags & LONG_NAME)
120     write_int(f,l2);
121   else
122     write_byte(f,l2);
123   write_buf(f,file->name+l1,l2);
124
125   write_int(f,(int)file->length);
126   if (!(flags & SAME_TIME))
127     write_int(f,(int)file->modtime);
128   if (!(flags & SAME_MODE))
129     write_int(f,(int)file->mode);
130   if (preserve_uid && !(flags & SAME_UID))
131     write_int(f,(int)file->uid);
132   if (preserve_gid && !(flags & SAME_GID))
133     write_int(f,(int)file->gid);
134   if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_RDEV))
135     write_int(f,(int)file->rdev);
136
137 #if SUPPORT_LINKS
138   if (preserve_links && S_ISLNK(file->mode)) {
139     write_int(f,strlen(file->link));
140     write_buf(f,file->link,strlen(file->link));
141   }
142 #endif
143
144 #if SUPPORT_HARD_LINKS
145   if (preserve_hard_links && S_ISREG(file->mode)) {
146     write_int(f,file->dev);
147     write_int(f,file->inode);
148   }
149 #endif
150
151   if (always_checksum) {
152     write_buf(f,file->sum,csum_length);
153   }       
154
155   last_mode = file->mode;
156   last_rdev = file->rdev;
157   last_uid = file->uid;
158   last_gid = file->gid;
159   last_time = file->modtime;
160
161   strcpy(lastname,file->name);
162   lastname[255] = 0;
163 }
164
165
166
167 void receive_file_entry_v11(struct file_struct *file,
168                             unsigned char flags,int f)
169 {
170   static time_t last_time=0;
171   static mode_t last_mode=0;
172   static dev_t last_rdev=0;
173   static uid_t last_uid=0;
174   static gid_t last_gid=0;
175   static char lastname[MAXPATHLEN]="";
176   int l1=0,l2=0;
177
178   if (flags & SAME_NAME)
179     l1 = read_byte(f);
180   
181   if (flags & LONG_NAME)
182     l2 = read_int(f);
183   else
184     l2 = read_byte(f);
185
186   bzero((char *)file,sizeof(*file));
187
188   file->name = (char *)malloc(l1+l2+1);
189   if (!file->name) out_of_memory("receive_file_entry");
190
191   strncpy(file->name,lastname,l1);
192   read_buf(f,file->name+l1,l2);
193   file->name[l1+l2] = 0;
194
195   file->length = (off_t)read_int(f);
196   file->modtime = (flags & SAME_TIME) ? last_time : (time_t)read_int(f);
197   file->mode = (flags & SAME_MODE) ? last_mode : (mode_t)read_int(f);
198   if (preserve_uid)
199     file->uid = (flags & SAME_UID) ? last_uid : (uid_t)read_int(f);
200   if (preserve_gid)
201     file->gid = (flags & SAME_GID) ? last_gid : (gid_t)read_int(f);
202   if (preserve_devices && IS_DEVICE(file->mode))
203     file->rdev = (flags & SAME_RDEV) ? last_rdev : (dev_t)read_int(f);
204
205 #if SUPPORT_LINKS
206   if (preserve_links && S_ISLNK(file->mode)) {
207     int l = read_int(f);
208     file->link = (char *)malloc(l+1);
209     if (!file->link) out_of_memory("receive_file_entry");
210     read_buf(f,file->link,l);
211     file->link[l] = 0;
212   }
213 #endif
214
215 #if SUPPORT_HARD_LINKS
216   if (preserve_hard_links && S_ISREG(file->mode)) {
217     file->dev = read_int(f);
218     file->inode = read_int(f);
219   }
220 #endif
221   
222   if (always_checksum)
223     read_buf(f,file->sum,csum_length);
224   
225   last_mode = file->mode;
226   last_rdev = file->rdev;
227   last_uid = file->uid;
228   last_gid = file->gid;
229   last_time = file->modtime;
230
231   strcpy(lastname,file->name);
232   lastname[255] = 0;
233 }
234
235
236
237 static struct file_struct *make_file(char *fname)
238 {
239   static struct file_struct file;
240   struct stat st;
241   char sum[SUM_LENGTH];
242
243   bzero(sum,SUM_LENGTH);
244
245   if (lstat(fname,&st) != 0) {
246     fprintf(FERROR,"%s: %s\n",
247             fname,strerror(errno));
248     return NULL;
249   }
250
251   if (S_ISDIR(st.st_mode) && !recurse) {
252     fprintf(FERROR,"skipping directory %s\n",fname);
253     return NULL;
254   }
255
256   if (one_file_system && st.st_dev != filesystem_dev)
257     return NULL;
258
259   if (!match_file_name(fname,&st))
260     return NULL;
261
262   if (verbose > 2)
263     fprintf(FERROR,"make_file(%s)\n",fname);
264
265   bzero((char *)&file,sizeof(file));
266
267   file.name = strdup(fname);
268   file.modtime = st.st_mtime;
269   file.length = st.st_size;
270   file.mode = st.st_mode;
271   file.uid = st.st_uid;
272   file.gid = st.st_gid;
273   file.dev = st.st_dev;
274   file.inode = st.st_ino;
275 #ifdef HAVE_ST_RDEV
276   file.rdev = st.st_rdev;
277 #endif
278
279 #if SUPPORT_LINKS
280   if (S_ISLNK(st.st_mode)) {
281     int l;
282     char lnk[MAXPATHLEN];
283     if ((l=readlink(fname,lnk,MAXPATHLEN-1)) == -1) {
284       fprintf(FERROR,"readlink %s : %s\n",fname,strerror(errno));
285       return NULL;
286     }
287     lnk[l] = 0;
288     file.link = strdup(lnk);
289   }
290 #endif
291
292   if (always_checksum && S_ISREG(st.st_mode)) {
293     file_checksum(fname,file.sum,st.st_size);
294   }       
295
296   if (flist_dir)
297     file.dir = strdup(flist_dir);
298   else
299     file.dir = NULL;
300
301   if (!S_ISDIR(st.st_mode))
302     total_size += st.st_size;
303
304   return &file;
305 }
306
307
308
309 static void send_file_name(int f,struct file_list *flist,char *fname)
310 {
311   struct file_struct *file;
312
313   file = make_file(fname);
314
315   if (!file) return;  
316   
317   if (flist->count >= flist->malloced) {
318     flist->malloced += 100;
319     flist->files = (struct file_struct *)realloc(flist->files,
320                                                  sizeof(flist->files[0])*
321                                                  flist->malloced);
322     if (!flist->files)
323       out_of_memory("send_file_name");
324   }
325
326   if (strcmp(file->name,".") && strcmp(file->name,"/")) {
327     flist->files[flist->count++] = *file;    
328     send_file_entry(file,f);
329   }
330
331   if (S_ISDIR(file->mode) && recurse) {
332     char **last_exclude_list = local_exclude_list;
333     send_directory(f,flist,file->name);
334     local_exclude_list = last_exclude_list;
335     return;
336   }
337 }
338
339
340
341 static void send_directory(int f,struct file_list *flist,char *dir)
342 {
343   DIR *d;
344   struct dirent *di;
345   char fname[MAXPATHLEN];
346   int l;
347   char *p;
348
349   d = opendir(dir);
350   if (!d) {
351     fprintf(FERROR,"%s: %s\n",
352             dir,strerror(errno));
353     return;
354   }
355
356   strcpy(fname,dir);
357   l = strlen(fname);
358   if (fname[l-1] != '/')
359     strcat(fname,"/");
360   p = fname + strlen(fname);
361
362   if (cvs_exclude) {
363     strcpy(p,".cvsignore");
364     local_exclude_list = make_exclude_list(fname,NULL,0);
365   }  
366
367   for (di=readdir(d); di; di=readdir(d)) {
368     if (strcmp(di->d_name,".")==0 ||
369         strcmp(di->d_name,"..")==0)
370       continue;
371     strcpy(p,di->d_name);
372     send_file_name(f,flist,fname);
373   }
374
375   closedir(d);
376 }
377
378
379
380 struct file_list *send_file_list(int f,int argc,char *argv[])
381 {
382   int i,l;
383   struct stat st;
384   char *p,*dir;
385   char dbuf[MAXPATHLEN];
386   struct file_list *flist;
387
388   if (verbose && recurse && !am_server) {
389     fprintf(FINFO,"building file list ... ");
390     fflush(FINFO);
391   }
392
393   flist = (struct file_list *)malloc(sizeof(flist[0]));
394   if (!flist) out_of_memory("send_file_list");
395
396   flist->count=0;
397   flist->malloced = 100;
398   flist->files = (struct file_struct *)malloc(sizeof(flist->files[0])*
399                                               flist->malloced);
400   if (!flist->files) out_of_memory("send_file_list");
401
402   for (i=0;i<argc;i++) {
403     char fname2[MAXPATHLEN];
404     char *fname = fname2;
405
406     strcpy(fname,argv[i]);
407
408     l = strlen(fname);
409     if (l != 1 && fname[l-1] == '/') {
410       strcat(fname,".");
411     }
412
413     if (lstat(fname,&st) != 0) {
414       fprintf(FERROR,"%s : %s\n",fname,strerror(errno));
415       continue;
416     }
417
418     if (S_ISDIR(st.st_mode) && !recurse) {
419       fprintf(FERROR,"skipping directory %s\n",fname);
420       continue;
421     }
422
423     dir = NULL;
424     p = strrchr(fname,'/');
425     if (p) {
426       *p = 0;
427       if (p == fname) 
428         dir = "/";
429       else
430         dir = fname;      
431       fname = p+1;      
432     }
433     if (!*fname)
434       fname = ".";
435
436     if (dir && *dir) {
437       if (getcwd(dbuf,MAXPATHLEN-1) == NULL) {
438         fprintf(FERROR,"getwd : %s\n",strerror(errno));
439         exit_cleanup(1);
440       }
441       if (chdir(dir) != 0) {
442         fprintf(FERROR,"chdir %s : %s\n",dir,strerror(errno));
443         continue;
444       }
445       flist_dir = dir;
446       if (one_file_system)
447         set_filesystem(fname);
448       send_file_name(f,flist,fname);
449       flist_dir = NULL;
450       if (chdir(dbuf) != 0) {
451         fprintf(FERROR,"chdir %s : %s\n",dbuf,strerror(errno));
452         exit_cleanup(1);
453       }
454       continue;
455     }
456
457     if (one_file_system)
458       set_filesystem(fname);
459     send_file_name(f,flist,fname);
460   }
461
462   if (f != -1) {
463     send_file_entry(NULL,f);
464     write_flush(f);
465   }
466
467   if (verbose && recurse && !am_server)
468     fprintf(FINFO,"done\n");
469
470   clean_flist(flist);
471
472   return flist;
473 }
474
475
476 struct file_list *recv_file_list(int f)
477 {
478   struct file_list *flist;
479   unsigned char flags;
480
481   if (verbose && recurse && !am_server) {
482     fprintf(FINFO,"receiving file list ... ");
483     fflush(FINFO);
484   }
485
486   flist = (struct file_list *)malloc(sizeof(flist[0]));
487   if (!flist)
488     goto oom;
489
490   flist->count=0;
491   flist->malloced=100;
492   flist->files = (struct file_struct *)malloc(sizeof(flist->files[0])*
493                                               flist->malloced);
494   if (!flist->files)
495     goto oom;
496
497
498   for (flags=read_byte(f); flags; flags=read_byte(f)) {
499     int i = flist->count;
500
501     if (i >= flist->malloced) {
502       flist->malloced += 100;
503       flist->files =(struct file_struct *)realloc(flist->files,
504                                                   sizeof(flist->files[0])*
505                                                   flist->malloced);
506       if (!flist->files)
507         goto oom;
508     }
509
510     receive_file_entry(&flist->files[i],flags,f);
511
512     if (S_ISREG(flist->files[i].mode))
513       total_size += flist->files[i].length;
514
515     flist->count++;
516
517     if (verbose > 2)
518       fprintf(FERROR,"recv_file_name(%s)\n",flist->files[i].name);
519   }
520
521
522   if (verbose > 2)
523     fprintf(FERROR,"received %d names\n",flist->count);
524
525   clean_flist(flist);
526
527   if (verbose && recurse && !am_server) {
528     fprintf(FINFO,"done\n");
529   }
530
531   return flist;
532
533 oom:
534     out_of_memory("recv_file_list");
535     return NULL; /* not reached */
536 }
537
538
539 int file_compare(struct file_struct *f1,struct file_struct *f2)
540 {
541   if (!f1->name && !f2->name) return 0;
542   if (!f1->name) return -1;
543   if (!f2->name) return 1;
544   return strcmp(f1->name,f2->name);
545 }
546
547
548 int flist_find(struct file_list *flist,struct file_struct *f)
549 {
550   int low=0,high=flist->count;
551
552   while (low != high) {
553     int mid = (low+high)/2;
554     int ret = file_compare(&flist->files[mid],f);
555     if (ret == 0) return mid;
556     if (ret > 0) 
557       high=mid;
558     else
559       low=mid+1;
560   }
561   if (file_compare(&flist->files[low],f) == 0)
562     return low;
563   return -1;
564 }
565
566
567 static void clean_fname(char *name)
568 {
569   char *p;
570   int l;
571   int modified = 1;
572
573   if (!name) return;
574
575   while (modified) {
576     modified = 0;
577
578     if ((p=strstr(name,"/./"))) {
579       modified = 1;
580       while (*p) {
581         p[0] = p[2];
582         p++;
583       }
584     }
585
586     if ((p=strstr(name,"//"))) {
587       modified = 1;
588       while (*p) {
589         p[0] = p[1];
590         p++;
591       }
592     }
593
594     if (strncmp(p=name,"./",2) == 0) {      
595       modified = 1;
596       while (*p) {
597         p[0] = p[2];
598         p++;
599       }
600     }
601
602     l = strlen(p=name);
603     if (l > 1 && p[l-1] == '/') {
604       modified = 1;
605       p[l-1] = 0;
606     }
607   }
608 }
609
610
611 /*
612  * This routine ensures we don't have any duplicate names in our file list.
613  * duplicate names can cause corruption because of the pipelining 
614  */
615 void clean_flist(struct file_list *flist)
616 {
617   int i;
618
619   if (!flist || flist->count == 0) 
620     return;
621   
622   for (i=0;i<flist->count;i++) {
623     clean_fname(flist->files[i].name);
624   }
625       
626   qsort(flist->files,flist->count,
627         sizeof(flist->files[0]),
628         (int (*)())file_compare);
629
630   for (i=1;i<flist->count;i++) {
631     if (flist->files[i].name &&
632         strcmp(flist->files[i].name,flist->files[i-1].name) == 0) {
633       if (verbose > 1 && !am_server)
634         fprintf(FERROR,"removing duplicate name %s from file list %d\n",
635                 flist->files[i-1].name,i-1);
636       free(flist->files[i-1].name);
637       bzero((char *)&flist->files[i-1],sizeof(flist->files[i-1]));
638     } 
639   }
640 }
641