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