| 1 | /* Miscellaneous functions, not really specific to GNU tar.
|
|---|
| 2 |
|
|---|
| 3 | Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
|
|---|
| 4 | 2003, 2004, 2005 Free Software Foundation, Inc.
|
|---|
| 5 |
|
|---|
| 6 | This program is free software; you can redistribute it and/or modify it
|
|---|
| 7 | under the terms of the GNU General Public License as published by the
|
|---|
| 8 | Free Software Foundation; either version 2, or (at your option) any later
|
|---|
| 9 | version.
|
|---|
| 10 |
|
|---|
| 11 | This program is distributed in the hope that it will be useful, but
|
|---|
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|---|
| 14 | Public License for more details.
|
|---|
| 15 |
|
|---|
| 16 | You should have received a copy of the GNU General Public License along
|
|---|
| 17 | with this program; if not, write to the Free Software Foundation, Inc.,
|
|---|
| 18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
|---|
| 19 |
|
|---|
| 20 | #include <system.h>
|
|---|
| 21 | #include <sys/time.h>
|
|---|
| 22 | #include <sys/resource.h>
|
|---|
| 23 | #include <rmt.h>
|
|---|
| 24 | #include "common.h"
|
|---|
| 25 | #include <quotearg.h>
|
|---|
| 26 | #include <save-cwd.h>
|
|---|
| 27 | #include <xgetcwd.h>
|
|---|
| 28 | #include <unlinkdir.h>
|
|---|
| 29 | #include <utimens.h>
|
|---|
| 30 |
|
|---|
| 31 | #if HAVE_STROPTS_H
|
|---|
| 32 | # include <stropts.h>
|
|---|
| 33 | #endif
|
|---|
| 34 | #if HAVE_SYS_FILIO_H
|
|---|
| 35 | # include <sys/filio.h>
|
|---|
| 36 | #endif
|
|---|
| 37 |
|
|---|
| 38 | |
|---|
| 39 |
|
|---|
| 40 | /* Handling strings. */
|
|---|
| 41 |
|
|---|
| 42 | /* Assign STRING to a copy of VALUE if not zero, or to zero. If
|
|---|
| 43 | STRING was nonzero, it is freed first. */
|
|---|
| 44 | void
|
|---|
| 45 | assign_string (char **string, const char *value)
|
|---|
| 46 | {
|
|---|
| 47 | if (*string)
|
|---|
| 48 | free (*string);
|
|---|
| 49 | *string = value ? xstrdup (value) : 0;
|
|---|
| 50 | }
|
|---|
| 51 |
|
|---|
| 52 | /* Allocate a copy of the string quoted as in C, and returns that. If
|
|---|
| 53 | the string does not have to be quoted, it returns a null pointer.
|
|---|
| 54 | The allocated copy should normally be freed with free() after the
|
|---|
| 55 | caller is done with it.
|
|---|
| 56 |
|
|---|
| 57 | This is used in one context only: generating the directory file in
|
|---|
| 58 | incremental dumps. The quoted string is not intended for human
|
|---|
| 59 | consumption; it is intended only for unquote_string. The quoting
|
|---|
| 60 | is locale-independent, so that users needn't worry about locale
|
|---|
| 61 | when reading directory files. This means that we can't use
|
|---|
| 62 | quotearg, as quotearg is locale-dependent and is meant for human
|
|---|
| 63 | consumption. */
|
|---|
| 64 | char *
|
|---|
| 65 | quote_copy_string (const char *string)
|
|---|
| 66 | {
|
|---|
| 67 | const char *source = string;
|
|---|
| 68 | char *destination = 0;
|
|---|
| 69 | char *buffer = 0;
|
|---|
| 70 | int copying = 0;
|
|---|
| 71 |
|
|---|
| 72 | while (*source)
|
|---|
| 73 | {
|
|---|
| 74 | int character = *source++;
|
|---|
| 75 |
|
|---|
| 76 | switch (character)
|
|---|
| 77 | {
|
|---|
| 78 | case '\n': case '\\':
|
|---|
| 79 | if (!copying)
|
|---|
| 80 | {
|
|---|
| 81 | size_t length = (source - string) - 1;
|
|---|
| 82 |
|
|---|
| 83 | copying = 1;
|
|---|
| 84 | buffer = xmalloc (length + 2 + 2 * strlen (source) + 1);
|
|---|
| 85 | memcpy (buffer, string, length);
|
|---|
| 86 | destination = buffer + length;
|
|---|
| 87 | }
|
|---|
| 88 | *destination++ = '\\';
|
|---|
| 89 | *destination++ = character == '\\' ? '\\' : 'n';
|
|---|
| 90 | break;
|
|---|
| 91 |
|
|---|
| 92 | default:
|
|---|
| 93 | if (copying)
|
|---|
| 94 | *destination++ = character;
|
|---|
| 95 | break;
|
|---|
| 96 | }
|
|---|
| 97 | }
|
|---|
| 98 | if (copying)
|
|---|
| 99 | {
|
|---|
| 100 | *destination = '\0';
|
|---|
| 101 | return buffer;
|
|---|
| 102 | }
|
|---|
| 103 | return 0;
|
|---|
| 104 | }
|
|---|
| 105 |
|
|---|
| 106 | /* Takes a quoted C string (like those produced by quote_copy_string)
|
|---|
| 107 | and turns it back into the un-quoted original. This is done in
|
|---|
| 108 | place. Returns 0 only if the string was not properly quoted, but
|
|---|
| 109 | completes the unquoting anyway.
|
|---|
| 110 |
|
|---|
| 111 | This is used for reading the saved directory file in incremental
|
|---|
| 112 | dumps. It is used for decoding old `N' records (demangling names).
|
|---|
| 113 | But also, it is used for decoding file arguments, would they come
|
|---|
| 114 | from the shell or a -T file, and for decoding the --exclude
|
|---|
| 115 | argument. */
|
|---|
| 116 | int
|
|---|
| 117 | unquote_string (char *string)
|
|---|
| 118 | {
|
|---|
| 119 | int result = 1;
|
|---|
| 120 | char *source = string;
|
|---|
| 121 | char *destination = string;
|
|---|
| 122 |
|
|---|
| 123 | /* Escape sequences other than \\ and \n are no longer generated by
|
|---|
| 124 | quote_copy_string, but accept them for backwards compatibility,
|
|---|
| 125 | and also because unquote_string is used for purposes other than
|
|---|
| 126 | parsing the output of quote_copy_string. */
|
|---|
| 127 |
|
|---|
| 128 | while (*source)
|
|---|
| 129 | if (*source == '\\')
|
|---|
| 130 | switch (*++source)
|
|---|
| 131 | {
|
|---|
| 132 | case '\\':
|
|---|
| 133 | *destination++ = '\\';
|
|---|
| 134 | source++;
|
|---|
| 135 | break;
|
|---|
| 136 |
|
|---|
| 137 | case 'a':
|
|---|
| 138 | *destination++ = '\a';
|
|---|
| 139 | source++;
|
|---|
| 140 | break;
|
|---|
| 141 |
|
|---|
| 142 | case 'b':
|
|---|
| 143 | *destination++ = '\b';
|
|---|
| 144 | source++;
|
|---|
| 145 | break;
|
|---|
| 146 |
|
|---|
| 147 | case 'f':
|
|---|
| 148 | *destination++ = '\f';
|
|---|
| 149 | source++;
|
|---|
| 150 | break;
|
|---|
| 151 |
|
|---|
| 152 | case 'n':
|
|---|
| 153 | *destination++ = '\n';
|
|---|
| 154 | source++;
|
|---|
| 155 | break;
|
|---|
| 156 |
|
|---|
| 157 | case 'r':
|
|---|
| 158 | *destination++ = '\r';
|
|---|
| 159 | source++;
|
|---|
| 160 | break;
|
|---|
| 161 |
|
|---|
| 162 | case 't':
|
|---|
| 163 | *destination++ = '\t';
|
|---|
| 164 | source++;
|
|---|
| 165 | break;
|
|---|
| 166 |
|
|---|
| 167 | case 'v':
|
|---|
| 168 | *destination++ = '\v';
|
|---|
| 169 | source++;
|
|---|
| 170 | break;
|
|---|
| 171 |
|
|---|
| 172 | case '?':
|
|---|
| 173 | *destination++ = 0177;
|
|---|
| 174 | source++;
|
|---|
| 175 | break;
|
|---|
| 176 |
|
|---|
| 177 | case '0':
|
|---|
| 178 | case '1':
|
|---|
| 179 | case '2':
|
|---|
| 180 | case '3':
|
|---|
| 181 | case '4':
|
|---|
| 182 | case '5':
|
|---|
| 183 | case '6':
|
|---|
| 184 | case '7':
|
|---|
| 185 | {
|
|---|
| 186 | int value = *source++ - '0';
|
|---|
| 187 |
|
|---|
| 188 | if (*source < '0' || *source > '7')
|
|---|
| 189 | {
|
|---|
| 190 | *destination++ = value;
|
|---|
| 191 | break;
|
|---|
| 192 | }
|
|---|
| 193 | value = value * 8 + *source++ - '0';
|
|---|
| 194 | if (*source < '0' || *source > '7')
|
|---|
| 195 | {
|
|---|
| 196 | *destination++ = value;
|
|---|
| 197 | break;
|
|---|
| 198 | }
|
|---|
| 199 | value = value * 8 + *source++ - '0';
|
|---|
| 200 | *destination++ = value;
|
|---|
| 201 | break;
|
|---|
| 202 | }
|
|---|
| 203 |
|
|---|
| 204 | default:
|
|---|
| 205 | result = 0;
|
|---|
| 206 | *destination++ = '\\';
|
|---|
| 207 | if (*source)
|
|---|
| 208 | *destination++ = *source++;
|
|---|
| 209 | break;
|
|---|
| 210 | }
|
|---|
| 211 | else if (source != destination)
|
|---|
| 212 | *destination++ = *source++;
|
|---|
| 213 | else
|
|---|
| 214 | source++, destination++;
|
|---|
| 215 |
|
|---|
| 216 | if (source != destination)
|
|---|
| 217 | *destination = '\0';
|
|---|
| 218 | return result;
|
|---|
| 219 | }
|
|---|
| 220 | |
|---|
| 221 |
|
|---|
| 222 | /* Handling numbers. */
|
|---|
| 223 |
|
|---|
| 224 | /* Output fraction and trailing digits appropriate for a nanoseconds
|
|---|
| 225 | count equal to NS, but don't output unnecessary '.' or trailing
|
|---|
| 226 | zeros. */
|
|---|
| 227 |
|
|---|
| 228 | void
|
|---|
| 229 | code_ns_fraction (int ns, char *p)
|
|---|
| 230 | {
|
|---|
| 231 | if (ns == 0)
|
|---|
| 232 | *p = '\0';
|
|---|
| 233 | else
|
|---|
| 234 | {
|
|---|
| 235 | int i = 9;
|
|---|
| 236 | *p++ = '.';
|
|---|
| 237 |
|
|---|
| 238 | while (ns % 10 == 0)
|
|---|
| 239 | {
|
|---|
| 240 | ns /= 10;
|
|---|
| 241 | i--;
|
|---|
| 242 | }
|
|---|
| 243 |
|
|---|
| 244 | p[i] = '\0';
|
|---|
| 245 |
|
|---|
| 246 | for (;;)
|
|---|
| 247 | {
|
|---|
| 248 | p[--i] = '0' + ns % 10;
|
|---|
| 249 | if (i == 0)
|
|---|
| 250 | break;
|
|---|
| 251 | ns /= 10;
|
|---|
| 252 | }
|
|---|
| 253 | }
|
|---|
| 254 | }
|
|---|
| 255 |
|
|---|
| 256 | char const *
|
|---|
| 257 | code_timespec (struct timespec t, char sbuf[TIMESPEC_STRSIZE_BOUND])
|
|---|
| 258 | {
|
|---|
| 259 | time_t s = t.tv_sec;
|
|---|
| 260 | int ns = t.tv_nsec;
|
|---|
| 261 | char *np;
|
|---|
| 262 | bool negative = s < 0;
|
|---|
| 263 |
|
|---|
| 264 | if (negative && ns != 0)
|
|---|
| 265 | {
|
|---|
| 266 | s++;
|
|---|
| 267 | ns = BILLION - ns;
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 | np = umaxtostr (negative ? - (uintmax_t) s : (uintmax_t) s, sbuf + 1);
|
|---|
| 271 | if (negative)
|
|---|
| 272 | *--np = '-';
|
|---|
| 273 | code_ns_fraction (ns, sbuf + UINTMAX_STRSIZE_BOUND);
|
|---|
| 274 | return np;
|
|---|
| 275 | }
|
|---|
| 276 | |
|---|
| 277 |
|
|---|
| 278 | /* File handling. */
|
|---|
| 279 |
|
|---|
| 280 | /* Saved names in case backup needs to be undone. */
|
|---|
| 281 | static char *before_backup_name;
|
|---|
| 282 | static char *after_backup_name;
|
|---|
| 283 |
|
|---|
| 284 | /* Return 1 if FILE_NAME is obviously "." or "/". */
|
|---|
| 285 | static bool
|
|---|
| 286 | must_be_dot_or_slash (char const *file_name)
|
|---|
| 287 | {
|
|---|
| 288 | file_name += FILE_SYSTEM_PREFIX_LEN (file_name);
|
|---|
| 289 |
|
|---|
| 290 | if (ISSLASH (file_name[0]))
|
|---|
| 291 | {
|
|---|
| 292 | for (;;)
|
|---|
| 293 | if (ISSLASH (file_name[1]))
|
|---|
| 294 | file_name++;
|
|---|
| 295 | else if (file_name[1] == '.'
|
|---|
| 296 | && ISSLASH (file_name[2 + (file_name[2] == '.')]))
|
|---|
| 297 | file_name += 2 + (file_name[2] == '.');
|
|---|
| 298 | else
|
|---|
| 299 | return ! file_name[1];
|
|---|
| 300 | }
|
|---|
| 301 | else
|
|---|
| 302 | {
|
|---|
| 303 | while (file_name[0] == '.' && ISSLASH (file_name[1]))
|
|---|
| 304 | {
|
|---|
| 305 | file_name += 2;
|
|---|
| 306 | while (ISSLASH (*file_name))
|
|---|
| 307 | file_name++;
|
|---|
| 308 | }
|
|---|
| 309 |
|
|---|
| 310 | return ! file_name[0] || (file_name[0] == '.' && ! file_name[1]);
|
|---|
| 311 | }
|
|---|
| 312 | }
|
|---|
| 313 |
|
|---|
| 314 | /* Some implementations of rmdir let you remove '.' or '/'.
|
|---|
| 315 | Report an error with errno set to zero for obvious cases of this;
|
|---|
| 316 | otherwise call rmdir. */
|
|---|
| 317 | static int
|
|---|
| 318 | safer_rmdir (const char *file_name)
|
|---|
| 319 | {
|
|---|
| 320 | if (must_be_dot_or_slash (file_name))
|
|---|
| 321 | {
|
|---|
| 322 | errno = 0;
|
|---|
| 323 | return -1;
|
|---|
| 324 | }
|
|---|
| 325 |
|
|---|
| 326 | return rmdir (file_name);
|
|---|
| 327 | }
|
|---|
| 328 |
|
|---|
| 329 | /* Remove FILE_NAME, returning 1 on success. If FILE_NAME is a directory,
|
|---|
| 330 | then if OPTION is RECURSIVE_REMOVE_OPTION is set remove FILE_NAME
|
|---|
| 331 | recursively; otherwise, remove it only if it is empty. If FILE_NAME is
|
|---|
| 332 | a directory that cannot be removed (e.g., because it is nonempty)
|
|---|
| 333 | and if OPTION is WANT_DIRECTORY_REMOVE_OPTION, then return -1.
|
|---|
| 334 | Return 0 on error, with errno set; if FILE_NAME is obviously the working
|
|---|
| 335 | directory return zero with errno set to zero. */
|
|---|
| 336 | int
|
|---|
| 337 | remove_any_file (const char *file_name, enum remove_option option)
|
|---|
| 338 | {
|
|---|
| 339 | /* Try unlink first if we cannot unlink directories, as this saves
|
|---|
| 340 | us a system call in the common case where we're removing a
|
|---|
| 341 | non-directory. */
|
|---|
| 342 | bool try_unlink_first = cannot_unlink_dir ();
|
|---|
| 343 |
|
|---|
| 344 | if (try_unlink_first)
|
|---|
| 345 | {
|
|---|
| 346 | if (unlink (file_name) == 0)
|
|---|
| 347 | return 1;
|
|---|
| 348 |
|
|---|
| 349 | /* POSIX 1003.1-2001 requires EPERM when attempting to unlink a
|
|---|
| 350 | directory without appropriate privileges, but many Linux
|
|---|
| 351 | kernels return the more-sensible EISDIR. */
|
|---|
| 352 | if (errno != EPERM && errno != EISDIR)
|
|---|
| 353 | return 0;
|
|---|
| 354 | }
|
|---|
| 355 |
|
|---|
| 356 | if (safer_rmdir (file_name) == 0)
|
|---|
| 357 | return 1;
|
|---|
| 358 |
|
|---|
| 359 | switch (errno)
|
|---|
| 360 | {
|
|---|
| 361 | case ENOTDIR:
|
|---|
| 362 | return !try_unlink_first && unlink (file_name) == 0;
|
|---|
| 363 |
|
|---|
| 364 | case 0:
|
|---|
| 365 | case EEXIST:
|
|---|
| 366 | #if defined ENOTEMPTY && ENOTEMPTY != EEXIST
|
|---|
| 367 | case ENOTEMPTY:
|
|---|
| 368 | #endif
|
|---|
| 369 | switch (option)
|
|---|
| 370 | {
|
|---|
| 371 | case ORDINARY_REMOVE_OPTION:
|
|---|
| 372 | break;
|
|---|
| 373 |
|
|---|
| 374 | case WANT_DIRECTORY_REMOVE_OPTION:
|
|---|
| 375 | return -1;
|
|---|
| 376 |
|
|---|
| 377 | case RECURSIVE_REMOVE_OPTION:
|
|---|
| 378 | {
|
|---|
| 379 | char *directory = savedir (file_name);
|
|---|
| 380 | char const *entry;
|
|---|
| 381 | size_t entrylen;
|
|---|
| 382 |
|
|---|
| 383 | if (! directory)
|
|---|
| 384 | return 0;
|
|---|
| 385 |
|
|---|
| 386 | for (entry = directory;
|
|---|
| 387 | (entrylen = strlen (entry)) != 0;
|
|---|
| 388 | entry += entrylen + 1)
|
|---|
| 389 | {
|
|---|
| 390 | char *file_name_buffer = new_name (file_name, entry);
|
|---|
| 391 | int r = remove_any_file (file_name_buffer,
|
|---|
| 392 | RECURSIVE_REMOVE_OPTION);
|
|---|
| 393 | int e = errno;
|
|---|
| 394 | free (file_name_buffer);
|
|---|
| 395 |
|
|---|
| 396 | if (! r)
|
|---|
| 397 | {
|
|---|
| 398 | free (directory);
|
|---|
| 399 | errno = e;
|
|---|
| 400 | return 0;
|
|---|
| 401 | }
|
|---|
| 402 | }
|
|---|
| 403 |
|
|---|
| 404 | free (directory);
|
|---|
| 405 | return safer_rmdir (file_name) == 0;
|
|---|
| 406 | }
|
|---|
| 407 | }
|
|---|
| 408 | break;
|
|---|
| 409 | }
|
|---|
| 410 |
|
|---|
| 411 | return 0;
|
|---|
| 412 | }
|
|---|
| 413 |
|
|---|
| 414 | /* Check if FILE_NAME already exists and make a backup of it right now.
|
|---|
| 415 | Return success (nonzero) only if the backup is either unneeded, or
|
|---|
| 416 | successful. For now, directories are considered to never need
|
|---|
| 417 | backup. If THIS_IS_THE_ARCHIVE is nonzero, this is the archive and
|
|---|
| 418 | so, we do not have to backup block or character devices, nor remote
|
|---|
| 419 | entities. */
|
|---|
| 420 | bool
|
|---|
| 421 | maybe_backup_file (const char *file_name, bool this_is_the_archive)
|
|---|
| 422 | {
|
|---|
| 423 | struct stat file_stat;
|
|---|
| 424 |
|
|---|
| 425 | /* Check if we really need to backup the file. */
|
|---|
| 426 |
|
|---|
| 427 | if (this_is_the_archive && _remdev (file_name))
|
|---|
| 428 | return true;
|
|---|
| 429 |
|
|---|
| 430 | if (stat (file_name, &file_stat))
|
|---|
| 431 | {
|
|---|
| 432 | if (errno == ENOENT)
|
|---|
| 433 | return true;
|
|---|
| 434 |
|
|---|
| 435 | stat_error (file_name);
|
|---|
| 436 | return false;
|
|---|
| 437 | }
|
|---|
| 438 |
|
|---|
| 439 | if (S_ISDIR (file_stat.st_mode))
|
|---|
| 440 | return true;
|
|---|
| 441 |
|
|---|
| 442 | if (this_is_the_archive
|
|---|
| 443 | && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
|
|---|
| 444 | return true;
|
|---|
| 445 |
|
|---|
| 446 | assign_string (&before_backup_name, file_name);
|
|---|
| 447 |
|
|---|
| 448 | /* A run situation may exist between Emacs or other GNU programs trying to
|
|---|
| 449 | make a backup for the same file simultaneously. If theoretically
|
|---|
| 450 | possible, real problems are unlikely. Doing any better would require a
|
|---|
| 451 | convention, GNU-wide, for all programs doing backups. */
|
|---|
| 452 |
|
|---|
| 453 | assign_string (&after_backup_name, 0);
|
|---|
| 454 | after_backup_name = find_backup_file_name (file_name, backup_type);
|
|---|
| 455 | if (! after_backup_name)
|
|---|
| 456 | xalloc_die ();
|
|---|
| 457 |
|
|---|
| 458 | if (rename (before_backup_name, after_backup_name) == 0)
|
|---|
| 459 | {
|
|---|
| 460 | if (verbose_option)
|
|---|
| 461 | fprintf (stdlis, _("Renaming %s to %s\n"),
|
|---|
| 462 | quote_n (0, before_backup_name),
|
|---|
| 463 | quote_n (1, after_backup_name));
|
|---|
| 464 | return true;
|
|---|
| 465 | }
|
|---|
| 466 | else
|
|---|
| 467 | {
|
|---|
| 468 | /* The backup operation failed. */
|
|---|
| 469 | int e = errno;
|
|---|
| 470 | ERROR ((0, e, _("%s: Cannot rename to %s"),
|
|---|
| 471 | quotearg_colon (before_backup_name),
|
|---|
| 472 | quote_n (1, after_backup_name)));
|
|---|
| 473 | assign_string (&after_backup_name, 0);
|
|---|
| 474 | return false;
|
|---|
| 475 | }
|
|---|
| 476 | }
|
|---|
| 477 |
|
|---|
| 478 | /* Try to restore the recently backed up file to its original name.
|
|---|
| 479 | This is usually only needed after a failed extraction. */
|
|---|
| 480 | void
|
|---|
| 481 | undo_last_backup (void)
|
|---|
| 482 | {
|
|---|
| 483 | if (after_backup_name)
|
|---|
| 484 | {
|
|---|
| 485 | if (rename (after_backup_name, before_backup_name) != 0)
|
|---|
| 486 | {
|
|---|
| 487 | int e = errno;
|
|---|
| 488 | ERROR ((0, e, _("%s: Cannot rename to %s"),
|
|---|
| 489 | quotearg_colon (after_backup_name),
|
|---|
| 490 | quote_n (1, before_backup_name)));
|
|---|
| 491 | }
|
|---|
| 492 | if (verbose_option)
|
|---|
| 493 | fprintf (stdlis, _("Renaming %s back to %s\n"),
|
|---|
| 494 | quote_n (0, after_backup_name),
|
|---|
| 495 | quote_n (1, before_backup_name));
|
|---|
| 496 | assign_string (&after_backup_name, 0);
|
|---|
| 497 | }
|
|---|
| 498 | }
|
|---|
| 499 |
|
|---|
| 500 | /* Depending on DEREF, apply either stat or lstat to (NAME, BUF). */
|
|---|
| 501 | int
|
|---|
| 502 | deref_stat (bool deref, char const *name, struct stat *buf)
|
|---|
| 503 | {
|
|---|
| 504 | return deref ? stat (name, buf) : lstat (name, buf);
|
|---|
| 505 | }
|
|---|
| 506 |
|
|---|
| 507 | /* Set FD's (i.e., FILE's) access time to TIMESPEC[0]. If that's not
|
|---|
| 508 | possible to do by itself, set its access and data modification
|
|---|
| 509 | times to TIMESPEC[0] and TIMESPEC[1], respectively. */
|
|---|
| 510 | int
|
|---|
| 511 | set_file_atime (int fd, char const *file, struct timespec const timespec[2])
|
|---|
| 512 | {
|
|---|
| 513 | #ifdef _FIOSATIME
|
|---|
| 514 | if (0 <= fd)
|
|---|
| 515 | {
|
|---|
| 516 | struct timeval timeval;
|
|---|
| 517 | timeval.tv_sec = timespec[0].tv_sec;
|
|---|
| 518 | timeval.tv_usec = timespec[0].tv_nsec / 1000;
|
|---|
| 519 | if (ioctl (fd, _FIOSATIME, &timeval) == 0)
|
|---|
| 520 | return 0;
|
|---|
| 521 | }
|
|---|
| 522 | #endif
|
|---|
| 523 |
|
|---|
| 524 | return futimens (fd, file, timespec);
|
|---|
| 525 | }
|
|---|
| 526 |
|
|---|
| 527 | /* A description of a working directory. */
|
|---|
| 528 | struct wd
|
|---|
| 529 | {
|
|---|
| 530 | char const *name;
|
|---|
| 531 | int saved;
|
|---|
| 532 | struct saved_cwd saved_cwd;
|
|---|
| 533 | };
|
|---|
| 534 |
|
|---|
| 535 | /* A vector of chdir targets. wd[0] is the initial working directory. */
|
|---|
| 536 | static struct wd *wd;
|
|---|
| 537 |
|
|---|
| 538 | /* The number of working directories in the vector. */
|
|---|
| 539 | static size_t wds;
|
|---|
| 540 |
|
|---|
| 541 | /* The allocated size of the vector. */
|
|---|
| 542 | static size_t wd_alloc;
|
|---|
| 543 |
|
|---|
| 544 | /* DIR is the operand of a -C option; add it to vector of chdir targets,
|
|---|
| 545 | and return the index of its location. */
|
|---|
| 546 | int
|
|---|
| 547 | chdir_arg (char const *dir)
|
|---|
| 548 | {
|
|---|
| 549 | if (wds == wd_alloc)
|
|---|
| 550 | {
|
|---|
| 551 | if (wd_alloc == 0)
|
|---|
| 552 | {
|
|---|
| 553 | wd_alloc = 2;
|
|---|
| 554 | wd = xmalloc (sizeof *wd * wd_alloc);
|
|---|
| 555 | }
|
|---|
| 556 | else
|
|---|
| 557 | wd = x2nrealloc (wd, &wd_alloc, sizeof *wd);
|
|---|
| 558 |
|
|---|
| 559 | if (! wds)
|
|---|
| 560 | {
|
|---|
| 561 | wd[wds].name = ".";
|
|---|
| 562 | wd[wds].saved = 0;
|
|---|
| 563 | wds++;
|
|---|
| 564 | }
|
|---|
| 565 | }
|
|---|
| 566 |
|
|---|
| 567 | /* Optimize the common special case of the working directory,
|
|---|
| 568 | or the working directory as a prefix. */
|
|---|
| 569 | if (dir[0])
|
|---|
| 570 | {
|
|---|
| 571 | while (dir[0] == '.' && ISSLASH (dir[1]))
|
|---|
| 572 | for (dir += 2; ISSLASH (*dir); dir++)
|
|---|
| 573 | continue;
|
|---|
| 574 | if (! dir[dir[0] == '.'])
|
|---|
| 575 | return wds - 1;
|
|---|
| 576 | }
|
|---|
| 577 |
|
|---|
| 578 | wd[wds].name = dir;
|
|---|
| 579 | wd[wds].saved = 0;
|
|---|
| 580 | return wds++;
|
|---|
| 581 | }
|
|---|
| 582 |
|
|---|
| 583 | /* Return maximum number of open files */
|
|---|
| 584 | int
|
|---|
| 585 | get_max_open_files ()
|
|---|
| 586 | {
|
|---|
| 587 | #if defined _SC_OPEN_MAX
|
|---|
| 588 | return sysconf (_SC_OPEN_MAX);
|
|---|
| 589 | #elif defined RLIMIT_NOFILE
|
|---|
| 590 | struct rlimit rlim;
|
|---|
| 591 |
|
|---|
| 592 | if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
|
|---|
| 593 | return rlim.rlim_max;
|
|---|
| 594 | #elif defined HAVE_GETDTABLESIZE
|
|---|
| 595 | return getdtablesize ();
|
|---|
| 596 | #endif
|
|---|
| 597 | return -1;
|
|---|
| 598 | }
|
|---|
| 599 |
|
|---|
| 600 | /* Close all descriptors, except the first three */
|
|---|
| 601 | void
|
|---|
| 602 | closeopen ()
|
|---|
| 603 | {
|
|---|
| 604 | int i;
|
|---|
| 605 |
|
|---|
| 606 | for (i = get_max_open_files () - 1; i > 2; i--)
|
|---|
| 607 | close (i);
|
|---|
| 608 | }
|
|---|
| 609 |
|
|---|
| 610 | /* Change to directory I. If I is 0, change to the initial working
|
|---|
| 611 | directory; otherwise, I must be a value returned by chdir_arg. */
|
|---|
| 612 | void
|
|---|
| 613 | chdir_do (int i)
|
|---|
| 614 | {
|
|---|
| 615 | static int previous;
|
|---|
| 616 | static int saved_count;
|
|---|
| 617 |
|
|---|
| 618 | if (previous != i)
|
|---|
| 619 | {
|
|---|
| 620 | struct wd *prev = &wd[previous];
|
|---|
| 621 | struct wd *curr = &wd[i];
|
|---|
| 622 |
|
|---|
| 623 | if (! prev->saved)
|
|---|
| 624 | {
|
|---|
| 625 | prev->saved = 1;
|
|---|
| 626 | saved_count++;
|
|---|
| 627 | /* Make sure we still have at least one descriptor available */
|
|---|
| 628 | if (saved_count >= get_max_open_files () - 4)
|
|---|
| 629 | {
|
|---|
| 630 | /* Force restore_cwd to use chdir_long */
|
|---|
| 631 | prev->saved_cwd.desc = -1;
|
|---|
| 632 | prev->saved_cwd.name = xgetcwd ();
|
|---|
| 633 | }
|
|---|
| 634 | else if (save_cwd (&prev->saved_cwd) != 0)
|
|---|
| 635 | FATAL_ERROR ((0, 0, _("Cannot save working directory")));
|
|---|
| 636 | }
|
|---|
| 637 |
|
|---|
| 638 | if (curr->saved)
|
|---|
| 639 | {
|
|---|
| 640 | if (restore_cwd (&curr->saved_cwd))
|
|---|
| 641 | FATAL_ERROR ((0, 0, _("Cannot change working directory")));
|
|---|
| 642 | }
|
|---|
| 643 | else
|
|---|
| 644 | {
|
|---|
| 645 | if (i && ! ISSLASH (curr->name[0]))
|
|---|
| 646 | chdir_do (i - 1);
|
|---|
| 647 | if (chdir (curr->name) != 0)
|
|---|
| 648 | chdir_fatal (curr->name);
|
|---|
| 649 | }
|
|---|
| 650 |
|
|---|
| 651 | previous = i;
|
|---|
| 652 | }
|
|---|
| 653 | }
|
|---|
| 654 | |
|---|
| 655 |
|
|---|
| 656 | void
|
|---|
| 657 | close_diag (char const *name)
|
|---|
| 658 | {
|
|---|
| 659 | if (ignore_failed_read_option)
|
|---|
| 660 | close_warn (name);
|
|---|
| 661 | else
|
|---|
| 662 | close_error (name);
|
|---|
| 663 | }
|
|---|
| 664 |
|
|---|
| 665 | void
|
|---|
| 666 | open_diag (char const *name)
|
|---|
| 667 | {
|
|---|
| 668 | if (ignore_failed_read_option)
|
|---|
| 669 | open_warn (name);
|
|---|
| 670 | else
|
|---|
| 671 | open_error (name);
|
|---|
| 672 | }
|
|---|
| 673 |
|
|---|
| 674 | void
|
|---|
| 675 | read_diag_details (char const *name, off_t offset, size_t size)
|
|---|
| 676 | {
|
|---|
| 677 | if (ignore_failed_read_option)
|
|---|
| 678 | read_warn_details (name, offset, size);
|
|---|
| 679 | else
|
|---|
| 680 | read_error_details (name, offset, size);
|
|---|
| 681 | }
|
|---|
| 682 |
|
|---|
| 683 | void
|
|---|
| 684 | readlink_diag (char const *name)
|
|---|
| 685 | {
|
|---|
| 686 | if (ignore_failed_read_option)
|
|---|
| 687 | readlink_warn (name);
|
|---|
| 688 | else
|
|---|
| 689 | readlink_error (name);
|
|---|
| 690 | }
|
|---|
| 691 |
|
|---|
| 692 | void
|
|---|
| 693 | savedir_diag (char const *name)
|
|---|
| 694 | {
|
|---|
| 695 | if (ignore_failed_read_option)
|
|---|
| 696 | savedir_warn (name);
|
|---|
| 697 | else
|
|---|
| 698 | savedir_error (name);
|
|---|
| 699 | }
|
|---|
| 700 |
|
|---|
| 701 | void
|
|---|
| 702 | seek_diag_details (char const *name, off_t offset)
|
|---|
| 703 | {
|
|---|
| 704 | if (ignore_failed_read_option)
|
|---|
| 705 | seek_warn_details (name, offset);
|
|---|
| 706 | else
|
|---|
| 707 | seek_error_details (name, offset);
|
|---|
| 708 | }
|
|---|
| 709 |
|
|---|
| 710 | void
|
|---|
| 711 | stat_diag (char const *name)
|
|---|
| 712 | {
|
|---|
| 713 | if (ignore_failed_read_option)
|
|---|
| 714 | stat_warn (name);
|
|---|
| 715 | else
|
|---|
| 716 | stat_error (name);
|
|---|
| 717 | }
|
|---|
| 718 |
|
|---|
| 719 | void
|
|---|
| 720 | write_fatal_details (char const *name, ssize_t status, size_t size)
|
|---|
| 721 | {
|
|---|
| 722 | write_error_details (name, status, size);
|
|---|
| 723 | fatal_exit ();
|
|---|
| 724 | }
|
|---|
| 725 |
|
|---|
| 726 | /* Fork, aborting if unsuccessful. */
|
|---|
| 727 | pid_t
|
|---|
| 728 | xfork (void)
|
|---|
| 729 | {
|
|---|
| 730 | pid_t p = fork ();
|
|---|
| 731 | if (p == (pid_t) -1)
|
|---|
| 732 | call_arg_fatal ("fork", _("child process"));
|
|---|
| 733 | return p;
|
|---|
| 734 | }
|
|---|
| 735 |
|
|---|
| 736 | /* Create a pipe, aborting if unsuccessful. */
|
|---|
| 737 | void
|
|---|
| 738 | xpipe (int fd[2])
|
|---|
| 739 | {
|
|---|
| 740 | if (pipe (fd) < 0)
|
|---|
| 741 | call_arg_fatal ("pipe", _("interprocess channel"));
|
|---|
| 742 | }
|
|---|
| 743 |
|
|---|
| 744 | /* Return PTR, aligned upward to the next multiple of ALIGNMENT.
|
|---|
| 745 | ALIGNMENT must be nonzero. The caller must arrange for ((char *)
|
|---|
| 746 | PTR) through ((char *) PTR + ALIGNMENT - 1) to be addressable
|
|---|
| 747 | locations. */
|
|---|
| 748 |
|
|---|
| 749 | static inline void *
|
|---|
| 750 | ptr_align (void *ptr, size_t alignment)
|
|---|
| 751 | {
|
|---|
| 752 | char *p0 = ptr;
|
|---|
| 753 | char *p1 = p0 + alignment - 1;
|
|---|
| 754 | return p1 - (size_t) p1 % alignment;
|
|---|
| 755 | }
|
|---|
| 756 |
|
|---|
| 757 | /* Return the address of a page-aligned buffer of at least SIZE bytes.
|
|---|
| 758 | The caller should free *PTR when done with the buffer. */
|
|---|
| 759 |
|
|---|
| 760 | void *
|
|---|
| 761 | page_aligned_alloc (void **ptr, size_t size)
|
|---|
| 762 | {
|
|---|
| 763 | size_t alignment = getpagesize ();
|
|---|
| 764 | size_t size1 = size + alignment;
|
|---|
| 765 | if (size1 < size)
|
|---|
| 766 | xalloc_die ();
|
|---|
| 767 | *ptr = xmalloc (size1);
|
|---|
| 768 | return ptr_align (*ptr, alignment);
|
|---|
| 769 | }
|
|---|