Diff for /embedaddon/rsync/util.c between versions 1.1.1.1 and 1.1.1.4

version 1.1.1.1, 2012/02/17 15:09:30 version 1.1.1.4, 2021/03/17 00:32:36
Line 4 Line 4
  * Copyright (C) 1996-2000 Andrew Tridgell   * Copyright (C) 1996-2000 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras   * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>   * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
 * Copyright (C) 2003-2009 Wayne Davison * Copyright (C) 2003-2020 Wayne Davison
  *   *
  * This program is free software; you can redistribute it and/or modify   * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
Line 22 Line 22
   
 #include "rsync.h"  #include "rsync.h"
 #include "ifuncs.h"  #include "ifuncs.h"
   #include "itypes.h"
   #include "inums.h"
   
extern int verbose;extern int dry_run;
 extern int module_id;  extern int module_id;
   extern int do_fsync;
   extern int protect_args;
 extern int modify_window;  extern int modify_window;
 extern int relative_paths;  extern int relative_paths;
 extern int preserve_times;  extern int preserve_times;
 extern int human_readable;  
 extern int preserve_xattrs;  extern int preserve_xattrs;
   extern int preallocate_files;
   extern int force_change;
 extern char *module_dir;  extern char *module_dir;
 extern unsigned int module_dirlen;  extern unsigned int module_dirlen;
 extern mode_t orig_umask;  
 extern char *partial_dir;  extern char *partial_dir;
extern struct filter_list_struct daemon_filter_list;extern filter_rule_list daemon_filter_list;
   
 int sanitize_paths = 0;  int sanitize_paths = 0;
   
