Commit | Line | Data |
---|---|---|
c627d613 AT |
1 | /* |
2 | Copyright (C) Andrew Tridgell 1996 | |
3 | Copyright (C) Paul Mackerras 1996 | |
736a6a29 | 4 | Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org> |
c627d613 AT |
5 | |
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | */ | |
20 | ||
736a6a29 MP |
21 | /** @file flist.c |
22 | * Generate and receive file lists | |
23 | * | |
24 | * @todo Get rid of the string_area optimization. Efficiently | |
25 | * allocating blocks is the responsibility of the system's malloc | |
26 | * library, not of rsync. | |
27 | * | |
172875cf MP |
28 | * @sa http://lists.samba.org/pipermail/rsync/2000-June/002351.html |
29 | * | |
736a6a29 | 30 | **/ |
c627d613 AT |
31 | |
32 | #include "rsync.h" | |
33 | ||
a800434a AT |
34 | extern struct stats stats; |
35 | ||
c627d613 AT |
36 | extern int verbose; |
37 | extern int am_server; | |
38 | extern int always_checksum; | |
c627d613 AT |
39 | |
40 | extern int cvs_exclude; | |
41 | ||
a06d19e3 AT |
42 | extern int recurse; |
43 | ||
c627d613 AT |
44 | extern int one_file_system; |
45 | extern int make_backups; | |
46 | extern int preserve_links; | |
dc5ddbcc | 47 | extern int preserve_hard_links; |
c627d613 AT |
48 | extern int preserve_perms; |
49 | extern int preserve_devices; | |
50 | extern int preserve_uid; | |
51 | extern int preserve_gid; | |
52 | extern int preserve_times; | |
6574b4f7 | 53 | extern int relative_paths; |
82306bf6 | 54 | extern int copy_links; |
b5313607 | 55 | extern int copy_unsafe_links; |
f6c34742 | 56 | extern int remote_version; |
6ba9279f | 57 | extern int io_error; |
cb13abfe | 58 | extern int sanitize_paths; |
c627d613 | 59 | |
6902ed17 MP |
60 | extern int read_batch; |
61 | extern int write_batch; | |
62 | ||
b5313607 DD |
63 | static char topsrcname[MAXPATHLEN]; |
64 | ||
2b6b4d53 | 65 | static struct exclude_struct **local_exclude_list; |
c627d613 | 66 | |
3d382777 AT |
67 | static struct file_struct null_file; |
68 | ||
0199b05f AT |
69 | static void clean_flist(struct file_list *flist, int strip_root); |
70 | ||
58225000 MP |
71 | |
72 | static int show_build_progress_p(void) | |
73 | { | |
74 | extern int do_progress; | |
ebed4c3a | 75 | |
58225000 MP |
76 | return do_progress && verbose && recurse && !am_server; |
77 | } | |
78 | ||
79 | /** | |
80 | * True if we're local, etc, and should emit progress emssages. | |
81 | **/ | |
82 | static void emit_build_progress(const struct file_list *flist) | |
83 | { | |
ebed4c3a | 84 | rprintf(FINFO, " %d files...\r", flist->count); |
58225000 MP |
85 | } |
86 | ||
87 | ||
88 | static void finish_build_progress(const struct file_list *flist) | |
89 | { | |
90 | if (verbose && recurse && !am_server) { | |
91 | /* This overwrites the progress line, if any. */ | |
92 | rprintf(FINFO, RSYNC_NAME ": %d files to consider.\n", | |
93 | flist->count); | |
94 | } | |
95 | } | |
96 | ||
97 | ||
5c66303a | 98 | static struct string_area *string_area_new(int size) |
3d382777 AT |
99 | { |
100 | struct string_area *a; | |
101 | ||
ebed4c3a MP |
102 | if (size <= 0) |
103 | size = ARENA_SIZE; | |
3d382777 | 104 | a = malloc(sizeof(*a)); |
ebed4c3a MP |
105 | if (!a) |
106 | out_of_memory("string_area_new"); | |
3d382777 | 107 | a->current = a->base = malloc(size); |
ebed4c3a MP |
108 | if (!a->current) |
109 | out_of_memory("string_area_new buffer"); | |
3d382777 | 110 | a->end = a->base + size; |
5c66303a | 111 | a->next = NULL; |
3d382777 AT |
112 | |
113 | return a; | |
114 | } | |
115 | ||
5c66303a | 116 | static void string_area_free(struct string_area *a) |
3d382777 AT |
117 | { |
118 | struct string_area *next; | |
119 | ||
ebed4c3a | 120 | for (; a; a = next) { |
3d382777 AT |
121 | next = a->next; |
122 | free(a->base); | |
123 | } | |
124 | } | |
125 | ||
5c66303a | 126 | static char *string_area_malloc(struct string_area **ap, int size) |
3d382777 AT |
127 | { |
128 | char *p; | |
129 | struct string_area *a; | |
130 | ||
131 | /* does the request fit into the current space? */ | |
132 | a = *ap; | |
133 | if (a->current + size >= a->end) { | |
134 | /* no; get space, move new string_area to front of the list */ | |
135 | a = string_area_new(size > ARENA_SIZE ? size : ARENA_SIZE); | |
136 | a->next = *ap; | |
137 | *ap = a; | |
138 | } | |
139 | ||
140 | /* have space; do the "allocation." */ | |
141 | p = a->current; | |
142 | a->current += size; | |
143 | return p; | |
144 | } | |
145 | ||
5c66303a | 146 | static char *string_area_strdup(struct string_area **ap, const char *src) |
3d382777 | 147 | { |
ebed4c3a | 148 | char *dest = string_area_malloc(ap, strlen(src) + 1); |
3d382777 AT |
149 | return strcpy(dest, src); |
150 | } | |
f7632fc6 AT |
151 | |
152 | static void list_file_entry(struct file_struct *f) | |
153 | { | |
740819ef | 154 | char perms[11]; |
f7632fc6 | 155 | |
7212be92 DD |
156 | if (!f->basename) |
157 | /* this can happen if duplicate names were removed */ | |
158 | return; | |
159 | ||
740819ef MP |
160 | permstring(perms, f->mode); |
161 | ||
f7632fc6 | 162 | if (preserve_links && S_ISLNK(f->mode)) { |
ebed4c3a MP |
163 | rprintf(FINFO, "%s %11.0f %s %s -> %s\n", |
164 | perms, | |
165 | (double) f->length, timestring(f->modtime), | |
f7632fc6 AT |
166 | f_name(f), f->link); |
167 | } else { | |
ebed4c3a MP |
168 | rprintf(FINFO, "%s %11.0f %s %s\n", |
169 | perms, | |
170 | (double) f->length, timestring(f->modtime), | |
171 | f_name(f)); | |
f7632fc6 AT |
172 | } |
173 | } | |
174 | ||
175 | ||
ebed4c3a | 176 | int readlink_stat(const char *Path, STRUCT_STAT * Buffer, char *Linkbuf) |
b5313607 DD |
177 | { |
178 | #if SUPPORT_LINKS | |
179 | if (copy_links) { | |
180 | return do_stat(Path, Buffer); | |
181 | } | |
182 | if (do_lstat(Path, Buffer) == -1) { | |
183 | return -1; | |
184 | } | |
185 | if (S_ISLNK(Buffer->st_mode)) { | |
ab94af5c | 186 | int l; |
ebed4c3a MP |
187 | if ((l = |
188 | readlink((char *) Path, Linkbuf, | |
189 | MAXPATHLEN - 1)) == -1) { | |
b5313607 DD |
190 | return -1; |
191 | } | |
192 | Linkbuf[l] = 0; | |
193 | if (copy_unsafe_links && (topsrcname[0] != '\0') && | |
ebed4c3a | 194 | unsafe_symlink(Linkbuf, topsrcname)) { |
b5313607 DD |
195 | return do_stat(Path, Buffer); |
196 | } | |
197 | } | |
198 | return 0; | |
199 | #else | |
200 | return do_stat(Path, Buffer); | |
201 | #endif | |
202 | } | |
203 | ||
ebed4c3a | 204 | int link_stat(const char *Path, STRUCT_STAT * Buffer) |
82306bf6 AT |
205 | { |
206 | #if SUPPORT_LINKS | |
ebed4c3a MP |
207 | if (copy_links) { |
208 | return do_stat(Path, Buffer); | |
209 | } else { | |
210 | return do_lstat(Path, Buffer); | |
211 | } | |
82306bf6 | 212 | #else |
ebed4c3a | 213 | return do_stat(Path, Buffer); |
82306bf6 AT |
214 | #endif |
215 | } | |
216 | ||
c627d613 AT |
217 | /* |
218 | This function is used to check if a file should be included/excluded | |
219 | from the list of files based on its name and type etc | |
220 | */ | |
ebed4c3a | 221 | static int check_exclude_file(int f, char *fname, STRUCT_STAT * st) |
c627d613 | 222 | { |
76e26e10 DD |
223 | extern int delete_excluded; |
224 | ||
225 | /* f is set to -1 when calculating deletion file list */ | |
226 | if ((f == -1) && delete_excluded) { | |
227 | return 0; | |
228 | } | |
ebed4c3a | 229 | if (check_exclude(fname, local_exclude_list, st)) { |
76e26e10 DD |
230 | return 1; |
231 | } | |
232 | return 0; | |
c627d613 AT |
233 | } |
234 | ||
235 | /* used by the one_file_system code */ | |
236 | static dev_t filesystem_dev; | |
237 | ||
238 | static void set_filesystem(char *fname) | |
239 | { | |
ebed4c3a MP |
240 | STRUCT_STAT st; |
241 | if (link_stat(fname, &st) != 0) | |
242 | return; | |
243 | filesystem_dev = st.st_dev; | |
c627d613 AT |
244 | } |
245 | ||
246 | ||
b280a1f4 AT |
247 | static int to_wire_mode(mode_t mode) |
248 | { | |
efe3037c | 249 | if (S_ISLNK(mode) && (_S_IFLNK != 0120000)) { |
b280a1f4 AT |
250 | return (mode & ~(_S_IFMT)) | 0120000; |
251 | } | |
ebed4c3a | 252 | return (int) mode; |
b280a1f4 AT |
253 | } |
254 | ||
255 | static mode_t from_wire_mode(int mode) | |
256 | { | |
efe3037c AT |
257 | if ((mode & (_S_IFMT)) == 0120000 && (_S_IFLNK != 0120000)) { |
258 | return (mode & ~(_S_IFMT)) | _S_IFLNK; | |
b280a1f4 | 259 | } |
ebed4c3a | 260 | return (mode_t) mode; |
b280a1f4 AT |
261 | } |
262 | ||
263 | ||
ebed4c3a | 264 | static void send_directory(int f, struct file_list *flist, char *dir); |
c627d613 | 265 | |
3a6a366f | 266 | static char *flist_dir; |
c627d613 | 267 | |
3ec4dd97 | 268 | |
ebed4c3a MP |
269 | static void send_file_entry(struct file_struct *file, int f, |
270 | unsigned base_flags) | |
c627d613 | 271 | { |
72914a60 AT |
272 | unsigned char flags; |
273 | static time_t last_time; | |
274 | static mode_t last_mode; | |
275 | static dev_t last_rdev; | |
276 | static uid_t last_uid; | |
277 | static gid_t last_gid; | |
278 | static char lastname[MAXPATHLEN]; | |
279 | char *fname; | |
ebed4c3a | 280 | int l1, l2; |
72914a60 | 281 | |
ebed4c3a MP |
282 | if (f == -1) |
283 | return; | |
72914a60 AT |
284 | |
285 | if (!file) { | |
ebed4c3a | 286 | write_byte(f, 0); |
72914a60 AT |
287 | return; |
288 | } | |
289 | ||
290 | fname = f_name(file); | |
291 | ||
292 | flags = base_flags; | |
293 | ||
ebed4c3a MP |
294 | if (file->mode == last_mode) |
295 | flags |= SAME_MODE; | |
296 | if (file->rdev == last_rdev) | |
297 | flags |= SAME_RDEV; | |
298 | if (file->uid == last_uid) | |
299 | flags |= SAME_UID; | |
300 | if (file->gid == last_gid) | |
301 | flags |= SAME_GID; | |
302 | if (file->modtime == last_time) | |
303 | flags |= SAME_TIME; | |
304 | ||
305 | for (l1 = 0; | |
306 | lastname[l1] && (fname[l1] == lastname[l1]) && (l1 < 255); | |
307 | l1++); | |
72914a60 AT |
308 | l2 = strlen(fname) - l1; |
309 | ||
ebed4c3a MP |
310 | if (l1 > 0) |
311 | flags |= SAME_NAME; | |
312 | if (l2 > 255) | |
313 | flags |= LONG_NAME; | |
72914a60 AT |
314 | |
315 | /* we must make sure we don't send a zero flags byte or the other | |
316 | end will terminate the flist transfer */ | |
ebed4c3a MP |
317 | if (flags == 0 && !S_ISDIR(file->mode)) |
318 | flags |= FLAG_DELETE; | |
319 | if (flags == 0) | |
320 | flags |= LONG_NAME; | |
72914a60 | 321 | |
ebed4c3a | 322 | write_byte(f, flags); |
72914a60 | 323 | if (flags & SAME_NAME) |
ebed4c3a | 324 | write_byte(f, l1); |
72914a60 | 325 | if (flags & LONG_NAME) |
ebed4c3a | 326 | write_int(f, l2); |
72914a60 | 327 | else |
ebed4c3a MP |
328 | write_byte(f, l2); |
329 | write_buf(f, fname + l1, l2); | |
72914a60 | 330 | |
ebed4c3a | 331 | write_longint(f, file->length); |
72914a60 | 332 | if (!(flags & SAME_TIME)) |
ebed4c3a | 333 | write_int(f, (int) file->modtime); |
72914a60 | 334 | if (!(flags & SAME_MODE)) |
ebed4c3a | 335 | write_int(f, to_wire_mode(file->mode)); |
72914a60 AT |
336 | if (preserve_uid && !(flags & SAME_UID)) { |
337 | add_uid(file->uid); | |
ebed4c3a | 338 | write_int(f, (int) file->uid); |
72914a60 AT |
339 | } |
340 | if (preserve_gid && !(flags & SAME_GID)) { | |
341 | add_gid(file->gid); | |
ebed4c3a | 342 | write_int(f, (int) file->gid); |
72914a60 | 343 | } |
ebed4c3a MP |
344 | if (preserve_devices && IS_DEVICE(file->mode) |
345 | && !(flags & SAME_RDEV)) | |
346 | write_int(f, (int) file->rdev); | |
c627d613 AT |
347 | |
348 | #if SUPPORT_LINKS | |
72914a60 | 349 | if (preserve_links && S_ISLNK(file->mode)) { |
ebed4c3a MP |
350 | write_int(f, strlen(file->link)); |
351 | write_buf(f, file->link, strlen(file->link)); | |
72914a60 | 352 | } |
c627d613 AT |
353 | #endif |
354 | ||
dc5ddbcc | 355 | #if SUPPORT_HARD_LINKS |
72914a60 | 356 | if (preserve_hard_links && S_ISREG(file->mode)) { |
736a6a29 MP |
357 | if (remote_version < 26) { |
358 | /* 32-bit dev_t and ino_t */ | |
ebed4c3a MP |
359 | write_int(f, (int) file->dev); |
360 | write_int(f, (int) file->inode); | |
736a6a29 MP |
361 | } else { |
362 | /* 64-bit dev_t and ino_t */ | |
6abd193f MP |
363 | write_longint(f, file->dev); |
364 | write_longint(f, file->inode); | |
736a6a29 | 365 | } |
72914a60 | 366 | } |
dc5ddbcc AT |
367 | #endif |
368 | ||
72914a60 | 369 | if (always_checksum) { |
f855a7d0 | 370 | if (remote_version < 21) { |
ebed4c3a | 371 | write_buf(f, file->sum, 2); |
f855a7d0 | 372 | } else { |
ebed4c3a | 373 | write_buf(f, file->sum, MD4_SUM_LENGTH); |
f855a7d0 | 374 | } |
ebed4c3a | 375 | } |
182dca5c | 376 | |
72914a60 AT |
377 | last_mode = file->mode; |
378 | last_rdev = file->rdev; | |
379 | last_uid = file->uid; | |
380 | last_gid = file->gid; | |
381 | last_time = file->modtime; | |
4fe159a8 | 382 | |
ebed4c3a MP |
383 | strlcpy(lastname, fname, MAXPATHLEN); |
384 | lastname[MAXPATHLEN - 1] = 0; | |
182dca5c AT |
385 | } |
386 | ||
387 | ||
388 | ||
3333ffbd | 389 | static void receive_file_entry(struct file_struct **fptr, |
ebed4c3a | 390 | unsigned flags, int f) |
182dca5c | 391 | { |
72914a60 AT |
392 | static time_t last_time; |
393 | static mode_t last_mode; | |
394 | static dev_t last_rdev; | |
395 | static uid_t last_uid; | |
396 | static gid_t last_gid; | |
397 | static char lastname[MAXPATHLEN]; | |
398 | char thisname[MAXPATHLEN]; | |
ebed4c3a | 399 | unsigned int l1 = 0, l2 = 0; |
72914a60 AT |
400 | char *p; |
401 | struct file_struct *file; | |
402 | ||
403 | if (flags & SAME_NAME) | |
404 | l1 = read_byte(f); | |
ebed4c3a | 405 | |
72914a60 AT |
406 | if (flags & LONG_NAME) |
407 | l2 = read_int(f); | |
408 | else | |
409 | l2 = read_byte(f); | |
410 | ||
ebed4c3a MP |
411 | file = (struct file_struct *) malloc(sizeof(*file)); |
412 | if (!file) | |
413 | out_of_memory("receive_file_entry"); | |
414 | memset((char *) file, 0, sizeof(*file)); | |
72914a60 AT |
415 | (*fptr) = file; |
416 | ||
ebed4c3a MP |
417 | if (l2 >= MAXPATHLEN - l1) { |
418 | rprintf(FERROR, | |
419 | "overflow: flags=0x%x l1=%d l2=%d lastname=%s\n", | |
d0fd26aa AT |
420 | flags, l1, l2, lastname); |
421 | overflow("receive_file_entry"); | |
422 | } | |
72914a60 | 423 | |
ebed4c3a MP |
424 | strlcpy(thisname, lastname, l1 + 1); |
425 | read_sbuf(f, &thisname[l1], l2); | |
426 | thisname[l1 + l2] = 0; | |
72914a60 | 427 | |
ebed4c3a MP |
428 | strlcpy(lastname, thisname, MAXPATHLEN); |
429 | lastname[MAXPATHLEN - 1] = 0; | |
72914a60 AT |
430 | |
431 | clean_fname(thisname); | |
432 | ||
cb13abfe DD |
433 | if (sanitize_paths) { |
434 | sanitize_path(thisname, NULL); | |
435 | } | |
436 | ||
ebed4c3a | 437 | if ((p = strrchr(thisname, '/'))) { |
72914a60 AT |
438 | static char *lastdir; |
439 | *p = 0; | |
ebed4c3a | 440 | if (lastdir && strcmp(thisname, lastdir) == 0) { |
72914a60 AT |
441 | file->dirname = lastdir; |
442 | } else { | |
443 | file->dirname = strdup(thisname); | |
444 | lastdir = file->dirname; | |
445 | } | |
ebed4c3a | 446 | file->basename = strdup(p + 1); |
72914a60 AT |
447 | } else { |
448 | file->dirname = NULL; | |
449 | file->basename = strdup(thisname); | |
450 | } | |
451 | ||
ebed4c3a MP |
452 | if (!file->basename) |
453 | out_of_memory("receive_file_entry 1"); | |
72914a60 AT |
454 | |
455 | ||
456 | file->flags = flags; | |
457 | file->length = read_longint(f); | |
ebed4c3a MP |
458 | file->modtime = |
459 | (flags & SAME_TIME) ? last_time : (time_t) read_int(f); | |
460 | file->mode = | |
461 | (flags & SAME_MODE) ? last_mode : from_wire_mode(read_int(f)); | |
72914a60 | 462 | if (preserve_uid) |
ebed4c3a MP |
463 | file->uid = |
464 | (flags & SAME_UID) ? last_uid : (uid_t) read_int(f); | |
72914a60 | 465 | if (preserve_gid) |
ebed4c3a MP |
466 | file->gid = |
467 | (flags & SAME_GID) ? last_gid : (gid_t) read_int(f); | |
72914a60 | 468 | if (preserve_devices && IS_DEVICE(file->mode)) |
ebed4c3a MP |
469 | file->rdev = |
470 | (flags & SAME_RDEV) ? last_rdev : (dev_t) read_int(f); | |
72914a60 AT |
471 | |
472 | if (preserve_links && S_ISLNK(file->mode)) { | |
473 | int l = read_int(f); | |
9dd891bb | 474 | if (l < 0) { |
ebed4c3a | 475 | rprintf(FERROR, "overflow: l=%d\n", l); |
9dd891bb MP |
476 | overflow("receive_file_entry"); |
477 | } | |
ebed4c3a MP |
478 | file->link = (char *) malloc(l + 1); |
479 | if (!file->link) | |
480 | out_of_memory("receive_file_entry 2"); | |
481 | read_sbuf(f, file->link, l); | |
cb13abfe DD |
482 | if (sanitize_paths) { |
483 | sanitize_path(file->link, file->dirname); | |
484 | } | |
72914a60 | 485 | } |
dc5ddbcc | 486 | #if SUPPORT_HARD_LINKS |
72914a60 | 487 | if (preserve_hard_links && S_ISREG(file->mode)) { |
736a6a29 MP |
488 | if (remote_version < 26) { |
489 | file->dev = read_int(f); | |
490 | file->inode = read_int(f); | |
491 | } else { | |
492 | file->dev = read_longint(f); | |
493 | file->inode = read_longint(f); | |
494 | } | |
72914a60 | 495 | } |
dc5ddbcc | 496 | #endif |
ebed4c3a | 497 | |
72914a60 | 498 | if (always_checksum) { |
ebed4c3a MP |
499 | file->sum = (char *) malloc(MD4_SUM_LENGTH); |
500 | if (!file->sum) | |
501 | out_of_memory("md4 sum"); | |
f855a7d0 | 502 | if (remote_version < 21) { |
ebed4c3a | 503 | read_buf(f, file->sum, 2); |
f855a7d0 | 504 | } else { |
ebed4c3a | 505 | read_buf(f, file->sum, MD4_SUM_LENGTH); |
f855a7d0 | 506 | } |
72914a60 | 507 | } |
ebed4c3a | 508 | |
72914a60 AT |
509 | last_mode = file->mode; |
510 | last_rdev = file->rdev; | |
511 | last_uid = file->uid; | |
512 | last_gid = file->gid; | |
513 | last_time = file->modtime; | |
514 | ||
515 | if (!preserve_perms) { | |
516 | extern int orig_umask; | |
517 | /* set an appropriate set of permissions based on original | |
518 | permissions and umask. This emulates what GNU cp does */ | |
519 | file->mode &= ~orig_umask; | |
520 | } | |
c627d613 AT |
521 | } |
522 | ||
523 | ||
0c5f37d9 AT |
524 | /* determine if a file in a different filesstem should be skipped |
525 | when one_file_system is set. We bascally only want to include | |
526 | the mount points - but they can be hard to find! */ | |
ebed4c3a | 527 | static int skip_filesystem(char *fname, STRUCT_STAT * st) |
0c5f37d9 | 528 | { |
bcacc18b | 529 | STRUCT_STAT st2; |
0c5f37d9 AT |
530 | char *p = strrchr(fname, '/'); |
531 | ||
532 | /* skip all but directories */ | |
ebed4c3a MP |
533 | if (!S_ISDIR(st->st_mode)) |
534 | return 1; | |
0c5f37d9 AT |
535 | |
536 | /* if its not a subdirectory then allow */ | |
ebed4c3a MP |
537 | if (!p) |
538 | return 0; | |
0c5f37d9 AT |
539 | |
540 | *p = 0; | |
541 | if (link_stat(fname, &st2)) { | |
542 | *p = '/'; | |
543 | return 0; | |
544 | } | |
545 | *p = '/'; | |
ebed4c3a | 546 | |
0c5f37d9 AT |
547 | return (st2.st_dev != filesystem_dev); |
548 | } | |
4fe159a8 | 549 | |
3d382777 | 550 | #define STRDUP(ap, p) (ap ? string_area_strdup(ap, p) : strdup(p)) |
87a819ed MP |
551 | /* IRIX cc cares that the operands to the ternary have the same type. */ |
552 | #define MALLOC(ap, i) (ap ? (void*) string_area_malloc(ap, i) : malloc(i)) | |
3d382777 | 553 | |
66203a98 | 554 | /* create a file_struct for a named file */ |
ac1a0994 AT |
555 | struct file_struct *make_file(int f, char *fname, struct string_area **ap, |
556 | int noexcludes) | |
c627d613 | 557 | { |
3ec4dd97 | 558 | struct file_struct *file; |
bcacc18b | 559 | STRUCT_STAT st; |
3ec4dd97 AT |
560 | char sum[SUM_LENGTH]; |
561 | char *p; | |
562 | char cleaned_name[MAXPATHLEN]; | |
b5313607 | 563 | char linkbuf[MAXPATHLEN]; |
ac1a0994 | 564 | extern int module_id; |
3ec4dd97 | 565 | |
37f9805d | 566 | strlcpy(cleaned_name, fname, MAXPATHLEN); |
ebed4c3a | 567 | cleaned_name[MAXPATHLEN - 1] = 0; |
3ec4dd97 | 568 | clean_fname(cleaned_name); |
cb13abfe DD |
569 | if (sanitize_paths) { |
570 | sanitize_path(cleaned_name, NULL); | |
571 | } | |
3ec4dd97 AT |
572 | fname = cleaned_name; |
573 | ||
ebed4c3a | 574 | memset(sum, 0, SUM_LENGTH); |
3ec4dd97 | 575 | |
ebed4c3a | 576 | if (readlink_stat(fname, &st, linkbuf) != 0) { |
76e26e10 DD |
577 | int save_errno = errno; |
578 | if ((errno == ENOENT) && copy_links && !noexcludes) { | |
579 | /* symlink pointing nowhere, see if excluded */ | |
ebed4c3a MP |
580 | memset((char *) &st, 0, sizeof(st)); |
581 | if (check_exclude_file(f, fname, &st)) { | |
76e26e10 DD |
582 | /* file is excluded anyway, ignore silently */ |
583 | return NULL; | |
584 | } | |
585 | } | |
6ba9279f | 586 | io_error = 1; |
ebed4c3a MP |
587 | rprintf(FERROR, "readlink %s: %s\n", |
588 | fname, strerror(save_errno)); | |
3ec4dd97 AT |
589 | return NULL; |
590 | } | |
c627d613 | 591 | |
ac1a0994 | 592 | /* we use noexcludes from backup.c */ |
ebed4c3a MP |
593 | if (noexcludes) |
594 | goto skip_excludes; | |
ac1a0994 | 595 | |
3ec4dd97 | 596 | if (S_ISDIR(st.st_mode) && !recurse) { |
ebed4c3a | 597 | rprintf(FINFO, "skipping directory %s\n", fname); |
3ec4dd97 AT |
598 | return NULL; |
599 | } | |
ebed4c3a | 600 | |
0c5f37d9 AT |
601 | if (one_file_system && st.st_dev != filesystem_dev) { |
602 | if (skip_filesystem(fname, &st)) | |
603 | return NULL; | |
604 | } | |
ebed4c3a MP |
605 | |
606 | if (check_exclude_file(f, fname, &st)) | |
76e26e10 DD |
607 | return NULL; |
608 | ||
ac1a0994 | 609 | |
ebed4c3a | 610 | if (lp_ignore_nonreadable(module_id) && access(fname, R_OK) != 0) |
ac1a0994 AT |
611 | return NULL; |
612 | ||
ebed4c3a | 613 | skip_excludes: |
ac1a0994 | 614 | |
3ec4dd97 | 615 | if (verbose > 2) |
ebed4c3a MP |
616 | rprintf(FINFO, "make_file(%d,%s)\n", f, fname); |
617 | ||
618 | file = (struct file_struct *) malloc(sizeof(*file)); | |
619 | if (!file) | |
620 | out_of_memory("make_file"); | |
621 | memset((char *) file, 0, sizeof(*file)); | |
3ec4dd97 | 622 | |
ebed4c3a | 623 | if ((p = strrchr(fname, '/'))) { |
3ec4dd97 AT |
624 | static char *lastdir; |
625 | *p = 0; | |
ebed4c3a | 626 | if (lastdir && strcmp(fname, lastdir) == 0) { |
3ec4dd97 AT |
627 | file->dirname = lastdir; |
628 | } else { | |
a20aa42a | 629 | file->dirname = strdup(fname); |
3ec4dd97 AT |
630 | lastdir = file->dirname; |
631 | } | |
ebed4c3a | 632 | file->basename = STRDUP(ap, p + 1); |
3ec4dd97 AT |
633 | *p = '/'; |
634 | } else { | |
635 | file->dirname = NULL; | |
3d382777 | 636 | file->basename = STRDUP(ap, fname); |
3ec4dd97 | 637 | } |
c627d613 | 638 | |
3ec4dd97 AT |
639 | file->modtime = st.st_mtime; |
640 | file->length = st.st_size; | |
641 | file->mode = st.st_mode; | |
642 | file->uid = st.st_uid; | |
643 | file->gid = st.st_gid; | |
644 | file->dev = st.st_dev; | |
645 | file->inode = st.st_ino; | |
c627d613 | 646 | #ifdef HAVE_ST_RDEV |
3ec4dd97 | 647 | file->rdev = st.st_rdev; |
c627d613 AT |
648 | #endif |
649 | ||
650 | #if SUPPORT_LINKS | |
3ec4dd97 | 651 | if (S_ISLNK(st.st_mode)) { |
3d382777 | 652 | file->link = STRDUP(ap, linkbuf); |
3ec4dd97 | 653 | } |
c627d613 AT |
654 | #endif |
655 | ||
1250f24e | 656 | if (always_checksum) { |
ebed4c3a MP |
657 | file->sum = (char *) MALLOC(ap, MD4_SUM_LENGTH); |
658 | if (!file->sum) | |
659 | out_of_memory("md4 sum"); | |
1250f24e AT |
660 | /* drat. we have to provide a null checksum for non-regular |
661 | files in order to be compatible with earlier versions | |
662 | of rsync */ | |
663 | if (S_ISREG(st.st_mode)) { | |
ebed4c3a | 664 | file_checksum(fname, file->sum, st.st_size); |
1250f24e AT |
665 | } else { |
666 | memset(file->sum, 0, MD4_SUM_LENGTH); | |
667 | } | |
ebed4c3a | 668 | } |
c627d613 | 669 | |
3ec4dd97 AT |
670 | if (flist_dir) { |
671 | static char *lastdir; | |
ebed4c3a | 672 | if (lastdir && strcmp(lastdir, flist_dir) == 0) { |
3ec4dd97 AT |
673 | file->basedir = lastdir; |
674 | } else { | |
a20aa42a | 675 | file->basedir = strdup(flist_dir); |
3ec4dd97 AT |
676 | lastdir = file->basedir; |
677 | } | |
678 | } else { | |
679 | file->basedir = NULL; | |
680 | } | |
c627d613 | 681 | |
3ec4dd97 | 682 | if (!S_ISDIR(st.st_mode)) |
a800434a | 683 | stats.total_size += st.st_size; |
c627d613 | 684 | |
3ec4dd97 | 685 | return file; |
c627d613 AT |
686 | } |
687 | ||
688 | ||
689 | ||
ebed4c3a MP |
690 | void send_file_name(int f, struct file_list *flist, char *fname, |
691 | int recursive, unsigned base_flags) | |
c627d613 | 692 | { |
ebed4c3a MP |
693 | struct file_struct *file; |
694 | ||
695 | file = make_file(f, fname, &flist->string_area, 0); | |
696 | ||
697 | if (!file) | |
698 | return; | |
699 | ||
700 | if (show_build_progress_p() & !(flist->count % 100)) | |
701 | emit_build_progress(flist); | |
702 | ||
703 | if (flist->count >= flist->malloced) { | |
704 | if (flist->malloced < 1000) | |
705 | flist->malloced += 1000; | |
706 | else | |
707 | flist->malloced *= 2; | |
708 | flist->files = | |
709 | (struct file_struct **) realloc(flist->files, | |
710 | sizeof(flist-> | |
711 | files[0]) * | |
712 | flist->malloced); | |
713 | if (!flist->files) | |
714 | out_of_memory("send_file_name"); | |
715 | } | |
716 | ||
717 | if (write_batch) /* dw */ | |
718 | file->flags = FLAG_DELETE; | |
719 | ||
720 | if (strcmp(file->basename, "")) { | |
721 | flist->files[flist->count++] = file; | |
722 | send_file_entry(file, f, base_flags); | |
723 | } | |
724 | ||
725 | if (S_ISDIR(file->mode) && recursive) { | |
726 | struct exclude_struct **last_exclude_list = | |
727 | local_exclude_list; | |
728 | send_directory(f, flist, f_name(file)); | |
729 | local_exclude_list = last_exclude_list; | |
730 | return; | |
731 | } | |
c627d613 AT |
732 | } |
733 | ||
734 | ||
735 | ||
ebed4c3a | 736 | static void send_directory(int f, struct file_list *flist, char *dir) |
c627d613 | 737 | { |
3ec4dd97 AT |
738 | DIR *d; |
739 | struct dirent *di; | |
740 | char fname[MAXPATHLEN]; | |
741 | int l; | |
742 | char *p; | |
743 | ||
744 | d = opendir(dir); | |
745 | if (!d) { | |
6ba9279f | 746 | io_error = 1; |
ebed4c3a | 747 | rprintf(FERROR, "opendir(%s): %s\n", dir, strerror(errno)); |
3ec4dd97 AT |
748 | return; |
749 | } | |
c627d613 | 750 | |
ebed4c3a | 751 | strlcpy(fname, dir, MAXPATHLEN); |
3ec4dd97 | 752 | l = strlen(fname); |
ebed4c3a MP |
753 | if (fname[l - 1] != '/') { |
754 | if (l == MAXPATHLEN - 1) { | |
6ba9279f | 755 | io_error = 1; |
ebed4c3a MP |
756 | rprintf(FERROR, |
757 | "skipping long-named directory %s\n", | |
758 | fname); | |
3ec4dd97 AT |
759 | closedir(d); |
760 | return; | |
761 | } | |
ebed4c3a | 762 | strlcat(fname, "/", MAXPATHLEN); |
3ec4dd97 AT |
763 | l++; |
764 | } | |
765 | p = fname + strlen(fname); | |
c627d613 | 766 | |
3d913675 AT |
767 | local_exclude_list = NULL; |
768 | ||
3ec4dd97 | 769 | if (cvs_exclude) { |
ebed4c3a MP |
770 | if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN - 1) { |
771 | strcpy(p, ".cvsignore"); | |
772 | local_exclude_list = | |
773 | make_exclude_list(fname, NULL, 0, 0); | |
3ec4dd97 | 774 | } else { |
6ba9279f | 775 | io_error = 1; |
ebed4c3a MP |
776 | rprintf(FINFO, |
777 | "cannot cvs-exclude in long-named directory %s\n", | |
778 | fname); | |
3ec4dd97 | 779 | } |
ebed4c3a MP |
780 | } |
781 | ||
782 | for (di = readdir(d); di; di = readdir(d)) { | |
d6e6ecbd | 783 | char *dname = d_name(di); |
ebed4c3a | 784 | if (strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) |
3ec4dd97 | 785 | continue; |
ebed4c3a MP |
786 | strlcpy(p, dname, MAXPATHLEN - l); |
787 | send_file_name(f, flist, fname, recurse, 0); | |
3ec4dd97 | 788 | } |
c627d613 | 789 | |
3d913675 AT |
790 | if (local_exclude_list) { |
791 | add_exclude_list("!", &local_exclude_list, 0); | |
792 | } | |
793 | ||
3ec4dd97 | 794 | closedir(d); |
c627d613 AT |
795 | } |
796 | ||
797 | ||
58225000 MP |
798 | /* |
799 | * | |
800 | * I *think* f==-1 means that the list should just be built in memory | |
801 | * and not transmitted. But who can tell? -- mbp | |
802 | */ | |
ebed4c3a | 803 | struct file_list *send_file_list(int f, int argc, char *argv[]) |
c627d613 | 804 | { |
ebed4c3a | 805 | int i, l; |
bcacc18b | 806 | STRUCT_STAT st; |
ebed4c3a MP |
807 | char *p, *dir, *olddir; |
808 | char lastpath[MAXPATHLEN] = ""; | |
649d65ed | 809 | struct file_list *flist; |
a800434a | 810 | int64 start_write; |
649d65ed AT |
811 | |
812 | if (verbose && recurse && !am_server && f != -1) { | |
58225000 | 813 | rprintf(FINFO, RSYNC_NAME ": building file list...\n"); |
ebed4c3a MP |
814 | if (verbose > 1) |
815 | rprintf(FINFO, "\n"); | |
9486289c | 816 | rflush(FINFO); |
649d65ed | 817 | } |
c627d613 | 818 | |
a800434a AT |
819 | start_write = stats.total_written; |
820 | ||
3d382777 | 821 | flist = flist_new(); |
c627d613 | 822 | |
d6dead6b AT |
823 | if (f != -1) { |
824 | io_start_buffering(f); | |
825 | } | |
826 | ||
ebed4c3a | 827 | for (i = 0; i < argc; i++) { |
b5313607 | 828 | char *fname = topsrcname; |
c627d613 | 829 | |
ebed4c3a | 830 | strlcpy(fname, argv[i], MAXPATHLEN); |
c627d613 | 831 | |
649d65ed | 832 | l = strlen(fname); |
ebed4c3a | 833 | if (l != 1 && fname[l - 1] == '/') { |
53f821f1 DD |
834 | if ((l == 2) && (fname[0] == '.')) { |
835 | /* Turn ./ into just . rather than ./. | |
ebed4c3a MP |
836 | This was put in to avoid a problem with |
837 | rsync -aR --delete from ./ | |
838 | The send_file_name() below of ./ was | |
839 | mysteriously preventing deletes */ | |
53f821f1 DD |
840 | fname[1] = 0; |
841 | } else { | |
ebed4c3a | 842 | strlcat(fname, ".", MAXPATHLEN); |
53f821f1 | 843 | } |
649d65ed | 844 | } |
c627d613 | 845 | |
ebed4c3a | 846 | if (link_stat(fname, &st) != 0) { |
f76933b1 | 847 | if (f != -1) { |
ebed4c3a MP |
848 | io_error = 1; |
849 | rprintf(FERROR, "link_stat %s : %s\n", | |
850 | fname, strerror(errno)); | |
f76933b1 | 851 | } |
649d65ed AT |
852 | continue; |
853 | } | |
c627d613 | 854 | |
649d65ed | 855 | if (S_ISDIR(st.st_mode) && !recurse) { |
ebed4c3a | 856 | rprintf(FINFO, "skipping directory %s\n", fname); |
649d65ed AT |
857 | continue; |
858 | } | |
c627d613 | 859 | |
649d65ed | 860 | dir = NULL; |
2bca43f6 | 861 | olddir = NULL; |
649d65ed AT |
862 | |
863 | if (!relative_paths) { | |
ebed4c3a | 864 | p = strrchr(fname, '/'); |
649d65ed AT |
865 | if (p) { |
866 | *p = 0; | |
ebed4c3a | 867 | if (p == fname) |
649d65ed AT |
868 | dir = "/"; |
869 | else | |
ebed4c3a MP |
870 | dir = fname; |
871 | fname = p + 1; | |
649d65ed | 872 | } |
ebed4c3a | 873 | } else if (f != -1 && (p = strrchr(fname, '/'))) { |
649d65ed AT |
874 | /* this ensures we send the intermediate directories, |
875 | thus getting their permissions right */ | |
876 | *p = 0; | |
ebed4c3a | 877 | if (strcmp(lastpath, fname)) { |
37f9805d | 878 | strlcpy(lastpath, fname, sizeof(lastpath)); |
649d65ed | 879 | *p = '/'; |
ebed4c3a MP |
880 | for (p = fname + 1; (p = strchr(p, '/')); |
881 | p++) { | |
6c82f74b | 882 | int copy_links_saved = copy_links; |
245fbb51 | 883 | int recurse_saved = recurse; |
649d65ed | 884 | *p = 0; |
b5313607 | 885 | copy_links = copy_unsafe_links; |
245fbb51 DD |
886 | /* set recurse to 1 to prevent make_file |
887 | from ignoring directory, but still | |
888 | turn off the recursive parameter to | |
889 | send_file_name */ | |
890 | recurse = 1; | |
ebed4c3a MP |
891 | send_file_name(f, flist, fname, 0, |
892 | 0); | |
6c82f74b | 893 | copy_links = copy_links_saved; |
245fbb51 | 894 | recurse = recurse_saved; |
649d65ed AT |
895 | *p = '/'; |
896 | } | |
897 | } else { | |
898 | *p = '/'; | |
899 | } | |
900 | } | |
ebed4c3a | 901 | |
649d65ed AT |
902 | if (!*fname) |
903 | fname = "."; | |
ebed4c3a | 904 | |
649d65ed | 905 | if (dir && *dir) { |
2bca43f6 | 906 | olddir = push_dir(dir, 1); |
5243c216 AT |
907 | |
908 | if (!olddir) { | |
ebed4c3a MP |
909 | io_error = 1; |
910 | rprintf(FERROR, "push_dir %s : %s\n", | |
911 | dir, strerror(errno)); | |
649d65ed AT |
912 | continue; |
913 | } | |
5243c216 | 914 | |
649d65ed | 915 | flist_dir = dir; |
2bca43f6 | 916 | } |
ebed4c3a | 917 | |
2bca43f6 DD |
918 | if (one_file_system) |
919 | set_filesystem(fname); | |
920 | ||
ebed4c3a | 921 | send_file_name(f, flist, fname, recurse, FLAG_DELETE); |
2bca43f6 DD |
922 | |
923 | if (olddir != NULL) { | |
649d65ed | 924 | flist_dir = NULL; |
5243c216 | 925 | if (pop_dir(olddir) != 0) { |
ebed4c3a MP |
926 | rprintf(FERROR, "pop_dir %s : %s\n", |
927 | dir, strerror(errno)); | |
65417579 | 928 | exit_cleanup(RERR_FILESELECT); |
649d65ed | 929 | } |
649d65ed | 930 | } |
649d65ed | 931 | } |
dc5ddbcc | 932 | |
b5313607 DD |
933 | topsrcname[0] = '\0'; |
934 | ||
649d65ed | 935 | if (f != -1) { |
ebed4c3a | 936 | send_file_entry(NULL, f, 0); |
649d65ed | 937 | } |
c627d613 | 938 | |
58225000 | 939 | finish_build_progress(flist); |
ebed4c3a | 940 | |
0199b05f | 941 | clean_flist(flist, 0); |
ebed4c3a | 942 | |
649d65ed | 943 | /* now send the uid/gid list. This was introduced in protocol |
ebed4c3a | 944 | version 15 */ |
649d65ed AT |
945 | if (f != -1 && remote_version >= 15) { |
946 | send_uid_list(f); | |
947 | } | |
f6c34742 | 948 | |
6ba9279f AT |
949 | /* if protocol version is >= 17 then send the io_error flag */ |
950 | if (f != -1 && remote_version >= 17) { | |
cda2ae84 | 951 | extern int module_id; |
ebed4c3a | 952 | write_int(f, lp_ignore_errors(module_id) ? 0 : io_error); |
6ba9279f AT |
953 | } |
954 | ||
d6dead6b AT |
955 | if (f != -1) { |
956 | io_end_buffering(f); | |
a800434a AT |
957 | stats.flist_size = stats.total_written - start_write; |
958 | stats.num_files = flist->count; | |
ebed4c3a MP |
959 | if (write_batch) /* dw */ |
960 | write_batch_flist_info(flist->count, flist->files); | |
d6dead6b AT |
961 | } |
962 | ||
17faa41c | 963 | if (verbose > 2) |
ebed4c3a | 964 | rprintf(FINFO, "send_file_list done\n"); |
17faa41c | 965 | |
649d65ed | 966 | return flist; |
c627d613 AT |
967 | } |
968 | ||
969 | ||
970 | struct file_list *recv_file_list(int f) | |
971 | { | |
ebed4c3a MP |
972 | struct file_list *flist; |
973 | unsigned char flags; | |
974 | int64 start_read; | |
975 | extern int list_only; | |
c627d613 | 976 | |
ebed4c3a MP |
977 | if (verbose && recurse && !am_server) { |
978 | rprintf(FINFO, "receiving file list ... "); | |
979 | rflush(FINFO); | |
980 | } | |
c627d613 | 981 | |
ebed4c3a | 982 | start_read = stats.total_read; |
a800434a | 983 | |
ebed4c3a MP |
984 | flist = (struct file_list *) malloc(sizeof(flist[0])); |
985 | if (!flist) | |
986 | goto oom; | |
c627d613 | 987 | |
ebed4c3a MP |
988 | flist->count = 0; |
989 | flist->malloced = 1000; | |
990 | flist->files = | |
991 | (struct file_struct **) malloc(sizeof(flist->files[0]) * | |
992 | flist->malloced); | |
993 | if (!flist->files) | |
994 | goto oom; | |
c627d613 AT |
995 | |
996 | ||
ebed4c3a MP |
997 | for (flags = read_byte(f); flags; flags = read_byte(f)) { |
998 | int i = flist->count; | |
c627d613 | 999 | |
ebed4c3a MP |
1000 | if (i >= flist->malloced) { |
1001 | if (flist->malloced < 1000) | |
1002 | flist->malloced += 1000; | |
1003 | else | |
1004 | flist->malloced *= 2; | |
1005 | flist->files = | |
1006 | (struct file_struct **) realloc(flist->files, | |
1007 | sizeof(flist-> | |
1008 | files | |
1009 | [0]) * | |
1010 | flist-> | |
1011 | malloced); | |
1012 | if (!flist->files) | |
1013 | goto oom; | |
1014 | } | |
c627d613 | 1015 | |
ebed4c3a | 1016 | receive_file_entry(&flist->files[i], flags, f); |
c627d613 | 1017 | |
ebed4c3a MP |
1018 | if (S_ISREG(flist->files[i]->mode)) |
1019 | stats.total_size += flist->files[i]->length; | |
c627d613 | 1020 | |
ebed4c3a | 1021 | flist->count++; |
c627d613 | 1022 | |
ebed4c3a MP |
1023 | if (verbose > 2) |
1024 | rprintf(FINFO, "recv_file_name(%s)\n", | |
1025 | f_name(flist->files[i])); | |
1026 | } | |
c627d613 AT |
1027 | |
1028 | ||
ebed4c3a MP |
1029 | if (verbose > 2) |
1030 | rprintf(FINFO, "received %d names\n", flist->count); | |
c627d613 | 1031 | |
ebed4c3a | 1032 | clean_flist(flist, relative_paths); |
c627d613 | 1033 | |
ebed4c3a MP |
1034 | if (verbose && recurse && !am_server) { |
1035 | rprintf(FINFO, "done\n"); | |
1036 | } | |
a06d19e3 | 1037 | |
ebed4c3a MP |
1038 | /* now recv the uid/gid list. This was introduced in protocol version 15 */ |
1039 | if (f != -1 && remote_version >= 15) { | |
1040 | recv_uid_list(f, flist); | |
1041 | } | |
f6c34742 | 1042 | |
ebed4c3a MP |
1043 | /* if protocol version is >= 17 then recv the io_error flag */ |
1044 | if (f != -1 && remote_version >= 17 && !read_batch) { /* dw-added readbatch */ | |
1045 | extern int module_id; | |
1046 | extern int ignore_errors; | |
1047 | if (lp_ignore_errors(module_id) || ignore_errors) { | |
1048 | read_int(f); | |
1049 | } else { | |
1050 | io_error |= read_int(f); | |
1051 | } | |
1052 | } | |
6ba9279f | 1053 | |
ebed4c3a MP |
1054 | if (list_only) { |
1055 | int i; | |
1056 | for (i = 0; i < flist->count; i++) { | |
1057 | list_file_entry(flist->files[i]); | |
1058 | } | |
1059 | } | |
f7632fc6 AT |
1060 | |
1061 | ||
ebed4c3a MP |
1062 | if (verbose > 2) |
1063 | rprintf(FINFO, "recv_file_list done\n"); | |
17faa41c | 1064 | |
ebed4c3a MP |
1065 | stats.flist_size = stats.total_read - start_read; |
1066 | stats.num_files = flist->count; | |
a800434a | 1067 | |
ebed4c3a | 1068 | return flist; |
c627d613 | 1069 | |
ebed4c3a MP |
1070 | oom: |
1071 | out_of_memory("recv_file_list"); | |
1072 | return NULL; /* not reached */ | |
c627d613 AT |
1073 | } |
1074 | ||
1075 | ||
e03dfae5 MP |
1076 | /* |
1077 | * XXX: This is currently the hottest function while building the file | |
1078 | * list, because building f_name()s every time is expensive. | |
1079 | **/ | |
ebed4c3a | 1080 | int file_compare(struct file_struct **f1, struct file_struct **f2) |
c627d613 | 1081 | { |
ebed4c3a MP |
1082 | if (!(*f1)->basename && !(*f2)->basename) |
1083 | return 0; | |
1084 | if (!(*f1)->basename) | |
1085 | return -1; | |
1086 | if (!(*f2)->basename) | |
1087 | return 1; | |
3ec4dd97 | 1088 | if ((*f1)->dirname == (*f2)->dirname) |
aa9b77a5 | 1089 | return u_strcmp((*f1)->basename, (*f2)->basename); |
ebed4c3a | 1090 | return u_strcmp(f_name(*f1), f_name(*f2)); |
c627d613 AT |
1091 | } |
1092 | ||
1093 | ||
ebed4c3a | 1094 | int flist_find(struct file_list *flist, struct file_struct *f) |
c627d613 | 1095 | { |
ebed4c3a | 1096 | int low = 0, high = flist->count - 1; |
d966ee25 | 1097 | |
ebed4c3a MP |
1098 | if (flist->count <= 0) |
1099 | return -1; | |
d966ee25 AT |
1100 | |
1101 | while (low != high) { | |
ebed4c3a MP |
1102 | int mid = (low + high) / 2; |
1103 | int ret = | |
1104 | file_compare(&flist->files[flist_up(flist, mid)], &f); | |
1105 | if (ret == 0) | |
1106 | return flist_up(flist, mid); | |
d966ee25 | 1107 | if (ret > 0) { |
ebed4c3a | 1108 | high = mid; |
d966ee25 | 1109 | } else { |
ebed4c3a | 1110 | low = mid + 1; |
d966ee25 AT |
1111 | } |
1112 | } | |
1113 | ||
ebed4c3a MP |
1114 | if (file_compare(&flist->files[flist_up(flist, low)], &f) == 0) |
1115 | return flist_up(flist, low); | |
d966ee25 | 1116 | return -1; |
c627d613 AT |
1117 | } |
1118 | ||
1119 | ||
3ec4dd97 AT |
1120 | /* |
1121 | * free up one file | |
1122 | */ | |
66203a98 | 1123 | void free_file(struct file_struct *file) |
c627d613 | 1124 | { |
ebed4c3a MP |
1125 | if (!file) |
1126 | return; | |
1127 | if (file->basename) | |
1128 | free(file->basename); | |
1129 | if (file->link) | |
1130 | free(file->link); | |
1131 | if (file->sum) | |
1132 | free(file->sum); | |
3d382777 | 1133 | *file = null_file; |
3ec4dd97 | 1134 | } |
c627d613 | 1135 | |
c627d613 | 1136 | |
3d382777 AT |
1137 | /* |
1138 | * allocate a new file list | |
1139 | */ | |
1140 | struct file_list *flist_new() | |
1141 | { | |
1142 | struct file_list *flist; | |
1143 | ||
ebed4c3a MP |
1144 | flist = (struct file_list *) malloc(sizeof(flist[0])); |
1145 | if (!flist) | |
1146 | out_of_memory("send_file_list"); | |
3d382777 | 1147 | |
ebed4c3a | 1148 | flist->count = 0; |
3d382777 | 1149 | flist->malloced = 1000; |
ebed4c3a MP |
1150 | flist->files = |
1151 | (struct file_struct **) malloc(sizeof(flist->files[0]) * | |
1152 | flist->malloced); | |
1153 | if (!flist->files) | |
1154 | out_of_memory("send_file_list"); | |
3d382777 AT |
1155 | #if ARENA_SIZE > 0 |
1156 | flist->string_area = string_area_new(0); | |
1157 | #else | |
5c66303a | 1158 | flist->string_area = NULL; |
3d382777 AT |
1159 | #endif |
1160 | return flist; | |
1161 | } | |
ebed4c3a | 1162 | |
3ec4dd97 AT |
1163 | /* |
1164 | * free up all elements in a flist | |
1165 | */ | |
1166 | void flist_free(struct file_list *flist) | |
1167 | { | |
1168 | int i; | |
ebed4c3a | 1169 | for (i = 1; i < flist->count; i++) { |
3d382777 AT |
1170 | if (!flist->string_area) |
1171 | free_file(flist->files[i]); | |
649d65ed | 1172 | free(flist->files[i]); |
ebed4c3a MP |
1173 | } |
1174 | memset((char *) flist->files, 0, | |
1175 | sizeof(flist->files[0]) * flist->count); | |
3ec4dd97 | 1176 | free(flist->files); |
3d382777 AT |
1177 | if (flist->string_area) |
1178 | string_area_free(flist->string_area); | |
ebed4c3a | 1179 | memset((char *) flist, 0, sizeof(*flist)); |
3ec4dd97 | 1180 | free(flist); |
c627d613 AT |
1181 | } |
1182 | ||
1183 | ||
1184 | /* | |
1185 | * This routine ensures we don't have any duplicate names in our file list. | |
1186 | * duplicate names can cause corruption because of the pipelining | |
1187 | */ | |
0199b05f | 1188 | static void clean_flist(struct file_list *flist, int strip_root) |
c627d613 | 1189 | { |
3ec4dd97 | 1190 | int i; |
c627d613 | 1191 | |
ebed4c3a | 1192 | if (!flist || flist->count == 0) |
3ec4dd97 | 1193 | return; |
3ec4dd97 | 1194 | |
ebed4c3a MP |
1195 | qsort(flist->files, flist->count, |
1196 | sizeof(flist->files[0]), (int (*)()) file_compare); | |
1197 | ||
1198 | for (i = 1; i < flist->count; i++) { | |
3ec4dd97 | 1199 | if (flist->files[i]->basename && |
ebed4c3a | 1200 | flist->files[i - 1]->basename && |
3ec4dd97 | 1201 | strcmp(f_name(flist->files[i]), |
ebed4c3a | 1202 | f_name(flist->files[i - 1])) == 0) { |
3ec4dd97 | 1203 | if (verbose > 1 && !am_server) |
ebed4c3a MP |
1204 | rprintf(FINFO, |
1205 | "removing duplicate name %s from file list %d\n", | |
1206 | f_name(flist->files[i - 1]), | |
1207 | i - 1); | |
3d382777 AT |
1208 | /* it's not great that the flist knows the semantics of the |
1209 | * file memory usage, but i'd rather not add a flag byte | |
1210 | * to that struct. XXX can i use a bit in the flags field? */ | |
1211 | if (flist->string_area) | |
1212 | flist->files[i][0] = null_file; | |
1213 | else | |
1214 | free_file(flist->files[i]); | |
ebed4c3a | 1215 | } |
3ec4dd97 | 1216 | } |
0199b05f | 1217 | |
736a6a29 MP |
1218 | /* FIXME: There is a bug here when filenames are repeated more |
1219 | * than once, because we don't handle freed files when doing | |
1220 | * the comparison. */ | |
1221 | ||
0199b05f AT |
1222 | if (strip_root) { |
1223 | /* we need to strip off the root directory in the case | |
1224 | of relative paths, but this must be done _after_ | |
1225 | the sorting phase */ | |
ebed4c3a | 1226 | for (i = 0; i < flist->count; i++) { |
0199b05f AT |
1227 | if (flist->files[i]->dirname && |
1228 | flist->files[i]->dirname[0] == '/') { | |
1229 | memmove(&flist->files[i]->dirname[0], | |
1230 | &flist->files[i]->dirname[1], | |
1231 | strlen(flist->files[i]->dirname)); | |
1232 | } | |
ebed4c3a MP |
1233 | |
1234 | if (flist->files[i]->dirname && | |
0199b05f AT |
1235 | !flist->files[i]->dirname[0]) { |
1236 | flist->files[i]->dirname = NULL; | |
1237 | } | |
1238 | } | |
1239 | } | |
1240 | ||
1241 | ||
ebed4c3a MP |
1242 | if (verbose <= 3) |
1243 | return; | |
0199b05f | 1244 | |
ebed4c3a MP |
1245 | for (i = 0; i < flist->count; i++) { |
1246 | rprintf(FINFO, "[%d] i=%d %s %s mode=0%o len=%.0f\n", | |
1247 | (int) getpid(), i, | |
74e708d8 AT |
1248 | NS(flist->files[i]->dirname), |
1249 | NS(flist->files[i]->basename), | |
08a740ff | 1250 | (int) flist->files[i]->mode, |
ebed4c3a | 1251 | (double) flist->files[i]->length); |
0199b05f | 1252 | } |
3ec4dd97 AT |
1253 | } |
1254 | ||
1255 | ||
1256 | /* | |
1257 | * return the full filename of a flist entry | |
e03dfae5 MP |
1258 | * |
1259 | * This function is too expensive at the moment, because it copies | |
1260 | * strings when often we only want to compare them. In any case, | |
1261 | * using strlcat is silly because it will walk the string repeatedly. | |
3ec4dd97 AT |
1262 | */ |
1263 | char *f_name(struct file_struct *f) | |
1264 | { | |
1265 | static char names[10][MAXPATHLEN]; | |
1266 | static int n; | |
1267 | char *p = names[n]; | |
1268 | ||
ebed4c3a MP |
1269 | if (!f || !f->basename) |
1270 | return NULL; | |
3ec4dd97 | 1271 | |
ebed4c3a | 1272 | n = (n + 1) % 10; |
3ec4dd97 AT |
1273 | |
1274 | if (f->dirname) { | |
e03dfae5 MP |
1275 | int off; |
1276 | ||
1277 | off = strlcpy(p, f->dirname, MAXPATHLEN); | |
ebed4c3a MP |
1278 | off += strlcpy(p + off, "/", MAXPATHLEN - off); |
1279 | off += strlcpy(p + off, f->basename, MAXPATHLEN - off); | |
3ec4dd97 | 1280 | } else { |
37f9805d | 1281 | strlcpy(p, f->basename, MAXPATHLEN); |
3ec4dd97 AT |
1282 | } |
1283 | ||
1284 | return p; | |
c627d613 | 1285 | } |