]> Dogcows Code - chaz/tar/blob - src/create.c
(write_header_name) In pax format, use "path" keyword if the file name is not ASCII
[chaz/tar] / src / create.c
1 /* Create a tar archive.
2
3 Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
4 2003, 2004 Free Software Foundation, Inc.
5
6 Written by John Gilmore, on 1985-08-25.
7
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16 Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22 #include "system.h"
23
24 #if HAVE_UTIME_H
25 # include <utime.h>
26 #else
27 struct utimbuf
28 {
29 long actime;
30 long modtime;
31 };
32 #endif
33
34 #include <quotearg.h>
35
36 #include "common.h"
37 #include <hash.h>
38
39 struct link
40 {
41 dev_t dev;
42 ino_t ino;
43 size_t nlink;
44 char name[1];
45 };
46 \f
47 /* The maximum uintmax_t value that can be represented with DIGITS digits,
48 assuming that each digit is BITS_PER_DIGIT wide. */
49 #define MAX_VAL_WITH_DIGITS(digits, bits_per_digit) \
50 ((digits) * (bits_per_digit) < sizeof (uintmax_t) * CHAR_BIT \
51 ? ((uintmax_t) 1 << ((digits) * (bits_per_digit))) - 1 \
52 : (uintmax_t) -1)
53
54 /* Convert VALUE to an octal representation suitable for tar headers.
55 Output to buffer WHERE with size SIZE.
56 The result is undefined if SIZE is 0 or if VALUE is too large to fit. */
57
58 static void
59 to_octal (uintmax_t value, char *where, size_t size)
60 {
61 uintmax_t v = value;
62 size_t i = size;
63
64 do
65 {
66 where[--i] = '0' + (v & ((1 << LG_8) - 1));
67 v >>= LG_8;
68 }
69 while (i);
70 }
71
72 /* Convert NEGATIVE VALUE to a base-256 representation suitable for
73 tar headers. NEGATIVE is 1 if VALUE was negative before being cast
74 to uintmax_t, 0 otherwise. Output to buffer WHERE with size SIZE.
75 The result is undefined if SIZE is 0 or if VALUE is too large to
76 fit. */
77
78 static void
79 to_base256 (int negative, uintmax_t value, char *where, size_t size)
80 {
81 uintmax_t v = value;
82 uintmax_t propagated_sign_bits =
83 ((uintmax_t) - negative << (CHAR_BIT * sizeof v - LG_256));
84 size_t i = size;
85
86 do
87 {
88 where[--i] = v & ((1 << LG_256) - 1);
89 v = propagated_sign_bits | (v >> LG_256);
90 }
91 while (i);
92 }
93
94 /* Convert NEGATIVE VALUE (which was originally of size VALSIZE) to
95 external form, using SUBSTITUTE (...) if VALUE won't fit. Output
96 to buffer WHERE with size SIZE. NEGATIVE is 1 iff VALUE was
97 negative before being cast to uintmax_t; its original bitpattern
98 can be deduced from VALSIZE, its original size before casting.
99 TYPE is the kind of value being output (useful for diagnostics).
100 Prefer the POSIX format of SIZE - 1 octal digits (with leading zero
101 digits), followed by '\0'. If this won't work, and if GNU or
102 OLDGNU format is allowed, use '\200' followed by base-256, or (if
103 NEGATIVE is nonzero) '\377' followed by two's complement base-256.
104 If neither format works, use SUBSTITUTE (...) instead. Pass to
105 SUBSTITUTE the address of an 0-or-1 flag recording whether the
106 substitute value is negative. */
107
108 static void
109 to_chars (int negative, uintmax_t value, size_t valsize,
110 uintmax_t (*substitute) (int *),
111 char *where, size_t size, const char *type)
112 {
113 int base256_allowed = (archive_format == GNU_FORMAT
114 || archive_format == OLDGNU_FORMAT);
115
116 /* Generate the POSIX octal representation if the number fits. */
117 if (! negative && value <= MAX_VAL_WITH_DIGITS (size - 1, LG_8))
118 {
119 where[size - 1] = '\0';
120 to_octal (value, where, size - 1);
121 }
122
123 /* Otherwise, generate the base-256 representation if we are
124 generating an old or new GNU format and if the number fits. */
125 else if (((negative ? -1 - value : value)
126 <= MAX_VAL_WITH_DIGITS (size - 1, LG_256))
127 && base256_allowed)
128 {
129 where[0] = negative ? -1 : 1 << (LG_256 - 1);
130 to_base256 (negative, value, where + 1, size - 1);
131 }
132
133 /* Otherwise, if the number is negative, and if it would not cause
134 ambiguity on this host by confusing positive with negative
135 values, then generate the POSIX octal representation of the value
136 modulo 2**(field bits). The resulting tar file is
137 machine-dependent, since it depends on the host word size. Yuck!
138 But this is the traditional behavior. */
139 else if (negative && valsize * CHAR_BIT <= (size - 1) * LG_8)
140 {
141 static int warned_once;
142 if (! warned_once)
143 {
144 warned_once = 1;
145 WARN ((0, 0, _("Generating negative octal headers")));
146 }
147 where[size - 1] = '\0';
148 to_octal (value & MAX_VAL_WITH_DIGITS (valsize * CHAR_BIT, 1),
149 where, size - 1);
150 }
151
152 /* Otherwise, output a substitute value if possible (with a
153 warning), and an error message if not. */
154 else
155 {
156 uintmax_t maxval = (base256_allowed
157 ? MAX_VAL_WITH_DIGITS (size - 1, LG_256)
158 : MAX_VAL_WITH_DIGITS (size - 1, LG_8));
159 char valbuf[UINTMAX_STRSIZE_BOUND + 1];
160 char maxbuf[UINTMAX_STRSIZE_BOUND];
161 char minbuf[UINTMAX_STRSIZE_BOUND + 1];
162 char const *minval_string;
163 char const *maxval_string = STRINGIFY_BIGINT (maxval, maxbuf);
164 char const *value_string;
165
166 if (base256_allowed)
167 {
168 uintmax_t m = maxval + 1 ? maxval + 1 : maxval / 2 + 1;
169 char *p = STRINGIFY_BIGINT (m, minbuf + 1);
170 *--p = '-';
171 minval_string = p;
172 }
173 else
174 minval_string = "0";
175
176 if (negative)
177 {
178 char *p = STRINGIFY_BIGINT (- value, valbuf + 1);
179 *--p = '-';
180 value_string = p;
181 }
182 else
183 value_string = STRINGIFY_BIGINT (value, valbuf);
184
185 if (substitute)
186 {
187 int negsub;
188 uintmax_t sub = substitute (&negsub) & maxval;
189 /* FIXME: This is the only place where GNU_FORMAT differs from
190 OLDGNU_FORMAT. Apart from this they are completely identical. */
191 uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? - sub : sub;
192 char subbuf[UINTMAX_STRSIZE_BOUND + 1];
193 char *sub_string = STRINGIFY_BIGINT (s, subbuf + 1);
194 if (negsub)
195 *--sub_string = '-';
196 WARN ((0, 0, _("value %s out of %s range %s..%s; substituting %s"),
197 value_string, type, minval_string, maxval_string,
198 sub_string));
199 to_chars (negsub, s, valsize, 0, where, size, type);
200 }
201 else
202 ERROR ((0, 0, _("value %s out of %s range %s..%s"),
203 value_string, type, minval_string, maxval_string));
204 }
205 }
206
207 static uintmax_t
208 gid_substitute (int *negative)
209 {
210 gid_t r;
211 #ifdef GID_NOBODY
212 r = GID_NOBODY;
213 #else
214 static gid_t gid_nobody;
215 if (!gid_nobody && !gname_to_gid ("nobody", &gid_nobody))
216 gid_nobody = -2;
217 r = gid_nobody;
218 #endif
219 *negative = r < 0;
220 return r;
221 }
222
223 void
224 gid_to_chars (gid_t v, char *p, size_t s)
225 {
226 to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t");
227 }
228
229 void
230 major_to_chars (major_t v, char *p, size_t s)
231 {
232 to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "major_t");
233 }
234
235 void
236 minor_to_chars (minor_t v, char *p, size_t s)
237 {
238 to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "minor_t");
239 }
240
241 void
242 mode_to_chars (mode_t v, char *p, size_t s)
243 {
244 /* In the common case where the internal and external mode bits are the same,
245 and we are not using POSIX or GNU format,
246 propagate all unknown bits to the external mode.
247 This matches historical practice.
248 Otherwise, just copy the bits we know about. */
249 int negative;
250 uintmax_t u;
251 if (S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX
252 && S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC
253 && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC
254 && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
255 && archive_format != POSIX_FORMAT
256 && archive_format != USTAR_FORMAT
257 && archive_format != GNU_FORMAT)
258 {
259 negative = v < 0;
260 u = v;
261 }
262 else
263 {
264 negative = 0;
265 u = ((v & S_ISUID ? TSUID : 0)
266 | (v & S_ISGID ? TSGID : 0)
267 | (v & S_ISVTX ? TSVTX : 0)
268 | (v & S_IRUSR ? TUREAD : 0)
269 | (v & S_IWUSR ? TUWRITE : 0)
270 | (v & S_IXUSR ? TUEXEC : 0)
271 | (v & S_IRGRP ? TGREAD : 0)
272 | (v & S_IWGRP ? TGWRITE : 0)
273 | (v & S_IXGRP ? TGEXEC : 0)
274 | (v & S_IROTH ? TOREAD : 0)
275 | (v & S_IWOTH ? TOWRITE : 0)
276 | (v & S_IXOTH ? TOEXEC : 0));
277 }
278 to_chars (negative, u, sizeof v, 0, p, s, "mode_t");
279 }
280
281 void
282 off_to_chars (off_t v, char *p, size_t s)
283 {
284 to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "off_t");
285 }
286
287 void
288 size_to_chars (size_t v, char *p, size_t s)
289 {
290 to_chars (0, (uintmax_t) v, sizeof v, 0, p, s, "size_t");
291 }
292
293 void
294 time_to_chars (time_t v, char *p, size_t s)
295 {
296 to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "time_t");
297 }
298
299 static uintmax_t
300 uid_substitute (int *negative)
301 {
302 uid_t r;
303 #ifdef UID_NOBODY
304 r = UID_NOBODY;
305 #else
306 static uid_t uid_nobody;
307 if (!uid_nobody && !uname_to_uid ("nobody", &uid_nobody))
308 uid_nobody = -2;
309 r = uid_nobody;
310 #endif
311 *negative = r < 0;
312 return r;
313 }
314
315 void
316 uid_to_chars (uid_t v, char *p, size_t s)
317 {
318 to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
319 }
320
321 void
322 uintmax_to_chars (uintmax_t v, char *p, size_t s)
323 {
324 to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
325 }
326
327 void
328 string_to_chars (char *str, char *p, size_t s)
329 {
330 strncpy (p, str, s);
331 p[s-1] = 0;
332 }
333
334 \f
335 /* A file is not dumpable if
336 a) it is empty *and* world-readable, or
337 b) current archive is /dev/null */
338
339 bool
340 file_dumpable_p (struct tar_stat_info *stat)
341 {
342 return !(dev_null_output
343 || (stat->archive_file_size == 0
344 && (stat->stat.st_mode & MODE_R) == MODE_R));
345 }
346
347 \f
348 /* Writing routines. */
349
350 /* Write the EOT block(s). Zero at least two blocks, through the end
351 of the record. Old tar, as previous versions of GNU tar, writes
352 garbage after two zeroed blocks. */
353 void
354 write_eot (void)
355 {
356 union block *pointer = find_next_block ();
357 memset (pointer->buffer, 0, BLOCKSIZE);
358 set_next_block_after (pointer);
359 pointer = find_next_block ();
360 memset (pointer->buffer, 0, available_space_after (pointer));
361 set_next_block_after (pointer);
362 }
363
364 /* Copy at most LEN bytes from SRC to DST. Terminate with NUL unless
365 SRC is LEN characters long */
366 static void
367 tar_copy_str (char *dst, const char *src, size_t len)
368 {
369 dst[len-1] = 0;
370 strncpy (dst, src, len);
371 }
372
373 /* Write a "private" header */
374 union block *
375 start_private_header (const char *name, size_t size)
376 {
377 time_t t;
378 union block *header = find_next_block ();
379
380 memset (header->buffer, 0, sizeof (union block));
381
382 tar_copy_str (header->header.name, name, NAME_FIELD_SIZE);
383 OFF_TO_CHARS (size, header->header.size);
384
385 time (&t);
386 TIME_TO_CHARS (t, header->header.mtime);
387 MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode);
388 UID_TO_CHARS (getuid (), header->header.uid);
389 GID_TO_CHARS (getgid (), header->header.gid);
390 MAJOR_TO_CHARS (0, header->header.devmajor);
391 MAJOR_TO_CHARS (0, header->header.devminor);
392 strncpy (header->header.magic, TMAGIC, TMAGLEN);
393 strncpy (header->header.version, TVERSION, TVERSLEN);
394 return header;
395 }
396
397 /* Create a new header and store there at most NAME_FIELD_SIZE bytes of
398 the file name */
399
400 static union block *
401 write_short_name (struct tar_stat_info *st)
402 {
403 union block *header = find_next_block ();
404 memset (header->buffer, 0, sizeof (union block));
405 tar_copy_str (header->header.name, st->file_name, NAME_FIELD_SIZE);
406 return header;
407 }
408
409 /* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */
410 static void
411 write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
412 {
413 size_t size = strlen (p) + 1;
414 size_t bufsize;
415 union block *header;
416
417 header = start_private_header ("././@LongLink", size);
418 strcpy (header->header.magic, OLDGNU_MAGIC);
419 header->header.typeflag = type;
420 finish_header (st, header, -1);
421
422 header = find_next_block ();
423
424 bufsize = available_space_after (header);
425
426 while (bufsize < size)
427 {
428 memcpy (header->buffer, p, bufsize);
429 p += bufsize;
430 size -= bufsize;
431 set_next_block_after (header + (bufsize - 1) / BLOCKSIZE);
432 header = find_next_block ();
433 bufsize = available_space_after (header);
434 }
435 memcpy (header->buffer, p, size);
436 memset (header->buffer + size, 0, bufsize - size);
437 set_next_block_after (header + (size - 1) / BLOCKSIZE);
438 }
439
440 static size_t
441 split_long_name (const char *name, size_t length)
442 {
443 size_t i;
444
445 if (length > PREFIX_FIELD_SIZE)
446 length = PREFIX_FIELD_SIZE+2;
447 for (i = length - 1; i > 0; i--)
448 if (ISSLASH (name[i]))
449 break;
450 return i;
451 }
452
453 static union block *
454 write_ustar_long_name (const char *name)
455 {
456 size_t length = strlen (name);
457 size_t i;
458 union block *header;
459
460 if (length > PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1)
461 {
462 WARN ((0, 0, _("%s: file name is too long (max %d); not dumped"),
463 quotearg_colon (name),
464 PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1));
465 return NULL;
466 }
467
468 i = split_long_name (name, length);
469 if (i == 0 || length - i - 1 > NAME_FIELD_SIZE)
470 {
471 WARN ((0, 0,
472 _("%s: file name is too long (cannot be split); not dumped"),
473 quotearg_colon (name)));
474 return NULL;
475 }
476
477 header = find_next_block ();
478 memset (header->buffer, 0, sizeof (header->buffer));
479 memcpy (header->header.prefix, name, i);
480 memcpy (header->header.name, name + i + 1, length - i - 1);
481
482 return header;
483 }
484
485 /* Write a long link name, depending on the current archive format */
486 static void
487 write_long_link (struct tar_stat_info *st)
488 {
489 switch (archive_format)
490 {
491 case POSIX_FORMAT:
492 xheader_store ("linkpath", st, NULL);
493 break;
494
495 case V7_FORMAT: /* old V7 tar format */
496 case USTAR_FORMAT:
497 case STAR_FORMAT:
498 WARN ((0, 0,
499 _("%s: link name is too long; not dumped"),
500 quotearg_colon (st->link_name)));
501 break;
502
503 case OLDGNU_FORMAT:
504 case GNU_FORMAT:
505 write_gnu_long_link (st, st->link_name, GNUTYPE_LONGLINK);
506 break;
507
508 default:
509 abort(); /*FIXME*/
510 }
511 }
512
513 static union block *
514 write_long_name (struct tar_stat_info *st)
515 {
516 switch (archive_format)
517 {
518 case POSIX_FORMAT:
519 xheader_store ("path", st, NULL);
520 break;
521
522 case V7_FORMAT:
523 case USTAR_FORMAT:
524 case STAR_FORMAT:
525 return write_ustar_long_name (st->file_name);
526
527 case OLDGNU_FORMAT:
528 case GNU_FORMAT:
529 write_gnu_long_link (st, st->file_name, GNUTYPE_LONGNAME);
530 break;
531
532 default:
533 abort(); /*FIXME*/
534 }
535 return write_short_name (st);
536 }
537
538 static union block *
539 write_extended (struct tar_stat_info *st, union block *old_header)
540 {
541 union block *header, hp;
542 size_t size;
543 char *p;
544
545 if (extended_header.buffer || extended_header.stk == NULL)
546 return old_header;
547
548 xheader_finish (&extended_header);
549 memcpy (hp.buffer, old_header, sizeof (hp));
550 p = xheader_xhdr_name (st);
551 xheader_write (XHDTYPE, p, &extended_header);
552 free (p);
553 header = find_next_block ();
554 memcpy (header, &hp.buffer, sizeof (hp.buffer));
555 return header;
556 }
557
558 static union block *
559 write_header_name (struct tar_stat_info *st)
560 {
561 if (archive_format == POSIX_FORMAT && !string_ascii_p (st->file_name))
562 {
563 xheader_store ("path", st, NULL);
564 return write_short_name (st);
565 }
566 else if (NAME_FIELD_SIZE < strlen (st->file_name))
567 return write_long_name (st);
568 else
569 return write_short_name (st);
570 }
571
572 \f
573 /* Header handling. */
574
575 /* Make a header block for the file whose stat info is st,
576 and return its address. */
577
578 union block *
579 start_header (struct tar_stat_info *st)
580 {
581 union block *header;
582
583 header = write_header_name (st);
584 if (!header)
585 return NULL;
586
587 /* Override some stat fields, if requested to do so. */
588
589 if (owner_option != (uid_t) -1)
590 st->stat.st_uid = owner_option;
591 if (group_option != (gid_t) -1)
592 st->stat.st_gid = group_option;
593 if (mode_option)
594 st->stat.st_mode = ((st->stat.st_mode & ~MODE_ALL)
595 | mode_adjust (st->stat.st_mode, mode_option));
596
597 /* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a)
598 for a few tars and came up with the following interoperability
599 matrix:
600
601 WRITER
602 1 2 3 4 5 6 7 8 9 READER
603 . . . . . . . . . 1 = SunOS 4.2 tar
604 # . . # # . . # # 2 = NEC SVR4.0.2 tar
605 . . . # # . . # . 3 = Solaris 2.1 tar
606 . . . . . . . . . 4 = GNU tar 1.11.1
607 . . . . . . . . . 5 = HP-UX 8.07 tar
608 . . . . . . . . . 6 = Ultrix 4.1
609 . . . . . . . . . 7 = AIX 3.2
610 . . . . . . . . . 8 = Hitachi HI-UX 1.03
611 . . . . . . . . . 9 = Omron UNIOS-B 4.3BSD 1.60Beta
612
613 . = works
614 # = ``impossible file type''
615
616 The following mask for old archive removes the `#'s in column 4
617 above, thus making GNU tar both a universal donor and a universal
618 acceptor for Paul's test. */
619
620 if (archive_format == V7_FORMAT || archive_format == USTAR_FORMAT)
621 MODE_TO_CHARS (st->stat.st_mode & MODE_ALL, header->header.mode);
622 else
623 MODE_TO_CHARS (st->stat.st_mode, header->header.mode);
624
625 if (st->stat.st_uid > MAXOCTAL7 && archive_format == POSIX_FORMAT)
626 xheader_store ("uid", st, NULL);
627 else
628 UID_TO_CHARS (st->stat.st_uid, header->header.uid);
629
630 if (st->stat.st_gid > MAXOCTAL7 && archive_format == POSIX_FORMAT)
631 xheader_store ("gid", st, NULL);
632 else
633 GID_TO_CHARS (st->stat.st_gid, header->header.gid);
634
635 if (st->stat.st_size > MAXOCTAL11 && archive_format == POSIX_FORMAT)
636 xheader_store ("size", st, NULL);
637 else
638 OFF_TO_CHARS (st->stat.st_size, header->header.size);
639
640 TIME_TO_CHARS (st->stat.st_mtime, header->header.mtime);
641
642 /* FIXME */
643 if (S_ISCHR (st->stat.st_mode)
644 || S_ISBLK (st->stat.st_mode))
645 {
646 st->devmajor = major (st->stat.st_rdev);
647 st->devminor = minor (st->stat.st_rdev);
648
649 if (st->devmajor > MAXOCTAL7 && archive_format == POSIX_FORMAT)
650 xheader_store ("devmajor", st, NULL);
651 else
652 MAJOR_TO_CHARS (st->devmajor, header->header.devmajor);
653
654 if (st->devminor > MAXOCTAL7 && archive_format == POSIX_FORMAT)
655 xheader_store ("devminor", st, NULL);
656 else
657 MAJOR_TO_CHARS (st->devminor, header->header.devminor);
658 }
659 else
660 {
661 MAJOR_TO_CHARS (0, header->header.devmajor);
662 MINOR_TO_CHARS (0, header->header.devminor);
663 }
664
665 if (archive_format == POSIX_FORMAT)
666 {
667 xheader_store ("atime", st, NULL);
668 xheader_store ("ctime", st, NULL);
669 }
670 else if (incremental_option)
671 if (archive_format == OLDGNU_FORMAT)
672 {
673 TIME_TO_CHARS (st->stat.st_atime, header->oldgnu_header.atime);
674 TIME_TO_CHARS (st->stat.st_ctime, header->oldgnu_header.ctime);
675 }
676
677 header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
678
679 switch (archive_format)
680 {
681 case V7_FORMAT:
682 break;
683
684 case OLDGNU_FORMAT:
685 case GNU_FORMAT: /*FIXME?*/
686 /* Overwrite header->header.magic and header.version in one blow. */
687 strcpy (header->header.magic, OLDGNU_MAGIC);
688 break;
689
690 case POSIX_FORMAT:
691 case USTAR_FORMAT:
692 strncpy (header->header.magic, TMAGIC, TMAGLEN);
693 strncpy (header->header.version, TVERSION, TVERSLEN);
694 break;
695
696 default:
697 abort ();
698 }
699
700 if (archive_format == V7_FORMAT || numeric_owner_option)
701 {
702 /* header->header.[ug]name are left as the empty string. */
703 }
704 else
705 {
706 uid_to_uname (st->stat.st_uid, &st->uname);
707 gid_to_gname (st->stat.st_gid, &st->gname);
708
709 if (archive_format == POSIX_FORMAT
710 && (strlen (st->uname) > UNAME_FIELD_SIZE
711 || !string_ascii_p (st->uname)))
712 xheader_store ("uname", st, NULL);
713 else
714 UNAME_TO_CHARS (st->uname, header->header.uname);
715
716 if (archive_format == POSIX_FORMAT
717 && (strlen (st->gname) > GNAME_FIELD_SIZE
718 || !string_ascii_p (st->gname)))
719 xheader_store ("gname", st, NULL);
720 else
721 GNAME_TO_CHARS (st->gname, header->header.gname);
722 }
723
724 return header;
725 }
726
727 void
728 simple_finish_header (union block *header)
729 {
730 size_t i;
731 int sum;
732 char *p;
733
734 memcpy (header->header.chksum, CHKBLANKS, sizeof header->header.chksum);
735
736 sum = 0;
737 p = header->buffer;
738 for (i = sizeof *header; i-- != 0; )
739 /* We can't use unsigned char here because of old compilers, e.g. V7. */
740 sum += 0xFF & *p++;
741
742 /* Fill in the checksum field. It's formatted differently from the
743 other fields: it has [6] digits, a null, then a space -- rather than
744 digits, then a null. We use to_chars.
745 The final space is already there, from
746 checksumming, and to_chars doesn't modify it.
747
748 This is a fast way to do:
749
750 sprintf(header->header.chksum, "%6o", sum); */
751
752 uintmax_to_chars ((uintmax_t) sum, header->header.chksum, 7);
753
754 set_next_block_after (header);
755 }
756
757 /* Finish off a filled-in header block and write it out. We also
758 print the file name and/or full info if verbose is on. If BLOCK_ORDINAL
759 is not negative, is the block ordinal of the first record for this
760 file, which may be a preceding long name or long link record. */
761 void
762 finish_header (struct tar_stat_info *st,
763 union block *header, off_t block_ordinal)
764 {
765 size_t i;
766 int sum;
767 char *p;
768
769 /* Note: It is important to do this before the call to write_extended(),
770 so that the actual ustar header is printed */
771 if (verbose_option
772 && header->header.typeflag != GNUTYPE_LONGLINK
773 && header->header.typeflag != GNUTYPE_LONGNAME
774 && header->header.typeflag != XHDTYPE
775 && header->header.typeflag != XGLTYPE)
776 {
777 /* These globals are parameters to print_header, sigh. */
778
779 current_header = header;
780 current_format = archive_format;
781 print_header (st, block_ordinal);
782 }
783
784 header = write_extended (st, header);
785 simple_finish_header (header);
786 }
787 \f
788
789 void
790 pad_archive (off_t size_left)
791 {
792 union block *blk;
793 while (size_left > 0)
794 {
795 save_sizeleft = size_left;
796 blk = find_next_block ();
797 memset (blk->buffer, 0, BLOCKSIZE);
798 set_next_block_after (blk);
799 size_left -= BLOCKSIZE;
800 }
801 }
802
803 static enum dump_status
804 dump_regular_file (int fd, struct tar_stat_info *stat)
805 {
806 off_t size_left = stat->stat.st_size;
807 off_t block_ordinal;
808 union block *blk;
809
810 block_ordinal = current_block_ordinal ();
811 blk = start_header (stat);
812 if (!blk)
813 return dump_status_fail;
814
815 /* Mark contiguous files, if we support them. */
816 if (archive_format != V7_FORMAT && S_ISCTG (stat->stat.st_mode))
817 blk->header.typeflag = CONTTYPE;
818
819 finish_header (stat, blk, block_ordinal);
820
821 while (size_left > 0)
822 {
823 size_t bufsize, count;
824
825 if (multi_volume_option)
826 {
827 assign_string (&save_name, stat->file_name);
828 save_sizeleft = size_left;
829 save_totsize = stat->stat.st_size;
830 }
831 blk = find_next_block ();
832
833 bufsize = available_space_after (blk);
834
835 if (size_left < bufsize)
836 {
837 /* Last read -- zero out area beyond. */
838 bufsize = size_left;
839 count = bufsize % BLOCKSIZE;
840 if (count)
841 memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
842 }
843
844 count = (fd < 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
845 if (count < 0)
846 {
847 read_diag_details (stat->orig_file_name,
848 stat->stat.st_size - size_left, bufsize);
849 pad_archive (size_left);
850 return dump_status_short;
851 }
852 size_left -= count;
853
854 set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
855
856 if (count != bufsize)
857 {
858 char buf[UINTMAX_STRSIZE_BOUND];
859 memset (blk->buffer + count, 0, bufsize - count);
860 WARN ((0, 0,
861 ngettext ("%s: File shrank by %s byte; padding with zeros",
862 "%s: File shrank by %s bytes; padding with zeros",
863 size_left),
864 quotearg_colon (stat->orig_file_name),
865 STRINGIFY_BIGINT (size_left, buf)));
866 if (! ignore_failed_read_option)
867 exit_status = TAREXIT_FAILURE;
868 pad_archive (size_left);
869 return dump_status_short;
870 }
871 }
872 return dump_status_ok;
873 }
874
875 void
876 dump_regular_finish (int fd, struct tar_stat_info *st, time_t original_ctime)
877 {
878 if (fd >= 0)
879 {
880 struct stat final_stat;
881 if (fstat (fd, &final_stat) != 0)
882 {
883 stat_diag (st->orig_file_name);
884 }
885 else if (final_stat.st_ctime != original_ctime)
886 {
887 WARN ((0, 0, _("%s: file changed as we read it"),
888 quotearg_colon (st->orig_file_name)));
889 }
890 if (close (fd) != 0)
891 {
892 close_diag (st->orig_file_name);
893 }
894 }
895 if (remove_files_option)
896 {
897 if (unlink (st->orig_file_name) == -1)
898 unlink_error (st->orig_file_name);
899 }
900 }
901
902 void
903 dump_dir0 (char *directory,
904 struct tar_stat_info *stat, int top_level, dev_t parent_device)
905 {
906 dev_t our_device = stat->stat.st_dev;
907
908 if (!is_avoided_name (stat->orig_file_name))
909 {
910 union block *blk = NULL;
911 off_t block_ordinal = current_block_ordinal ();
912 stat->stat.st_size = 0; /* force 0 size on dir */
913
914 blk = start_header (stat);
915 if (!blk)
916 return;
917
918 if (incremental_option)
919 blk->header.typeflag = GNUTYPE_DUMPDIR;
920 else /* if (standard_option) */
921 blk->header.typeflag = DIRTYPE;
922
923 /* If we're gnudumping, we aren't done yet so don't close it. */
924
925 if (!incremental_option)
926 finish_header (stat, blk, block_ordinal);
927 else if (gnu_list_name->dir_contents)
928 {
929 off_t size_left;
930 off_t totsize;
931 size_t bufsize;
932 ssize_t count;
933 const char *buffer, *p_buffer;
934 off_t block_ordinal = current_block_ordinal ();
935
936 buffer = gnu_list_name->dir_contents; /* FOO */
937 totsize = 0;
938 if (buffer)
939 for (p_buffer = buffer; *p_buffer; )
940 {
941 size_t size = strlen (p_buffer) + 1;
942 totsize += size;
943 p_buffer += size;
944 }
945 totsize++;
946 OFF_TO_CHARS (totsize, blk->header.size);
947 finish_header (stat, blk, block_ordinal);
948 p_buffer = buffer;
949 size_left = totsize;
950 while (size_left > 0)
951 {
952 if (multi_volume_option)
953 {
954 assign_string (&save_name, stat->orig_file_name);
955 save_sizeleft = size_left;
956 save_totsize = totsize;
957 }
958 blk = find_next_block ();
959 bufsize = available_space_after (blk);
960 if (size_left < bufsize)
961 {
962 bufsize = size_left;
963 count = bufsize % BLOCKSIZE;
964 if (count)
965 memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
966 }
967 memcpy (blk->buffer, p_buffer, bufsize);
968 size_left -= bufsize;
969 p_buffer += bufsize;
970 set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
971 }
972 if (multi_volume_option)
973 assign_string (&save_name, 0);
974 return;
975 }
976 }
977
978 if (!recursion_option)
979 return;
980
981 if (one_file_system_option
982 && !top_level
983 && parent_device != stat->stat.st_dev)
984 {
985 if (verbose_option)
986 WARN ((0, 0,
987 _("%s: file is on a different filesystem; not dumped"),
988 quotearg_colon (stat->orig_file_name)));
989 return;
990 }
991
992 {
993 char const *entry;
994 size_t entry_len;
995 char *name_buf = strdup (stat->orig_file_name);
996 size_t name_size = strlen (name_buf);
997 size_t name_len = name_size;
998
999 /* Now output all the files in the directory. */
1000 /* FIXME: Should speed this up by cd-ing into the dir. */
1001
1002 for (entry = directory; (entry_len = strlen (entry)) != 0;
1003 entry += entry_len + 1)
1004 {
1005 if (name_size < name_len + entry_len)
1006 {
1007 name_size = name_len + entry_len;
1008 name_buf = xrealloc (name_buf, name_size + 1);
1009 }
1010 strcpy (name_buf + name_len, entry);
1011 if (!excluded_name (name_buf))
1012 dump_file (name_buf, 0, our_device);
1013 }
1014
1015 free (name_buf);
1016 }
1017 }
1018
1019 /* Ensure exactly one trailing slash. */
1020 static void
1021 ensure_slash (char **pstr)
1022 {
1023 size_t len = strlen (*pstr);
1024 while (len >= 1 && ISSLASH ((*pstr)[len - 1]))
1025 len--;
1026 if (!ISSLASH ((*pstr)[len]))
1027 *pstr = xrealloc (*pstr, len + 2);
1028 (*pstr)[len++] = '/';
1029 (*pstr)[len] = '\0';
1030 }
1031
1032 bool
1033 dump_dir (struct tar_stat_info *stat, int top_level, dev_t parent_device)
1034 {
1035 char *directory;
1036
1037 directory = savedir (stat->orig_file_name);
1038 if (!directory)
1039 {
1040 savedir_diag (stat->orig_file_name);
1041 return false;
1042 }
1043
1044 ensure_slash (&stat->orig_file_name);
1045 ensure_slash (&stat->file_name);
1046
1047 dump_dir0 (directory, stat, top_level, parent_device);
1048
1049 free (directory);
1050 return true;
1051 }
1052
1053 \f
1054 /* Main functions of this module. */
1055
1056 void
1057 create_archive (void)
1058 {
1059 char *p;
1060
1061 open_archive (ACCESS_WRITE);
1062 xheader_write_global ();
1063
1064 if (incremental_option)
1065 {
1066 size_t buffer_size = 1000;
1067 char *buffer = xmalloc (buffer_size);
1068 const char *q;
1069
1070 collect_and_sort_names ();
1071
1072 while ((p = name_from_list ()) != NULL)
1073 if (!excluded_name (p))
1074 dump_file (p, -1, (dev_t) 0);
1075
1076 blank_name_list ();
1077 while ((p = name_from_list ()) != NULL)
1078 if (!excluded_name (p))
1079 {
1080 size_t plen = strlen (p);
1081 if (buffer_size <= plen)
1082 {
1083 while ((buffer_size *= 2) <= plen)
1084 continue;
1085 buffer = xrealloc (buffer, buffer_size);
1086 }
1087 memcpy (buffer, p, plen);
1088 if (! ISSLASH (buffer[plen - 1]))
1089 buffer[plen++] = '/';
1090 q = gnu_list_name->dir_contents;
1091 if (q)
1092 while (*q)
1093 {
1094 size_t qlen = strlen (q);
1095 if (*q == 'Y')
1096 {
1097 if (buffer_size < plen + qlen)
1098 {
1099 while ((buffer_size *=2 ) < plen + qlen)
1100 continue;
1101 buffer = xrealloc (buffer, buffer_size);
1102 }
1103 strcpy (buffer + plen, q + 1);
1104 dump_file (buffer, -1, (dev_t) 0);
1105 }
1106 q += qlen + 1;
1107 }
1108 }
1109 free (buffer);
1110 }
1111 else
1112 {
1113 while ((p = name_next (1)) != NULL)
1114 if (!excluded_name (p))
1115 dump_file (p, 1, (dev_t) 0);
1116 }
1117
1118 write_eot ();
1119 close_archive ();
1120
1121 if (listed_incremental_option)
1122 write_directory_file ();
1123 }
1124
1125
1126 /* Calculate the hash of a link. */
1127 static unsigned
1128 hash_link (void const *entry, unsigned n_buckets)
1129 {
1130 struct link const *link = entry;
1131 return (uintmax_t) (link->dev ^ link->ino) % n_buckets;
1132 }
1133
1134 /* Compare two links for equality. */
1135 static bool
1136 compare_links (void const *entry1, void const *entry2)
1137 {
1138 struct link const *link1 = entry1;
1139 struct link const *link2 = entry2;
1140 return ((link1->dev ^ link2->dev) | (link1->ino ^ link2->ino)) == 0;
1141 }
1142
1143 static void
1144 unknown_file_error (char *p)
1145 {
1146 WARN ((0, 0, _("%s: Unknown file type; file ignored"),
1147 quotearg_colon (p)));
1148 if (!ignore_failed_read_option)
1149 exit_status = TAREXIT_FAILURE;
1150 }
1151
1152 \f
1153 /* Handling of hard links */
1154
1155 /* Table of all non-directories that we've written so far. Any time
1156 we see another, we check the table and avoid dumping the data
1157 again if we've done it once already. */
1158 static Hash_table *link_table;
1159
1160 /* Try to dump stat as a hard link to another file in the archive. If
1161 succeeded returns true */
1162 static bool
1163 dump_hard_link (struct tar_stat_info *stat)
1164 {
1165 if (link_table && stat->stat.st_nlink > 1)
1166 {
1167 struct link lp;
1168 struct link *dup;
1169 off_t block_ordinal;
1170 union block *blk;
1171
1172 lp.ino = stat->stat.st_ino;
1173 lp.dev = stat->stat.st_dev;
1174
1175 if ((dup = hash_lookup (link_table, &lp)))
1176 {
1177 /* We found a link. */
1178 char const *link_name = safer_name_suffix (dup->name, true);
1179
1180 dup->nlink--;
1181
1182 block_ordinal = current_block_ordinal ();
1183 assign_string (&stat->link_name, link_name);
1184 if (NAME_FIELD_SIZE < strlen (link_name))
1185 write_long_link (stat);
1186
1187 stat->stat.st_size = 0;
1188 blk = start_header (stat);
1189 if (!blk)
1190 return true;
1191 tar_copy_str (blk->header.linkname, link_name, NAME_FIELD_SIZE);
1192
1193 blk->header.typeflag = LNKTYPE;
1194 finish_header (stat, blk, block_ordinal);
1195
1196 if (remove_files_option && unlink (stat->orig_file_name) != 0)
1197 unlink_error (stat->orig_file_name);
1198
1199 return true;
1200 }
1201 }
1202 return false;
1203 }
1204
1205 static void
1206 file_count_links (struct tar_stat_info *stat)
1207 {
1208 if (stat->stat.st_nlink > 1)
1209 {
1210 struct link *dup;
1211 struct link *lp = xmalloc (offsetof (struct link, name)
1212 + strlen (stat->orig_file_name) + 1);
1213 lp->ino = stat->stat.st_ino;
1214 lp->dev = stat->stat.st_dev;
1215 lp->nlink = stat->stat.st_nlink;
1216 strcpy (lp->name, stat->orig_file_name);
1217
1218 if (! ((link_table
1219 || (link_table = hash_initialize (0, 0, hash_link,
1220 compare_links, 0)))
1221 && (dup = hash_insert (link_table, lp))))
1222 xalloc_die ();
1223
1224 if (dup != lp)
1225 abort ();
1226 lp->nlink--;
1227 }
1228 }
1229
1230 /* For each dumped file, check if all its links were dumped. Emit
1231 warnings if it is not so. */
1232 void
1233 check_links ()
1234 {
1235 struct link *lp;
1236
1237 if (!link_table)
1238 return;
1239
1240 for (lp = hash_get_first (link_table); lp;
1241 lp = hash_get_next (link_table, lp))
1242 {
1243 if (lp->nlink)
1244 {
1245 WARN ((0, 0, _("Missing links to '%s'.\n"), lp->name));
1246 }
1247 }
1248 }
1249
1250
1251 /* Dump a single file, recursing on directories. P is the file name
1252 to dump. TOP_LEVEL tells whether this is a top-level call; zero
1253 means no, positive means yes, and negative means the top level
1254 of an incremental dump. PARENT_DEVICE is the device of P's
1255 parent directory; it is examined only if TOP_LEVEL is zero. */
1256
1257 /* FIXME: One should make sure that for *every* path leading to setting
1258 exit_status to failure, a clear diagnostic has been issued. */
1259
1260 void
1261 dump_file0 (struct tar_stat_info *stat, char *p,
1262 int top_level, dev_t parent_device)
1263 {
1264 union block *header;
1265 char type;
1266 time_t original_ctime;
1267 struct utimbuf restore_times;
1268 off_t block_ordinal = -1;
1269
1270 if (interactive_option && !confirm ("add", p))
1271 return;
1272
1273 assign_string (&stat->orig_file_name, p);
1274 assign_string (&stat->file_name, safer_name_suffix (p, false));
1275
1276 if (deref_stat (dereference_option, p, &stat->stat) != 0)
1277 {
1278 stat_diag (p);
1279 return;
1280 }
1281 stat->archive_file_size = stat->stat.st_size;
1282 sys_stat_nanoseconds(stat);
1283 original_ctime = stat->stat.st_ctime;
1284 restore_times.actime = stat->stat.st_atime;
1285 restore_times.modtime = stat->stat.st_mtime;
1286
1287 #ifdef S_ISHIDDEN
1288 if (S_ISHIDDEN (stat->stat.st_mode))
1289 {
1290 char *new = (char *) alloca (strlen (p) + 2);
1291 if (new)
1292 {
1293 strcpy (new, p);
1294 strcat (new, "@");
1295 p = new;
1296 }
1297 }
1298 #endif
1299
1300 /* See if we want only new files, and check if this one is too old to
1301 put in the archive. */
1302
1303 if (!S_ISDIR (stat->stat.st_mode)
1304 && stat->stat.st_mtime < newer_mtime_option
1305 && (!after_date_option || stat->stat.st_ctime < newer_ctime_option))
1306 {
1307 if (0 < top_level) /* equivalent to !incremental_option */
1308 WARN ((0, 0, _("%s: file is unchanged; not dumped"),
1309 quotearg_colon (p)));
1310 /* FIXME: recheck this return. */
1311 return;
1312 }
1313
1314 /* See if we are trying to dump the archive. */
1315 if (sys_file_is_archive (stat))
1316 {
1317 WARN ((0, 0, _("%s: file is the archive; not dumped"),
1318 quotearg_colon (p)));
1319 return;
1320 }
1321
1322 if (S_ISDIR (stat->stat.st_mode))
1323 {
1324 dump_dir (stat, top_level, parent_device);
1325 if (atime_preserve_option)
1326 utime (p, &restore_times);
1327 return;
1328 }
1329 else if (is_avoided_name (p))
1330 return;
1331 else
1332 {
1333 /* Check for multiple links. */
1334 if (dump_hard_link (stat))
1335 return;
1336
1337 /* This is not a link to a previously dumped file, so dump it. */
1338
1339 if (S_ISREG (stat->stat.st_mode)
1340 || S_ISCTG (stat->stat.st_mode))
1341 {
1342 int fd;
1343 enum dump_status status;
1344
1345 if (file_dumpable_p (stat))
1346 {
1347 fd = open (stat->orig_file_name,
1348 O_RDONLY | O_BINARY);
1349 if (fd < 0)
1350 {
1351 if (!top_level && errno == ENOENT)
1352 WARN ((0, 0, _("%s: File removed before we read it"),
1353 quotearg_colon (stat->orig_file_name)));
1354 else
1355 open_diag (stat->orig_file_name);
1356 return;
1357 }
1358 }
1359 else
1360 fd = -1;
1361
1362 if (sparse_option && sparse_file_p (stat))
1363 {
1364 status = sparse_dump_file (fd, stat);
1365 if (status == dump_status_not_implemented)
1366 status = dump_regular_file (fd, stat);
1367 }
1368 else
1369 status = dump_regular_file (fd, stat);
1370
1371 switch (status)
1372 {
1373 case dump_status_ok:
1374 if (multi_volume_option)
1375 assign_string (&save_name, 0);
1376 dump_regular_finish (fd, stat, original_ctime);
1377 break;
1378
1379 case dump_status_short:
1380 if (multi_volume_option)
1381 assign_string (&save_name, 0);
1382 close (fd);
1383 break;
1384
1385 case dump_status_fail:
1386 close (fd);
1387 return;
1388
1389 case dump_status_not_implemented:
1390 abort ();
1391 }
1392
1393 if (atime_preserve_option)
1394 utime (stat->orig_file_name, &restore_times);
1395 file_count_links (stat);
1396 return;
1397 }
1398 #ifdef HAVE_READLINK
1399 else if (S_ISLNK (stat->stat.st_mode))
1400 {
1401 char *buffer;
1402 int size;
1403 size_t linklen = stat->stat.st_size;
1404 if (linklen != stat->stat.st_size || linklen + 1 == 0)
1405 xalloc_die ();
1406 buffer = (char *) alloca (linklen + 1);
1407 size = readlink (p, buffer, linklen + 1);
1408 if (size < 0)
1409 {
1410 readlink_diag (p);
1411 return;
1412 }
1413 buffer[size] = '\0';
1414 assign_string (&stat->link_name, buffer);
1415 if (size > NAME_FIELD_SIZE)
1416 write_long_link (stat);
1417
1418 block_ordinal = current_block_ordinal ();
1419 stat->stat.st_size = 0; /* force 0 size on symlink */
1420 header = start_header (stat);
1421 if (!header)
1422 return;
1423 tar_copy_str (header->header.linkname, buffer, NAME_FIELD_SIZE);
1424 header->header.typeflag = SYMTYPE;
1425 finish_header (stat, header, block_ordinal);
1426 /* nothing more to do to it */
1427
1428 if (remove_files_option)
1429 {
1430 if (unlink (p) == -1)
1431 unlink_error (p);
1432 }
1433 file_count_links (stat);
1434 return;
1435 }
1436 #endif
1437 else if (S_ISCHR (stat->stat.st_mode))
1438 type = CHRTYPE;
1439 else if (S_ISBLK (stat->stat.st_mode))
1440 type = BLKTYPE;
1441 else if (S_ISFIFO (stat->stat.st_mode))
1442 type = FIFOTYPE;
1443 else if (S_ISSOCK (stat->stat.st_mode))
1444 {
1445 WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
1446 return;
1447 }
1448 else if (S_ISDOOR (stat->stat.st_mode))
1449 {
1450 WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
1451 return;
1452 }
1453 else
1454 {
1455 unknown_file_error (p);
1456 return;
1457 }
1458 }
1459
1460 if (archive_format == V7_FORMAT)
1461 {
1462 unknown_file_error (p);
1463 return;
1464 }
1465
1466 block_ordinal = current_block_ordinal ();
1467 stat->stat.st_size = 0; /* force 0 size */
1468 header = start_header (stat);
1469 if (!header)
1470 return;
1471 header->header.typeflag = type;
1472
1473 if (type != FIFOTYPE)
1474 {
1475 MAJOR_TO_CHARS (major (stat->stat.st_rdev),
1476 header->header.devmajor);
1477 MINOR_TO_CHARS (minor (stat->stat.st_rdev),
1478 header->header.devminor);
1479 }
1480
1481 finish_header (stat, header, block_ordinal);
1482 if (remove_files_option)
1483 {
1484 if (unlink (p) == -1)
1485 unlink_error (p);
1486 }
1487 }
1488
1489 void
1490 dump_file (char *p, int top_level, dev_t parent_device)
1491 {
1492 struct tar_stat_info stat;
1493 tar_stat_init (&stat);
1494 dump_file0 (&stat, p, top_level, parent_device);
1495 tar_stat_destroy (&stat);
1496 }
This page took 0.114069 seconds and 5 git commands to generate.