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

generator.c File Reference

Go to the source code of this file.

Functions

int skip_file (char *fname, struct file_struct *file, STRUCT_STAT *st)
int adapt_block_size (struct file_struct *file, int bsize)
void send_sums (struct sum_struct *s, int f_out)
BOOL disable_deltas_p (void)
 Perhaps we want to just send an empty checksum set for this file, which will force the whole thing to be literally transferred. More...

sum_structgenerate_sums (struct map_struct *buf, OFF_T len, int n)
 Generate a stream of signatures/checksums that describe a buffer. More...

void recv_generator (char *fname, struct file_list *flist, int i, int f_out)
 Acts on file number i from flist, whose name is fname. More...

void generate_files (int f, struct file_list *flist, char *local_name, int f_recv)

Variables

int verbose
int dry_run
int relative_paths
int preserve_links
int am_root
int preserve_devices
int preserve_hard_links
int update_only
int opt_ignore_existing
int block_size
int csum_length
int ignore_times
int size_only
int io_timeout
int remote_version
int always_checksum
int modify_window = 0
char * compare_dest


Function Documentation

int skip_file char *    fname,
struct file_struct   file,
STRUCT_STAT *    st
[static]
 

Definition at line 47 of file generator.c.

References always_checksum, cmp_modtime(), compare_dest, file_checksum(), file_struct::length, file_struct::modtime, remote_version, snprintf(), and file_struct::sum.

Referenced by recv_generator().

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 }

int adapt_block_size struct file_struct   file,
int    bsize
[static]
 

Definition at line 88 of file generator.c.

References file_struct::length.

Referenced by recv_generator().

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 }

void send_sums struct sum_struct   s,
int    f_out
[static]
 

Definition at line 105 of file generator.c.

References block_size, sum_struct::count, csum_length, sum_struct::n, sum_struct::remainder, sum_buf::sum1, sum_buf::sum2, sum_struct::sums, write_buf(), and write_int().

Referenced by recv_generator().

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 }

BOOL disable_deltas_p void    [static]
 

Perhaps we want to just send an empty checksum set for this file, which will force the whole thing to be literally transferred.

When do we do this? If the user's explicitly said they want the whole thing, or if { they haven't explicitly requested a delta, and it's local but not batch mode.}

Whew.

Definition at line 139 of file generator.c.

References local_server, no_whole_file, and whole_file.

Referenced by generate_files(), and recv_generator().

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 }

struct sum_struct* generate_sums struct map_struct   buf,
OFF_T    len,
int    n
[static]
 

Generate a stream of signatures/checksums that describe a buffer.

Generate approximately one checksum every n bytes.

Returns:
Newly-allocated sum_struct

Definition at line 167 of file generator.c.

References sum_struct::count, FINFO, sum_struct::flength, get_checksum1(), get_checksum2(), sum_buf::i, sum_buf::len, map_ptr(), sum_struct::n, sum_buf::offset, out_of_memory(), sum_struct::remainder, rprintf(), sum_buf::sum1, sum_buf::sum2, sum_struct::sums, and verbose.

Referenced by recv_generator().

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 }

void recv_generator char *    fname,
struct file_list   flist,
int    i,
int    f_out
 

Acts on file number i from flist, whose name is fname.

First fixes up permissions, then generates checksums for the file.

Note:
This comment was added later by mbp who was trying to work it out. It might be wrong.

Definition at line 237 of file generator.c.

References adapt_block_size(), am_root, block_size, check_hard_link(), cmp_modtime(), compare_dest, create_directory_path(), delete_file(), disable_deltas_p(), do_mkdir(), do_mknod(), do_open(), do_symlink(), dry_run, f_name(), FERROR, file_list::files, FINFO, free_sums(), generate_sums(), file_struct::link, link_stat(), map_file(), file_struct::mode, file_struct::modtime, only_existing, opt_ignore_existing, orig_umask, preserve_devices, preserve_hard_links, preserve_links, file_struct::rdev, relative_paths, robust_unlink(), rprintf(), safe_symlinks, send_sums(), set_perms(), skip_file(), snprintf(), unmap_file(), unsafe_symlink(), update_only, verbose, and write_int().

Referenced by generate_files(), and recv_files().

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 }

void generate_files int    f,
struct file_list   flist,
char *    local_name,
int    f_recv
 

Definition at line 488 of file generator.c.

References am_root, file_struct::basename, file_list::count, csum_length, disable_deltas_p(), file_list::files, FINFO, ignore_times, io_timeout, file_struct::mode, read_int(), recv_generator(), remote_version, rprintf(), verbose, and write_int().

Referenced by do_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 }


Variable Documentation

int verbose
 

Definition at line 26 of file generator.c.

Referenced by generate_files(), generate_sums(), and recv_generator().

int dry_run
 

Definition at line 27 of file generator.c.

Referenced by recv_generator().

int relative_paths
 

Definition at line 28 of file generator.c.

Referenced by recv_generator().

int preserve_links
 

Definition at line 29 of file generator.c.

Referenced by parse_arguments(), and recv_generator().

int am_root
 

Definition at line 30 of file generator.c.

Referenced by generate_files(), and recv_generator().

int preserve_devices
 

Definition at line 31 of file generator.c.

Referenced by parse_arguments(), and recv_generator().

int preserve_hard_links
 

Definition at line 32 of file generator.c.

Referenced by recv_generator().

int update_only
 

Definition at line 33 of file generator.c.

Referenced by recv_generator().

int opt_ignore_existing
 

Definition at line 34 of file generator.c.

Referenced by recv_generator(), and server_options().

int block_size
 

Definition at line 35 of file generator.c.

Referenced by recv_generator(), send_sums(), and server_options().

int csum_length
 

Definition at line 36 of file generator.c.

Referenced by generate_files(), and send_sums().

int ignore_times
 

Definition at line 37 of file generator.c.

Referenced by generate_files().

int size_only
 

Definition at line 38 of file generator.c.

int io_timeout
 

Definition at line 39 of file generator.c.

Referenced by generate_files().

int remote_version
 

Definition at line 40 of file generator.c.

Referenced by generate_files(), and skip_file().

int always_checksum
 

Definition at line 41 of file generator.c.

Referenced by skip_file().

int modify_window = 0
 

Definition at line 86 of file options.c.

Referenced by server_options(), and usage().

char* compare_dest
 

Definition at line 43 of file generator.c.

Referenced by recv_generator(), and skip_file().


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