Handle nested "." dirs (caused by --relative and a trailing slash or
[rsync.git] / sender.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 #include "rsync.h"
21
22 extern int verbose;
23 extern int do_xfers;
24 extern int am_server;
25 extern int am_daemon;
26 extern int log_before_transfer;
27 extern int log_format_has_i;
28 extern int daemon_log_format_has_i;
29 extern int csum_length;
30 extern int io_error;
31 extern int allowed_lull;
32 extern int protocol_version;
33 extern int remove_sent_files;
34 extern int updating_basis_file;
35 extern int make_backups;
36 extern int do_progress;
37 extern int inplace;
38 extern int batch_fd;
39 extern int write_batch;
40 extern struct stats stats;
41 extern struct file_list *the_file_list;
42 extern char *log_format;
43
44
45 /**
46  * @file
47  *
48  * The sender gets checksums from the generator, calculates deltas,
49  * and transmits them to the receiver.  The sender process runs on the
50  * machine holding the source files.
51  **/
52
53 /**
54  * Receive the checksums for a buffer
55  **/
56 static struct sum_struct *receive_sums(int f)
57 {
58         struct sum_struct *s;
59         int32 i;
60         int lull_mod = allowed_lull * 5;
61         OFF_T offset = 0;
62
63         if (!(s = new(struct sum_struct)))
64                 out_of_memory("receive_sums");
65
66         read_sum_head(f, s);
67
68         s->sums = NULL;
69
70         if (verbose > 3) {
71                 rprintf(FINFO, "count=%.0f n=%ld rem=%ld\n",
72                         (double)s->count, (long)s->blength, (long)s->remainder);
73         }
74
75         if (s->count == 0)
76                 return(s);
77
78         if (!(s->sums = new_array(struct sum_buf, s->count)))
79                 out_of_memory("receive_sums");
80
81         for (i = 0; i < s->count; i++) {
82                 s->sums[i].sum1 = read_int(f);
83                 read_buf(f, s->sums[i].sum2, s->s2length);
84
85                 s->sums[i].offset = offset;
86                 s->sums[i].flags = 0;
87
88                 if (i == s->count-1 && s->remainder != 0)
89                         s->sums[i].len = s->remainder;
90                 else
91                         s->sums[i].len = s->blength;
92                 offset += s->sums[i].len;
93
94                 if (allowed_lull && !(i % lull_mod))
95                         maybe_send_keepalive();
96
97                 if (verbose > 3) {
98                         rprintf(FINFO,
99                                 "chunk[%d] len=%d offset=%.0f sum1=%08x\n",
100                                 i, s->sums[i].len, (double)s->sums[i].offset,
101                                 s->sums[i].sum1);
102                 }
103         }
104
105         s->flength = offset;
106
107         return s;
108 }
109
110 void successful_send(int ndx)
111 {
112         char fname[MAXPATHLEN];
113         struct file_struct *file;
114         unsigned int offset;
115
116         if (ndx < 0 || ndx >= the_file_list->count)
117                 return;
118
119         file = the_file_list->files[ndx];
120         /* The generator might tell us about symlinks we didn't send. */
121         if (!(file->flags & FLAG_SENT) && !S_ISLNK(file->mode))
122                 return;
123         if (file->dir.root) {
124                 offset = stringjoin(fname, sizeof fname,
125                                     file->dir.root, "/", NULL);
126         } else
127                 offset = 0;
128         f_name_to(file, fname + offset);
129         if (remove_sent_files && do_unlink(fname) == 0 && verbose > 1) {
130                 rprintf(FINFO, "sender removed %s\n",
131                         safe_fname(fname + offset));
132         }
133 }
134
135 static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
136                                 uchar fnamecmp_type, char *buf, int len)
137 {
138         write_int(f_out, ndx);
139         if (protocol_version < 29)
140                 return;
141         write_shortint(f_out, iflags);
142         if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
143                 write_byte(f_out, fnamecmp_type);
144         if (iflags & ITEM_XNAME_FOLLOWS)
145                 write_vstring(f_out, buf, len);
146 }
147
148 /* This is also used by receive.c with f_out = -1. */
149 int read_item_attrs(int f_in, int f_out, int ndx, uchar *type_ptr,
150                     char *buf, int *len_ptr)
151 {
152         int len;
153         uchar fnamecmp_type = FNAMECMP_FNAME;
154         int iflags = protocol_version >= 29 ? read_shortint(f_in)
155                    : ITEM_TRANSFER | ITEM_MISSING_DATA;
156
157         /* Handle the new keep-alive (no-op) packet. */
158         if (ndx == the_file_list->count && iflags == ITEM_IS_NEW)
159                 ;
160         else if (ndx < 0 || ndx >= the_file_list->count) {
161                 rprintf(FERROR, "Invalid file index: %d (count=%d) [%s]\n",
162                         ndx, the_file_list->count, who_am_i());
163                 exit_cleanup(RERR_PROTOCOL);
164         } else if (iflags == ITEM_IS_NEW) {
165                 rprintf(FERROR, "Invalid itemized flag word: %x [%s]\n",
166                         iflags, who_am_i());
167                 exit_cleanup(RERR_PROTOCOL);
168         }
169
170         if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
171                 fnamecmp_type = read_byte(f_in);
172         *type_ptr = fnamecmp_type;
173
174         if (iflags & ITEM_XNAME_FOLLOWS) {
175                 if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0)
176                         exit_cleanup(RERR_PROTOCOL);
177         } else {
178                 *buf = '\0';
179                 len = -1;
180         }
181         *len_ptr = len;
182
183         if (iflags & ITEM_TRANSFER) {
184                 if (!S_ISREG(the_file_list->files[ndx]->mode)) {
185                         rprintf(FERROR,
186                                 "received request to transfer non-regular file: %d [%s]\n",
187                                 ndx, who_am_i());
188                         exit_cleanup(RERR_PROTOCOL);
189                 }
190         } else if (f_out >= 0) {
191                 write_ndx_and_attrs(f_out, ndx, iflags,
192                                     fnamecmp_type, buf, len);
193         }
194
195         return iflags;
196 }
197
198 void send_files(struct file_list *flist, int f_out, int f_in)
199 {
200         int fd = -1;
201         struct sum_struct *s;
202         struct map_struct *mbuf = NULL;
203         STRUCT_STAT st;
204         char *fname2, fname[MAXPATHLEN];
205         char xname[MAXPATHLEN];
206         uchar fnamecmp_type;
207         int iflags, xlen;
208         struct file_struct *file;
209         int phase = 0, max_phase = protocol_version >= 29 ? 2 : 1;
210         struct stats initial_stats;
211         int save_make_backups = make_backups;
212         int itemizing = am_daemon ? daemon_log_format_has_i
213                       : !am_server && log_format_has_i;
214         int f_xfer = write_batch < 0 ? batch_fd : f_out;
215         int i, j;
216
217         if (verbose > 2)
218                 rprintf(FINFO, "send_files starting\n");
219
220         while (1) {
221                 unsigned int offset;
222
223                 i = read_int(f_in);
224                 if (i == -1) {
225                         if (++phase > max_phase)
226                                 break;
227                         csum_length = SUM_LENGTH;
228                         if (verbose > 2)
229                                 rprintf(FINFO, "send_files phase=%d\n", phase);
230                         write_int(f_out, -1);
231                         /* For inplace: redo phase turns off the backup
232                          * flag so that we do a regular inplace send. */
233                         make_backups = 0;
234                         continue;
235                 }
236
237                 iflags = read_item_attrs(f_in, f_out, i, &fnamecmp_type,
238                                          xname, &xlen);
239                 if (iflags == ITEM_IS_NEW) /* no-op packet */
240                         continue;
241
242                 file = flist->files[i];
243                 if (file->dir.root) {
244                         /* N.B. We're sure that this fits, so offset is OK. */
245                         offset = strlcpy(fname, file->dir.root, sizeof fname);
246                         if (!offset || fname[offset-1] != '/')
247                                 fname[offset++] = '/';
248                 } else
249                         offset = 0;
250                 fname2 = f_name_to(file, fname + offset);
251
252                 if (verbose > 2)
253                         rprintf(FINFO, "send_files(%d, %s)\n", i, fname);
254
255                 if (!(iflags & ITEM_TRANSFER)) {
256                         maybe_log_item(file, iflags, itemizing, xname);
257                         continue;
258                 }
259                 if (phase == 2) {
260                         rprintf(FERROR,
261                                 "got transfer request in phase 2 [%s]\n",
262                                 who_am_i());
263                         exit_cleanup(RERR_PROTOCOL);
264                 }
265
266                 updating_basis_file = inplace && (protocol_version >= 29
267                         ? fnamecmp_type == FNAMECMP_FNAME : !make_backups);
268
269                 stats.current_file_index = i;
270                 stats.num_transferred_files++;
271                 stats.total_transferred_size += file->length;
272
273                 if (!do_xfers) { /* log the transfer */
274                         if (!am_server && log_format)
275                                 log_item(file, &stats, iflags, NULL);
276                         write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type,
277                                             xname, xlen);
278                         continue;
279                 }
280
281                 initial_stats = stats;
282
283                 if (!(s = receive_sums(f_in))) {
284                         io_error |= IOERR_GENERAL;
285                         rprintf(FERROR, "receive_sums failed\n");
286                         return;
287                 }
288
289                 fd = do_open(fname, O_RDONLY, 0);
290                 if (fd == -1) {
291                         if (errno == ENOENT) {
292                                 enum logcode c = am_daemon
293                                     && protocol_version < 28 ? FERROR
294                                                              : FINFO;
295                                 io_error |= IOERR_VANISHED;
296                                 rprintf(c, "file has vanished: %s\n",
297                                         full_fname(fname));
298                         } else {
299                                 io_error |= IOERR_GENERAL;
300                                 rsyserr(FERROR, errno,
301                                         "send_files failed to open %s",
302                                         full_fname(fname));
303                         }
304                         free_sums(s);
305                         continue;
306                 }
307
308                 /* map the local file */
309                 if (do_fstat(fd, &st) != 0) {
310                         io_error |= IOERR_GENERAL;
311                         rsyserr(FERROR, errno, "fstat failed");
312                         free_sums(s);
313                         close(fd);
314                         return;
315                 }
316
317                 if (st.st_size) {
318                         int32 read_size = MAX(s->blength * 3, MAX_MAP_SIZE);
319                         mbuf = map_file(fd, st.st_size, read_size, s->blength);
320                 } else
321                         mbuf = NULL;
322
323                 if (verbose > 2) {
324                         rprintf(FINFO, "send_files mapped %s of size %.0f\n",
325                                 safe_fname(fname), (double)st.st_size);
326                 }
327
328                 write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type,
329                                     xname, xlen);
330                 write_sum_head(f_xfer, s);
331
332                 if (verbose > 2) {
333                         rprintf(FINFO, "calling match_sums %s\n",
334                                 safe_fname(fname));
335                 }
336
337                 if (log_before_transfer)
338                         log_item(file, &initial_stats, iflags, NULL);
339                 else if (!am_server && verbose && do_progress)
340                         rprintf(FINFO, "%s\n", safe_fname(fname2));
341
342                 set_compression(fname);
343
344                 match_sums(f_xfer, s, mbuf, st.st_size);
345                 if (do_progress)
346                         end_progress(st.st_size);
347
348                 if (!log_before_transfer)
349                         log_item(file, &initial_stats, iflags, NULL);
350
351                 if (mbuf) {
352                         j = unmap_file(mbuf);
353                         if (j) {
354                                 io_error |= IOERR_GENERAL;
355                                 rsyserr(FERROR, j,
356                                         "read errors mapping %s",
357                                         full_fname(fname));
358                         }
359                 }
360                 close(fd);
361
362                 free_sums(s);
363
364                 if (verbose > 2) {
365                         rprintf(FINFO, "sender finished %s\n",
366                                 safe_fname(fname));
367                 }
368
369                 /* Flag that we actually sent this entry. */
370                 file->flags |= FLAG_SENT;
371         }
372         make_backups = save_make_backups;
373
374         if (verbose > 2)
375                 rprintf(FINFO, "send files finished\n");
376
377         match_report();
378
379         write_int(f_out, -1);
380 }