]> Dogcows Code - chaz/tar/blob - src/xheader.c
(code_time,decode_time): Support for subsecond precision. (atime_coder,atime_decoder...
[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, unsigned long nano,
254 char const *keyword, struct xheader *xhdr)
255 {
256 char sbuf[200];
257 size_t s = format_uintmax (t, NULL, 0);
258 if (s + 11 >= sizeof sbuf)
259 return;
260 format_uintmax (t, sbuf, s);
261 sbuf[s++] = '.';
262 s += format_uintmax (nano, sbuf + s, 9);
263 sbuf[s] = 0;
264 xheader_print (xhdr, keyword, sbuf);
265 }
266
267 static void
268 decode_time (char const *arg, time_t *secs, unsigned long *nsecs)
269 {
270 uintmax_t u;
271 char *p;
272 if (xstrtoumax (arg, &p, 10, &u, "") == LONGINT_OK)
273 {
274 *secs = u;
275 if (*p == '.' && xstrtoumax (p+1, NULL, 10, &u, "") == LONGINT_OK)
276 *nsecs = u;
277 }
278 }
279
280 static void
281 code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
282 {
283 char sbuf[100];
284 size_t s = format_uintmax (value, NULL, 0);
285 format_uintmax (value, sbuf, s);
286 sbuf[s] = 0;
287 xheader_print (xhdr, keyword, sbuf);
288 }
289
290 static void
291 dummy_coder (struct tar_stat_info const *st, char const *keyword,
292 struct xheader *xhdr, void *data)
293 {
294 }
295
296 static void
297 dummy_decoder (struct tar_stat_info *st, char const *arg)
298 {
299 }
300
301 static void
302 atime_coder (struct tar_stat_info const *st, char const *keyword,
303 struct xheader *xhdr, void *data)
304 {
305 code_time (st->stat.st_atime, st->atime_nsec, keyword, xhdr);
306 }
307
308 static void
309 atime_decoder (struct tar_stat_info *st, char const *arg)
310 {
311 decode_time (arg, &st->stat.st_atime, &st->atime_nsec);
312 }
313
314 static void
315 gid_coder (struct tar_stat_info const *st, char const *keyword,
316 struct xheader *xhdr, void *data)
317 {
318 code_num (st->stat.st_gid, keyword, xhdr);
319 }
320
321 static void
322 gid_decoder (struct tar_stat_info *st, char const *arg)
323 {
324 uintmax_t u;
325 if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
326 st->stat.st_gid = u;
327 }
328
329 static void
330 gname_coder (struct tar_stat_info const *st, char const *keyword,
331 struct xheader *xhdr, void *data)
332 {
333 code_string (st->gname, keyword, xhdr);
334 }
335
336 static void
337 gname_decoder (struct tar_stat_info *st, char const *arg)
338 {
339 assign_string (&st->gname, arg);
340 }
341
342 static void
343 linkpath_coder (struct tar_stat_info const *st, char const *keyword,
344 struct xheader *xhdr, void *data)
345 {
346 code_string (st->link_name, keyword, xhdr);
347 }
348
349 static void
350 linkpath_decoder (struct tar_stat_info *st, char const *arg)
351 {
352 assign_string (&st->link_name, arg);
353 }
354
355 static void
356 ctime_coder (struct tar_stat_info const *st, char const *keyword,
357 struct xheader *xhdr, void *data)
358 {
359 code_time (st->stat.st_ctime, st->ctime_nsec, keyword, xhdr);
360 }
361
362 static void
363 ctime_decoder (struct tar_stat_info *st, char const *arg)
364 {
365 decode_time (arg, &st->stat.st_ctime, &st->ctime_nsec);
366 }
367
368 static void
369 mtime_coder (struct tar_stat_info const *st, char const *keyword,
370 struct xheader *xhdr, void *data)
371 {
372 code_time (st->stat.st_mtime, st->mtime_nsec, keyword, xhdr);
373 }
374
375 static void
376 mtime_decoder (struct tar_stat_info *st, char const *arg)
377 {
378 decode_time (arg, &st->stat.st_mtime, &st->mtime_nsec);
379 }
380
381 static void
382 path_coder (struct tar_stat_info const *st, char const *keyword,
383 struct xheader *xhdr, void *data)
384 {
385 code_string (st->file_name, keyword, xhdr);
386 }
387
388 static void
389 path_decoder (struct tar_stat_info *st, char const *arg)
390 {
391 assign_string (&st->orig_file_name, arg);
392 assign_string (&st->file_name, arg);
393 st->had_trailing_slash = strip_trailing_slashes (st->file_name);
394 }
395
396 static void
397 size_coder (struct tar_stat_info const *st, char const *keyword,
398 struct xheader *xhdr, void *data)
399 {
400 code_num (st->stat.st_size, keyword, xhdr);
401 }
402
403 static void
404 size_decoder (struct tar_stat_info *st, char const *arg)
405 {
406 uintmax_t u;
407 if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
408 st->stat.st_size = u;
409 }
410
411 static void
412 uid_coder (struct tar_stat_info const *st, char const *keyword,
413 struct xheader *xhdr, void *data)
414 {
415 code_num (st->stat.st_uid, keyword, xhdr);
416 }
417
418 static void
419 uid_decoder (struct tar_stat_info *st, char const *arg)
420 {
421 uintmax_t u;
422 if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
423 st->stat.st_uid = u;
424 }
425
426 static void
427 uname_coder (struct tar_stat_info const *st, char const *keyword,
428 struct xheader *xhdr, void *data)
429 {
430 code_string (st->uname, keyword, xhdr);
431 }
432
433 static void
434 uname_decoder (struct tar_stat_info *st, char const *arg)
435 {
436 assign_string (&st->uname, arg);
437 }
438
439 static void
440 sparse_size_coder (struct tar_stat_info const *st, char const *keyword,
441 struct xheader *xhdr, void *data)
442 {
443 size_coder (st, keyword, xhdr, data);
444 }
445
446 static void
447 sparse_size_decoder (struct tar_stat_info *st, char const *arg)
448 {
449 uintmax_t u;
450 if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
451 st->archive_file_size = u;
452 }
453
454 static void
455 sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword,
456 struct xheader *xhdr, void *data)
457 {
458 code_num (st->sparse_map_avail, keyword, xhdr);
459 }
460
461 static void
462 sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg)
463 {
464 uintmax_t u;
465 if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
466 {
467 st->sparse_map_size = u;
468 st->sparse_map = calloc(st->sparse_map_size, sizeof(st->sparse_map[0]));
469 st->sparse_map_avail = 0;
470 }
471 }
472
473 static void
474 sparse_offset_coder (struct tar_stat_info const *st, char const *keyword,
475 struct xheader *xhdr, void *data)
476 {
477 size_t i = *(size_t*)data;
478 code_num (st->sparse_map[i].offset, keyword, xhdr);
479 }
480
481 static void
482 sparse_offset_decoder (struct tar_stat_info *st, char const *arg)
483 {
484 uintmax_t u;
485 if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
486 st->sparse_map[st->sparse_map_avail].offset = u;
487 }
488
489 static void
490 sparse_numbytes_coder (struct tar_stat_info const *st, char const *keyword,
491 struct xheader *xhdr, void *data)
492 {
493 size_t i = *(size_t*)data;
494 code_num (st->sparse_map[i].numbytes, keyword, xhdr);
495 }
496
497 static void
498 sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg)
499 {
500 uintmax_t u;
501 if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
502 {
503 if (st->sparse_map_avail == st->sparse_map_size)
504 {
505 size_t newsize = st->sparse_map_size *= 2;
506 st->sparse_map = xrealloc (st->sparse_map,
507 st->sparse_map_size
508 * sizeof st->sparse_map[0]);
509 }
510 st->sparse_map[st->sparse_map_avail++].numbytes = u;
511 }
512 }
513
514 struct xhdr_tab const xhdr_tab[] = {
515 { "atime", atime_coder, atime_decoder },
516 { "comment", dummy_coder, dummy_decoder },
517 { "charset", dummy_coder, dummy_decoder },
518 { "ctime", ctime_coder, ctime_decoder },
519 { "gid", gid_coder, gid_decoder },
520 { "gname", gname_coder, gname_decoder },
521 { "linkpath", linkpath_coder, linkpath_decoder},
522 { "mtime", mtime_coder, mtime_decoder },
523 { "path", path_coder, path_decoder },
524 { "size", size_coder, size_decoder },
525 { "uid", uid_coder, uid_decoder },
526 { "uname", uname_coder, uname_decoder },
527
528 /* Sparse file handling */
529 { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder },
530 { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder },
531 { "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder },
532 { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder },
533
534 #if 0 /* GNU private keywords (not yet implemented) */
535
536 /* The next directory entry actually contains the names of files
537 that were in the directory at the time the dump was made.
538 Supersedes GNUTYPE_DUMPDIR header type. */
539 { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder },
540
541 /* Keeps the tape/volume header. May be present only in the global headers.
542 Equivalent to GNUTYPE_VOLHDR. */
543 { "GNU.volume.header", volume_header_coder, volume_header_decoder },
544
545 /* These may be present in a first global header of the archive.
546 They provide the same functionality as GNUTYPE_MULTIVOL header.
547 The GNU.volume.size keeps the real_s_sizeleft value, which is
548 otherwise kept in the size field of a multivolume header. The
549 GNU.volume.offset keeps the offset of the start of this volume,
550 otherwise kept in oldgnu_header.offset. */
551 { "GNU.volume.size", volume_size_coder, volume_size_decoder },
552 { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder },
553 #endif
554
555 { NULL, NULL, NULL }
556 };
This page took 0.061057 seconds and 5 git commands to generate.