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

generator.c

Go to the documentation of this file.
00001 /* -*- c-file-style: "linux" -*-
00002 
00003    rsync -- fast file replication program
00004    
00005    Copyright (C) 1996-2000 by Andrew Tridgell 
00006    Copyright (C) Paul Mackerras 1996
00007    Copyright (C) 2002 by Martin Pool <mbp@samba.org>
00008    
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 2 of the License, or
00012    (at your option) any later version.
00013    
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018    
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022 */
00023 
00024 #include "rsync.h"
00025 
00026 extern int verbose;
00027 extern int dry_run;
00028 extern int relative_paths;
00029 extern int preserve_links;
00030 extern int am_root;
00031 extern int preserve_devices;
00032 extern int preserve_hard_links;
00033 extern int update_only;
00034 extern int opt_ignore_existing;
00035 extern int block_size;
00036 extern int csum_length;
00037 extern int ignore_times;
00038 extern int size_only;
00039 extern int io_timeout;
00040 extern int remote_version;
00041 extern int always_checksum;
00042 extern int modify_window;
00043 extern char *compare_dest;
00044 
00045 
00046 /* choose whether to skip a particular file */
00047 static int skip_file(char *fname,
00048                      struct file_struct *file, STRUCT_STAT *st)
00049 {
00050         if (st->st_size != file->length) {
00051                 return 0;
00052         }
00053         
00054         /* if always checksum is set then we use the checksum instead 
00055            of the file time to determine whether to sync */
00056         if (always_checksum && S_ISREG(st->st_mode)) {
00057                 char sum[MD4_SUM_LENGTH];
00058                 char fnamecmpdest[MAXPATHLEN];
00059 
00060                 if (compare_dest != NULL) {
00061                         if (access(fname, 0) != 0) {
00062                                 snprintf(fnamecmpdest,MAXPATHLEN,"%s/%s",
00063                                                     compare_dest,fname);
00064                                 fname = fnamecmpdest;
00065                         }
00066                 }
00067                 file_checksum(fname,sum,st->st_size);
00068                 if (remote_version < 21) {
00069                         return (memcmp(sum,file->sum,2) == 0);
00070                 } else {
00071                         return (memcmp(sum,file->sum,MD4_SUM_LENGTH) == 0);
00072                 }
00073         }
00074 
00075         if (size_only) {
00076                 return 1;
00077         }
00078 
00079         if (ignore_times) {
00080                 return 0;
00081         }
00082 
00083         return (cmp_modtime(st->st_mtime,file->modtime) == 0);
00084 }
00085 
00086 
00087 /* use a larger block size for really big files */
00088 static int adapt_block_size(struct file_struct *file, int bsize)
00089 {
00090         int ret;
00091 
00092         if (bsize != BLOCK_SIZE) return bsize;
00093 
00094         ret = file->length / (10000); /* rough heuristic */
00095         ret = ret & ~15; /* multiple of 16 */
00096         if (ret < bsize) ret = bsize;
00097         if (ret > CHUNK_SIZE/2) ret = CHUNK_SIZE/2;
00098         return ret;
00099 }
00100 
00101 
00102 /*
00103   send a sums struct down a fd
00104   */
00105 static void send_sums(struct sum_struct *s, int f_out)
00106 {
00107         if (s) {
00108                 size_t i;
00109 
00110                 /* tell the other guy how many we are going to be
00111                    doing and how many bytes there are in the last
00112                    chunk */
00113                 write_int(f_out, s->count);
00114                 write_int(f_out, s->n);
00115                 write_int(f_out, s->remainder);
00116 
00117                 for (i = 0; i < s->count; i++) {
00118                         write_int(f_out, s->sums[i].sum1);
00119                         write_buf(f_out, s->sums[i].sum2, csum_length);
00120                 }
00121         } else {
00122                 /* we don't have checksums */
00123                 write_int(f_out, 0);
00124                 write_int(f_out, block_size);
00125                 write_int(f_out, 0);
00126         }
00127 }
00128 
00129 
00130 /**
00131  * Perhaps we want to just send an empty checksum set for this file,
00132  * which will force the whole thing to be literally transferred.
00133  *
00134  * When do we do this?  If the user's explicitly said they
00135  * want the whole thing, or if { they haven't explicitly
00136  * requested a delta, and it's local but not batch mode.}
00137  *
00138  * Whew. */
00139 static BOOL disable_deltas_p(void)
00140 {
00141         extern int whole_file, no_whole_file;
00142         extern int local_server;
00143         extern int write_batch;
00144 
00145         assert(whole_file == 0 || whole_file == 1);
00146 
00147         /* whole_file and no_whole_file are never both on at the same time */
00148 
00149         if (whole_file)
00150                 return True;
00151         else if (no_whole_file)
00152                 return False;
00153         else if (write_batch)
00154                 return False;
00155         else
00156                 return local_server;
00157 }
00158 
00159 
00160 /**
00161  * Generate a stream of signatures/checksums that describe a buffer.
00162  *
00163  * Generate approximately one checksum every @p n bytes.
00164  *
00165  * @return Newly-allocated sum_struct
00166  **/
00167 static struct sum_struct *generate_sums(struct map_struct *buf, OFF_T len,
00168                                         int n)
00169 {
00170         int i;
00171         struct sum_struct *s;
00172         int count;
00173         int block_len = n;
00174         int remainder = (len % block_len);
00175         OFF_T offset = 0;
00176 
00177         count = (len + (block_len - 1)) / block_len;
00178 
00179         s = (struct sum_struct *) malloc(sizeof(*s));
00180         if (!s)
00181                 out_of_memory("generate_sums");
00182 
00183         s->count = count;
00184         s->remainder = remainder;
00185         s->n = n;
00186         s->flength = len;
00187 
00188         if (count == 0) {
00189                 s->sums = NULL;
00190                 return s;
00191         }
00192 
00193         if (verbose > 3) {
00194                 rprintf(FINFO, "count=%ld rem=%ld n=%ld flength=%.0f\n",
00195                         (long) s->count, (long) s->remainder,
00196                         (long) s->n, (double) s->flength);
00197         }
00198 
00199         s->sums = (struct sum_buf *) malloc(sizeof(s->sums[0]) * s->count);
00200         if (!s->sums)
00201                 out_of_memory("generate_sums");
00202 
00203         for (i = 0; i < count; i++) {
00204                 int n1 = MIN(len, n);
00205                 char *map = map_ptr(buf, offset, n1);
00206 
00207                 s->sums[i].sum1 = get_checksum1(map, n1);
00208                 get_checksum2(map, n1, s->sums[i].sum2);
00209 
00210                 s->sums[i].offset = offset;
00211                 s->sums[i].len = n1;
00212                 s->sums[i].i = i;
00213 
00214                 if (verbose > 3)
00215                         rprintf(FINFO,
00216                                 "chunk[%d] offset=%.0f len=%d sum1=%08x\n",
00217                                 i, (double) s->sums[i].offset,
00218                                 s->sums[i].len, s->sums[i].sum1);
00219 
00220                 len -= n1;
00221                 offset += n1;
00222         }
00223 
00224         return s;
00225 }
00226 
00227 
00228 
00229 /**
00230  * Acts on file number @p i from @p flist, whose name is @p fname.
00231  *
00232  * First fixes up permissions, then generates checksums for the file.
00233  *
00234  * @note This comment was added later by mbp who was trying to work it
00235  * out.  It might be wrong.
00236  **/ 
00237 void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
00238 {  
00239         int fd;
00240         STRUCT_STAT st;
00241         struct map_struct *buf;
00242         struct sum_struct *s;
00243         int statret;
00244         struct file_struct *file = flist->files[i];
00245         char *fnamecmp;
00246         char fnamecmpbuf[MAXPATHLEN];
00247         extern char *compare_dest;
00248         extern int list_only;
00249         extern int preserve_perms;
00250         extern int only_existing;
00251         extern int orig_umask;
00252 
00253         if (list_only) return;
00254 
00255         if (verbose > 2)
00256                 rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
00257 
00258         statret = link_stat(fname,&st);
00259 
00260         if (only_existing && statret == -1 && errno == ENOENT) {
00261                 /* we only want to update existing files */
00262                 if (verbose > 1) rprintf(FINFO, "not creating new file \"%s\"\n",fname);
00263                 return;
00264         }
00265 
00266         if (statret == 0 && 
00267             !preserve_perms && 
00268             (S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
00269                 /* if the file exists already and we aren't perserving
00270                    presmissions then act as though the remote end sent
00271                    us the file permissions we already have */
00272                 file->mode = (file->mode & _S_IFMT) | (st.st_mode & ~_S_IFMT);
00273         }
00274 
00275         if (S_ISDIR(file->mode)) {
00276                 /* The file to be received is a directory, so we need
00277                  * to prepare appropriately.  If there is already a
00278                  * file of that name and it is *not* a directory, then
00279                  * we need to delete it.  If it doesn't exist, then
00280                  * recursively create it. */
00281           
00282                 if (dry_run) return; /* XXXX -- might cause inaccuracies?? -- mbp */
00283                 if (statret == 0 && !S_ISDIR(st.st_mode)) {
00284                         if (robust_unlink(fname) != 0) {
00285                                 rprintf(FERROR, RSYNC_NAME
00286                                         ": recv_generator: unlink \"%s\" to make room for directory: %s\n",
00287                                         fname,strerror(errno));
00288                                 return;
00289                         }
00290                         statret = -1;
00291                 }
00292                 if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
00293                         if (!(relative_paths && errno==ENOENT && 
00294                               create_directory_path(fname, orig_umask)==0 && 
00295                               do_mkdir(fname,file->mode)==0)) {
00296                                 rprintf(FERROR, RSYNC_NAME ": recv_generator: mkdir \"%s\": %s (2)\n",
00297                                         fname,strerror(errno));
00298                         }
00299                 }
00300                 /* f_out is set to -1 when doing final directory 
00301                    permission and modification time repair */
00302                 if (set_perms(fname,file,NULL,0) && verbose && (f_out != -1)) 
00303                         rprintf(FINFO,"%s/\n",fname);
00304                 return;
00305         }
00306 
00307         if (preserve_links && S_ISLNK(file->mode)) {
00308 #if SUPPORT_LINKS
00309                 char lnk[MAXPATHLEN];
00310                 int l;
00311                 extern int safe_symlinks;
00312 
00313                 if (safe_symlinks && unsafe_symlink(file->link, fname)) {
00314                         if (verbose) {
00315                                 rprintf(FINFO,"ignoring unsafe symlink \"%s\" -> \"%s\"\n",
00316                                         fname,file->link);
00317                         }
00318                         return;
00319                 }
00320                 if (statret == 0) {
00321                         l = readlink(fname,lnk,MAXPATHLEN-1);
00322                         if (l > 0) {
00323                                 lnk[l] = 0;
00324                                 /* A link already pointing to the
00325                                  * right place -- no further action
00326                                  * required. */
00327                                 if (strcmp(lnk,file->link) == 0) {
00328                                         set_perms(fname,file,&st,1);
00329                                         return;
00330                                 }
00331                         }  
00332                         /* Not a symlink, so delete whatever's
00333                          * already there and put a new symlink
00334                          * in place. */                    
00335                         delete_file(fname);
00336                 }
00337                 if (do_symlink(file->link,fname) != 0) {
00338                         rprintf(FERROR,RSYNC_NAME": symlink \"%s\" -> \"%s\": %s\n",
00339                                 fname,file->link,strerror(errno));
00340                 } else {
00341                         set_perms(fname,file,NULL,0);
00342                         if (verbose) {
00343                                 rprintf(FINFO,"%s -> %s\n", fname,file->link);
00344                         }
00345                 }
00346 #endif
00347                 return;
00348         }
00349 
00350 #ifdef HAVE_MKNOD
00351         if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
00352                 if (statret != 0 || 
00353                     st.st_mode != file->mode ||
00354                     st.st_rdev != file->rdev) { 
00355                         delete_file(fname);
00356                         if (verbose > 2)
00357                                 rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
00358                                         fname,(int)file->mode,(int)file->rdev);
00359                         if (do_mknod(fname,file->mode,file->rdev) != 0) {
00360                                 rprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno));
00361                         } else {
00362                                 set_perms(fname,file,NULL,0);
00363                                 if (verbose)
00364                                         rprintf(FINFO,"%s\n",fname);
00365                         }
00366                 } else {
00367                         set_perms(fname,file,&st,1);
00368                 }
00369                 return;
00370         }
00371 #endif
00372 
00373         if (preserve_hard_links && check_hard_link(file)) {
00374                 if (verbose > 1)
00375                         rprintf(FINFO, "recv_generator: \"%s\" is a hard link\n",f_name(file));
00376                 return;
00377         }
00378 
00379         if (!S_ISREG(file->mode)) {
00380                 rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
00381                 return;
00382         }
00383 
00384         fnamecmp = fname;
00385 
00386         if ((statret == -1) && (compare_dest != NULL)) {
00387                 /* try the file at compare_dest instead */
00388                 int saveerrno = errno;
00389                 snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
00390                 statret = link_stat(fnamecmpbuf,&st);
00391                 if (!S_ISREG(st.st_mode))
00392                         statret = -1;
00393                 if (statret == -1)
00394                         errno = saveerrno;
00395                 else
00396                         fnamecmp = fnamecmpbuf;
00397         }
00398 
00399         if (statret == -1) {
00400                 if (errno == ENOENT) {
00401                         write_int(f_out,i);
00402                         if (!dry_run) send_sums(NULL,f_out);
00403                 } else {
00404                         if (verbose > 1)
00405                                 rprintf(FERROR, RSYNC_NAME
00406                                         ": recv_generator failed to open \"%s\": %s\n",
00407                                         fname, strerror(errno));
00408                 }
00409                 return;
00410         }
00411 
00412         if (!S_ISREG(st.st_mode)) {
00413                 if (delete_file(fname) != 0) {
00414                         return;
00415                 }
00416 
00417                 /* now pretend the file didn't exist */
00418                 write_int(f_out,i);
00419                 if (!dry_run) send_sums(NULL,f_out);    
00420                 return;
00421         }
00422 
00423         if (opt_ignore_existing && fnamecmp == fname) { 
00424                 if (verbose > 1)
00425                         rprintf(FINFO,"%s exists\n",fname);
00426                 return;
00427         } 
00428 
00429         if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
00430                 if (verbose > 1)
00431                         rprintf(FINFO,"%s is newer\n",fname);
00432                 return;
00433         }
00434 
00435         if (skip_file(fname, file, &st)) {
00436                 if (fnamecmp == fname)
00437                         set_perms(fname,file,&st,1);
00438                 return;
00439         }
00440 
00441         if (dry_run) {
00442                 write_int(f_out,i);
00443                 return;
00444         }
00445 
00446         if (disable_deltas_p()) {
00447                 write_int(f_out,i);
00448                 send_sums(NULL,f_out);    
00449                 return;
00450         }
00451 
00452         /* open the file */  
00453         fd = do_open(fnamecmp, O_RDONLY, 0);
00454 
00455         if (fd == -1) {
00456                 rprintf(FERROR,RSYNC_NAME": failed to open \"%s\", continuing : %s\n",fnamecmp,strerror(errno));
00457                 /* pretend the file didn't exist */
00458                 write_int(f_out,i);
00459                 send_sums(NULL,f_out);
00460                 return;
00461         }
00462 
00463         if (st.st_size > 0) {
00464                 buf = map_file(fd,st.st_size);
00465         } else {
00466                 buf = NULL;
00467         }
00468 
00469         if (verbose > 3)
00470                 rprintf(FINFO,"gen mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
00471 
00472         s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));
00473 
00474         if (verbose > 2)
00475                 rprintf(FINFO,"sending sums for %d\n",i);
00476 
00477         write_int(f_out,i);
00478         send_sums(s,f_out);
00479 
00480         close(fd);
00481         if (buf) unmap_file(buf);
00482 
00483         free_sums(s);
00484 }
00485 
00486 
00487 
00488 void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
00489 {
00490         int i;
00491         int phase=0;
00492 
00493         if (verbose > 2)
00494                 rprintf(FINFO,"generator starting pid=%d count=%d\n",
00495                         (int)getpid(),flist->count);
00496 
00497         if (verbose >= 2) {
00498                 rprintf(FINFO,
00499                         disable_deltas_p() 
00500                         ? "delta-transmission disabled for local transfer or --whole-file\n"
00501                         : "delta transmission enabled\n");
00502         }
00503         
00504         /* we expect to just sit around now, so don't exit on a
00505            timeout. If we really get a timeout then the other process should
00506            exit */
00507         io_timeout = 0;
00508 
00509         for (i = 0; i < flist->count; i++) {
00510                 struct file_struct *file = flist->files[i];
00511                 mode_t saved_mode = file->mode;
00512                 if (!file->basename) continue;
00513 
00514                 /* we need to ensure that any directories we create have writeable
00515                    permissions initially so that we can create the files within
00516                    them. This is then fixed after the files are transferred */
00517                 if (!am_root && S_ISDIR(file->mode)) {
00518                         file->mode |= S_IWUSR; /* user write */
00519                         /* XXX: Could this be causing a problem on SCO?  Perhaps their
00520                          * handling of permissions is strange? */
00521                 }
00522 
00523                 recv_generator(local_name?local_name:f_name(file),
00524                                flist,i,f);
00525 
00526                 file->mode = saved_mode;
00527         }
00528 
00529         phase++;
00530         csum_length = SUM_LENGTH;
00531         ignore_times=1;
00532 
00533         if (verbose > 2)
00534                 rprintf(FINFO,"generate_files phase=%d\n",phase);
00535 
00536         write_int(f,-1);
00537 
00538         if (remote_version >= 13) {
00539                 /* in newer versions of the protocol the files can cycle through
00540                    the system more than once to catch initial checksum errors */
00541                 for (i=read_int(f_recv); i != -1; i=read_int(f_recv)) {
00542                         struct file_struct *file = flist->files[i];
00543                         recv_generator(local_name?local_name:f_name(file),
00544                                        flist,i,f);    
00545                 }
00546 
00547                 phase++;
00548                 if (verbose > 2)
00549                         rprintf(FINFO,"generate_files phase=%d\n",phase);
00550 
00551                 write_int(f,-1);
00552         }
00553 }

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