version 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 same | int 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'; |
} |
} |