added SIGPIPE catch
[rsync/rsync.git] / flist.c
CommitLineData
c627d613
AT
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
24extern int verbose;
25extern int am_server;
26extern int always_checksum;
27extern off_t total_size;
28
29extern int cvs_exclude;
30
31extern int one_file_system;
32extern int make_backups;
33extern int preserve_links;
34extern int preserve_perms;
35extern int preserve_devices;
36extern int preserve_uid;
37extern int preserve_gid;
38extern int preserve_times;
39
40static char **local_exclude_list = NULL;
41
42static void clean_fname(char *name);
43
44
45/*
46 This function is used to check if a file should be included/excluded
47 from the list of files based on its name and type etc
48 */
49static int match_file_name(char *fname,struct stat *st)
50{
51 if (check_exclude(fname,local_exclude_list)) {
52 if (verbose > 2)
53 fprintf(stderr,"excluding file %s\n",fname);
54 return 0;
55 }
56 return 1;
57}
58
59/* used by the one_file_system code */
60static dev_t filesystem_dev;
61
62static void set_filesystem(char *fname)
63{
64 struct stat st;
65 if (lstat(fname,&st) != 0) return;
66 filesystem_dev = st.st_dev;
67}
68
69
70static void send_directory(int f,struct file_list *flist,char *dir);
71
72static char *flist_dir = NULL;
73
74static void send_file_entry(struct file_struct *file,int f)
75{
76 if (f == -1) return;
77
78 write_int(f,strlen(file->name));
79 write_buf(f,file->name,strlen(file->name));
80 write_int(f,(int)file->modtime);
81 write_int(f,(int)file->length);
82 write_int(f,(int)file->mode);
83 if (preserve_uid)
84 write_int(f,(int)file->uid);
85 if (preserve_gid)
86 write_int(f,(int)file->gid);
87 if (preserve_devices) {
88 if (verbose > 2)
89 fprintf(stderr,"dev=0x%x\n",(int)file->dev);
90 write_int(f,(int)file->dev);
91 }
92
93#if SUPPORT_LINKS
94 if (preserve_links && S_ISLNK(file->mode)) {
95 write_int(f,strlen(file->link));
96 write_buf(f,file->link,strlen(file->link));
97 }
98#endif
99
100 if (always_checksum) {
101 write_buf(f,file->sum,SUM_LENGTH);
102 }
103}
104
105
106static struct file_struct *make_file(int recurse,char *fname)
107{
108 static struct file_struct file;
109 struct stat st;
110 char sum[SUM_LENGTH];
111
112 bzero(sum,SUM_LENGTH);
113
114 if (lstat(fname,&st) != 0) {
115 fprintf(stderr,"%s: %s\n",
116 fname,strerror(errno));
117 return NULL;
118 }
119
120 if (S_ISDIR(st.st_mode) && !recurse) {
121 fprintf(stderr,"skipping directory %s\n",fname);
122 return NULL;
123 }
124
125 if (one_file_system && st.st_dev != filesystem_dev)
126 return NULL;
127
128 if (!match_file_name(fname,&st))
129 return NULL;
130
131 if (verbose > 2)
132 fprintf(stderr,"make_file(%s)\n",fname);
133
134 file.name = strdup(fname);
135 file.modtime = st.st_mtime;
136 file.length = st.st_size;
137 file.mode = st.st_mode;
138 file.uid = st.st_uid;
139 file.gid = st.st_gid;
140#ifdef HAVE_ST_RDEV
141 file.dev = st.st_rdev;
142#endif
143
144#if SUPPORT_LINKS
145 if (S_ISLNK(st.st_mode)) {
146 int l;
147 char lnk[MAXPATHLEN];
148 if ((l=readlink(fname,lnk,MAXPATHLEN-1)) == -1) {
149 fprintf(stderr,"readlink %s : %s\n",fname,strerror(errno));
150 return NULL;
151 }
152 lnk[l] = 0;
153 file.link = strdup(lnk);
154 }
155#endif
156
157 if (always_checksum && S_ISREG(st.st_mode)) {
158 file_checksum(fname,file.sum,st.st_size);
159 }
160
161 if (flist_dir)
162 file.dir = strdup(flist_dir);
163 else
164 file.dir = NULL;
165
166 if (!S_ISDIR(st.st_mode))
167 total_size += st.st_size;
168
169 return &file;
170}
171
172
173
174static void send_file_name(int f,struct file_list *flist,
175 int recurse,char *fname)
176{
177 struct file_struct *file;
178
179 file = make_file(recurse,fname);
180
181 if (!file) return;
182
183 if (flist->count >= flist->malloced) {
184 flist->malloced += 100;
185 flist->files = (struct file_struct *)realloc(flist->files,
186 sizeof(flist->files[0])*
187 flist->malloced);
188 if (!flist->files)
189 out_of_memory("send_file_name");
190 }
191
192 if (strcmp(file->name,".") && strcmp(file->name,"/")) {
193 flist->files[flist->count++] = *file;
194 send_file_entry(file,f);
195 }
196
197 if (S_ISDIR(file->mode) && recurse) {
198 char **last_exclude_list = local_exclude_list;
199 send_directory(f,flist,file->name);
200 local_exclude_list = last_exclude_list;
201 return;
202 }
203}
204
205
206
207static void send_directory(int f,struct file_list *flist,char *dir)
208{
209 DIR *d;
210 struct dirent *di;
211 char fname[MAXPATHLEN];
212 int l;
213 char *p;
214
215 d = opendir(dir);
216 if (!d) {
217 fprintf(stderr,"%s: %s\n",
218 dir,strerror(errno));
219 return;
220 }
221
222 strcpy(fname,dir);
223 l = strlen(fname);
224 if (fname[l-1] != '/')
225 strcat(fname,"/");
226 p = fname + strlen(fname);
227
228 if (cvs_exclude) {
229 strcpy(p,".cvsignore");
230 local_exclude_list = make_exclude_list(fname,NULL,0);
231 }
232
233 for (di=readdir(d); di; di=readdir(d)) {
234 if (strcmp(di->d_name,".")==0 ||
235 strcmp(di->d_name,"..")==0)
236 continue;
237 strcpy(p,di->d_name);
238 send_file_name(f,flist,1,fname);
239 }
240
241 closedir(d);
242}
243
244
245
246struct file_list *send_file_list(int f,int recurse,int argc,char *argv[])
247{
248 int i,l;
249 struct stat st;
250 char *p,*dir;
251 char dbuf[MAXPATHLEN];
252 struct file_list *flist;
253
254 if (verbose && recurse) {
255 fprintf(am_server?stderr:stdout,"building file list ... ");
256 fflush(am_server?stderr:stdout);
257 }
258
259 flist = (struct file_list *)malloc(sizeof(flist[0]));
260 if (!flist) out_of_memory("send_file_list");
261
262 flist->count=0;
263 flist->malloced = 100;
264 flist->files = (struct file_struct *)malloc(sizeof(flist->files[0])*
265 flist->malloced);
266 if (!flist->files) out_of_memory("send_file_list");
267
268 for (i=0;i<argc;i++) {
269 char fname2[MAXPATHLEN];
270 char *fname = fname2;
271
272 strcpy(fname,argv[i]);
273
274 l = strlen(fname);
275 if (l != 1 && fname[l-1] == '/') {
276 strcat(fname,".");
277 }
278
279 if (lstat(fname,&st) != 0) {
280 fprintf(stderr,"%s : %s\n",fname,strerror(errno));
281 continue;
282 }
283
284 if (S_ISDIR(st.st_mode) && !recurse) {
285 fprintf(stderr,"skipping directory %s\n",fname);
286 continue;
287 }
288
289 dir = NULL;
290 p = strrchr(fname,'/');
291 if (p) {
292 *p = 0;
293 dir = fname;
294 fname = p+1;
295 }
296 if (!*fname)
297 fname = ".";
298
299 if (dir && *dir) {
300 if (getcwd(dbuf,MAXPATHLEN-1) == NULL) {
301 fprintf(stderr,"getwd : %s\n",strerror(errno));
302 exit(1);
303 }
304 if (chdir(dir) != 0) {
305 fprintf(stderr,"chdir %s : %s\n",dir,strerror(errno));
306 continue;
307 }
308 flist_dir = dir;
309 if (one_file_system)
310 set_filesystem(fname);
311 send_file_name(f,flist,recurse,fname);
312 flist_dir = NULL;
313 if (chdir(dbuf) != 0) {
314 fprintf(stderr,"chdir %s : %s\n",dbuf,strerror(errno));
315 exit(1);
316 }
317 continue;
318 }
319
320 if (one_file_system)
321 set_filesystem(fname);
322 send_file_name(f,flist,recurse,fname);
323 }
324
325 if (f != -1) {
326 write_int(f,0);
327 write_flush(f);
328 }
329
330 clean_flist(flist);
331
332 if (verbose && recurse)
333 fprintf(am_server?stderr:stdout,"done\n");
334
335 return flist;
336}
337
338
339struct file_list *recv_file_list(int f)
340{
341 int l;
342 struct file_list *flist;
343
344 if (verbose > 2)
345 fprintf(stderr,"recv_file_list starting\n");
346
347 flist = (struct file_list *)malloc(sizeof(flist[0]));
348 if (!flist)
349 goto oom;
350
351 flist->count=0;
352 flist->malloced=100;
353 flist->files = (struct file_struct *)malloc(sizeof(flist->files[0])*
354 flist->malloced);
355 if (!flist->files)
356 goto oom;
357
358
359 for (l=read_int(f); l; l=read_int(f)) {
360 int i = flist->count;
361
362 if (i >= flist->malloced) {
363 flist->malloced += 100;
364 flist->files =(struct file_struct *)realloc(flist->files,
365 sizeof(flist->files[0])*
366 flist->malloced);
367 if (!flist->files)
368 goto oom;
369 }
370
371 flist->files[i].name = (char *)malloc(l+1);
372 if (!flist->files[i].name)
373 goto oom;
374
375 read_buf(f,flist->files[i].name,l);
376 flist->files[i].name[l] = 0;
377 flist->files[i].modtime = (time_t)read_int(f);
378 flist->files[i].length = (off_t)read_int(f);
379 flist->files[i].mode = (mode_t)read_int(f);
380 if (preserve_uid)
381 flist->files[i].uid = (uid_t)read_int(f);
382 if (preserve_gid)
383 flist->files[i].gid = (gid_t)read_int(f);
384 if (preserve_devices)
385 flist->files[i].dev = (dev_t)read_int(f);
386
387#if SUPPORT_LINKS
388 if (preserve_links && S_ISLNK(flist->files[i].mode)) {
389 int l = read_int(f);
390 flist->files[i].link = (char *)malloc(l+1);
391 read_buf(f,flist->files[i].link,l);
392 flist->files[i].link[l] = 0;
393 }
394#endif
395
396 if (always_checksum)
397 read_buf(f,flist->files[i].sum,SUM_LENGTH);
398
399 if (S_ISREG(flist->files[i].mode))
400 total_size += flist->files[i].length;
401
402 flist->count++;
403
404 if (verbose > 2)
405 fprintf(stderr,"recv_file_name(%s)\n",flist->files[i].name);
406 }
407
408
409 if (verbose > 2)
410 fprintf(stderr,"received %d names\n",flist->count);
411
412 clean_flist(flist);
413
414 return flist;
415
416oom:
417 out_of_memory("recv_file_list");
418 return NULL; /* not reached */
419}
420
421
422static int flist_compare(struct file_struct *f1,struct file_struct *f2)
423{
424 if (!f1->name && !f2->name) return 0;
425 if (!f1->name) return -1;
426 if (!f2->name) return 1;
427 return strcmp(f1->name,f2->name);
428}
429
430
431int flist_find(struct file_list *flist,struct file_struct *f)
432{
433 int low=0,high=flist->count;
434
435 while (low != high) {
436 int mid = (low+high)/2;
437 int ret = flist_compare(&flist->files[mid],f);
438 if (ret == 0) return mid;
439 if (ret > 0)
440 high=mid;
441 else
442 low=mid+1;
443 }
444 if (flist_compare(&flist->files[low],f) == 0)
445 return low;
446 return -1;
447}
448
449
450static void clean_fname(char *name)
451{
452 char *p;
453 int l;
454 int modified = 1;
455
456 if (!name) return;
457
458 while (modified) {
459 modified = 0;
460
461 if ((p=strstr(name,"/./"))) {
462 modified = 1;
463 while (*p) {
464 p[0] = p[2];
465 p++;
466 }
467 }
468
469 if ((p=strstr(name,"//"))) {
470 modified = 1;
471 while (*p) {
472 p[0] = p[1];
473 p++;
474 }
475 }
476
477 if (strncmp(p=name,"./",2) == 0) {
478 modified = 1;
479 while (*p) {
480 p[0] = p[2];
481 p++;
482 }
483 }
484
485 l = strlen(p=name);
486 if (l > 1 && p[l-1] == '/') {
487 modified = 1;
488 p[l-1] = 0;
489 }
490 }
491}
492
493
494/*
495 * This routine ensures we don't have any duplicate names in our file list.
496 * duplicate names can cause corruption because of the pipelining
497 */
498void clean_flist(struct file_list *flist)
499{
500 int i;
501
502 if (!flist || flist->count == 0)
503 return;
504
505 for (i=0;i<flist->count;i++) {
506 clean_fname(flist->files[i].name);
507 }
508
509 qsort(flist->files,flist->count,
510 sizeof(flist->files[0]),
511 (int (*)())flist_compare);
512
513 for (i=1;i<flist->count;i++) {
514 if (flist->files[i].name &&
515 strcmp(flist->files[i].name,flist->files[i-1].name) == 0) {
516 if (verbose > 1 && !am_server)
517 fprintf(stderr,"removing duplicate name %s from file list\n",
518 flist->files[i].name);
519 free(flist->files[i-1].name);
520 flist->files[i-1].name = NULL;
521 }
522 }
523}
524