2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
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.
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.
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.
24 extern int delete_mode
;
25 extern int remote_version
;
26 extern int csum_length
;
27 extern struct stats stats
;
30 extern int relative_paths
;
31 extern int preserve_hard_links
;
32 extern int cvs_exclude
;
35 extern char *compare_dest
;
36 extern int make_backups
;
37 extern char *backup_suffix
;
40 static struct delete_list
{
44 static int dlist_len
, dlist_alloc_len
;
47 /* yuck! This function wouldn't have been necessary if I had the sorting
48 algorithm right. Unfortunately fixing the sorting algorithm would introduce
49 a backward incompatibility as file list indexes are sent over the link.
51 static int delete_already_done(struct file_list
*flist
,int j
)
56 if (link_stat(f_name(flist
->files
[j
]), &st
)) return 1;
58 for (i
=0;i
<dlist_len
;i
++) {
59 if (st
.st_ino
== delete_list
[i
].inode
&&
60 st
.st_dev
== delete_list
[i
].dev
)
67 static void add_delete_entry(struct file_struct
*file
)
69 if (dlist_len
== dlist_alloc_len
) {
70 dlist_alloc_len
+= 1024;
71 delete_list
= (struct delete_list
*)Realloc(delete_list
, sizeof(delete_list
[0])*dlist_alloc_len
);
72 if (!delete_list
) out_of_memory("add_delete_entry");
75 delete_list
[dlist_len
].dev
= file
->dev
;
76 delete_list
[dlist_len
].inode
= file
->inode
;
80 rprintf(FINFO
,"added %s to delete list\n", f_name(file
));
83 static void delete_one(struct file_struct
*f
)
85 if (!S_ISDIR(f
->mode
)) {
86 if (robust_unlink(f_name(f
)) != 0) {
87 rprintf(FERROR
,"unlink %s : %s\n",f_name(f
),strerror(errno
));
89 rprintf(FINFO
,"deleting %s\n",f_name(f
));
92 if (do_rmdir(f_name(f
)) != 0) {
93 if (errno
!= ENOTEMPTY
&& errno
!= EEXIST
)
94 rprintf(FERROR
,"rmdir %s : %s\n",f_name(f
),strerror(errno
));
96 rprintf(FINFO
,"deleting directory %s\n",f_name(f
));
104 /* this deletes any files on the receiving side that are not present
105 on the sending side. For version 1.6.4 I have changed the behaviour
106 to match more closely what most people seem to expect of this option */
107 static void delete_files(struct file_list
*flist
)
109 struct file_list
*local_file_list
;
112 extern int module_id
;
117 if (io_error
&& !lp_ignore_errors(module_id
)) {
118 rprintf(FINFO
,"IO error encountered - skipping file deletion\n");
122 for (j
=0;j
<flist
->count
;j
++) {
123 if (!S_ISDIR(flist
->files
[j
]->mode
) ||
124 !(flist
->files
[j
]->flags
& FLAG_DELETE
)) continue;
126 if (remote_version
< 19 &&
127 delete_already_done(flist
, j
)) continue;
129 name
= strdup(f_name(flist
->files
[j
]));
131 if (!(local_file_list
= send_file_list(-1,1,&name
))) {
137 rprintf(FINFO
,"deleting in %s\n", name
);
139 for (i
=local_file_list
->count
-1;i
>=0;i
--) {
140 if (!local_file_list
->files
[i
]->basename
) continue;
141 if (remote_version
< 19 &&
142 S_ISDIR(local_file_list
->files
[i
]->mode
))
143 add_delete_entry(local_file_list
->files
[i
]);
144 if (-1 == flist_find(flist
,local_file_list
->files
[i
])) {
145 char *f
= f_name(local_file_list
->files
[i
]);
146 int k
= strlen(f
) - strlen(backup_suffix
);
147 if (make_backups
&& ((k
<= 0) ||
148 (strcmp(f
+k
,backup_suffix
) != 0))) {
149 (void) make_backup(f
);
151 delete_one(local_file_list
->files
[i
]);
155 flist_free(local_file_list
);
161 static int get_tmpname(char *fnametmp
, char *fname
)
167 f
= strrchr(fname
,'/');
172 if (strlen(tmpdir
)+strlen(f
)+10 > MAXPATHLEN
) {
173 rprintf(FERROR
,"filename too long\n");
176 slprintf(fnametmp
,MAXPATHLEN
, "%s/.%s.XXXXXX",tmpdir
,f
);
180 f
= strrchr(fname
,'/');
182 if (strlen(fname
)+9 > MAXPATHLEN
) {
183 rprintf(FERROR
,"filename too long\n");
189 slprintf(fnametmp
,MAXPATHLEN
,"%s/.%s.XXXXXX",
193 slprintf(fnametmp
,MAXPATHLEN
,".%s.XXXXXX",fname
);
200 static int receive_data(int f_in
,struct map_struct
*buf
,int fd
,char *fname
,
203 int i
,n
,remainder
,len
,count
;
207 static char file_sum1
[MD4_SUM_LENGTH
];
208 static char file_sum2
[MD4_SUM_LENGTH
];
211 count
= read_int(f_in
);
213 remainder
= read_int(f_in
);
217 for (i
=recv_token(f_in
,&data
); i
!= 0; i
=recv_token(f_in
,&data
)) {
219 show_progress(offset
, total_size
);
222 extern int cleanup_got_literal
;
225 rprintf(FINFO
,"data recv %d at %d\n",
229 stats
.literal_data
+= i
;
230 cleanup_got_literal
= 1;
234 if (fd
!= -1 && write_file(fd
,data
,i
) != i
) {
235 rprintf(FERROR
,"write failed on %s : %s\n",fname
,strerror(errno
));
236 exit_cleanup(RERR_FILEIO
);
245 if (i
== count
-1 && remainder
!= 0)
248 stats
.matched_data
+= len
;
251 rprintf(FINFO
,"chunk[%d] of size %d at %d offset=%d\n",
252 i
,len
,(int)offset2
,(int)offset
);
254 map
= map_ptr(buf
,offset2
,len
);
259 if (fd
!= -1 && write_file(fd
,map
,len
) != len
) {
260 rprintf(FERROR
,"write failed on %s : %s\n",
261 fname
,strerror(errno
));
262 exit_cleanup(RERR_FILEIO
);
269 if (fd
!= -1 && offset
> 0 && sparse_end(fd
) != 0) {
270 rprintf(FERROR
,"write failed on %s : %s\n",
271 fname
,strerror(errno
));
272 exit_cleanup(RERR_FILEIO
);
277 if (remote_version
>= 14) {
278 read_buf(f_in
,file_sum2
,MD4_SUM_LENGTH
);
280 rprintf(FINFO
,"got file_sum\n");
283 memcmp(file_sum1
,file_sum2
,MD4_SUM_LENGTH
) != 0) {
292 int recv_files(int f_in
,struct file_list
*flist
,char *local_name
,int f_gen
)
297 char fnametmp
[MAXPATHLEN
];
299 char fnamecmpbuf
[MAXPATHLEN
];
300 struct map_struct
*buf
;
302 struct file_struct
*file
;
305 extern struct stats stats
;
306 extern int preserve_perms
;
307 struct stats initial_stats
;
310 rprintf(FINFO
,"recv_files(%d) starting\n",flist
->count
);
313 if (recurse
&& delete_mode
&& !local_name
&& flist
->count
>0) {
322 if (phase
==0 && remote_version
>= 13) {
324 csum_length
= SUM_LENGTH
;
326 rprintf(FINFO
,"recv_files phase=%d\n",phase
);
333 if (i
< 0 || i
>= flist
->count
) {
334 rprintf(FERROR
,"Invalid file index %d in recv_files (count=%d)\n",
336 exit_cleanup(RERR_PROTOCOL
);
339 file
= flist
->files
[i
];
340 fname
= f_name(file
);
342 stats
.num_transferred_files
++;
343 stats
.total_transferred_size
+= file
->length
;
350 log_transfer(file
, fname
);
355 initial_stats
= stats
;
358 rprintf(FINFO
,"recv_files(%s)\n",fname
);
363 fd1
= do_open(fnamecmp
, O_RDONLY
, 0);
365 if ((fd1
== -1) && (compare_dest
!= NULL
)) {
366 /* try the file at compare_dest instead */
367 slprintf(fnamecmpbuf
,MAXPATHLEN
,"%s/%s",
369 fnamecmp
= fnamecmpbuf
;
370 fd1
= do_open(fnamecmp
, O_RDONLY
, 0);
373 if (fd1
!= -1 && do_fstat(fd1
,&st
) != 0) {
374 rprintf(FERROR
,"fstat %s : %s\n",fnamecmp
,strerror(errno
));
375 receive_data(f_in
,NULL
,-1,NULL
,file
->length
);
380 if (fd1
!= -1 && !S_ISREG(st
.st_mode
)) {
381 rprintf(FERROR
,"%s : not a regular file (recv_files)\n",fnamecmp
);
382 receive_data(f_in
,NULL
,-1,NULL
,file
->length
);
387 if (fd1
!= -1 && !preserve_perms
) {
388 /* if the file exists already and we aren't perserving
389 presmissions then act as though the remote end sent
390 us the file permissions we already have */
391 file
->mode
= st
.st_mode
;
394 if (fd1
!= -1 && st
.st_size
> 0) {
395 buf
= map_file(fd1
,st
.st_size
);
397 rprintf(FINFO
,"recv mapped %s of size %d\n",fnamecmp
,(int)st
.st_size
);
402 if (!get_tmpname(fnametmp
,fname
)) {
403 if (buf
) unmap_file(buf
);
404 if (fd1
!= -1) close(fd1
);
408 /* mktemp is deliberately used here instead of mkstemp.
409 because O_EXCL is used on the open, the race condition
410 is not a problem or a security hole, and we want to
411 control the access permissions on the created file. */
412 if (NULL
== do_mktemp(fnametmp
)) {
413 rprintf(FERROR
,"mktemp %s failed\n",fnametmp
);
414 receive_data(f_in
,buf
,-1,NULL
,file
->length
);
415 if (buf
) unmap_file(buf
);
416 if (fd1
!= -1) close(fd1
);
420 /* we initially set the perms without the
421 setuid/setgid bits to ensure that there is no race
422 condition. They are then correctly updated after
423 the lchown. Thanks to snabb@epipe.fi for pointing
424 this out. We also set it initially without group
425 access because of a similar race condition. */
426 fd2
= do_open(fnametmp
,O_WRONLY
|O_CREAT
|O_EXCL
,
427 file
->mode
& INITACCESSPERMS
);
429 /* in most cases parent directories will already exist
430 because their information should have been previously
431 transferred, but that may not be the case with -R */
432 if (fd2
== -1 && relative_paths
&& errno
== ENOENT
&&
433 create_directory_path(fnametmp
) == 0) {
434 fd2
= do_open(fnametmp
,O_WRONLY
|O_CREAT
|O_EXCL
,
435 file
->mode
& INITACCESSPERMS
);
438 rprintf(FERROR
,"cannot create %s : %s\n",fnametmp
,strerror(errno
));
439 receive_data(f_in
,buf
,-1,NULL
,file
->length
);
440 if (buf
) unmap_file(buf
);
441 if (fd1
!= -1) close(fd1
);
445 cleanup_set(fnametmp
, fname
, file
, buf
, fd1
, fd2
);
448 log_transfer(file
, fname
);
452 recv_ok
= receive_data(f_in
,buf
,fd2
,fname
,file
->length
);
454 log_recv(file
, &initial_stats
);
456 if (buf
) unmap_file(buf
);
463 rprintf(FINFO
,"renaming %s to %s\n",fnametmp
,fname
);
465 finish_transfer(fname
, fnametmp
, file
);
470 if (csum_length
== SUM_LENGTH
) {
471 rprintf(FERROR
,"ERROR: file corruption in %s. File changed during transfer?\n",
475 rprintf(FINFO
,"redoing %s(%d)\n",fname
,i
);
481 if (preserve_hard_links
)
482 do_hard_links(flist
);
484 /* now we need to fix any directory permissions that were
485 modified during the transfer */
486 for (i
= 0; i
< flist
->count
; i
++) {
487 file
= flist
->files
[i
];
488 if (!file
->basename
|| !S_ISDIR(file
->mode
)) continue;
489 recv_generator(local_name
?local_name
:f_name(file
),flist
,i
,-1);
493 rprintf(FINFO
,"recv_files finished\n");