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

util.c

Go to the documentation of this file.
00001 /*  -*- c-file-style: "linux" -*-
00002  * 
00003  * Copyright (C) 1996-2000 by Andrew Tridgell 
00004  * Copyright (C) Paul Mackerras 1996
00005  * Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
00006  * 
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020  */
00021 
00022 /**
00023  * @file
00024  *
00025  * Utilities used in rsync 
00026  **/
00027 
00028 #include "rsync.h"
00029 
00030 extern int verbose;
00031 
00032 int sanitize_paths = 0;
00033 
00034 
00035 
00036 /**
00037  * Set a fd into nonblocking mode
00038  **/
00039 void set_nonblocking(int fd)
00040 {
00041         int val;
00042 
00043         if ((val = fcntl(fd, F_GETFL, 0)) == -1)
00044                 return;
00045         if (!(val & NONBLOCK_FLAG)) {
00046                 val |= NONBLOCK_FLAG;
00047                 fcntl(fd, F_SETFL, val);
00048         }
00049 }
00050 
00051 /**
00052  * Set a fd into blocking mode
00053  **/
00054 void set_blocking(int fd)
00055 {
00056         int val;
00057 
00058         if ((val = fcntl(fd, F_GETFL, 0)) == -1)
00059                 return;
00060         if (val & NONBLOCK_FLAG) {
00061                 val &= ~NONBLOCK_FLAG;
00062                 fcntl(fd, F_SETFL, val);
00063         }
00064 }
00065 
00066 
00067 /**
00068  * Create a file descriptor pair - like pipe() but use socketpair if
00069  * possible (because of blocking issues on pipes).
00070  * 
00071  * Always set non-blocking.
00072  */
00073 int fd_pair(int fd[2])
00074 {
00075         int ret;
00076 
00077 #if HAVE_SOCKETPAIR
00078         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
00079 #else
00080         ret = pipe(fd);
00081 #endif
00082 
00083         if (ret == 0) {
00084                 set_nonblocking(fd[0]);
00085                 set_nonblocking(fd[1]);
00086         }
00087 
00088         return ret;
00089 }
00090 
00091 
00092 void print_child_argv(char **cmd)
00093 {
00094         rprintf(FINFO, "opening connection using ");
00095         for (; *cmd; cmd++) {
00096                 /* Look for characters that ought to be quoted.  This
00097                 * is not a great quoting algorithm, but it's
00098                 * sufficient for a log message. */
00099                 if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz"
00100                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00101                            "0123456789"
00102                            ",.-_=+@/") != strlen(*cmd)) {
00103                         rprintf(FINFO, "\"%s\" ", *cmd);
00104                 } else {
00105                         rprintf(FINFO, "%s ", *cmd);
00106                 }
00107         }
00108         rprintf(FINFO, "\n");
00109 }
00110 
00111 
00112 void out_of_memory(char *str)
00113 {
00114   rprintf(FERROR,"ERROR: out of memory in %s\n",str);
00115   exit_cleanup(RERR_MALLOC);
00116 }
00117 
00118 void overflow(char *str)
00119 {
00120   rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
00121   exit_cleanup(RERR_MALLOC);
00122 }
00123 
00124 
00125 
00126 int set_modtime(char *fname, time_t modtime)
00127 {
00128         extern int dry_run;
00129         if (dry_run)
00130                 return 0;
00131 
00132         if (verbose > 2) {
00133                 rprintf(FINFO, "set modtime of %s to (%ld) %s",
00134                         fname, (long) modtime,
00135                         asctime(localtime(&modtime)));
00136         }
00137         
00138         {
00139 #ifdef HAVE_UTIMBUF
00140                 struct utimbuf tbuf;  
00141                 tbuf.actime = time(NULL);
00142                 tbuf.modtime = modtime;
00143                 return utime(fname,&tbuf);
00144 #elif defined(HAVE_UTIME)
00145                 time_t t[2];
00146                 t[0] = time(NULL);
00147                 t[1] = modtime;
00148                 return utime(fname,t);
00149 #else
00150                 struct timeval t[2];
00151                 t[0].tv_sec = time(NULL);
00152                 t[0].tv_usec = 0;
00153                 t[1].tv_sec = modtime;
00154                 t[1].tv_usec = 0;
00155                 return utimes(fname,t);
00156 #endif
00157         }
00158 }
00159 
00160 
00161 /**
00162    Create any necessary directories in fname. Unfortunately we don't know
00163    what perms to give the directory when this is called so we need to rely
00164    on the umask
00165 **/
00166 int create_directory_path(char *fname, int base_umask)
00167 {
00168         char *p;
00169 
00170         while (*fname == '/') fname++;
00171         while (strncmp(fname,"./",2)==0) fname += 2;
00172 
00173         p = fname;
00174         while ((p=strchr(p,'/'))) {
00175                 *p = 0;
00176                 do_mkdir(fname, 0777 & ~base_umask); 
00177                 *p = '/';
00178                 p++;
00179         }
00180         return 0;
00181 }
00182 
00183 
00184 /**
00185  * Write @p len bytes at @p ptr to descriptor @p desc, retrying if
00186  * interrupted.
00187  *
00188  * @retval len upon success
00189  *
00190  * @retval <0 write's (negative) error code
00191  *
00192  * Derived from GNU C's cccp.c.
00193  */
00194 static int full_write(int desc, char *ptr, size_t len)
00195 {
00196         int total_written;
00197         
00198         total_written = 0;
00199         while (len > 0) {
00200                 int written = write (desc, ptr, len);
00201                 if (written < 0)  {
00202 #ifdef EINTR
00203                         if (errno == EINTR)
00204                                 continue;
00205 #endif
00206                         return written;
00207                 }
00208                 total_written += written;
00209                 ptr += written;
00210                 len -= written;
00211         }
00212         return total_written;
00213 }
00214 
00215 
00216 /**
00217  * Read @p len bytes at @p ptr from descriptor @p desc, retrying if
00218  * interrupted.
00219  *
00220  * @retval >0 the actual number of bytes read
00221  *
00222  * @retval 0 for EOF
00223  *
00224  * @retval <0 for an error.
00225  *
00226  * Derived from GNU C's cccp.c. */
00227 static int safe_read(int desc, char *ptr, size_t len)
00228 {
00229         int n_chars;
00230  
00231         if (len == 0)
00232                 return len;
00233  
00234 #ifdef EINTR
00235         do {
00236                 n_chars = read(desc, ptr, len);
00237         } while (n_chars < 0 && errno == EINTR);
00238 #else
00239         n_chars = read(desc, ptr, len);
00240 #endif
00241  
00242         return n_chars;
00243 }
00244 
00245 
00246 /** Copy a file.
00247  *
00248  * This is used in conjunction with the --temp-dir option */
00249 int copy_file(char *source, char *dest, mode_t mode)
00250 {
00251         int ifd;
00252         int ofd;
00253         char buf[1024 * 8];
00254         int len;   /* Number of bytes read into `buf'. */
00255 
00256         ifd = do_open(source, O_RDONLY, 0);
00257         if (ifd == -1) {
00258                 rprintf(FERROR,"open %s: %s\n",
00259                         source,strerror(errno));
00260                 return -1;
00261         }
00262 
00263         if (robust_unlink(dest) && errno != ENOENT) {
00264                 rprintf(FERROR,"unlink %s: %s\n",
00265                         dest,strerror(errno));
00266                 return -1;
00267         }
00268 
00269         ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
00270         if (ofd == -1) {
00271                 rprintf(FERROR,"open %s: %s\n",
00272                         dest,strerror(errno));
00273                 close(ifd);
00274                 return -1;
00275         }
00276 
00277         while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
00278                 if (full_write(ofd, buf, len) < 0) {
00279                         rprintf(FERROR,"write %s: %s\n",
00280                                 dest,strerror(errno));
00281                         close(ifd);
00282                         close(ofd);
00283                         return -1;
00284                 }
00285         }
00286 
00287         close(ifd);
00288         close(ofd);
00289 
00290         if (len < 0) {
00291                 rprintf(FERROR,"read %s: %s\n",
00292                         source,strerror(errno));
00293                 return -1;
00294         }
00295 
00296         return 0;
00297 }
00298 
00299 /* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
00300 #define MAX_RENAMES_DIGITS 3
00301 #define MAX_RENAMES 1000
00302 
00303 /**
00304  * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
00305  * rename to <path>/.rsyncNNN instead.
00306  *
00307  * Note that successive rsync runs will shuffle the filenames around a
00308  * bit as long as the file is still busy; this is because this function
00309  * does not know if the unlink call is due to a new file coming in, or
00310  * --delete trying to remove old .rsyncNNN files, hence it renames it
00311  * each time.
00312  **/
00313 int robust_unlink(char *fname)
00314 {
00315 #ifndef ETXTBSY
00316         return do_unlink(fname);
00317 #else
00318         static int counter = 1;
00319         int rc, pos, start;
00320         char path[MAXPATHLEN];
00321 
00322         rc = do_unlink(fname);
00323         if ((rc == 0) || (errno != ETXTBSY))
00324                 return rc;
00325 
00326         strlcpy(path, fname, MAXPATHLEN);
00327 
00328         pos = strlen(path);
00329         while((path[--pos] != '/') && (pos >= 0))
00330                 ;
00331         ++pos;
00332         strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
00333         pos += sizeof(".rsync")-1;
00334 
00335         if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
00336                 errno = ETXTBSY;
00337                 return -1;
00338         }
00339 
00340         /* start where the last one left off to reduce chance of clashes */
00341         start = counter;
00342         do {
00343                 sprintf(&path[pos], "%03d", counter);
00344                 if (++counter >= MAX_RENAMES)
00345                         counter = 1;
00346         } while (((rc = access(path, 0)) == 0) && (counter != start));
00347 
00348         if (verbose > 0)
00349                 rprintf(FINFO,"renaming %s to %s because of text busy\n",
00350                                             fname, path);
00351 
00352         /* maybe we should return rename()'s exit status? Nah. */
00353         if (do_rename(fname, path) != 0) {
00354                 errno = ETXTBSY;
00355                 return -1;
00356         }
00357         return 0;
00358 #endif
00359 }
00360 
00361 int robust_rename(char *from, char *to)
00362 {
00363 #ifndef ETXTBSY
00364         return do_rename(from, to);
00365 #else
00366         int rc = do_rename(from, to);
00367         if ((rc == 0) || (errno != ETXTBSY))
00368                 return rc;
00369         if (robust_unlink(to) != 0)
00370                 return -1;
00371         return do_rename(from, to);
00372 #endif
00373 }
00374 
00375 
00376 static pid_t all_pids[10];
00377 static int num_pids;
00378 
00379 /** Fork and record the pid of the child. **/
00380 pid_t do_fork(void)
00381 {
00382         pid_t newpid = fork();
00383         
00384         if (newpid != 0  &&  newpid != -1) {
00385                 all_pids[num_pids++] = newpid;
00386         }
00387         return newpid;
00388 }
00389 
00390 /**
00391  * Kill all children.
00392  *
00393  * @todo It would be kind of nice to make sure that they are actually
00394  * all our children before we kill them, because their pids may have
00395  * been recycled by some other process.  Perhaps when we wait for a
00396  * child, we should remove it from this array.  Alternatively we could
00397  * perhaps use process groups, but I think that would not work on
00398  * ancient Unix versions that don't support them.
00399  **/
00400 void kill_all(int sig)
00401 {
00402         int i;
00403 
00404         for (i = 0; i < num_pids; i++) {
00405                 /* Let's just be a little careful where we
00406                  * point that gun, hey?  See kill(2) for the
00407                  * magic caused by negative values. */
00408                 pid_t p = all_pids[i];
00409 
00410                 if (p == getpid())
00411                         continue;
00412                 if (p <= 0)
00413                         continue;
00414 
00415                 kill(p, sig);
00416         }
00417 }
00418 
00419 
00420 /** Turn a user name into a uid */
00421 int name_to_uid(char *name, uid_t *uid)
00422 {
00423         struct passwd *pass;
00424         if (!name || !*name) return 0;
00425         pass = getpwnam(name);
00426         if (pass) {
00427                 *uid = pass->pw_uid;
00428                 return 1;
00429         }
00430         return 0;
00431 }
00432 
00433 /** Turn a group name into a gid */
00434 int name_to_gid(char *name, gid_t *gid)
00435 {
00436         struct group *grp;
00437         if (!name || !*name) return 0;
00438         grp = getgrnam(name);
00439         if (grp) {
00440                 *gid = grp->gr_gid;
00441                 return 1;
00442         }
00443         return 0;
00444 }
00445 
00446 
00447 /** Lock a byte range in a open file */
00448 int lock_range(int fd, int offset, int len)
00449 {
00450         struct flock lock;
00451 
00452         lock.l_type = F_WRLCK;
00453         lock.l_whence = SEEK_SET;
00454         lock.l_start = offset;
00455         lock.l_len = len;
00456         lock.l_pid = 0;
00457         
00458         return fcntl(fd,F_SETLK,&lock) == 0;
00459 }
00460 
00461 
00462 static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
00463 {
00464 #if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
00465         if (!*s) s = ".";
00466         argv[*argc] = strdup(s);
00467         (*argc)++;
00468         return;
00469 #else
00470         extern int sanitize_paths;
00471         glob_t globbuf;
00472         int i;
00473 
00474         if (!*s) s = ".";
00475 
00476         argv[*argc] = strdup(s);
00477         if (sanitize_paths) {
00478                 sanitize_path(argv[*argc], NULL);
00479         }
00480 
00481         memset(&globbuf, 0, sizeof(globbuf));
00482         glob(argv[*argc], 0, NULL, &globbuf);
00483         if (globbuf.gl_pathc == 0) {
00484                 (*argc)++;
00485                 globfree(&globbuf);
00486                 return;
00487         }
00488         for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
00489                 if (i == 0) free(argv[*argc]);
00490                 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
00491                 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
00492         }
00493         globfree(&globbuf);
00494         (*argc) += i;
00495 #endif
00496 }
00497 
00498 void glob_expand(char *base1, char **argv, int *argc, int maxargs)
00499 {
00500         char *s = argv[*argc];
00501         char *p, *q;
00502         char *base = base1;
00503 
00504         if (!s || !*s) return;
00505 
00506         if (strncmp(s, base, strlen(base)) == 0) {
00507                 s += strlen(base);
00508         }
00509 
00510         s = strdup(s);
00511         if (!s) out_of_memory("glob_expand");
00512 
00513         if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
00514 
00515         q = s;
00516         while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
00517                 /* split it at this point */
00518                 *p = 0;
00519                 glob_expand_one(q, argv, argc, maxargs);
00520                 q = p+strlen(base);
00521         }
00522 
00523         if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
00524 
00525         free(s);
00526         free(base);
00527 }
00528 
00529 /**
00530  * Convert a string to lower case
00531  **/
00532 void strlower(char *s)
00533 {
00534         while (*s) {
00535                 if (isupper(* (unsigned char *) s))
00536                         *s = tolower(* (unsigned char *) s);
00537                 s++;
00538         }
00539 }
00540 
00541 void *Realloc(void *p, int size)
00542 {
00543         if (!p) return (void *)malloc(size);
00544         return (void *)realloc(p, size);
00545 }
00546 
00547 
00548 void clean_fname(char *name)
00549 {
00550         char *p;
00551         int l;
00552         int modified = 1;
00553 
00554         if (!name) return;
00555 
00556         while (modified) {
00557                 modified = 0;
00558 
00559                 if ((p=strstr(name,"/./"))) {
00560                         modified = 1;
00561                         while (*p) {
00562                                 p[0] = p[2];
00563                                 p++;
00564                         }
00565                 }
00566 
00567                 if ((p=strstr(name,"//"))) {
00568                         modified = 1;
00569                         while (*p) {
00570                                 p[0] = p[1];
00571                                 p++;
00572                         }
00573                 }
00574 
00575                 if (strncmp(p=name,"./",2) == 0) {      
00576                         modified = 1;
00577                         do {
00578                                 p[0] = p[2];
00579                         } while (*p++);
00580                 }
00581 
00582                 l = strlen(p=name);
00583                 if (l > 1 && p[l-1] == '/') {
00584                         modified = 1;
00585                         p[l-1] = 0;
00586                 }
00587         }
00588 }
00589 
00590 /**
00591  * Make path appear as if a chroot had occurred:
00592  *
00593  * @li 1. remove leading "/" (or replace with "." if at end)
00594  *
00595  * @li 2. remove leading ".." components (except those allowed by @p reldir)
00596  *
00597  * @li 3. delete any other "<dir>/.." (recursively)
00598  *
00599  * Can only shrink paths, so sanitizes in place.
00600  *
00601  * While we're at it, remove double slashes and "." components like
00602  *   clean_fname() does, but DON'T remove a trailing slash because that
00603  *   is sometimes significant on command line arguments.
00604  *
00605  * If @p reldir is non-null, it is a sanitized directory that the path will be
00606  *    relative to, so allow as many ".." at the beginning of the path as
00607  *    there are components in reldir.  This is used for symbolic link targets.
00608  *    If reldir is non-null and the path began with "/", to be completely like
00609  *    a chroot we should add in depth levels of ".." at the beginning of the
00610  *    path, but that would blow the assumption that the path doesn't grow and
00611  *    it is not likely to end up being a valid symlink anyway, so just do
00612  *    the normal removal of the leading "/" instead.
00613  *
00614  * Contributed by Dave Dykstra <dwd@bell-labs.com>
00615  */
00616 void sanitize_path(char *p, char *reldir)
00617 {
00618         char *start, *sanp;
00619         int depth = 0;
00620         int allowdotdot = 0;
00621 
00622         if (reldir) {
00623                 depth++;
00624                 while (*reldir) {
00625                         if (*reldir++ == '/') {
00626                                 depth++;
00627                         }
00628                 }
00629         }
00630         start = p;
00631         sanp = p;
00632         while (*p == '/') {
00633                 /* remove leading slashes */
00634                 p++;
00635         }
00636         while (*p != '\0') {
00637                 /* this loop iterates once per filename component in p.
00638                  * both p (and sanp if the original had a slash) should
00639                  * always be left pointing after a slash
00640                  */
00641                 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
00642                         /* skip "." component */
00643                         while (*++p == '/') {
00644                                 /* skip following slashes */
00645                                 ;
00646                         }
00647                         continue;
00648                 }
00649                 allowdotdot = 0;
00650                 if ((*p == '.') && (*(p+1) == '.') &&
00651                             ((*(p+2) == '/') || (*(p+2) == '\0'))) {
00652                         /* ".." component followed by slash or end */
00653                         if ((depth > 0) && (sanp == start)) {
00654                                 /* allow depth levels of .. at the beginning */
00655                                 --depth;
00656                                 allowdotdot = 1;
00657                         } else {
00658                                 p += 2;
00659                                 if (*p == '/')
00660                                         p++;
00661                                 if (sanp != start) {
00662                                         /* back up sanp one level */
00663                                         --sanp; /* now pointing at slash */
00664                                         while ((sanp > start) && (*(sanp - 1) != '/')) {
00665                                                 /* skip back up to slash */
00666                                                 sanp--;
00667                                         }
00668                                 }
00669                                 continue;
00670                         }
00671                 }
00672                 while (1) {
00673                         /* copy one component through next slash */
00674                         *sanp++ = *p++;
00675                         if ((*p == '\0') || (*(p-1) == '/')) {
00676                                 while (*p == '/') {
00677                                         /* skip multiple slashes */
00678                                         p++;
00679                                 }
00680                                 break;
00681                         }
00682                 }
00683                 if (allowdotdot) {
00684                         /* move the virtual beginning to leave the .. alone */
00685                         start = sanp;
00686                 }
00687         }
00688         if ((sanp == start) && !allowdotdot) {
00689                 /* ended up with nothing, so put in "." component */
00690                 /*
00691                  * note that the !allowdotdot doesn't prevent this from
00692                  *  happening in all allowed ".." situations, but I didn't
00693                  *  think it was worth putting in an extra variable to ensure
00694                  *  it since an extra "." won't hurt in those situations.
00695                  */
00696                 *sanp++ = '.';
00697         }
00698         *sanp = '\0';
00699 }
00700 
00701 
00702 static char curr_dir[MAXPATHLEN];
00703 
00704 /**
00705  * Like chdir() but can be reversed with pop_dir() if @p save is set.
00706  * It is also much faster as it remembers where we have been.
00707  **/
00708 char *push_dir(char *dir, int save)
00709 {
00710         char *ret = curr_dir;
00711         static int initialised;
00712 
00713         if (!initialised) {
00714                 initialised = 1;
00715                 getcwd(curr_dir, sizeof(curr_dir)-1);
00716         }
00717 
00718         if (!dir) return NULL; /* this call was probably just to initialize */
00719 
00720         if (chdir(dir)) return NULL;
00721 
00722         if (save) {
00723                 ret = strdup(curr_dir);
00724         }
00725 
00726         if (*dir == '/') {
00727                 strlcpy(curr_dir, dir, sizeof(curr_dir));
00728         } else {
00729                 strlcat(curr_dir,"/", sizeof(curr_dir));
00730                 strlcat(curr_dir,dir, sizeof(curr_dir));
00731         }
00732 
00733         clean_fname(curr_dir);
00734 
00735         return ret;
00736 }
00737 
00738 /** Reverse a push_dir() call */
00739 int pop_dir(char *dir)
00740 {
00741         int ret;
00742 
00743         ret = chdir(dir);
00744         if (ret) {
00745                 free(dir);
00746                 return ret;
00747         }
00748 
00749         strlcpy(curr_dir, dir, sizeof(curr_dir));
00750 
00751         free(dir);
00752 
00753         return 0;
00754 }
00755 
00756 /** We need to supply our own strcmp function for file list comparisons
00757    to ensure that signed/unsigned usage is consistent between machines. */
00758 int u_strcmp(const char *cs1, const char *cs2)
00759 {
00760         const uchar *s1 = (const uchar *)cs1;
00761         const uchar *s2 = (const uchar *)cs2;
00762 
00763         while (*s1 && *s2 && (*s1 == *s2)) {
00764                 s1++; s2++;
00765         }
00766         
00767         return (int)*s1 - (int)*s2;
00768 }
00769 
00770 
00771 
00772 /**
00773  * Determine if a symlink points outside the current directory tree.
00774  * This is considered "unsafe" because e.g. when mirroring somebody
00775  * else's machine it might allow them to establish a symlink to
00776  * /etc/passwd, and then read it through a web server.
00777  *
00778  * Null symlinks and absolute symlinks are always unsafe.
00779  *
00780  * Basically here we are concerned with symlinks whose target contains
00781  * "..", because this might cause us to walk back up out of the
00782  * transferred directory.  We are not allowed to go back up and
00783  * reenter.
00784  *
00785  * @param dest Target of the symlink in question.
00786  *
00787  * @param src Top source directory currently applicable.  Basically this
00788  * is the first parameter to rsync in a simple invocation, but it's
00789  * modified by flist.c in slightly complex ways.
00790  *
00791  * @retval True if unsafe
00792  * @retval False is unsafe
00793  *
00794  * @sa t_unsafe.c
00795  **/
00796 int unsafe_symlink(char *dest, char *src)
00797 {
00798         char *tok;
00799         int depth = 0;
00800 
00801         /* all absolute and null symlinks are unsafe */
00802         if (!dest || !(*dest) || (*dest == '/')) return 1;
00803 
00804         src = strdup(src);
00805         if (!src) out_of_memory("unsafe_symlink");
00806 
00807         /* find out what our safety margin is */
00808         for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
00809                 if (strcmp(tok,"..") == 0) {
00810                         depth=0;
00811                 } else if (strcmp(tok,".") == 0) {
00812                         /* nothing */
00813                 } else {
00814                         depth++;
00815                 }
00816         }
00817         free(src);
00818 
00819         /* drop by one to account for the filename portion */
00820         depth--;
00821 
00822         dest = strdup(dest);
00823         if (!dest) out_of_memory("unsafe_symlink");
00824 
00825         for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
00826                 if (strcmp(tok,"..") == 0) {
00827                         depth--;
00828                 } else if (strcmp(tok,".") == 0) {
00829                         /* nothing */
00830                 } else {
00831                         depth++;
00832                 }
00833                 /* if at any point we go outside the current directory then
00834                    stop - it is unsafe */
00835                 if (depth < 0) break;
00836         }
00837 
00838         free(dest);
00839         return (depth < 0);
00840 }
00841 
00842 
00843 /**
00844  * Return the date and time as a string
00845  **/
00846 char *timestring(time_t t)
00847 {
00848         static char TimeBuf[200];
00849         struct tm *tm = localtime(&t);
00850 
00851 #ifdef HAVE_STRFTIME
00852         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
00853 #else
00854         strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
00855 #endif
00856 
00857         if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
00858                 TimeBuf[strlen(TimeBuf)-1] = 0;
00859         }
00860 
00861         return(TimeBuf);
00862 }
00863 
00864 
00865 /**
00866  * Sleep for a specified number of milliseconds.
00867  *
00868  * Always returns TRUE.  (In the future it might return FALSE if
00869  * interrupted.)
00870  **/
00871 int msleep(int t)
00872 {
00873         int tdiff=0;
00874         struct timeval tval,t1,t2;  
00875 
00876         gettimeofday(&t1, NULL);
00877         gettimeofday(&t2, NULL);
00878   
00879         while (tdiff < t) {
00880                 tval.tv_sec = (t-tdiff)/1000;
00881                 tval.tv_usec = 1000*((t-tdiff)%1000);
00882  
00883                 errno = 0;
00884                 select(0,NULL,NULL, NULL, &tval);
00885 
00886                 gettimeofday(&t2, NULL);
00887                 tdiff = (t2.tv_sec - t1.tv_sec)*1000 + 
00888                         (t2.tv_usec - t1.tv_usec)/1000;
00889         }
00890 
00891         return True;
00892 }
00893 
00894 
00895 /**
00896  * Determine if two file modification times are equivalent (either
00897  * exact or in the modification timestamp window established by
00898  * --modify-window).
00899  *
00900  * @retval 0 if the times should be treated as the same
00901  *
00902  * @retval +1 if the first is later
00903  *
00904  * @retval -1 if the 2nd is later
00905  **/
00906 int cmp_modtime(time_t file1, time_t file2)
00907 {
00908         extern int modify_window;
00909 
00910         if (file2 > file1) {
00911                 if (file2 - file1 <= modify_window) return 0;
00912                 return -1;
00913         }
00914         if (file1 - file2 <= modify_window) return 0;
00915         return 1;
00916 }
00917 
00918 
00919 #ifdef __INSURE__XX
00920 #include <dlfcn.h>
00921 
00922 /**
00923    This routine is a trick to immediately catch errors when debugging
00924    with insure. A xterm with a gdb is popped up when insure catches
00925    a error. It is Linux specific.
00926 **/
00927 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
00928 {
00929         static int (*fn)();
00930         int ret;
00931         char *cmd;
00932 
00933         asprintf(&cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'", 
00934                 getpid(), getpid(), getpid());
00935 
00936         if (!fn) {
00937                 static void *h;
00938                 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
00939                 fn = dlsym(h, "_Insure_trap_error");
00940         }
00941 
00942         ret = fn(a1, a2, a3, a4, a5, a6);
00943 
00944         system(cmd);
00945 
00946         free(cmd);
00947 
00948         return ret;
00949 }
00950 #endif

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