📄 genfile.c
字号:
/* Generate a file containing some preset patterns. Print statistics for existing files. Copyright (C) 1995, 1996, 1997, 2001, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. François Pinard <pinard@iro.umontreal.ca>, 1995. Sergey Poznyakoff <gray@mirddin.farlep.net>, 2004, 2005, 2006, 2007, 2008. 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 the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/#include <system.h>#include <signal.h>#include <stdarg.h>#include <argmatch.h>#include <argp.h>#include <argcv.h>#include <getdate.h>#include <utimens.h>#include <inttostr.h>#include <fcntl.h>#include <sys/stat.h>#define obstack_chunk_alloc malloc#define obstack_chunk_free free#include <obstack.h>#ifndef EXIT_SUCCESS# define EXIT_SUCCESS 0#endif#ifndef EXIT_FAILURE# define EXIT_FAILURE 1#endif#if ! defined SIGCHLD && defined SIGCLD# define SIGCHLD SIGCLD#endifenum pattern{ DEFAULT_PATTERN, ZEROS_PATTERN};/* The name this program was run with. */const char *program_name;/* Name of file to generate */static char *file_name;/* Name of the file-list file: */static char *files_from;static char filename_terminator = '\n';/* Length of file to generate. */static off_t file_length = 0;static off_t seek_offset = 0;/* Pattern to generate. */static enum pattern pattern = DEFAULT_PATTERN;/* Next checkpoint number */size_t checkpoint;enum genfile_mode { mode_generate, mode_sparse, mode_stat, mode_exec };enum genfile_mode mode = mode_generate;#define DEFAULT_STAT_FORMAT \ "name,dev,ino,mode,nlink,uid,gid,size,blksize,blocks,atime,mtime,ctime"/* Format for --stat option */static char *stat_format = DEFAULT_STAT_FORMAT;/* Size of a block for sparse file */size_t block_size = 512;/* Block buffer for sparse file */char *buffer;/* Number of arguments and argument vector for mode == mode_exec */int exec_argc;char **exec_argv;/* Time for --touch option */struct timespec touch_time;/* Verbose mode */int verbose;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""OPTIONS are:\n");#define OPT_CHECKPOINT 256#define OPT_TOUCH 257#define OPT_APPEND 258#define OPT_TRUNCATE 259#define OPT_EXEC 260#define OPT_DATE 261#define OPT_VERBOSE 262#define OPT_SEEK 263static struct argp_option options[] = {#define GRP 0 {NULL, 0, NULL, 0, N_("File creation options:"), GRP}, {"length", 'l', N_("SIZE"), 0, N_("Create file of the given SIZE"), GRP+1 }, {"file", 'f', N_("NAME"), 0, N_("Write to file NAME, instead of standard output"), GRP+1}, {"files-from", 'T', N_("FILE"), 0, N_("Read file names from FILE"), GRP+1}, {"null", '0', NULL, 0, N_("-T reads null-terminated names"), GRP+1}, {"pattern", 'p', N_("PATTERN"), 0, N_("Fill the file with the given PATTERN. PATTERN is 'default' or 'zeros'"), GRP+1 }, {"block-size", 'b', N_("SIZE"), 0, N_("Size of a block for sparse file"), GRP+1}, {"sparse", 's', NULL, 0, N_("Generate sparse file. Rest of the command line gives the file map."), GRP+1 }, {"seek", OPT_SEEK, N_("OFFSET"), 0, N_("Seek to the given offset before writing data"), GRP+1 },#undef GRP#define GRP 10 {NULL, 0, NULL, 0, N_("File statistics options:"), GRP}, {"stat", 'S', N_("FORMAT"), OPTION_ARG_OPTIONAL, N_("Print contents of struct stat for each given file. Default FORMAT is: ") DEFAULT_STAT_FORMAT, GRP+1 },#undef GRP#define GRP 20 {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"), GRP+1 }, {"checkpoint", OPT_CHECKPOINT, N_("NUMBER"), 0, N_("Perform given action (see below) upon reaching checkpoint NUMBER"), GRP+1 }, {"date", OPT_DATE, N_("STRING"), 0, N_("Set date for next --touch option"), GRP+1 }, {"verbose", OPT_VERBOSE, NULL, 0, N_("Display executed checkpoints and exit status of COMMAND"), GRP+1 },#undef GRP#define GRP 30 {NULL, 0, NULL, 0, N_("Synchronous execution actions. These are executed when checkpoint number given by --checkpoint option is reached."), GRP}, {"cut", OPT_TRUNCATE, N_("FILE"), 0, N_("Truncate FILE to the size specified by previous --length option (or 0, if it is not given)"), GRP+1 }, {"truncate", 0, NULL, OPTION_ALIAS, NULL, GRP+1 }, {"append", OPT_APPEND, N_("FILE"), 0, N_("Append SIZE bytes to FILE. SIZE is given by previous --length option."), GRP+1 }, {"touch", OPT_TOUCH, N_("FILE"), 0, N_("Update the access and modification times of FILE"), GRP+1 }, {"exec", OPT_EXEC, N_("COMMAND"), 0, N_("Execute COMMAND"), GRP+1 },#undef GRP { NULL, }};static char const * const pattern_args[] = { "default", "zeros", 0 };static enum pattern const pattern_types[] = {DEFAULT_PATTERN, ZEROS_PATTERN};static intxlat_suffix (off_t *vp, const char *p){ off_t val = *vp; if (p[1]) return 1; switch (p[0]) { case 'g': case 'G': *vp *= 1024; case 'm': case 'M': *vp *= 1024; case 'k': case 'K': *vp *= 1024; break; default: return 1; } return *vp <= val;}static off_tget_size (const char *str, int allow_zero){ const char *p; off_t v = 0; for (p = str; *p; p++) { int digit = *p - '0'; off_t x = v * 10; if (9 < (unsigned) digit) { if (xlat_suffix (&v, p)) error (EXIT_FAILURE, 0, _("Invalid size: %s"), str); else break; } else if (x / 10 != v) error (EXIT_FAILURE, 0, _("Number out of allowed range: %s"), str); v = x + digit; if (v < 0) error (EXIT_FAILURE, 0, _("Negative size: %s"), str); } return v;}voidverify_file (char *file_name){ if (file_name) { struct stat st; if (stat (file_name, &st)) error (0, errno, _("stat(%s) failed"), file_name); if (st.st_size != file_length + seek_offset) { printf ("%lu %lu\n", (unsigned long)st.st_size , (unsigned long)file_length); exit (1); } if (mode == mode_sparse && !ST_IS_SPARSE (st)) exit (1); }}struct action{ struct action *next; size_t checkpoint; int action; char *name; off_t size; enum pattern pattern; struct timespec ts;};static struct action *action_list;voidreg_action (int action, char *arg){ struct action *act = xmalloc (sizeof (*act)); act->checkpoint = checkpoint; act->action = action; act->pattern = pattern; act->ts = touch_time; act->size = file_length; act->name = arg; act->next = action_list; action_list = act;}static error_tparse_opt (int key, char *arg, struct argp_state *state){ switch (key) { case '0': filename_terminator = 0; break; case 'f': file_name = arg; break; case 'l': file_length = get_size (arg, 1); break; case 'p': pattern = XARGMATCH ("--pattern", arg, pattern_args, pattern_types); break; case 'b': block_size = get_size (arg, 0); break; case 's': mode = mode_sparse; break; case 'S': mode = mode_stat; if (arg) stat_format = arg; break; case 'r': mode = mode_exec; argcv_get (arg, "", NULL, &exec_argc, &exec_argv); break; case 'T': files_from = arg; break; case OPT_SEEK: seek_offset = get_size (arg, 0); break; case OPT_CHECKPOINT: { char *p; checkpoint = strtoul (arg, &p, 0); if (*p) argp_error (state, _("Error parsing number near `%s'"), p); } break; case OPT_DATE: if (!get_date (&touch_time, arg, NULL)) argp_error (state, _("Unknown date format")); break; case OPT_APPEND: case OPT_TRUNCATE: case OPT_TOUCH: case OPT_EXEC: reg_action (key, arg); break; case OPT_VERBOSE: verbose++; break; default: return ARGP_ERR_UNKNOWN; } return 0;}static struct argp argp = { options, parse_opt, N_("[ARGS...]"), doc, NULL, NULL, NULL};voidfill (FILE *fp, off_t length, enum pattern pattern){ off_t i; switch (pattern) { case DEFAULT_PATTERN: for (i = 0; i < length; i++) fputc (i & 255, fp); break; case ZEROS_PATTERN: for (i = 0; i < length; i++) fputc (0, fp); break; }}/* Generate Mode: usual files */static voidgenerate_simple_file (char *filename){ FILE *fp; if (filename) { fp = fopen (filename, seek_offset ? "rb+" : "wb"); if (!fp) error (EXIT_FAILURE, errno, _("cannot open `%s'"), filename); } else fp = stdout; if (fseeko (fp, seek_offset, 0)) error (EXIT_FAILURE, errno, "%s", _("cannot seek")); fill (fp, file_length, pattern); fclose (fp);}/* A simplified version of the same function from tar */intread_name_from_file (FILE *fp, struct obstack *stk){ int c; size_t counter = 0; for (c = getc (fp); c != EOF && c != filename_terminator; c = getc (fp)) { if (c == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -