rsync.c

説明を見る。
00001 /*
00002    Copyright (C) Andrew Tridgell 1996
00003    Copyright (C) Paul Mackerras 1996
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2 of the License, or
00008    (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software
00017    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 /* this file contains code used by more than one part of the rsync
00021    process */
00022 
00023 #include "rsync.h"
00024 #if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
00025 #include <iconv.h>
00026 #endif
00027 #if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
00028 #include <libcharset.h>
00029 #elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
00030 #include <langinfo.h>
00031 #endif
00032 
00033 extern int verbose;
00034 extern int dry_run;
00035 extern int daemon_log_format_has_i;
00036 extern int preserve_acls;
00037 extern int preserve_xattrs;
00038 extern int preserve_perms;
00039 extern int preserve_executability;
00040 extern int preserve_times;
00041 extern int omit_dir_times;
00042 extern int am_root;
00043 extern int am_server;
00044 extern int am_sender;
00045 extern int am_generator;
00046 extern int am_starting_up;
00047 extern int allow_8bit_chars;
00048 extern int preserve_uid;
00049 extern int preserve_gid;
00050 extern int inplace;
00051 extern int keep_dirlinks;
00052 extern int make_backups;
00053 extern mode_t orig_umask;
00054 extern struct stats stats;
00055 extern struct chmod_mode_struct *daemon_chmod_modes;
00056 
00057 #if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
00058 iconv_t ic_chck = (iconv_t)-1;
00059 
00060 static const char *default_charset(void)
00061 {
00062 #if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
00063         return locale_charset();
00064 #elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
00065         return nl_langinfo(CODESET);
00066 #else
00067         return ""; /* Works with (at the very least) gnu iconv... */
00068 #endif
00069 }
00070 
00071 void setup_iconv()
00072 {
00073         if (!am_server && !allow_8bit_chars) {
00074                 const char *defset = default_charset();
00075 
00076                 /* It's OK if this fails... */
00077                 ic_chck = iconv_open(defset, defset);
00078 
00079                 if (verbose > 3) {
00080                         if (ic_chck == (iconv_t)-1) {
00081                                 rprintf(FINFO,
00082                                         "note: iconv_open(\"%s\", \"%s\") failed (%d)"
00083                                         " -- using isprint() instead of iconv().\n",
00084                                         defset, defset, errno);
00085                         } else {
00086                                 rprintf(FINFO,
00087                                         "note: iconv_open(\"%s\", \"%s\") succeeded.\n",
00088                                         defset, defset);
00089                         }
00090                 }
00091         }
00092 }
00093 #endif
00094 
00095 /*
00096   free a sums struct
00097   */
00098 void free_sums(struct sum_struct *s)
00099 {
00100         if (s->sums) free(s->sums);
00101         free(s);
00102 }
00103 
00104 /* This is only called when we aren't preserving permissions.  Figure out what
00105  * the permissions should be and return them merged back into the mode. */
00106 mode_t dest_mode(mode_t flist_mode, mode_t cur_mode, int dflt_perms,
00107                  int exists)
00108 {
00109         /* If the file already exists, we'll return the local permissions,
00110          * possibly tweaked by the --executability option. */
00111         if (exists) {
00112                 if (preserve_executability && S_ISREG(flist_mode)) {
00113                         /* If the source file is executable, grant execute
00114                          * rights to everyone who can read, but ONLY if the
00115                          * file isn't already executable. */
00116                         if (!(flist_mode & 0111))
00117                                 cur_mode &= ~0111;
00118                         else if (!(cur_mode & 0111))
00119                                 cur_mode |= (cur_mode & 0444) >> 2;
00120                 }
00121         } else
00122                 cur_mode = flist_mode & ACCESSPERMS & dflt_perms;
00123         if (daemon_chmod_modes && !S_ISLNK(flist_mode))
00124                 cur_mode = tweak_mode(cur_mode, daemon_chmod_modes);
00125         return (flist_mode & ~CHMOD_BITS) | (cur_mode & CHMOD_BITS);
00126 }
00127 
00128 int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
00129                    int flags)
00130 {
00131         int updated = 0;
00132         STRUCT_STAT st2;
00133         int change_uid, change_gid;
00134 
00135         if (!st) {
00136                 if (dry_run)
00137                         return 1;
00138                 if (link_stat(fname, &st2, 0) < 0) {
00139                         rsyserr(FERROR, errno, "stat %s failed",
00140                                 full_fname(fname));
00141                         return 0;
00142                 }
00143                 st = &st2;
00144                 if (!preserve_perms && S_ISDIR(file->mode)
00145                  && st->st_mode & S_ISGID) {
00146                         /* We just created this directory and its setgid
00147                          * bit is on, so make sure it stays on. */
00148                         file->mode |= S_ISGID;
00149                 }
00150         }
00151 
00152         if (!preserve_times || (S_ISDIR(st->st_mode) && omit_dir_times))
00153                 flags |= ATTRS_SKIP_MTIME;
00154         if (!(flags & ATTRS_SKIP_MTIME)
00155             && cmp_time(st->st_mtime, file->modtime) != 0) {
00156                 int ret = set_modtime(fname, file->modtime, st->st_mode);
00157                 if (ret < 0) {
00158                         rsyserr(FERROR, errno, "failed to set times on %s",
00159                                 full_fname(fname));
00160                         return 0;
00161                 }
00162                 if (ret == 0) /* ret == 1 if symlink could not be set */
00163                         updated = 1;
00164         }
00165 
00166         change_uid = am_root && preserve_uid && st->st_uid != file->uid;
00167         change_gid = preserve_gid && file->gid != GID_NONE
00168                 && st->st_gid != file->gid;
00169 #if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
00170         if (S_ISLNK(st->st_mode))
00171                 ;
00172         else
00173 #endif
00174         if (change_uid || change_gid) {
00175                 if (verbose > 2) {
00176                         if (change_uid) {
00177                                 rprintf(FINFO,
00178                                         "set uid of %s from %ld to %ld\n",
00179                                         fname,
00180                                         (long)st->st_uid, (long)file->uid);
00181                         }
00182                         if (change_gid) {
00183                                 rprintf(FINFO,
00184                                         "set gid of %s from %ld to %ld\n",
00185                                         fname,
00186                                         (long)st->st_gid, (long)file->gid);
00187                         }
00188                 }
00189                 if (do_lchown(fname,
00190                     change_uid ? file->uid : st->st_uid,
00191                     change_gid ? file->gid : st->st_gid) != 0) {
00192                         /* shouldn't have attempted to change uid or gid
00193                          * unless have the privilege */
00194                         rsyserr(FERROR, errno, "%s %s failed",
00195                             change_uid ? "chown" : "chgrp",
00196                             full_fname(fname));
00197                         return 0;
00198                 }
00199                 /* a lchown had been done - we have to re-stat if the
00200                  * destination had the setuid or setgid bits set due
00201                  * to the side effect of the chown call */
00202                 if (st->st_mode & (S_ISUID | S_ISGID)) {
00203                         link_stat(fname, st,
00204                                   keep_dirlinks && S_ISDIR(st->st_mode));
00205                 }
00206                 updated = 1;
00207         }
00208 
00209 #ifdef SUPPORT_ACLS
00210         /* It's OK to call set_acl() now, even for a dir, as the generator
00211          * will enable owner-writability using chmod, if necessary.
00212          * 
00213          * If set_acl changes permission bits in the process of setting
00214          * an access ACL, it changes st->st_mode so we know whether we
00215          * need to chmod. */
00216         if (preserve_acls && set_acl(fname, file, &st->st_mode) == 0)
00217                 updated = 1;
00218 #endif
00219 #ifdef SUPPORT_XATTRS
00220         if (preserve_xattrs && set_xattr(fname, file) == 0)
00221                 updated = 1;
00222 #endif
00223 
00224 #ifdef HAVE_CHMOD
00225         if ((st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) {
00226                 int ret = do_chmod(fname, file->mode);
00227                 if (ret < 0) {
00228                         rsyserr(FERROR, errno,
00229                                 "failed to set permissions on %s",
00230                                 full_fname(fname));
00231                         return 0;
00232                 }
00233                 if (ret == 0) /* ret == 1 if symlink could not be set */
00234                         updated = 1;
00235         }
00236 #endif
00237 
00238         if (verbose > 1 && flags & ATTRS_REPORT) {
00239                 enum logcode code = daemon_log_format_has_i || dry_run
00240                                   ? FCLIENT : FINFO;
00241                 if (updated)
00242                         rprintf(code, "%s\n", fname);
00243                 else
00244                         rprintf(code, "%s is uptodate\n", fname);
00245         }
00246         return updated;
00247 }
00248 
00249 RETSIGTYPE sig_int(UNUSED(int val))
00250 {
00251         /* KLUGE: if the user hits Ctrl-C while ssh is prompting
00252          * for a password, then our cleanup's sending of a SIGUSR1
00253          * signal to all our children may kill ssh before it has a
00254          * chance to restore the tty settings (i.e. turn echo back
00255          * on).  By sleeping for a short time, ssh gets a bigger
00256          * chance to do the right thing.  If child processes are
00257          * not ssh waiting for a password, then this tiny delay
00258          * shouldn't hurt anything. */
00259         msleep(400);
00260         exit_cleanup(RERR_SIGNAL);
00261 }
00262 
00263 /* Finish off a file transfer: renaming the file and setting the file's
00264  * attributes (e.g. permissions, ownership, etc.).  If partialptr is not
00265  * NULL and the robust_rename() call is forced to copy the temp file, we
00266  * stage the file into the partial-dir and then rename it into place. */
00267 void finish_transfer(char *fname, char *fnametmp, char *partialptr,
00268                      struct file_struct *file, int ok_to_set_time,
00269                      int overwriting_basis)
00270 {
00271         int ret;
00272 
00273         if (inplace) {
00274                 if (verbose > 2)
00275                         rprintf(FINFO, "finishing %s\n", fname);
00276                 fnametmp = fname;
00277                 goto do_set_file_attrs;
00278         }
00279 
00280         if (make_backups && overwriting_basis && !make_backup(fname))
00281                 return;
00282 
00283         /* Change permissions before putting the file into place. */
00284         set_file_attrs(fnametmp, file, NULL,
00285                        ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
00286 
00287         /* move tmp file over real file */
00288         if (verbose > 2)
00289                 rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
00290         ret = robust_rename(fnametmp, fname, partialptr,
00291                             file->mode & INITACCESSPERMS);
00292         if (ret < 0) {
00293                 rsyserr(FERROR, errno, "%s %s -> \"%s\"",
00294                         ret == -2 ? "copy" : "rename",
00295                         full_fname(fnametmp), fname);
00296                 do_unlink(fnametmp);
00297                 return;
00298         }
00299         if (ret == 0) {
00300                 /* The file was moved into place (not copied), so it's done. */
00301                 return;
00302         }
00303         /* The file was copied, so tweak the perms of the copied file.  If it
00304          * was copied to partialptr, move it into its final destination. */
00305         fnametmp = partialptr ? partialptr : fname;
00306 
00307   do_set_file_attrs:
00308         set_file_attrs(fnametmp, file, NULL,
00309                        ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
00310 
00311         if (partialptr) {
00312                 if (do_rename(fnametmp, fname) < 0) {
00313                         rsyserr(FERROR, errno, "rename %s -> \"%s\"",
00314                                 full_fname(fnametmp), fname);
00315                 } else
00316                         handle_partial_dir(partialptr, PDIR_DELETE);
00317         }
00318 }
00319 
00320 const char *who_am_i(void)
00321 {
00322         if (am_starting_up)
00323                 return am_server ? "server" : "client";
00324         return am_sender ? "sender" : am_generator ? "generator" : "receiver";
00325 }

rsyncに対してSat Dec 5 19:45:42 2009に生成されました。  doxygen 1.4.7