]> Dogcows Code - chaz/tar/blob - src/xheader.c
(struct xhdr_tab.coder; all coder function): Added
[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 <hash.h>
22 #include <quotearg.h>
23 #include <xstrtol.h>
24
25 #include "common.h"
26
27 #define obstack_chunk_alloc xmalloc
28 #define obstack_chunk_free free
29 #include <obstack.h>
30
31 /* General Interface */
32
33 struct xhdr_tab
34 {
35 char const *keyword;
36 void (*coder) (struct tar_stat_info const *, char const *,
37 struct xheader *, void *data);
38 void (*decoder) (struct tar_stat_info *, char const *);
39 };
40
41 /* This declaration must be extern, because ISO C99 section 6.9.2
42 prohibits a tentative definition that has both internal linkage and
43 incomplete type. If we made it static, we'd have to declare its
44 size which would be a maintenance pain; if we put its initializer
45 here, we'd need a boatload of forward declarations, which would be
46 even more of a pain. */
47 extern struct xhdr_tab const xhdr_tab[];
48
49 static struct xhdr_tab const *
50 locate_handler (char const *keyword)
51 {
52 struct xhdr_tab const *p;
53
54 for (p = xhdr_tab; p->keyword; p++)
55 if (strcmp (p->keyword, keyword) == 0)
56 return p;
57 return NULL;
58 }
59
60 /* Decodes a single extended header record. Advances P to the next
61 record.
62 Returns true on success, false otherwise. */
63 static bool
64 decode_record (char **p, struct tar_stat_info *st)
65 {
66 size_t len;
67 char const *keyword;
68 char *eqp;
69 char *start = *p;
70 struct xhdr_tab const *t;
71
72 if (**p == 0)
73 return false;
74
75 len = strtoul (*p, p, 10);
76 if (**p != ' ')
77 {
78 ERROR ((0, 0, _("Malformed extended header: missing whitespace after the length")));
79 return false;
80 }
81
82 keyword = ++*p;
83 for (;*p < start + len; ++*p)
84 if (**p == '=')
85 break;
86
87 if (**p != '=')
88 {
89 ERROR ((0, 0, _("Malformed extended header: missing equal sign")));
90 return false;
91 }
92
93 eqp = *p;
94 **p = 0;
95 t = locate_handler (keyword);
96 if (t)
97 {
98 char endc;
99 char *value;
100
101 value = ++*p;
102
103 endc = start[len-1];
104 start[len-1] = 0;
105 t->decoder (st, value);
106 start[len-1] = endc;
107 }
108 *eqp = '=';
109 *p = &start[len];
110 return true;
111 }
112
113 void
114 xheader_decode (struct tar_stat_info *st)
115 {
116 char *p = extended_header.buffer + BLOCKSIZE;
117 char *endp = &extended_header.buffer[extended_header.size-1];
118
119 while (p < endp)
120 if (!decode_record (&p, st))
121 break;
122 }
123
124 void
125 xheader_store (char const *keyword, struct tar_stat_info const *st, void *data)
126 {
127 struct xhdr_tab const *t;
128
129 if (extended_header.buffer)
130 return;
131 t = locate_handler (keyword);
132 if (!t)
133 return;
134 if (!extended_header.stk)
135 {
136 extended_header.stk = xmalloc (sizeof *extended_header.stk);
137 obstack_init (extended_header.stk);
138 }
139 t->coder (st, keyword, &extended_header, data);
140 }
141
142 void
143 xheader_read (union block *p, size_t size)
144 {
145 size_t j = 0;
146 size_t nblocks;
147
148 free (extended_header.buffer);
149 size += BLOCKSIZE;
150 extended_header.size = size;
151 nblocks = (size + BLOCKSIZE - 1) / BLOCKSIZE;
152 extended_header.buffer = xmalloc (size + 1);
153
154 do
155 {
156 size_t len = size;
157
158 if (len > BLOCKSIZE)
159 len = BLOCKSIZE;
160
161 memcpy (&extended_header.buffer[j], p->buffer, len);
162 set_next_block_after (p);
163
164 p = find_next_block ();
165
166 j += len;
167 size -= len;
168 }
169 while (size > 0);
170 }
171
172 static size_t
173 format_uintmax (uintmax_t val, char *buf, size_t s)
174 {
175 if (!buf)
176 {
177 s = 0;
178 do
179 s++;
180 while ((val /= 10) != 0);
181 }
182 else
183 {
184 char *p = buf + s - 1;
185
186 do
187 {
188 *p-- = val % 10 + '0';
189 }
190 while ((val /= 10) != 0);
191
192 while (p >= buf)
193 *p-- = '0';
194 }
195 return s;
196 }
197
198 static void
199 xheader_print (struct xheader *xhdr, char const *keyword, char const *value)
200 {
201 size_t len = strlen (keyword) + strlen (value) + 3; /* ' ' + '=' + '\n' */
202 size_t p, n = 0;
203 char nbuf[100];
204
205 do
206 {
207 p = n;
208 n = format_uintmax (len + p, NULL, 0);
209 }
210 while (n != p);
211
212 format_uintmax (len + n, nbuf, n);
213 obstack_grow (xhdr->stk, nbuf, n);
214 obstack_1grow (xhdr->stk, ' ');
215 obstack_grow (xhdr->stk, keyword, strlen (keyword));
216 obstack_1grow (xhdr->stk, '=');
217 obstack_grow (xhdr->stk, value, strlen (value));
218 obstack_1grow (xhdr->stk, '\n');
219 }
220
221 void
222 xheader_finish (struct xheader *xhdr)
223 {
224 obstack_1grow (xhdr->stk, 0);
225 xhdr->buffer = obstack_finish (xhdr->stk);
226 xhdr->size = strlen (xhdr->buffer);
227 }
228
229 void
230 xheader_destroy (struct xheader *xhdr)
231 {
232 if (xhdr->stk)
233 {
234 obstack_free (xhdr->stk, NULL);
235 free (xhdr->stk);
236 xhdr->stk = NULL;
237 }
238 else
239 free (xhdr->buffer);
240 xhdr->buffer = 0;
241 xhdr->size = 0;
242 }
243
244 \f
245 /* Implementations */
246 static void
247 code_string (char const *string, char const *keyword, struct xheader *xhdr)
248 {
249 xheader_print (xhdr, keyword, string);
250 }
251
252 static void
253 code_time (time_t t, char const *keyword, struct xheader *xhdr)
254 {
255 char sbuf[100];
256 size_t s = format_uintmax (t, NULL, 0);
257 format_uintmax (t, sbuf, s);
258 sbuf[s++] = '.';
259 format_uintmax (0, sbuf + s, 9);
260 sbuf[s+9] = 0;
261 xheader_print (xhdr, keyword, sbuf);
262 }
263
264 static void
265 code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
266 {
267 char sbuf[100];
268 size_t s = format_uintmax (value, NULL, 0);
269 format_uintmax (value, sbuf, s);
270 sbuf[s] = 0;
271 xheader_print (xhdr, keyword, sbuf);
272 }
273
274 static void
275 dummy_coder (struct tar_stat_info const *st, char const *keyword,
276 struct xheader *xhdr, void *data)
277 {
278 }
279
280 static void
281 dummy_decoder (struct tar_stat_info *st, char const *arg)
282 {
283 }
284
285 static void
286 atime_coder (struct tar_stat_info const *st, char const *keyword,
287 struct xheader *xhdr, void *data)
288 {
289 code_time (st->stat.st_atime, keyword, xhdr);
290 }
291
292 static void
293 atime_decoder (struct tar_stat_info *st, char const *arg)
294 {
295 uintmax_t u;
296 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
297 st->stat.st_atime = u;
298 }
299
300 static void
301 gid_coder (struct tar_stat_info const *st, char const *keyword,
302 struct xheader *xhdr, void *data)
303 {
304 code_num (st->stat.st_gid, keyword, xhdr);
305 }
306
307 static void
308 gid_decoder (struct tar_stat_info *st, char const *arg)
309 {
310 uintmax_t u;
311 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
312 st->stat.st_gid = u;
313 }
314
315 static void
316 gname_coder (struct tar_stat_info const *st, char const *keyword,
317 struct xheader *xhdr, void *data)
318 {
319 code_string (st->gname, keyword, xhdr);
320 }
321
322 static void
323 gname_decoder (struct tar_stat_info *st, char const *arg)
324 {
325 assign_string (&st->gname, arg);
326 }
327
328 static void
329 linkpath_coder (struct tar_stat_info const *st, char const *keyword,
330 struct xheader *xhdr, void *data)
331 {
332 code_string (st->link_name, keyword, xhdr);
333 }
334
335 static void
336 linkpath_decoder (struct tar_stat_info *st, char const *arg)
337 {
338 assign_string (&st->link_name, arg);
339 }
340
341 static void
342 ctime_coder (struct tar_stat_info const *st, char const *keyword,
343 struct xheader *xhdr, void *data)
344 {
345 code_time (st->stat.st_ctime, keyword, xhdr);
346 }
347
348 static void
349 ctime_decoder (struct tar_stat_info *st, char const *arg)
350 {
351 uintmax_t u;
352 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
353 st->stat.st_ctime = u;
354 }
355
356 static void
357 mtime_coder (struct tar_stat_info const *st, char const *keyword,
358 struct xheader *xhdr, void *data)
359 {
360 code_time (st->stat.st_mtime, keyword, xhdr);
361 }
362
363 static void
364 mtime_decoder (struct tar_stat_info *st, char const *arg)
365 {
366 uintmax_t u;
367 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
368 st->stat.st_mtime = u;
369 }
370
371 static void
372 path_coder (struct tar_stat_info const *st, char const *keyword,
373 struct xheader *xhdr, void *data)
374 {
375 code_string (st->file_name, keyword, xhdr);
376 }
377
378 static void
379 path_decoder (struct tar_stat_info *st, char const *arg)
380 {
381 assign_string (&st->orig_file_name, arg);
382 assign_string (&st->file_name, arg);
383 st->had_trailing_slash = strip_trailing_slashes (st->file_name);
384 }
385
386 static void
387 size_coder (struct tar_stat_info const *st, char const *keyword,
388 struct xheader *xhdr, void *data)
389 {
390 code_num (st->stat.st_size, keyword, xhdr);
391 }
392
393 static void
394 size_decoder (struct tar_stat_info *st, char const *arg)
395 {
396 uintmax_t u;
397 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
398 st->stat.st_size = u;
399 }
400
401 static void
402 uid_coder (struct tar_stat_info const *st, char const *keyword,
403 struct xheader *xhdr, void *data)
404 {
405 code_num (st->stat.st_uid, keyword, xhdr);
406 }
407
408 static void
409 uid_decoder (struct tar_stat_info *st, char const *arg)
410 {
411 uintmax_t u;
412 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
413 st->stat.st_uid = u;
414 }
415
416 static void
417 uname_coder (struct tar_stat_info const *st, char const *keyword,
418 struct xheader *xhdr, void *data)
419 {
420 code_string (st->uname, keyword, xhdr);
421 }
422
423 static void
424 uname_decoder (struct tar_stat_info *st, char const *arg)
425 {
426 assign_string (&st->uname, arg);
427 }
428
429 static void
430 sparse_size_coder (struct tar_stat_info const *st, char const *keyword,
431 struct xheader *xhdr, void *data)
432 {
433 size_coder (st, keyword, xhdr, data);
434 }
435
436 static void
437 sparse_size_decoder (struct tar_stat_info *st, char const *arg)
438 {
439 uintmax_t u;
440 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
441 st->archive_file_size = u;
442 }
443
444 static void
445 sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword,
446 struct xheader *xhdr, void *data)
447 {
448 code_num (st->sparse_map_avail, keyword, xhdr);
449 }
450
451 static void
452 sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg)
453 {
454 uintmax_t u;
455 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
456 {
457 st->sparse_map_size = u;
458 st->sparse_map = calloc(st->sparse_map_size, sizeof(st->sparse_map[0]));
459 st->sparse_map_avail = 0;
460 }
461 }
462
463 static void
464 sparse_offset_coder (struct tar_stat_info const *st, char const *keyword,
465 struct xheader *xhdr, void *data)
466 {
467 size_t i = *(size_t*)data;
468 code_num (st->sparse_map[i].offset, keyword, xhdr);
469 }
470
471 static void
472 sparse_offset_decoder (struct tar_stat_info *st, char const *arg)
473 {
474 uintmax_t u;
475 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
476 st->sparse_map[st->sparse_map_avail].offset = u;
477 }
478
479 static void
480 sparse_numbytes_coder (struct tar_stat_info const *st, char const *keyword,
481 struct xheader *xhdr, void *data)
482 {
483 size_t i = *(size_t*)data;
484 code_num (st->sparse_map[i].numbytes, keyword, xhdr);
485 }
486
487 static void
488 sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg)
489 {
490 uintmax_t u;
491 if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
492 {
493 if (st->sparse_map_avail == st->sparse_map_size)
494 {
495 size_t newsize = st->sparse_map_size *= 2;
496 st->sparse_map = xrealloc (st->sparse_map,
497 st->sparse_map_size
498 * sizeof st->sparse_map[0]);
499 }
500 st->sparse_map[st->sparse_map_avail++].numbytes = u;
501 }
502 }
503
504 struct xhdr_tab const xhdr_tab[] = {
505 { "atime", atime_coder, atime_decoder },
506 { "comment", dummy_coder, dummy_decoder },
507 { "charset", dummy_coder, dummy_decoder },
508 { "ctime", ctime_coder, ctime_decoder },
509 { "gid", gid_coder, gid_decoder },
510 { "gname", gname_coder, gname_decoder },
511 { "linkpath", linkpath_coder, linkpath_decoder},
512 { "mtime", mtime_coder, mtime_decoder },
513 { "path", path_coder, path_decoder },
514 { "size", size_coder, size_decoder },
515 { "uid", uid_coder, uid_decoder },
516 { "uname", uname_coder, uname_decoder },
517
518 /* Sparse file handling */
519 { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder },
520 { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder },
521 { "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder },
522 { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder },
523
524 #if 0 /* GNU private keywords (not yet implemented) */
525
526 /* The next directory entry actually contains the names of files
527 that were in the directory at the time the dump was made.
528 Supersedes GNUTYPE_DUMPDIR header type. */
529 { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder },
530
531 /* Keeps the tape/volume header. May be present only in the global headers.
532 Equivalent to GNUTYPE_VOLHDR. */
533 { "GNU.volume.header", volume_header_coder, volume_header_decoder },
534
535 /* These may be present in a first global header of the archive.
536 They provide the same functionality as GNUTYPE_MULTIVOL header.
537 The GNU.volume.size keeps the real_s_sizeleft value, which is
538 otherwise kept in the size field of a multivolume header. The
539 GNU.volume.offset keeps the offset of the start of this volume,
540 otherwise kept in oldgnu_header.offset. */
541 { "GNU.volume.size", volume_size_coder, volume_size_decoder },
542 { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder },
543 #endif
544
545 { NULL, NULL, NULL }
546 };
This page took 0.066463 seconds and 5 git commands to generate.