Tweaked some formatting.
[rsync/rsync.git] / rsync.c
CommitLineData
7a2fd68b 1/*
c627d613
AT
2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
7a2fd68b 4
c627d613
AT
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.
7a2fd68b 9
c627d613
AT
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.
7a2fd68b 14
c627d613
AT
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
2f03f956
AT
20/* this file contains code used by more than one part of the rsync
21 process */
c627d613 22
2f03f956 23#include "rsync.h"
43a481dc 24
c627d613 25extern int verbose;
c627d613 26extern int dry_run;
2f03f956 27extern int preserve_times;
7b8356d0 28extern int am_root;
c3e5e585
WD
29extern int am_sender;
30extern int am_generator;
2f03f956
AT
31extern int preserve_uid;
32extern int preserve_gid;
ee1df1cc
WD
33extern int force_delete;
34extern int recurse;
2f03f956 35extern int make_backups;
ee1df1cc 36extern char *backup_dir;
fe055c71
AT
37
38
c627d613
AT
39/*
40 free a sums struct
41 */
2f03f956 42void free_sums(struct sum_struct *s)
c627d613 43{
298c10d5
AT
44 if (s->sums) free(s->sums);
45 free(s);
c627d613
AT
46}
47
48
3cb6f5d6 49/*
7a2fd68b
WD
50 * delete a file or directory. If force_delete is set then delete
51 * recursively
3cb6f5d6 52 */
2f03f956 53int delete_file(char *fname)
3cb6f5d6
AT
54{
55 DIR *d;
56 struct dirent *di;
57 char buf[MAXPATHLEN];
bcacc18b 58 STRUCT_STAT st;
3cb6f5d6
AT
59 int ret;
60
3cb6f5d6 61#if SUPPORT_LINKS
bcacc18b 62 ret = do_lstat(fname, &st);
3cb6f5d6 63#else
bcacc18b 64 ret = do_stat(fname, &st);
3cb6f5d6 65#endif
a7ed6ca6 66 if (ret)
3cb6f5d6 67 return -1;
3cb6f5d6
AT
68
69 if (!S_ISDIR(st.st_mode)) {
a7ed6ca6
WD
70 if (robust_unlink(fname) == 0 || errno == ENOENT)
71 return 0;
d62bcc17
WD
72 rsyserr(FERROR, errno, "delete_file: unlink %s failed",
73 full_fname(fname));
3cb6f5d6
AT
74 return -1;
75 }
76
a7ed6ca6
WD
77 if (do_rmdir(fname) == 0 || errno == ENOENT)
78 return 0;
79 if (!force_delete || !recurse
80 || (errno != ENOTEMPTY && errno != EEXIST)) {
d62bcc17
WD
81 rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
82 full_fname(fname));
3cb6f5d6
AT
83 return -1;
84 }
85
86 /* now we do a recsursive delete on the directory ... */
a7ed6ca6 87 if (!(d = opendir(fname))) {
d62bcc17
WD
88 rsyserr(FERROR, errno, "delete_file: opendir %s failed",
89 full_fname(fname));
3cb6f5d6
AT
90 return -1;
91 }
92
6a7cc46c 93 for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
d6e6ecbd 94 char *dname = d_name(di);
a7ed6ca6
WD
95 if (dname[0] == '.' && (dname[1] == '\0'
96 || (dname[1] == '.' && dname[2] == '\0')))
3cb6f5d6 97 continue;
a7725e6d 98 pathjoin(buf, sizeof buf, fname, dname);
3cb6f5d6 99 if (verbose > 0)
a7ed6ca6 100 rprintf(FINFO, "deleting %s\n", buf);
3cb6f5d6
AT
101 if (delete_file(buf) != 0) {
102 closedir(d);
103 return -1;
104 }
7a2fd68b 105 }
6a7cc46c 106 if (errno) {
d62bcc17
WD
107 rsyserr(FERROR, errno, "delete_file: readdir %s failed",
108 full_fname(fname));
6a7cc46c
S
109 closedir(d);
110 return -1;
111 }
3cb6f5d6
AT
112
113 closedir(d);
7a2fd68b 114
3cb6f5d6 115 if (do_rmdir(fname) != 0) {
d62bcc17
WD
116 rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
117 full_fname(fname));
3cb6f5d6
AT
118 return -1;
119 }
120
121 return 0;
122}
c627d613 123
2f03f956 124int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
4ecc9e6b 125 int flags)
c627d613 126{
667e72a1
AT
127 int updated = 0;
128 STRUCT_STAT st2;
460f6b99 129 int change_uid, change_gid;
c627d613 130
ee1df1cc
WD
131 if (dry_run)
132 return 0;
c627d613 133
667e72a1 134 if (!st) {
373ef160 135 if (link_stat(fname, &st2, 0) < 0) {
d62bcc17
WD
136 rsyserr(FERROR, errno, "stat %s failed",
137 full_fname(fname));
667e72a1
AT
138 return 0;
139 }
140 st = &st2;
141 }
c627d613 142
ee1df1cc
WD
143 if (!preserve_times || S_ISLNK(st->st_mode)
144 || (make_backups && !backup_dir && S_ISDIR(st->st_mode)))
38443188
WD
145 flags |= PERMS_SKIP_MTIME;
146 if (!(flags & PERMS_SKIP_MTIME)
4ecc9e6b 147 && cmp_modtime(st->st_mtime, file->modtime) != 0) {
8d249b63 148 /* don't complain about not setting times on directories
a174e1ed 149 * because some filesystems can't do it */
8d249b63
AT
150 if (set_modtime(fname,file->modtime) != 0 &&
151 !S_ISDIR(st->st_mode)) {
d62bcc17
WD
152 rsyserr(FERROR, errno, "failed to set times on %s",
153 full_fname(fname));
667e72a1
AT
154 return 0;
155 }
a174e1ed 156 updated = 1;
667e72a1
AT
157 }
158
460f6b99 159 change_uid = am_root && preserve_uid && st->st_uid != file->uid;
a60e2dca 160 change_gid = preserve_gid && file->gid != GID_NONE
7352b873 161 && st->st_gid != file->gid;
460f6b99 162 if (change_uid || change_gid) {
62c9e6b3 163 if (verbose > 2) {
ce37eb2d
WD
164 if (change_uid) {
165 rprintf(FINFO,
166 "set uid of %s from %ld to %ld\n",
167 fname, (long)st->st_uid, (long)file->uid);
168 }
169 if (change_gid) {
170 rprintf(FINFO,
171 "set gid of %s from %ld to %ld\n",
172 fname, (long)st->st_gid, (long)file->gid);
173 }
174 }
667e72a1 175 if (do_lchown(fname,
a174e1ed
WD
176 change_uid ? file->uid : st->st_uid,
177 change_gid ? file->gid : st->st_gid) != 0) {
460f6b99 178 /* shouldn't have attempted to change uid or gid
a174e1ed 179 * unless have the privilege */
d62bcc17 180 rsyserr(FERROR, errno, "%s %s failed",
a174e1ed 181 change_uid ? "chown" : "chgrp",
d62bcc17 182 full_fname(fname));
460f6b99 183 return 0;
667e72a1 184 }
a5827a28 185 /* a lchown had been done - we have to re-stat if the
a174e1ed
WD
186 * destination had the setuid or setgid bits set due
187 * to the side effect of the chown call */
a5827a28 188 if (st->st_mode & (S_ISUID | S_ISGID)) {
373ef160 189 link_stat(fname, st, 0);
a5827a28 190 }
460f6b99 191 updated = 1;
667e72a1 192 }
c627d613
AT
193
194#ifdef HAVE_CHMOD
972a3619 195 if (!S_ISLNK(st->st_mode)) {
b0d791bb 196 if ((st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) {
972a3619 197 updated = 1;
b0d791bb 198 if (do_chmod(fname,(file->mode & CHMOD_BITS)) != 0) {
d62bcc17
WD
199 rsyserr(FERROR, errno, "failed to set permissions on %s",
200 full_fname(fname));
972a3619
DD
201 return 0;
202 }
667e72a1
AT
203 }
204 }
c627d613 205#endif
6a7cc46c 206
4ecc9e6b 207 if (verbose > 1 && flags & PERMS_REPORT) {
667e72a1
AT
208 if (updated)
209 rprintf(FINFO,"%s\n",fname);
210 else
211 rprintf(FINFO,"%s is uptodate\n",fname);
212 }
213 return updated;
c627d613
AT
214}
215
216
34ccb63e
AT
217void sig_int(void)
218{
d5a0b483
WD
219 /* KLUGE: if the user hits Ctrl-C while ssh is prompting
220 * for a password, then our cleanup's sending of a SIGUSR1
221 * signal to all our children may kill ssh before it has a
222 * chance to restore the tty settings (i.e. turn echo back
223 * on). By sleeping for a short time, ssh gets a bigger
224 * chance to do the right thing. If child processes are
225 * not ssh waiting for a password, then this tiny delay
226 * shouldn't hurt anything. */
227 msleep(400);
65417579 228 exit_cleanup(RERR_SIGNAL);
c627d613
AT
229}
230
231
c95da96a
AT
232/* finish off a file transfer, renaming the file and setting the permissions
233 and ownership */
4ecc9e6b
WD
234void finish_transfer(char *fname, char *fnametmp, struct file_struct *file,
235 int ok_to_set_time)
c95da96a 236{
62c9e6b3
WD
237 int ret;
238
53dd3135
DD
239 if (make_backups && !make_backup(fname))
240 return;
c95da96a
AT
241
242 /* move tmp file over real file */
62c9e6b3 243 ret = robust_rename(fnametmp, fname, file->mode & INITACCESSPERMS);
3d061653 244 if (ret < 0) {
d62bcc17 245 rsyserr(FERROR, errno, "%s %s -> \"%s\"",
62c9e6b3 246 ret == -2 ? "copy" : "rename",
d62bcc17 247 full_fname(fnametmp), fname);
c7c11a0d 248 do_unlink(fnametmp);
c95da96a 249 } else {
4ecc9e6b 250 set_perms(fname, file, NULL,
38443188 251 ok_to_set_time ? 0 : PERMS_SKIP_MTIME);
c95da96a
AT
252 }
253}
c3e5e585
WD
254
255const char *who_am_i(void)
256{
257 return am_sender ? "sender" : am_generator ? "generator" : "receiver";
258}