]> Dogcows Code - chaz/tar/blobdiff - src/misc.c
Carefully crafted invalid headers can cause buffer overrun.
[chaz/tar] / src / misc.c
index bae6cfc1ef0a092d83133d763d35512086048ef8..55bedd2b2c901669ff4025feadbb2fd338984831 100644 (file)
@@ -1,7 +1,7 @@
 /* Miscellaneous functions, not really specific to GNU tar.
 
    Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004 Free Software Foundation, Inc.
+   2003, 2004, 2005 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
 
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
-   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-#include "system.h"
-#include "rmt.h"
+#include <system.h>
+#include <rmt.h>
 #include "common.h"
 #include <quotearg.h>
 #include <save-cwd.h>
+#include <unlinkdir.h>
 
-static void call_arg_fatal (char const *, char const *)
-     __attribute__ ((noreturn));
 \f
 /* Handling strings.  */
 
@@ -123,13 +122,13 @@ unquote_string (char *string)
          source++;
          break;
 
-       case 'n':
-         *destination++ = '\n';
+       case 'a':
+         *destination++ = '\a';
          source++;
          break;
 
-       case 't':
-         *destination++ = '\t';
+       case 'b':
+         *destination++ = '\b';
          source++;
          break;
 
@@ -138,8 +137,8 @@ unquote_string (char *string)
          source++;
          break;
 
-       case 'b':
-         *destination++ = '\b';
+       case 'n':
+         *destination++ = '\n';
          source++;
          break;
 
@@ -148,6 +147,16 @@ unquote_string (char *string)
          source++;
          break;
 
+       case 't':
+         *destination++ = '\t';
+         source++;
+         break;
+
+       case 'v':
+         *destination++ = '\v';
+         source++;
+         break;
+
        case '?':
          *destination++ = 0177;
          source++;
@@ -197,6 +206,40 @@ unquote_string (char *string)
   return result;
 }
 \f
+/* Handling numbers.  */
+
+/* Output fraction and trailing digits appropriate for a nanoseconds
+   count equal to NS, but don't output unnecessary '.' or trailing
+   zeros.  */
+
+void
+code_ns_fraction (int ns, char *p)
+{
+  if (ns == 0)
+    *p = '\0';
+  else
+    {
+      int i = 9;
+      *p++ = '.';
+
+      while (ns % 10 == 0)
+       {
+         ns /= 10;
+         i--;
+       }
+
+      p[i] = '\0';
+
+      for (;;)
+       {
+         p[--i] = '0' + ns % 10;
+         if (i == 0)
+           break;
+         ns /= 10;
+       }
+    }
+}
+\f
 /* File handling.  */
 
 /* Saved names in case backup needs to be undone.  */