Line 94  int fd_pair(int fd[2]) Line 98  int fd_pair(int fd[2])
   
 void print_child_argv(const char *prefix, char **cmd)  void print_child_argv(const char *prefix, char **cmd)
 {  {
           int cnt = 0;
         rprintf(FCLIENT, "%s ", prefix);          rprintf(FCLIENT, "%s ", prefix);
         for (; *cmd; cmd++) {          for (; *cmd; cmd++) {
                 /* Look for characters that ought to be quoted.  This                  /* Look for characters that ought to be quoted.  This
Line 107  void print_child_argv(const char *prefix, char **cmd) Line 112  void print_child_argv(const char *prefix, char **cmd)
                 } else {                  } else {
                         rprintf(FCLIENT, "%s ", *cmd);                          rprintf(FCLIENT, "%s ", *cmd);
                 }                  }
                   cnt++;
         }          }
        rprintf(FCLIENT, "\n");        rprintf(FCLIENT, " (%d args)\n", cnt);
 }  }
   
NORETURN void out_of_memory(const char *str)#ifdef SUPPORT_FORCE_CHANGE
 static int try_a_force_change(const char *fname, STRUCT_STAT *stp)
 {  {
        rprintf(FERROR, "ERROR: out of memory in %s [%s]\n", str, who_am_i());        uint32 fileflags = ST_FLAGS(*stp);
        exit_cleanup(RERR_MALLOC);        if (fileflags == NO_FFLAGS) {
}                STRUCT_STAT st;
                 if (x_lstat(fname, &st, NULL) == 0)
                         fileflags = st.st_flags;
         }
         if (fileflags != NO_FFLAGS && make_mutable(fname, stp->st_mode, fileflags, force_change) > 0) {
                 int ret, save_force_change = force_change;
   
NORETURN void overflow_exit(const char *str)                force_change = 0; /* Make certain we can't come back here. */
{                ret = set_times(fname, stp);
        rprintf(FERROR, "ERROR: buffer overflow in %s [%s]\n", str, who_am_i());                force_change = save_force_change;
        exit_cleanup(RERR_MALLOC);
                 undo_make_mutable(fname, fileflags);
 
                 return ret;
         }
 
         errno = EPERM;
 
         return -1;
 }  }
   #endif
   
 /* This returns 0 for success, 1 for a symlink if symlink time-setting  /* This returns 0 for success, 1 for a symlink if symlink time-setting
  * is not possible, or -1 for any other error. */   * is not possible, or -1 for any other error. */
int set_modtime(const char *fname, time_t modtime, mode_t mode)int set_times(const char *fname, STRUCT_STAT *stp)
 {  {
         static int switch_step = 0;          static int switch_step = 0;
   
        if (verbose > 2) {        if (DEBUG_GTE(TIME, 1)) {
                rprintf(FINFO, "set modtime of %s to (%ld) %s",                rprintf(FINFO,
                        fname, (long)modtime,                        "set modtime, atime of %s to (%ld) %s, (%ld) %s\n",
                        asctime(localtime(&modtime)));                        fname, (long)stp->st_mtime,
                         timestring(stp->st_mtime), (long)stp->st_atime, timestring(stp->st_atime));
         }          }
   
         switch (switch_step) {          switch (switch_step) {
   #ifdef HAVE_SETATTRLIST
   #include "case_N.h"
                   if (do_setattrlist_times(fname, stp) == 0)
                           break;
                   if (errno != ENOSYS)
                           return -1;
                   switch_step++;
   #endif
   
 #ifdef HAVE_UTIMENSAT  #ifdef HAVE_UTIMENSAT
 #include "case_N.h"  #include "case_N.h"
                if (do_utimensat(fname, modtime, 0) == 0)                if (do_utimensat(fname, stp) == 0)
                         break;                          break;
   #ifdef SUPPORT_FORCE_CHANGE
                   if (force_change && errno == EPERM && try_a_force_change(fname, stp) == 0)
                           break;
   #endif
                 if (errno != ENOSYS)                  if (errno != ENOSYS)
                         return -1;                          return -1;
                 switch_step++;                  switch_step++;
                 /* FALLTHROUGH */  
 #endif  #endif
   
 #ifdef HAVE_LUTIMES  #ifdef HAVE_LUTIMES
 #include "case_N.h"  #include "case_N.h"
                if (do_lutimes(fname, modtime, 0) == 0)                if (do_lutimes(fname, stp) == 0)
                         break;                          break;
   #ifdef SUPPORT_FORCE_CHANGE
                   if (force_change && errno == EPERM && try_a_force_change(fname, stp) == 0)
                           break;
   #endif
                 if (errno != ENOSYS)                  if (errno != ENOSYS)
                         return -1;                          return -1;
                 switch_step++;                  switch_step++;
                 /* FALLTHROUGH */  
 #endif  #endif
   
 #include "case_N.h"  #include "case_N.h"
                 switch_step++;                  switch_step++;
                 if (preserve_times & PRESERVE_LINK_TIMES) {                  if (preserve_times & PRESERVE_LINK_TIMES) {
                         preserve_times &= ~PRESERVE_LINK_TIMES;                          preserve_times &= ~PRESERVE_LINK_TIMES;
                        if (S_ISLNK(mode))                        if (S_ISLNK(stp->st_mode))
                                 return 1;                                  return 1;
                 }                  }
                 /* FALLTHROUGH */  
   
 #include "case_N.h"  #include "case_N.h"
 #ifdef HAVE_UTIMES  #ifdef HAVE_UTIMES
                if (do_utimes(fname, modtime, 0) == 0)                if (do_utimes(fname, stp) == 0)
                         break;                          break;
 #else  #else
                if (do_utime(fname, modtime, 0) == 0)                if (do_utime(fname, stp) == 0)
                         break;                          break;
 #endif  #endif
   #ifdef SUPPORT_FORCE_CHANGE
                   if (force_change && errno == EPERM && try_a_force_change(fname, stp) == 0)
                           break;
   #endif
   
                 return -1;                  return -1;
         }          }
Line 180  int set_modtime(const char *fname, time_t modtime, mod Line 220  int set_modtime(const char *fname, time_t modtime, mod
         return 0;          return 0;
 }  }
   
 /* This creates a new directory with default permissions.  Since there  
  * might be some directory-default permissions affecting this, we can't  
  * force the permissions directly using the original umask and mkdir(). */  
 int mkdir_defmode(char *fname)  
 {  
         int ret;  
   
         umask(orig_umask);  
         ret = do_mkdir(fname, ACCESSPERMS);  
         umask(0);  
   
         return ret;  
 }  
   
 /* Create any necessary directories in fname.  Any missing directories are  /* Create any necessary directories in fname.  Any missing directories are
 * created with default permissions. */ * created with default permissions.  Returns < 0 on error, or the number
int create_directory_path(char *fname) * of directories created. */
 int make_path(char *fname, mode_t mode, int flags)
 {  {
        char *p;        char *end, *p;
         int ret = 0;          int ret = 0;
   
        while (*fname == '/')        if (flags & MKP_SKIP_SLASH) {
                fname++;                while (*fname == '/')
        while (strncmp(fname, "./", 2) == 0)                        fname++;
         }
 
         while (*fname == '.' && fname[1] == '/')
                 fname += 2;                  fname += 2;
   
        umask(orig_umask);        if (flags & MKP_DROP_NAME) {
        p = fname;                end = strrchr(fname, '/');
        while ((p = strchr(p,'/')) != NULL) {                if (!end || end == fname)
                *p = '\0';                        return 0;
                if (do_mkdir(fname, ACCESSPERMS) < 0 && errno != EEXIST)                *end = '\0';
                    ret = -1;        } else
                *p++ = '/';                end = fname + strlen(fname);
 
         /* Try to find an existing dir, starting from the deepest dir. */
         for (p = end; ; ) {
                 if (dry_run) {
                         STRUCT_STAT st;
                         if (do_stat(fname, &st) == 0) {
                                 if (S_ISDIR(st.st_mode))
                                         errno = EEXIST;
                                 else
                                         errno = ENOTDIR;
                         }
                 } else if (do_mkdir(fname, mode) == 0) {
                         ret++;
                         break;
                 }
 
                 if (errno != ENOENT) {
                         STRUCT_STAT st;
                         if (errno != EEXIST || (do_stat(fname, &st) == 0 && !S_ISDIR(st.st_mode)))
                                 ret = -ret - 1;
                         break;
                 }
                 while (1) {
                         if (p == fname) {
                                 /* We got a relative path that doesn't exist, so assume that '.'
                                  * is there and just break out and create the whole thing. */
                                 p = NULL;
                                 goto double_break;
                         }
                         if (*--p == '/') {
                                 if (p == fname) {
                                         /* We reached the "/" dir, which we assume is there. */
                                         goto double_break;
                                 }
                                 *p = '\0';
                                 break;
                         }
                 }
         }          }
        umask(0);  double_break:
   
           /* Make all the dirs that we didn't find on the way here. */
           while (p != end) {
                   if (p)
                           *p = '/';
                   else
                           p = fname;
                   p += strlen(p);
                   if (ret < 0) /* Skip mkdir on error, but keep restoring the path. */
                           continue;
                   if (do_mkdir(fname, mode) < 0)
                           ret = -ret - 1;
                   else
                           ret++;
           }
   
           if (flags & MKP_DROP_NAME)
                   *end = '/';
   
         return ret;          return ret;
 }  }
   
Line 280  static int safe_read(int desc, char *ptr, size_t len) Line 366  static int safe_read(int desc, char *ptr, size_t len)
  *   *
  * This is used in conjunction with the --temp-dir, --backup, and   * This is used in conjunction with the --temp-dir, --backup, and
  * --copy-dest options. */   * --copy-dest options. */
int copy_file(const char *source, const char *dest, int ofd,int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
              mode_t mode, int create_bak_dir) 
 {  {
         int ifd;          int ifd;
         char buf[1024 * 8];          char buf[1024 * 8];
         int len;   /* Number of bytes read into `buf'. */          int len;   /* Number of bytes read into `buf'. */
           OFF_T prealloc_len = 0, offset = 0;
   
         if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {          if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
                 int save_errno = errno;                  int save_errno = errno;
Line 298  int copy_file(const char *source, const char *dest, in Line 384  int copy_file(const char *source, const char *dest, in
                 if (robust_unlink(dest) && errno != ENOENT) {                  if (robust_unlink(dest) && errno != ENOENT) {
                         int save_errno = errno;                          int save_errno = errno;
                         rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest));                          rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest));
                           close(ifd);
                         errno = save_errno;                          errno = save_errno;
                         return -1;                          return -1;
                 }                  }
   
   #ifdef SUPPORT_XATTRS
                   if (preserve_xattrs)
                           mode |= S_IWUSR;
   #endif
                   mode &= INITACCESSPERMS;
                 if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {                  if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
                        int save_errno = errno ? errno : EINVAL; /* 0 paranoia */                        int save_errno = errno;
                        if (create_bak_dir && errno == ENOENT && make_bak_dir(dest) == 0) {                        rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest));
                                if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0)                        close(ifd);
                                        save_errno = errno ? errno : save_errno;                        errno = save_errno;
                                else                        return -1;
                                        save_errno = 0; 
                        } 
                        if (save_errno) { 
                                rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest)); 
                                close(ifd); 
                                errno = save_errno; 
                                return -1; 
                        } 
                 }                  }
         }          }
   
   #ifdef SUPPORT_PREALLOCATION
           if (preallocate_files) {
                   STRUCT_STAT srcst;
   
                   /* Try to preallocate enough space for file's eventual length.  Can
                    * reduce fragmentation on filesystems like ext4, xfs, and NTFS. */
                   if (do_fstat(ifd, &srcst) < 0)
                           rsyserr(FWARNING, errno, "fstat %s", full_fname(source));
                   else if (srcst.st_size > 0) {
                           prealloc_len = do_fallocate(ofd, 0, srcst.st_size);
                           if (prealloc_len < 0)
                                   rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest));
                   }
           }
   #endif
   
         while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {          while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
                 if (full_write(ofd, buf, len) < 0) {                  if (full_write(ofd, buf, len) < 0) {
                         int save_errno = errno;                          int save_errno = errno;
Line 328  int copy_file(const char *source, const char *dest, in Line 428  int copy_file(const char *source, const char *dest, in
                         errno = save_errno;                          errno = save_errno;
                         return -1;                          return -1;
                 }                  }
                   offset += len;
         }          }
   
         if (len < 0) {          if (len < 0) {
Line 344  int copy_file(const char *source, const char *dest, in Line 445  int copy_file(const char *source, const char *dest, in
                         full_fname(source));                          full_fname(source));
         }          }
   
           /* Source file might have shrunk since we fstatted it.
            * Cut off any extra preallocated zeros from dest file. */
           if (offset < prealloc_len && do_ftruncate(ofd, offset) < 0) {
                   /* If we fail to truncate, the dest file may be wrong, so we
                    * must trigger the "partial transfer" error. */
                   rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest));
           }
   
           if (do_fsync && fsync(ofd) < 0) {
                   rsyserr(FERROR, errno, "fsync failed on %s",
                           full_fname(dest));
                   close(ofd);
                   return -1;
           }
   
         if (close(ofd) < 0) {          if (close(ofd) < 0) {
                 int save_errno = errno;                  int save_errno = errno;
                 rsyserr(FERROR_XFER, errno, "close failed on %s",                  rsyserr(FERROR_XFER, errno, "close failed on %s",
Line 407  int robust_unlink(const char *fname) Line 523  int robust_unlink(const char *fname)
                         counter = 1;                          counter = 1;
         } while ((rc = access(path, 0)) == 0 && counter != start);          } while ((rc = access(path, 0)) == 0 && counter != start);
   
        if (verbose > 0) {        if (INFO_GTE(MISC, 1)) {
                 rprintf(FWARNING, "renaming %s to %s because of text busy\n",                  rprintf(FWARNING, "renaming %s to %s because of text busy\n",
                         fname, path);                          fname, path);
         }          }
Line 430  int robust_rename(const char *from, const char *to, co Line 546  int robust_rename(const char *from, const char *to, co
 {  {
         int tries = 4;          int tries = 4;
   
           /* A resumed in-place partial-dir transfer might call us with from and
            * to pointing to the same buf if the transfer failed yet again. */
           if (from == to)
                   return 0;
   
         while (tries--) {          while (tries--) {
                 if (do_rename(from, to) == 0)                  if (do_rename(from, to) == 0)
                         return 0;                          return 0;
Line 450  int robust_rename(const char *from, const char *to, co Line 571  int robust_rename(const char *from, const char *to, co
                                         return -2;                                          return -2;
                                 to = partialptr;                                  to = partialptr;
                         }                          }
                        if (copy_file(from, to, -1, mode, 0) != 0)                        if (copy_file(from, to, -1, mode) != 0)
                                 return -2;                                  return -2;
                         do_unlink(from);                          do_unlink(from);
                         return 1;                          return 1;
Line 504  void kill_all(int sig) Line 625  void kill_all(int sig)
         }          }
 }  }
   
 /** Turn a user name into a uid */  
 int name_to_uid(const char *name, uid_t *uid_p)  
 {  
         struct passwd *pass;  
         if (!name || !*name)  
                 return 0;  
         if (!(pass = getpwnam(name)))  
                 return 0;  
         *uid_p = pass->pw_uid;  
         return 1;  
 }  
   
 /** Turn a group name into a gid */  
 int name_to_gid(const char *name, gid_t *gid_p)  
 {  
         struct group *grp;  
         if (!name || !*name)  
                 return 0;  
         if (!(grp = getgrnam(name)))  
                 return 0;  
         *gid_p = grp->gr_gid;  
         return 1;  
 }  
   
 /** Lock a byte range in a open file */  /** Lock a byte range in a open file */
 int lock_range(int fd, int offset, int len)  int lock_range(int fd, int offset, int len)
 {  {
Line 543  int lock_range(int fd, int offset, int len) Line 640  int lock_range(int fd, int offset, int len)
 }  }
   
 #define ENSURE_MEMSPACE(buf, type, sz, req) \  #define ENSURE_MEMSPACE(buf, type, sz, req) \
        if ((req) > sz && !(buf = realloc_array(buf, type, sz = MAX(sz * 2, req)))) \        do { if ((req) > sz) buf = realloc_array(buf, type, sz = MAX(sz * 2, req)); } while(0)
                out_of_memory("glob_expand") 
   
 static inline void call_glob_match(const char *name, int len, int from_glob,  static inline void call_glob_match(const char *name, int len, int from_glob,
                                    char *arg, int abpos, int fbpos);                                     char *arg, int abpos, int fbpos);
Line 646  static inline void call_glob_match(const char *name, i Line 742  static inline void call_glob_match(const char *name, i
                 glob_match(arg, abpos, fbpos);                  glob_match(arg, abpos, fbpos);
         } else {          } else {
                 ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);                  ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);
                if (!(glob.argv[glob.argc++] = strdup(glob.arg_buf)))                glob.argv[glob.argc++] = strdup(glob.arg_buf);
                        out_of_memory("glob_match"); 
         }          }
 }  }
   
