Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

rsync.c

Go to the documentation of this file.
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 
00025 extern int verbose;
00026 extern int dry_run;
00027 extern int preserve_times;
00028 extern int am_root;
00029 extern int preserve_uid;
00030 extern int preserve_gid;
00031 extern int preserve_perms;
00032 extern int make_backups;
00033 
00034 
00035 /*
00036   free a sums struct
00037   */
00038 void free_sums(struct sum_struct *s)
00039 {
00040         if (s->sums) free(s->sums);
00041         free(s);
00042 }
00043 
00044 
00045 /*
00046  * delete a file or directory. If force_delete is set then delete 
00047  * recursively 
00048  */
00049 int delete_file(char *fname)
00050 {
00051         DIR *d;
00052         struct dirent *di;
00053         char buf[MAXPATHLEN];
00054         extern int force_delete;
00055         STRUCT_STAT st;
00056         int ret;
00057         extern int recurse;
00058 
00059 #if SUPPORT_LINKS
00060         ret = do_lstat(fname, &st);
00061 #else
00062         ret = do_stat(fname, &st);
00063 #endif
00064         if (ret) {
00065                 return -1;
00066         }
00067 
00068         if (!S_ISDIR(st.st_mode)) {
00069                 if (robust_unlink(fname) == 0 || errno == ENOENT) return 0;
00070                 rprintf(FERROR,"delete_file: unlink(%s) : %s\n", fname, strerror(errno));
00071                 return -1;
00072         }
00073 
00074         if (do_rmdir(fname) == 0 || errno == ENOENT) return 0;
00075         if (!force_delete || !recurse || 
00076             (errno != ENOTEMPTY && errno != EEXIST)) {
00077                 rprintf(FERROR,"delete_file: rmdir(%s) : %s\n", fname, strerror(errno));
00078                 return -1;
00079         }
00080 
00081         /* now we do a recsursive delete on the directory ... */
00082         d = opendir(fname);
00083         if (!d) {
00084                 rprintf(FERROR,"delete_file: opendir(%s): %s\n",
00085                         fname,strerror(errno));
00086                 return -1;
00087         }
00088 
00089         for (di=readdir(d); di; di=readdir(d)) {
00090                 char *dname = d_name(di);
00091                 if (strcmp(dname,".")==0 ||
00092                     strcmp(dname,"..")==0)
00093                         continue;
00094                 snprintf(buf, sizeof(buf), "%s/%s", fname, dname);
00095                 if (verbose > 0)
00096                         rprintf(FINFO,"deleting %s\n", buf);
00097                 if (delete_file(buf) != 0) {
00098                         closedir(d);
00099                         return -1;
00100                 }
00101         }       
00102 
00103         closedir(d);
00104         
00105         if (do_rmdir(fname) != 0) {
00106                 rprintf(FERROR,"delete_file: rmdir(%s) : %s\n", fname, strerror(errno));
00107                 return -1;
00108         }
00109 
00110         return 0;
00111 }
00112 
00113 static int is_in_group(gid_t gid)
00114 {
00115 #ifdef GETGROUPS_T
00116         static gid_t last_in = (gid_t) -2, last_out;
00117         static int ngroups = -2;
00118         static GETGROUPS_T *gidset;
00119         int n;
00120 
00121         if (gid == last_in)
00122                 return last_out;
00123         if (ngroups < -1) {
00124                 /* treat failure (-1) as if not member of any group */
00125                 ngroups = getgroups(0, 0);
00126                 if (ngroups > 0) {
00127                         gidset = (GETGROUPS_T *) malloc(ngroups * sizeof(GETGROUPS_T));
00128                         ngroups = getgroups(ngroups, gidset);
00129                 }
00130         }
00131 
00132         last_in = gid;
00133         last_out = 0;
00134         for (n = 0; n < ngroups; n++) {
00135                 if (gidset[n] == gid) {
00136                         last_out = 1;
00137                         break;
00138                 }
00139         }
00140         return last_out;
00141 
00142 #else
00143         return 0;
00144 #endif
00145 }
00146 
00147 int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
00148               int report)
00149 {
00150         int updated = 0;
00151         STRUCT_STAT st2;
00152         int change_uid, change_gid;
00153 
00154         if (dry_run) return 0;
00155 
00156         if (!st) {
00157                 if (link_stat(fname,&st2) != 0) {
00158                         rprintf(FERROR,"stat %s : %s\n",fname,strerror(errno));
00159                         return 0;
00160                 }
00161                 st = &st2;
00162         }
00163 
00164         if (preserve_times && !S_ISLNK(st->st_mode) &&
00165             cmp_modtime(st->st_mtime, file->modtime) != 0) {
00166                 /* don't complain about not setting times on directories
00167                    because some filesystems can't do it */
00168                 if (set_modtime(fname,file->modtime) != 0 &&
00169                     !S_ISDIR(st->st_mode)) {
00170                         rprintf(FERROR,"failed to set times on %s : %s\n",
00171                                 fname,strerror(errno));
00172                         return 0;
00173                 } else {
00174                         updated = 1;
00175                 }
00176         }
00177 
00178         change_uid = am_root && preserve_uid && st->st_uid != file->uid;
00179         change_gid = preserve_gid && file->gid != (gid_t) -1 && \
00180                                 st->st_gid != file->gid;
00181         if (change_gid && !am_root) {
00182                 /* enforce bsd-style group semantics: non-root can only
00183                     change to groups that the user is a member of */
00184                 change_gid = is_in_group(file->gid);
00185         }
00186         if (change_uid || change_gid) {
00187                 if (do_lchown(fname,
00188                               change_uid?file->uid:st->st_uid,
00189                               change_gid?file->gid:st->st_gid) != 0) {
00190                         /* shouldn't have attempted to change uid or gid
00191                              unless have the privilege */
00192                         rprintf(FERROR,"chown %s : %s\n", fname,strerror(errno));
00193                         return 0;
00194                 }
00195                 /* a lchown had been done - we have to re-stat if the
00196                    destination had the setuid or setgid bits set due
00197                    to the side effect of the chown call */
00198                 if (st->st_mode & (S_ISUID | S_ISGID)) {
00199                         link_stat(fname, st);
00200                 }
00201                 updated = 1;
00202         }
00203 
00204 #ifdef HAVE_CHMOD
00205         if (!S_ISLNK(st->st_mode)) {
00206                 if (st->st_mode != file->mode) {
00207                         updated = 1;
00208                         if (do_chmod(fname,file->mode) != 0) {
00209                                 rprintf(FERROR,"failed to set permissions on %s : %s\n",
00210                                         fname,strerror(errno));
00211                                 return 0;
00212                         }
00213                 }
00214         }
00215 #endif
00216     
00217         if (verbose > 1 && report) {
00218                 if (updated)
00219                         rprintf(FINFO,"%s\n",fname);
00220                 else
00221                         rprintf(FINFO,"%s is uptodate\n",fname);
00222         }
00223         return updated;
00224 }
00225 
00226 
00227 void sig_int(void)
00228 {
00229         exit_cleanup(RERR_SIGNAL);
00230 }
00231 
00232 
00233 /* finish off a file transfer, renaming the file and setting the permissions
00234    and ownership */
00235 void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
00236 {
00237         if (make_backups && !make_backup(fname))
00238                 return;
00239 
00240         /* move tmp file over real file */
00241         if (robust_rename(fnametmp,fname) != 0) {
00242                 if (errno == EXDEV) {
00243                         /* rename failed on cross-filesystem link.  
00244                            Copy the file instead. */
00245                         if (copy_file(fnametmp,fname, file->mode & INITACCESSPERMS)) {
00246                                 rprintf(FERROR,"copy %s -> %s : %s\n",
00247                                         fnametmp,fname,strerror(errno));
00248                         } else {
00249                                 set_perms(fname,file,NULL,0);
00250                         }
00251                 } else {
00252                         rprintf(FERROR,"rename %s -> %s : %s\n",
00253                                 fnametmp,fname,strerror(errno));
00254                 }
00255                 do_unlink(fnametmp);
00256         } else {
00257                 set_perms(fname,file,NULL,0);
00258         }
00259 }

Generated on Tue Apr 16 12:37:37 2002 for rsync by doxygen1.2.15