From befdaa92d2c6ea36d6c3900b3882e7bf89934fb6 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Sat, 4 Mar 2017 21:06:10 +0100 Subject: ripe-atlas-fw: imported version 4760 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- coreutils/condmv.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 252 insertions(+), 9 deletions(-) (limited to 'coreutils/condmv.c') diff --git a/coreutils/condmv.c b/coreutils/condmv.c index 0139779..2fd976f 100644 --- a/coreutils/condmv.c +++ b/coreutils/condmv.c @@ -6,23 +6,36 @@ #include "libbb.h" -#define SAFE_PREFIX_FROM ATLAS_DATA_NEW -#define SAFE_PREFIX_TO ATLAS_DATA_OUT +#define SAFE_PREFIX_FROM1 ATLAS_DATA_NEW +#define SAFE_PREFIX_FROM2 ATLAS_DATA_OUT +#define SAFE_PREFIX_TO1 ATLAS_DATA_OUT +#define SAFE_PREFIX_TO2 ATLAS_DATA_STORAGE #define A_FLAG (1 << 0) -#define F_FLAG (1 << 1) +#define a_FLAG (1 << 1) +#define D_FLAG (1 << 2) +#define f_FLAG (1 << 3) +#define t_FLAG (1 << 4) +#define x_FLAG (1 << 5) + +static time_t age_value; +static int cross_filesystems, append_timestamp; + +static int do_dir(char *from_dir, char *to_dir); +static int do_cprm(char *from_file, char *to_file); int condmv_main(int argc, char *argv[]) { - char *opt_add, *from, *to; + char *opt_add, *opt_age, *from, *to, *check; uint32_t opt; struct stat sb; FILE *file; time_t mytime; opt_add= NULL; + opt_age= NULL; opt_complementary= NULL; /* For when we are called by crond */ - opt= getopt32(argv, "!A:f", &opt_add); + opt= getopt32(argv, "!A:a:Dftx", &opt_add, &opt_age); if (opt == (uint32_t)-1) { @@ -39,19 +52,41 @@ int condmv_main(int argc, char *argv[]) from= argv[optind]; to= argv[optind+1]; - if (!validate_filename(from, SAFE_PREFIX_FROM)) + if (!validate_filename(from, SAFE_PREFIX_FROM1) && + !validate_filename(from, SAFE_PREFIX_FROM2)) { fprintf(stderr, "insecure from file '%s'\n", from); return 1; } - if (!validate_filename(to, SAFE_PREFIX_TO) && - !validate_filename(to, SAFE_PREFIX_FROM)) + if (!validate_filename(to, SAFE_PREFIX_TO1) && + !validate_filename(to, SAFE_PREFIX_TO2) && + !validate_filename(to, SAFE_PREFIX_FROM1)) { fprintf(stderr, "insecure to file '%s'\n", to); return 1; } - if (stat(to, &sb) == 0 && !(opt & F_FLAG)) + if (opt_age) + { + age_value= strtol(opt_age, &check, 0); + if (check[0] != '\0' || age_value <= 0) + { + fprintf(stderr, "bad age value '%s'\n", opt_age); + return 1; + } + } + else + age_value= 0; + + cross_filesystems= !!(opt & x_FLAG); + append_timestamp= !!(opt & t_FLAG); + + if (opt & D_FLAG) + { + return do_dir(from, to); + } + + if (stat(to, &sb) == 0 && !(opt & f_FLAG)) { /* Destination exists */ fprintf(stderr, "condmv: not moving, destination '%s' exists\n", @@ -98,3 +133,211 @@ int condmv_main(int argc, char *argv[]) return 0; } + +static int do_dir(char *from_dir, char *to_dir) +{ + int r, error; + size_t len, extra_len; + time_t now; + DIR *dir; + struct dirent *de; + char *from_file, *new_from_file; + char *to_file, *new_to_file; + size_t from_file_len, to_file_len; + struct stat sb; + + from_file= NULL; + from_file_len= 0; + to_file= NULL; + to_file_len= 0; + + dir= opendir(from_dir); + if (dir == NULL) + { + fprintf(stderr, "condmv: unable to open dir '%s': %s\n", + from_dir, strerror(errno)); + return 1; + } + + now= time (NULL); /* For age_value */ + + error= 0; /* Assume no failures */ + while (de= readdir(dir), de != NULL) + { + len= strlen(from_dir) + 1 + strlen(de->d_name) + 1; + if (len > from_file_len) + { + new_from_file= realloc(from_file, len); + if (new_from_file == NULL) + { + fprintf(stderr, + "condmv: out of memory (from_file)\n"); + error= 1; + break; + } + from_file= new_from_file; new_from_file= NULL; + from_file_len= len; + } + snprintf(from_file, from_file_len, "%s/%s", + from_dir, de->d_name); + r= stat(from_file, &sb); + if (r == -1) + { + fprintf(stderr, "condmv: stat %s failed: %sn", + from_file, strerror(errno)); + error= 1; + break; + } + if (!S_ISREG(sb.st_mode)) + { + /* Skip non-regular objects */ + continue; + } + + if (age_value) + { + if (sb.st_mtime + age_value > now) + continue; + } + + if (append_timestamp) + { + /* A unix timestamp is currently 10 characters. + * Allocate an extra 16 characters to have enough + * space, also for the separator. + */ + extra_len= 16; + } + else + extra_len= 0; + len= strlen(to_dir) + 1 + strlen(de->d_name) + extra_len + 1; + if (len > to_file_len) + { + new_to_file= realloc(to_file, len); + if (new_to_file == NULL) + { + fprintf(stderr, + "condmv: out of memory (to_file)\n"); + error= 1; + break; + } + to_file= new_to_file; new_to_file= NULL; + to_file_len= len; + } + if (append_timestamp) + { + snprintf(to_file, to_file_len, "%s/%s.%lu", + to_dir, de->d_name, (unsigned long)now); + } + else + { + snprintf(to_file, to_file_len, "%s/%s", + to_dir, de->d_name); + } + + /* Make sure to_file doesn't exist */ + r= stat(to_file, &sb); + if (r == 0 || (r == -1 && errno != ENOENT)) + { + /* Something wrong with to_file */ + continue; + } + + if (cross_filesystems) + { + r= do_cprm(from_file, to_file); + if (r == 0) + { + /* Okay, next one */ + continue; + } + error= 1; + break; + } + + r= rename(from_file, to_file); + if (r == -1) + { + fprintf(stderr, + "condmv: rename %s to %s failed: %s\n", + from_file, to_file, strerror(errno)); + error= 1; + break; + } + } + + closedir(dir); + + if (from_file) + { + free(from_file); + from_file= NULL; + } + if (to_file) + { + free(to_file); + to_file= NULL; + } + + return error; +} + +static int do_cprm(char *from_file, char *to_file) +{ + FILE *fp_in, *fp_out; + size_t len_in, len_out; + char buf[1024]; + + fp_in= fopen(from_file, "rb"); + if (fp_in == NULL) + { + fprintf(stderr, "condmv: cannot open '%s' for reading: %s\n", + from_file, strerror(errno)); + return 1; + } + + fp_out= fopen(to_file, "wb"); + if (fp_out == NULL) + { + fprintf(stderr, "condmv: cannot open '%s' for writing: %s\n", + to_file, strerror(errno)); + fclose(fp_in); fp_in= NULL; + return 1; + } + + for (;;) + { + len_in= fread(buf, 1, sizeof(buf), fp_in); + if (len_in == 0) + break; /* EOF or error */ + + len_out= fwrite(buf, 1, len_in, fp_out); + if (len_out != len_in) + { + fprintf(stderr, + "condmv: error writing to '%s': %s\n", + to_file, strerror(errno)); + fclose(fp_in); fp_in= NULL; + fclose(fp_out); fp_out= NULL; + unlink(to_file); + return 1; + } + } + + if (ferror(fp_in)) + { + fprintf(stderr, + "condmv: error reading from '%s': %s\n", + from_file, strerror(errno)); + fclose(fp_in); fp_in= NULL; + fclose(fp_out); fp_out= NULL; + unlink(to_file); + return 1; + } + + fclose(fp_in); fp_in= NULL; + fclose(fp_out); fp_out= NULL; + unlink(from_file); + + return 0; +} -- cgit v1.2.3