(print_total_written): Use a format compatible with
[debian/tar] / 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.
3
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
7    version.
8
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.
13
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.  */
17
18 #include "system.h"
19
20 #include "backupfile.h"
21 #include "rmt.h"
22
23 /* The following inclusion for crosschecking prototypes, only.  */
24 #include "common.h"
25 \f
26 /* Handling strings.  */
27
28 #define ISPRINT(Char) (ISASCII (Char) && isprint (Char))
29
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 `-------------------------------------------------------------------------*/
34
35 void
36 assign_string (char **string, const char *value)
37 {
38   if (*string)
39     free (*string);
40   *string = value ? xstrdup (value) : NULL;
41 }
42
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 |
47 | done with it.                                                           |
48 |                                                                         |
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     |
51 | dumps.                                                                  |
52 `------------------------------------------------------------------------*/
53
54 char *
55 quote_copy_string (const char *string)
56 {
57   const char *source = string;
58   char *destination = NULL;
59   char *buffer = NULL;
60   int copying = 0;
61
62   while (*source)
63     {
64       int character = (unsigned char) *source++;
65
66       if (character == '\\')
67         {
68           if (!copying)
69             {
70               int length = (source - string) - 1;
71
72               copying = 1;
73               buffer = (char *) xmalloc (length + 5 + strlen (source) * 4);
74               memcpy (buffer, string, (size_t) length);
75               destination = buffer + length;
76             }
77           *destination++ = '\\';
78           *destination++ = '\\';
79         }
80       else if (ISPRINT (character))
81         {
82           if (copying)
83             *destination++ = character;
84         }
85       else
86         {
87           if (!copying)
88             {
89               int length = (source - string) - 1;
90
91               copying = 1;
92               buffer = (char *) xmalloc (length + 5 + strlen (source) * 4);
93               memcpy (buffer, string, (size_t) length);
94               destination = buffer + length;
95             }
96           *destination++ = '\\';
97           switch (character)
98             {
99             case '\n':
100               *destination++ = 'n';
101               break;
102
103             case '\t':
104               *destination++ = 't';
105               break;
106
107             case '\f':
108               *destination++ = 'f';
109               break;
110
111             case '\b':
112               *destination++ = 'b';
113               break;
114
115             case '\r':
116               *destination++ = 'r';
117               break;
118
119             case '\177':
120               *destination++ = '?';
121               break;
122
123             default:
124               *destination++ = (character >> 6) + '0';
125               *destination++ = ((character >> 3) & 07) + '0';
126               *destination++ = (character & 07) + '0';
127               break;
128             }
129         }
130     }
131   if (copying)
132     {
133       *destination = '\0';
134       return buffer;
135     }
136   return NULL;
137 }
138
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.                                                        |
144 |                                                                          |
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 `-------------------------------------------------------------------------*/
150
151 int
152 unquote_string (char *string)
153 {
154   int result = 1;
155   char *source = string;
156   char *destination = string;
157
158   while (*source)
159     if (*source == '\\')
160       switch (*++source)
161         {
162         case '\\':
163           *destination++ = '\\';
164           source++;
165           break;
166
167         case 'n':
168           *destination++ = '\n';
169           source++;
170           break;
171
172         case 't':
173           *destination++ = '\t';
174           source++;
175           break;
176
177         case 'f':
178           *destination++ = '\f';
179           source++;
180           break;
181
182         case 'b':
183           *destination++ = '\b';
184           source++;
185           break;
186
187         case 'r':
188           *destination++ = '\r';
189           source++;
190           break;
191
192         case '?':
193           *destination++ = 0177;
194           source++;
195           break;
196
197         case '0':
198         case '1':
199         case '2':
200         case '3':
201         case '4':
202         case '5':
203         case '6':
204         case '7':
205           {
206             int value = *source++ - '0';
207
208             if (*source < '0' || *source > '7')
209               {
210                 *destination++ = value;
211                 break;
212               }
213             value = value * 8 + *source++ - '0';
214             if (*source < '0' || *source > '7')
215               {
216                 *destination++ = value;
217                 break;
218               }
219             value = value * 8 + *source++ - '0';
220             *destination++ = value;
221             break;
222           }
223
224         default:
225           result = 0;
226           *destination++ = '\\';
227           if (*source)
228             *destination++ = *source++;
229           break;
230         }
231     else if (source != destination)
232       *destination++ = *source++;
233     else
234       source++, destination++;
235
236   if (source != destination)
237     *destination = '\0';
238   return result;
239 }
240 \f
241 /* Sorting lists.  */
242
243 /*---.
244 | ?  |
245 `---*/
246
247 char *
248 merge_sort (char *list, int length, int offset, int (*compare) (char *, char *))
249 {
250   char *first_list;
251   char *second_list;
252   int first_length;
253   int second_length;
254   char *result;
255   char **merge_point;
256   char *cursor;
257   int counter;
258
259 #define SUCCESSOR(Pointer) \
260   (*((char **) (((char *) (Pointer)) + offset)))
261
262   if (length == 1)
263     return list;
264
265   if (length == 2)
266     {
267       if ((*compare) (list, SUCCESSOR (list)) > 0)
268         {
269           result = SUCCESSOR (list);
270           SUCCESSOR (result) = list;
271           SUCCESSOR (list) = NULL;
272           return result;
273         }
274       return list;
275     }
276
277   first_list = list;
278   first_length = (length + 1) / 2;
279   second_length = length / 2;
280   for (cursor = list, counter = first_length - 1;
281        counter;
282        cursor = SUCCESSOR (cursor), counter--)
283     continue;
284   second_list = SUCCESSOR (cursor);
285   SUCCESSOR (cursor) = NULL;
286
287   first_list = merge_sort (first_list, first_length, offset, compare);
288   second_list = merge_sort (second_list, second_length, offset, compare);
289
290   merge_point = &result;
291   while (first_list && second_list)
292     if ((*compare) (first_list, second_list) < 0)
293       {
294         cursor = SUCCESSOR (first_list);
295         *merge_point = first_list;
296         merge_point = &SUCCESSOR (first_list);
297         first_list = cursor;
298       }
299     else
300       {
301         cursor = SUCCESSOR (second_list);
302         *merge_point = second_list;
303         merge_point = &SUCCESSOR (second_list);
304         second_list = cursor;
305       }
306   if (first_list)
307     *merge_point = first_list;
308   else
309     *merge_point = second_list;
310
311   return result;
312
313 #undef SUCCESSOR
314 }
315 \f
316 /* File handling.  */
317
318 /* Saved names in case backup needs to be undone.  */
319 static char *before_backup_name = NULL;
320 static char *after_backup_name = NULL;
321
322 /*------------------------------------------------------------------------.
323 | Returns nonzero if p is `.' or `..'.  This could be a macro for speed.  |
324 `------------------------------------------------------------------------*/
325
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.  */
329
330 int
331 is_dot_or_dotdot (const char *p)
332 {
333   return (p[0] == '\0'
334           || (p[0] == '.' && (p[1] == '\0'
335                               || (p[1] == '.' && p[2] == '\0'))));
336 }
337
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 `-------------------------------------------------------------------------*/
344
345 int
346 remove_any_file (const char *path, int recurse)
347 {
348   struct stat stat_buffer;
349
350   if (lstat (path, &stat_buffer) < 0)
351     return 0;
352
353   if (S_ISDIR (stat_buffer.st_mode))
354     if (recurse)
355       {
356         DIR *dirp = opendir (path);
357         struct dirent *dp;
358
359         if (dirp == NULL)
360           return 0;
361
362         while (dp = readdir (dirp), dp && !is_dot_or_dotdot (dp->d_name))
363           {
364             char *path_buffer = new_name (path, dp->d_name);
365
366             if (!remove_any_file (path_buffer, 1))
367               {
368                 int saved_errno = errno;
369
370                 free (path_buffer);
371                 closedir (dirp);
372                 errno = saved_errno; /* FIXME: errno should be read-only */
373                 return 0;
374               }
375             free (path_buffer);
376           }
377         closedir (dirp);
378         return rmdir (path) >= 0;
379       }
380     else
381       {
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;
385
386         if (rmdir (path) >= 0)
387           return 1;
388         errno = saved_errno;    /* FIXME: errno should be read-only */
389         return 0;
390       }
391
392   return unlink (path) >= 0;
393 }
394
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.  |
398 |                                                                          |
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 `-------------------------------------------------------------------------*/
403
404 int
405 maybe_backup_file (const char *path, int archive)
406 {
407   struct stat file_stat;
408
409   /* Check if we really need to backup the file.  */
410
411   if (archive && _remdev (path))
412     return 1;
413
414   if (stat (path, &file_stat))
415     {
416       if (errno == ENOENT)
417         return 1;
418
419       ERROR ((0, errno, "%s", path));
420       return 0;
421     }
422
423   if (S_ISDIR (file_stat.st_mode))
424     return 1;
425
426 #ifdef S_ISBLK
427   if (archive && S_ISBLK (file_stat.st_mode))
428     return 1;
429 #endif
430
431 #ifdef S_ISCHR
432   if (archive && S_ISCHR (file_stat.st_mode))
433     return 1;
434 #endif
435
436   assign_string (&before_backup_name, path);
437
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.  */
442
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"));
447
448   if (rename (before_backup_name, after_backup_name) == 0)
449     {
450       if (verbose_option)
451         fprintf (stdlis, _("Renaming previous `%s' to `%s'\n"),
452                  before_backup_name, after_backup_name);
453       return 1;
454     }
455
456   /* The backup operation failed.  */
457
458   ERROR ((0, errno, _("%s: Cannot rename for backup"), before_backup_name));
459   assign_string (&after_backup_name, NULL);
460   return 0;
461 }
462
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 `-----------------------------------------------------------------------*/
467
468 void
469 undo_last_backup (void)
470 {
471   if (after_backup_name)
472     {
473       if (rename (after_backup_name, before_backup_name) != 0)
474         ERROR ((0, errno, _("%s: Cannot rename from backup"),
475                 before_backup_name));
476       if (verbose_option)
477         fprintf (stdlis, _("Renaming `%s' back to `%s'\n"),
478                  after_backup_name, before_backup_name);
479       assign_string (&after_backup_name, NULL);
480     }
481 }