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.
20 /* this file contains code used by more than one part of the rsync
27 extern int preserve_times
;
29 extern int preserve_uid
;
30 extern int preserve_gid
;
31 extern int preserve_perms
;
32 extern int make_backups
;
38 void free_sums(struct sum_struct
*s
)
40 if (s
->sums
) free(s
->sums
);
46 * delete a file or directory. If force_delete is set then delete
49 int delete_file(char *fname
)
54 extern int force_delete
;
60 ret
= do_lstat(fname
, &st
);
62 ret
= do_stat(fname
, &st
);
68 if (!S_ISDIR(st
.st_mode
)) {
69 if (robust_unlink(fname
) == 0 || errno
== ENOENT
) return 0;
70 rprintf(FERROR
, "delete_file: unlink %s failed: %s\n",
71 full_fname(fname
), strerror(errno
));
75 if (do_rmdir(fname
) == 0 || errno
== ENOENT
) return 0;
76 if (!force_delete
|| !recurse
||
77 (errno
!= ENOTEMPTY
&& errno
!= EEXIST
)) {
78 rprintf(FERROR
, "delete_file: rmdir %s failed: %s\n",
79 full_fname(fname
), strerror(errno
));
83 /* now we do a recsursive delete on the directory ... */
86 rprintf(FERROR
, "delete_file: opendir %s failed: %s\n",
87 full_fname(fname
), strerror(errno
));
91 for (errno
= 0, di
= readdir(d
); di
; errno
= 0, di
= readdir(d
)) {
92 char *dname
= d_name(di
);
93 if (strcmp(dname
,".") == 0
94 || strcmp(dname
,"..") == 0)
96 snprintf(buf
, sizeof(buf
), "%s/%s", fname
, dname
);
98 rprintf(FINFO
,"deleting %s\n", buf
);
99 if (delete_file(buf
) != 0) {
105 rprintf(FERROR
, "delete_file: readdir %s failed: %s\n",
106 full_fname(fname
), strerror(errno
));
113 if (do_rmdir(fname
) != 0) {
114 rprintf(FERROR
, "delete_file: rmdir %s failed: %s\n",
115 full_fname(fname
), strerror(errno
));
122 static int is_in_group(gid_t gid
)
125 static gid_t last_in
= (gid_t
) -2, last_out
;
126 static int ngroups
= -2;
127 static GETGROUPS_T
*gidset
;
133 /* treat failure (-1) as if not member of any group */
134 ngroups
= getgroups(0, 0);
136 gidset
= new_array(GETGROUPS_T
, ngroups
);
137 ngroups
= getgroups(ngroups
, gidset
);
143 for (n
= 0; n
< ngroups
; n
++) {
144 if (gidset
[n
] == gid
) {
156 int set_perms(char *fname
,struct file_struct
*file
,STRUCT_STAT
*st
,
161 int change_uid
, change_gid
;
163 if (dry_run
) return 0;
166 if (link_stat(fname
,&st2
) != 0) {
167 rprintf(FERROR
, "stat %s failed: %s\n",
168 full_fname(fname
), strerror(errno
));
174 if (preserve_times
&& !S_ISLNK(st
->st_mode
) &&
175 cmp_modtime(st
->st_mtime
, file
->modtime
) != 0) {
176 /* don't complain about not setting times on directories
177 because some filesystems can't do it */
178 if (set_modtime(fname
,file
->modtime
) != 0 &&
179 !S_ISDIR(st
->st_mode
)) {
180 rprintf(FERROR
, "failed to set times on %s: %s\n",
181 full_fname(fname
), strerror(errno
));
188 change_uid
= am_root
&& preserve_uid
&& st
->st_uid
!= file
->uid
;
189 change_gid
= preserve_gid
&& file
->gid
!= (gid_t
) -1 && \
190 st
->st_gid
!= file
->gid
;
191 if (change_gid
&& !am_root
) {
192 /* enforce bsd-style group semantics: non-root can only
193 change to groups that the user is a member of */
194 change_gid
= is_in_group(file
->gid
);
196 if (change_uid
|| change_gid
) {
198 change_uid
?file
->uid
:st
->st_uid
,
199 change_gid
?file
->gid
:st
->st_gid
) != 0) {
200 /* shouldn't have attempted to change uid or gid
201 unless have the privilege */
202 rprintf(FERROR
, "chown %s failed: %s\n",
203 full_fname(fname
), strerror(errno
));
206 /* a lchown had been done - we have to re-stat if the
207 destination had the setuid or setgid bits set due
208 to the side effect of the chown call */
209 if (st
->st_mode
& (S_ISUID
| S_ISGID
)) {
210 link_stat(fname
, st
);
216 if (!S_ISLNK(st
->st_mode
)) {
217 if ((st
->st_mode
& CHMOD_BITS
) != (file
->mode
& CHMOD_BITS
)) {
219 if (do_chmod(fname
,(file
->mode
& CHMOD_BITS
)) != 0) {
220 rprintf(FERROR
, "failed to set permissions on %s: %s\n",
221 full_fname(fname
), strerror(errno
));
228 if (verbose
> 1 && report
) {
230 rprintf(FINFO
,"%s\n",fname
);
232 rprintf(FINFO
,"%s is uptodate\n",fname
);
240 exit_cleanup(RERR_SIGNAL
);
244 /* finish off a file transfer, renaming the file and setting the permissions
246 void finish_transfer(char *fname
, char *fnametmp
, struct file_struct
*file
)
248 if (make_backups
&& !make_backup(fname
))
251 /* move tmp file over real file */
252 if (robust_rename(fnametmp
,fname
) != 0) {
253 if (errno
== EXDEV
) {
254 /* rename failed on cross-filesystem link.
255 Copy the file instead. */
256 if (copy_file(fnametmp
,fname
, file
->mode
& INITACCESSPERMS
)) {
257 rprintf(FERROR
, "copy %s -> \"%s\": %s\n",
258 full_fname(fnametmp
), fname
,
261 set_perms(fname
,file
,NULL
,0);
264 rprintf(FERROR
,"rename %s -> \"%s\": %s\n",
265 full_fname(fnametmp
), fname
, strerror(errno
));
269 set_perms(fname
,file
,NULL
,0);