X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=tests%2Fgenfile.c;h=219fb5e9ed90d702674c74cac6956dc4a0d11d0d;hb=HEAD;hp=1b338bce2f95a77635abe7f7f6926b53802d4395;hpb=d3daaa199aca7497bb507f92b693c8457353f96a;p=debian%2Ftar diff --git a/tests/genfile.c b/tests/genfile.c index 1b338bce..219fb5e9 100644 --- a/tests/genfile.c +++ b/tests/genfile.c @@ -2,7 +2,7 @@ Print statistics for existing files. Copyright (C) 1995, 1996, 1997, 2001, 2003, 2004, 2005, 2006, 2007, - 2008 Free Software Foundation, Inc. + 2008, 2009, 2016 Free Software Foundation, Inc. François Pinard , 1995. Sergey Poznyakoff , 2004, 2005, 2006, 2007, 2008. @@ -28,11 +28,11 @@ #include #include #include -#include -#include +#include #include #include #include +#include #define obstack_chunk_alloc malloc #define obstack_chunk_free free #include @@ -99,6 +99,7 @@ char *buffer; /* Number of arguments and argument vector for mode == mode_exec */ int exec_argc; char **exec_argv; +char *checkpoint_option; /* Time for --touch option */ struct timespec touch_time; @@ -106,6 +107,9 @@ struct timespec touch_time; /* Verbose mode */ int verbose; +/* Quiet mode */ +int quiet; + const char *argp_program_version = "genfile (" PACKAGE ") " VERSION; const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; static char doc[] = N_("genfile manipulates data files for GNU paxutils test suite.\n" @@ -119,6 +123,7 @@ static char doc[] = N_("genfile manipulates data files for GNU paxutils test sui #define OPT_DATE 261 #define OPT_VERBOSE 262 #define OPT_SEEK 263 +#define OPT_UNLINK 264 static struct argp_option options[] = { #define GRP 0 @@ -143,7 +148,8 @@ static struct argp_option options[] = { {"seek", OPT_SEEK, N_("OFFSET"), 0, N_("Seek to the given offset before writing data"), GRP+1 }, - + {"quiet", 'q', NULL, 0, + N_("Suppress non-fatal diagnostic messages") }, #undef GRP #define GRP 10 {NULL, 0, NULL, 0, @@ -159,8 +165,8 @@ static struct argp_option options[] = { {NULL, 0, NULL, 0, N_("Synchronous execution options:"), GRP}, - {"run", 'r', N_("COMMAND"), 0, - N_("Execute given COMMAND. Useful with --checkpoint and one of --cut, --append, --touch"), + {"run", 'r', N_("OPTION"), OPTION_ARG_OPTIONAL, + N_("Execute ARGS. Useful with --checkpoint and one of --cut, --append, --touch, --unlink"), GRP+1 }, {"checkpoint", OPT_CHECKPOINT, N_("NUMBER"), 0, N_("Perform given action (see below) upon reaching checkpoint NUMBER"), @@ -189,6 +195,9 @@ static struct argp_option options[] = { {"exec", OPT_EXEC, N_("COMMAND"), 0, N_("Execute COMMAND"), GRP+1 }, + {"unlink", OPT_UNLINK, N_("FILE"), 0, + N_("Unlink FILE"), + GRP+1 }, #undef GRP { NULL, } }; @@ -261,11 +270,11 @@ verify_file (char *file_name) error (0, errno, _("stat(%s) failed"), file_name); if (st.st_size != file_length + seek_offset) - error (1, 0, _("requested file length %lu, actual %lu"), + error (EXIT_FAILURE, 0, _("requested file length %lu, actual %lu"), (unsigned long)st.st_size, (unsigned long)file_length); - if (mode == mode_sparse && !ST_IS_SPARSE (st)) - error (1, 0, _("created file is not sparse")); + if (!quiet && mode == mode_sparse && !ST_IS_SPARSE (st)) + error (EXIT_FAILURE, 0, _("created file is not sparse")); } } @@ -321,6 +330,10 @@ parse_opt (int key, char *arg, struct argp_state *state) block_size = get_size (arg, 0); break; + case 'q': + quiet = 1; + break; + case 's': mode = mode_sparse; break; @@ -333,7 +346,11 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'r': mode = mode_exec; - argcv_get (arg, "", NULL, &exec_argc, &exec_argv); + if (arg) + { + argcv_get (arg, "", NULL, &exec_argc, &exec_argv); + checkpoint_option = "--checkpoint"; + } break; case 'T': @@ -355,7 +372,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case OPT_DATE: - if (!get_date (&touch_time, arg, NULL)) + if (! parse_datetime (&touch_time, arg, NULL)) argp_error (state, _("Unknown date format")); break; @@ -363,6 +380,7 @@ parse_opt (int key, char *arg, struct argp_state *state) case OPT_TRUNCATE: case OPT_TOUCH: case OPT_EXEC: + case OPT_UNLINK: reg_action (key, arg); break; @@ -476,9 +494,11 @@ generate_files_from_list () static void mkhole (int fd, off_t displ) { - if (lseek (fd, displ, SEEK_CUR) == -1) + off_t offset = lseek (fd, displ, SEEK_CUR); + if (offset < 0) error (EXIT_FAILURE, errno, "lseek"); - ftruncate (fd, lseek (fd, 0, SEEK_CUR)); + if (ftruncate (fd, offset) != 0) + error (EXIT_FAILURE, errno, "ftruncate"); } static void @@ -495,10 +515,56 @@ mksparse (int fd, off_t displ, char *marks) } } +static int +make_fragment (int fd, char *offstr, char *mapstr) +{ + int i; + off_t displ = get_size (offstr, 1); + + file_length += displ; + + if (!mapstr || !*mapstr) + { + mkhole (fd, displ); + return 1; + } + else if (*mapstr == '=') + { + off_t n = get_size (mapstr + 1, 1); + + switch (pattern) + { + case DEFAULT_PATTERN: + for (i = 0; i < block_size; i++) + buffer[i] = i & 255; + break; + + case ZEROS_PATTERN: + memset (buffer, 0, block_size); + break; + } + + if (lseek (fd, displ, SEEK_CUR) == -1) + error (EXIT_FAILURE, errno, "lseek"); + + for (; n; n--) + { + if (write (fd, buffer, block_size) != block_size) + error (EXIT_FAILURE, errno, "write"); + file_length += block_size; + } + } + else + { + file_length += block_size * strlen (mapstr); + mksparse (fd, displ, mapstr); + } + return 0; +} + static void generate_sparse_file (int argc, char **argv) { - int i; int fd; int flags = O_CREAT | O_RDWR | O_BINARY; @@ -515,20 +581,33 @@ generate_sparse_file (int argc, char **argv) file_length = 0; - for (i = 0; i < argc; i += 2) + while (argc) { - off_t displ = get_size (argv[i], 1); - file_length += displ; - - if (i == argc-1) + if (argv[0][0] == '-' && argv[0][1] == 0) { - mkhole (fd, displ); - break; + char buf[256]; + while (fgets (buf, sizeof (buf), stdin)) + { + size_t n = strlen (buf); + + while (n > 0 && c_isspace (buf[n-1])) + buf[--n] = 0; + + n = strcspn (buf, " \t"); + buf[n++] = 0; + while (buf[n] && c_isblank (buf[n])) + ++n; + make_fragment (fd, buf, buf + n); + } + ++argv; + --argc; } else { - file_length += block_size * strlen (argv[i+1]); - mksparse (fd, displ, argv[i+1]); + if (make_fragment (fd, argv[0], argv[1])) + break; + argc -= 2; + argv += 2; } } @@ -572,13 +651,13 @@ print_stat (const char *name) printf ("%lu", (unsigned long) st.st_ino); else if (strncmp (p, "mode", 4) == 0) { - mode_t mask = ~0; + unsigned val = st.st_mode; - if (ispunct (p[4])) + if (ispunct ((unsigned char) p[4])) { char *q; - mask = strtoul (p + 5, &q, 8); + val &= strtoul (p + 5, &q, 8); if (*q) { printf ("\n"); @@ -590,7 +669,7 @@ print_stat (const char *name) printf ("\n"); error (EXIT_FAILURE, 0, _("Unknown field `%s'"), p); } - printf ("%0o", st.st_mode & mask); + printf ("%0o", val); } else if (strcmp (p, "nlink") == 0) printf ("%lu", (unsigned long) st.st_nlink); @@ -646,7 +725,7 @@ exec_checkpoint (struct action *p) struct timespec ts[2]; ts[0] = ts[1] = p->ts; - if (utimens (p->name, ts) != 0) + if (utimensat (AT_FDCWD, p->name, ts, 0) != 0) { error (0, errno, _("cannot set time on `%s'"), p->name); break; @@ -676,13 +755,23 @@ exec_checkpoint (struct action *p) error (0, errno, _("cannot open `%s'"), p->name); break; } - ftruncate (fd, p->size); + if (ftruncate (fd, p->size) != 0) + { + error (0, errno, _("cannot truncate `%s'"), p->name); + break; + } close (fd); } break; case OPT_EXEC: - system (p->name); + if (system (p->name) != 0) + error (0, 0, _("command failed: %s"), p->name); + break; + + case OPT_UNLINK: + if (unlink (p->name)) + error (0, errno, _("cannot unlink `%s'"), p->name); break; default: @@ -730,18 +819,25 @@ exec_command (void) /* Insert --checkpoint option. FIXME: This assumes that exec_argv does not use traditional tar options - (without dash) */ - exec_argc++; - exec_argv = xrealloc (exec_argv, (exec_argc + 1) * sizeof (*exec_argv)); - memmove (exec_argv+2, exec_argv+1, (exec_argc - 1) * sizeof (*exec_argv)); - exec_argv[1] = "--checkpoint"; + (without dash). + FIXME: There is no way to set checkpoint argument (granularity). + */ + if (checkpoint_option) + { + exec_argc++; + exec_argv = xrealloc (exec_argv, (exec_argc + 1) * sizeof (*exec_argv)); + memmove (exec_argv+2, exec_argv+1, + (exec_argc - 1) * sizeof (*exec_argv)); + exec_argv[1] = checkpoint_option; + } #ifdef SIGCHLD /* System V fork+wait does not work if SIGCHLD is ignored. */ signal (SIGCHLD, SIG_DFL); #endif - pipe (fd); + if (pipe (fd) != 0) + error (EXIT_FAILURE, errno, "pipe"); pid = fork (); if (pid == -1) @@ -760,7 +856,7 @@ exec_command (void) setenv ("LC_ALL", "POSIX", 1); execvp (exec_argv[0], exec_argv); - error (EXIT_FAILURE, errno, "execvp"); + error (EXIT_FAILURE, errno, "execvp %s", exec_argv[0]); } /* Master */ @@ -771,12 +867,12 @@ exec_command (void) while ((p = fgets (buf, sizeof buf, fp))) { - while (*p && !isspace (*p) && *p != ':') + while (*p && !isspace ((unsigned char) *p) && *p != ':') p++; if (*p == ':') { - for (p++; *p && isspace (*p); p++) + for (p++; *p && isspace ((unsigned char) *p); p++) ; if (*p @@ -784,7 +880,7 @@ exec_command (void) { char *end; size_t n = strtoul (p + sizeof CHECKPOINT_TEXT - 1, &end, 10); - if (!(*end && !isspace (*end))) + if (!(*end && !isspace ((unsigned char) *end))) { process_checkpoint (n); continue; @@ -834,7 +930,7 @@ main (int argc, char **argv) bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); - get_date (&touch_time, "now", NULL); + parse_datetime (&touch_time, "now", NULL); /* Decode command options. */ @@ -872,6 +968,13 @@ main (int argc, char **argv) break; case mode_exec: + if (!checkpoint_option) + { + exec_argc = argc; + exec_argv = argv; + } + else if (argc) + error (EXIT_FAILURE, 0, _("too many arguments")); exec_command (); break;