]> Dogcows Code - chaz/tar/blobdiff - src/misc.c
Port to Forte Developer 7 C 5.4 and C99.
[chaz/tar] / src / misc.c
index 2ba52a38ae58fd935de74e9c13662184a2a52c90..1d7e9e1eb7daff061e447029c7756fcbe28e4c27 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, 2005 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006 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
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include <system.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 #include <rmt.h>
 #include "common.h"
 #include <quotearg.h>
 #include <save-cwd.h>
+#include <xgetcwd.h>
 #include <unlinkdir.h>
+#include <utimens.h>
+
+#if HAVE_STROPTS_H
+# include <stropts.h>
+#endif
+#if HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
 
 \f
 /* Handling strings.  */
@@ -206,6 +217,61 @@ 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;
+       }
+    }
+}
+
+char const *
+code_timespec (struct timespec t, char sbuf[TIMESPEC_STRSIZE_BOUND])
+{
+  time_t s = t.tv_sec;
+  int ns = t.tv_nsec;
+  char *np;
+  bool negative = s < 0;
+
+  if (negative && ns != 0)
+    {
+      s++;
+      ns = BILLION - ns;
+    }
+
+  np = umaxtostr (negative ? - (uintmax_t) s : (uintmax_t) s, sbuf + 1);
+  if (negative)
+    *--np = '-';
+  code_ns_fraction (ns, sbuf + UINTMAX_STRSIZE_BOUND);
+  return np;
+}
+\f
 /* File handling.  */
 
 /* Saved names in case backup needs to be undone.  */
@@ -349,7 +415,7 @@ remove_any_file (const char *file_name, enum remove_option option)
    so, we do not have to backup block or character devices, nor remote
    entities.  */
 bool
-maybe_backup_file (const char *file_name, int this_is_the_archive)
+maybe_backup_file (const char *file_name, bool this_is_the_archive)
 {
   struct stat file_stat;
 
@@ -435,6 +501,26 @@ deref_stat (bool deref, char const *name, struct stat *buf)
   return deref ? stat (name, buf) : lstat (name, buf);
 }
 
+/* Set FD's (i.e., FILE's) access time to TIMESPEC[0].  If that's not
+   possible to do by itself, set its access and data modification
+   times to TIMESPEC[0] and TIMESPEC[1], respectively.  */
+int
+set_file_atime (int fd, char const *file, struct timespec const timespec[2])
+{
+#ifdef _FIOSATIME
+  if (0 <= fd)
+    {
+      struct timeval timeval;
+      timeval.tv_sec = timespec[0].tv_sec;
+      timeval.tv_usec = timespec[0].tv_nsec / 1000;
+      if (ioctl (fd, _FIOSATIME, &timeval) == 0)
+       return 0;
+    }
+#endif
+
+  return futimens (fd, file, timespec);
+}
+
 /* A description of a working directory.  */
 struct wd
 {
@@ -459,8 +545,14 @@ chdir_arg (char const *dir)
 {
   if (wds == wd_alloc)
     {
-      wd_alloc = 2 * (wd_alloc + 1);
-      wd = xrealloc (wd, sizeof *wd * wd_alloc);
+      if (wd_alloc == 0)
+       {
+         wd_alloc = 2;
+         wd = xmalloc (sizeof *wd * wd_alloc);
+       }
+      else
+       wd = x2nrealloc (wd, &wd_alloc, sizeof *wd);
+
       if (! wds)
        {
          wd[wds].name = ".";
@@ -485,12 +577,42 @@ chdir_arg (char const *dir)
   return wds++;
 }
 
+/* Return maximum number of open files */
+int
+get_max_open_files ()
+{
+#if defined _SC_OPEN_MAX
+  return sysconf (_SC_OPEN_MAX);
+#elif defined RLIMIT_NOFILE
+  struct rlimit rlim;
+
+  if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
+    return rlim.rlim_max;
+  return -1;
+#elif defined HAVE_GETDTABLESIZE
+  return getdtablesize ();
+#else
+  return -1;
+#endif
+}
+
+/* Close all descriptors, except the first three */
+void
+closeopen ()
+{
+  int i;
+
+  for (i = get_max_open_files () - 1; i > 2; i--)
+    close (i);
+}
+
 /* Change to directory I.  If I is 0, change to the initial working
    directory; otherwise, I must be a value returned by chdir_arg.  */
 void
 chdir_do (int i)
 {
   static int previous;
+  static int saved_count;
 
   if (previous != i)
     {
@@ -500,7 +622,15 @@ chdir_do (int i)
       if (! prev->saved)
        {
          prev->saved = 1;
-         if (save_cwd (&prev->saved_cwd) != 0)
+         saved_count++;
+         /* Make sure we still have at least one descriptor available */
+         if (saved_count >= get_max_open_files () - 4)
+           {
+             /* Force restore_cwd to use chdir_long */
+             prev->saved_cwd.desc = -1;
+             prev->saved_cwd.name = xgetcwd ();
+           }
+         else if (save_cwd (&prev->saved_cwd) != 0)
            FATAL_ERROR ((0, 0, _("Cannot save working directory")));
        }
 
This page took 0.024107 seconds and 4 git commands to generate.