summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2014-11-07 11:37:33 +0200
committerSergey Poznyakoff <gray@gnu.org>2014-11-07 11:43:42 +0200
commit45af1632aa64a5ba1b108e248920e67c180e8485 (patch)
tree7155302a54ddc140882612178fde753000c5e60b
parent02e1fb17d864f2658ab14353e0bd026949c9f8a4 (diff)
downloadpaxutils-45af1632aa64a5ba1b108e248920e67c180e8485.tar.gz
genfile: improve sparse mode
* tests/genfile.c (generate_sparse_file): Handle '-' argument (read from stdin); If content strings starts with '=', treat it as fragment size and use default pattern to fill it. * doc/genfile.texi: Document changes to genfile.
-rw-r--r--doc/genfile.texi33
-rw-r--r--tests/genfile.c79
2 files changed, 92 insertions, 20 deletions
diff --git a/doc/genfile.texi b/doc/genfile.texi
index e0f4e35..bd2e505 100644
--- a/doc/genfile.texi
+++ b/doc/genfile.texi
@@ -124,9 +124,8 @@ the rest of the command line specifies a so-called @dfn{file map}.
descriptors}. Each descriptor is composed of two values: a number,
specifying fragment offset from the end of the previous fragment or,
for the very first fragment, from the beginning of the file, and
-@dfn{contents string}, i.e., a string of characters, specifying the
-pattern to fill the fragment with. File offset can be suffixed with
-the following quantifiers:
+@dfn{contents string}, that specifies the pattern to fill the fragment
+with. File offset can be suffixed with the following quantifiers:
@table @samp
@item k
@@ -140,17 +139,29 @@ The number is expressed in megabytes.
The number is expressed in gigabytes.
@end table
- For each letter in contents string @command{genfile} will generate
-a @dfn{block} of data, filled with this letter and will write it to
-the fragment. The size of block is given by @option{--block-size}
-option. It defaults to 512. Thus, if the string consists of @var{n}
-characters, the resulting file fragment will contain
-@code{@var{n}*@var{block-size}} of data.
-
- Last fragment descriptor can have only file offset part. In this
+ Contents string can be either a fragment size or a pattern.
+Fragment size is a decimal number, prefixed with an equals sign. It
+can be suffixed with a quantifier, as discussed above. If fragment
+size is given, the fragment of that size will be filled with the
+currently selected pattern (@pxref{Generate Mode, --pattern}) and
+written to the file.
+
+ A pattern is a string of arbitrary ASCII characters. For each
+of them, @command{genfile} will generate a @dfn{block} of data,
+filled with that character and will write it to the fragment. The size
+of block is given by @option{--block-size} option. It defaults to 512.
+Thus, if pattern consists of @var{n} characters, the resulting file
+fragment will contain @code{@var{n}*@var{block-size}} bytes of data.
+
+ The last fragment descriptor can have only file offset part. In this
case @command{genfile} will create a hole at the end of the file up to
the given offset.
+ A dash appearing as a fragment descriptor instructs
+@command{genfile} to read file map from the standard input. Each line
+of input should consist of fragment offset and contents string,
+separated by any amount of whitespace.
+
For example, consider the following invocation:
@smallexample
diff --git a/tests/genfile.c b/tests/genfile.c
index fa480ef..d41336b 100644
--- a/tests/genfile.c
+++ b/tests/genfile.c
@@ -32,6 +32,7 @@
#include <inttostr.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <c-ctype.h>
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
#include <obstack.h>
@@ -506,6 +507,53 @@ 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)
{
@@ -526,20 +574,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;
}
}