Merge from vendor branch OPENSSH:
[dragonfly.git] / contrib / tar / src / mangle.c
1 /* Encode long filenames for GNU tar.
2    Copyright 1988, 92, 94, 96, 97, 99, 2000 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 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #include "system.h"
19 #include "common.h"
20 #include <quotearg.h>
21
22 struct mangled
23   {
24     struct mangled *next;
25     int type;
26     char mangled[NAME_FIELD_SIZE];
27     char *linked_to;
28     char normal[1];
29   };
30
31 /* Extract a GNUTYPE_NAMES record contents.  It seems that such are
32    not produced anymore by GNU tar, but we leave the reading code
33    around nevertheless, for salvaging old tapes.  */
34 void
35 extract_mangle (void)
36 {
37   off_t size = current_stat.st_size;
38   char *buffer = xmalloc ((size_t) (size + 1));
39   char *copy = buffer;
40   char *cursor = buffer;
41
42   if (size != (size_t) size || size == (size_t) -1)
43     xalloc_die ();
44
45   buffer[size] = '\0';
46
47   while (size > 0)
48     {
49       union block *block = find_next_block ();
50       size_t available;
51
52       if (!block)
53         {
54           ERROR ((0, 0, _("Unexpected EOF in mangled names")));
55           return;
56         }
57       available = available_space_after (block);
58       if (available > size)
59         available = size;
60       memcpy (copy, block->buffer, available);
61       copy += available;
62       size -= available;
63       set_next_block_after ((union block *) (block->buffer + available - 1));
64     }
65
66   while (*cursor)
67     {
68       char *next_cursor;
69       char *name;
70       char *name_end;
71
72       next_cursor = strchr (cursor, '\n');
73       *next_cursor++ = '\0';
74
75       if (!strncmp (cursor, "Rename ", 7))
76         {
77
78           name = cursor + 7;
79           name_end = strchr (name, ' ');
80           while (strncmp (name_end, " to ", 4))
81             {
82               name_end++;
83               name_end = strchr (name_end, ' ');
84             }
85           *name_end = '\0';
86           if (next_cursor[-2] == '/')
87             next_cursor[-2] = '\0';
88           unquote_string (name_end + 4);
89           if (rename (name, name_end + 4))
90             ERROR ((0, errno, _("%s: Cannot rename to %s"),
91                     quotearg_colon (name), quote_n (1, name_end + 4)));
92           else if (verbose_option)
93             WARN ((0, 0, _("Renamed %s to %s"), name, name_end + 4));
94         }
95 #ifdef HAVE_SYMLINK
96       else if (!strncmp (cursor, "Symlink ", 8))
97         {
98           name = cursor + 8;
99           name_end = strchr (name, ' ');
100           while (strncmp (name_end, " to ", 4))
101             {
102               name_end++;
103               name_end = strchr (name_end, ' ');
104             }
105           *name_end = '\0';
106           unquote_string (name);
107           unquote_string (name_end + 4);
108           if (symlink (name, name_end + 4)
109               && (unlink (name_end + 4) || symlink (name, name_end + 4)))
110             ERROR ((0, errno, _("%s: Cannot symlink to %s"),
111                     quotearg_colon (name), quote_n (1, name_end + 4)));
112           else if (verbose_option)
113             WARN ((0, 0, _("Symlinked %s to %s"), name, name_end + 4));
114         }
115 #endif
116       else
117         ERROR ((0, 0, _("Unknown demangling command %s"), cursor));
118
119       cursor = next_cursor;
120     }
121 }