]>
Dogcows Code - chaz/tar/blob - src/misc.c
1 /* Miscellaneous functions, not really specific to GNU tar.
2 Copyright (C) 1988, 92, 94, 95, 96, 97 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any later
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #include "backupfile.h"
23 /* The following inclusion for crosschecking prototypes, only. */
26 /* Handling strings. */
28 #define ISPRINT(Char) (ISASCII (Char) && isprint (Char))
30 /*-------------------------------------------------------------------------.
31 | Assign STRING to a copy of VALUE if not NULL, or to NULL. If STRING was |
32 | not NULL, it is freed first. |
33 `-------------------------------------------------------------------------*/
36 assign_string (char **string
, const char *value
)
40 *string
= value
? xstrdup (value
) : NULL
;
43 /*------------------------------------------------------------------------.
44 | Allocate a copy of the string quoted as in C, and returns that. If the |
45 | string does not have to be quoted, it returns the NULL string. The |
46 | allocated copy should normally be freed with free() after the caller is |
49 | This is used in two contexts only: either listing a tar file for the |
50 | --list (-t) option, or generating the directory file in incremental |
52 `------------------------------------------------------------------------*/
55 quote_copy_string (const char *string
)
57 const char *source
= string
;
58 char *destination
= NULL
;
64 int character
= (unsigned char) *source
++;
66 if (character
== '\\')
70 int length
= (source
- string
) - 1;
73 buffer
= (char *) xmalloc (length
+ 5 + strlen (source
) * 4);
74 memcpy (buffer
, string
, (size_t) length
);
75 destination
= buffer
+ length
;
77 *destination
++ = '\\';
78 *destination
++ = '\\';
80 else if (ISPRINT (character
))
83 *destination
++ = character
;
89 int length
= (source
- string
) - 1;
92 buffer
= (char *) xmalloc (length
+ 5 + strlen (source
) * 4);
93 memcpy (buffer
, string
, (size_t) length
);
94 destination
= buffer
+ length
;
96 *destination
++ = '\\';
100 *destination
++ = 'n';
104 *destination
++ = 't';
108 *destination
++ = 'f';
112 *destination
++ = 'b';
116 *destination
++ = 'r';
120 *destination
++ = '?';
124 *destination
++ = (character
>> 6) + '0';
125 *destination
++ = ((character
>> 3) & 07) + '0';
126 *destination
++ = (character
& 07) + '0';
139 /*-------------------------------------------------------------------------.
140 | Takes a quoted C string (like those produced by quote_copy_string) and |
141 | turns it back into the un-quoted original. This is done in place. |
142 | Returns 0 only if the string was not properly quoted, but completes the |
143 | unquoting anyway. |
145 | This is used for reading the saved directory file in incremental dumps. |
146 | It is used for decoding old `N' records (demangling names). But also, |
147 | it is used for decoding file arguments, would they come from the shell |
148 | or a -T file, and for decoding the --exclude argument. |
149 `-------------------------------------------------------------------------*/
152 unquote_string (char *string
)
155 char *source
= string
;
156 char *destination
= string
;
163 *destination
++ = '\\';
168 *destination
++ = '\n';
173 *destination
++ = '\t';
178 *destination
++ = '\f';
183 *destination
++ = '\b';
188 *destination
++ = '\r';
193 *destination
++ = 0177;
206 int value
= *source
++ - '0';
208 if (*source
< '0' || *source
> '7')
210 *destination
++ = value
;
213 value
= value
* 8 + *source
++ - '0';
214 if (*source
< '0' || *source
> '7')
216 *destination
++ = value
;
219 value
= value
* 8 + *source
++ - '0';
220 *destination
++ = value
;
226 *destination
++ = '\\';
228 *destination
++ = *source
++;
231 else if (source
!= destination
)
232 *destination
++ = *source
++;
234 source
++, destination
++;
236 if (source
!= destination
)
248 merge_sort (char *list
, int length
, int offset
, int (*compare
) (char *, char *))
259 #define SUCCESSOR(Pointer) \
260 (*((char **) (((char *) (Pointer)) + offset)))
267 if ((*compare
) (list
, SUCCESSOR (list
)) > 0)
269 result
= SUCCESSOR (list
);
270 SUCCESSOR (result
) = list
;
271 SUCCESSOR (list
) = NULL
;
278 first_length
= (length
+ 1) / 2;
279 second_length
= length
/ 2;
280 for (cursor
= list
, counter
= first_length
- 1;
282 cursor
= SUCCESSOR (cursor
), counter
--)
284 second_list
= SUCCESSOR (cursor
);
285 SUCCESSOR (cursor
) = NULL
;
287 first_list
= merge_sort (first_list
, first_length
, offset
, compare
);
288 second_list
= merge_sort (second_list
, second_length
, offset
, compare
);
290 merge_point
= &result
;
291 while (first_list
&& second_list
)
292 if ((*compare
) (first_list
, second_list
) < 0)
294 cursor
= SUCCESSOR (first_list
);
295 *merge_point
= first_list
;
296 merge_point
= &SUCCESSOR (first_list
);
301 cursor
= SUCCESSOR (second_list
);
302 *merge_point
= second_list
;
303 merge_point
= &SUCCESSOR (second_list
);
304 second_list
= cursor
;
307 *merge_point
= first_list
;
309 *merge_point
= second_list
;
318 /* Saved names in case backup needs to be undone. */
319 static char *before_backup_name
= NULL
;
320 static char *after_backup_name
= NULL
;
322 /*------------------------------------------------------------------------.
323 | Returns nonzero if p is `.' or `..'. This could be a macro for speed. |
324 `------------------------------------------------------------------------*/
326 /* Early Solaris 2.4 readdir may return d->d_name as `' in NFS-mounted
327 directories. The workaround here skips `' just like `.'. Without it,
328 GNU tar would then treat `' much like `.' and loop endlessly. */
331 is_dot_or_dotdot (const char *p
)
334 || (p
[0] == '.' && (p
[1] == '\0'
335 || (p
[1] == '.' && p
[2] == '\0'))));
338 /*-------------------------------------------------------------------------.
339 | Delete PATH, whatever it might be. If RECURSE, first recursively delete |
340 | the contents of PATH when it is a directory. Return zero on any error, |
341 | with errno set. As a special case, if we fail to delete a directory |
342 | when not RECURSE, do not set errno (just be tolerant to this error). |
343 `-------------------------------------------------------------------------*/
346 remove_any_file (const char *path
, int recurse
)
348 struct stat stat_buffer
;
350 if (lstat (path
, &stat_buffer
) < 0)
353 if (S_ISDIR (stat_buffer
.st_mode
))
356 DIR *dirp
= opendir (path
);
362 while (dp
= readdir (dirp
), dp
&& !is_dot_or_dotdot (dp
->d_name
))
364 char *path_buffer
= new_name (path
, dp
->d_name
);
366 if (!remove_any_file (path_buffer
, 1))
368 int saved_errno
= errno
;
372 errno
= saved_errno
; /* FIXME: errno should be read-only */
378 return rmdir (path
) >= 0;
382 /* FIXME: Saving errno might not be needed anymore, now that
383 extract_archive tests for the special case before recovery. */
384 int saved_errno
= errno
;
386 if (rmdir (path
) >= 0)
388 errno
= saved_errno
; /* FIXME: errno should be read-only */
392 return unlink (path
) >= 0;
395 /*-------------------------------------------------------------------------.
396 | Check if PATH already exists and make a backup of it right now. Return |
397 | success (nonzero) only if the backup in either unneeded, or successful. |
399 | For now, directories are considered to never need backup. If ARCHIVE is |
400 | nonzero, this is the archive and so, we do not have to backup block or |
401 | character devices, nor remote entities. |
402 `-------------------------------------------------------------------------*/
405 maybe_backup_file (const char *path
, int archive
)
407 struct stat file_stat
;
409 /* Check if we really need to backup the file. */
411 if (archive
&& _remdev (path
))
414 if (stat (path
, &file_stat
))
419 ERROR ((0, errno
, "%s", path
));
423 if (S_ISDIR (file_stat
.st_mode
))
427 if (archive
&& S_ISBLK (file_stat
.st_mode
))
432 if (archive
&& S_ISCHR (file_stat
.st_mode
))
436 assign_string (&before_backup_name
, path
);
438 /* A run situation may exist between Emacs or other GNU programs trying to
439 make a backup for the same file simultaneously. If theoretically
440 possible, real problems are unlikely. Doing any better would require a
441 convention, GNU-wide, for all programs doing backups. */
443 assign_string (&after_backup_name
, NULL
);
444 after_backup_name
= find_backup_file_name (path
);
445 if (after_backup_name
== NULL
)
446 FATAL_ERROR ((0, 0, "Virtual memory exhausted"));
448 if (rename (before_backup_name
, after_backup_name
) == 0)
451 fprintf (stdlis
, _("Renaming previous `%s' to `%s'\n"),
452 before_backup_name
, after_backup_name
);
456 /* The backup operation failed. */
458 ERROR ((0, errno
, _("%s: Cannot rename for backup"), before_backup_name
));
459 assign_string (&after_backup_name
, NULL
);
463 /*-----------------------------------------------------------------------.
464 | Try to restore the recently backed up file to its original name. This |
465 | is usually only needed after a failed extraction. |
466 `-----------------------------------------------------------------------*/
469 undo_last_backup (void)
471 if (after_backup_name
)
473 if (rename (after_backup_name
, before_backup_name
) != 0)
474 ERROR ((0, errno
, _("%s: Cannot rename from backup"),
475 before_backup_name
));
477 fprintf (stdlis
, _("Renaming `%s' back to `%s'\n"),
478 after_backup_name
, before_backup_name
);
479 assign_string (&after_backup_name
, NULL
);
This page took 0.052898 seconds and 4 git commands to generate.