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 | #if defined __KLIBC__ /* Workaround for kLIBC bug #163. */
|
---|
362 | # if __KLIBC_VERSION__ <= 0x60002
|
---|
363 | case ENOENT:
|
---|
364 | {
|
---|
365 | struct stat s;
|
---|
366 | if ( lstat (file_name, &s) != 0
|
---|
367 | || S_ISDIR (s.st_mode) /* paranoia */)
|
---|
368 | {
|
---|
369 | errno = ENOENT;
|
---|
370 | break;
|
---|
371 | }
|
---|
372 | errno = ENOTDIR;
|
---|
373 | /* fall thru */
|
---|
374 | }
|
---|
375 | # endif
|
---|
376 | #endif
|
---|
377 | case ENOTDIR:
|
---|
378 | return !try_unlink_first && unlink (file_name) == 0;
|
---|
379 |
|
---|
380 | case 0:
|
---|
381 | case EEXIST:
|
---|
382 | #if defined ENOTEMPTY && ENOTEMPTY != EEXIST
|
---|
383 | case ENOTEMPTY:
|
---|
384 | #endif
|
---|
385 | switch (option)
|
---|
386 | {
|
---|
387 | case ORDINARY_REMOVE_OPTION:
|
---|
388 | break;
|
---|
389 |
|
---|
390 | case WANT_DIRECTORY_REMOVE_OPTION:
|
---|
391 | return -1;
|
---|
392 |
|
---|
393 | case RECURSIVE_REMOVE_OPTION:
|
---|
394 | {
|
---|
395 | char *directory = savedir (file_name);
|
---|
396 | char const *entry;
|
---|
397 | size_t entrylen;
|
---|
398 |
|
---|
399 | if (! directory)
|
---|
400 | return 0;
|
---|
401 |
|
---|
402 | for (entry = directory;
|
---|
403 | (entrylen = strlen (entry)) != 0;
|
---|
404 | entry += entrylen + 1)
|
---|
405 | {
|
---|
406 | char *file_name_buffer = new_name (file_name, entry);
|
---|
407 | int r = remove_any_file (file_name_buffer,
|
---|
408 | RECURSIVE_REMOVE_OPTION);
|
---|
409 | int e = errno;
|
---|
410 | free (file_name_buffer);
|
---|
411 |
|
---|
412 | if (! r)
|
---|
413 | {
|
---|
414 | free (directory);
|
---|
415 | errno = e;
|
---|
416 | return 0;
|
---|
417 | }
|
---|
418 | }
|
---|
419 |
|
---|
420 | free (directory);
|
---|
421 | return safer_rmdir (file_name) == 0;
|
---|
422 | }
|
---|
423 | }
|
---|
424 | break;
|
---|
425 | }
|
---|
426 |
|
---|
427 | return 0;
|
---|
428 | }
|
---|
429 |
|
---|
430 | /* Check if FILE_NAME already exists and make a backup of it right now.
|
---|
431 | Return success (nonzero) only if the backup is either unneeded, or
|
---|
432 | successful. For now, directories are considered to never need
|
---|
433 | backup. If THIS_IS_THE_ARCHIVE is nonzero, this is the archive and
|
---|
434 | so, we do not have to backup block or character devices, nor remote
|
---|
435 | entities. */
|
---|
436 | bool
|
---|
437 | maybe_backup_file (const char *file_name, bool this_is_the_archive)
|
---|
438 | {
|
---|
439 | struct stat file_stat;
|
---|
440 |
|
---|
441 | /* Check if we really need to backup the file. */
|
---|
442 |
|
---|
443 | if (this_is_the_archive && _remdev (file_name))
|
---|
444 | return true;
|
---|
445 |
|
---|
446 | if (stat (file_name, &file_stat))
|
---|
447 | {
|
---|
448 | if (errno == ENOENT)
|
---|
449 | return true;
|
---|
450 |
|
---|
451 | stat_error (file_name);
|
---|
452 | return false;
|
---|
453 | }
|
---|
454 |
|
---|
455 | if (S_ISDIR (file_stat.st_mode))
|
---|
456 | return true;
|
---|
457 |
|
---|
458 | if (this_is_the_archive
|
---|
459 | && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
|
---|
460 | return true;
|
---|
461 |
|
---|
462 | assign_string (&before_backup_name, file_name);
|
---|
463 |
|
---|
464 | /* A run situation may exist between Emacs or other GNU programs trying to
|
---|
465 | make a backup for the same file simultaneously. If theoretically
|
---|
466 | possible, real problems are unlikely. Doing any better would require a
|
---|
467 | convention, GNU-wide, for all programs doing backups. */
|
---|
468 |
|
---|
469 | assign_string (&after_backup_name, 0);
|
---|
470 | after_backup_name = find_backup_file_name (file_name, backup_type);
|
---|
471 | if (! after_backup_name)
|
---|
472 | xalloc_die ();
|
---|
473 |
|
---|
474 | if (rename (before_backup_name, after_backup_name) == 0)
|
---|
475 | {
|
---|
476 | if (verbose_option)
|
---|
477 | fprintf (stdlis, _("Renaming %s to %s\n"),
|
---|
478 | quote_n (0, before_backup_name),
|
---|
479 | quote_n (1, after_backup_name));
|
---|
480 | return true;
|
---|
481 | }
|
---|
482 | else
|
---|
483 | {
|
---|
484 | /* The backup operation failed. */
|
---|
485 | int e = errno;
|
---|
486 | ERROR ((0, e, _("%s: Cannot rename to %s"),
|
---|
487 | quotearg_colon (before_backup_name),
|
---|
488 | quote_n (1, after_backup_name)));
|
---|
489 | assign_string (&after_backup_name, 0);
|
---|
490 | return false;
|
---|
491 | }
|
---|
492 | }
|
---|
493 |
|
---|
494 | /* Try to restore the recently backed up file to its original name.
|
---|
495 | This is usually only needed after a failed extraction. */
|
---|
496 | void
|
---|
497 | undo_last_backup (void)
|
---|
498 | {
|
---|
499 | if (after_backup_name)
|
---|
500 | {
|
---|
501 | if (rename (after_backup_name, before_backup_name) != 0)
|
---|
502 | {
|
---|
503 | int e = errno;
|
---|
504 | ERROR ((0, e, _("%s: Cannot rename to %s"),
|
---|
505 | quotearg_colon (after_backup_name),
|
---|
506 | quote_n (1, before_backup_name)));
|
---|
507 | }
|
---|
508 | if (verbose_option)
|
---|
509 | fprintf (stdlis, _("Renaming %s back to %s\n"),
|
---|
510 | quote_n (0, after_backup_name),
|
---|
511 | quote_n (1, before_backup_name));
|
---|
512 | assign_string (&after_backup_name, 0);
|
---|
513 | }
|
---|
514 | }
|
---|
515 |
|
---|
516 | /* Depending on DEREF, apply either stat or lstat to (NAME, BUF). */
|
---|
517 | int
|
---|
518 | deref_stat (bool deref, char const *name, struct stat *buf)
|
---|
519 | {
|
---|
520 | return deref ? stat (name, buf) : lstat (name, buf);
|
---|
521 | }
|
---|
522 |
|
---|
523 | /* Set FD's (i.e., FILE's) access time to TIMESPEC[0]. If that's not
|
---|
524 | possible to do by itself, set its access and data modification
|
---|
525 | times to TIMESPEC[0] and TIMESPEC[1], respectively. */
|
---|
526 | int
|
---|
527 | set_file_atime (int fd, char const *file, struct timespec const timespec[2])
|
---|
528 | {
|
---|
529 | #ifdef _FIOSATIME
|
---|
530 | if (0 <= fd)
|
---|
531 | {
|
---|
532 | struct timeval timeval;
|
---|
533 | timeval.tv_sec = timespec[0].tv_sec;
|
---|
534 | timeval.tv_usec = timespec[0].tv_nsec / 1000;
|
---|
535 | if (ioctl (fd, _FIOSATIME, &timeval) == 0)
|
---|
536 | return 0;
|
---|
537 | }
|
---|
538 | #endif
|
---|
539 |
|
---|
540 | return futimens (fd, file, timespec);
|
---|
541 | }
|
---|
542 |
|
---|
543 | /* A description of a working directory. */
|
---|
544 | struct wd
|
---|
545 | {
|
---|
546 | char const *name;
|
---|
547 | int saved;
|
---|
548 | struct saved_cwd saved_cwd;
|
---|
549 | };
|
---|
550 |
|
---|
551 | /* A vector of chdir targets. wd[0] is the initial working directory. */
|
---|
552 | static struct wd *wd;
|
---|
553 |
|
---|
554 | /* The number of working directories in the vector. */
|
---|
555 | static size_t wds;
|
---|
556 |
|
---|
557 | /* The allocated size of the vector. */
|
---|
558 | static size_t wd_alloc;
|
---|
559 |
|
---|
560 | /* DIR is the operand of a -C option; add it to vector of chdir targets,
|
---|
561 | and return the index of its location. */
|
---|
562 | int
|
---|
563 | chdir_arg (char const *dir)
|
---|
564 | {
|
---|
565 | if (wds == wd_alloc)
|
---|
566 | {
|
---|
567 | if (wd_alloc == 0)
|
---|
568 | {
|
---|
569 | wd_alloc = 2;
|
---|
570 | wd = xmalloc (sizeof *wd * wd_alloc);
|
---|
571 | }
|
---|
572 | else
|
---|
573 | wd = x2nrealloc (wd, &wd_alloc, sizeof *wd);
|
---|
574 |
|
---|
575 | if (! wds)
|
---|
576 | {
|
---|
577 | wd[wds].name = ".";
|
---|
578 | wd[wds].saved = 0;
|
---|
579 | wds++;
|
---|
580 | }
|
---|
581 | }
|
---|
582 |
|
---|
583 | /* Optimize the common special case of the working directory,
|
---|
584 | or the working directory as a prefix. */
|
---|
585 | if (dir[0])
|
---|
586 | {
|
---|
587 | while (dir[0] == '.' && ISSLASH (dir[1]))
|
---|
588 | for (dir += 2; ISSLASH (*dir); dir++)
|
---|
589 | continue;
|
---|
590 | if (! dir[dir[0] == '.'])
|
---|
591 | return wds - 1;
|
---|
592 | }
|
---|
593 |
|
---|
594 | wd[wds].name = dir;
|
---|
595 | wd[wds].saved = 0;
|
---|
596 | return wds++;
|
---|
597 | }
|
---|
598 |
|
---|
599 | /* Return maximum number of open files */
|
---|
600 | int
|
---|
601 | get_max_open_files ()
|
---|
602 | {
|
---|
603 | #if defined _SC_OPEN_MAX
|
---|
604 | return sysconf (_SC_OPEN_MAX);
|
---|
605 | #elif defined RLIMIT_NOFILE
|
---|
606 | struct rlimit rlim;
|
---|
607 |
|
---|
608 | if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
|
---|
609 | return rlim.rlim_max;
|
---|
610 | #elif defined HAVE_GETDTABLESIZE
|
---|
611 | return getdtablesize ();
|
---|
612 | #endif
|
---|
613 | return -1;
|
---|
614 | }
|
---|
615 |
|
---|
616 | /* Close all descriptors, except the first three */
|
---|
617 | void
|
---|
618 | closeopen ()
|
---|
619 | {
|
---|
620 | int i;
|
---|
621 |
|
---|
622 | for (i = get_max_open_files () - 1; i > 2; i--)
|
---|
623 | close (i);
|
---|
624 | }
|
---|
625 |
|
---|
626 | /* Change to directory I. If I is 0, change to the initial working
|
---|
627 | directory; otherwise, I must be a value returned by chdir_arg. */
|
---|
628 | void
|
---|
629 | chdir_do (int i)
|
---|
630 | {
|
---|
631 | static int previous;
|
---|
632 | static int saved_count;
|
---|
633 |
|
---|
634 | if (previous != i)
|
---|
635 | {
|
---|
636 | struct wd *prev = &wd[previous];
|
---|
637 | struct wd *curr = &wd[i];
|
---|
638 |
|
---|
639 | if (! prev->saved)
|
---|
640 | {
|
---|
641 | prev->saved = 1;
|
---|
642 | saved_count++;
|
---|
643 | /* Make sure we still have at least one descriptor available */
|
---|
644 | if (saved_count >= get_max_open_files () - 4)
|
---|
645 | {
|
---|
646 | /* Force restore_cwd to use chdir_long */
|
---|
647 | prev->saved_cwd.desc = -1;
|
---|
648 | prev->saved_cwd.name = xgetcwd ();
|
---|
649 | }
|
---|
650 | else if (save_cwd (&prev->saved_cwd) != 0)
|
---|
651 | FATAL_ERROR ((0, 0, _("Cannot save working directory")));
|
---|
652 | }
|
---|
653 |
|
---|
654 | if (curr->saved)
|
---|
655 | {
|
---|
656 | if (restore_cwd (&curr->saved_cwd))
|
---|
657 | FATAL_ERROR ((0, 0, _("Cannot change working directory")));
|
---|
658 | }
|
---|
659 | else
|
---|
660 | {
|
---|
661 | if (i && ! ISSLASH (curr->name[0]))
|
---|
662 | chdir_do (i - 1);
|
---|
663 | if (chdir (curr->name) != 0)
|
---|
664 | chdir_fatal (curr->name);
|
---|
665 | }
|
---|
666 |
|
---|
667 | previous = i;
|
---|
668 | }
|
---|
669 | }
|
---|
670 | |
---|
671 |
|
---|
672 | void
|
---|
673 | close_diag (char const *name)
|
---|
674 | {
|
---|
675 | if (ignore_failed_read_option)
|
---|
676 | close_warn (name);
|
---|
677 | else
|
---|
678 | close_error (name);
|
---|
679 | }
|
---|
680 |
|
---|
681 | void
|
---|
682 | open_diag (char const *name)
|
---|
683 | {
|
---|
684 | if (ignore_failed_read_option)
|
---|
685 | open_warn (name);
|
---|
686 | else
|
---|
687 | open_error (name);
|
---|
688 | }
|
---|
689 |
|
---|
690 | void
|
---|
691 | read_diag_details (char const *name, off_t offset, size_t size)
|
---|
692 | {
|
---|
693 | if (ignore_failed_read_option)
|
---|
694 | read_warn_details (name, offset, size);
|
---|
695 | else
|
---|
696 | read_error_details (name, offset, size);
|
---|
697 | }
|
---|
698 |
|
---|
699 | void
|
---|
700 | readlink_diag (char const *name)
|
---|
701 | {
|
---|
702 | if (ignore_failed_read_option)
|
---|
703 | readlink_warn (name);
|
---|
704 | else
|
---|
705 | readlink_error (name);
|
---|
706 | }
|
---|
707 |
|
---|
708 | void
|
---|
709 | savedir_diag (char const *name)
|
---|
710 | {
|
---|
711 | if (ignore_failed_read_option)
|
---|
712 | savedir_warn (name);
|
---|
713 | else
|
---|
714 | savedir_error (name);
|
---|
715 | }
|
---|
716 |
|
---|
717 | void
|
---|
718 | seek_diag_details (char const *name, off_t offset)
|
---|
719 | {
|
---|
720 | if (ignore_failed_read_option)
|
---|
721 | seek_warn_details (name, offset);
|
---|
722 | else
|
---|
723 | seek_error_details (name, offset);
|
---|
724 | }
|
---|
725 |
|
---|
726 | void
|
---|
727 | stat_diag (char const *name)
|
---|
728 | {
|
---|
729 | if (ignore_failed_read_option)
|
---|
730 | stat_warn (name);
|
---|
731 | else
|
---|
732 | stat_error (name);
|
---|
733 | }
|
---|
734 |
|
---|
735 | void
|
---|
736 | write_fatal_details (char const *name, ssize_t status, size_t size)
|
---|
737 | {
|
---|
738 | write_error_details (name, status, size);
|
---|
739 | fatal_exit ();
|
---|
740 | }
|
---|
741 |
|
---|
742 | /* Fork, aborting if unsuccessful. */
|
---|
743 | pid_t
|
---|
744 | xfork (void)
|
---|
745 | {
|
---|
746 | pid_t p = fork ();
|
---|
747 | if (p == (pid_t) -1)
|
---|
748 | call_arg_fatal ("fork", _("child process"));
|
---|
749 | return p;
|
---|
750 | }
|
---|
751 |
|
---|
752 | /* Create a pipe, aborting if unsuccessful. */
|
---|
753 | void
|
---|
754 | xpipe (int fd[2])
|
---|
755 | {
|
---|
756 | if (pipe (fd) < 0)
|
---|
757 | call_arg_fatal ("pipe", _("interprocess channel"));
|
---|
758 | }
|
---|
759 |
|
---|
760 | /* Return PTR, aligned upward to the next multiple of ALIGNMENT.
|
---|
761 | ALIGNMENT must be nonzero. The caller must arrange for ((char *)
|
---|
762 | PTR) through ((char *) PTR + ALIGNMENT - 1) to be addressable
|
---|
763 | locations. */
|
---|
764 |
|
---|
765 | static inline void *
|
---|
766 | ptr_align (void *ptr, size_t alignment)
|
---|
767 | {
|
---|
768 | char *p0 = ptr;
|
---|
769 | char *p1 = p0 + alignment - 1;
|
---|
770 | return p1 - (size_t) p1 % alignment;
|
---|
771 | }
|
---|
772 |
|
---|
773 | /* Return the address of a page-aligned buffer of at least SIZE bytes.
|
---|
774 | The caller should free *PTR when done with the buffer. */
|
---|
775 |
|
---|
776 | void *
|
---|
777 | page_aligned_alloc (void **ptr, size_t size)
|
---|
778 | {
|
---|
779 | size_t alignment = getpagesize ();
|
---|
780 | size_t size1 = size + alignment;
|
---|
781 | if (size1 < size)
|
---|
782 | xalloc_die ();
|
---|
783 | *ptr = xmalloc (size1);
|
---|
784 | return ptr_align (*ptr, alignment);
|
---|
785 | }
|
---|