aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/args.c633
-rw-r--r--lib/bunzip.c1039
-rw-r--r--lib/dirtree.c206
-rw-r--r--lib/getmountlist.c47
-rw-r--r--lib/lib.c1217
-rw-r--r--lib/lib.h43
-rw-r--r--lib/llist.c51
-rw-r--r--lib/password.c238
-rw-r--r--lib/portability.c93
-rw-r--r--lib/xregcomp.c17
10 files changed, 1771 insertions, 1813 deletions
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 <rob@landley.net>
*/
@@ -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<<i;
- } else if (*options == '[') { // TODO
- } else if (-1 != (idx = stridx("|^ ", *options)))
- new->flags |= 1<<idx;
- // bounds checking
- else if (-1 != (idx = stridx("<>=", *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<<i;
+ } else if (*options == '[') { // TODO
+ } else if (-1 != (idx = stridx("|^ ", *options))) new->flags |= 1<<idx;
+ // bounds checking
+ else if (-1 != (idx = stridx("<>=", *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.optc<gof.minargs) {
- error_exit("Need%s %d argument%s", letters[!!(gof.minargs-1)],
- gof.minargs, letters[!(gof.minargs-1)]);
- }
- if (toys.optc>gof.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.optc<gof.minargs)
+ error_exit("Need%s %d argument%s", letters[!!(gof.minargs-1)],
+ gof.minargs, letters[!(gof.minargs-1)]);
+ if (toys.optc>gof.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<<bd->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<<bits_wanted)-1);
-
- return bits;
+ 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<<bd->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<<bits_wanted)-1);
+
+ return bits;
}
/* Read block header at start of a new compressed data block. Consists of:
@@ -139,156 +137,153 @@ static unsigned int get_bits(struct bunzip_data *bd, char bits_wanted)
static int read_block_header(struct bunzip_data *bd, struct bwdata *bw)
{
- 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; ii<bd->groupCount; ii++) bd->mtfSymbol[ii] = ii;
- for (ii=0; ii<bd->nSelectors; 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; jj<bd->groupCount; 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; ii<bd->groupCount; ii++) bd->mtfSymbol[ii] = ii;
+ for (ii=0; ii<bd->nSelectors; 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; jj<bd->groupCount; 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; i<THREADS; i++)
- bd->bwdata[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; i<THREADS; i++)
+ bd->bwdata[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; j<THREADS; j++) free(bd->bwdata[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; j<THREADS; j++) free(bd->bwdata[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 <rob@landley.net>
@@ -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 <rob@landley.net>
@@ -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<len) {
- int i = read(fd, buf+count, len-count);
- if (!i) break;
- if (i<0) return i;
- count += i;
- }
+ while (count<len) {
+ int i = read(fd, buf+count, len-count);
+ if (!i) break;
+ if (i<0) return i;
+ count += i;
+ }
- return count;
+ return count;
}
// Keep writing until done or EOF
ssize_t writeall(int fd, void *buf, size_t len)
{
- size_t count = 0;
- while (count<len) {
- int i = write(fd, buf+count, len-count);
- if (i<1) return i;
- count += i;
- }
+ size_t count = 0;
+ while (count<len) {
+ int i = write(fd, buf+count, len-count);
+ if (i<1) return i;
+ count += i;
+ }
- return count;
+ return count;
}
// Die if there's an error other than EOF.
size_t xread(int fd, void *buf, size_t len)
{
- ssize_t ret = read(fd, buf, len);
- if (ret < 0) perror_exit("xread");
+ ssize_t ret = read(fd, buf, len);
+ if (ret < 0) perror_exit("xread");
- return ret;
+ return ret;
}
void xreadall(int fd, void *buf, size_t len)
{
- if (len != readall(fd, buf, len)) perror_exit("xreadall");
+ if (len != readall(fd, buf, len)) perror_exit("xreadall");
}
// There's no xwriteall(), just xwrite(). When we read, there may or may not
@@ -273,51 +272,51 @@ void xreadall(int fd, void *buf, size_t len)
void xwrite(int fd, void *buf, size_t len)
{
- if (len != writeall(fd, buf, len)) perror_exit("xwrite");
+ if (len != writeall(fd, buf, len)) perror_exit("xwrite");
}
// Die if lseek fails, probably due to being called on a pipe.
off_t xlseek(int fd, off_t offset, int whence)
{
- offset = lseek(fd, offset, whence);
- if (offset<0) perror_exit("lseek");
+ offset = lseek(fd, offset, whence);
+ if (offset<0) perror_exit("lseek");
- return offset;
+ return offset;
}
off_t lskip(int fd, off_t offset)
{
- off_t and = lseek(fd, offset, SEEK_CUR);
+ off_t and = lseek(fd, offset, SEEK_CUR);
- 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;
+ 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<size) {
- buf[len]=0;
- return buf;
- }
- }
+ if (len<0) {
+ free(buf);
+ return 0;
+ }
+ if (len<size) {
+ buf[len]=0;
+ return buf;
+ }
+ }
}
/*
@@ -628,24 +627,24 @@ char *xreadlink(char *name)
// Read contents of file as a single freshly allocated nul-terminated string.
char *readfile(char *name)
{
- off_t len;
- int fd;
- char *buf;
+ off_t len;
+ int fd;
+ char *buf;
- fd = open(name, O_RDONLY);
- if (fd == -1) return 0;
- len = fdlength(fd);
- buf = xmalloc(len+1);
- buf[readall(fd, buf, len)] = 0;
+ fd = open(name, O_RDONLY);
+ if (fd == -1) return 0;
+ len = fdlength(fd);
+ buf = xmalloc(len+1);
+ buf[readall(fd, buf, len)] = 0;
- return buf;
+ return buf;
}
char *xreadfile(char *name)
{
- char *buf = readfile(name);
- if (!buf) perror_exit("xreadfile %s", name);
- return buf;
+ char *buf = readfile(name);
+ if (!buf) perror_exit("xreadfile %s", name);
+ return buf;
}
*/
@@ -654,33 +653,33 @@ char *xreadfile(char *name)
// exists and is this executable.
void xpidfile(char *name)
{
- char pidfile[256], spid[32];
- int i, fd;
- pid_t pid;
-
- sprintf(pidfile, "/var/run/%s.pid", name);
- // Try three times to open the sucker.
- for (i=0; i<3; i++) {
- fd = open(pidfile, O_CREAT|O_EXCL, 0644);
- if (fd != -1) break;
+ char pidfile[256], spid[32];
+ int i, fd;
+ pid_t pid;
+
+ sprintf(pidfile, "/var/run/%s.pid", name);
+ // Try three times to open the sucker.
+ for (i=0; i<3; i++) {
+ fd = open(pidfile, O_CREAT|O_EXCL, 0644);
+ if (fd != -1) break;
- // If it already existed, read it. Loop for race condition.
- fd = open(pidfile, O_RDONLY);
- if (fd == -1) continue;
+ // If it already existed, read it. Loop for race condition.
+ fd = open(pidfile, O_RDONLY);
+ if (fd == -1) continue;
- // Is the old program still there?
- spid[xread(fd, spid, sizeof(spid)-1)] = 0;
- close(fd);
- pid = atoi(spid);
- if (pid < 1 || kill(pid, 0) == ESRCH) unlink(pidfile);
+ // Is the old program still there?
+ spid[xread(fd, spid, sizeof(spid)-1)] = 0;
+ close(fd);
+ pid = atoi(spid);
+ if (pid < 1 || kill(pid, 0) == ESRCH) unlink(pidfile);
- // An else with more sanity checking might be nice here.
- }
+ // An else with more sanity checking might be nice here.
+ }
- if (i == 3) error_exit("xpidfile %s", name);
+ if (i == 3) error_exit("xpidfile %s", name);
- xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
- close(fd);
+ xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
+ close(fd);
}
// Iterate through an array of files, opening each one and calling a function
@@ -691,157 +690,157 @@ void xpidfile(char *name)
// Note: read only filehandles are automatically closed when function()
// returns, but writeable filehandles must be close by function()
void loopfiles_rw(char **argv, int flags, int permissions, int failok,
- void (*function)(int fd, char *name))
+ void (*function)(int fd, char *name))
{
- int fd;
+ int fd;
- // If no arguments, read from stdin.
- if (!*argv) function(flags ? 1 : 0, "-");
- else do {
- // Filename "-" means read from stdin.
- // Inability to open a file prints a warning, but doesn't exit.
+ // If no arguments, read from stdin.
+ if (!*argv) function(flags ? 1 : 0, "-");
+ else do {
+ // Filename "-" means read from stdin.
+ // Inability to open a file prints a warning, but doesn't exit.
- 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);
+ 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<sizeof(signames)/sizeof(struct signame); i++)
- if (signames[i].num == sig) return signames[i].name;
- return NULL;
+ for (i=0; i<sizeof(signames)/sizeof(struct signame); i++)
+ if (signames[i].num == sig) return signames[i].name;
+ return NULL;
}
// premute mode bits based on posix mode strings.
mode_t string_to_mode(char *modestr, mode_t mode)
{
- char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu";
- char *s, *str = modestr;
-
- // Handle octal mode
- if (isdigit(*str)) {
- mode = strtol(str, &s, 8);
- if (*s || (mode & ~(07777))) goto barf;
-
- return mode;
- }
-
- // Gaze into the bin of permission...
- for (;;) {
- int i, j, dowho, dohow, dowhat, amask;
-
- dowho = dohow = dowhat = amask = 0;
-
- // Find the who, how, and what stanzas, in that order
- while (*str && (s = strchr(whos, *str))) {
- dowho |= 1<<(s-whos);
- str++;
- }
- // If who isn't specified, like "a" but honoring umask.
- if (!dowho) {
- dowho = 8;
- umask(amask=umask(0));
- }
- if (!*str || !(s = strchr(hows, *str))) goto barf;
- dohow = *(str++);
-
- if (!dohow) goto barf;
- while (*str && (s = strchr(whats, *str))) {
- dowhat |= 1<<(s-whats);
- str++;
- }
-
- // Convert X to x for directory or if already executable somewhere
- if ((dowhat&32) && (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
-
- // Copy mode from another category?
- if (!dowhat && *str && (s = strchr(whys, *str))) {
- dowhat = (mode>>(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<<i)))) bit++;
- } else if (dowhat & 16) bit++;
- } else {
- if (!(dowho&(8|(1<<i)))) continue;
- if (dowhat&(1<<j)) bit++;
- }
-
- // When selection active, modify bit
-
- if (dohow == '=' || (bit && dohow == '-'))
- mode &= ~where;
- if (bit && dohow != '-') mode |= where;
- }
- }
-
- if (!*str) break;
- }
- return mode;
+ char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu";
+ char *s, *str = modestr;
+
+ // Handle octal mode
+ if (isdigit(*str)) {
+ mode = strtol(str, &s, 8);
+ if (*s || (mode & ~(07777))) goto barf;
+
+ return mode;
+ }
+
+ // Gaze into the bin of permission...
+ for (;;) {
+ int i, j, dowho, dohow, dowhat, amask;
+
+ dowho = dohow = dowhat = amask = 0;
+
+ // Find the who, how, and what stanzas, in that order
+ while (*str && (s = strchr(whos, *str))) {
+ dowho |= 1<<(s-whos);
+ str++;
+ }
+ // If who isn't specified, like "a" but honoring umask.
+ if (!dowho) {
+ dowho = 8;
+ umask(amask=umask(0));
+ }
+ if (!*str || !(s = strchr(hows, *str))) goto barf;
+ dohow = *(str++);
+
+ if (!dohow) goto barf;
+ while (*str && (s = strchr(whats, *str))) {
+ dowhat |= 1<<(s-whats);
+ str++;
+ }
+
+ // Convert X to x for directory or if already executable somewhere
+ if ((dowhat&32) && (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
+
+ // Copy mode from another category?
+ if (!dowhat && *str && (s = strchr(whys, *str))) {
+ dowhat = (mode>>(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<<i)))) bit++;
+ } else if (dowhat & 16) bit++;
+ } else {
+ if (!(dowho&(8|(1<<i)))) continue;
+ if (dowhat&(1<<j)) bit++;
+ }
+
+ // When selection active, modify bit
+
+ if (dohow == '=' || (bit && dohow == '-')) mode &= ~where;
+ if (bit && dohow != '-') mode |= where;
+ }
+ }
+
+ if (!*str) break;
+ }
+ return mode;
barf:
- error_exit("bad mode '%s'", modestr);
+ error_exit("bad mode '%s'", modestr);
}
char* make_human_readable(unsigned long long size, unsigned long unit)
{
- unsigned int frac = 0;
- if(unit) {
- size = (size/(unit)) + (size%(unit)?1:0);
- return xmsprintf("%llu", size);
+ unsigned int frac = 0;
+ if(unit) {
+ size = (size/(unit)) + (size%(unit)?1:0);
+ return xmsprintf("%llu", size);
+ }
+ 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++;
}
- 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 <rob@landley.net>
@@ -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 <ak.ashwini@gmail.com>
*/
@@ -7,136 +6,131 @@
#include "toys.h"
#include <time.h>
-
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 <rob@landley.net>
@@ -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 <rob@landley.net>
*
@@ -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);
+ }
}