summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2008-06-21 02:20:20 +0000
committerkientzle <kientzle@FreeBSD.org>2008-06-21 02:20:20 +0000
commit9254f3ae51d2393c6c949dd0df66da7390fb9b0e (patch)
tree2261941fea24abe81097c5b38c9d9c251c575253
parent93b5d5e1a904f166be427a7592aaf206581b09a9 (diff)
downloadFreeBSD-src-9254f3ae51d2393c6c949dd0df66da7390fb9b0e.zip
FreeBSD-src-9254f3ae51d2393c6c949dd0df66da7390fb9b0e.tar.gz
Rework line-processing framework to add support for --null and
to eliminate a callback.
-rw-r--r--usr.bin/cpio/cmdline.c3
-rw-r--r--usr.bin/cpio/cpio.c168
-rw-r--r--usr.bin/cpio/cpio.h10
-rw-r--r--usr.bin/cpio/matching.c11
4 files changed, 130 insertions, 62 deletions
diff --git a/usr.bin/cpio/cmdline.c b/usr.bin/cpio/cmdline.c
index 81912e9..29183f1 100644
--- a/usr.bin/cpio/cmdline.c
+++ b/usr.bin/cpio/cmdline.c
@@ -66,7 +66,7 @@ struct option {
*/
-static const char *cpio_opts = "AaBC:F:O:cdE:f:H:hijLlmopR:rtuvW:yZz";
+static const char *cpio_opts = "0AaBC:F:O:cdE:f:H:hijLlmopR:rtuvW:yZz";
/*
* On systems that lack getopt_long, long options can be specified
@@ -91,6 +91,7 @@ static const struct option cpio_longopts[] = {
{ "link", no_argument, NULL, 'l' },
{ "list", no_argument, NULL, 't' },
{ "make-directories", no_argument, NULL, 'd' },
+ { "null", no_argument, NULL, '0' },
{ "owner", required_argument, NULL, 'R' },
{ "pass-through", no_argument, NULL, 'p' },
{ "preserve-modification-time", no_argument, NULL, 'm' },
diff --git a/usr.bin/cpio/cpio.c b/usr.bin/cpio/cpio.c
index 1d78ce1..715fb95 100644
--- a/usr.bin/cpio/cpio.c
+++ b/usr.bin/cpio/cpio.c
@@ -101,6 +101,7 @@ main(int argc, char *argv[])
cpio->gid_override = -1;
cpio->argv = argv;
cpio->argc = argc;
+ cpio->line_separator = '\n';
cpio->mode = '\0';
cpio->verbose = 0;
cpio->compress = '\0';
@@ -116,6 +117,9 @@ main(int argc, char *argv[])
while ((opt = cpio_getopt(cpio)) != -1) {
switch (opt) {
+ case '0': /* GNU convention: --null, -0 */
+ cpio->line_separator = '\0';
+ break;
case 'A': /* NetBSD/OpenBSD */
cpio->option_append = 1;
break;
@@ -341,8 +345,10 @@ version(void)
static void
mode_out(struct cpio *cpio)
{
- struct archive_entry *entry, *spare;
unsigned long blocks;
+ struct archive_entry *entry, *spare;
+ struct line_reader *lr;
+ const char *p;
int r;
if (cpio->option_append)
@@ -375,7 +381,10 @@ mode_out(struct cpio *cpio)
r = archive_write_open_file(cpio->archive, cpio->filename);
if (r != ARCHIVE_OK)
cpio_errc(1, 0, archive_error_string(cpio->archive));
- process_lines(cpio, "-", file_to_archive);
+ lr = process_lines_init("-", cpio->line_separator);
+ while ((p = process_lines_next(lr)) != NULL)
+ file_to_archive(cpio, p);
+ process_lines_free(lr);
/*
* The hardlink detection may have queued up a couple of entries
@@ -793,6 +802,8 @@ mode_list(struct cpio *cpio)
static void
mode_pass(struct cpio *cpio, const char *destdir)
{
+ struct line_reader *lr;
+ const char *p;
int r;
/* Ensure target dir has a trailing '/' to simplify path surgery. */
@@ -809,7 +820,10 @@ mode_pass(struct cpio *cpio, const char *destdir)
cpio_errc(1, 0, archive_error_string(cpio->archive));
cpio->linkresolver = archive_entry_linkresolver_new();
archive_write_disk_set_standard_lookup(cpio->archive);
- process_lines(cpio, "-", file_to_archive);
+ lr = process_lines_init("-", cpio->line_separator);
+ while ((p = process_lines_next(lr)) != NULL)
+ file_to_archive(cpio, p);
+ process_lines_free(lr);
archive_entry_linkresolver_free(cpio->linkresolver);
r = archive_write_close(cpio->archive);
@@ -868,79 +882,119 @@ cpio_rename(const char *name)
* terminated with newlines.
*
* This uses a self-sizing buffer to handle arbitrarily-long lines.
- * If the "process" function returns non-zero for any line, this
- * function will return non-zero after attempting to process all
- * remaining lines.
*/
-int
-process_lines(struct cpio *cpio, const char *pathname,
- int (*process)(struct cpio *, const char *))
-{
+struct line_reader {
FILE *f;
char *buff, *buff_end, *line_start, *line_end, *p;
- size_t buff_length, bytes_read, bytes_wanted;
+ char *pathname;
+ size_t buff_length;
int separator;
int ret;
+};
+
+struct line_reader *
+process_lines_init(const char *pathname, char separator)
+{
+ struct line_reader *lr;
+
+ lr = calloc(1, sizeof(*lr));
+ if (lr == NULL)
+ cpio_errc(1, ENOMEM, "Can't open %s", pathname);
- separator = cpio->option_null ? '\0' : '\n';
- ret = 0;
+ lr->separator = separator;
+ lr->pathname = strdup(pathname);
if (strcmp(pathname, "-") == 0)
- f = stdin;
+ lr->f = stdin;
else
- f = fopen(pathname, "r");
- if (f == NULL)
+ lr->f = fopen(pathname, "r");
+ if (lr->f == NULL)
cpio_errc(1, errno, "Couldn't open %s", pathname);
- buff_length = 8192;
- buff = malloc(buff_length);
- if (buff == NULL)
+ lr->buff_length = 8192;
+ lr->buff = malloc(lr->buff_length);
+ if (lr->buff == NULL)
cpio_errc(1, ENOMEM, "Can't read %s", pathname);
- line_start = line_end = buff_end = buff;
+ lr->line_start = lr->line_end = lr->buff_end = lr->buff;
+
+ return (lr);
+}
+
+const char *
+process_lines_next(struct line_reader *lr)
+{
+ size_t bytes_wanted, bytes_read, new_buff_size;
+ char *line_start, *p;
+
for (;;) {
- /* Get some more data into the buffer. */
- bytes_wanted = buff + buff_length - buff_end;
- bytes_read = fread(buff_end, 1, bytes_wanted, f);
- buff_end += bytes_read;
- /* Process all complete lines in the buffer. */
- while (line_end < buff_end) {
- if (*line_end == separator) {
- *line_end = '\0';
- if ((*process)(cpio, line_start) != 0)
- ret = -1;
- line_start = line_end + 1;
- line_end = line_start;
+ /* If there's a line in the buffer, return it immediately. */
+ while (lr->line_end < lr->buff_end) {
+ if (*lr->line_end == lr->separator) {
+ *lr->line_end = '\0';
+ line_start = lr->line_start;
+ lr->line_start = lr->line_end + 1;
+ lr->line_end = lr->line_start;
+ return (line_start);
} else
- line_end++;
+ lr->line_end++;
}
- if (feof(f))
- break;
- if (ferror(f))
- cpio_errc(1, errno, "Can't read %s", pathname);
- if (line_start > buff) {
+
+ /* If we're at end-of-file, process the final data. */
+ if (lr->f == NULL) {
+ /* If there's more text, return one last line. */
+ if (lr->line_end > lr->line_start) {
+ *lr->line_end = '\0';
+ line_start = lr->line_start;
+ lr->line_start = lr->line_end + 1;
+ lr->line_end = lr->line_start;
+ return (line_start);
+ }
+ /* Otherwise, we're done. */
+ return (NULL);
+ }
+
+ /* Buffer only has part of a line. */
+ if (lr->line_start > lr->buff) {
/* Move a leftover fractional line to the beginning. */
- memmove(buff, line_start, buff_end - line_start);
- buff_end -= line_start - buff;
- line_end -= line_start - buff;
- line_start = buff;
+ memmove(lr->buff, lr->line_start,
+ lr->buff_end - lr->line_start);
+ lr->buff_end -= lr->line_start - lr->buff;
+ lr->line_end -= lr->line_start - lr->buff;
+ lr->line_start = lr->buff;
} else {
/* Line is too big; enlarge the buffer. */
- p = realloc(buff, buff_length *= 2);
+ new_buff_size = lr->buff_length * 2;
+ if (new_buff_size <= lr->buff_length)
+ cpio_errc(1, ENOMEM,
+ "Line too long in %s", lr->pathname);
+ lr->buff_length = new_buff_size;
+ p = realloc(lr->buff, new_buff_size);
if (p == NULL)
cpio_errc(1, ENOMEM,
- "Line too long in %s", pathname);
- buff_end = p + (buff_end - buff);
- line_end = p + (line_end - buff);
- line_start = buff = p;
+ "Line too long in %s", lr->pathname);
+ lr->buff_end = p + (lr->buff_end - lr->buff);
+ lr->line_end = p + (lr->line_end - lr->buff);
+ lr->line_start = lr->buff = p;
+ }
+
+ /* Get some more data into the buffer. */
+ bytes_wanted = lr->buff + lr->buff_length - lr->buff_end;
+ bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f);
+ lr->buff_end += bytes_read;
+
+ if (ferror(lr->f))
+ cpio_errc(1, errno, "Can't read %s", lr->pathname);
+ if (feof(lr->f)) {
+ if (lr->f != stdin)
+ fclose(lr->f);
+ lr->f = NULL;
}
}
- /* At end-of-file, handle the final line. */
- if (line_end > line_start) {
- *line_end = '\0';
- if ((*process)(cpio, line_start) != 0)
- ret = -1;
- }
- free(buff);
- if (f != stdin)
- fclose(f);
- return (ret);
+}
+
+void
+process_lines_free(struct line_reader *lr)
+{
+ free(lr->buff);
+ free(lr->pathname);
+ free(lr);
}
diff --git a/usr.bin/cpio/cpio.h b/usr.bin/cpio/cpio.h
index ecec2ee..7808633 100644
--- a/usr.bin/cpio/cpio.h
+++ b/usr.bin/cpio/cpio.h
@@ -53,12 +53,12 @@ struct cpio {
int extract_flags; /* Flags for extract operation */
char symlink_mode; /* H or L, per BSD conventions */
const char *compress_program;
+ char line_separator; /* --null ? '\0' : '\n' */
int option_append; /* -A, only relevant for -o */
int option_atime_restore; /* -a */
int option_follow_links; /* -L */
int option_link; /* -l */
int option_list; /* -t */
- int option_null; /* -0 --null */
int option_rename; /* -r */
char *destdir;
size_t pass_destpath_alloc;
@@ -98,9 +98,13 @@ enum {
OPTION_VERSION
};
+struct line_reader;
+
+struct line_reader *process_lines_init(const char *, char separator);
+const char *process_lines_next(struct line_reader *);
+void process_lines_free(struct line_reader *);
+
int cpio_getopt(struct cpio *cpio);
-int process_lines(struct cpio *cpio, const char *pathname,
- int (*process)(struct cpio *, const char *));
int include_from_file(struct cpio *, const char *);
#endif
diff --git a/usr.bin/cpio/matching.c b/usr.bin/cpio/matching.c
index f98421e..8d1798f 100644
--- a/usr.bin/cpio/matching.c
+++ b/usr.bin/cpio/matching.c
@@ -107,7 +107,16 @@ include(struct cpio *cpio, const char *pattern)
int
include_from_file(struct cpio *cpio, const char *pathname)
{
- return (process_lines(cpio, pathname, &include));
+ struct line_reader *lr;
+ const char *p;
+ int ret = 0;
+
+ lr = process_lines_init(pathname, '\n');
+ while ((p = process_lines_next(lr)) != NULL)
+ if (include(cpio, p) != 0)
+ ret = -1;
+ process_lines_free(lr);
+ return (ret);
}
static void
OpenPOWER on IntegriCloud