X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fmisc.c;h=1d7e9e1eb7daff061e447029c7756fcbe28e4c27;hb=8e3f3adf9888cca4acedfe005d277867c999fcb3;hp=2ba52a38ae58fd935de74e9c13662184a2a52c90;hpb=5c35fdb275b519373e6eb34621d956d09a52bf31;p=chaz%2Ftar diff --git a/src/misc.c b/src/misc.c index 2ba52a3..1d7e9e1 100644 --- a/src/misc.c +++ b/src/misc.c @@ -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 @@ -18,11 +18,22 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include +#include +#include #include #include "common.h" #include #include +#include #include +#include + +#if HAVE_STROPTS_H +# include +#endif +#if HAVE_SYS_FILIO_H +# include +#endif /* Handling strings. */ @@ -206,6 +217,61 @@ unquote_string (char *string) return result; } +/* 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; +} + /* 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"))); }