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. */
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. */
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;
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
{
{
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 = ".";
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;
+#elif defined HAVE_GETDTABLESIZE
+ return getdtablesize ();
+#endif
+ return -1;
+}
+
+/* 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)
{
struct wd *prev = &wd[previous];
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")));
}