From 7aa651a6a4496d848f86de9b1e6b3a003256a01f Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 13 Nov 2012 17:14:08 -0600 Subject: Reindent to two spaces per level. Remove vi: directives that haven't worked right in years (ubuntu broke its' vim implementation). Remove trailing spaces. Add/remove blank lines. Re-wordwrap in places. Update documentation with new coding style. The actual code should be the same afterward, this is just cosmetic refactoring. --- lib/args.c | 633 ++++++++++++++------------- lib/bunzip.c | 1039 ++++++++++++++++++++++---------------------- lib/dirtree.c | 206 +++++---- lib/getmountlist.c | 47 +- lib/lib.c | 1217 ++++++++++++++++++++++++++-------------------------- lib/lib.h | 43 +- lib/llist.c | 51 ++- lib/password.c | 238 +++++----- lib/portability.c | 93 ++-- lib/xregcomp.c | 17 +- 10 files changed, 1771 insertions(+), 1813 deletions(-) (limited to 'lib') diff --git a/lib/args.c b/lib/args.c index 2f6132ab..b7119651 100644 --- a/lib/args.c +++ b/lib/args.c @@ -1,5 +1,4 @@ -/* vi: set sw=4 ts=4 : - * args.c - Command line argument parsing. +/* args.c - Command line argument parsing. * * Copyright 2006 Rob Landley */ @@ -34,6 +33,7 @@ // ~X enabling this disables X (switch off) // !X die with error if X already set (x!x die if x supplied twice) // [yz] needs at least one of y or z. TODO +// // at the beginning: // ^ stop at first nonoption argument // <0 die if less than # leftover arguments (default 0) @@ -48,19 +48,19 @@ // - is a synonym for stdin in file arguments // -abc means -a -b -c -/* This uses a getopt-like option string, but not getopt() itself. We call +/* This uses a getopt-like option string, but not getopt() itself. We call * it the get_opt string. * * Each option in the get_opt string corresponds to a bit position in the - * return value. The rightmost argument is (1<<0), the next to last is (1<<1) - * and so on. If the option isn't seen in argv[], its bit remains 0. + * return value. The rightmost argument is (1<<0), the next to last is (1<<1) + * and so on. If the option isn't seen in argv[], its bit remains 0. * * Options which have an argument fill in the corresponding slot in the global * union "this" (see generated/globals.h), which it treats as an array of longs * (note that sizeof(long)==sizeof(pointer) is guaranteed by LP64). * * You don't have to free the option strings, which point into the environment - * space. List objects should be freed by main() when command_main() returns. + * space. List objects should be freed by main() when command_main() returns. * * Example: * Calling get_optflags() when toys.which->options="ab:c:d" and @@ -79,343 +79,334 @@ // Linked list of all known options (get_opt string is parsed into this). struct opts { - struct opts *next; - long *arg; // Pointer into union "this" to store arguments at. - uint32_t edx[3]; // Flag mask to enable/disable/exclude. - int c; // Short argument character - int flags; // |=1, ^=2 - char type; // Type of arguments to store - union { - long l; - FLOAT f; - } val[3]; // low, high, default - range of allowed values + struct opts *next; + long *arg; // Pointer into union "this" to store arguments at. + uint32_t edx[3]; // Flag mask to enable/disable/exclude. + int c; // Short argument character + int flags; // |=1, ^=2 + char type; // Type of arguments to store + union { + long l; + FLOAT f; + } val[3]; // low, high, default - range of allowed values }; struct longopts { - struct longopts *next; - struct opts *opt; - char *str; - int len; + struct longopts *next; + struct opts *opt; + char *str; + int len; }; // State during argument parsing. struct getoptflagstate { - int argc, minargs, maxargs, nodash; - char *arg; - struct opts *opts, *this; - struct longopts *longopts; - int noerror, nodash_now, stopearly; - uint32_t excludes; + int argc, minargs, maxargs, nodash; + char *arg; + struct opts *opts, *this; + struct longopts *longopts; + int noerror, nodash_now, stopearly; + uint32_t excludes; }; // Parse one command line option. static int gotflag(struct getoptflagstate *gof) { - int type; - struct opts *opt = gof->this; - - // Did we recognize this option? - if (!opt) { - if (gof->noerror) return 1; - error_exit("Unknown option %s", gof->arg); - } - - // Set flags - toys.optflags |= opt->edx[0]; - toys.optflags &= ~opt->edx[1]; - gof->excludes = opt->edx[2]; - if (opt->flags&2) gof->stopearly=2; - - // Does this option take an argument? - gof->arg++; - type = opt->type; - if (type) { - char *arg = gof->arg; - - // Handle "-xblah" and "-x blah", but also a third case: "abxc blah" - // to make "tar xCjfv blah1 blah2 thingy" work like - // "tar -x -C blah1 -j -f blah2 -v thingy" - - if (gof->nodash_now || !arg[0]) arg = toys.argv[++gof->argc]; - // TODO: The following line doesn't display --longopt correctly - if (!arg) error_exit("Missing argument to -%c", opt->c); - - if (type == ':') *(opt->arg) = (long)arg; - else if (type == '*') { - struct arg_list **list; - - list = (struct arg_list **)opt->arg; - while (*list) list=&((*list)->next); - *list = xzalloc(sizeof(struct arg_list)); - (*list)->arg = arg; - } else if (type == '#' || type == '-') { - long l = atolx(arg); - if (type == '-' && !ispunct(*arg)) l*=-1; - if (l < opt->val[0].l) - error_exit("-%c < %ld", opt->c, opt->val[0].l); - if (l > opt->val[1].l) - error_exit("-%c > %ld", opt->c, opt->val[1].l); - - *(opt->arg) = l; - } else if (CFG_TOYBOX_FLOAT && type == '.') { - FLOAT *f = (FLOAT *)(opt->arg); - - *f = strtod(arg, &arg); - if (opt->val[0].l != LONG_MIN && *f < opt->val[0].f) - error_exit("-%c < %lf", opt->c, (double)opt->val[0].f); - if (opt->val[1].l != LONG_MAX && *f > opt->val[1].f) - error_exit("-%c > %lf", opt->c, (double)opt->val[1].f); - } else if (type == '@') ++*(opt->arg); - - if (!gof->nodash_now) gof->arg = ""; - } - - gof->this = NULL; - return 0; + int type; + struct opts *opt = gof->this; + + // Did we recognize this option? + if (!opt) { + if (gof->noerror) return 1; + error_exit("Unknown option %s", gof->arg); + } + + // Set flags + toys.optflags |= opt->edx[0]; + toys.optflags &= ~opt->edx[1]; + gof->excludes = opt->edx[2]; + if (opt->flags&2) gof->stopearly=2; + + // Does this option take an argument? + gof->arg++; + type = opt->type; + if (type) { + char *arg = gof->arg; + + // Handle "-xblah" and "-x blah", but also a third case: "abxc blah" + // to make "tar xCjfv blah1 blah2 thingy" work like + // "tar -x -C blah1 -j -f blah2 -v thingy" + + if (gof->nodash_now || !arg[0]) arg = toys.argv[++gof->argc]; + // TODO: The following line doesn't display --longopt correctly + if (!arg) error_exit("Missing argument to -%c", opt->c); + + if (type == ':') *(opt->arg) = (long)arg; + else if (type == '*') { + struct arg_list **list; + + list = (struct arg_list **)opt->arg; + while (*list) list=&((*list)->next); + *list = xzalloc(sizeof(struct arg_list)); + (*list)->arg = arg; + } else if (type == '#' || type == '-') { + long l = atolx(arg); + if (type == '-' && !ispunct(*arg)) l*=-1; + if (l < opt->val[0].l) error_exit("-%c < %ld", opt->c, opt->val[0].l); + if (l > opt->val[1].l) error_exit("-%c > %ld", opt->c, opt->val[1].l); + + *(opt->arg) = l; + } else if (CFG_TOYBOX_FLOAT && type == '.') { + FLOAT *f = (FLOAT *)(opt->arg); + + *f = strtod(arg, &arg); + if (opt->val[0].l != LONG_MIN && *f < opt->val[0].f) + error_exit("-%c < %lf", opt->c, (double)opt->val[0].f); + if (opt->val[1].l != LONG_MAX && *f > opt->val[1].f) + error_exit("-%c > %lf", opt->c, (double)opt->val[1].f); + } else if (type == '@') ++*(opt->arg); + + if (!gof->nodash_now) gof->arg = ""; + } + + gof->this = NULL; + return 0; } // Fill out toys.optflags and toys.optargs. void parse_optflaglist(struct getoptflagstate *gof) { - char *options = toys.which->options; - long *nextarg = (long *)&this; - struct opts *new = 0; - - // Parse option format string - memset(gof, 0, sizeof(struct getoptflagstate)); - gof->maxargs = INT_MAX; - if (!options) return; - - // Parse leading special behavior indicators - for (;;) { - if (*options == '^') gof->stopearly++; - else if (*options == '<') gof->minargs=*(++options)-'0'; - else if (*options == '>') gof->maxargs=*(++options)-'0'; - else if (*options == '?') gof->noerror++; - else if (*options == '&') gof->nodash++; - else break; - options++; - } - - // Parse the rest of the option string into a linked list - // of options with attributes. - - if (!*options) gof->stopearly++; - while (*options) { - char *temp; - int idx; - - // Allocate a new list entry when necessary - if (!new) { - new = xzalloc(sizeof(struct opts)); - new->next = gof->opts; - gof->opts = new; - new->val[0].l = LONG_MIN; - new->val[1].l = LONG_MAX; - ++*(new->edx); - } - // Each option must start with "(" or an option character. (Bare - // longopts only come at the start of the string.) - if (*options == '(') { - char *end; - struct longopts *lo = xmalloc(sizeof(struct longopts)); - - // Find the end of the longopt - for (end = ++options; *end && *end != ')'; end++); - if (CFG_TOYBOX_DEBUG && !*end) - error_exit("(longopt) didn't end"); - - // init a new struct longopts - lo->next = gof->longopts; - lo->opt = new; - lo->str = options; - lo->len = end-options; - gof->longopts = lo; - options = end; - - // Mark this struct opt as used, even when no short opt. - if (!new->c) new->c = -1; - - // If this is the start of a new option that wasn't a longopt, - - } else if (strchr(":*#@.-", *options)) { - if (CFG_TOYBOX_DEBUG && new->type) - error_exit("multiple types %c:%c%c", new->c, new->type, *options); - new->type = *options; - } else if (-1 != (idx = stridx("+~!", *options))) { - struct opts *opt; - int i; - - if (!*++options && CFG_TOYBOX_DEBUG) - error_exit("+~! no target"); - // Find this option flag (in previously parsed struct opt) - for (i=0, opt = new; ; opt = opt->next) { - if (CFG_TOYBOX_DEBUG && !opt) - error_exit("+~! unknown target"); - if (opt->c == *options) break; - i++; - } - new->edx[idx] |= 1<flags |= 1<=", *options))) { - if (new->type == '#') { - long l = strtol(++options, &temp, 10); - if (temp != options) new->val[idx].l = l; - } else if (CFG_TOYBOX_FLOAT && new->type == '.') { - FLOAT f = strtod(++options, &temp); - if (temp != options) new->val[idx].f = f; - } else if (CFG_TOYBOX_DEBUG) error_exit("<>= only after .#"); - options = --temp; - } - - // At this point, we've hit the end of the previous option. The - // current character is the start of a new option. If we've already - // assigned an option to this struct, loop to allocate a new one. - // (It'll get back here afterwards and fall through to next else.) - else if (new->c) { - new = NULL; - continue; - - // Claim this option, loop to see what's after it. - } else new->c = *options; - - options++; - } - - // Initialize enable/disable/exclude masks and pointers to store arguments. - // (We have to calculate all this ahead of time because longopts jump into - // the middle of the list. We have to do this after creating the list - // because we reverse direction: last entry created gets first global slot.) - int pos = 0; - for (new = gof->opts; new; new = new->next) { - int i; - - for (i=0;i<3;i++) new->edx[i] <<= pos; - pos++; - if (new->type) { - new->arg = (void *)nextarg; - *(nextarg++) = new->val[2].l; - } - } + char *options = toys.which->options; + long *nextarg = (long *)&this; + struct opts *new = 0; + + // Parse option format string + memset(gof, 0, sizeof(struct getoptflagstate)); + gof->maxargs = INT_MAX; + if (!options) return; + + // Parse leading special behavior indicators + for (;;) { + if (*options == '^') gof->stopearly++; + else if (*options == '<') gof->minargs=*(++options)-'0'; + else if (*options == '>') gof->maxargs=*(++options)-'0'; + else if (*options == '?') gof->noerror++; + else if (*options == '&') gof->nodash++; + else break; + options++; + } + + // Parse the rest of the option string into a linked list + // of options with attributes. + + if (!*options) gof->stopearly++; + while (*options) { + char *temp; + int idx; + + // Allocate a new list entry when necessary + if (!new) { + new = xzalloc(sizeof(struct opts)); + new->next = gof->opts; + gof->opts = new; + new->val[0].l = LONG_MIN; + new->val[1].l = LONG_MAX; + ++*(new->edx); + } + // Each option must start with "(" or an option character. (Bare + // longopts only come at the start of the string.) + if (*options == '(') { + char *end; + struct longopts *lo = xmalloc(sizeof(struct longopts)); + + // Find the end of the longopt + for (end = ++options; *end && *end != ')'; end++); + if (CFG_TOYBOX_DEBUG && !*end) error_exit("(longopt) didn't end"); + + // init a new struct longopts + lo->next = gof->longopts; + lo->opt = new; + lo->str = options; + lo->len = end-options; + gof->longopts = lo; + options = end; + + // Mark this struct opt as used, even when no short opt. + if (!new->c) new->c = -1; + + // If this is the start of a new option that wasn't a longopt, + + } else if (strchr(":*#@.-", *options)) { + if (CFG_TOYBOX_DEBUG && new->type) + error_exit("multiple types %c:%c%c", new->c, new->type, *options); + new->type = *options; + } else if (-1 != (idx = stridx("+~!", *options))) { + struct opts *opt; + int i; + + if (!*++options && CFG_TOYBOX_DEBUG) error_exit("+~! no target"); + // Find this option flag (in previously parsed struct opt) + for (i=0, opt = new; ; opt = opt->next) { + if (CFG_TOYBOX_DEBUG && !opt) error_exit("+~! unknown target"); + if (opt->c == *options) break; + i++; + } + new->edx[idx] |= 1<flags |= 1<=", *options))) { + if (new->type == '#') { + long l = strtol(++options, &temp, 10); + if (temp != options) new->val[idx].l = l; + } else if (CFG_TOYBOX_FLOAT && new->type == '.') { + FLOAT f = strtod(++options, &temp); + if (temp != options) new->val[idx].f = f; + } else if (CFG_TOYBOX_DEBUG) error_exit("<>= only after .#"); + options = --temp; + } + + // At this point, we've hit the end of the previous option. The + // current character is the start of a new option. If we've already + // assigned an option to this struct, loop to allocate a new one. + // (It'll get back here afterwards and fall through to next else.) + else if (new->c) { + new = NULL; + continue; + + // Claim this option, loop to see what's after it. + } else new->c = *options; + + options++; + } + + // Initialize enable/disable/exclude masks and pointers to store arguments. + // (We have to calculate all this ahead of time because longopts jump into + // the middle of the list. We have to do this after creating the list + // because we reverse direction: last entry created gets first global slot.) + int pos = 0; + for (new = gof->opts; new; new = new->next) { + int i; + + for (i=0;i<3;i++) new->edx[i] <<= pos; + pos++; + if (new->type) { + new->arg = (void *)nextarg; + *(nextarg++) = new->val[2].l; + } + } } void get_optflags(void) { - struct getoptflagstate gof; - long saveflags; - char *letters[]={"s",""}; - - // Option parsing is a two stage process: parse the option string into - // a struct opts list, then use that list to process argv[]; - - if (CFG_HELP) toys.exithelp++; - // Allocate memory for optargs - saveflags = 0; - while (toys.argv[saveflags++]); - toys.optargs = xzalloc(sizeof(char *)*saveflags); - - parse_optflaglist(&gof); - - // Iterate through command line arguments, skipping argv[0] - for (gof.argc=1; toys.argv[gof.argc]; gof.argc++) { - gof.arg = toys.argv[gof.argc]; - gof.this = NULL; - - // Parse this argument - if (gof.stopearly>1) goto notflag; - - gof.nodash_now = 0; - - // Various things with dashes - if (*gof.arg == '-') { - - // Handle - - if (!gof.arg[1]) goto notflag; - gof.arg++; - if (*gof.arg=='-') { - struct longopts *lo; - - gof.arg++; - // Handle -- - if (!*gof.arg) { - gof.stopearly += 2; - goto notflag; - } - // Handle --longopt - - for (lo = gof.longopts; lo; lo = lo->next) { - if (!strncmp(gof.arg, lo->str, lo->len)) { - if (gof.arg[lo->len]) { - if (gof.arg[lo->len]=='=' && lo->opt->type) - gof.arg += lo->len; - else continue; - } - // It's a match. - gof.arg = ""; - gof.this = lo->opt; - break; - } - } - - // Should we handle this --longopt as a non-option argument? - if (!lo && gof.noerror) { - gof.arg-=2; - goto notflag; - } - - // Long option parsed, handle option. - gotflag(&gof); - continue; - } - - // Handle things that don't start with a dash. - } else { - if (gof.nodash && (gof.nodash>1 || gof.argc == 1)) - gof.nodash_now = 1; - else goto notflag; - } - - // At this point, we have the args part of -args. Loop through - // each entry (could be -abc meaning -a -b -c) - saveflags = toys.optflags; - while (*gof.arg) { - - // Identify next option char. - for (gof.this = gof.opts; gof.this; gof.this = gof.this->next) - if (*gof.arg == gof.this->c) - if (!((gof.this->flags&4) && gof.arg[1])) break; - - // Handle option char (advancing past what was used) - if (gotflag(&gof) ) { - toys.optflags = saveflags; - gof.arg = toys.argv[gof.argc]; - goto notflag; - } - } - continue; - - // Not a flag, save value in toys.optargs[] + struct getoptflagstate gof; + long saveflags; + char *letters[]={"s",""}; + + // Option parsing is a two stage process: parse the option string into + // a struct opts list, then use that list to process argv[]; + + if (CFG_HELP) toys.exithelp++; + // Allocate memory for optargs + saveflags = 0; + while (toys.argv[saveflags++]); + toys.optargs = xzalloc(sizeof(char *)*saveflags); + + parse_optflaglist(&gof); + + // Iterate through command line arguments, skipping argv[0] + for (gof.argc=1; toys.argv[gof.argc]; gof.argc++) { + gof.arg = toys.argv[gof.argc]; + gof.this = NULL; + + // Parse this argument + if (gof.stopearly>1) goto notflag; + + gof.nodash_now = 0; + + // Various things with dashes + if (*gof.arg == '-') { + + // Handle - + if (!gof.arg[1]) goto notflag; + gof.arg++; + if (*gof.arg=='-') { + struct longopts *lo; + + gof.arg++; + // Handle -- + if (!*gof.arg) { + gof.stopearly += 2; + goto notflag; + } + // Handle --longopt + + for (lo = gof.longopts; lo; lo = lo->next) { + if (!strncmp(gof.arg, lo->str, lo->len)) { + if (gof.arg[lo->len]) { + if (gof.arg[lo->len]=='=' && lo->opt->type) gof.arg += lo->len; + else continue; + } + // It's a match. + gof.arg = ""; + gof.this = lo->opt; + break; + } + } + + // Should we handle this --longopt as a non-option argument? + if (!lo && gof.noerror) { + gof.arg-=2; + goto notflag; + } + + // Long option parsed, handle option. + gotflag(&gof); + continue; + } + + // Handle things that don't start with a dash. + } else { + if (gof.nodash && (gof.nodash>1 || gof.argc == 1)) gof.nodash_now = 1; + else goto notflag; + } + + // At this point, we have the args part of -args. Loop through + // each entry (could be -abc meaning -a -b -c) + saveflags = toys.optflags; + while (*gof.arg) { + + // Identify next option char. + for (gof.this = gof.opts; gof.this; gof.this = gof.this->next) + if (*gof.arg == gof.this->c) + if (!((gof.this->flags&4) && gof.arg[1])) break; + + // Handle option char (advancing past what was used) + if (gotflag(&gof) ) { + toys.optflags = saveflags; + gof.arg = toys.argv[gof.argc]; + goto notflag; + } + } + continue; + + // Not a flag, save value in toys.optargs[] notflag: - if (gof.stopearly) gof.stopearly++; - toys.optargs[toys.optc++] = toys.argv[gof.argc]; - } - - // Sanity check - if (toys.optcgof.maxargs) - error_exit("Max %d argument%s", gof.maxargs, letters[!(gof.maxargs-1)]); - if (CFG_HELP) toys.exithelp = 0; - - if (CFG_TOYBOX_FREE) { - llist_traverse(gof.opts, free); - llist_traverse(gof.longopts, free); - } + if (gof.stopearly) gof.stopearly++; + toys.optargs[toys.optc++] = toys.argv[gof.argc]; + } + + // Sanity check + if (toys.optcgof.maxargs) + error_exit("Max %d argument%s", gof.maxargs, letters[!(gof.maxargs-1)]); + if (CFG_HELP) toys.exithelp = 0; + + if (CFG_TOYBOX_FREE) { + llist_traverse(gof.opts, free); + llist_traverse(gof.longopts, free); + } } diff --git a/lib/bunzip.c b/lib/bunzip.c index f860aa64..2836d38c 100644 --- a/lib/bunzip.c +++ b/lib/bunzip.c @@ -1,14 +1,13 @@ -/* vi: set sw=4 ts=4: */ /* micro-bunzip, a small, simple bzip2 decompression implementation. - - Copyright 2003, 2006 by Rob Landley (rob@landley.net). - - Based on a close reading (but not the actual code) of the original bzip2 - decompression code by Julian R Seward (jseward@acm.org), which also - acknowledges contributions by Mike Burrows, David Wheeler, Peter Fenwick, - Alistair Moffat, Radford Neal, Ian H. Witten, Robert Sedgewick, and - Jon L. Bentley. -*/ + * + * Copyright 2003, 2006 by Rob Landley (rob@landley.net). + * + * Based on a close reading (but not the actual code) of the original bzip2 + * decompression code by Julian R Seward (jseward@acm.org), which also + * acknowledges contributions by Mike Burrows, David Wheeler, Peter Fenwick, + * Alistair Moffat, Radford Neal, Ian H. Witten, Robert Sedgewick, and + * Jon L. Bentley. + */ #include "toys.h" @@ -32,93 +31,92 @@ #define RETVAL_OBSOLETE_INPUT (-3) char *bunzip_errors[]={ - NULL, - "Not bzip data", - "Data error", - "Obsolete (pre 0.9.5) bzip format not supported." + NULL, + "Not bzip data", + "Data error", + "Obsolete (pre 0.9.5) bzip format not supported." }; // This is what we know about each huffman coding group struct group_data { - int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS]; - char minLen, maxLen; + int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS]; + char minLen, maxLen; }; // Data for burrows wheeler transform struct bwdata { - unsigned int origPtr; - int byteCount[256]; - // State saved when interrupting output - int writePos, writeRun, writeCount, writeCurrent; - unsigned int dataCRC, headerCRC; - unsigned int *dbuf; + unsigned int origPtr; + int byteCount[256]; + // State saved when interrupting output + int writePos, writeRun, writeCount, writeCurrent; + unsigned int dataCRC, headerCRC; + unsigned int *dbuf; }; // Structure holding all the housekeeping data, including IO buffers and // memory that persists between calls to bunzip struct bunzip_data { + // Input stream, input buffer, input bit buffer + int in_fd, inbufCount, inbufPos; + char *inbuf; + unsigned int inbufBitCount, inbufBits; - // Input stream, input buffer, input bit buffer - int in_fd, inbufCount, inbufPos; - char *inbuf; - unsigned int inbufBitCount, inbufBits; - - // Output buffer - char outbuf[IOBUF_SIZE]; - int outbufPos; + // Output buffer + char outbuf[IOBUF_SIZE]; + int outbufPos; - unsigned int totalCRC; + unsigned int totalCRC; - // First pass decompression data (Huffman and MTF decoding) - char selectors[32768]; // nSelectors=15 bits - struct group_data groups[MAX_GROUPS]; // huffman coding tables - int symTotal, groupCount, nSelectors; - unsigned char symToByte[256], mtfSymbol[256]; + // First pass decompression data (Huffman and MTF decoding) + char selectors[32768]; // nSelectors=15 bits + struct group_data groups[MAX_GROUPS]; // huffman coding tables + int symTotal, groupCount, nSelectors; + unsigned char symToByte[256], mtfSymbol[256]; - // The CRC values stored in the block header and calculated from the data - unsigned int crc32Table[256]; + // The CRC values stored in the block header and calculated from the data + unsigned int crc32Table[256]; - // Second pass decompression data (burrows-wheeler transform) - unsigned int dbufSize; - struct bwdata bwdata[THREADS]; + // Second pass decompression data (burrows-wheeler transform) + unsigned int dbufSize; + struct bwdata bwdata[THREADS]; }; // Return the next nnn bits of input. All reads from the compressed input // are done through this function. All reads are big endian. static unsigned int get_bits(struct bunzip_data *bd, char bits_wanted) { - unsigned int bits = 0; - - // If we need to get more data from the byte buffer, do so. (Loop getting - // one byte at a time to enforce endianness and avoid unaligned access.) - while (bd->inbufBitCount < bits_wanted) { - - // If we need to read more data from file into byte buffer, do so - if (bd->inbufPos == bd->inbufCount) { - if (0 >= (bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE))) - error_exit("Unexpected input EOF"); - bd->inbufPos = 0; - } - - // Avoid 32-bit overflow (dump bit buffer to top of output) - if (bd->inbufBitCount>=24) { - bits = bd->inbufBits&((1<inbufBitCount)-1); - bits_wanted -= bd->inbufBitCount; - bits <<= bits_wanted; - bd->inbufBitCount = 0; - } - - // Grab next 8 bits of input from buffer. - bd->inbufBits = (bd->inbufBits<<8) | bd->inbuf[bd->inbufPos++]; - bd->inbufBitCount += 8; - } - - // Calculate result - bd->inbufBitCount -= bits_wanted; - bits |= (bd->inbufBits>>bd->inbufBitCount) & ((1<inbufBitCount < bits_wanted) { + + // If we need to read more data from file into byte buffer, do so + if (bd->inbufPos == bd->inbufCount) { + if (0 >= (bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE))) + error_exit("Unexpected input EOF"); + bd->inbufPos = 0; + } + + // Avoid 32-bit overflow (dump bit buffer to top of output) + if (bd->inbufBitCount>=24) { + bits = bd->inbufBits&((1<inbufBitCount)-1); + bits_wanted -= bd->inbufBitCount; + bits <<= bits_wanted; + bd->inbufBitCount = 0; + } + + // Grab next 8 bits of input from buffer. + bd->inbufBits = (bd->inbufBits<<8) | bd->inbuf[bd->inbufPos++]; + bd->inbufBitCount += 8; + } + + // Calculate result + bd->inbufBitCount -= bits_wanted; + bits |= (bd->inbufBits>>bd->inbufBitCount) & ((1<headerCRC = get_bits(bd,32); - - // Is this the EOF block with CRC for whole file? (Constant is "e") - if (ii==0x177245 && jj==0x385090) return RETVAL_LAST_BLOCK; - - // Is this a valid data block? (Constant is "pi".) - if (ii!=0x314159 || jj!=0x265359) return RETVAL_NOT_BZIP_DATA; - - // We can add support for blockRandomised if anybody complains. - if (get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT; - if ((bw->origPtr = get_bits(bd,24)) > bd->dbufSize) - return RETVAL_DATA_ERROR; - - // mapping table: if some byte values are never used (encoding things - // like ascii text), the compression code removes the gaps to have fewer - // symbols to deal with, and writes a sparse bitfield indicating which - // values were present. We make a translation table to convert the symbols - // back to the corresponding bytes. - hh = get_bits(bd, 16); - bd->symTotal = 0; - for (ii=0; ii<16; ii++) { - if (hh & (1 << (15 - ii))) { - kk = get_bits(bd, 16); - for (jj=0; jj<16; jj++) - if (kk & (1 << (15 - jj))) - bd->symToByte[bd->symTotal++] = (16 * ii) + jj; - } - } - - // How many different huffman coding groups does this block use? - bd->groupCount = get_bits(bd,3); - if (bd->groupCount<2 || bd->groupCount>MAX_GROUPS) return RETVAL_DATA_ERROR; - - // nSelectors: Every GROUP_SIZE many symbols we switch huffman coding - // tables. Each group has a selector, which is an index into the huffman - // coding table arrays. - // - // Read in the group selector array, which is stored as MTF encoded - // bit runs. (MTF = Move To Front. Every time a symbol occurs it's moved - // to the front of the table, so it has a shorter encoding next time.) - if (!(bd->nSelectors = get_bits(bd, 15))) return RETVAL_DATA_ERROR; - for (ii=0; iigroupCount; ii++) bd->mtfSymbol[ii] = ii; - for (ii=0; iinSelectors; ii++) { - - // Get next value - for(jj=0;get_bits(bd,1);jj++) - if (jj>=bd->groupCount) return RETVAL_DATA_ERROR; - - // Decode MTF to get the next selector, and move it to the front. - uc = bd->mtfSymbol[jj]; - memmove(bd->mtfSymbol+1, bd->mtfSymbol, jj); - bd->mtfSymbol[0] = bd->selectors[ii] = uc; - } - - // Read the huffman coding tables for each group, which code for symTotal - // literal symbols, plus two run symbols (RUNA, RUNB) - symCount = bd->symTotal+2; - for (jj=0; jjgroupCount; jj++) { - unsigned char length[MAX_SYMBOLS]; - unsigned temp[MAX_HUFCODE_BITS+1]; - int minLen, maxLen, pp; - - // Read lengths - hh = get_bits(bd, 5); - for (ii = 0; ii < symCount; ii++) { - for(;;) { - // !hh || hh > MAX_HUFCODE_BITS in one test. - if (MAX_HUFCODE_BITS-1 < (unsigned)hh-1) - return RETVAL_DATA_ERROR; - // Grab 2 bits instead of 1 (slightly smaller/faster). Stop if - // first bit is 0, otherwise second bit says whether to - // increment or decrement. - kk = get_bits(bd, 2); - if (kk & 2) hh += 1 - ((kk&1)<<1); - else { - bd->inbufBitCount++; - break; - } - } - length[ii] = hh; - } - - // Find largest and smallest lengths in this group - minLen = maxLen = length[0]; - for (ii = 1; ii < symCount; ii++) { - if(length[ii] > maxLen) maxLen = length[ii]; - else if(length[ii] < minLen) minLen = length[ii]; - } - - /* Calculate permute[], base[], and limit[] tables from length[]. - * - * permute[] is the lookup table for converting huffman coded symbols - * into decoded symbols. It contains symbol values sorted by length. - * - * base[] is the amount to subtract from the value of a huffman symbol - * of a given length when using permute[]. - * - * limit[] indicates the largest numerical value a symbol with a given - * number of bits can have. It lets us know when to stop reading. - * - * To use these, keep reading bits until value <= limit[bitcount] or - * you've read over 20 bits (error). Then the decoded symbol - * equals permute[hufcode_value - base[hufcode_bitcount]]. - */ - hufGroup = bd->groups+jj; - hufGroup->minLen = minLen; - hufGroup->maxLen = maxLen; - - // Note that minLen can't be smaller than 1, so we adjust the base - // and limit array pointers so we're not always wasting the first - // entry. We do this again when using them (during symbol decoding). - base = hufGroup->base-1; - limit = hufGroup->limit-1; - - // zero temp[] and limit[], and calculate permute[] - pp = 0; - for (ii = minLen; ii <= maxLen; ii++) { - temp[ii] = limit[ii] = 0; - for (hh = 0; hh < symCount; hh++) - if (length[hh] == ii) - hufGroup->permute[pp++] = hh; - } - - // Count symbols coded for at each bit length - for (ii = 0; ii < symCount; ii++) temp[length[ii]]++; - - /* Calculate limit[] (the largest symbol-coding value at each bit - * length, which is (previous limit<<1)+symbols at this level), and - * base[] (number of symbols to ignore at each bit length, which is - * limit minus the cumulative count of symbols coded for already). */ - pp = hh = 0; - for (ii = minLen; ii < maxLen; ii++) { - pp += temp[ii]; - limit[ii] = pp-1; - pp <<= 1; - base[ii+1] = pp-(hh+=temp[ii]); - } - limit[maxLen] = pp+temp[maxLen]-1; - limit[maxLen+1] = INT_MAX; - base[minLen] = 0; - } - - return 0; + struct group_data *hufGroup; + int hh, ii, jj, kk, symCount, *base, *limit; + unsigned char uc; + + // Read in header signature and CRC (which is stored big endian) + ii = get_bits(bd, 24); + jj = get_bits(bd, 24); + bw->headerCRC = get_bits(bd,32); + + // Is this the EOF block with CRC for whole file? (Constant is "e") + if (ii==0x177245 && jj==0x385090) return RETVAL_LAST_BLOCK; + + // Is this a valid data block? (Constant is "pi".) + if (ii!=0x314159 || jj!=0x265359) return RETVAL_NOT_BZIP_DATA; + + // We can add support for blockRandomised if anybody complains. + if (get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT; + if ((bw->origPtr = get_bits(bd,24)) > bd->dbufSize) return RETVAL_DATA_ERROR; + + // mapping table: if some byte values are never used (encoding things + // like ascii text), the compression code removes the gaps to have fewer + // symbols to deal with, and writes a sparse bitfield indicating which + // values were present. We make a translation table to convert the symbols + // back to the corresponding bytes. + hh = get_bits(bd, 16); + bd->symTotal = 0; + for (ii=0; ii<16; ii++) { + if (hh & (1 << (15 - ii))) { + kk = get_bits(bd, 16); + for (jj=0; jj<16; jj++) + if (kk & (1 << (15 - jj))) + bd->symToByte[bd->symTotal++] = (16 * ii) + jj; + } + } + + // How many different huffman coding groups does this block use? + bd->groupCount = get_bits(bd,3); + if (bd->groupCount<2 || bd->groupCount>MAX_GROUPS) return RETVAL_DATA_ERROR; + + // nSelectors: Every GROUP_SIZE many symbols we switch huffman coding + // tables. Each group has a selector, which is an index into the huffman + // coding table arrays. + // + // Read in the group selector array, which is stored as MTF encoded + // bit runs. (MTF = Move To Front. Every time a symbol occurs it's moved + // to the front of the table, so it has a shorter encoding next time.) + if (!(bd->nSelectors = get_bits(bd, 15))) return RETVAL_DATA_ERROR; + for (ii=0; iigroupCount; ii++) bd->mtfSymbol[ii] = ii; + for (ii=0; iinSelectors; ii++) { + + // Get next value + for(jj=0;get_bits(bd,1);jj++) + if (jj>=bd->groupCount) return RETVAL_DATA_ERROR; + + // Decode MTF to get the next selector, and move it to the front. + uc = bd->mtfSymbol[jj]; + memmove(bd->mtfSymbol+1, bd->mtfSymbol, jj); + bd->mtfSymbol[0] = bd->selectors[ii] = uc; + } + + // Read the huffman coding tables for each group, which code for symTotal + // literal symbols, plus two run symbols (RUNA, RUNB) + symCount = bd->symTotal+2; + for (jj=0; jjgroupCount; jj++) { + unsigned char length[MAX_SYMBOLS]; + unsigned temp[MAX_HUFCODE_BITS+1]; + int minLen, maxLen, pp; + + // Read lengths + hh = get_bits(bd, 5); + for (ii = 0; ii < symCount; ii++) { + for(;;) { + // !hh || hh > MAX_HUFCODE_BITS in one test. + if (MAX_HUFCODE_BITS-1 < (unsigned)hh-1) return RETVAL_DATA_ERROR; + // Grab 2 bits instead of 1 (slightly smaller/faster). Stop if + // first bit is 0, otherwise second bit says whether to + // increment or decrement. + kk = get_bits(bd, 2); + if (kk & 2) hh += 1 - ((kk&1)<<1); + else { + bd->inbufBitCount++; + break; + } + } + length[ii] = hh; + } + + // Find largest and smallest lengths in this group + minLen = maxLen = length[0]; + for (ii = 1; ii < symCount; ii++) { + if(length[ii] > maxLen) maxLen = length[ii]; + else if(length[ii] < minLen) minLen = length[ii]; + } + + /* Calculate permute[], base[], and limit[] tables from length[]. + * + * permute[] is the lookup table for converting huffman coded symbols + * into decoded symbols. It contains symbol values sorted by length. + * + * base[] is the amount to subtract from the value of a huffman symbol + * of a given length when using permute[]. + * + * limit[] indicates the largest numerical value a symbol with a given + * number of bits can have. It lets us know when to stop reading. + * + * To use these, keep reading bits until value <= limit[bitcount] or + * you've read over 20 bits (error). Then the decoded symbol + * equals permute[hufcode_value - base[hufcode_bitcount]]. + */ + hufGroup = bd->groups+jj; + hufGroup->minLen = minLen; + hufGroup->maxLen = maxLen; + + // Note that minLen can't be smaller than 1, so we adjust the base + // and limit array pointers so we're not always wasting the first + // entry. We do this again when using them (during symbol decoding). + base = hufGroup->base-1; + limit = hufGroup->limit-1; + + // zero temp[] and limit[], and calculate permute[] + pp = 0; + for (ii = minLen; ii <= maxLen; ii++) { + temp[ii] = limit[ii] = 0; + for (hh = 0; hh < symCount; hh++) + if (length[hh] == ii) hufGroup->permute[pp++] = hh; + } + + // Count symbols coded for at each bit length + for (ii = 0; ii < symCount; ii++) temp[length[ii]]++; + + /* Calculate limit[] (the largest symbol-coding value at each bit + * length, which is (previous limit<<1)+symbols at this level), and + * base[] (number of symbols to ignore at each bit length, which is + * limit minus the cumulative count of symbols coded for already). */ + pp = hh = 0; + for (ii = minLen; ii < maxLen; ii++) { + pp += temp[ii]; + limit[ii] = pp-1; + pp <<= 1; + base[ii+1] = pp-(hh+=temp[ii]); + } + limit[maxLen] = pp+temp[maxLen]-1; + limit[maxLen+1] = INT_MAX; + base[minLen] = 0; + } + + return 0; } /* First pass, read block's symbols into dbuf[dbufCount]. @@ -300,191 +295,188 @@ static int read_block_header(struct bunzip_data *bd, struct bwdata *bw) static int read_huffman_data(struct bunzip_data *bd, struct bwdata *bw) { - struct group_data *hufGroup; - int hh, ii, jj, kk, runPos, dbufCount, symCount, selector, nextSym, - *byteCount, *base, *limit; - unsigned int *dbuf = bw->dbuf; - unsigned char uc; - - // We've finished reading and digesting the block header. Now read this - // block's huffman coded symbols from the file and undo the huffman coding - // and run length encoding, saving the result into dbuf[dbufCount++] = uc - - // Initialize symbol occurrence counters and symbol mtf table - byteCount = bw->byteCount; - for(ii=0; ii<256; ii++) { - byteCount[ii] = 0; - bd->mtfSymbol[ii] = ii; - } - - // Loop through compressed symbols. This is the first "tight inner loop" - // that needs to be micro-optimized for speed. (This one fills out dbuf[] - // linearly, staying in cache more, so isn't as limited by DRAM access.) - runPos = dbufCount = symCount = selector = 0; - // Some unnecessary initializations to shut gcc up. - base = limit = 0; - hufGroup = 0; - hh = 0; - - for (;;) { - - // Have we reached the end of this huffman group? - if (!(symCount--)) { - // Determine which huffman coding group to use. - symCount = GROUP_SIZE-1; - if (selector >= bd->nSelectors) return RETVAL_DATA_ERROR; - hufGroup = bd->groups + bd->selectors[selector++]; - base = hufGroup->base-1; - limit = hufGroup->limit-1; - } - - // Read next huffman-coded symbol (into jj). - ii = hufGroup->minLen; - jj = get_bits(bd, ii); - while (jj > limit[ii]) { - // if (ii > hufGroup->maxLen) return RETVAL_DATA_ERROR; - ii++; - - // Unroll get_bits() to avoid a function call when the data's in - // the buffer already. - kk = bd->inbufBitCount - ? (bd->inbufBits >> --(bd->inbufBitCount)) & 1 - : get_bits(bd, 1); - jj = (jj << 1) | kk; - } - // Huffman decode jj into nextSym (with bounds checking) - jj-=base[ii]; - - if (ii > hufGroup->maxLen || (unsigned)jj >= MAX_SYMBOLS) - return RETVAL_DATA_ERROR; - nextSym = hufGroup->permute[jj]; - - // If this is a repeated run, loop collecting data - if ((unsigned)nextSym <= SYMBOL_RUNB) { - - // If this is the start of a new run, zero out counter - if(!runPos) { - runPos = 1; - hh = 0; - } - - /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at - each bit position, add 1 or 2 instead. For example, - 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2. - You can make any bit pattern that way using 1 less symbol than - the basic or 0/1 method (except all bits 0, which would use no - symbols, but a run of length 0 doesn't mean anything in this - context). Thus space is saved. */ - hh += (runPos << nextSym); // +runPos if RUNA; +2*runPos if RUNB - runPos <<= 1; - continue; - } - - /* When we hit the first non-run symbol after a run, we now know - how many times to repeat the last literal, so append that many - copies to our buffer of decoded symbols (dbuf) now. (The last - literal used is the one at the head of the mtfSymbol array.) */ - if (runPos) { - runPos = 0; - if (dbufCount+hh >= bd->dbufSize) return RETVAL_DATA_ERROR; - - uc = bd->symToByte[bd->mtfSymbol[0]]; - byteCount[uc] += hh; - while (hh--) dbuf[dbufCount++] = uc; - } - - // Is this the terminating symbol? - if (nextSym>bd->symTotal) break; - - /* At this point, the symbol we just decoded indicates a new literal - character. Subtract one to get the position in the MTF array - at which this literal is currently to be found. (Note that the - result can't be -1 or 0, because 0 and 1 are RUNA and RUNB. - Another instance of the first symbol in the mtf array, position 0, - would have been handled as part of a run.) */ - if (dbufCount>=bd->dbufSize) return RETVAL_DATA_ERROR; - ii = nextSym - 1; - uc = bd->mtfSymbol[ii]; - // On my laptop, unrolling this memmove() into a loop shaves 3.5% off - // the total running time. - while(ii--) bd->mtfSymbol[ii+1] = bd->mtfSymbol[ii]; - bd->mtfSymbol[0] = uc; - uc = bd->symToByte[uc]; - - // We have our literal byte. Save it into dbuf. - byteCount[uc]++; - dbuf[dbufCount++] = (unsigned int)uc; - } - - // Now we know what dbufCount is, do a better sanity check on origPtr. - if (bw->origPtr >= (bw->writeCount = dbufCount)) return RETVAL_DATA_ERROR; - - return 0; + struct group_data *hufGroup; + int hh, ii, jj, kk, runPos, dbufCount, symCount, selector, nextSym, + *byteCount, *base, *limit; + unsigned int *dbuf = bw->dbuf; + unsigned char uc; + + // We've finished reading and digesting the block header. Now read this + // block's huffman coded symbols from the file and undo the huffman coding + // and run length encoding, saving the result into dbuf[dbufCount++] = uc + + // Initialize symbol occurrence counters and symbol mtf table + byteCount = bw->byteCount; + for(ii=0; ii<256; ii++) { + byteCount[ii] = 0; + bd->mtfSymbol[ii] = ii; + } + + // Loop through compressed symbols. This is the first "tight inner loop" + // that needs to be micro-optimized for speed. (This one fills out dbuf[] + // linearly, staying in cache more, so isn't as limited by DRAM access.) + runPos = dbufCount = symCount = selector = 0; + // Some unnecessary initializations to shut gcc up. + base = limit = 0; + hufGroup = 0; + hh = 0; + + for (;;) { + // Have we reached the end of this huffman group? + if (!(symCount--)) { + // Determine which huffman coding group to use. + symCount = GROUP_SIZE-1; + if (selector >= bd->nSelectors) return RETVAL_DATA_ERROR; + hufGroup = bd->groups + bd->selectors[selector++]; + base = hufGroup->base-1; + limit = hufGroup->limit-1; + } + + // Read next huffman-coded symbol (into jj). + ii = hufGroup->minLen; + jj = get_bits(bd, ii); + while (jj > limit[ii]) { + // if (ii > hufGroup->maxLen) return RETVAL_DATA_ERROR; + ii++; + + // Unroll get_bits() to avoid a function call when the data's in + // the buffer already. + kk = bd->inbufBitCount + ? (bd->inbufBits >> --(bd->inbufBitCount)) & 1 : get_bits(bd, 1); + jj = (jj << 1) | kk; + } + // Huffman decode jj into nextSym (with bounds checking) + jj-=base[ii]; + + if (ii > hufGroup->maxLen || (unsigned)jj >= MAX_SYMBOLS) + return RETVAL_DATA_ERROR; + nextSym = hufGroup->permute[jj]; + + // If this is a repeated run, loop collecting data + if ((unsigned)nextSym <= SYMBOL_RUNB) { + // If this is the start of a new run, zero out counter + if(!runPos) { + runPos = 1; + hh = 0; + } + + /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at + each bit position, add 1 or 2 instead. For example, + 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2. + You can make any bit pattern that way using 1 less symbol than + the basic or 0/1 method (except all bits 0, which would use no + symbols, but a run of length 0 doesn't mean anything in this + context). Thus space is saved. */ + hh += (runPos << nextSym); // +runPos if RUNA; +2*runPos if RUNB + runPos <<= 1; + continue; + } + + /* When we hit the first non-run symbol after a run, we now know + how many times to repeat the last literal, so append that many + copies to our buffer of decoded symbols (dbuf) now. (The last + literal used is the one at the head of the mtfSymbol array.) */ + if (runPos) { + runPos = 0; + if (dbufCount+hh >= bd->dbufSize) return RETVAL_DATA_ERROR; + + uc = bd->symToByte[bd->mtfSymbol[0]]; + byteCount[uc] += hh; + while (hh--) dbuf[dbufCount++] = uc; + } + + // Is this the terminating symbol? + if (nextSym>bd->symTotal) break; + + /* At this point, the symbol we just decoded indicates a new literal + character. Subtract one to get the position in the MTF array + at which this literal is currently to be found. (Note that the + result can't be -1 or 0, because 0 and 1 are RUNA and RUNB. + Another instance of the first symbol in the mtf array, position 0, + would have been handled as part of a run.) */ + if (dbufCount>=bd->dbufSize) return RETVAL_DATA_ERROR; + ii = nextSym - 1; + uc = bd->mtfSymbol[ii]; + // On my laptop, unrolling this memmove() into a loop shaves 3.5% off + // the total running time. + while(ii--) bd->mtfSymbol[ii+1] = bd->mtfSymbol[ii]; + bd->mtfSymbol[0] = uc; + uc = bd->symToByte[uc]; + + // We have our literal byte. Save it into dbuf. + byteCount[uc]++; + dbuf[dbufCount++] = (unsigned int)uc; + } + + // Now we know what dbufCount is, do a better sanity check on origPtr. + if (bw->origPtr >= (bw->writeCount = dbufCount)) return RETVAL_DATA_ERROR; + + return 0; } // Flush output buffer to disk void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd) { - if (bd->outbufPos) { - if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos) - error_exit("Unexpected output EOF"); - bd->outbufPos = 0; - } + if (bd->outbufPos) { + if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos) + error_exit("Unexpected output EOF"); + bd->outbufPos = 0; + } } void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw) { - int ii, jj; - unsigned int *dbuf = bw->dbuf; - int *byteCount = bw->byteCount; - - // Technically this part is preparation for the burrows-wheeler - // transform, but it's quick and convenient to do here. - - // Turn byteCount into cumulative occurrence counts of 0 to n-1. - jj = 0; - for (ii=0; ii<256; ii++) { - int kk = jj + byteCount[ii]; - byteCount[ii] = jj; - jj = kk; - } - - // Use occurrence counts to quickly figure out what order dbuf would be in - // if we sorted it. - for (ii=0; ii < bw->writeCount; ii++) { - unsigned char uc = dbuf[ii]; - dbuf[byteCount[uc]] |= (ii << 8); - byteCount[uc]++; - } - - // blockRandomised support would go here. - - // Using ii as position, jj as previous character, hh as current character, - // and uc as run count. - bw->dataCRC = 0xffffffffL; - - /* Decode first byte by hand to initialize "previous" byte. Note that it - doesn't get output, and if the first three characters are identical - it doesn't qualify as a run (hence uc=255, which will either wrap - to 1 or get reset). */ - if (bw->writeCount) { - bw->writePos = dbuf[bw->origPtr]; - bw->writeCurrent = (unsigned char)bw->writePos; - bw->writePos >>= 8; - bw->writeRun = -1; - } + int ii, jj; + unsigned int *dbuf = bw->dbuf; + int *byteCount = bw->byteCount; + + // Technically this part is preparation for the burrows-wheeler + // transform, but it's quick and convenient to do here. + + // Turn byteCount into cumulative occurrence counts of 0 to n-1. + jj = 0; + for (ii=0; ii<256; ii++) { + int kk = jj + byteCount[ii]; + byteCount[ii] = jj; + jj = kk; + } + + // Use occurrence counts to quickly figure out what order dbuf would be in + // if we sorted it. + for (ii=0; ii < bw->writeCount; ii++) { + unsigned char uc = dbuf[ii]; + dbuf[byteCount[uc]] |= (ii << 8); + byteCount[uc]++; + } + + // blockRandomised support would go here. + + // Using ii as position, jj as previous character, hh as current character, + // and uc as run count. + bw->dataCRC = 0xffffffffL; + + /* Decode first byte by hand to initialize "previous" byte. Note that it + doesn't get output, and if the first three characters are identical + it doesn't qualify as a run (hence uc=255, which will either wrap + to 1 or get reset). */ + if (bw->writeCount) { + bw->writePos = dbuf[bw->origPtr]; + bw->writeCurrent = (unsigned char)bw->writePos; + bw->writePos >>= 8; + bw->writeRun = -1; + } } // Decompress a block of text to intermediate buffer int read_bunzip_data(struct bunzip_data *bd) { - int rc = read_block_header(bd, bd->bwdata); - if (!rc) rc=read_huffman_data(bd, bd->bwdata); + int rc = read_block_header(bd, bd->bwdata); + if (!rc) rc=read_huffman_data(bd, bd->bwdata); - // First thing that can be done by a background thread. - burrows_wheeler_prep(bd, bd->bwdata); + // First thing that can be done by a background thread. + burrows_wheeler_prep(bd, bd->bwdata); - return rc; + return rc; } // Undo burrows-wheeler transform on intermediate buffer to produce output. @@ -497,149 +489,144 @@ int read_bunzip_data(struct bunzip_data *bd) int write_bunzip_data(struct bunzip_data *bd, struct bwdata *bw, int out_fd, char *outbuf, int len) { - unsigned int *dbuf = bw->dbuf; - int count, pos, current, run, copies, outbyte, previous, gotcount = 0; - - for (;;) { - - // If last read was short due to end of file, return last block now - if (bw->writeCount < 0) return bw->writeCount; - - // If we need to refill dbuf, do it. - if (!bw->writeCount) { - int i = read_bunzip_data(bd); - if (i) { - if (i == RETVAL_LAST_BLOCK) { - bw->writeCount = i; - return gotcount; - } else return i; - } - } - - // loop generating output - count = bw->writeCount; - pos = bw->writePos; - current = bw->writeCurrent; - run = bw->writeRun; - while (count) { - - // If somebody (like tar) wants a certain number of bytes of - // data from memory instead of written to a file, humor them. - if (len && bd->outbufPos>=len) goto dataus_interruptus; - count--; - - // Follow sequence vector to undo Burrows-Wheeler transform. - previous = current; - pos = dbuf[pos]; - current = pos&0xff; - pos >>= 8; - - // Whenever we see 3 consecutive copies of the same byte, - // the 4th is a repeat count - if (run++ == 3) { - copies = current; - outbyte = previous; - current = -1; - } else { - copies = 1; - outbyte = current; - } - - // Output bytes to buffer, flushing to file if necessary - while (copies--) { - if (bd->outbufPos == IOBUF_SIZE) flush_bunzip_outbuf(bd,out_fd); - bd->outbuf[bd->outbufPos++] = outbyte; - bw->dataCRC = (bw->dataCRC << 8) - ^ bd->crc32Table[(bw->dataCRC >> 24) ^ outbyte]; - } - if (current!=previous) run=0; - } - - // decompression of this block completed successfully - bw->dataCRC = ~(bw->dataCRC); - bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) - ^ bw->dataCRC; - - // if this block had a crc error, force file level crc error. - if (bw->dataCRC != bw->headerCRC) { - bd->totalCRC = bw->headerCRC+1; - - return RETVAL_LAST_BLOCK; - } + unsigned int *dbuf = bw->dbuf; + int count, pos, current, run, copies, outbyte, previous, gotcount = 0; + + for (;;) { + // If last read was short due to end of file, return last block now + if (bw->writeCount < 0) return bw->writeCount; + + // If we need to refill dbuf, do it. + if (!bw->writeCount) { + int i = read_bunzip_data(bd); + if (i) { + if (i == RETVAL_LAST_BLOCK) { + bw->writeCount = i; + return gotcount; + } else return i; + } + } + + // loop generating output + count = bw->writeCount; + pos = bw->writePos; + current = bw->writeCurrent; + run = bw->writeRun; + while (count) { + + // If somebody (like tar) wants a certain number of bytes of + // data from memory instead of written to a file, humor them. + if (len && bd->outbufPos>=len) goto dataus_interruptus; + count--; + + // Follow sequence vector to undo Burrows-Wheeler transform. + previous = current; + pos = dbuf[pos]; + current = pos&0xff; + pos >>= 8; + + // Whenever we see 3 consecutive copies of the same byte, + // the 4th is a repeat count + if (run++ == 3) { + copies = current; + outbyte = previous; + current = -1; + } else { + copies = 1; + outbyte = current; + } + + // Output bytes to buffer, flushing to file if necessary + while (copies--) { + if (bd->outbufPos == IOBUF_SIZE) flush_bunzip_outbuf(bd,out_fd); + bd->outbuf[bd->outbufPos++] = outbyte; + bw->dataCRC = (bw->dataCRC << 8) + ^ bd->crc32Table[(bw->dataCRC >> 24) ^ outbyte]; + } + if (current!=previous) run=0; + } + + // decompression of this block completed successfully + bw->dataCRC = ~(bw->dataCRC); + bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ bw->dataCRC; + + // if this block had a crc error, force file level crc error. + if (bw->dataCRC != bw->headerCRC) { + bd->totalCRC = bw->headerCRC+1; + + return RETVAL_LAST_BLOCK; + } dataus_interruptus: - bw->writeCount = count; - if (len) { - gotcount += bd->outbufPos; - memcpy(outbuf, bd->outbuf, len); - - // If we got enough data, checkpoint loop state and return - if ((len-=bd->outbufPos)<1) { - bd->outbufPos -= len; - if (bd->outbufPos) - memmove(bd->outbuf, bd->outbuf+len, bd->outbufPos); - bw->writePos = pos; - bw->writeCurrent = current; - bw->writeRun = run; - - return gotcount; - } - } - } + bw->writeCount = count; + if (len) { + gotcount += bd->outbufPos; + memcpy(outbuf, bd->outbuf, len); + + // If we got enough data, checkpoint loop state and return + if ((len-=bd->outbufPos)<1) { + bd->outbufPos -= len; + if (bd->outbufPos) memmove(bd->outbuf, bd->outbuf+len, bd->outbufPos); + bw->writePos = pos; + bw->writeCurrent = current; + bw->writeRun = run; + + return gotcount; + } + } + } } -// Allocate the structure, read file header. If !len, src_fd contains -// filehandle to read from. Else inbuf contains data. +// Allocate the structure, read file header. If !len, src_fd contains +// filehandle to read from. Else inbuf contains data. int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf, int len) { - struct bunzip_data *bd; - unsigned int i; - - // Figure out how much data to allocate. - i = sizeof(struct bunzip_data); - if (!len) i += IOBUF_SIZE; - - // Allocate bunzip_data. Most fields initialize to zero. - bd = *bdp = xzalloc(i); - if (len) { - bd->inbuf = inbuf; - bd->inbufCount = len; - bd->in_fd = -1; - } else { - bd->inbuf = (char *)(bd+1); - bd->in_fd = src_fd; - } - - crc_init(bd->crc32Table, 0); - - // Ensure that file starts with "BZh". - for (i=0;i<3;i++) - if (get_bits(bd,8)!="BZh"[i]) return RETVAL_NOT_BZIP_DATA; - - // Next byte ascii '1'-'9', indicates block size in units of 100k of - // uncompressed data. Allocate intermediate buffer for block. - i = get_bits(bd, 8); - if (i<'1' || i>'9') return RETVAL_NOT_BZIP_DATA; - bd->dbufSize = 100000*(i-'0')*THREADS; - for (i=0; ibwdata[i].dbuf = xmalloc(bd->dbufSize * sizeof(int)); - - return 0; + struct bunzip_data *bd; + unsigned int i; + + // Figure out how much data to allocate. + i = sizeof(struct bunzip_data); + if (!len) i += IOBUF_SIZE; + + // Allocate bunzip_data. Most fields initialize to zero. + bd = *bdp = xzalloc(i); + if (len) { + bd->inbuf = inbuf; + bd->inbufCount = len; + bd->in_fd = -1; + } else { + bd->inbuf = (char *)(bd+1); + bd->in_fd = src_fd; + } + + crc_init(bd->crc32Table, 0); + + // Ensure that file starts with "BZh". + for (i=0;i<3;i++) if (get_bits(bd,8)!="BZh"[i]) return RETVAL_NOT_BZIP_DATA; + + // Next byte ascii '1'-'9', indicates block size in units of 100k of + // uncompressed data. Allocate intermediate buffer for block. + i = get_bits(bd, 8); + if (i<'1' || i>'9') return RETVAL_NOT_BZIP_DATA; + bd->dbufSize = 100000*(i-'0')*THREADS; + for (i=0; ibwdata[i].dbuf = xmalloc(bd->dbufSize * sizeof(int)); + + return 0; } -// Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data, +// Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data, // not end of file.) void bunzipStream(int src_fd, int dst_fd) { - struct bunzip_data *bd; - int i, j; - - if (!(i = start_bunzip(&bd,src_fd,0,0))) { - i = write_bunzip_data(bd,bd->bwdata,dst_fd,0,0); - if (i==RETVAL_LAST_BLOCK && bd->bwdata[0].headerCRC==bd->totalCRC) - i = 0; - } - flush_bunzip_outbuf(bd,dst_fd); - for (j=0; jbwdata[j].dbuf); - free(bd); - if (i) error_exit(bunzip_errors[-i]); + struct bunzip_data *bd; + int i, j; + + if (!(i = start_bunzip(&bd,src_fd,0,0))) { + i = write_bunzip_data(bd,bd->bwdata,dst_fd,0,0); + if (i==RETVAL_LAST_BLOCK && bd->bwdata[0].headerCRC==bd->totalCRC) i = 0; + } + flush_bunzip_outbuf(bd,dst_fd); + for (j=0; jbwdata[j].dbuf); + free(bd); + if (i) error_exit(bunzip_errors[-i]); } diff --git a/lib/dirtree.c b/lib/dirtree.c index 3f5a2935..d1de40ee 100644 --- a/lib/dirtree.c +++ b/lib/dirtree.c @@ -1,4 +1,3 @@ -/* vi: set sw=4 ts=4 :*/ /* dirtree.c - Functions for dealing with directory trees. * * Copyright 2007 Rob Landley @@ -12,76 +11,75 @@ struct dirtree *dirtree_add_node(int dirfd, char *name, int symfollow) { - struct dirtree *dt = NULL; - struct stat st; - char buf[4096]; - int len = 0, linklen = 0; - - if (name) { - if (fstatat(dirfd, name, &st, symfollow ? 0 : AT_SYMLINK_NOFOLLOW)) - goto error; - if (S_ISLNK(st.st_mode)) { - if (0>(linklen = readlinkat(dirfd, name, buf, 4095))) goto error; - buf[linklen++]=0; - } - len = strlen(name); - } - dt = xzalloc((len = sizeof(struct dirtree)+len+1)+linklen); - if (name) { - memcpy(&(dt->st), &st, sizeof(struct stat)); - strcpy(dt->name, name); - - if (linklen) { - dt->symlink = memcpy(len+(char *)dt, buf, linklen); - dt->data = --linklen; - } - } - - return dt; + struct dirtree *dt = NULL; + struct stat st; + char buf[4096]; + int len = 0, linklen = 0; + + if (name) { + if (fstatat(dirfd, name, &st, symfollow ? 0 : AT_SYMLINK_NOFOLLOW)) + goto error; + if (S_ISLNK(st.st_mode)) { + if (0>(linklen = readlinkat(dirfd, name, buf, 4095))) goto error; + buf[linklen++]=0; + } + len = strlen(name); + } + dt = xzalloc((len = sizeof(struct dirtree)+len+1)+linklen); + if (name) { + memcpy(&(dt->st), &st, sizeof(struct stat)); + strcpy(dt->name, name); + + if (linklen) { + dt->symlink = memcpy(len+(char *)dt, buf, linklen); + dt->data = --linklen; + } + } + + return dt; error: - perror_msg("%s",name); - free(dt); - return 0; + perror_msg("%s",name); + free(dt); + return 0; } // Return path to this node, assembled recursively. char *dirtree_path(struct dirtree *node, int *plen) { - char *path; - int len; - - if (!node || !node->name) { - path = xmalloc(*plen); - *plen = 0; - return path; - } - - len = (plen ? *plen : 0)+strlen(node->name)+1; - path = dirtree_path(node->parent, &len); - if (len && path[len-1] != '/') path[len++]='/'; - len = (stpcpy(path+len, node->name) - path); - if (plen) *plen = len; - - return path; + char *path; + int len; + + if (!node || !node->name) { + path = xmalloc(*plen); + *plen = 0; + return path; + } + + len = (plen ? *plen : 0)+strlen(node->name)+1; + path = dirtree_path(node->parent, &len); + if (len && path[len-1] != '/') path[len++]='/'; + len = (stpcpy(path+len, node->name) - path); + if (plen) *plen = len; + + return path; } // Default callback, filters out "." and "..". int dirtree_notdotdot(struct dirtree *catch) { - // Should we skip "." and ".."? - if (catch->name[0]=='.' && (!catch->name[1] || - (catch->name[1]=='.' && !catch->name[2]))) - return 0; + // Should we skip "." and ".."? + if (catch->name[0]=='.' && (!catch->name[1] || + (catch->name[1]=='.' && !catch->name[2]))) return 0; - return DIRTREE_SAVE|DIRTREE_RECURSE; + return DIRTREE_SAVE|DIRTREE_RECURSE; } int dirtree_parentfd(struct dirtree *node) { - return node->parent ? node->parent->data : AT_FDCWD; + return node->parent ? node->parent->data : AT_FDCWD; } // Handle callback for a node in the tree. Returns saved node(s) or NULL. @@ -93,69 +91,69 @@ int dirtree_parentfd(struct dirtree *node) // struct dirtree *handle_callback(struct dirtree *new, - int (*callback)(struct dirtree *node)) + int (*callback)(struct dirtree *node)) { - int flags, dir = S_ISDIR(new->st.st_mode); + int flags, dir = S_ISDIR(new->st.st_mode); - if (!callback) callback = dirtree_notdotdot; + if (!callback) callback = dirtree_notdotdot; - flags = callback(new); + flags = callback(new); - if (dir) { - if (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)) { - new->data = openat(dirtree_parentfd(new), new->name, 0); - dirtree_recurse(new, callback, flags & DIRTREE_SYMFOLLOW); - if (flags & DIRTREE_COMEAGAIN) flags = callback(new); - } - } + if (dir) { + if (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)) { + new->data = openat(dirtree_parentfd(new), new->name, 0); + dirtree_recurse(new, callback, flags & DIRTREE_SYMFOLLOW); + if (flags & DIRTREE_COMEAGAIN) flags = callback(new); + } + } - // If this had children, it was callback's job to free them already. - if (!(flags & DIRTREE_SAVE)) { - free(new); - new = NULL; - } + // If this had children, it was callback's job to free them already. + if (!(flags & DIRTREE_SAVE)) { + free(new); + new = NULL; + } - return (flags & DIRTREE_ABORT)==DIRTREE_ABORT ? DIRTREE_ABORTVAL : new; + return (flags & DIRTREE_ABORT)==DIRTREE_ABORT ? DIRTREE_ABORTVAL : new; } // Recursively read/process children of directory node (with dirfd in data), // filtering through callback(). void dirtree_recurse(struct dirtree *node, - int (*callback)(struct dirtree *node), int symfollow) + int (*callback)(struct dirtree *node), int symfollow) { - struct dirtree *new, **ddt = &(node->child); - struct dirent *entry; - DIR *dir; - - if (!(dir = fdopendir(node->data))) { - char *path = dirtree_path(node, 0); - perror_msg("No %s", path); - free(path); - close(node->data); - - return; - } - - // according to the fddir() man page, the filehandle in the DIR * can still - // be externally used by things that don't lseek() it. - - // The extra parentheses are to shut the stupid compiler up. - while ((entry = readdir(dir))) { - if (!(new = dirtree_add_node(node->data, entry->d_name, symfollow))) - continue; - new->parent = node; - new = handle_callback(new, callback); - if (new == DIRTREE_ABORTVAL) break; - if (new) { - *ddt = new; - ddt = &((*ddt)->next); - } - } - - // This closes filehandle as well, so note it - closedir(dir); - node->data = -1; + struct dirtree *new, **ddt = &(node->child); + struct dirent *entry; + DIR *dir; + + if (!(dir = fdopendir(node->data))) { + char *path = dirtree_path(node, 0); + perror_msg("No %s", path); + free(path); + close(node->data); + + return; + } + + // according to the fddir() man page, the filehandle in the DIR * can still + // be externally used by things that don't lseek() it. + + // The extra parentheses are to shut the stupid compiler up. + while ((entry = readdir(dir))) { + if (!(new = dirtree_add_node(node->data, entry->d_name, symfollow))) + continue; + new->parent = node; + new = handle_callback(new, callback); + if (new == DIRTREE_ABORTVAL) break; + if (new) { + *ddt = new; + ddt = &((*ddt)->next); + } + } + + // This closes filehandle as well, so note it + closedir(dir); + node->data = -1; } // Create dirtree from path, using callback to filter nodes. @@ -165,7 +163,7 @@ void dirtree_recurse(struct dirtree *node, struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node)) { - struct dirtree *root = dirtree_add_node(AT_FDCWD, path, 0); + struct dirtree *root = dirtree_add_node(AT_FDCWD, path, 0); - return root ? handle_callback(root, callback) : DIRTREE_ABORTVAL; + return root ? handle_callback(root, callback) : DIRTREE_ABORTVAL; } diff --git a/lib/getmountlist.c b/lib/getmountlist.c index 1b235446..efbcff13 100644 --- a/lib/getmountlist.c +++ b/lib/getmountlist.c @@ -1,4 +1,3 @@ -/* vi: set sw=4 ts=4 : */ /* getmountlist.c - Get a linked list of mount points, with stat information. * * Copyright 2006 Rob Landley @@ -16,28 +15,28 @@ char *path_mounts = "/proc/mounts"; struct mtab_list *getmountlist(int die) { - FILE *fp; - struct mtab_list *mtlist, *mt; - struct mntent me; - char evilbuf[2*PATH_MAX]; + FILE *fp; + struct mtab_list *mtlist, *mt; + struct mntent me; + char evilbuf[2*PATH_MAX]; - mtlist = 0; - if (!(fp = setmntent(path_mounts, "r"))) { - if (die) error_exit("cannot open %s", path_mounts); - } else { - while (getmntent_r(fp, &me, evilbuf, sizeof(evilbuf))) { - mt = xzalloc(sizeof(struct mtab_list) + strlen(me.mnt_fsname) + - strlen(me.mnt_dir) + strlen(me.mnt_type) + 3); - mt->next = mtlist; - // Get information about this filesystem. Yes, we need both. - stat(me.mnt_dir, &(mt->stat)); - statvfs(me.mnt_dir, &(mt->statvfs)); - // Remember information from /proc/mounts - mt->dir = stpcpy(mt->type, me.mnt_type) + 1; - mt->device = stpcpy(mt->dir, me.mnt_dir) + 1; - strcpy(mt->device, me.mnt_fsname); - mtlist = mt; - } - } - return mtlist; + mtlist = 0; + if (!(fp = setmntent(path_mounts, "r"))) { + if (die) error_exit("cannot open %s", path_mounts); + } else { + while (getmntent_r(fp, &me, evilbuf, sizeof(evilbuf))) { + mt = xzalloc(sizeof(struct mtab_list) + strlen(me.mnt_fsname) + + strlen(me.mnt_dir) + strlen(me.mnt_type) + 3); + mt->next = mtlist; + // Get information about this filesystem. Yes, we need both. + stat(me.mnt_dir, &(mt->stat)); + statvfs(me.mnt_dir, &(mt->statvfs)); + // Remember information from /proc/mounts + mt->dir = stpcpy(mt->type, me.mnt_type) + 1; + mt->device = stpcpy(mt->dir, me.mnt_dir) + 1; + strcpy(mt->device, me.mnt_fsname); + mtlist = mt; + } + } + return mtlist; } diff --git a/lib/lib.c b/lib/lib.c index 2c2ea63e..06828a40 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -1,4 +1,3 @@ -/* vi: set sw=4 ts=4 :*/ /* lib.c - reusable stuff. * * Functions with the x prefix are wrappers for library functions. They either @@ -14,257 +13,257 @@ // Strcpy with size checking: exit if there's not enough space for the string. void xstrcpy(char *dest, char *src, size_t size) { - if (strlen(src)+1 > size) error_exit("xstrcpy"); - strcpy(dest, src); + if (strlen(src)+1 > size) error_exit("xstrcpy"); + strcpy(dest, src); } void verror_msg(char *msg, int err, va_list va) { - char *s = ": %s"; + char *s = ": %s"; - fprintf(stderr, "%s: ", toys.which->name); - if (msg) vfprintf(stderr, msg, va); - else s+=2; - if (err) fprintf(stderr, s, strerror(err)); - putc('\n', stderr); + fprintf(stderr, "%s: ", toys.which->name); + if (msg) vfprintf(stderr, msg, va); + else s+=2; + if (err) fprintf(stderr, s, strerror(err)); + putc('\n', stderr); } void error_msg(char *msg, ...) { - va_list va; + va_list va; - va_start(va, msg); - verror_msg(msg, 0, va); - va_end(va); + va_start(va, msg); + verror_msg(msg, 0, va); + va_end(va); } void perror_msg(char *msg, ...) { - va_list va; + va_list va; - va_start(va, msg); - verror_msg(msg, errno, va); - va_end(va); + va_start(va, msg); + verror_msg(msg, errno, va); + va_end(va); } // Die with an error message. void error_exit(char *msg, ...) { - va_list va; + va_list va; - if (CFG_HELP && toys.exithelp) { - *toys.optargs=*toys.argv; - USE_HELP(help_main();) // dear gcc: shut up. - fprintf(stderr,"\n"); - } + if (CFG_HELP && toys.exithelp) { + *toys.optargs=*toys.argv; + USE_HELP(help_main();) // dear gcc: shut up. + fprintf(stderr,"\n"); + } - va_start(va, msg); - verror_msg(msg, 0, va); - va_end(va); + va_start(va, msg); + verror_msg(msg, 0, va); + va_end(va); - exit(!toys.exitval ? 1 : toys.exitval); + exit(!toys.exitval ? 1 : toys.exitval); } // Die with an error message and strerror(errno) void perror_exit(char *msg, ...) { - va_list va; + va_list va; - va_start(va, msg); - verror_msg(msg, errno, va); - va_end(va); + va_start(va, msg); + verror_msg(msg, errno, va); + va_end(va); - exit(!toys.exitval ? 1 : toys.exitval); + exit(!toys.exitval ? 1 : toys.exitval); } // Die unless we can allocate memory. void *xmalloc(size_t size) { - void *ret = malloc(size); - if (!ret) error_exit("xmalloc"); + void *ret = malloc(size); + if (!ret) error_exit("xmalloc"); - return ret; + return ret; } // Die unless we can allocate prezeroed memory. void *xzalloc(size_t size) { - void *ret = xmalloc(size); - memset(ret, 0, size); - return ret; + void *ret = xmalloc(size); + memset(ret, 0, size); + return ret; } // Die unless we can change the size of an existing allocation, possibly // moving it. (Notice different arguments from libc function.) void *xrealloc(void *ptr, size_t size) { - ptr = realloc(ptr, size); - if (!ptr) error_exit("xrealloc"); + ptr = realloc(ptr, size); + if (!ptr) error_exit("xrealloc"); - return ptr; + return ptr; } // Die unless we can allocate a copy of this many bytes of string. char *xstrndup(char *s, size_t n) { - char *ret = xmalloc(++n); - strncpy(ret, s, n); - ret[--n]=0; + char *ret = xmalloc(++n); + strncpy(ret, s, n); + ret[--n]=0; - return ret; + return ret; } // Die unless we can allocate a copy of this string. char *xstrdup(char *s) { - return xstrndup(s, strlen(s)); + return xstrndup(s, strlen(s)); } // Die unless we can allocate enough space to sprintf() into. char *xmsprintf(char *format, ...) { - va_list va, va2; - int len; - char *ret; + va_list va, va2; + int len; + char *ret; - va_start(va, format); - va_copy(va2, va); + va_start(va, format); + va_copy(va2, va); - // How long is it? - len = vsnprintf(0, 0, format, va); - len++; - va_end(va); + // How long is it? + len = vsnprintf(0, 0, format, va); + len++; + va_end(va); - // Allocate and do the sprintf() - ret = xmalloc(len); - vsnprintf(ret, len, format, va2); - va_end(va2); + // Allocate and do the sprintf() + ret = xmalloc(len); + vsnprintf(ret, len, format, va2); + va_end(va2); - return ret; + return ret; } void xprintf(char *format, ...) { - va_list va; - va_start(va, format); + va_list va; + va_start(va, format); - vprintf(format, va); - if (ferror(stdout)) perror_exit("write"); + vprintf(format, va); + if (ferror(stdout)) perror_exit("write"); } void xputs(char *s) { - if (EOF == puts(s)) perror_exit("write"); + if (EOF == puts(s)) perror_exit("write"); } void xputc(char c) { - if (EOF == fputc(c, stdout) || fflush(stdout)) perror_exit("write"); + if (EOF == fputc(c, stdout) || fflush(stdout)) perror_exit("write"); } void xflush(void) { - if (fflush(stdout)) perror_exit("write");; + if (fflush(stdout)) perror_exit("write");; } // Die unless we can exec argv[] (or run builtin command). Note that anything // with a path isn't a builtin, so /bin/sh won't match the builtin sh. void xexec(char **argv) { - toy_exec(argv); - execvp(argv[0], argv); + toy_exec(argv); + execvp(argv[0], argv); - perror_exit("exec %s", argv[0]); + perror_exit("exec %s", argv[0]); } void xaccess(char *path, int flags) { - if (access(path, flags)) perror_exit("Can't access '%s'", path); + if (access(path, flags)) perror_exit("Can't access '%s'", path); } // Die unless we can delete a file. (File must exist to be deleted.) void xunlink(char *path) { - if (unlink(path)) perror_exit("unlink '%s'", path); + if (unlink(path)) perror_exit("unlink '%s'", path); } // Die unless we can open/create a file, returning file descriptor. int xcreate(char *path, int flags, int mode) { - int fd = open(path, flags, mode); - if (fd == -1) perror_exit("%s", path); - return fd; + int fd = open(path, flags, mode); + if (fd == -1) perror_exit("%s", path); + return fd; } // Die unless we can open a file, returning file descriptor. int xopen(char *path, int flags) { - return xcreate(path, flags, 0); + return xcreate(path, flags, 0); } void xclose(int fd) { - if (close(fd)) perror_exit("xclose"); + if (close(fd)) perror_exit("xclose"); } int xdup(int fd) { - if (fd != -1) { - fd = dup(fd); - if (fd == -1) perror_exit("xdup"); - } - return fd; + if (fd != -1) { + fd = dup(fd); + if (fd == -1) perror_exit("xdup"); + } + return fd; } // Die unless we can open/create a file, returning FILE *. FILE *xfopen(char *path, char *mode) { - FILE *f = fopen(path, mode); - if (!f) perror_exit("No file %s", path); - return f; + FILE *f = fopen(path, mode); + if (!f) perror_exit("No file %s", path); + return f; } // Keep reading until full or EOF ssize_t readall(int fd, void *buf, size_t len) { - size_t count = 0; + size_t count = 0; - while (count= lseek(fd, offset, SEEK_END) - && offset+and == lseek(fd, offset+and, SEEK_SET)) return 0; - else { - char buf[4096]; - while (offset>0) { - int try = offset>sizeof(buf) ? sizeof(buf) : offset, or; + if (and != -1 && offset >= lseek(fd, offset, SEEK_END) + && offset+and == lseek(fd, offset+and, SEEK_SET)) return 0; + else { + char buf[4096]; + while (offset>0) { + int try = offset>sizeof(buf) ? sizeof(buf) : offset, or; - or = readall(fd, buf, try); - if (or < 0) perror_msg("lskip to %lld", (long long)offset); - else offset -= try; - if (or < try) break; - } + or = readall(fd, buf, try); + if (or < 0) perror_msg("lskip to %lld", (long long)offset); + else offset -= try; + if (or < try) break; + } - return offset; - } + return offset; + } } char *xgetcwd(void) { - char *buf = getcwd(NULL, 0); - if (!buf) perror_exit("xgetcwd"); + char *buf = getcwd(NULL, 0); + if (!buf) perror_exit("xgetcwd"); - return buf; + return buf; } void xstat(char *path, struct stat *st) { - if(stat(path, st)) perror_exit("Can't stat %s", path); + if(stat(path, st)) perror_exit("Can't stat %s", path); } // Cannonicalizes path by removing ".", "..", and "//" elements. This is not @@ -325,60 +324,60 @@ void xstat(char *path, struct stat *st) // following symlinks. char *xabspath(char *path) { - char *from, *to; - - // If this isn't an absolute path, make it one with cwd. - if (path[0]!='/') { - char *cwd=xgetcwd(); - path = xmsprintf("%s/%s", cwd, path); - free(cwd); - } else path = xstrdup(path); - - // Loop through path elements - from = to = path; - while (*from) { - - // Continue any current path component. - if (*from!='/') { - *(to++) = *(from++); - continue; - } - - // Skip duplicate slashes. - while (*from=='/') from++; - - // Start of a new filename. Handle . and .. - while (*from=='.') { - // Skip . - if (from[1]=='/') from += 2; - else if (!from[1]) from++; - // Back up for .. - else if (from[1]=='.') { - if (from[2]=='/') from +=3; - else if(!from[2]) from+=2; - else break; - while (to>path && *(--to)!='/'); - } else break; - } - // Add directory separator slash. - *(to++) = '/'; - } - *to = 0; - - return path; + char *from, *to; + + // If this isn't an absolute path, make it one with cwd. + if (path[0]!='/') { + char *cwd=xgetcwd(); + path = xmsprintf("%s/%s", cwd, path); + free(cwd); + } else path = xstrdup(path); + + // Loop through path elements + from = to = path; + while (*from) { + + // Continue any current path component. + if (*from!='/') { + *(to++) = *(from++); + continue; + } + + // Skip duplicate slashes. + while (*from=='/') from++; + + // Start of a new filename. Handle . and .. + while (*from=='.') { + // Skip . + if (from[1]=='/') from += 2; + else if (!from[1]) from++; + // Back up for .. + else if (from[1]=='.') { + if (from[2]=='/') from +=3; + else if(!from[2]) from+=2; + else break; + while (to>path && *(--to)!='/'); + } else break; + } + // Add directory separator slash. + *(to++) = '/'; + } + *to = 0; + + return path; } // Resolve all symlinks, returning malloc() memory. char *xrealpath(char *path) { - char *new = realpath(path, NULL); - if (!new) perror_exit("realpath '%s'", path); - return new; + char *new = realpath(path, NULL); + if (!new) perror_exit("realpath '%s'", path); + return new; } void xchdir(char *path) { - if (chdir(path)) error_exit("chdir '%s'", path); + if (chdir(path)) error_exit("chdir '%s'", path); } // Ensure entire path exists. @@ -386,27 +385,27 @@ void xchdir(char *path) // Requires that path string be writable (for temporary null terminators). void xmkpath(char *path, int mode) { - char *p, old; - mode_t mask; - int rc; - struct stat st; - - for (p = path; ; p++) { - if (!*p || *p == '/') { - old = *p; - *p = rc = 0; - if (stat(path, &st) || !S_ISDIR(st.st_mode)) { - if (mode != -1) { - mask=umask(0); - rc = mkdir(path, mode); - umask(mask); - } else rc = mkdir(path, 0777); - } - *p = old; - if(rc) perror_exit("mkpath '%s'", path); - } - if (!*p) break; - } + char *p, old; + mode_t mask; + int rc; + struct stat st; + + for (p = path; ; p++) { + if (!*p || *p == '/') { + old = *p; + *p = rc = 0; + if (stat(path, &st) || !S_ISDIR(st.st_mode)) { + if (mode != -1) { + mask=umask(0); + rc = mkdir(path, mode); + umask(mask); + } else rc = mkdir(path, 0777); + } + *p = old; + if(rc) perror_exit("mkpath '%s'", path); + } + if (!*p) break; + } } // setuid() can fail (for example, too many processes belonging to that user), @@ -414,7 +413,7 @@ void xmkpath(char *path, int mode) void xsetuid(uid_t uid) { - if (setuid(uid)) perror_exit("xsetuid"); + if (setuid(uid)) perror_exit("xsetuid"); } @@ -424,40 +423,40 @@ void xsetuid(uid_t uid) struct string_list *find_in_path(char *path, char *filename) { - struct string_list *rlist = NULL, **prlist=&rlist; - char *cwd = xgetcwd(); - - for (;;) { - char *next = path ? strchr(path, ':') : NULL; - int len = next ? next-path : strlen(path); - struct string_list *rnext; - struct stat st; - - rnext = xmalloc(sizeof(void *) + strlen(filename) - + (len ? len : strlen(cwd)) + 2); - if (!len) sprintf(rnext->str, "%s/%s", cwd, filename); - else { - char *res = rnext->str; - strncpy(res, path, len); - res += len; - *(res++) = '/'; - strcpy(res, filename); - } - - // Confirm it's not a directory. - if (!stat(rnext->str, &st) && S_ISREG(st.st_mode)) { - *prlist = rnext; - rnext->next = NULL; - prlist = &(rnext->next); - } else free(rnext); - - if (!next) break; - path += len; - path++; - } - free(cwd); - - return rlist; + struct string_list *rlist = NULL, **prlist=&rlist; + char *cwd = xgetcwd(); + + for (;;) { + char *next = path ? strchr(path, ':') : NULL; + int len = next ? next-path : strlen(path); + struct string_list *rnext; + struct stat st; + + rnext = xmalloc(sizeof(void *) + strlen(filename) + + (len ? len : strlen(cwd)) + 2); + if (!len) sprintf(rnext->str, "%s/%s", cwd, filename); + else { + char *res = rnext->str; + strncpy(res, path, len); + res += len; + *(res++) = '/'; + strcpy(res, filename); + } + + // Confirm it's not a directory. + if (!stat(rnext->str, &st) && S_ISREG(st.st_mode)) { + *prlist = rnext; + rnext->next = NULL; + prlist = &(rnext->next); + } else free(rnext); + + if (!next) break; + path += len; + path++; + } + free(cwd); + + return rlist; } // Convert unsigned int to ascii, writing into supplied buffer. A truncated @@ -465,31 +464,31 @@ struct string_list *find_in_path(char *path, char *filename) // always null terminated (unless buflen is 0). void utoa_to_buf(unsigned n, char *buf, unsigned buflen) { - int i, out = 0; + int i, out = 0; - if (buflen) { - for (i=1000000000; i; i/=10) { - int res = n/i; + if (buflen) { + for (i=1000000000; i; i/=10) { + int res = n/i; - if ((res || out || i == 1) && --buflen>0) { - out++; - n -= res*i; - *buf++ = '0' + res; - } - } - *buf = 0; - } + if ((res || out || i == 1) && --buflen>0) { + out++; + n -= res*i; + *buf++ = '0' + res; + } + } + *buf = 0; + } } // Convert signed integer to ascii, using utoa_to_buf() void itoa_to_buf(int n, char *buf, unsigned buflen) { - if (buflen && n<0) { - n = -n; - *buf++ = '-'; - buflen--; - } - utoa_to_buf((unsigned)n, buf, buflen); + if (buflen && n<0) { + n = -n; + *buf++ = '-'; + buflen--; + } + utoa_to_buf((unsigned)n, buf, buflen); } // This static buffer is used by both utoa() and itoa(), calling either one a @@ -504,122 +503,122 @@ static char itoa_buf[12]; // Convert unsigned integer to ascii, returning a static buffer. char *utoa(unsigned n) { - utoa_to_buf(n, itoa_buf, sizeof(itoa_buf)); + utoa_to_buf(n, itoa_buf, sizeof(itoa_buf)); - return itoa_buf; + return itoa_buf; } char *itoa(int n) { - itoa_to_buf(n, itoa_buf, sizeof(itoa_buf)); + itoa_to_buf(n, itoa_buf, sizeof(itoa_buf)); - return itoa_buf; + return itoa_buf; } // atol() with the kilo/mega/giga/tera/peta/exa extensions. // (zetta and yotta don't fit in 64 bits.) long atolx(char *numstr) { - char *c, *suffixes="bkmgtpe", *end; - long val = strtol(numstr, &c, 0); + char *c, *suffixes="bkmgtpe", *end; + long val = strtol(numstr, &c, 0); - if (*c) { - if (c != numstr && (end = strchr(suffixes, tolower(*c)))) { - int shift = end-suffixes; - if (shift--) val *= 1024L<<(shift*10); - } else { - while (isspace(*c)) c++; - if (*c) error_exit("not integer: %s", numstr); - } - } + if (*c) { + if (c != numstr && (end = strchr(suffixes, tolower(*c)))) { + int shift = end-suffixes; + if (shift--) val *= 1024L<<(shift*10); + } else { + while (isspace(*c)) c++; + if (*c) error_exit("not integer: %s", numstr); + } + } - return val; + return val; } int numlen(long l) { - int len = 0; - while (l) { - l /= 10; - len++; - } - return len; + int len = 0; + while (l) { + l /= 10; + len++; + } + return len; } int stridx(char *haystack, char needle) { - char *off; + char *off; - if (!needle) return -1; - off = strchr(haystack, needle); - if (!off) return -1; + if (!needle) return -1; + off = strchr(haystack, needle); + if (!off) return -1; - return off-haystack; + return off-haystack; } // Return how long the file at fd is, if there's any way to determine it. off_t fdlength(int fd) { - off_t bottom = 0, top = 0, pos, old; - int size; + off_t bottom = 0, top = 0, pos, old; + int size; - // If the ioctl works for this, return it. + // If the ioctl works for this, return it. - if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512L; + if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512L; - // If not, do a binary search for the last location we can read. (Some - // block devices don't do BLKGETSIZE right.) This should probably have - // a CONFIG option... + // If not, do a binary search for the last location we can read. (Some + // block devices don't do BLKGETSIZE right.) This should probably have + // a CONFIG option... - old = lseek(fd, 0, SEEK_CUR); - do { - char temp; + old = lseek(fd, 0, SEEK_CUR); + do { + char temp; - pos = bottom + (top - bottom) / 2; + pos = bottom + (top - bottom) / 2; - // If we can read from the current location, it's bigger. + // If we can read from the current location, it's bigger. - if (lseek(fd, pos, 0)>=0 && read(fd, &temp, 1)==1) { - if (bottom == top) bottom = top = (top+1) * 2; - else bottom = pos; + if (lseek(fd, pos, 0)>=0 && read(fd, &temp, 1)==1) { + if (bottom == top) bottom = top = (top+1) * 2; + else bottom = pos; - // If we can't, it's smaller. + // If we can't, it's smaller. - } else { - if (bottom == top) { - if (!top) return 0; - bottom = top/2; - } else top = pos; - } - } while (bottom + 1 != top); + } else { + if (bottom == top) { + if (!top) return 0; + bottom = top/2; + } else top = pos; + } + } while (bottom + 1 != top); - lseek(fd, old, SEEK_SET); + lseek(fd, old, SEEK_SET); - return pos + 1; + return pos + 1; } // This can return null (meaning file not found). It just won't return null // for memory allocation reasons. char *xreadlink(char *name) { - int len, size = 0; - char *buf = 0; + int len, size = 0; + char *buf = 0; - // Grow by 64 byte chunks until it's big enough. - for(;;) { - size +=64; - buf = xrealloc(buf, size); - len = readlink(name, buf, size); + // Grow by 64 byte chunks until it's big enough. + for(;;) { + size +=64; + buf = xrealloc(buf, size); + len = readlink(name, buf, size); - if (len<0) { - free(buf); - return 0; - } - if (len(fd = open(*argv, flags, permissions)) && !failok) { - perror_msg("%s", *argv); - toys.exitval = 1; - continue; - } - function(fd, *argv); - if (flags == O_RDONLY) close(fd); - } while (*++argv); + if (!strcmp(*argv,"-")) fd=0; + else if (0>(fd = open(*argv, flags, permissions)) && !failok) { + perror_msg("%s", *argv); + toys.exitval = 1; + continue; + } + function(fd, *argv); + if (flags == O_RDONLY) close(fd); + } while (*++argv); } // Call loopfiles_rw with O_RDONLY and !failok (common case). void loopfiles(char **argv, void (*function)(int fd, char *name)) { - loopfiles_rw(argv, O_RDONLY, 0, 0, function); + loopfiles_rw(argv, O_RDONLY, 0, 0, function); } // Slow, but small. char *get_rawline(int fd, long *plen, char end) { - char c, *buf = NULL; - long len = 0; + char c, *buf = NULL; + long len = 0; - for (;;) { - if (1>read(fd, &c, 1)) break; - if (!(len & 63)) buf=xrealloc(buf, len+65); - if ((buf[len++]=c) == end) break; - } - if (buf) buf[len]=0; - if (plen) *plen = len; + for (;;) { + if (1>read(fd, &c, 1)) break; + if (!(len & 63)) buf=xrealloc(buf, len+65); + if ((buf[len++]=c) == end) break; + } + if (buf) buf[len]=0; + if (plen) *plen = len; - return buf; + return buf; } char *get_line(int fd) { - long len; - char *buf = get_rawline(fd, &len, '\n'); + long len; + char *buf = get_rawline(fd, &len, '\n'); - if (buf && buf[--len]=='\n') buf[len]=0; + if (buf && buf[--len]=='\n') buf[len]=0; - return buf; + return buf; } // Copy the rest of in to out and close both files. void xsendfile(int in, int out) { - long len; - char buf[4096]; + long len; + char buf[4096]; - if (in<0) return; - for (;;) { - len = xread(in, buf, 4096); - if (len<1) break; - xwrite(out, buf, len); - } + if (in<0) return; + for (;;) { + len = xread(in, buf, 4096); + if (len<1) break; + xwrite(out, buf, len); + } } int wfchmodat(int fd, char *name, mode_t mode) { - int rc = fchmodat(fd, name, mode, 0); + int rc = fchmodat(fd, name, mode, 0); - if (rc) { - perror_msg("chmod '%s' to %04o", name, mode); - toys.exitval=1; - } - return rc; + if (rc) { + perror_msg("chmod '%s' to %04o", name, mode); + toys.exitval=1; + } + return rc; } static char *tempfile2zap; static void tempfile_handler(int i) { - if (1 < (long)tempfile2zap) unlink(tempfile2zap); - _exit(1); + if (1 < (long)tempfile2zap) unlink(tempfile2zap); + _exit(1); } // Open a temporary file to copy an existing file into. int copy_tempfile(int fdin, char *name, char **tempname) { - struct stat statbuf; - int fd; + struct stat statbuf; + int fd; - *tempname = xstrndup(name, strlen(name)+6); - strcat(*tempname,"XXXXXX"); - if(-1 == (fd = mkstemp(*tempname))) error_exit("no temp file"); - if (!tempfile2zap) sigatexit(tempfile_handler); - tempfile2zap = *tempname; + *tempname = xstrndup(name, strlen(name)+6); + strcat(*tempname,"XXXXXX"); + if(-1 == (fd = mkstemp(*tempname))) error_exit("no temp file"); + if (!tempfile2zap) sigatexit(tempfile_handler); + tempfile2zap = *tempname; - // Set permissions of output file + // Set permissions of output file - fstat(fdin, &statbuf); - fchmod(fd, statbuf.st_mode); + fstat(fdin, &statbuf); + fchmod(fd, statbuf.st_mode); - return fd; + return fd; } // Abort the copy and delete the temporary file. void delete_tempfile(int fdin, int fdout, char **tempname) { - close(fdin); - close(fdout); - unlink(*tempname); - tempfile2zap = (char *)1; - free(*tempname); - *tempname = NULL; + close(fdin); + close(fdout); + unlink(*tempname); + tempfile2zap = (char *)1; + free(*tempname); + *tempname = NULL; } // Copy the rest of the data and replace the original with the copy. void replace_tempfile(int fdin, int fdout, char **tempname) { - char *temp = xstrdup(*tempname); + char *temp = xstrdup(*tempname); - temp[strlen(temp)-6]=0; - if (fdin != -1) { - xsendfile(fdin, fdout); - xclose(fdin); - } - xclose(fdout); - rename(*tempname, temp); - tempfile2zap = (char *)1; - free(*tempname); - free(temp); - *tempname = NULL; + temp[strlen(temp)-6]=0; + if (fdin != -1) { + xsendfile(fdin, fdout); + xclose(fdin); + } + xclose(fdout); + rename(*tempname, temp); + tempfile2zap = (char *)1; + free(*tempname); + free(temp); + *tempname = NULL; } // Create a 256 entry CRC32 lookup table. void crc_init(unsigned int *crc_table, int little_endian) { - unsigned int i; + unsigned int i; - // Init the CRC32 table (big endian) - for (i=0; i<256; i++) { - unsigned int j, c = little_endian ? i : i<<24; - for (j=8; j; j--) - if (little_endian) c = (c&1) ? (c>>1)^0xEDB88320 : c>>1; - else c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1); - crc_table[i] = c; - } + // Init the CRC32 table (big endian) + for (i=0; i<256; i++) { + unsigned int j, c = little_endian ? i : i<<24; + for (j=8; j; j--) + if (little_endian) c = (c&1) ? (c>>1)^0xEDB88320 : c>>1; + else c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1); + crc_table[i] = c; + } } // Quick and dirty query size of terminal, doesn't do ANSI probe fallback. @@ -850,86 +849,85 @@ void crc_init(unsigned int *crc_table, int little_endian) void terminal_size(unsigned *x, unsigned *y) { - struct winsize ws; - int i; + struct winsize ws; + int i; - //memset(&ws, 0, sizeof(ws)); - for (i=0; i<3; i++) { - if (ioctl(i, TIOCGWINSZ, &ws)) continue; - if (x) *x = ws.ws_col; - if (y) *y = ws.ws_row; - } - if (x) { - char *s = getenv("COLUMNS"); + //memset(&ws, 0, sizeof(ws)); + for (i=0; i<3; i++) { + if (ioctl(i, TIOCGWINSZ, &ws)) continue; + if (x) *x = ws.ws_col; + if (y) *y = ws.ws_row; + } + if (x) { + char *s = getenv("COLUMNS"); - i = s ? atoi(s) : 0; - if (i>0) *x = i; - } - if (y) { - char *s = getenv("ROWS"); + i = s ? atoi(s) : 0; + if (i>0) *x = i; + } + if (y) { + char *s = getenv("ROWS"); - i = s ? atoi(s) : 0; - if (i>0) *y = i; - } + i = s ? atoi(s) : 0; + if (i>0) *y = i; + } } // This should use a raw tty, fixit later. int yesno(char *prompt, int def) { - FILE *fps[] = {stdin, stdout, stderr}; - int i; - char buf; + FILE *fps[] = {stdin, stdout, stderr}; + int i; + char buf; - for (i=0; i<3; i++) if (isatty(i)) break; - if (i == 3) return 1; + for (i=0; i<3; i++) if (isatty(i)) break; + if (i == 3) return 1; - fprintf(fps[i], "%s (%c/%c):", prompt, def ? 'Y' : 'y', def ? 'n' : 'N'); - fflush(fps[i]); - while (fread(&buf, 1, 1, fps[i])) { - if (tolower(buf) == 'y') def = 1; - if (tolower(buf) == 'n') def = 0; - else if (!isspace(buf)) continue; + fprintf(fps[i], "%s (%c/%c):", prompt, def ? 'Y' : 'y', def ? 'n' : 'N'); + fflush(fps[i]); + while (fread(&buf, 1, 1, fps[i])) { + if (tolower(buf) == 'y') def = 1; + if (tolower(buf) == 'n') def = 0; + else if (!isspace(buf)) continue; - break; - } + break; + } - return def; + return def; } // Execute a callback for each PID that matches a process name from a list. void for_each_pid_with_name_in(char **names, void (*callback)(pid_t pid)) { - DIR *dp; - struct dirent *entry; - char cmd[sizeof(toybuf)], path[64]; - char **curname; + DIR *dp; + struct dirent *entry; + char cmd[sizeof(toybuf)], path[64]; + char **curname; - if (!(dp = opendir("/proc"))) perror_exit("opendir"); + if (!(dp = opendir("/proc"))) perror_exit("opendir"); - while ((entry = readdir(dp))) { - int fd, n; + while ((entry = readdir(dp))) { + int fd, n; - if (!isdigit(*entry->d_name)) continue; + if (!isdigit(*entry->d_name)) continue; - if (sizeof(path) <= snprintf(path, sizeof(path), "/proc/%s/cmdline", - entry->d_name)) continue; + if (sizeof(path) <= snprintf(path, sizeof(path), "/proc/%s/cmdline", + entry->d_name)) continue; - if (-1 == (fd=open(path, O_RDONLY))) continue; - n = read(fd, cmd, sizeof(cmd)); - close(fd); - if (n<1) continue; + if (-1 == (fd=open(path, O_RDONLY))) continue; + n = read(fd, cmd, sizeof(cmd)); + close(fd); + if (n<1) continue; - for (curname = names; *curname; curname++) - if (!strcmp(basename(cmd), *curname)) - callback(atol(entry->d_name)); - } + for (curname = names; *curname; curname++) + if (!strcmp(basename(cmd), *curname)) callback(atol(entry->d_name)); + } - closedir(dp); + closedir(dp); } struct signame { - int num; - char *name; + int num; + char *name; }; // Signals required by POSIX 2008: @@ -938,16 +936,16 @@ struct signame { #define SIGNIFY(x) {SIG##x, #x} static struct signame signames[] = { - SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS), - SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL), - SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM), - SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP), - SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ), + SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS), + SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL), + SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM), + SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP), + SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ), - // Start of non-terminal signals + // Start of non-terminal signals - SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP), - SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG) + SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP), + SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG) }; // not in posix: SIGNIFY(STKFLT), SIGNIFY(WINCH), SIGNIFY(IO), SIGNIFY(PWR) @@ -956,147 +954,144 @@ static struct signame signames[] = { // Install the same handler on every signal that defaults to killing the process void sigatexit(void *handler) { - int i; - for (i=0; signames[i].num != SIGCHLD; i++) - signal(signames[i].num, handler); + int i; + for (i=0; signames[i].num != SIGCHLD; i++) signal(signames[i].num, handler); } // Convert name to signal number. If name == NULL print names. int sig_to_num(char *pidstr) { - int i; + int i; - if (pidstr) { - char *s; - i = strtol(pidstr, &s, 10); - if (!*s) return i; + if (pidstr) { + char *s; + i = strtol(pidstr, &s, 10); + if (!*s) return i; - if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3; - } - for (i = 0; i < sizeof(signames)/sizeof(struct signame); i++) - if (!pidstr) xputs(signames[i].name); - else if (!strcasecmp(pidstr, signames[i].name)) - return signames[i].num; + if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3; + } + for (i = 0; i < sizeof(signames)/sizeof(struct signame); i++) + if (!pidstr) xputs(signames[i].name); + else if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num; - return -1; + return -1; } char *num_to_sig(int sig) { - int i; + int i; - for (i=0; i>(3*(s-whys)))&7; - str++; - } - - // Are we ready to do a thing yet? - if (*str && *(str++) != ',') goto barf; - - // Ok, apply the bits to the mode. - for (i=0; i<4; i++) { - for (j=0; j<3; j++) { - mode_t bit = 0; - int where = 1<<((3*i)+j); - - if (amask & where) continue; - - // Figure out new value at this location - if (i == 3) { - // suid/sticky bit. - if (j) { - if ((dowhat & 8) && (dowho&(8|(1<>(3*(s-whys)))&7; + str++; + } + + // Are we ready to do a thing yet? + if (*str && *(str++) != ',') goto barf; + + // Ok, apply the bits to the mode. + for (i=0; i<4; i++) { + for (j=0; j<3; j++) { + mode_t bit = 0; + int where = 1<<((3*i)+j); + + if (amask & where) continue; + + // Figure out new value at this location + if (i == 3) { + // suid/sticky bit. + if (j) { + if ((dowhat & 8) && (dowho&(8|(1<= 1024) { + frac = size%1024; + size /= 1024; + index++; } - else { - static char units[] = {'\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'}; - int index = 0; - while(size >= 1024) { - frac = size%1024; - size /= 1024; - index++; - } - frac = (frac/102) + ((frac%102)?1:0); - if(frac >= 10) { - size += 1; - frac = 0; - } - if(frac) return xmsprintf("%llu.%u%c", size, frac, units[index]); - else return xmsprintf("%llu%c", size, units[index]); + frac = (frac/102) + ((frac%102)?1:0); + if(frac >= 10) { + size += 1; + frac = 0; } - return NULL; //not reached + if(frac) return xmsprintf("%llu.%u%c", size, frac, units[index]); + else return xmsprintf("%llu%c", size, units[index]); + } + return NULL; //not reached } diff --git a/lib/lib.h b/lib/lib.h index d81e2d94..2b452566 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -1,4 +1,3 @@ -/* vi: set ts=4 :*/ /* lib.h - header file for lib directory * * Copyright 2006 Rob Landley @@ -21,18 +20,18 @@ ssize_t getline(char **lineptr, size_t *n, FILE *stream); // is always next pointer, so next = (mytype *)&struct. struct string_list { - struct string_list *next; - char str[0]; + struct string_list *next; + char str[0]; }; struct arg_list { - struct arg_list *next; - char *arg; + struct arg_list *next; + char *arg; }; struct double_list { - struct double_list *next, *prev; - char *data; + struct double_list *next, *prev; + char *data; }; void llist_traverse(void *list, void (*using)(void *data)); @@ -63,12 +62,12 @@ void get_optflags(void); #define DIRTREE_ABORTVAL ((struct dirtree *)1) struct dirtree { - struct dirtree *next, *parent, *child; - long extra; // place for user to store their stuff (can be pointer) - struct stat st; - char *symlink; - int data; // dirfd for directory, linklen for symlink, -1 = comeagain - char name[]; + struct dirtree *next, *parent, *child; + long extra; // place for user to store their stuff (can be pointer) + struct stat st; + char *symlink; + int data; // dirfd for directory, linklen for symlink, -1 = comeagain + char name[]; }; struct dirtree *dirtree_add_node(int dirfd, char *name, int symfollow); @@ -76,9 +75,9 @@ char *dirtree_path(struct dirtree *node, int *plen); int dirtree_notdotdot(struct dirtree *catch); int dirtree_parentfd(struct dirtree *node); struct dirtree *handle_callback(struct dirtree *new, - int (*callback)(struct dirtree *node)); + int (*callback)(struct dirtree *node)); void dirtree_recurse(struct dirtree *node, - int (*callback)(struct dirtree *node), int symfollow); + int (*callback)(struct dirtree *node), int symfollow); struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node)); // lib.c @@ -133,7 +132,7 @@ int stridx(char *haystack, char needle); off_t fdlength(int fd); char *xreadlink(char *name); void loopfiles_rw(char **argv, int flags, int permissions, int failok, - void (*function)(int fd, char *name)); + void (*function)(int fd, char *name)); void loopfiles(char **argv, void (*function)(int fd, char *name)); char *get_rawline(int fd, long *plen, char end); char *get_line(int fd); @@ -150,12 +149,12 @@ void for_each_pid_with_name_in(char **names, void (*callback)(pid_t pid)); // getmountlist.c struct mtab_list { - struct mtab_list *next; - struct stat stat; - struct statvfs statvfs; - char *dir; - char *device; - char type[0]; + struct mtab_list *next; + struct stat stat; + struct statvfs statvfs; + char *dir; + char *device; + char type[0]; }; struct mtab_list *getmountlist(int die); diff --git a/lib/llist.c b/lib/llist.c index 4799db1c..9b6c2950 100644 --- a/lib/llist.c +++ b/lib/llist.c @@ -1,5 +1,4 @@ -/* vi: set sw=4 ts=4 : - * llist.c - Linked list functions +/* llist.c - Linked list functions * * Linked list structures have a next pointer as their first element. */ @@ -9,47 +8,47 @@ // Call a function (such as free()) on each element of a linked list. void llist_traverse(void *list, void (*using)(void *data)) { - while (list) { - void *pop = llist_pop(&list); - using(pop); + while (list) { + void *pop = llist_pop(&list); + using(pop); - // End doubly linked list too. - if (list==pop) break; - } + // End doubly linked list too. + if (list==pop) break; + } } // Return the first item from the list, advancing the list (which must be called // as &list) void *llist_pop(void *list) { - // I'd use a void ** for the argument, and even accept the typecast in all - // callers as documentation you need the &, except the stupid compiler - // would then scream about type-punned pointers. Screw it. - void **llist = (void **)list; - void **next = (void **)*llist; - *llist = *next; - - return (void *)next; + // I'd use a void ** for the argument, and even accept the typecast in all + // callers as documentation you need the &, except the stupid compiler + // would then scream about type-punned pointers. Screw it. + void **llist = (void **)list; + void **next = (void **)*llist; + *llist = *next; + + return (void *)next; } void dlist_add_nomalloc(struct double_list **list, struct double_list *new) { - if (*list) { - new->next = *list; - new->prev = (*list)->prev; - (*list)->prev->next = new; - (*list)->prev = new; - } else *list = new->next = new->prev = new; + if (*list) { + new->next = *list; + new->prev = (*list)->prev; + (*list)->prev->next = new; + (*list)->prev = new; + } else *list = new->next = new->prev = new; } // Add an entry to the end of a doubly linked list struct double_list *dlist_add(struct double_list **list, char *data) { - struct double_list *new = xmalloc(sizeof(struct double_list)); + struct double_list *new = xmalloc(sizeof(struct double_list)); - new->data = data; - dlist_add_nomalloc(list, new); + new->data = data; + dlist_add_nomalloc(list, new); - return new; + return new; } diff --git a/lib/password.c b/lib/password.c index 8221a022..d1489eb3 100644 --- a/lib/password.c +++ b/lib/password.c @@ -1,5 +1,4 @@ -/* vi: set sw=4 ts=4 : - * pwdutils.c - password read/update helper functions. +/* pwdutils.c - password read/update helper functions. * * Copyright 2012 Ashwini Kumar */ @@ -7,136 +6,131 @@ #include "toys.h" #include - int read_password(char * buff, int buflen, char* mesg) -{ - int i = 0; - struct termios termio, oldtermio; - tcgetattr(0, &oldtermio); - tcflush(0, TCIFLUSH); - termio = oldtermio; - - termio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); - termio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); - tcsetattr(0, TCSANOW, &termio); - - fputs(mesg, stdout); - fflush(stdout); - - while (1) { - int ret = read(0, &buff[i], 1); - if ( ret < 0 ) { - buff[0] = 0; - tcsetattr(0, TCSANOW, &oldtermio); - return 1; - } - else if ( ret == 0 || buff[i] == '\n' || - buff[i] == '\r' || buflen == i+1) { - buff[i] = '\0'; - break; - } - i++; - } - - tcsetattr(0, TCSANOW, &oldtermio); - puts(""); - fflush(stdout); - return 0; +{ + int i = 0; + struct termios termio, oldtermio; + tcgetattr(0, &oldtermio); + tcflush(0, TCIFLUSH); + termio = oldtermio; + + termio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); + termio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); + tcsetattr(0, TCSANOW, &termio); + + fputs(mesg, stdout); + fflush(stdout); + + while (1) { + int ret = read(0, &buff[i], 1); + if ( ret < 0 ) { + buff[0] = 0; + tcsetattr(0, TCSANOW, &oldtermio); + return 1; + } else if (ret == 0 || buff[i] == '\n' || buff[i] == '\r' || buflen == i+1) + { + buff[i] = '\0'; + break; + } + i++; + } + + tcsetattr(0, TCSANOW, &oldtermio); + puts(""); + fflush(stdout); + return 0; } static char *get_nextcolon(const char *line, char delim) { - char *current_ptr = NULL; - if((current_ptr = strchr(line, ':')) == NULL) - error_exit("Invalid Entry\n"); - return current_ptr; + char *current_ptr = NULL; + if((current_ptr = strchr(line, ':')) == NULL) error_exit("Invalid Entry\n"); + return current_ptr; } int update_password(char *filename, char* username, char* encrypted) { - char *filenamesfx = NULL, *namesfx = NULL; - char *shadow = NULL, *sfx = NULL; - FILE *exfp, *newfp; - int ret = -1; //fail - struct flock lock; - char *line = NULL; - - shadow = strstr(filename, "shadow"); - filenamesfx = xmsprintf("%s+", filename); - sfx = strchr(filenamesfx, '+'); - - exfp = fopen(filename, "r+"); - if(!exfp) { - perror_msg("Couldn't open file %s",filename); - goto free_storage; + char *filenamesfx = NULL, *namesfx = NULL; + char *shadow = NULL, *sfx = NULL; + FILE *exfp, *newfp; + int ret = -1; //fail + struct flock lock; + char *line = NULL; + + shadow = strstr(filename, "shadow"); + filenamesfx = xmsprintf("%s+", filename); + sfx = strchr(filenamesfx, '+'); + + exfp = fopen(filename, "r+"); + if(!exfp) { + perror_msg("Couldn't open file %s",filename); + goto free_storage; + } + + *sfx = '-'; + ret = unlink(filenamesfx); + ret = link(filename, filenamesfx); + if(ret < 0) error_msg("can't create backup file"); + + *sfx = '+'; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + + ret = fcntl(fileno(exfp), F_SETLK, &lock); + if(ret < 0) perror_msg("Couldn't lock file %s",filename); + + lock.l_type = F_UNLCK; //unlocking at a later stage + + newfp = fopen(filenamesfx, "w+"); + if(!newfp) { + error_msg("couldn't open file for writing"); + ret = -1; + fclose(exfp); + goto free_storage; + } + + ret = 0; + namesfx = xmsprintf("%s:",username); + while((line = get_line(fileno(exfp))) != NULL) + { + if(strncmp(line, namesfx, strlen(namesfx)) != 0) + fprintf(newfp, "%s\n", line); + else { + char *current_ptr = NULL; + fprintf(newfp, "%s%s:",namesfx,encrypted); + current_ptr = get_nextcolon(line, ':'); //past username + current_ptr++; //past colon ':' after username + current_ptr = get_nextcolon(current_ptr, ':'); //past passwd + current_ptr++; //past colon ':' after passwd + if(shadow) { + fprintf(newfp, "%u:",(unsigned)(time(NULL))/(24*60*60)); + current_ptr = get_nextcolon(current_ptr, ':'); + current_ptr++; //past time stamp colon. + fprintf(newfp, "%s\n",current_ptr); + } + else fprintf(newfp, "%s\n",current_ptr); } - *sfx = '-'; - ret = unlink(filenamesfx); - ret = link(filename, filenamesfx); - if(ret < 0) error_msg("can't create backup file"); - - *sfx = '+'; - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - - ret = fcntl(fileno(exfp), F_SETLK, &lock); - if(ret < 0) perror_msg("Couldn't lock file %s",filename); - - lock.l_type = F_UNLCK; //unlocking at a later stage - - newfp = fopen(filenamesfx, "w+"); - if(!newfp) { - error_msg("couldn't open file for writing"); - ret = -1; - fclose(exfp); - goto free_storage; - } - - ret = 0; - namesfx = xmsprintf("%s:",username); - while((line = get_line(fileno(exfp))) != NULL) - { - if(strncmp(line, namesfx, strlen(namesfx)) != 0) - fprintf(newfp, "%s\n", line); - else { - char *current_ptr = NULL; - fprintf(newfp, "%s%s:",namesfx,encrypted); - current_ptr = get_nextcolon(line, ':'); //past username - current_ptr++; //past colon ':' after username - current_ptr = get_nextcolon(current_ptr, ':'); //past passwd - current_ptr++; //past colon ':' after passwd - if(shadow) { - fprintf(newfp, "%u:",(unsigned)(time(NULL))/(24*60*60)); - current_ptr = get_nextcolon(current_ptr, ':'); - current_ptr++; //past time stamp colon. - fprintf(newfp, "%s\n",current_ptr); - } - else { - fprintf(newfp, "%s\n",current_ptr); - } - } - - free(line); - } - free(namesfx); - fcntl(fileno(exfp), F_SETLK, &lock); - fclose(exfp); - - errno = 0; - fflush(newfp); - fsync(fileno(newfp)); - fclose(newfp); - rename(filenamesfx, filename); - if(errno) { - perror_msg("File Writing/Saving failed: "); - unlink(filenamesfx); - ret = -1; - } + free(line); + } + free(namesfx); + fcntl(fileno(exfp), F_SETLK, &lock); + fclose(exfp); + + errno = 0; + fflush(newfp); + fsync(fileno(newfp)); + fclose(newfp); + rename(filenamesfx, filename); + if(errno) { + perror_msg("File Writing/Saving failed: "); + unlink(filenamesfx); + ret = -1; + } free_storage: - free(filenamesfx); - return ret; -} + free(filenamesfx); + return ret; +} diff --git a/lib/portability.c b/lib/portability.c index b1c448c8..d901a4b6 100644 --- a/lib/portability.c +++ b/lib/portability.c @@ -1,4 +1,3 @@ -/* vi: set sw=4 ts=4 :*/ /* portability.c - code to workaround the deficiencies of various platforms. * * Copyright 2012 Rob Landley @@ -10,66 +9,64 @@ #if defined(__APPLE__) || defined(__ANDROID__) ssize_t getdelim(char **linep, size_t *np, int delim, FILE *stream) { - int ch; - size_t new_len; - ssize_t i = 0; - char *line, *new_line; + int ch; + size_t new_len; + ssize_t i = 0; + char *line, *new_line; - // Invalid input - if (!linep || !np) { - errno = EINVAL; - return -1; - } + // Invalid input + if (!linep || !np) { + errno = EINVAL; + return -1; + } - if (*linep == NULL || *np == 0) { - *np = 1024; - *linep = calloc(1, *np); - if (*linep == NULL) - return -1; - } - line = *linep; + if (*linep == NULL || *np == 0) { + *np = 1024; + *linep = calloc(1, *np); + if (*linep == NULL) return -1; + } + line = *linep; - while ((ch = getc(stream)) != EOF) { - if (i > *np) { - // Need more space - new_len = *np + 1024; - new_line = realloc(*linep, new_len); - if (!new_line) - return -1; - *np = new_len; - *linep = new_line; - } + while ((ch = getc(stream)) != EOF) { + if (i > *np) { + // Need more space + new_len = *np + 1024; + new_line = realloc(*linep, new_len); + if (!new_line) return -1; + *np = new_len; + *linep = new_line; + } - line[i] = ch; - if (ch == delim) - break; - i += 1; - } + line[i] = ch; + if (ch == delim) break; + i += 1; + } - if (i > *np) { - // Need more space - new_len = i + 2; - new_line = realloc(*linep, new_len); - if (!new_line) - return -1; - *np = new_len; - *linep = new_line; - } - line[i + 1] = '\0'; + if (i > *np) { + // Need more space + new_len = i + 2; + new_line = realloc(*linep, new_len); + if (!new_line) return -1; + *np = new_len; + *linep = new_line; + } + line[i + 1] = '\0'; - return i > 0 ? i : -1; + return i > 0 ? i : -1; } -ssize_t getline(char **linep, size_t *np, FILE *stream) { - return getdelim(linep, np, '\n', stream); +ssize_t getline(char **linep, size_t *np, FILE *stream) +{ + return getdelim(linep, np, '\n', stream); } #endif #if defined(__APPLE__) extern char **environ; -int clearenv(void) { - *environ = NULL; - return 0; +int clearenv(void) +{ + *environ = NULL; + return 0; } #endif diff --git a/lib/xregcomp.c b/lib/xregcomp.c index 732ce4db..ec7d1b79 100644 --- a/lib/xregcomp.c +++ b/lib/xregcomp.c @@ -1,5 +1,4 @@ -/* vi: set ts=4: - * Call regcomp() and handle errors. +/* Call regcomp() and handle errors. * * Copyright 2007 Rob Landley * @@ -12,12 +11,12 @@ void xregcomp(regex_t *preg, char *regex, int cflags) { - int rc = regcomp(preg, regex, cflags); + int rc = regcomp(preg, regex, cflags); - if (rc) { - char msg[256]; - regerror(rc, preg, msg, 255); - msg[255]=0; - error_exit("xregcomp: %s", msg); - } + if (rc) { + char msg[256]; + regerror(rc, preg, msg, 255); + msg[255]=0; + error_exit("xregcomp: %s", msg); + } } -- cgit v1.2.3