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