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) : %s\n", fname
, strerror(errno
));
74 if (do_rmdir(fname
) == 0 || errno
== ENOENT
) return 0;
75 if (!force_delete
|| !recurse
||
76 (errno
!= ENOTEMPTY
&& errno
!= EEXIST
)) {
77 rprintf(FERROR
,"delete_file: rmdir(%s) : %s\n", fname
, strerror(errno
));
81 /* now we do a recsursive delete on the directory ... */
84 rprintf(FERROR
,"delete_file: opendir(%s): %s\n",
85 fname
,strerror(errno
));
89 for (di
=readdir(d
); di
; di
=readdir(d
)) {
90 char *dname
= d_name(di
);
91 if (strcmp(dname
,".")==0 ||
92 strcmp(dname
,"..")==0)
94 snprintf(buf
, sizeof(buf
), "%s/%s", fname
, dname
);
96 rprintf(FINFO
,"deleting %s\n", buf
);
97 if (delete_file(buf
) != 0) {
105 if (do_rmdir(fname
) != 0) {
106 rprintf(FERROR
,"delete_file: rmdir(%s) : %s\n", fname
, strerror(errno
));
113 static int is_in_group(gid_t gid
)
116 static gid_t last_in
= (gid_t
) -2, last_out
;
117 static int ngroups
= -2;
118 static GETGROUPS_T
*gidset
;
124 /* treat failure (-1) as if not member of any group */
125 ngroups
= getgroups(0, 0);
127 gidset
= (GETGROUPS_T
*) malloc(ngroups
* sizeof(GETGROUPS_T
));
128 ngroups
= getgroups(ngroups
, gidset
);
134 for (n
= 0; n
< ngroups
; n
++) {
135 if (gidset
[n
] == gid
) {
147 int set_perms(char *fname
,struct file_struct
*file
,STRUCT_STAT
*st
,
152 int change_uid
, change_gid
;
154 if (dry_run
) return 0;
157 if (link_stat(fname
,&st2
) != 0) {
158 rprintf(FERROR
,"stat %s : %s\n",fname
,strerror(errno
));
164 if (preserve_times
&& !S_ISLNK(st
->st_mode
) &&
165 cmp_modtime(st
->st_mtime
, file
->modtime
) != 0) {
166 /* don't complain about not setting times on directories
167 because some filesystems can't do it */
168 if (set_modtime(fname
,file
->modtime
) != 0 &&
169 !S_ISDIR(st
->st_mode
)) {
170 rprintf(FERROR
,"failed to set times on %s : %s\n",
171 fname
,strerror(errno
));
178 change_uid
= am_root
&& preserve_uid
&& st
->st_uid
!= file
->uid
;
179 change_gid
= preserve_gid
&& file
->gid
!= (gid_t
) -1 && \
180 st
->st_gid
!= file
->gid
;
181 if (change_gid
&& !am_root
) {
182 /* enforce bsd-style group semantics: non-root can only
183 change to groups that the user is a member of */
184 change_gid
= is_in_group(file
->gid
);
186 if (change_uid
|| change_gid
) {
188 change_uid
?file
->uid
:st
->st_uid
,
189 change_gid
?file
->gid
:st
->st_gid
) != 0) {
190 /* shouldn't have attempted to change uid or gid
191 unless have the privilege */
192 rprintf(FERROR
,"chown %s : %s\n", fname
,strerror(errno
));
195 /* a lchown had been done - we have to re-stat if the
196 destination had the setuid or setgid bits set due
197 to the side effect of the chown call */
198 if (st
->st_mode
& (S_ISUID
| S_ISGID
)) {
199 link_stat(fname
, st
);
205 if (!S_ISLNK(st
->st_mode
)) {
206 if ((st
->st_mode
& CHMOD_BITS
) != (file
->mode
& CHMOD_BITS
)) {
208 if (do_chmod(fname
,(file
->mode
& CHMOD_BITS
)) != 0) {
209 rprintf(FERROR
,"failed to set permissions on %s : %s\n",
210 fname
,strerror(errno
));
217 if (verbose
> 1 && report
) {
219 rprintf(FINFO
,"%s\n",fname
);
221 rprintf(FINFO
,"%s is uptodate\n",fname
);
229 exit_cleanup(RERR_SIGNAL
);
233 /* finish off a file transfer, renaming the file and setting the permissions
235 void finish_transfer(char *fname
, char *fnametmp
, struct file_struct
*file
)
237 if (make_backups
&& !make_backup(fname
))
240 /* move tmp file over real file */
241 if (robust_rename(fnametmp
,fname
) != 0) {
242 if (errno
== EXDEV
) {
243 /* rename failed on cross-filesystem link.
244 Copy the file instead. */
245 if (copy_file(fnametmp
,fname
, file
->mode
& INITACCESSPERMS
)) {
246 rprintf(FERROR
,"copy %s -> %s : %s\n",
247 fnametmp
,fname
,strerror(errno
));
249 set_perms(fname
,file
,NULL
,0);
252 rprintf(FERROR
,"rename %s -> %s : %s\n",
253 fnametmp
,fname
,strerror(errno
));
257 set_perms(fname
,file
,NULL
,0);