@@ -207,14 +250,14 @@ static char *after_backup_name;
 static bool
 must_be_dot_or_slash (char const *file_name)
 {
-  file_name += FILESYSTEM_PREFIX_LEN (file_name);
+  file_name += FILE_SYSTEM_PREFIX_LEN (file_name);
 
   if (ISSLASH (file_name[0]))
     {
       for (;;)
        if (ISSLASH (file_name[1]))
          file_name++;
-       else if (file_name[1] == '.' 
+       else if (file_name[1] == '.'
                  && ISSLASH (file_name[2 + (file_name[2] == '.')]))
          file_name += 2 + (file_name[2] == '.');
        else
@@ -248,7 +291,7 @@ safer_rmdir (const char *file_name)
   return rmdir (file_name);
 }
 
-/* Remove FILE_NAME, returning 1 on success.  If FILE_NAME is a directory, 
+/* Remove FILE_NAME, returning 1 on success.  If FILE_NAME is a directory,
    then if OPTION is RECURSIVE_REMOVE_OPTION is set remove FILE_NAME
    recursively; otherwise, remove it only if it is empty.  If FILE_NAME is
    a directory that cannot be removed (e.g., because it is nonempty)
@@ -258,9 +301,12 @@ safer_rmdir (const char *file_name)
 int
 remove_any_file (const char *file_name, enum remove_option option)
 {
-  /* Try unlink first if we are not root, as this saves us a system
-     call in the common case where we're removing a non-directory.  */
-  if (! we_are_root)
+  /* Try unlink first if we cannot unlink directories, as this saves
+     us a system call in the common case where we're removing a
+     non-directory.  */
+  bool try_unlink_first = cannot_unlink_dir ();
+
+  if (try_unlink_first)
     {
       if (unlink (file_name) == 0)
        return 1;
@@ -278,7 +324,7 @@ remove_any_file (const char *file_name, enum remove_option option)
   switch (errno)
     {
     case ENOTDIR:
-      return we_are_root && unlink (file_name) == 0;
+      return !try_unlink_first && unlink (file_name) == 0;
 
     case 0:
     case EEXIST:
@@ -307,7 +353,8 @@ remove_any_file (const char *file_name, enum remove_option option)
                 entry += entrylen + 1)
              {
                char *file_name_buffer = new_name (file_name, entry);
-               int r = remove_any_file (file_name_buffer, 1);
+               int r = remove_any_file (file_name_buffer,
+                                         RECURSIVE_REMOVE_OPTION);
                int e = errno;
                free (file_name_buffer);
 
@@ -508,93 +555,6 @@ chdir_do (int i)
     }
 }
 \f
-/* Decode MODE from its binary form in a stat structure, and encode it
-   into a 9-byte string STRING, terminated with a NUL.  */
-
-void
-decode_mode (mode_t mode, char *string)
-{
-  *string++ = mode & S_IRUSR ? 'r' : '-';
-  *string++ = mode & S_IWUSR ? 'w' : '-';
-  *string++ = (mode & S_ISUID
-              ? (mode & S_IXUSR ? 's' : 'S')
-              : (mode & S_IXUSR ? 'x' : '-'));
-  *string++ = mode & S_IRGRP ? 'r' : '-';
-  *string++ = mode & S_IWGRP ? 'w' : '-';
-  *string++ = (mode & S_ISGID
-              ? (mode & S_IXGRP ? 's' : 'S')
-              : (mode & S_IXGRP ? 'x' : '-'));
-  *string++ = mode & S_IROTH ? 'r' : '-';
-  *string++ = mode & S_IWOTH ? 'w' : '-';
-  *string++ = (mode & S_ISVTX
-              ? (mode & S_IXOTH ? 't' : 'T')
-              : (mode & S_IXOTH ? 'x' : '-'));
-  *string = '\0';
-}
-
-/* Report an error associated with the system call CALL and the
-   optional name NAME.  */
-static void
-call_arg_error (char const *call, char const *name)
-{
-  int e = errno;
-  ERROR ((0, e, _("%s: Cannot %s"), quotearg_colon (name), call));
-}
-
-/* Report a fatal error associated with the system call CALL and
-   the optional file name NAME.  */
-static void
-call_arg_fatal (char const *call, char const *name)
-{
-  int e = errno;
-  FATAL_ERROR ((0, e, _("%s: Cannot %s"), quotearg_colon (name),  call));
-}
-
-/* Report a warning associated with the system call CALL and
-   the optional file name NAME.  */
-static void
-call_arg_warn (char const *call, char const *name)
-{
-  int e = errno;
-  WARN ((0, e, _("%s: Warning: Cannot %s"), quotearg_colon (name), call));
-}
-
-void
-chdir_fatal (char const *name)
-{
-  call_arg_fatal ("chdir", name);
-}
-
-void
-chmod_error_details (char const *name, mode_t mode)
-{
-  int e = errno;
-  char buf[10];
-  decode_mode (mode, buf);
-  ERROR ((0, e, _("%s: Cannot change mode to %s"),
-         quotearg_colon (name), buf));
-}
-
-void
-chown_error_details (char const *name, uid_t uid, gid_t gid)
-{
-  int e = errno;
-  ERROR ((0, e, _("%s: Cannot change ownership to uid %lu, gid %lu"),
-         quotearg_colon (name), (unsigned long) uid, (unsigned long) gid));
-}
-
-void
-close_error (char const *name)
-{
-  call_arg_error ("close", name);
-}
-
-void
-close_warn (char const *name)
-{
-  call_arg_warn ("close", name);
-}
-
 void
 close_diag (char const *name)
 {
@@ -604,56 +564,6 @@ close_diag (char const *name)
     close_error (name);
 }
 
-void
-exec_fatal (char const *name)
-{
-  call_arg_fatal ("exec", name);
-}
-
-void
-link_error (char const *target, char const *source)
-{
-  int e = errno;
-  ERROR ((0, e, _("%s: Cannot hard link to %s"),
-         quotearg_colon (source), quote_n (1, target)));
-}
-
-void
-mkdir_error (char const *name)
-{
-  call_arg_error ("mkdir", name);
-}
-
-void
-mkfifo_error (char const *name)
-{
-  call_arg_error ("mkfifo", name);
-}
-
-void
-mknod_error (char const *name)
-{
-  call_arg_error ("mknod", name);
-}
-
-void
-open_error (char const *name)
-{
-  call_arg_error ("open", name);
-}
-
-void
-open_fatal (char const *name)
-{
-  call_arg_fatal ("open", name);
-}
-
-void
-open_warn (char const *name)
-{
-  call_arg_warn ("open", name);
-}
-
 void
 open_diag (char const *name)
 {
@@ -663,38 +573,6 @@ open_diag (char const *name)
     open_error (name);
 }
 
-void
-read_error (char const *name)
-{
-  call_arg_error ("read", name);
-}
-
-void
-read_error_details (char const *name, off_t offset, size_t size)
-{
-  char buf[UINTMAX_STRSIZE_BOUND];
-  int e = errno;
-  ERROR ((0, e,
-         ngettext ("%s: Read error at byte %s, reading %lu byte",
-                   "%s: Read error at byte %s, reading %lu bytes",
-                   size),
-         quotearg_colon (name), STRINGIFY_BIGINT (offset, buf),
-         (unsigned long) size));
-}
-
-void
-read_warn_details (char const *name, off_t offset, size_t size)
-{
-  char buf[UINTMAX_STRSIZE_BOUND];
-  int e = errno;
-  WARN ((0, e,
-        ngettext ("%s: Warning: Read error at byte %s, reading %lu byte",
-                  "%s: Warning: Read error at byte %s, reading %lu bytes",
-                  size),
-        quotearg_colon (name), STRINGIFY_BIGINT (offset, buf),
-        (unsigned long) size));
-}
-
 void
 read_diag_details (char const *name, off_t offset, size_t size)
 {
@@ -704,37 +582,6 @@ read_diag_details (char const *name, off_t offset, size_t size)
     read_error_details (name, offset, size);
 }
 
-void
-read_fatal (char const *name)
-{
-  call_arg_fatal ("read", name);
-}
-
-void
-read_fatal_details (char const *name, off_t offset, size_t size)
-{
-  char buf[UINTMAX_STRSIZE_BOUND];
-  int e = errno;
-  FATAL_ERROR ((0, e,
-               ngettext ("%s: Read error at byte %s, reading %lu byte",
-                         "%s: Read error at byte %s, reading %lu bytes",
-                         size),
-               quotearg_colon (name), STRINGIFY_BIGINT (offset, buf),
-               (unsigned long) size));
-}
-
-void
-readlink_error (char const *name)
-{
-  call_arg_error ("readlink", name);
-}
-
-void
-readlink_warn (char const *name)
-{
-  call_arg_warn ("readlink", name);
-}
-
 void
 readlink_diag (char const *name)
 {
@@ -744,18 +591,6 @@ readlink_diag (char const *name)
     readlink_error (name);
 }
 
-void
-savedir_error (char const *name)
-{
-  call_arg_error ("savedir", name);
-}
-
-void
-savedir_warn (char const *name)
-{
-  call_arg_warn ("savedir", name);
-}
-
 void
 savedir_diag (char const *name)
 {
@@ -765,38 +600,6 @@ savedir_diag (char const *name)
     savedir_error (name);
 }
 
-void
-seek_error (char const *name)
-{
-  call_arg_error ("seek", name);
-}
-
-void
-seek_error_details (char const *name, off_t offset)
-{
-  char buf[UINTMAX_STRSIZE_BOUND];
-  int e = errno;
-  ERROR ((0, e, _("%s: Cannot seek to %s"),
-         quotearg_colon (name),
-         STRINGIFY_BIGINT (offset, buf)));
-}
-
-void
-seek_warn (char const *name)
-{
-  call_arg_warn ("seek", name);
-}
-
-void
-seek_warn_details (char const *name, off_t offset)
-{
-  char buf[UINTMAX_STRSIZE_BOUND];
-  int e = errno;
-  WARN ((0, e, _("%s: Warning: Cannot seek to %s"),
-        quotearg_colon (name),
-        STRINGIFY_BIGINT (offset, buf)));
-}
-
 void
 seek_diag_details (char const *name, off_t offset)
 {
@@ -806,26 +609,6 @@ seek_diag_details (char const *name, off_t offset)
     seek_error_details (name, offset);
 }
 
-void
-symlink_error (char const *contents, char const *name)
-{
-  int e = errno;
-  ERROR ((0, e, _("%s: Cannot create symlink to %s"),
-         quotearg_colon (name), quote_n (1, contents)));
-}
-
-void
-stat_error (char const *name)
-{
-  call_arg_error ("stat", name);
-}
-
-void
-stat_warn (char const *name)
-{
-  call_arg_warn ("stat", name);
-}
-
 void
 stat_diag (char const *name)
 {
@@ -835,61 +618,6 @@ stat_diag (char const *name)
     stat_error (name);
 }
 
-void
-truncate_error (char const *name)
-{
-  call_arg_error ("truncate", name);
-}
-
-void
-truncate_warn (char const *name)
-{
-  call_arg_warn ("truncate", name);
-}
-
-void
-unlink_error (char const *name)
-{
-  call_arg_error ("unlink", name);
-}
-
-void
-utime_error (char const *name)
-{
-  call_arg_error ("utime", name);
-}
-
-void
-waitpid_error (char const *name)
-{
-  call_arg_error ("waitpid", name);
-}
-
-void
-write_error (char const *name)
-{
-  call_arg_error ("write", name);
-}
-
-void
-write_error_details (char const *name, size_t status, size_t size)
-{
-  if (status == 0)
-    write_error (name);
-  else
-    ERROR ((0, 0,
-           ngettext ("%s: Wrote only %lu of %lu byte",
-                     "%s: Wrote only %lu of %lu bytes",
-                     size),
-           name, (unsigned long int) status, (unsigned long int) size));
-}
-
-void
-write_fatal (char const *name)
-{
-  call_arg_fatal ("write", name);
-}
-
 void
 write_fatal_details (char const *name, ssize_t status, size_t size)
 {
@@ -897,7 +625,6 @@ write_fatal_details (char const *name, ssize_t status, size_t size)
   fatal_exit ();
 }
 
-
 /* Fork, aborting if unsuccessful.  */
 pid_t
 xfork (void)
@@ -916,18 +643,29 @@ xpipe (int fd[2])
     call_arg_fatal ("pipe", _("interprocess channel"));
 }
 
-/* Return an unambiguous printable representation, allocated in slot N,
-   for NAME, suitable for diagnostics.  */
-char const *
-quote_n (int n, char const *name)
+/* Return PTR, aligned upward to the next multiple of ALIGNMENT.
+   ALIGNMENT must be nonzero.  The caller must arrange for ((char *)
+   PTR) through ((char *) PTR + ALIGNMENT - 1) to be addressable
+   locations.  */
+
+static inline void *
+ptr_align (void *ptr, size_t alignment)
 {
-  return quotearg_n_style (n, locale_quoting_style, name);
+  char *p0 = ptr;
+  char *p1 = p0 + alignment - 1;
+  return p1 - (size_t) p1 % alignment;
 }
 
-/* Return an unambiguous printable representation of NAME, suitable
-   for diagnostics.  */
-char const *
-quote (char const *name)
+/* Return the address of a page-aligned buffer of at least SIZE bytes.
+   The caller should free *PTR when done with the buffer.  */
+
+void *
+page_aligned_alloc (void **ptr, size_t size)
 {
-  return quote_n (0, name);
+  size_t alignment = getpagesize ();
+  size_t size1 = size + alignment;
+  if (size1 < size)
+    xalloc_die ();
+  *ptr = xmalloc (size1);
+  return ptr_align (*ptr, alignment);
 }
This page took 0.032673 seconds and 4 git commands to generate.