Line 671  int glob_expand(const char *arg, char ***argv_p, int * Line 766  int glob_expand(const char *arg, char ***argv_p, int *
                 s = sanitize_path(NULL, arg, "", 0, SP_KEEP_DOT_DIRS);                  s = sanitize_path(NULL, arg, "", 0, SP_KEEP_DOT_DIRS);
         else {          else {
                 s = strdup(arg);                  s = strdup(arg);
                if (!s)                clean_fname(s, CFN_KEEP_DOT_DIRS | CFN_KEEP_TRAILING_SLASH | CFN_COLLAPSE_DOT_DOT_DIRS);
                        out_of_memory("glob_expand"); 
                clean_fname(s, CFN_KEEP_DOT_DIRS 
                             | CFN_KEEP_TRAILING_SLASH 
                             | CFN_COLLAPSE_DOT_DOT_DIRS); 
         }          }
   
         ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN);          ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN);
Line 719  void glob_expand_module(char *base1, char *arg, char * Line 810  void glob_expand_module(char *base1, char *arg, char *
         if (strncmp(arg, base, base_len) == 0)          if (strncmp(arg, base, base_len) == 0)
                 arg += base_len;                  arg += base_len;
   
        if (!(arg = strdup(arg)))        if (protect_args) {
                out_of_memory("glob_expand_module");                glob_expand(arg, argv_p, argc_p, maxargs_p);
                 return;
         }
   
        if (asprintf(&base," %s/", base1) <= 0)        arg = strdup(arg);
 
         if (asprintf(&base," %s/", base1) < 0)
                 out_of_memory("glob_expand_module");                  out_of_memory("glob_expand_module");
         base_len++;          base_len++;
   
Line 750  void strlower(char *s) Line 845  void strlower(char *s)
         }          }
 }  }
   
   /**
    * Split a string into tokens based (usually) on whitespace & commas.  If the
    * string starts with a comma (after skipping any leading whitespace), then
    * splitting is done only on commas. No empty tokens are ever returned. */
   char *conf_strtok(char *str)
   {
           static int commas_only = 0;
   
           if (str) {
                   while (isSpace(str)) str++;
                   if (*str == ',') {
                           commas_only = 1;
                           str++;
                   } else
                           commas_only = 0;
           }
   
           while (commas_only) {
                   char *end, *tok = strtok(str, ",");
                   if (!tok)
                           return NULL;
                   /* Trim just leading and trailing whitespace. */
                   while (isSpace(tok))
                           tok++;
                   end = tok + strlen(tok);
                   while (end > tok && isSpace(end-1))
                           *--end = '\0';
                   if (*tok)
                           return tok;
                   str = NULL;
           }
   
           return strtok(str, " ,\t\r\n");
   }
   
 /* Join strings p1 & p2 into "dest" with a guaranteed '/' between them.  (If  /* Join strings p1 & p2 into "dest" with a guaranteed '/' between them.  (If
  * p1 ends with a '/', no extra '/' is inserted.)  Returns the length of both   * p1 ends with a '/', no extra '/' is inserted.)  Returns the length of both
  * strings + 1 (if '/' was inserted), regardless of whether the null-terminated   * strings + 1 (if '/' was inserted), regardless of whether the null-terminated
Line 802  size_t stringjoin(char *dest, size_t destsize, ...) Line 932  size_t stringjoin(char *dest, size_t destsize, ...)
         return ret;          return ret;
 }  }
   
   /* Append formatted text at *dest_ptr up to a maximum of sz (like snprintf).
    * On success, advance *dest_ptr and return True; on overflow, return False. */
   BOOL snappendf(char **dest_ptr, size_t sz, const char *format, ...)
   {
           va_list ap;
           size_t len;
   
           va_start(ap, format);
           len = vsnprintf(*dest_ptr, sz, format, ap);
           va_end(ap);
   
           if (len >= sz)
                   return False;
           else {
                   *dest_ptr += len;
                   return True;
           }
   }
   
 int count_dir_elements(const char *p)  int count_dir_elements(const char *p)
 {  {
         int cnt = 0, new_component = 1;          int cnt = 0, new_component = 1;
Line 824  int count_dir_elements(const char *p) Line 973  int count_dir_elements(const char *p)
  * CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements   * CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements
  * (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged.  If the   * (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged.  If the
  * resulting name would be empty, returns ".". */   * resulting name would be empty, returns ".". */
unsigned int clean_fname(char *name, int flags)int clean_fname(char *name, int flags)
 {  {
         char *limit = name - 1, *t = name, *f = name;          char *limit = name - 1, *t = name, *f = name;
         int anchored;          int anchored;
Line 832  unsigned int clean_fname(char *name, int flags) Line 981  unsigned int clean_fname(char *name, int flags)
         if (!name)          if (!name)
                 return 0;                  return 0;
   
   #define DOT_IS_DOT_DOT_DIR(bp) (bp[1] == '.' && (bp[2] == '/' || !bp[2]))
   
         if ((anchored = *f == '/') != 0) {          if ((anchored = *f == '/') != 0) {
                 *t++ = *f++;                  *t++ = *f++;
 #ifdef __CYGWIN__  #ifdef __CYGWIN__
Line 844  unsigned int clean_fname(char *name, int flags) Line 995  unsigned int clean_fname(char *name, int flags)
         } else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') {          } else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') {
                 *t++ = *f++;                  *t++ = *f++;
                 *t++ = *f++;                  *t++ = *f++;
        }        } else if (flags & CFN_REFUSE_DOT_DOT_DIRS && *f == '.' && DOT_IS_DOT_DOT_DIR(f))
                 return -1;
         while (*f) {          while (*f) {
                 /* discard extra slashes */                  /* discard extra slashes */
                 if (*f == '/') {                  if (*f == '/') {
Line 860  unsigned int clean_fname(char *name, int flags) Line 1012  unsigned int clean_fname(char *name, int flags)
                         if (f[1] == '\0' && flags & CFN_DROP_TRAILING_DOT_DIR)                          if (f[1] == '\0' && flags & CFN_DROP_TRAILING_DOT_DIR)
                                 break;                                  break;
                         /* collapse ".." dirs */                          /* collapse ".." dirs */
                        if (flags & CFN_COLLAPSE_DOT_DOT_DIRS                        if (flags & (CFN_COLLAPSE_DOT_DOT_DIRS|CFN_REFUSE_DOT_DOT_DIRS) && DOT_IS_DOT_DOT_DIR(f)) {
                         && f[1] == '.' && (f[2] == '/' || !f[2])) { 
                                 char *s = t - 1;                                  char *s = t - 1;
                                   if (flags & CFN_REFUSE_DOT_DOT_DIRS)
                                           return -1;
                                 if (s == name && anchored) {                                  if (s == name && anchored) {
                                         f += 2;                                          f += 2;
                                         continue;                                          continue;
Line 885  unsigned int clean_fname(char *name, int flags) Line 1038  unsigned int clean_fname(char *name, int flags)
                 *t++ = '.';                  *t++ = '.';
         *t = '\0';          *t = '\0';
   
   #undef DOT_IS_DOT_DOT_DIR
   
         return t - name;          return t - name;
 }  }
   
Line 910  unsigned int clean_fname(char *name, int flags) Line 1065  unsigned int clean_fname(char *name, int flags)
  * ALWAYS collapses ".." elements (except for those at the start of the   * ALWAYS collapses ".." elements (except for those at the start of the
  * string up to "depth" deep).  If the resulting name would be empty,   * string up to "depth" deep).  If the resulting name would be empty,
  * change it into a ".". */   * change it into a ".". */
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth,char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth, int flags)
                    int flags) 
 {  {
         char *start, *sanp;          char *start, *sanp;
         int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS);          int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS);
   
         if (dest != p) {          if (dest != p) {
                int plen = strlen(p);                int plen = strlen(p); /* the path len INCLUDING any separating slash */
                 if (*p == '/') {                  if (*p == '/') {
                         if (!rootdir)                          if (!rootdir)
                                 rootdir = module_dir;                                  rootdir = module_dir;
Line 925  char *sanitize_path(char *dest, const char *p, const c Line 1079  char *sanitize_path(char *dest, const char *p, const c
                         depth = 0;                          depth = 0;
                         p++;                          p++;
                 }                  }
                if (dest) {                if (!dest)
                        if (rlen + plen + 1 >= MAXPATHLEN)                        dest = new_array(char, MAX(rlen + plen + 1, 2));
                                return NULL;                else if (rlen + plen + 1 >= MAXPATHLEN)
                } else if (!(dest = new_array(char, rlen + plen + 1)))                        return NULL;
                        out_of_memory("sanitize_path");                if (rlen) { /* only true if p previously started with a slash */
                if (rlen) { 
                         memcpy(dest, rootdir, rlen);                          memcpy(dest, rootdir, rlen);
                        if (rlen > 1)                        if (rlen > 1) /* a rootdir of len 1 is "/", so this avoids a 2nd slash */
                                 dest[rlen++] = '/';                                  dest[rlen++] = '/';
                 }                  }
         }          }
Line 992  char *sanitize_path(char *dest, const char *p, const c Line 1145  char *sanitize_path(char *dest, const char *p, const c
  * Also cleans the path using the clean_fname() function. */   * Also cleans the path using the clean_fname() function. */
 int change_dir(const char *dir, int set_path_only)  int change_dir(const char *dir, int set_path_only)
 {  {
        static int initialised;        static int initialised, skipped_chdir;
         unsigned int len;          unsigned int len;
   
         if (!initialised) {          if (!initialised) {
Line 1008  int change_dir(const char *dir, int set_path_only) Line 1161  int change_dir(const char *dir, int set_path_only)
                 return 0;                  return 0;
   
         len = strlen(dir);          len = strlen(dir);
        if (len == 1 && *dir == '.')        if (len == 1 && *dir == '.' && (!skipped_chdir || set_path_only))
                 return 1;                  return 1;
   
         if (*dir == '/') {          if (*dir == '/') {
Line 1018  int change_dir(const char *dir, int set_path_only) Line 1171  int change_dir(const char *dir, int set_path_only)
                 }                  }
                 if (!set_path_only && chdir(dir))                  if (!set_path_only && chdir(dir))
                         return 0;                          return 0;
                   skipped_chdir = set_path_only;
                 memcpy(curr_dir, dir, len + 1);                  memcpy(curr_dir, dir, len + 1);
         } else {          } else {
                   unsigned int save_dir_len = curr_dir_len;
                 if (curr_dir_len + 1 + len >= sizeof curr_dir) {                  if (curr_dir_len + 1 + len >= sizeof curr_dir) {
                         errno = ENAMETOOLONG;                          errno = ENAMETOOLONG;
                         return 0;                          return 0;
Line 1029  int change_dir(const char *dir, int set_path_only) Line 1184  int change_dir(const char *dir, int set_path_only)
                 memcpy(curr_dir + curr_dir_len, dir, len + 1);                  memcpy(curr_dir + curr_dir_len, dir, len + 1);
   
                 if (!set_path_only && chdir(curr_dir)) {                  if (!set_path_only && chdir(curr_dir)) {
                           curr_dir_len = save_dir_len;
                         curr_dir[curr_dir_len] = '\0';                          curr_dir[curr_dir_len] = '\0';
                         return 0;                          return 0;
                 }                  }
                   skipped_chdir = set_path_only;
         }          }
   
        curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS);        curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);
         if (sanitize_paths) {          if (sanitize_paths) {
                 if (module_dirlen > curr_dir_len)                  if (module_dirlen > curr_dir_len)
                         module_dirlen = curr_dir_len;                          module_dirlen = curr_dir_len;
                 curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);                  curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);
         }          }
   
        if (verbose >= 5 && !set_path_only)        if (DEBUG_GTE(CHDIR, 1) && !set_path_only)
                 rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir);                  rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir);
   
         return 1;          return 1;
Line 1059  char *normalize_path(char *path, BOOL force_newbuf, un Line 1216  char *normalize_path(char *path, BOOL force_newbuf, un
                         return NULL;                          return NULL;
                 curr_dir[curr_dir_len] = '/';                  curr_dir[curr_dir_len] = '/';
                 memcpy(curr_dir + curr_dir_len + 1, path, len + 1);                  memcpy(curr_dir + curr_dir_len + 1, path, len + 1);
                if (!(path = strdup(curr_dir)))                path = strdup(curr_dir);
                        out_of_memory("normalize_path"); 
                 curr_dir[curr_dir_len] = '\0';                  curr_dir[curr_dir_len] = '\0';
        } else if (force_newbuf) {        } else if (force_newbuf)
                if (!(path = strdup(path)))                path = strdup(path);
                        out_of_memory("normalize_path"); 
        } 
   
         len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);          len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);
   
Line 1075  char *normalize_path(char *path, BOOL force_newbuf, un Line 1229  char *normalize_path(char *path, BOOL force_newbuf, un
         return path;          return path;
 }  }
   
   /* We need to supply our own strcmp function for file list comparisons
    * to ensure that signed/unsigned usage is consistent between machines. */
   int u_strcmp(const char *p1, const char *p2)
   {
           for ( ; *p1; p1++, p2++) {
                   if (*p1 != *p2)
                           break;
           }
   
           return (int)*(uchar*)p1 - (int)*(uchar*)p2;
   }
   
   /* We need a memcmp function compares unsigned-byte values. */
   int u_memcmp(const void *p1, const void *p2, size_t len)
   {
           const uchar *u1 = p1;
           const uchar *u2 = p2;
   
           while (len--) {
                   if (*u1 != *u2)
                           return (int)*u1 - (int)*u2;
           }
   
           return 0;
   }
   
 /**  /**
  * Return a quoted string with the full pathname of the indicated filename.   * Return a quoted string with the full pathname of the indicated filename.
  * The string " (in MODNAME)" may also be appended.  The returned pointer   * The string " (in MODNAME)" may also be appended.  The returned pointer
Line 1104  char *full_fname(const char *fn) Line 1284  char *full_fname(const char *fn)
         } else          } else
                 m1 = m2 = m3 = "";                  m1 = m2 = m3 = "";
   
        if (asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3) <= 0)        if (asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3) < 0)
                 out_of_memory("full_fname");                  out_of_memory("full_fname");
   
         return result;          return result;
Line 1168  int handle_partial_dir(const char *fname, int create) Line 1348  int handle_partial_dir(const char *fname, int create)
                         }                          }
                         statret = -1;                          statret = -1;
                 }                  }
                if (statret < 0 && do_mkdir(dir, 0700) < 0) {                if (statret < 0 && make_path(dir, 0700, 0) < 0) {
                         *fn = '/';                          *fn = '/';
                         return 0;                          return 0;
                 }                  }
Line 1238  int unsafe_symlink(const char *dest, const char *src) Line 1418  int unsafe_symlink(const char *dest, const char *src)
         return depth < 0;          return depth < 0;
 }  }
   
 #define HUMANIFY(mult) \  
         do { \  
                 if (num >= mult || num <= -mult) { \  
                         double dnum = (double)num / mult; \  
                         char units; \  
                         if (num < 0) \  
                                 dnum = -dnum; \  
                         if (dnum < mult) \  
                                 units = 'K'; \  
                         else if ((dnum /= mult) < mult) \  
                                 units = 'M'; \  
                         else { \  
                                 dnum /= mult; \  
                                 units = 'G'; \  
                         } \  
                         if (num < 0) \  
                                 dnum = -dnum; \  
                         snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); \  
                         return bufs[n]; \  
                 } \  
         } while (0)  
   
 /* Return the int64 number as a string.  If the --human-readable option was  
  * specified, we may output the number in K, M, or G units.  We can return  
  * up to 4 buffers at a time. */  
 char *human_num(int64 num)  
 {  
         static char bufs[4][128]; /* more than enough room */  
         static unsigned int n;  
         char *s;  
         int negated;  
   
         n = (n + 1) % (sizeof bufs / sizeof bufs[0]);  
   
         if (human_readable) {  
                 if (human_readable == 1)  
                         HUMANIFY(1000);  
                 else  
                         HUMANIFY(1024);  
         }  
   
         s = bufs[n] + sizeof bufs[0] - 1;  
         *s = '\0';  
   
         if (!num)  
                 *--s = '0';  
         if (num < 0) {  
                 /* A maximum-size negated number can't fit as a positive,  
                  * so do one digit in negated form to start us off. */  
                 *--s = (char)(-(num % 10)) + '0';  
                 num = -(num / 10);  
                 negated = 1;  
         } else  
                 negated = 0;  
   
         while (num) {  
                 *--s = (char)(num % 10) + '0';  
                 num /= 10;  
         }  
   
         if (negated)  
                 *--s = '-';  
   
         return s;  
 }  
   
 /* Return the double number as a string.  If the --human-readable option was  
  * specified, we may output the number in K, M, or G units.  We use a buffer  
  * from human_num() to return our result. */  
 char *human_dnum(double dnum, int decimal_digits)  
 {  
         char *buf = human_num(dnum);  
         int len = strlen(buf);  
         if (isDigit(buf + len - 1)) {  
                 /* There's extra room in buf prior to the start of the num. */  
                 buf -= decimal_digits + 2;  
                 snprintf(buf, len + decimal_digits + 3, "%.*f", decimal_digits, dnum);  
         }  
         return buf;  
 }  
   
 /* Return the date and time as a string.  Some callers tweak returned buf. */  /* Return the date and time as a string.  Some callers tweak returned buf. */
 char *timestring(time_t t)  char *timestring(time_t t)
 {  {
        static char TimeBuf[200];        static int ndx = 0;
         static char buffers[4][20]; /* We support 4 simultaneous timestring results. */
         char *TimeBuf = buffers[ndx = (ndx + 1) % 4];
         struct tm *tm = localtime(&t);          struct tm *tm = localtime(&t);
        char *p;        int len = snprintf(TimeBuf, sizeof buffers[0], "%4d/%02d/%02d %02d:%02d:%02d",
                  (int)tm->tm_year + 1900, (int)tm->tm_mon + 1, (int)tm->tm_mday,
                  (int)tm->tm_hour, (int)tm->tm_min, (int)tm->tm_sec);
         assert(len > 0); /* Silence gcc warning */
   
 #ifdef HAVE_STRFTIME  
         strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm);  
 #else  
         strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf);  
 #endif  
   
         if ((p = strchr(TimeBuf, '\n')) != NULL)  
                 *p = '\0';  
   
         return TimeBuf;          return TimeBuf;
 }  }
   
 /**  
  * Sleep for a specified number of milliseconds.  
  *  
  * Always returns TRUE.  (In the future it might return FALSE if  
  * interrupted.)  
  **/  
 int msleep(int t)  
 {  
         int tdiff = 0;  
         struct timeval tval, t1, t2;  
   
         gettimeofday(&t1, NULL);  
   
         while (tdiff < t) {  
                 tval.tv_sec = (t-tdiff)/1000;  
                 tval.tv_usec = 1000*((t-tdiff)%1000);  
   
                 errno = 0;  
                 select(0,NULL,NULL, NULL, &tval);  
   
                 gettimeofday(&t2, NULL);  
                 tdiff = (t2.tv_sec - t1.tv_sec)*1000 +  
                         (t2.tv_usec - t1.tv_usec)/1000;  
         }  
   
         return True;  
 }  
   
 /* Determine if two time_t values are equivalent (either exact, or in  /* Determine if two time_t values are equivalent (either exact, or in
  * the modification timestamp window established by --modify-window).   * the modification timestamp window established by --modify-window).
 * * Returns 1 if the times the "same", or 0 if they are different. */
 * @retval 0 if the times should be treated as the sameint same_time(time_t f1_sec, unsigned long f1_nsec, time_t f2_sec, unsigned long f2_nsec)
 * 
 * @retval +1 if the first is later 
 * 
 * @retval -1 if the 2nd is later 
 **/ 
int cmp_time(time_t file1, time_t file2) 
 {  {
        if (file2 > file1) {        if (modify_window == 0)
                if (file2 - file1 <= modify_window)                return f1_sec == f2_sec;
                        return 0;        if (modify_window < 0)
                return -1;                return f1_sec == f2_sec && f1_nsec == f2_nsec;
        }        /* The nano seconds doesn't figure into these checks -- time windows don't care about that. */
        if (file1 - file2 <= modify_window)        if (f2_sec > f1_sec)
                return 0;                return f2_sec - f1_sec <= modify_window;
        return 1;        return f1_sec - f2_sec <= modify_window;
 }  }
   
   
 #ifdef __INSURE__XX  #ifdef __INSURE__XX
 #include <dlfcn.h>  #include <dlfcn.h>
   
Line 1399  int cmp_time(time_t file1, time_t file2) Line 1459  int cmp_time(time_t file1, time_t file2)
 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)  int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
 {  {
         static int (*fn)();          static int (*fn)();
        int ret;        int ret, pid_int = getpid();
         char *cmd;          char *cmd;
   
        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'",        if (asprintf(&cmd,
                getpid(), getpid(), getpid());            "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; "
             "gdb /proc/%d/exe %d'", pid_int, pid_int, pid_int) < 0)
                 return -1;
   
         if (!fn) {          if (!fn) {
                 static void *h;                  static void *h;
Line 1421  int _Insure_trap_error(int a1, int a2, int a3, int a4, Line 1483  int _Insure_trap_error(int a1, int a2, int a3, int a4,
 }  }
 #endif  #endif
   
 #define MALLOC_MAX 0x40000000  
   
 void *_new_array(unsigned long num, unsigned int size, int use_calloc)  
 {  
         if (num >= MALLOC_MAX/size)  
                 return NULL;  
         return use_calloc ? calloc(num, size) : malloc(num * size);  
 }  
   
 void *_realloc_array(void *ptr, unsigned int size, size_t num)  
 {  
         if (num >= MALLOC_MAX/size)  
                 return NULL;  
         if (!ptr)  
                 return malloc(size * num);  
         return realloc(ptr, size * num);  
 }  
   
 /* Take a filename and filename length and return the most significant  /* Take a filename and filename length and return the most significant
  * filename suffix we can find.  This ignores suffixes such as "~",   * filename suffix we can find.  This ignores suffixes such as "~",
  * ".bak", ".orig", ".~1~", etc. */   * ".bak", ".orig", ".~1~", etc. */
Line 1475  const char *find_filename_suffix(const char *fn, int f Line 1519  const char *find_filename_suffix(const char *fn, int f
                 } else if (s_len == 5) {                  } else if (s_len == 5) {
                         if (strcmp(s+1, "orig") == 0)                          if (strcmp(s+1, "orig") == 0)
                                 continue;                                  continue;
                } else if (s_len > 2 && had_tilde                } else if (s_len > 2 && had_tilde && s[1] == '~' && isDigit(s + 2))
                    && s[1] == '~' && isDigit(s + 2)) 
                         continue;                          continue;
                 *len_ptr = s_len;                  *len_ptr = s_len;
                 suf = s;                  suf = s;
Line 1487  const char *find_filename_suffix(const char *fn, int f Line 1530  const char *find_filename_suffix(const char *fn, int f
                         if (!isDigit(s))                          if (!isDigit(s))
                                 return suf;                                  return suf;
                 }                  }
                /* An all-digit suffix may not be that signficant. */                /* An all-digit suffix may not be that significant. */
                 s = suf;                  s = suf;
         }          }
   
Line 1503  const char *find_filename_suffix(const char *fn, int f Line 1546  const char *find_filename_suffix(const char *fn, int f
   
 #define UNIT (1 << 16)  #define UNIT (1 << 16)
   
uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2)uint32 fuzzy_distance(const char *s1, unsigned len1, const char *s2, unsigned len2)
 {  {
         uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc;          uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc;
         int32 cost;          int32 cost;
        int i1, i2;        unsigned i1, i2;
   
         if (!len1 || !len2) {          if (!len1 || !len2) {
                 if (!len1) {                  if (!len1) {
Line 1551  uint32 fuzzy_distance(const char *s1, int len1, const  Line 1594  uint32 fuzzy_distance(const char *s1, int len1, const 
 #define BB_PER_SLOT_INTS (BB_SLOT_SIZE / 4) /* Number of int32s per slot */  #define BB_PER_SLOT_INTS (BB_SLOT_SIZE / 4) /* Number of int32s per slot */
   
 struct bitbag {  struct bitbag {
    uint32 **bits;        uint32 **bits;
    int slot_cnt;        int slot_cnt;
 };  };
   
 struct bitbag *bitbag_create(int max_ndx)  struct bitbag *bitbag_create(int max_ndx)
Line 1560  struct bitbag *bitbag_create(int max_ndx) Line 1603  struct bitbag *bitbag_create(int max_ndx)
         struct bitbag *bb = new(struct bitbag);          struct bitbag *bb = new(struct bitbag);
         bb->slot_cnt = (max_ndx + BB_PER_SLOT_BITS - 1) / BB_PER_SLOT_BITS;          bb->slot_cnt = (max_ndx + BB_PER_SLOT_BITS - 1) / BB_PER_SLOT_BITS;
   
        if (!(bb->bits = (uint32**)calloc(bb->slot_cnt, sizeof (uint32*))))        bb->bits = new_array0(uint32*, bb->slot_cnt);
                out_of_memory("bitbag_create"); 
   
         return bb;          return bb;
 }  }
Line 1571  void bitbag_set_bit(struct bitbag *bb, int ndx) Line 1613  void bitbag_set_bit(struct bitbag *bb, int ndx)
         int slot = ndx / BB_PER_SLOT_BITS;          int slot = ndx / BB_PER_SLOT_BITS;
         ndx %= BB_PER_SLOT_BITS;          ndx %= BB_PER_SLOT_BITS;
   
        if (!bb->bits[slot]) {        if (!bb->bits[slot])
                if (!(bb->bits[slot] = (uint32*)calloc(BB_PER_SLOT_INTS, 4)))                bb->bits[slot] = new_array0(uint32, BB_PER_SLOT_INTS);
                        out_of_memory("bitbag_set_bit"); 
        } 
   
         bb->bits[slot][ndx/32] |= 1u << (ndx % 32);          bb->bits[slot][ndx/32] |= 1u << (ndx % 32);
 }  }
Line 1642  void flist_ndx_push(flist_ndx_list *lp, int ndx) Line 1682  void flist_ndx_push(flist_ndx_list *lp, int ndx)
 {  {
         struct flist_ndx_item *item;          struct flist_ndx_item *item;
   
        if (!(item = new(struct flist_ndx_item)))        item = new(struct flist_ndx_item);
                out_of_memory("flist_ndx_push"); 
         item->next = NULL;          item->next = NULL;
         item->ndx = ndx;          item->ndx = ndx;
         if (lp->tail)          if (lp->tail)
Line 1671  int flist_ndx_pop(flist_ndx_list *lp) Line 1710  int flist_ndx_pop(flist_ndx_list *lp)
         return ndx;          return ndx;
 }  }
   
void *expand_item_list(item_list *lp, size_t item_size,/* Make sure there is room for one more item in the item list.  If there
                       const char *desc, int incr) * is not, expand the list as indicated by the value of "incr":
  *  - if incr < 0 then increase the malloced size by -1 * incr
  *  - if incr >= 0 then either make the malloced size equal to "incr"
  *    or (if that's not large enough) double the malloced size
  * After the size check, the list's count is incremented by 1 and a pointer
  * to the "new" list item is returned.
  */
 void *expand_item_list(item_list *lp, size_t item_size, const char *desc, int incr)
 {  {
         /* First time through, 0 <= 0, so list is expanded. */          /* First time through, 0 <= 0, so list is expanded. */
         if (lp->malloced <= lp->count) {          if (lp->malloced <= lp->count) {
                 void *new_ptr;                  void *new_ptr;
                size_t new_size = lp->malloced;                size_t expand_size;
                 if (incr < 0)                  if (incr < 0)
                        new_size += -incr; /* increase slowly */                        expand_size = -incr; /* increase slowly */
                else if (new_size < (size_t)incr)                else if (lp->malloced < (size_t)incr)
                        new_size += incr;                        expand_size = incr - lp->malloced;
                 else if (lp->malloced)
                         expand_size = lp->malloced; /* double in size */
                 else                  else
                        new_size *= 2;                        expand_size = 1;
                if (new_size < lp->malloced)                if (SIZE_MAX/item_size - expand_size < lp->malloced)
                         overflow_exit("expand_item_list");                          overflow_exit("expand_item_list");
                /* Using _realloc_array() lets us pass the size, not a type. */                expand_size += lp->malloced;
                new_ptr = _realloc_array(lp->items, item_size, new_size);                new_ptr = realloc_buf(lp->items, expand_size * item_size);
                if (verbose >= 4) {                if (DEBUG_GTE(FLIST, 3)) {
                        rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n",                        rprintf(FINFO, "[%s] expand %s to %s bytes, did%s move\n",
                                who_am_i(), desc, (double)new_size * item_size,                                who_am_i(), desc, big_num(expand_size * item_size),
                                 new_ptr == lp->items ? " not" : "");                                  new_ptr == lp->items ? " not" : "");
                 }                  }
                 if (!new_ptr)  
                         out_of_memory("expand_item_list");  
   
                 lp->items = new_ptr;                  lp->items = new_ptr;
                lp->malloced = new_size;                lp->malloced = expand_size;
         }          }
         return (char*)lp->items + (lp->count++ * item_size);          return (char*)lp->items + (lp->count++ * item_size);
   }
   
   /* This zeroing of memory won't be optimized away by the compiler. */
   void force_memzero(void *buf, size_t len)
   {
           volatile uchar *z = buf;
           while (len-- > 0)
                   *z++ = '\0';
 }  }

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>