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