]> Dogcows Code - chaz/tar/blob - src/xheader.c
(xheader_decode): Store the header as well (for eventual delete).
[chaz/tar] / src / xheader.c
1 /* POSIX extended and STAR headers.
2
3 Copyright (C) 2003 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any later
8 version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18
19 #include "system.h"
20
21 #include <grp.h>
22 #include <hash.h>
23 #include <pwd.h>
24 #include <quotearg.h>
25
26 #include "common.h"
27
28 #define obstack_chunk_alloc xmalloc
29 #define obstack_chunk_free free
30 #include <obstack.h>
31
32 /* General Interface */
33
34 struct xhdr_tab
35 {
36 char const *keyword;
37 void (*coder) (struct tar_stat_info const *, char const *, struct xheader *);
38 void (*decoder) (struct tar_stat_info *, char const *);
39 };
40
41 static struct xhdr_tab const xhdr_tab[];
42
43 static struct xhdr_tab const *
44 locate_handler (char const *keyword)
45 {
46 struct xhdr_tab const *p;
47
48 for (p = xhdr_tab; p->keyword; p++)
49 if (strcmp (p->keyword, keyword) == 0)
50 return p;
51 return NULL;
52 }
53
54 /* Decodes a single extended header record. Advances P to the next
55 record.
56 Returns true on success, false otherwise. */
57 static bool
58 decode_record (char **p, struct tar_stat_info *st)
59 {
60 size_t len;
61 char const *keyword;
62 char *eqp;
63 char *start = *p;
64 struct xhdr_tab const *t;
65
66 if (**p == 0)
67 return false;
68
69 len = strtoul (*p, p, 10);
70 if (**p != ' ')
71 {
72 ERROR ((0, 0, _("Malformed extended header: missing whitespace after the length")));
73 return false;
74 }
75
76 keyword = ++*p;
77 for (;*p < start + len; ++*p)
78 if (**p == '=')
79 break;
80
81 if (**p != '=')
82 {
83 ERROR ((0, 0, _("Malformed extended header: missing equal sign")));
84 return false;
85 }
86
87 eqp = *p;
88 **p = 0;
89 t = locate_handler (keyword);
90 if (t)
91 {
92 char endc;
93 char *value;
94
95 value = ++*p;
96
97 endc = start[len-1];
98 start[len-1] = 0;
99 t->decoder (st, value);
100 start[len-1] = endc;
101 }
102 *eqp = '=';
103 *p = &start[len];
104 return true;
105 }
106
107 void
108 xheader_decode (struct tar_stat_info *st)
109 {
110 char *p = extended_header.buffer + BLOCKSIZE;
111 char *endp = &extended_header.buffer[extended_header.size-1];
112
113 while (p < endp)
114 if (!decode_record (&p, st))
115 break;
116 }
117
118 void
119 xheader_store (char const *keyword, struct tar_stat_info const *st)
120 {
121 struct xhdr_tab const *t;
122
123 if (extended_header.buffer)
124 return;
125 t = locate_handler (keyword);
126 if (!t)
127 return;
128 if (!extended_header.stk)
129 {
130 extended_header.stk = xmalloc (sizeof *extended_header.stk);
131 obstack_init (extended_header.stk);
132 }
133 t->coder (st, keyword, &extended_header);
134 }
135
136 void
137 xheader_read (union block *p, size_t size)
138 {
139 size_t j = 0;
140 size_t nblocks;
141
142 free (extended_header.buffer);
143 size += BLOCKSIZE;
144 extended_header.size = size;
145 nblocks = (size + BLOCKSIZE - 1) / BLOCKSIZE;
146 extended_header.buffer = xmalloc (size + 1);
147
148 do
149 {
150 size_t len = size;
151
152 if (len > BLOCKSIZE)
153 len = BLOCKSIZE;
154
155 memcpy (&extended_header.buffer[j], p->buffer, len);
156 set_next_block_after (p);
157
158 p = find_next_block ();
159
160 j += len;
161 size -= len;
162 }
163 while (size > 0);
164 }
165
166 static size_t
167 format_uintmax (uintmax_t val, char *buf, size_t s)
168 {
169 if (!buf)
170 {
171 s = 0;
172 do
173 s++;
174 while ((val /= 10) != 0);
175 }
176 else
177 {
178 char *p = buf + s - 1;
179
180 do
181 {
182 *p-- = val % 10 + '0';
183 }
184 while ((val /= 10) != 0);
185
186 while (p >= buf)
187 *p-- = '0';
188 }
189 return s;
190 }
191
192 static void
193 xheader_print (struct xheader *xhdr, char const *keyword, char const *value)
194 {
195 size_t len = strlen (keyword) + strlen (value) + 3; /* ' ' + '=' + '\n' */
196 size_t p, n = 0;
197 char nbuf[100];
198
199 do
200 {
201 p = n;
202 n = format_uintmax (len + p, NULL, 0);
203 }
204 while (n != p);
205
206 format_uintmax (len + n, nbuf, n);
207 obstack_grow (xhdr->stk, nbuf, n);
208 obstack_1grow (xhdr->stk, ' ');
209 obstack_grow (xhdr->stk, keyword, strlen (keyword));
210 obstack_1grow (xhdr->stk, '=');
211 obstack_grow (xhdr->stk, value, strlen (value));
212 obstack_1grow (xhdr->stk, '\n');
213 }
214
215 void
216 xheader_finish (struct xheader *xhdr)
217 {
218 obstack_1grow (xhdr->stk, 0);
219 xhdr->buffer = obstack_finish (xhdr->stk);
220 xhdr->size = strlen (xhdr->buffer);
221 }
222
223 void
224 xheader_destroy (struct xheader *xhdr)
225 {
226 if (xhdr->stk)
227 {
228 obstack_free (xhdr->stk, NULL);
229 free (xhdr->stk);
230 xhdr->stk = NULL;
231 }
232 else
233 free (xhdr->buffer);
234 xhdr->buffer = 0;
235 xhdr->size = 0;
236 }
237
238 \f
239 /* Implementations */
240 static void
241 code_string (char const *string, char const *keyword, struct xheader *xhdr)
242 {
243 xheader_print (xhdr, keyword, string);
244 }
245
246 static void
247 code_time (time_t t, char const *keyword, struct xheader *xhdr)
248 {
249 char sbuf[100];
250 size_t s = format_uintmax (t, NULL, 0);
251 format_uintmax (t, sbuf, s);
252 sbuf[s++] = '.';
253 format_uintmax (0, sbuf + s, 9);
254 sbuf[s+9] = 0;
255 xheader_print (xhdr, keyword, sbuf);
256 }
257
258 static void
259 code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
260 {
261 char sbuf[100];
262 size_t s = format_uintmax (value, NULL, 0);
263 format_uintmax (value, sbuf, s);
264 sbuf[s] = 0;
265 xheader_print (xhdr, keyword, sbuf);
266 }
267
268 static void
269 dummy_coder (struct tar_stat_info const *st, char const *keyword,
270 struct xheader *xhdr)
271 {
272 }
273
274 static void
275 dummy_decoder (struct tar_stat_info *st, char const *arg)
276 {
277 }
278
279 static void
280 atime_coder (struct tar_stat_info const *st, char const *keyword,
281 struct xheader *xhdr)
282 {
283 code_time (st->stat.st_atime, keyword, xhdr);
284 }
285
286 static void
287 atime_decoder (struct tar_stat_info *st, char const *arg)
288 {
289 st->stat.st_atime = strtoul (arg, NULL, 0);
290 }
291
292 static void
293 gid_coder (struct tar_stat_info const *st, char const *keyword,
294 struct xheader *xhdr)
295 {
296 code_num (st->stat.st_gid, keyword, xhdr);
297 }
298
299 static void
300 gid_decoder (struct tar_stat_info *st, char const *arg)
301 {
302 st->stat.st_gid = strtoul (arg, NULL, 0);
303 }
304
305 static void
306 gname_coder (struct tar_stat_info const *st, char const *keyword,
307 struct xheader *xhdr)
308 {
309 code_string (st->gname, keyword, xhdr);
310 }
311
312 static void
313 gname_decoder (struct tar_stat_info *st, char const *arg)
314 {
315 assign_string (&st->gname, arg);
316 }
317
318 static void
319 linkpath_coder (struct tar_stat_info const *st, char const *keyword,
320 struct xheader *xhdr)
321 {
322 code_string (st->link_name, keyword, xhdr);
323 }
324
325 static void
326 linkpath_decoder (struct tar_stat_info *st, char const *arg)
327 {
328 assign_string (&st->link_name, arg);
329 }
330
331 static void
332 ctime_coder (struct tar_stat_info const *st, char const *keyword,
333 struct xheader *xhdr)
334 {
335 code_time (st->stat.st_ctime, keyword, xhdr);
336 }
337
338 static void
339 ctime_decoder (struct tar_stat_info *st, char const *arg)
340 {
341 st->stat.st_ctime = strtoul (arg, NULL, 0);
342 }
343
344 static void
345 mtime_coder (struct tar_stat_info const *st, char const *keyword,
346 struct xheader *xhdr)
347 {
348 code_time (st->stat.st_mtime, keyword, xhdr);
349 }
350
351 static void
352 mtime_decoder (struct tar_stat_info *st, char const *arg)
353 {
354 st->stat.st_mtime = strtoul (arg, NULL, 0);
355 }
356
357 static void
358 path_coder (struct tar_stat_info const *st, char const *keyword,
359 struct xheader *xhdr)
360 {
361 code_string (st->file_name, keyword, xhdr);
362 }
363
364 static void
365 path_decoder (struct tar_stat_info *st, char const *arg)
366 {
367 assign_string (&st->orig_file_name, arg);
368 assign_string (&st->file_name, arg);
369 st->had_trailing_slash = strip_trailing_slashes (st->file_name);
370 }
371
372 static void
373 size_coder (struct tar_stat_info const *st, char const *keyword,
374 struct xheader *xhdr)
375 {
376 code_num (st->stat.st_size, keyword, xhdr);
377 }
378
379 static void
380 size_decoder (struct tar_stat_info *st, char const *arg)
381 {
382 st->stat.st_size = strtoul (arg, NULL, 0);
383 }
384
385 static void
386 uid_coder (struct tar_stat_info const *st, char const *keyword,
387 struct xheader *xhdr)
388 {
389 code_num (st->stat.st_uid, keyword, xhdr);
390 }
391
392 static void
393 uid_decoder (struct tar_stat_info *st, char const *arg)
394 {
395 st->stat.st_uid = strtoul (arg, NULL, 0);
396 }
397
398 static void
399 uname_coder (struct tar_stat_info const *st, char const *keyword,
400 struct xheader *xhdr)
401 {
402 code_string (st->uname, keyword, xhdr);
403 }
404
405 static void
406 uname_decoder (struct tar_stat_info *st, char const *arg)
407 {
408 assign_string (&st->uname, arg);
409 }
410
411 static struct xhdr_tab const xhdr_tab[] = {
412 { "atime", atime_coder, atime_decoder },
413 { "comment", dummy_coder, dummy_decoder },
414 { "charset", dummy_coder, dummy_decoder },
415 { "ctime", ctime_coder, ctime_decoder },
416 { "gid", gid_coder, gid_decoder },
417 { "gname", gname_coder, gname_decoder },
418 { "linkpath", linkpath_coder, linkpath_decoder},
419 { "mtime", mtime_coder, mtime_decoder },
420 { "path", path_coder, path_decoder },
421 { "size", size_coder, size_decoder },
422 { "uid", uid_coder, uid_decoder },
423 { "uname", uname_coder, uname_decoder },
424
425 #if 0 /* GNU private keywords (not yet implemented) */
426 /* Sparse file handling */
427 { "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder },
428 { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder },
429
430 /* The next directory entry actually contains the names of files
431 that were in the directory at the time the dump was made.
432 Supersedes GNUTYPE_DUMPDIR header type. */
433 { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder },
434
435 /* Keeps the tape/volume header. May be present only in the global headers.
436 Equivalent to GNUTYPE_VOLHDR. */
437 { "GNU.volume.header", volume_header_coder, volume_header_decoder },
438
439 /* These may be present in a first global header of the archive.
440 They provide the same functionality as GNUTYPE_MULTIVOL header.
441 The GNU.volume.size keeps the real_s_sizeleft value, which is
442 otherwise kept in the size field of a multivolume header. The
443 GNU.volume.offset keeps the offset of the start of this volume,
444 otherwise kept in oldgnu_header.offset. */
445 { "GNU.volume.size", volume_size_coder, volume_size_decoder },
446 { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder },
447 #endif
448
449 { NULL, NULL, NULL }
450 };
This page took 0.064903 seconds and 5 git commands to generate.