]> Dogcows Code - chaz/tar/blob - src/extract.c
*** empty log message ***
[chaz/tar] / src / extract.c
1 /* Extract files from a tar archive.
2 Copyright (C) 1988, 1992 Free Software Foundation
3
4 This file is part of GNU Tar.
5
6 GNU Tar is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Tar is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Tar; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 /*
21 * Extract files from a tar archive.
22 *
23 * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
24 */
25
26 #include <stdio.h>
27 #include <errno.h>
28 #ifndef STDC_HEADERS
29 extern int errno;
30 #endif
31 #include <sys/types.h>
32 #include <time.h>
33 time_t time();
34
35 #ifdef BSD42
36 #include <sys/file.h>
37 #else
38 #ifndef V7
39 #include <fcntl.h>
40 #endif
41 #endif
42
43 #ifdef NO_OPEN3
44 /* We need the #define's even though we don't use them. */
45 #include "open3.h"
46 #endif
47
48 #ifdef EMUL_OPEN3
49 /* Simulated 3-argument open for systems that don't have it */
50 #include "open3.h"
51 #endif
52
53 #include "tar.h"
54 #include "port.h"
55
56 #if defined(_POSIX_VERSION)
57 #include <utime.h>
58 #endif
59
60 extern FILE *msg_file;
61
62 extern union record *head; /* Points to current tape header */
63 extern struct stat hstat; /* Stat struct corresponding */
64 extern int head_standard; /* Tape header is in ANSI format */
65
66 extern char *save_name;
67 extern long save_totsize;
68 extern long save_sizeleft;
69
70 int confirm();
71 void decode_header();
72 void extract_mangle();
73 void extract_sparse_file();
74 long from_oct();
75 void gnu_restore();
76 extern void print_header();
77 extern void skip_file();
78 extern void skip_extended_headers();
79 extern void pr_mkdir();
80 void saverec();
81
82 int make_dirs(); /* Makes required directories */
83
84 static time_t now = 0; /* Current time */
85 static we_are_root = 0; /* True if our effective uid == 0 */
86 static int notumask = ~0; /* Masks out bits user doesn't want */
87
88 /*
89 * "Scratch" space to store the information about a sparse file before
90 * writing the info into the header or extended header
91 */
92 /*struct sp_array *sparsearray;*/
93
94 /* number of elts storable in the sparsearray */
95 /*int sp_array_size = 10;*/
96
97 struct saved_dir_info
98 {
99 char *path;
100 int mode;
101 int atime;
102 int mtime;
103 saved_dir_info *next;
104 };
105
106 struct saved_dir_info *saved_dir_info_head;
107
108 /*
109 * Set up to extract files.
110 */
111 void
112 extr_init()
113 {
114 int ourmask;
115
116 now = time((time_t *)0);
117 if (geteuid() == 0)
118 we_are_root = 1;
119
120 /*
121 * We need to know our umask. But if f_use_protection is set,
122 * leave our kernel umask at 0, and our "notumask" at ~0.
123 */
124 ourmask = umask(0); /* Read it */
125 if (!f_use_protection) {
126 (void) umask (ourmask); /* Set it back how it was */
127 notumask = ~ourmask; /* Make umask override permissions */
128 }
129 }
130
131
132 /*
133 * Extract a file from the archive.
134 */
135 void
136 extract_archive()
137 {
138 register char *data;
139 int fd, check, namelen, written, openflag;
140 long size;
141 time_t acc_upd_times[2];
142 register int skipcrud;
143 register int i;
144 /* int sparse_ind = 0;*/
145 union record *exhdr;
146 struct saved_dir_info *tmp;
147 /* int end_nulls; */
148 char **longp;
149 static char *longname;
150 static char *longlink;
151
152 saverec(&head); /* Make sure it sticks around */
153 userec(head); /* And go past it in the archive */
154 decode_header(head, &hstat, &head_standard, 1); /* Snarf fields */
155
156 if(f_confirm && !confirm("extract",head->header.name)) {
157 if (head->header.isextended)
158 skip_extended_headers();
159 skip_file((long)hstat.st_size);
160 saverec((union record **)0);
161 return;
162 }
163
164 /* Print the record from 'head' and 'hstat' */
165 if (f_verbose)
166 print_header();
167
168 /*
169 * Check for fully specified pathnames and other atrocities.
170 *
171 * Note, we can't just make a pointer to the new file name,
172 * since saverec() might move the header and adjust "head".
173 * We have to start from "head" every time we want to touch
174 * the header record.
175 */
176 skipcrud = 0;
177 while (!f_absolute_paths && '/' == head->header.name[skipcrud]) {
178 static int warned_once = 0;
179
180 skipcrud++; /* Force relative path */
181 if (!warned_once++) {
182 msg("Removing leading / from absolute path names in the archive.");
183 }
184 }
185
186 switch (head->header.linkflag) {
187
188 default:
189 msg("Unknown file type '%c' for %s, extracted as normal file",
190 head->header.linkflag, skipcrud+head->header.name);
191 /* FALL THRU */
192
193 /*
194 * JK - What we want to do if the file is sparse is loop through
195 * the array of sparse structures in the header and read in
196 * and translate the character strings representing 1) the offset
197 * at which to write and 2) how many bytes to write into numbers,
198 * which we store into the scratch array, "sparsearray". This
199 * array makes our life easier the same way it did in creating
200 * the tar file that had to deal with a sparse file.
201 *
202 * After we read in the first five (at most) sparse structures,
203 * we check to see if the file has an extended header, i.e.,
204 * if more sparse structures are needed to describe the contents
205 * of the new file. If so, we read in the extended headers
206 * and continue to store their contents into the sparsearray.
207 */
208 case LF_SPARSE:
209 sp_array_size = 10;
210 sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array));
211 for (i = 0; i < SPARSE_IN_HDR; i++) {
212 sparsearray[i].offset =
213 from_oct(1+12, head->header.sp[i].offset);
214 sparsearray[i].numbytes =
215 from_oct(1+12, head->header.sp[i].numbytes);
216 if (!sparsearray[i].numbytes)
217 break;
218 }
219
220 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
221
222 if (head->header.isextended) {
223 /* read in the list of extended headers
224 and translate them into the sparsearray
225 as before */
226
227 /* static */ int ind = SPARSE_IN_HDR;
228
229 for (;;) {
230
231 exhdr = findrec();
232 for (i = 0; i < SPARSE_EXT_HDR; i++) {
233
234 if (i+ind > sp_array_size-1) {
235 /*
236 * realloc the scratch area
237 * since we've run out of room --
238 */
239 sparsearray = (struct sp_array *)
240 realloc(sparsearray,
241 2 * sp_array_size * (sizeof(struct sp_array)));
242 sp_array_size *= 2;
243 }
244 if (!exhdr->ext_hdr.sp[i].numbytes)
245 break;
246 sparsearray[i+ind].offset =
247 from_oct(1+12, exhdr->ext_hdr.sp[i].offset);
248 sparsearray[i+ind].numbytes =
249 from_oct(1+12, exhdr->ext_hdr.sp[i].numbytes);
250 }
251 if (!exhdr->ext_hdr.isextended)
252 break;
253 else {
254 ind += SPARSE_EXT_HDR;
255 userec(exhdr);
256 }
257 }
258 userec(exhdr);
259 }
260
261 /* FALL THRU */
262 case LF_OLDNORMAL:
263 case LF_NORMAL:
264 case LF_CONTIG:
265 /*
266 * Appears to be a file.
267 * See if it's really a directory.
268 */
269 namelen = strlen(skipcrud+head->header.name)-1;
270 if (head->header.name[skipcrud+namelen] == '/')
271 goto really_dir;
272
273 /* FIXME, deal with protection issues */
274 again_file:
275 openflag = (f_keep?
276 O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL:
277 O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC)
278 | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
279 /*
280 * JK - The last | is a kludge to solve the problem
281 * the O_APPEND flag causes with files we are
282 * trying to make sparse: when a file is opened
283 * with O_APPEND, it writes to the last place
284 * that something was written, thereby ignoring
285 * any lseeks that we have done. We add this
286 * extra condition to make it able to lseek when
287 * a file is sparse, i.e., we don't open the new
288 * file with this flag. (Grump -- this bug caused
289 * me to waste a good deal of time, I might add)
290 */
291
292 if(f_exstdout) {
293 fd = 1;
294 goto extract_file;
295 }
296 #ifdef O_CTG
297 /*
298 * Contiguous files (on the Masscomp) have to specify
299 * the size in the open call that creates them.
300 */
301 if (head->header.linkflag == LF_CONTIG)
302 fd = open(skipcrud+head->header.name, openflag | O_CTG,
303 hstat.st_mode, hstat.st_size);
304 else
305 #endif
306 {
307 #ifdef NO_OPEN3
308 /*
309 * On raw V7 we won't let them specify -k (f_keep), but
310 * we just bull ahead and create the files.
311 */
312 fd = creat(skipcrud+head->header.name,
313 hstat.st_mode);
314 #else
315 /*
316 * With 3-arg open(), we can do this up right.
317 */
318 fd = open(skipcrud+head->header.name, openflag,
319 hstat.st_mode);
320 #endif
321 }
322
323 if (fd < 0) {
324 if (make_dirs(skipcrud+head->header.name))
325 goto again_file;
326 msg_perror("Could not create file %s",skipcrud+head->header.name);
327 if (head->header.isextended)
328 skip_extended_headers();
329 skip_file((long)hstat.st_size);
330 goto quit;
331 }
332
333 extract_file:
334 if (head->header.linkflag == LF_SPARSE) {
335 char *name;
336 int namelen;
337
338 /*
339 * Kludge alert. NAME is assigned to header.name
340 * because during the extraction, the space that
341 * contains the header will get scribbled on, and
342 * the name will get munged, so any error messages
343 * that happen to contain the filename will look
344 * REAL interesting unless we do this.
345 */
346 namelen = strlen(skipcrud+head->header.name);
347 name = (char *) malloc((sizeof(char)) * namelen);
348 bcopy(skipcrud+head->header.name, name, namelen);
349 size = hstat.st_size;
350 extract_sparse_file(fd, &size, hstat.st_size,
351 name);
352 }
353 else
354 for (size = hstat.st_size;
355 size > 0;
356 size -= written) {
357
358 /* long offset,
359 numbytes;*/
360
361 if(f_multivol) {
362 save_name=head->header.name;
363 save_totsize=hstat.st_size;
364 save_sizeleft=size;
365 }
366
367 /*
368 * Locate data, determine max length
369 * writeable, write it, record that
370 * we have used the data, then check
371 * if the write worked.
372 */
373 data = findrec()->charptr;
374 if (data == NULL) { /* Check it... */
375 msg("Unexpected EOF on archive file");
376 break;
377 }
378 /*
379 * JK - If the file is sparse, use the sparsearray
380 * that we created before to lseek into the new
381 * file the proper amount, and to see how many
382 * bytes we want to write at that position.
383 */
384 /* if (head->header.linkflag == LF_SPARSE) {
385 off_t pos;
386
387 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
388 printf("%d at %d\n", (int) pos, sparse_ind);
389 written = sparsearray[sparse_ind++].numbytes;
390 } else*/
391 written = endofrecs()->charptr - data;
392 if (written > size)
393 written = size;
394 errno = 0;
395 check = write(fd, data, written);
396 /*
397 * The following is in violation of strict
398 * typing, since the arg to userec
399 * should be a struct rec *. FIXME.
400 */
401 userec((union record *)(data + written - 1));
402 if (check == written) continue;
403 /*
404 * Error in writing to file.
405 * Print it, skip to next file in archive.
406 */
407 if(check<0)
408 msg_perror("couldn't write to file %s",skipcrud+head->header.name);
409 else
410 msg("could only write %d of %d bytes to file %s",written,check,skipcrud+head->header.name);
411 skip_file((long)(size - written));
412 break; /* Still do the close, mod time, chmod, etc */
413 }
414
415 if(f_multivol)
416 save_name = 0;
417
418 /* If writing to stdout, don't try to do anything
419 to the filename; it doesn't exist, or we don't
420 want to touch it anyway */
421 if(f_exstdout)
422 break;
423
424 /* if (head->header.isextended) {
425 register union record *exhdr;
426 register int i;
427
428 for (i = 0; i < 21; i++) {
429 long offset;
430
431 if (!exhdr->ext_hdr.sp[i].numbytes)
432 break;
433 offset = from_oct(1+12,
434 exhdr->ext_hdr.sp[i].offset);
435 written = from_oct(1+12,
436 exhdr->ext_hdr.sp[i].numbytes);
437 lseek(fd, offset, 0);
438 check = write(fd, data, written);
439 if (check == written) continue;
440
441 }
442
443
444 }*/
445 check = close(fd);
446 if (check < 0) {
447 msg_perror("Error while closing %s",skipcrud+head->header.name);
448 }
449
450
451 set_filestat:
452
453 /*
454 * If we are root, set the owner and group of the extracted
455 * file. This does what is wanted both on real Unix and on
456 * System V. If we are running as a user, we extract as that
457 * user; if running as root, we extract as the original owner.
458 */
459 if (we_are_root || f_do_chown) {
460 if (chown(skipcrud+head->header.name, hstat.st_uid,
461 hstat.st_gid) < 0) {
462 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.name,hstat.st_uid,hstat.st_gid);
463 }
464 }
465
466 /*
467 * Set the modified time of the file.
468 *
469 * Note that we set the accessed time to "now", which
470 * is really "the time we started extracting files".
471 * unless f_gnudump is used, in which case .st_atime is used
472 */
473 if (!f_modified) {
474 /* fixme if f_gnudump should set ctime too, but how? */
475 if(f_gnudump)
476 acc_upd_times[0]=hstat.st_atime;
477 else acc_upd_times[0] = now; /* Accessed now */
478 acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
479 if (utime(skipcrud+head->header.name,
480 acc_upd_times) < 0) {
481 msg_perror("couldn't change access and modification times of %s",skipcrud+head->header.name);
482 }
483 }
484 /* We do the utime before the chmod because some versions of
485 utime are broken and trash the modes of the file. Since
486 we then change the mode anyway, we don't care. . . */
487
488 /*
489 * If '-k' is not set, open() or creat() could have saved
490 * the permission bits from a previously created file,
491 * ignoring the ones we specified.
492 * Even if -k is set, if the file has abnormal
493 * mode bits, we must chmod since writing or chown() has
494 * probably reset them.
495 *
496 * If -k is set, we know *we* created this file, so the mode
497 * bits were set by our open(). If the file is "normal", we
498 * skip the chmod. This works because we did umask(0) if -p
499 * is set, so umask will have left the specified mode alone.
500 */
501 if ((!f_keep)
502 || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
503 if (chmod(skipcrud+head->header.name,
504 notumask & (int)hstat.st_mode) < 0) {
505 msg_perror("cannot change mode of file %s to %ld",skipcrud+head->header.name,notumask & (int)hstat.st_mode);
506 }
507 }
508
509 quit:
510 break;
511
512 case LF_LINK:
513 again_link:
514 {
515 struct stat st1,st2;
516
517 check = link (head->header.linkname,
518 skipcrud+head->header.name);
519 if (check == 0)
520 break;
521 if (make_dirs(skipcrud+head->header.name))
522 goto again_link;
523 if(f_gnudump && errno==EEXIST)
524 break;
525 if( stat(head->header.linkname, &st1) == 0
526 && stat(skipcrud+head->header.name, &st2)==0
527 && st1.st_dev==st2.st_dev
528 && st1.st_ino==st2.st_ino)
529 break;
530 msg_perror("Could not link %s to %s",
531 skipcrud+head->header.name,head->header.linkname);
532 }
533 break;
534
535 #ifdef S_ISLNK
536 case LF_SYMLINK:
537 again_symlink:
538 check = symlink(head->header.linkname,
539 skipcrud+head->header.name);
540 /* FIXME, don't worry uid, gid, etc... */
541 if (check == 0)
542 break;
543 if (make_dirs(skipcrud+head->header.name))
544 goto again_symlink;
545 msg_perror("Could not create symlink to %s",head->header.linkname);
546 break;
547 #endif
548
549 #ifdef S_IFCHR
550 case LF_CHR:
551 hstat.st_mode |= S_IFCHR;
552 goto make_node;
553 #endif
554
555 #ifdef S_IFBLK
556 case LF_BLK:
557 hstat.st_mode |= S_IFBLK;
558 #endif
559 #if defined(S_IFCHR) || defined(S_IFBLK)
560 make_node:
561 check = mknod(skipcrud+head->header.name,
562 (int) hstat.st_mode, (int) hstat.st_rdev);
563 if (check != 0) {
564 if (make_dirs(skipcrud+head->header.name))
565 goto make_node;
566 msg_perror("Could not make %s",skipcrud+head->header.name);
567 break;
568 };
569 goto set_filestat;
570 #endif
571
572 #ifdef S_ISFIFO
573 /* If local system doesn't support FIFOs, use default case */
574 case LF_FIFO:
575 make_fifo:
576 check = mkfifo(skipcrud+head->header.name,
577 (int) hstat.st_mode);
578 if (check != 0) {
579 if (make_dirs(skipcrud+head->header.name))
580 goto make_fifo;
581 msg_perror("Could not make %s",skipcrud+head->header.name);
582 break;
583 };
584 goto set_filestat;
585 #endif
586
587 case LF_DIR:
588 case LF_DUMPDIR:
589 namelen = strlen(skipcrud+head->header.name)-1;
590 really_dir:
591 /* Check for trailing /, and zap as many as we find. */
592 while (namelen && head->header.name[skipcrud+namelen] == '/')
593 head->header.name[skipcrud+namelen--] = '\0';
594 if(f_gnudump) { /* Read the entry and delete files
595 that aren't listed in the archive */
596 gnu_restore(skipcrud);
597
598 } else if(head->header.linkflag==LF_DUMPDIR)
599 skip_file((long)(hstat.st_size));
600
601
602 again_dir:
603 check = mkdir(skipcrud+head->header.name,
604 (we_are_root ? 0 : 0300) | (int)hstat.st_mode);
605 if (check != 0) {
606 struct stat st1;
607
608 if (make_dirs(skipcrud+head->header.name))
609 goto again_dir;
610 /* If we're trying to create '.', let it be. */
611 if (head->header.name[skipcrud+namelen] == '.' &&
612 (namelen==0 ||
613 head->header.name[skipcrud+namelen-1]=='/'))
614 goto check_perms;
615 if( errno==EEXIST
616 && stat(skipcrud+head->header.name,&st1)==0
617 && (S_ISDIR(st1.st_mode)))
618 break;
619 msg_perror("Could not create directory %s",skipcrud+head->header.name);
620 break;
621 }
622
623 check_perms:
624 if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) {
625 hstat.st_mode |= 0300;
626 msg("Added write and execute permission to directory %s",
627 skipcrud+head->header.name);
628 }
629
630 if (f_modified)
631 goto set_filestat;
632 tmp = malloc (sizeof (struct saved_dir_info));
633 tmp->path = malloc (strlen (skipcrud + head->header.name) + 1);
634 strcpy (tmp->path, skipcrud + head->header.name);
635 tmp->mode = hstat.st_mode;
636 tmp->atime = hstat.st_atime;
637 tmp->mtime = hstat.st_mtime;
638 tmp->next = saved_dir_info_head;
639 saved_dir_info_head = tmp;
640 case LF_VOLHDR:
641 if(f_verbose) {
642 printf("Reading %s\n",head->header.name);
643 }
644 break;
645
646 case LF_NAMES:
647 extract_mangle(head);
648 break;
649
650 case LF_MULTIVOL:
651 msg("Can't extract '%s'--file is continued from another volume\n",head->header.name);
652 skip_file((long)hstat.st_size);
653 break;
654
655 case LF_LONGNAME:
656 longp = &longname;
657 goto extract_long;
658
659 case LF_LONGLINK
660 longp = &longlink;
661 extract_long:
662
663 if (*longp)
664 free (*longp);
665 *longp = ck_malloc (hstat.st_size);
666
667 /* This loop is copied from the extract_file label above;
668 as a result, some of the variable names (like `written')
669 might be confusing. */
670 for (size = hstat.st_size;
671 size > 0;
672 size -= written)
673 {
674
675
676
677 }
678
679 /* We don't need to save it any longer. */
680 saverec((union record **) 0); /* Unsave it */
681 }
682
683 /*
684 * After a file/link/symlink/dir creation has failed, see if
685 * it's because some required directory was not present, and if
686 * so, create all required dirs.
687 */
688 int
689 make_dirs(pathname)
690 char *pathname;
691 {
692 char *p; /* Points into path */
693 int madeone = 0; /* Did we do anything yet? */
694 int save_errno = errno; /* Remember caller's errno */
695 int check;
696
697 if (errno != ENOENT)
698 return 0; /* Not our problem */
699
700 for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
701 /* Avoid mkdir of empty string, if leading or double '/' */
702 if (p == pathname || p[-1] == '/')
703 continue;
704 /* Avoid mkdir where last part of path is '.' */
705 if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
706 continue;
707 *p = 0; /* Truncate the path there */
708 check = mkdir (pathname, 0777); /* Try to create it as a dir */
709 if (check == 0) {
710 /* Fix ownership */
711 if (we_are_root) {
712 if (chown(pathname, hstat.st_uid,
713 hstat.st_gid) < 0) {
714 msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
715 }
716 }
717 pr_mkdir(pathname, p-pathname, notumask&0777);
718 madeone++; /* Remember if we made one */
719 *p = '/';
720 continue;
721 }
722 *p = '/';
723 if (errno == EEXIST) /* Directory already exists */
724 continue;
725 /*
726 * Some other error in the mkdir. We return to the caller.
727 */
728 break;
729 }
730
731 errno = save_errno; /* Restore caller's errno */
732 return madeone; /* Tell them to retry if we made one */
733 }
734
735 void
736 extract_sparse_file(fd, sizeleft, totalsize, name)
737 int fd;
738 long *sizeleft,
739 totalsize;
740 char *name;
741 {
742 /* register char *data;*/
743 union record *datarec;
744 int sparse_ind = 0;
745 int written,
746 count;
747
748 /* assuming sizeleft is initially totalsize */
749
750
751 while (*sizeleft > 0) {
752 datarec = findrec();
753 if (datarec == NULL) {
754 msg("Unexpected EOF on archive file");
755 return;
756 }
757 lseek(fd, sparsearray[sparse_ind].offset, 0);
758 written = sparsearray[sparse_ind++].numbytes;
759 while (written > RECORDSIZE) {
760 count = write(fd, datarec->charptr, RECORDSIZE);
761 if (count < 0)
762 msg_perror("couldn't write to file %s", name);
763 written -= count;
764 *sizeleft -= count;
765 userec(datarec);
766 datarec = findrec();
767 }
768
769 count = write(fd, datarec->charptr, written);
770
771 if (count < 0) {
772 msg_perror("couldn't write to file %s", name);
773 } else if (count != written) {
774 msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name);
775 skip_file((long) (*sizeleft));
776 }
777
778 written -= count;
779 *sizeleft -= count;
780 userec(datarec);
781 }
782 free(sparsearray);
783 /* if (end_nulls) {
784 register int i;
785
786 printf("%d\n", (int) end_nulls);
787 for (i = 0; i < end_nulls; i++)
788 write(fd, "\000", 1);
789 }*/
790 userec(datarec);
791 }
792
793 /* Set back the utime and mode for all the extracted directories. */
794 void restore_saved_dir_info ()
795 {
796 time_t acc_upd_times[2];
797 saved_dir_info *tmp;
798
799 while (saved_info_head != NULL)
800 {
801 /* fixme if f_gnudump should set ctime too, but how? */
802 if(f_gnudump)
803 acc_upd_times[0]=saved_info_head -> atime;
804 else acc_upd_times[0] = now; /* Accessed now */
805 acc_upd_times[1] = saved_info_head -> mtime; /* Mod'd */
806 if (utime(saved_info_head -> path, acc_upd_times) < 0) {
807 msg_perror("couldn't change access and modification times of %s",
808 saved_info_head -> path);
809 }
810 if ((!f_keep) || (saved_info_head -> mode & (S_ISUID|S_ISGID|S_ISVTX)))
811 {
812 if (chmod(saved_info_head -> path,
813 notumask & saved_info_head -> mode) < 0) {
814 msg_perror("cannot change mode of file %s to %ld",
815 saved_info_head -> path,
816 notumask & saved_info_head -> mode);
817 }
818 }
819 saved_info_head = saved_info_head -> next;
820 }
821 }
This page took 0.078913 seconds and 4 git commands to generate.