]>
git.ipfire.org Git - thirdparty/rsync.git/blob - rsync.c
2 * Routines common to more than one of the rsync processes.
4 * Copyright (C) 1996 Andrew Tridgell
5 * Copyright (C) 1996 Paul Mackerras
6 * Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
24 #if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
27 #if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
28 #include <libcharset.h>
29 #elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
35 extern int daemon_log_format_has_i
;
36 extern int preserve_perms
;
37 extern int preserve_executability
;
38 extern int preserve_times
;
39 extern int omit_dir_times
;
43 extern int am_generator
;
44 extern int am_starting_up
;
45 extern int allow_8bit_chars
;
46 extern int preserve_uid
;
47 extern int preserve_gid
;
49 extern int keep_dirlinks
;
50 extern int make_backups
;
51 extern mode_t orig_umask
;
52 extern struct stats stats
;
53 extern struct chmod_mode_struct
*daemon_chmod_modes
;
55 #if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
56 iconv_t ic_chck
= (iconv_t
)-1;
58 static const char *default_charset(void)
60 #if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
61 return locale_charset();
62 #elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
63 return nl_langinfo(CODESET
);
65 return ""; /* Works with (at the very least) gnu iconv... */
71 if (!am_server
&& !allow_8bit_chars
) {
72 const char *defset
= default_charset();
74 /* It's OK if this fails... */
75 ic_chck
= iconv_open(defset
, defset
);
78 if (ic_chck
== (iconv_t
)-1) {
80 "note: iconv_open(\"%s\", \"%s\") failed (%d)"
81 " -- using isprint() instead of iconv().\n",
82 defset
, defset
, errno
);
85 "note: iconv_open(\"%s\", \"%s\") succeeded.\n",
96 void free_sums(struct sum_struct
*s
)
98 if (s
->sums
) free(s
->sums
);
102 /* This is only called when we aren't preserving permissions. Figure out what
103 * the permissions should be and return them merged back into the mode. */
104 mode_t
dest_mode(mode_t flist_mode
, mode_t cur_mode
, int exists
)
106 /* If the file already exists, we'll return the local permissions,
107 * possibly tweaked by the --executability option. */
109 if (preserve_executability
&& S_ISREG(flist_mode
)) {
110 /* If the source file is executable, grant execute
111 * rights to everyone who can read, but ONLY if the
112 * file isn't already executable. */
113 if (!(flist_mode
& 0111))
115 else if (!(cur_mode
& 0111))
116 cur_mode
|= (cur_mode
& 0444) >> 2;
119 cur_mode
= flist_mode
& ACCESSPERMS
& ~orig_umask
;
120 if (daemon_chmod_modes
&& !S_ISLNK(flist_mode
))
121 cur_mode
= tweak_mode(cur_mode
, daemon_chmod_modes
);
122 return (flist_mode
& ~CHMOD_BITS
) | (cur_mode
& CHMOD_BITS
);
125 int set_file_attrs(char *fname
, struct file_struct
*file
, STRUCT_STAT
*st
,
130 int change_uid
, change_gid
;
135 if (link_stat(fname
, &st2
, 0) < 0) {
136 rsyserr(FERROR
, errno
, "stat %s failed",
141 if (!preserve_perms
&& S_ISDIR(file
->mode
)
142 && st
->st_mode
& S_ISGID
) {
143 /* We just created this directory and its setgid
144 * bit is on, so make sure it stays on. */
145 file
->mode
|= S_ISGID
;
149 if (!preserve_times
|| (S_ISDIR(st
->st_mode
) && omit_dir_times
))
150 flags
|= ATTRS_SKIP_MTIME
;
151 if (!(flags
& ATTRS_SKIP_MTIME
)
152 && cmp_time(st
->st_mtime
, file
->modtime
) != 0) {
153 int ret
= set_modtime(fname
, file
->modtime
, st
->st_mode
);
155 rsyserr(FERROR
, errno
, "failed to set times on %s",
159 if (ret
== 0) /* ret == 1 if symlink could not be set */
163 change_uid
= am_root
&& preserve_uid
&& st
->st_uid
!= file
->uid
;
164 change_gid
= preserve_gid
&& file
->gid
!= GID_NONE
165 && st
->st_gid
!= file
->gid
;
166 #if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
167 if (S_ISLNK(st
->st_mode
))
171 if (change_uid
|| change_gid
) {
175 "set uid of %s from %ld to %ld\n",
177 (long)st
->st_uid
, (long)file
->uid
);
181 "set gid of %s from %ld to %ld\n",
183 (long)st
->st_gid
, (long)file
->gid
);
187 change_uid
? file
->uid
: st
->st_uid
,
188 change_gid
? file
->gid
: st
->st_gid
) != 0) {
189 /* shouldn't have attempted to change uid or gid
190 * unless have the privilege */
191 rsyserr(FERROR
, errno
, "%s %s failed",
192 change_uid
? "chown" : "chgrp",
196 /* a lchown had been done - we have to re-stat if the
197 * destination had the setuid or setgid bits set due
198 * to the side effect of the chown call */
199 if (st
->st_mode
& (S_ISUID
| S_ISGID
)) {
201 keep_dirlinks
&& S_ISDIR(st
->st_mode
));
207 if ((st
->st_mode
& CHMOD_BITS
) != (file
->mode
& CHMOD_BITS
)) {
208 int ret
= do_chmod(fname
, file
->mode
);
210 rsyserr(FERROR
, errno
,
211 "failed to set permissions on %s",
215 if (ret
== 0) /* ret == 1 if symlink could not be set */
220 if (verbose
> 1 && flags
& ATTRS_REPORT
) {
221 enum logcode code
= daemon_log_format_has_i
|| dry_run
224 rprintf(code
, "%s\n", fname
);
226 rprintf(code
, "%s is uptodate\n", fname
);
231 RETSIGTYPE
sig_int(UNUSED(int val
))
233 /* KLUGE: if the user hits Ctrl-C while ssh is prompting
234 * for a password, then our cleanup's sending of a SIGUSR1
235 * signal to all our children may kill ssh before it has a
236 * chance to restore the tty settings (i.e. turn echo back
237 * on). By sleeping for a short time, ssh gets a bigger
238 * chance to do the right thing. If child processes are
239 * not ssh waiting for a password, then this tiny delay
240 * shouldn't hurt anything. */
242 exit_cleanup(RERR_SIGNAL
);
245 /* Finish off a file transfer: renaming the file and setting the file's
246 * attributes (e.g. permissions, ownership, etc.). If partialptr is not
247 * NULL and the robust_rename() call is forced to copy the temp file, we
248 * stage the file into the partial-dir and then rename it into place. */
249 void finish_transfer(char *fname
, char *fnametmp
, char *partialptr
,
250 struct file_struct
*file
, int ok_to_set_time
,
251 int overwriting_basis
)
257 rprintf(FINFO
, "finishing %s\n", fname
);
259 goto do_set_file_attrs
;
262 if (make_backups
&& overwriting_basis
&& !make_backup(fname
))
265 /* Change permissions before putting the file into place. */
266 set_file_attrs(fnametmp
, file
, NULL
,
267 ok_to_set_time
? 0 : ATTRS_SKIP_MTIME
);
269 /* move tmp file over real file */
271 rprintf(FINFO
, "renaming %s to %s\n", fnametmp
, fname
);
272 ret
= robust_rename(fnametmp
, fname
, partialptr
,
273 file
->mode
& INITACCESSPERMS
);
275 rsyserr(FERROR
, errno
, "%s %s -> \"%s\"",
276 ret
== -2 ? "copy" : "rename",
277 full_fname(fnametmp
), fname
);
282 /* The file was moved into place (not copied), so it's done. */
285 /* The file was copied, so tweak the perms of the copied file. If it
286 * was copied to partialptr, move it into its final destination. */
287 fnametmp
= partialptr
? partialptr
: fname
;
290 set_file_attrs(fnametmp
, file
, NULL
,
291 ok_to_set_time
? 0 : ATTRS_SKIP_MTIME
);
294 if (do_rename(fnametmp
, fname
) < 0) {
295 rsyserr(FERROR
, errno
, "rename %s -> \"%s\"",
296 full_fname(fnametmp
), fname
);
298 handle_partial_dir(partialptr
, PDIR_DELETE
);
302 const char *who_am_i(void)
305 return am_server
? "server" : "client";
306 return am_sender
? "sender" : am_generator
? "generator" : "receiver";