home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / rsync221.zip / util.c < prev    next >
C/C++ Source or Header  |  1999-03-06  |  18KB  |  808 lines

  1. /* 
  2.    Copyright (C) Andrew Tridgell 1996
  3.    Copyright (C) Paul Mackerras 1996
  4.    
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2 of the License, or
  8.    (at your option) any later version.
  9.    
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.    
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19.  
  20. /*
  21.   Utilities used in rsync 
  22.  
  23.   tridge, June 1996
  24.   */
  25. #include "rsync.h"
  26.  
  27. /****************************************************************************
  28. Set a fd into nonblocking mode. Uses POSIX O_NONBLOCK if available,
  29. else
  30. if SYSV use O_NDELAY
  31. if BSD use FNDELAY
  32. ****************************************************************************/
  33. int set_nonblocking(int fd)
  34. {
  35.     int val;
  36. #ifdef O_NONBLOCK
  37. #define FLAG_TO_SET O_NONBLOCK
  38. #else
  39. #ifdef SYSV
  40. #define FLAG_TO_SET O_NDELAY
  41. #else /* BSD */
  42. #define FLAG_TO_SET FNDELAY
  43. #endif
  44. #endif
  45.     
  46.     if((val = fcntl(fd, F_GETFL, 0)) == -1)
  47.         return -1;
  48.     val |= FLAG_TO_SET;
  49.     return fcntl( fd, F_SETFL, val);
  50. #undef FLAG_TO_SET
  51. }
  52.  
  53.  
  54. /* this is taken from CVS */
  55. int piped_child(char **command,int *f_in,int *f_out)
  56. {
  57.   int pid;
  58.   int to_child_pipe[2];
  59.   int from_child_pipe[2];
  60.  
  61.   if (pipe(to_child_pipe) < 0 ||
  62.       pipe(from_child_pipe) < 0) {
  63.     rprintf(FERROR,"pipe: %s\n",strerror(errno));
  64.     exit_cleanup(RERR_IPC);
  65.   }
  66.  
  67.  
  68.   pid = do_fork();
  69.   if (pid < 0) {
  70.     rprintf(FERROR,"fork: %s\n",strerror(errno));
  71.     exit_cleanup(RERR_IPC);
  72.   }
  73.  
  74.   if (pid == 0)
  75.     {
  76.       extern int orig_umask;
  77.       if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
  78.       close(to_child_pipe[1]) < 0 ||
  79.       close(from_child_pipe[0]) < 0 ||
  80.       dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
  81.     rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
  82.     exit_cleanup(RERR_IPC);
  83.       }
  84.       if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
  85.       if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
  86.       umask(orig_umask);
  87.       execvp(command[0], command);
  88.       rprintf(FERROR,"Failed to exec %s : %s\n",
  89.           command[0],strerror(errno));
  90.       exit_cleanup(RERR_IPC);
  91.     }
  92.  
  93.   if (close(from_child_pipe[1]) < 0 ||
  94.       close(to_child_pipe[0]) < 0) {
  95.     rprintf(FERROR,"Failed to close : %s\n",strerror(errno));   
  96.     exit_cleanup(RERR_IPC);
  97.   }
  98.  
  99.   *f_in = from_child_pipe[0];
  100.   *f_out = to_child_pipe[1];
  101.  
  102.   set_nonblocking(*f_in);
  103.   set_nonblocking(*f_out);
  104.   
  105.   return pid;
  106. }
  107.  
  108. int local_child(int argc, char **argv,int *f_in,int *f_out)
  109. {
  110.     int pid;
  111.     int to_child_pipe[2];
  112.     int from_child_pipe[2];
  113.  
  114.     if (pipe(to_child_pipe) < 0 ||
  115.         pipe(from_child_pipe) < 0) {
  116.         rprintf(FERROR,"pipe: %s\n",strerror(errno));
  117.         exit_cleanup(RERR_IPC);
  118.     }
  119.  
  120.  
  121.     pid = do_fork();
  122.     if (pid < 0) {
  123.         rprintf(FERROR,"fork: %s\n",strerror(errno));
  124.         exit_cleanup(RERR_IPC);
  125.     }
  126.  
  127.     if (pid == 0) {
  128.         extern int am_sender;
  129.         extern int am_server;
  130.  
  131.         am_sender = !am_sender;
  132.         am_server = 1;        
  133.  
  134.         if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
  135.             close(to_child_pipe[1]) < 0 ||
  136.             close(from_child_pipe[0]) < 0 ||
  137.             dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
  138.             rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
  139.             exit_cleanup(RERR_IPC);
  140.         }
  141.         if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
  142.         if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
  143.         start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
  144.     }
  145.  
  146.     if (close(from_child_pipe[1]) < 0 ||
  147.         close(to_child_pipe[0]) < 0) {
  148.         rprintf(FERROR,"Failed to close : %s\n",strerror(errno));   
  149.         exit_cleanup(RERR_IPC);
  150.     }
  151.  
  152.     *f_in = from_child_pipe[0];
  153.     *f_out = to_child_pipe[1];
  154.   
  155.     return pid;
  156. }
  157.  
  158.  
  159.  
  160. void out_of_memory(char *str)
  161. {
  162.   rprintf(FERROR,"ERROR: out of memory in %s\n",str);
  163.   exit_cleanup(RERR_MALLOC);
  164. }
  165.  
  166. void overflow(char *str)
  167. {
  168.   rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
  169.   exit_cleanup(RERR_MALLOC);
  170. }
  171.  
  172.  
  173.  
  174. int set_modtime(char *fname,time_t modtime)
  175. {
  176.     extern int dry_run;
  177.     if (dry_run) return 0;
  178.     {
  179. #ifdef HAVE_UTIMBUF
  180.         struct utimbuf tbuf;  
  181.         tbuf.actime = time(NULL);
  182.         tbuf.modtime = modtime;
  183.         return utime(fname,&tbuf);
  184. #elif defined(HAVE_UTIME)
  185.         time_t t[2];
  186.         t[0] = time(NULL);
  187.         t[1] = modtime;
  188.         return utime(fname,t);
  189. #else
  190.         struct timeval t[2];
  191.         t[0].tv_sec = time(NULL);
  192.         t[0].tv_usec = 0;
  193.         t[1].tv_sec = modtime;
  194.         t[1].tv_usec = 0;
  195.         return utimes(fname,t);
  196. #endif
  197.     }
  198. }
  199.  
  200.  
  201. /****************************************************************************
  202. create any necessary directories in fname. Unfortunately we don't know
  203. what perms to give the directory when this is called so we need to rely
  204. on the umask
  205. ****************************************************************************/
  206. int create_directory_path(char *fname)
  207. {
  208.     extern int orig_umask;
  209.     char *p;
  210.  
  211.     while (*fname == '/') fname++;
  212.     while (strncmp(fname,"./",2)==0) fname += 2;
  213.  
  214.     p = fname;
  215.     while ((p=strchr(p,'/'))) {
  216.         *p = 0;
  217.         do_mkdir(fname,0777 & ~orig_umask); 
  218.         *p = '/';
  219.         p++;
  220.     }
  221.     return 0;
  222. }
  223.  
  224.  
  225. /* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
  226.    Return LEN upon success, write's (negative) error code otherwise.  
  227.  
  228.    derived from GNU C's cccp.c.
  229. */
  230. static int full_write(int desc, char *ptr, int len)
  231. {
  232.     int total_written;
  233.     
  234.     total_written = 0;
  235.     while (len > 0) {
  236.         int written = write (desc, ptr, len);
  237.         if (written < 0)  {
  238. #ifdef EINTR
  239.             if (errno == EINTR)
  240.                 continue;
  241. #endif
  242.             return written;
  243.         }
  244.         total_written += written;
  245.         ptr += written;
  246.         len -= written;
  247.     }
  248.     return total_written;
  249. }
  250.  
  251. /* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
  252.    Return the actual number of bytes read, zero for EOF, or negative
  253.    for an error.  
  254.  
  255.    derived from GNU C's cccp.c. */
  256. static int safe_read(int desc, char *ptr, int len)
  257. {
  258.     int n_chars;
  259.  
  260.     if (len <= 0)
  261.         return len;
  262.  
  263. #ifdef EINTR
  264.     do {
  265.         n_chars = read(desc, ptr, len);
  266.     } while (n_chars < 0 && errno == EINTR);
  267. #else
  268.     n_chars = read(desc, ptr, len);
  269. #endif
  270.  
  271.     return n_chars;
  272. }
  273.  
  274.  
  275. /* copy a file - this is used in conjunction with the --temp-dir option */
  276. int copy_file(char *source, char *dest, mode_t mode)
  277. {
  278.     int ifd;
  279.     int ofd;
  280.     char buf[1024 * 8];
  281.     int len;   /* Number of bytes read into `buf'. */
  282.  
  283.     ifd = open(source, O_RDONLY);
  284.     if (ifd == -1) {
  285.         rprintf(FERROR,"open %s: %s\n",
  286.             source,strerror(errno));
  287.         return -1;
  288.     }
  289.  
  290.     if (do_unlink(dest) && errno != ENOENT) {
  291.         rprintf(FERROR,"unlink %s: %s\n",
  292.             dest,strerror(errno));
  293.         return -1;
  294.     }
  295.  
  296.     ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
  297.     if (ofd == -1) {
  298.         rprintf(FERROR,"open %s: %s\n",
  299.             dest,strerror(errno));
  300.         close(ifd);
  301.         return -1;
  302.     }
  303.  
  304.     while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
  305.         if (full_write(ofd, buf, len) < 0) {
  306.             rprintf(FERROR,"write %s: %s\n",
  307.                 dest,strerror(errno));
  308.             close(ifd);
  309.             close(ofd);
  310.             return -1;
  311.         }
  312.     }
  313.  
  314.     close(ifd);
  315.     close(ofd);
  316.  
  317.     if (len < 0) {
  318.         rprintf(FERROR,"read %s: %s\n",
  319.             source,strerror(errno));
  320.         return -1;
  321.     }
  322.  
  323.     return 0;
  324. }
  325.  
  326. /* sleep for a while via select */
  327. void u_sleep(int usec)
  328. {
  329.     struct timeval tv;
  330.  
  331.     tv.tv_sec = 0;
  332.     tv.tv_usec = usec;
  333.     select(0, NULL, NULL, NULL, &tv);
  334. }
  335.  
  336.  
  337. static pid_t all_pids[10];
  338. static int num_pids;
  339.  
  340. /* fork and record the pid of the child */
  341. pid_t do_fork(void)
  342. {
  343.     pid_t newpid = fork();
  344.     
  345.     if (newpid) {
  346.         all_pids[num_pids++] = newpid;
  347.     }
  348.     return newpid;
  349. }
  350.  
  351. /* kill all children */
  352. void kill_all(int sig)
  353. {
  354.     int i;
  355.     for (i=0;i<num_pids;i++) {
  356.         if (all_pids[i] != getpid())
  357.             kill(all_pids[i], sig);
  358.     }
  359. }
  360.  
  361. /* turn a user name into a uid */
  362. int name_to_uid(char *name, uid_t *uid)
  363. {
  364.     struct passwd *pass;
  365.     if (!name || !*name) return 0;
  366.     pass = getpwnam(name);
  367.     if (pass) {
  368.         *uid = pass->pw_uid;
  369.         return 1;
  370.     }
  371.     return 0;
  372. }
  373.  
  374. /* turn a group name into a gid */
  375. int name_to_gid(char *name, gid_t *gid)
  376. {
  377.     struct group *grp;
  378.     if (!name || !*name) return 0;
  379.     grp = getgrnam(name);
  380.     if (grp) {
  381.         *gid = grp->gr_gid;
  382.         return 1;
  383.     }
  384.     return 0;
  385. }
  386.  
  387.  
  388. /* lock a byte range in a open file */
  389. int lock_range(int fd, int offset, int len)
  390. {
  391. #ifdef __EMX__
  392.     /* We could provide file locking using the native OS/2 API,
  393.        but then the port would only work for OS/2 only.
  394.        Thus the port currently does not work as a deaemon. */
  395.     return -1;
  396. #else
  397.     struct flock lock;
  398.  
  399.     lock.l_type = F_WRLCK;
  400.     lock.l_whence = SEEK_SET;
  401.     lock.l_start = offset;
  402.     lock.l_len = len;
  403.     lock.l_pid = 0;
  404.     
  405.     return fcntl(fd,F_SETLK,&lock) == 0;
  406. #endif
  407. }
  408.  
  409.  
  410. static void glob_expand_one(char *s, char **argv, int *argc, int maxargs, int sanitize_paths)
  411. {
  412. #if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
  413.     if (!*s) s = ".";
  414.     argv[*argc] = strdup(s);
  415.     (*argc)++;
  416.     return;
  417. #else
  418.     glob_t globbuf;
  419.     int i;
  420.  
  421.     if (!*s) s = ".";
  422.  
  423.     s = strdup(s);
  424.     sanitize_path(s);
  425.     argv[*argc] = s;
  426.  
  427.     memset(&globbuf, 0, sizeof(globbuf));
  428.     glob(argv[*argc], 0, NULL, &globbuf);
  429.     if (globbuf.gl_pathc == 0) {
  430.         (*argc)++;
  431.         globfree(&globbuf);
  432.         return;
  433.     }
  434.     for (i=0; i<(maxargs - (*argc)) && i<globbuf.gl_pathc;i++) {
  435.         if (i == 0) free(argv[*argc]);
  436.         argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
  437.         if (!argv[(*argc) + i]) out_of_memory("glob_expand");
  438.     }
  439.     globfree(&globbuf);
  440.     (*argc) += i;
  441. #endif
  442. }
  443.  
  444. void glob_expand(char *base1, char **argv, int *argc, int maxargs, int sanitize_paths)
  445. {
  446.     char *s = argv[*argc];
  447.     char *p, *q;
  448.     char *base = base1;
  449.  
  450.     if (!s || !*s) return;
  451.  
  452.     if (strncmp(s, base, strlen(base)) == 0) {
  453.         s += strlen(base);
  454.     }
  455.  
  456.     s = strdup(s);
  457.     if (!s) out_of_memory("glob_expand");
  458.  
  459.     base = (char *)malloc(strlen(base1)+3);
  460.     if (!base) out_of_memory("glob_expand");
  461.  
  462.     sprintf(base," %s/", base1);
  463.  
  464.     q = s;
  465.     while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
  466.         /* split it at this point */
  467.         *p = 0;
  468.         glob_expand_one(q, argv, argc, maxargs, sanitize_paths);
  469.         q = p+strlen(base);
  470.     }
  471.  
  472.     if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs, sanitize_paths);
  473.  
  474.     free(s);
  475.     free(base);
  476. }
  477.  
  478. /*******************************************************************
  479.   convert a string to lower case
  480. ********************************************************************/
  481. void strlower(char *s)
  482. {
  483.     while (*s) {
  484.         if (isupper(*s)) *s = tolower(*s);
  485.         s++;
  486.     }
  487. }
  488.  
  489. /* this is like vsnprintf but it always null terminates, so you
  490.    can fit at most n-1 chars in */
  491. int vslprintf(char *str, int n, const char *format, va_list ap)
  492. {
  493.     int ret = vsnprintf(str, n, format, ap);
  494.     if (ret >= n || ret < 0) {
  495.         str[n-1] = 0;
  496.         return -1;
  497.     }
  498.     str[ret] = 0;
  499.     return ret;
  500. }
  501.  
  502.  
  503. /* like snprintf but always null terminates */
  504. int slprintf(char *str, int n, char *format, ...)
  505. {
  506.     va_list ap;  
  507.     int ret;
  508.  
  509.     va_start(ap, format);
  510.     ret = vslprintf(str,n,format,ap);
  511.     va_end(ap);
  512.     return ret;
  513. }
  514.  
  515.  
  516. void *Realloc(void *p, int size)
  517. {
  518.     if (!p) return (void *)malloc(size);
  519.     return (void *)realloc(p, size);
  520. }
  521.  
  522.  
  523. void clean_fname(char *name)
  524. {
  525.     char *p;
  526.     int l;
  527.     int modified = 1;
  528.  
  529.     if (!name) return;
  530.  
  531.     while (modified) {
  532.         modified = 0;
  533.  
  534.         if ((p=strstr(name,"/./"))) {
  535.             modified = 1;
  536.             while (*p) {
  537.                 p[0] = p[2];
  538.                 p++;
  539.             }
  540.         }
  541.  
  542.         if ((p=strstr(name,"//"))) {
  543.             modified = 1;
  544.             while (*p) {
  545.                 p[0] = p[1];
  546.                 p++;
  547.             }
  548.         }
  549.  
  550.         if (strncmp(p=name,"./",2) == 0) {      
  551.             modified = 1;
  552.             do {
  553.                 p[0] = p[2];
  554.             } while (*p++);
  555.         }
  556.  
  557.         l = strlen(p=name);
  558.         if (l > 1 && p[l-1] == '/') {
  559.             modified = 1;
  560.             p[l-1] = 0;
  561.         }
  562.     }
  563. }
  564.  
  565. /*
  566.  * Make path appear as if a chroot had occurred:
  567.  *    1. remove leading "/" (or replace with "." if at end)
  568.  *    2. remove leading ".." components
  569.  *    3. delete any other "<dir>/.." (recursively)
  570.  * While we're at it, remove double slashes and "." components like
  571.  *   clean_fname does(), but DON'T remove a trailing slash because that
  572.  *   is sometimes significant on command line arguments.
  573.  * Can only shrink paths, so sanitizes in place.
  574.  * Contributed by Dave Dykstra <dwd@bell-labs.com>
  575.  */
  576.  
  577. void sanitize_path(char *p)
  578. {
  579.     char *start, *sanp;
  580.  
  581.     start = p;
  582.     sanp = p;
  583.     while (*p == '/') {
  584.         /* remove leading slashes */
  585.         p++;
  586.     }
  587.     while (*p != '\0') {
  588.         /* this loop iterates once per filename component in p.
  589.          * both p (and sanp if the original had a slash) should
  590.          * always be left pointing after a slash
  591.          */
  592.         if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
  593.             /* skip "." component */
  594.             while (*++p == '/') {
  595.                 /* skip following slashes */
  596.                 ;
  597.             }
  598.         } else if ((*p == '.') && (*(p+1) == '.') &&
  599.                 ((*(p+2) == '/') || (*(p+2) == '\0'))) {
  600.             /* skip ".." component followed by slash or end */
  601.             p += 2;
  602.             if (*p == '/')
  603.                 p++;
  604.             if (sanp != start) {
  605.                 /* back up sanp one level */
  606.                 --sanp; /* now pointing at slash */
  607.                 while ((sanp > start) && (*(sanp - 1) != '/')) {
  608.                     /* skip back up to slash */
  609.                     sanp--;
  610.                 }
  611.             }
  612.         } else {
  613.             while (1) {
  614.                 /* copy one component through next slash */
  615.                 *sanp++ = *p++;
  616.                 if ((*p == '\0') || (*(p-1) == '/')) {
  617.                     while (*p == '/') {
  618.                         /* skip multiple slashes */
  619.                         p++;
  620.                     }
  621.                     break;
  622.                 }
  623.             }
  624.         }
  625.     }
  626.     if (sanp == start) {
  627.         /* ended up with nothing, so put in "." component */
  628.         *sanp++ = '.';
  629.     }
  630.     *sanp = '\0';
  631. }
  632.  
  633.  
  634. static char curr_dir[MAXPATHLEN];
  635.  
  636. /* like chdir() but can be reversed with pop_dir() if save is set. It
  637.    is also much faster as it remembers where we have been */
  638. char *push_dir(char *dir, int save)
  639. {
  640.     char *ret = curr_dir;
  641.     static int initialised;
  642.  
  643.     if (!initialised) {
  644.         initialised = 1;
  645. #ifdef __EMX__
  646.         _getcwd2(curr_dir, sizeof(curr_dir)-1);
  647. #else
  648.         getcwd(curr_dir, sizeof(curr_dir)-1);
  649. #endif
  650.     }
  651.  
  652. #ifdef __EMX__
  653.     if (_chdir2(dir)) return NULL;
  654. #else
  655.     if (chdir(dir)) return NULL;
  656. #endif
  657.  
  658.     if (save) {
  659.         ret = strdup(curr_dir);
  660.     }
  661.  
  662. #ifdef __EMX__
  663.     if ((*dir == '/') || (dir[1] == ':')) {
  664. #else
  665.     if (*dir == '/') {
  666. #endif
  667.         strlcpy(curr_dir, dir, sizeof(curr_dir));
  668.     } else {
  669.         strlcat(curr_dir,"/", sizeof(curr_dir));
  670.         strlcat(curr_dir,dir, sizeof(curr_dir));
  671.     }
  672.  
  673.     clean_fname(curr_dir);
  674.  
  675.     return ret;
  676. }
  677.  
  678. /* reverse a push_dir call */
  679. int pop_dir(char *dir)
  680. {
  681.     int ret;
  682.  
  683. #ifdef __EMX__
  684.     ret = _chdir2(dir);
  685. #else
  686.     ret = chdir(dir);
  687. #endif
  688.     if (ret) {
  689.         free(dir);
  690.         return ret;
  691.     }
  692.  
  693.     strlcpy(curr_dir, dir, sizeof(curr_dir));
  694.  
  695.     free(dir);
  696.  
  697.     return 0;
  698. }
  699.  
  700. /* we need to supply our own strcmp function for file list comparisons
  701.    to ensure that signed/unsigned usage is consistent between machines. */
  702. int u_strcmp(const char *cs1, const char *cs2)
  703. {
  704.     const uchar *s1 = (const uchar *)cs1;
  705.     const uchar *s2 = (const uchar *)cs2;
  706.  
  707.     while (*s1 && *s2 && (*s1 == *s2)) {
  708.         s1++; s2++;
  709.     }
  710.     
  711.     return (int)*s1 - (int)*s2;
  712. }
  713.  
  714. static OFF_T last_ofs;
  715.  
  716. void end_progress(void)
  717. {
  718.     extern int do_progress, am_server;
  719.  
  720.     if (do_progress && !am_server) {
  721.         rprintf(FINFO,"\n");
  722.     }
  723.     last_ofs = 0;
  724. }
  725.  
  726. void show_progress(OFF_T ofs, OFF_T size)
  727. {
  728.     extern int do_progress, am_server;
  729.  
  730.     if (do_progress && !am_server) {
  731.         if (ofs > last_ofs + 1000) {
  732.             int pct = (int)((100.0*ofs)/size);
  733.             rprintf(FINFO,"%.0f (%d%%)\r", (double)ofs, pct);
  734.             last_ofs = ofs;
  735.         }
  736.     }
  737. }
  738.  
  739. /* determine if a symlink points outside the current directory tree */
  740. int unsafe_symlink(char *dest, char *src)
  741. {
  742.     char *tok;
  743.     int depth = 0;
  744.  
  745.     /* all absolute and null symlinks are unsafe */
  746.     if (!dest || !(*dest) || (*dest == '/')) return 1;
  747.  
  748.     src = strdup(src);
  749.     if (!src) out_of_memory("unsafe_symlink");
  750.  
  751.     /* find out what our safety margin is */
  752.     for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
  753.         if (strcmp(tok,"..") == 0) {
  754.             depth=0;
  755.         } else if (strcmp(tok,".") == 0) {
  756.             /* nothing */
  757.         } else {
  758.             depth++;
  759.         }
  760.     }
  761.     free(src);
  762.  
  763.     /* drop by one to account for the filename portion */
  764.     depth--;
  765.  
  766.     dest = strdup(dest);
  767.     if (!dest) out_of_memory("unsafe_symlink");
  768.  
  769.     for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
  770.         if (strcmp(tok,"..") == 0) {
  771.             depth--;
  772.         } else if (strcmp(tok,".") == 0) {
  773.             /* nothing */
  774.         } else {
  775.             depth++;
  776.         }
  777.         /* if at any point we go outside the current directory then
  778.            stop - it is unsafe */
  779.         if (depth < 0) break;
  780.     }
  781.  
  782.     free(dest);
  783.     return (depth < 0);
  784. }
  785.  
  786.  
  787. /****************************************************************************
  788.   return the date and time as a string
  789. ****************************************************************************/
  790. char *timestring(time_t t)
  791. {
  792.     static char TimeBuf[200];
  793.     struct tm *tm = localtime(&t);
  794.  
  795. #ifdef HAVE_STRFTIME
  796.     strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
  797. #else
  798.     strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
  799. #endif
  800.  
  801.     if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
  802.         TimeBuf[strlen(TimeBuf)-1] = 0;
  803.     }
  804.  
  805.     return(TimeBuf);
  806. }
  807.  
  808.