mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
387 lines
9.8 KiB
C
387 lines
9.8 KiB
C
|
|
|
||
|
|
/*
|
||
|
|
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
|
||
|
|
*
|
||
|
|
* This program is free software; you can redistribute it and/or modify it
|
||
|
|
* under the terms of version 2 of the GNU General Public License as
|
||
|
|
* published by the Free Software Foundation.
|
||
|
|
*
|
||
|
|
* This program is distributed in the hope that it would be useful, but
|
||
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
|
*
|
||
|
|
* Further, this software is distributed without any warranty that it is
|
||
|
|
* free of the rightful claim of any third person regarding infringement
|
||
|
|
* or the like. Any license provided herein, whether implied or
|
||
|
|
* otherwise, applies only to this software file. Patent licenses, if
|
||
|
|
* any, provided herein do not apply to combinations of this program with
|
||
|
|
* other software, or any other product whatsoever.
|
||
|
|
*
|
||
|
|
* You should have received a copy of the GNU General Public License along
|
||
|
|
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||
|
|
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||
|
|
*
|
||
|
|
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
|
||
|
|
* Mountain View, CA 94043, or:
|
||
|
|
*
|
||
|
|
* http://www.sgi.com
|
||
|
|
*
|
||
|
|
* For further information regarding this notice, see:
|
||
|
|
*
|
||
|
|
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
* fill2:
|
||
|
|
* Derived from fill.c, adds command line options, block boundary marking
|
||
|
|
* and allows me to tweak to suit fill2fs without breaking other qa tests.
|
||
|
|
* This version marks block boundaries (512, 1k, 4k and 16k) within the file
|
||
|
|
* using characters guaranteed not to appear anywhere else, this may allow
|
||
|
|
* simple checks in future which can inspect these offsets and ensure one of
|
||
|
|
* of the four characters is present. Also fixes off-by-one error in fill.c
|
||
|
|
* and is more careful about checking when write operations fail - this is
|
||
|
|
* needed by fill2fs to ensure that the number of bytes written is accurately
|
||
|
|
* determined.
|
||
|
|
*
|
||
|
|
* $Id$
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
#include <libxfs.h>
|
||
|
|
#include <errno.h>
|
||
|
|
|
||
|
|
#define N(x) (sizeof(x)/sizeof(x[0]))
|
||
|
|
|
||
|
|
/* function prototypes */
|
||
|
|
static void illegal(char *, char *);
|
||
|
|
static void reqval(char, char * [], int);
|
||
|
|
static void respec(char, char * [], int);
|
||
|
|
static void unknown(char, char *);
|
||
|
|
static void usage(void);
|
||
|
|
static char *progname;
|
||
|
|
|
||
|
|
char *dopts[] = { "nbytes", "linelength", "seed", "file", NULL };
|
||
|
|
enum { D_NBYTES, D_LINELENGTH, D_SEED, D_FILE, D_ISSET, D_NUM };
|
||
|
|
int dflags[D_NUM] = { 0 };
|
||
|
|
char *bopts[] = { "512", "1k", "4k", "16k" };
|
||
|
|
enum { B_512, B_1K, B_4K, B_16K, B_ISSET, B_NUM };
|
||
|
|
int bflags[B_NUM] = { 0 };
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
* block boundaries
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
|
||
|
|
/* block boundaries which should be flagged in the output file */
|
||
|
|
/* flag is the character that should be used to indicate each type */
|
||
|
|
/* of block boundary */
|
||
|
|
|
||
|
|
|
||
|
|
struct s_block_type {
|
||
|
|
int mark;
|
||
|
|
int size;
|
||
|
|
char flag;
|
||
|
|
};
|
||
|
|
|
||
|
|
static struct s_block_type btypes[] = {
|
||
|
|
{ 0, 512, '!' }, /* 512 */
|
||
|
|
{ 0, 1024, '"' }, /* 1k */
|
||
|
|
{ 0, 4096, '#' }, /* 4k */
|
||
|
|
{ 0, 16384, '$' }, /* 16k */
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
* main
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
|
||
|
|
int
|
||
|
|
main(int argc, char **argv)
|
||
|
|
{
|
||
|
|
int status = 0; /* return status */
|
||
|
|
int c; /* current option character */
|
||
|
|
char *p; /* for getsubopt calls */
|
||
|
|
long nbytes; /* total number of bytes to write */
|
||
|
|
int dlen; /* length of normal output data line */
|
||
|
|
const char *dseed; /* input string for seeding rand */
|
||
|
|
unsigned int seed; /* seed for output data */
|
||
|
|
char *dfile; /* where to write output */
|
||
|
|
|
||
|
|
FILE *f; /* output file */
|
||
|
|
char *dbuf; /* output line buffer */
|
||
|
|
char bbuf[50]; /* block boundary string */
|
||
|
|
char *active; /* active buffer to copy out of */
|
||
|
|
size_t hlen; /* header length (bytes+key) in output */
|
||
|
|
/* lines */
|
||
|
|
char *hptr; /* pointer to end of header */
|
||
|
|
char *ptr; /* current position to copy from */
|
||
|
|
int blktype; /* current block boundary type */
|
||
|
|
int boundary; /* set if current output char lies on */
|
||
|
|
/* block boundary */
|
||
|
|
long i;
|
||
|
|
int j;
|
||
|
|
int l;
|
||
|
|
|
||
|
|
|
||
|
|
/* defaults */
|
||
|
|
progname = basename(argv[0]);
|
||
|
|
nbytes = 1024 * 1024;
|
||
|
|
dlen = 73; /* includes the trailing newline */
|
||
|
|
|
||
|
|
while ((c = getopt(argc, argv, "d:b:")) != EOF) {
|
||
|
|
switch (c) {
|
||
|
|
case 'd':
|
||
|
|
if (dflags[D_ISSET])
|
||
|
|
respec('d', NULL, 0);
|
||
|
|
dflags[D_ISSET] = 1;
|
||
|
|
|
||
|
|
p = optarg;
|
||
|
|
while (*p != '\0') {
|
||
|
|
char *value;
|
||
|
|
switch (getsubopt(&p, (constpp)dopts, &value)) {
|
||
|
|
case D_NBYTES:
|
||
|
|
if (! value) reqval('d', dopts, D_NBYTES);
|
||
|
|
if (dflags[D_NBYTES]) respec('d', dopts, D_NBYTES);
|
||
|
|
dflags[D_NBYTES] = 1;
|
||
|
|
nbytes = strtol(value, &ptr, 10);
|
||
|
|
if (ptr == value) illegal(value, "d nbytes");
|
||
|
|
break;
|
||
|
|
|
||
|
|
case D_LINELENGTH:
|
||
|
|
if (! value) reqval('d', dopts, D_LINELENGTH);
|
||
|
|
if (dflags[D_LINELENGTH]) respec('d', dopts, D_LINELENGTH);
|
||
|
|
dflags[D_LINELENGTH] = 1;
|
||
|
|
dlen = (int) strtol(value, &ptr, 10) + 1;
|
||
|
|
if (ptr == value) illegal(value, "d linelength");
|
||
|
|
break;
|
||
|
|
|
||
|
|
case D_SEED:
|
||
|
|
if (! value) reqval('d', dopts, D_SEED);
|
||
|
|
if (dflags[D_SEED]) respec('D', dopts, D_SEED);
|
||
|
|
dflags[D_SEED] = 1;
|
||
|
|
dseed = value;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case D_FILE:
|
||
|
|
if (! value) reqval('d', dopts, D_FILE);
|
||
|
|
if (dflags[D_FILE]) respec('d', dopts, D_FILE);
|
||
|
|
dflags[D_FILE] = 1;
|
||
|
|
dfile = value;
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
unknown('d', value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'b':
|
||
|
|
if (bflags[B_ISSET])
|
||
|
|
respec('b', NULL, 0);
|
||
|
|
bflags[B_ISSET] = 1;
|
||
|
|
|
||
|
|
p = optarg;
|
||
|
|
while (*p != '\0') {
|
||
|
|
char *value;
|
||
|
|
switch (getsubopt(&p, (constpp)bopts, &value)) {
|
||
|
|
case B_512:
|
||
|
|
if (value) illegal(value, "b 512");
|
||
|
|
if (bflags[B_512]) respec('b', bopts, B_512);
|
||
|
|
bflags[B_512] = 1;
|
||
|
|
btypes[0].mark = 1;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case B_1K:
|
||
|
|
if (value) illegal(value, "b 1k");
|
||
|
|
if (bflags[B_1K]) respec('b', bopts, B_1K);
|
||
|
|
bflags[B_1K] = 1;
|
||
|
|
btypes[1].mark = 1;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case B_4K:
|
||
|
|
if (value) illegal(value, "b 4k");
|
||
|
|
if (bflags[B_4K]) respec('b', bopts, B_4K);
|
||
|
|
bflags[B_4K] = 1;
|
||
|
|
btypes[2].mark = 1;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case B_16K:
|
||
|
|
if (value) illegal(value, "b 16k");
|
||
|
|
if (bflags[B_16K]) respec('b', bopts, B_16K);
|
||
|
|
bflags[B_16K] = 1;
|
||
|
|
btypes[3].mark = 1;
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
unknown('b', value);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case '?':
|
||
|
|
usage();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (dflags[D_FILE] && optind != argc)
|
||
|
|
usage();
|
||
|
|
|
||
|
|
if (! dflags[D_FILE] && argc - optind != 1)
|
||
|
|
usage();
|
||
|
|
|
||
|
|
if (! dflags[D_FILE])
|
||
|
|
dfile = argv[optind];
|
||
|
|
|
||
|
|
if ((f = fopen(dfile, "w")) == NULL) {
|
||
|
|
fprintf(stderr, "fill2: cannot create \"%s\": %s\n",
|
||
|
|
dfile, strerror(errno));
|
||
|
|
status = 1;
|
||
|
|
goto cleanup;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (! dflags[D_SEED])
|
||
|
|
dseed = dfile;
|
||
|
|
|
||
|
|
/* seed is an ascii string */
|
||
|
|
seed = 0;
|
||
|
|
i = 0;
|
||
|
|
while (dseed[i]) {
|
||
|
|
seed <<= 8;
|
||
|
|
seed |= dseed[i];
|
||
|
|
i++;
|
||
|
|
}
|
||
|
|
srand(seed);
|
||
|
|
|
||
|
|
|
||
|
|
/* normal data line format: XXXXXXXXXXXX CCCC...CCC CCCCCCCCCCCC...CCC */
|
||
|
|
/* block boundary format: CXXXXXXX */
|
||
|
|
|
||
|
|
dbuf = (char *) malloc(dlen + 1);
|
||
|
|
hlen = 12+1+strlen(dseed)+1;
|
||
|
|
assert(hlen < dlen);
|
||
|
|
hptr = dbuf + hlen;
|
||
|
|
|
||
|
|
for (i = 0; i < nbytes; i++) {
|
||
|
|
|
||
|
|
|
||
|
|
/* is this a block boundary? check largest to smallest */
|
||
|
|
boundary = 0;
|
||
|
|
for (j = N(btypes) - 1; j >= 0; j--) {
|
||
|
|
if (btypes[j].mark) {
|
||
|
|
/* first time through or just before a block boundary? */
|
||
|
|
if (i == 0 || i % btypes[j].size == btypes[j].size - 1) {
|
||
|
|
boundary = 1;
|
||
|
|
blktype = j;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/* are there block boundaries to check? */
|
||
|
|
/* is this the first time through? */
|
||
|
|
/* block boundaries take priority over other output */
|
||
|
|
if (bflags[B_ISSET] && (i == 0 || boundary)) {
|
||
|
|
sprintf(bbuf, "%s%c%07ld\n",
|
||
|
|
i ? "\n" : "",
|
||
|
|
btypes[blktype].flag,
|
||
|
|
/* remember i is one less than block boundary */
|
||
|
|
i ? (i+1) / btypes[blktype].size : 0);
|
||
|
|
active = bbuf;
|
||
|
|
ptr = bbuf;
|
||
|
|
}
|
||
|
|
/* are we at the start of a new line? */
|
||
|
|
else if (i == 0
|
||
|
|
|| (active == bbuf && *ptr == '\0')
|
||
|
|
|| (active == dbuf && l == dlen))
|
||
|
|
{
|
||
|
|
sprintf(dbuf, "%012ld %s ", i, dseed);
|
||
|
|
assert(*hptr == '\0');
|
||
|
|
for (ptr = hptr; ptr != dbuf + dlen - 1; ptr++) {
|
||
|
|
/* characters upto 126 '~' are used */
|
||
|
|
/* do not use !"#$ - leave free for use as block markers */
|
||
|
|
*ptr = 37 + (rand() % (127 - 37));
|
||
|
|
}
|
||
|
|
*ptr++ = '\n';
|
||
|
|
*ptr = '\0';
|
||
|
|
assert(ptr == dbuf + dlen);
|
||
|
|
active = dbuf;
|
||
|
|
ptr = dbuf;
|
||
|
|
l = 0;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
/* continue copying from the active buffer */
|
||
|
|
}
|
||
|
|
|
||
|
|
/* output one new character from current buffer */
|
||
|
|
if (fputc(*ptr++, f) == EOF) {
|
||
|
|
fprintf(stderr, "fill2: could not write character to \"%s\": %s\n",
|
||
|
|
dfile, strerror(errno));
|
||
|
|
status = 1;
|
||
|
|
goto cleanup;
|
||
|
|
}
|
||
|
|
if (active == dbuf) l++;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
cleanup:
|
||
|
|
|
||
|
|
/* close file and flush buffers - check if this fails */
|
||
|
|
if (fclose(f) != 0) {
|
||
|
|
fprintf(stderr, "fill2: fclose() on \"%s\" failed: %s\n",
|
||
|
|
dfile, strerror(errno));
|
||
|
|
status = 1;
|
||
|
|
}
|
||
|
|
exit(status);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
* suboption checking functions
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
|
||
|
|
static void
|
||
|
|
illegal(char *value, char *opt)
|
||
|
|
{
|
||
|
|
fprintf(stderr, "%s: Error: Illegal value \"%s\" for -%s option\n",
|
||
|
|
progname, value, opt);
|
||
|
|
usage();
|
||
|
|
}
|
||
|
|
static void
|
||
|
|
reqval(char opt, char *tab[], int idx)
|
||
|
|
{
|
||
|
|
fprintf(stderr, "%s: Error: -%c %s option requires a value\n",
|
||
|
|
progname, opt, tab[idx]);
|
||
|
|
usage();
|
||
|
|
}
|
||
|
|
static void
|
||
|
|
respec(char opt, char *tab[], int idx)
|
||
|
|
{
|
||
|
|
fprintf(stderr, "%s: Error: ", progname);
|
||
|
|
fprintf(stderr, "-%c ", opt);
|
||
|
|
if (tab) fprintf(stderr, "%s ", tab[idx]);
|
||
|
|
fprintf(stderr, "option respecified\n");
|
||
|
|
usage();
|
||
|
|
}
|
||
|
|
static void
|
||
|
|
unknown(char opt, char *s)
|
||
|
|
{
|
||
|
|
fprintf(stderr, "%s: Error: Unknown option -%c %s\n", progname, opt, s);
|
||
|
|
usage();
|
||
|
|
}
|
||
|
|
static void
|
||
|
|
usage(void)
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Usage: %s [options] filename\n"
|
||
|
|
"Options:\n"
|
||
|
|
" -d [nbytes=num,linelength=num, output data properties\n"
|
||
|
|
" seed=string,file=name]\n"
|
||
|
|
" -b [512,1k,4k,16k] where to mark block boundaries\n", progname);
|
||
|
|
exit(2);
|
||
|
|
}
|