X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fmisc.c;h=ff7e4b23cdbbcc140440fc288a35911cc2f358dd;hb=c1d3d134939d48e921b981f400808663f4e74001;hp=a76b24eb6764cc85106c8bc38fbfa94f446f76f0;hpb=2b1bffbad66faab91c3b080b63788d910f68632d;p=chaz%2Ftar diff --git a/src/misc.c b/src/misc.c index a76b24e..ff7e4b2 100644 --- a/src/misc.c +++ b/src/misc.c @@ -25,7 +25,6 @@ #include #include #include -#include #if HAVE_STROPTS_H # include @@ -34,6 +33,10 @@ # include #endif +#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT +# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 +#endif + /* Handling strings. */ @@ -230,10 +233,99 @@ zap_slashes (char *name) return name; } +/* Normalize NAME by resolving any relative references and + removing trailing slashes. Destructive version: modifies its argument. */ +int +normalize_filename_x (char *name) +{ + char *p, *q; + + p = name; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && ISSLASH (*p)) + p++; + + /* Remove /./, resolve /../ and compress sequences of slashes */ + for (q = p; *q; ) + { + if (ISSLASH (*q)) + { + *p++ = *q++; + while (ISSLASH (*q)) + q++; + continue; + } + else if (p == name) + { + if (*q == '.') + { + if (ISSLASH (q[1])) + { + q += 2; + continue; + } + if (q[1] == '.' && ISSLASH (q[2])) + return 1; + } + } + else + { + if (*q == '.' && ISSLASH (p[-1])) + { + if (ISSLASH (q[1])) + { + q += 2; + while (ISSLASH (*q)) + q++; + continue; + } + else if (q[1] == '.' && ISSLASH (q[2])) + { + do + { + --p; + } + while (p > name && !ISSLASH (p[-1])); + q += 3; + continue; + } + } + } + *p++ = *q++; + } + + /* Remove trailing slashes */ + while (p - 1 > name && ISSLASH (p[-1])) + p--; + + *p = 0; + return 0; +} + +/* Normalize NAME by resolving any relative references, removing trailing + slashes, and converting it to absolute file name. Return the normalized + name, or NULL in case of error. */ + char * normalize_filename (const char *name) { - return zap_slashes (canonicalize_filename_mode (name, CAN_MISSING)); + char *copy; + + if (name[0] != '/') + { + copy = xgetcwd (); + copy = xrealloc (copy, strlen (copy) + strlen (name) + 2); + + strcat (copy, "/"); + strcat (copy, name); + } + else + copy = xstrdup (name); + if (normalize_filename_x (copy)) + { + free (copy); + return NULL; + } + return xrealloc (copy, strlen (copy) + 1); } @@ -298,6 +390,10 @@ code_timespec (struct timespec t, char sbuf[TIMESPEC_STRSIZE_BOUND]) char *np; bool negative = s < 0; + /* ignore invalid values of ns */ + if (BILLION <= ns || ns < 0) + ns = 0; + if (negative && ns != 0) { s++; @@ -745,6 +841,36 @@ stat_diag (char const *name) stat_error (name); } +void +file_removed_diag (const char *name, bool top_level, + void (*diagfn) (char const *name)) +{ + if (!top_level && errno == ENOENT) + { + WARNOPT (WARN_FILE_REMOVED, + (0, 0, _("%s: File removed before we read it"), + quotearg_colon (name))); + set_exit_status (TAREXIT_DIFFERS); + } + else + diagfn (name); +} + +void +dir_removed_diag (const char *name, bool top_level, + void (*diagfn) (char const *name)) +{ + if (!top_level && errno == ENOENT) + { + WARNOPT (WARN_FILE_REMOVED, + (0, 0, _("%s: Directory removed before we read it"), + quotearg_colon (name))); + set_exit_status (TAREXIT_DIFFERS); + } + else + diagfn (name); +} + void write_fatal_details (char const *name, ssize_t status, size_t size) { @@ -797,3 +923,42 @@ page_aligned_alloc (void **ptr, size_t size) return ptr_align (*ptr, alignment); } + + +struct namebuf +{ + char *buffer; /* directory, `/', and directory member */ + size_t buffer_size; /* allocated size of name_buffer */ + size_t dir_length; /* length of directory part in buffer */ +}; + +namebuf_t +namebuf_create (const char *dir) +{ + namebuf_t buf = xmalloc (sizeof (*buf)); + buf->buffer_size = strlen (dir) + 2; + buf->buffer = xmalloc (buf->buffer_size); + strcpy (buf->buffer, dir); + buf->dir_length = strlen (buf->buffer); + if (!ISSLASH (buf->buffer[buf->dir_length - 1])) + buf->buffer[buf->dir_length++] = DIRECTORY_SEPARATOR; + return buf; +} + +void +namebuf_free (namebuf_t buf) +{ + free (buf->buffer); + free (buf); +} + +char * +namebuf_name (namebuf_t buf, const char *name) +{ + size_t len = strlen (name); + while (buf->dir_length + len + 1 >= buf->buffer_size) + buf->buffer = x2realloc (buf->buffer, &buf->buffer_size); + strcpy (buf->buffer + buf->dir_length, name); + return buf->buffer; +} +