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