]> 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 struct 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 char *bp;
150
151 saverec(&head); /* Make sure it sticks around */
152 userec(head); /* And go past it in the archive */
153 decode_header(head, &hstat, &head_standard, 1); /* Snarf fields */
154
155 if(f_confirm && !confirm("extract",current_file_name)) {
156 if (head->header.isextended)
157 skip_extended_headers();
158 skip_file((long)hstat.st_size);
159 saverec((union record **)0);
160 return;
161 }
162
163 /* Print the record from 'head' and 'hstat' */
164 if (f_verbose)
165 print_header();
166
167 /*
168 * Check for fully specified pathnames and other atrocities.
169 *
170 * Note, we can't just make a pointer to the new file name,
171 * since saverec() might move the header and adjust "head".
172 * We have to start from "head" every time we want to touch
173 * the header record.
174 */
175 skipcrud = 0;
176 while (!f_absolute_paths
177 && '/' == current_file_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+current_file_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+current_file_name)-1;
270 if (current_file_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((longname ? longname : head->header.name)
303 + skipcrud,
304 openflag | O_CTG,
305 hstat.st_mode, hstat.st_size);
306 else
307 #endif
308 {
309 #ifdef NO_OPEN3
310 /*
311 * On raw V7 we won't let them specify -k (f_keep), but
312 * we just bull ahead and create the files.
313 */
314 fd = creat((longname
315 ? longname
316 : head->header.name) + skipcrud,
317 hstat.st_mode);
318 #else
319 /*
320 * With 3-arg open(), we can do this up right.
321 */
322 fd = open(skipcrud + current_file_name,
323 openflag, hstat.st_mode);
324 #endif
325 }
326
327 if (fd < 0) {
328 if (make_dirs(skipcrud + current_file_name))
329 goto again_file;
330 msg_perror("Could not create file %s",
331 skipcrud + current_file_name);
332 if (head->header.isextended)
333 skip_extended_headers();
334 skip_file((long)hstat.st_size);
335 goto quit;
336 }
337
338 extract_file:
339 if (head->header.linkflag == LF_SPARSE) {
340 char *name;
341 int namelen;
342
343 /*
344 * Kludge alert. NAME is assigned to header.name
345 * because during the extraction, the space that
346 * contains the header will get scribbled on, and
347 * the name will get munged, so any error messages
348 * that happen to contain the filename will look
349 * REAL interesting unless we do this.
350 */
351 namelen = strlen(skipcrud + current_file_name);
352 name = (char *) malloc((sizeof(char)) * namelen);
353 bcopy(skipcrud+current_file_name, name, namelen);
354 size = hstat.st_size;
355 extract_sparse_file(fd, &size, hstat.st_size, name);
356 }
357 else
358 for (size = hstat.st_size;
359 size > 0;
360 size -= written) {
361
362 /* long offset,
363 numbytes;*/
364
365 if(f_multivol) {
366 save_name=current_file_name;
367 save_totsize=hstat.st_size;
368 save_sizeleft=size;
369 }
370
371 /*
372 * Locate data, determine max length
373 * writeable, write it, record that
374 * we have used the data, then check
375 * if the write worked.
376 */
377 data = findrec()->charptr;
378 if (data == NULL) { /* Check it... */
379 msg("Unexpected EOF on archive file");
380 break;
381 }
382 /*
383 * JK - If the file is sparse, use the sparsearray
384 * that we created before to lseek into the new
385 * file the proper amount, and to see how many
386 * bytes we want to write at that position.
387 */
388 /* if (head->header.linkflag == LF_SPARSE) {
389 off_t pos;
390
391 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
392 printf("%d at %d\n", (int) pos, sparse_ind);
393 written = sparsearray[sparse_ind++].numbytes;
394 } else*/
395 written = endofrecs()->charptr - data;
396 if (written > size)
397 written = size;
398 errno = 0;
399 check = write(fd, data, written);
400 /*
401 * The following is in violation of strict
402 * typing, since the arg to userec
403 * should be a struct rec *. FIXME.
404 */
405 userec((union record *)(data + written - 1));
406 if (check == written) continue;
407 /*
408 * Error in writing to file.
409 * Print it, skip to next file in archive.
410 */
411 if(check<0)
412 msg_perror("couldn't write to file %s",
413 skipcrud + current_file_name);
414 else
415 msg("could only write %d of %d bytes to file %s",
416 written,check,skipcrud + current_file_name);
417 skip_file((long)(size - written));
418 break; /* Still do the close, mod time, chmod, etc */
419 }
420
421 if(f_multivol)
422 save_name = 0;
423
424 /* If writing to stdout, don't try to do anything
425 to the filename; it doesn't exist, or we don't
426 want to touch it anyway */
427 if(f_exstdout)
428 break;
429
430 /* if (head->header.isextended) {
431 register union record *exhdr;
432 register int i;
433
434 for (i = 0; i < 21; i++) {
435 long offset;
436
437 if (!exhdr->ext_hdr.sp[i].numbytes)
438 break;
439 offset = from_oct(1+12,
440 exhdr->ext_hdr.sp[i].offset);
441 written = from_oct(1+12,
442 exhdr->ext_hdr.sp[i].numbytes);
443 lseek(fd, offset, 0);
444 check = write(fd, data, written);
445 if (check == written) continue;
446
447 }
448
449
450 }*/
451 check = close(fd);
452 if (check < 0) {
453 msg_perror("Error while closing %s",
454 skipcrud + current_file_name);
455 }
456
457
458 set_filestat:
459
460 /*
461 * If we are root, set the owner and group of the extracted
462 * file. This does what is wanted both on real Unix and on
463 * System V. If we are running as a user, we extract as that
464 * user; if running as root, we extract as the original owner.
465 */
466 if (we_are_root || f_do_chown) {
467 if (chown(skipcrud + current_file_name,
468 hstat.st_uid, hstat.st_gid) < 0) {
469 msg_perror("cannot chown file %s to uid %d gid %d",
470 skipcrud + current_file_name,
471 hstat.st_uid,hstat.st_gid);
472 }
473 }
474
475 /*
476 * Set the modified time of the file.
477 *
478 * Note that we set the accessed time to "now", which
479 * is really "the time we started extracting files".
480 * unless f_gnudump is used, in which case .st_atime is used
481 */
482 if (!f_modified) {
483 /* fixme if f_gnudump should set ctime too, but how? */
484 if(f_gnudump)
485 acc_upd_times[0]=hstat.st_atime;
486 else acc_upd_times[0] = now; /* Accessed now */
487 acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
488 if (utime(skipcrud + current_file_name,
489 acc_upd_times) < 0) {
490 msg_perror("couldn't change access and modification times of %s",skipcrud + current_file_name);
491 }
492 }
493 /* We do the utime before the chmod because some versions of
494 utime are broken and trash the modes of the file. Since
495 we then change the mode anyway, we don't care. . . */
496
497 /*
498 * If '-k' is not set, open() or creat() could have saved
499 * the permission bits from a previously created file,
500 * ignoring the ones we specified.
501 * Even if -k is set, if the file has abnormal
502 * mode bits, we must chmod since writing or chown() has
503 * probably reset them.
504 *
505 * If -k is set, we know *we* created this file, so the mode
506 * bits were set by our open(). If the file is "normal", we
507 * skip the chmod. This works because we did umask(0) if -p
508 * is set, so umask will have left the specified mode alone.
509 */
510 if ((!f_keep)
511 || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
512 if (chmod(skipcrud + current_file_name,
513 notumask & (int)hstat.st_mode) < 0) {
514 msg_perror("cannot change mode of file %s to %ld",
515 skipcrud + current_file_name,
516 notumask & (int)hstat.st_mode);
517 }
518 }
519
520 quit:
521 break;
522
523 case LF_LINK:
524 again_link:
525 {
526 struct stat st1,st2;
527
528 check = link (current_link_name, skipcrud + current_file_name);
529
530 if (check == 0)
531 break;
532 if (make_dirs(skipcrud + current_file_name))
533 goto again_link;
534 if(f_gnudump && errno==EEXIST)
535 break;
536 if(stat(current_link_name, &st1) == 0
537 && stat(current_file_name + skipcrud, &st2)==0
538 && st1.st_dev==st2.st_dev
539 && st1.st_ino==st2.st_ino)
540 break;
541 msg_perror("Could not link %s to %s",
542 skipcrud + current_file_name,
543 current_link_name);
544 }
545 break;
546
547 #ifdef S_ISLNK
548 case LF_SYMLINK:
549 again_symlink:
550 check = symlink(current_link_name,
551 skipcrud + current_file_name);
552 /* FIXME, don't worry uid, gid, etc... */
553 if (check == 0)
554 break;
555 if (make_dirs(current_file_name + skipcrud))
556 goto again_symlink;
557 msg_perror("Could not create symlink to %s",
558 current_link_name);
559 break;
560 #endif
561
562 #ifdef S_IFCHR
563 case LF_CHR:
564 hstat.st_mode |= S_IFCHR;
565 goto make_node;
566 #endif
567
568 #ifdef S_IFBLK
569 case LF_BLK:
570 hstat.st_mode |= S_IFBLK;
571 #endif
572 #if defined(S_IFCHR) || defined(S_IFBLK)
573 make_node:
574 check = mknod(current_file_name + skipcrud,
575 (int) hstat.st_mode, (int) hstat.st_rdev);
576 if (check != 0) {
577 if (make_dirs(skipcrud + current_file_name))
578 goto make_node;
579 msg_perror("Could not make %s",
580 current_file_name + skipcrud);
581 break;
582 };
583 goto set_filestat;
584 #endif
585
586 #ifdef S_ISFIFO
587 /* If local system doesn't support FIFOs, use default case */
588 case LF_FIFO:
589 make_fifo:
590 check = mkfifo(current_file_name + skipcrud,
591 (int) hstat.st_mode);
592 if (check != 0) {
593 if (make_dirs(current_file_name + skipcrud))
594 goto make_fifo;
595 msg_perror("Could not make %s",
596 skipcrud + current_file_name);
597 break;
598 };
599 goto set_filestat;
600 #endif
601
602 case LF_DIR:
603 case LF_DUMPDIR:
604 namelen = strlen(current_file_name) + skipcrud - 1;
605 really_dir:
606 /* Check for trailing /, and zap as many as we find. */
607 while (namelen
608 && current_file_name[skipcrud+namelen] == '/')
609 current_file_name[skipcrud+namelen--] = '\0';
610 if(f_gnudump) { /* Read the entry and delete files
611 that aren't listed in the archive */
612 gnu_restore(skipcrud);
613
614 } else if(head->header.linkflag==LF_DUMPDIR)
615 skip_file((long)(hstat.st_size));
616
617
618 again_dir:
619 check = mkdir(skipcrud+current_file_name,
620 (we_are_root ? 0 : 0300) | (int)hstat.st_mode);
621 if (check != 0) {
622 struct stat st1;
623
624 if (make_dirs(skipcrud+current_file_name))
625 goto again_dir;
626 /* If we're trying to create '.', let it be. */
627 if (current_file_name[skipcrud+namelen] == '.' &&
628 (namelen==0 ||
629 current_file_name[skipcrud+namelen-1]=='/'))
630 goto check_perms;
631 if( errno==EEXIST
632 && stat(skipcrud+current_file_name,&st1)==0
633 && (S_ISDIR(st1.st_mode)))
634 break;
635 msg_perror("Could not create directory %s",skipcrud+current_file_name);
636 break;
637 }
638
639 check_perms:
640 if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) {
641 hstat.st_mode |= 0300;
642 msg("Added write and execute permission to directory %s",
643 skipcrud+current_file_name);
644 }
645
646 if (f_modified)
647 goto set_filestat;
648 tmp = (struct saved_dir_info *) malloc (sizeof (struct saved_dir_info));
649 tmp->path = malloc (strlen (skipcrud + current_file_name) + 1);
650 strcpy (tmp->path, skipcrud + current_file_name);
651 tmp->mode = hstat.st_mode;
652 tmp->atime = hstat.st_atime;
653 tmp->mtime = hstat.st_mtime;
654 tmp->next = saved_dir_info_head;
655 saved_dir_info_head = tmp;
656 case LF_VOLHDR:
657 if(f_verbose) {
658 printf("Reading %s\n", current_file_name);
659 }
660 break;
661
662 case LF_NAMES:
663 extract_mangle(head);
664 break;
665
666 case LF_MULTIVOL:
667 msg("Can't extract '%s'--file is continued from another volume\n",current_file_name);
668 skip_file((long)hstat.st_size);
669 break;
670
671 case LF_LONGNAME:
672 case LF_LONGLINK:
673 msg ("Visible long name error\n");
674 skip_file ((long)hstat.st_size);
675 break;
676 }
677
678 /* We don't need to save it any longer. */
679 saverec((union record **) 0); /* Unsave it */
680 }
681
682 /*
683 * After a file/link/symlink/dir creation has failed, see if
684 * it's because some required directory was not present, and if
685 * so, create all required dirs.
686 */
687 int
688 make_dirs(pathname)
689 char *pathname;
690 {
691 char *p; /* Points into path */
692 int madeone = 0; /* Did we do anything yet? */
693 int save_errno = errno; /* Remember caller's errno */
694 int check;
695
696 if (errno != ENOENT)
697 return 0; /* Not our problem */
698
699 for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
700 /* Avoid mkdir of empty string, if leading or double '/' */
701 if (p == pathname || p[-1] == '/')
702 continue;
703 /* Avoid mkdir where last part of path is '.' */
704 if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
705 continue;
706 *p = 0; /* Truncate the path there */
707 check = mkdir (pathname, 0777); /* Try to create it as a dir */
708 if (check == 0) {
709 /* Fix ownership */
710 if (we_are_root) {
711 if (chown(pathname, hstat.st_uid,
712 hstat.st_gid) < 0) {
713 msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
714 }
715 }
716 pr_mkdir(pathname, p-pathname, notumask&0777);
717 madeone++; /* Remember if we made one */
718 *p = '/';
719 continue;
720 }
721 *p = '/';
722 if (errno == EEXIST) /* Directory already exists */
723 continue;
724 /*
725 * Some other error in the mkdir. We return to the caller.
726 */
727 break;
728 }
729
730 errno = save_errno; /* Restore caller's errno */
731 return madeone; /* Tell them to retry if we made one */
732 }
733
734 void
735 extract_sparse_file(fd, sizeleft, totalsize, name)
736 int fd;
737 long *sizeleft,
738 totalsize;
739 char *name;
740 {
741 /* register char *data;*/
742 union record *datarec;
743 int sparse_ind = 0;
744 int written,
745 count;
746
747 /* assuming sizeleft is initially totalsize */
748
749
750 while (*sizeleft > 0) {
751 datarec = findrec();
752 if (datarec == NULL) {
753 msg("Unexpected EOF on archive file");
754 return;
755 }
756 lseek(fd, sparsearray[sparse_ind].offset, 0);
757 written = sparsearray[sparse_ind++].numbytes;
758 while (written > RECORDSIZE) {
759 count = write(fd, datarec->charptr, RECORDSIZE);
760 if (count < 0)
761 msg_perror("couldn't write to file %s", name);
762 written -= count;
763 *sizeleft -= count;
764 userec(datarec);
765 datarec = findrec();
766 }
767
768 count = write(fd, datarec->charptr, written);
769
770 if (count < 0) {
771 msg_perror("couldn't write to file %s", name);
772 } else if (count != written) {
773 msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name);
774 skip_file((long) (*sizeleft));
775 }
776
777 written -= count;
778 *sizeleft -= count;
779 userec(datarec);
780 }
781 free(sparsearray);
782 /* if (end_nulls) {
783 register int i;
784
785 printf("%d\n", (int) end_nulls);
786 for (i = 0; i < end_nulls; i++)
787 write(fd, "\000", 1);
788 }*/
789 userec(datarec);
790 }
791
792 /* Set back the utime and mode for all the extracted directories. */
793 void restore_saved_dir_info ()
794 {
795 time_t acc_upd_times[2];
796 struct saved_dir_info *tmp;
797
798 while (saved_dir_info_head != NULL)
799 {
800 /* fixme if f_gnudump should set ctime too, but how? */
801 if(f_gnudump)
802 acc_upd_times[0]=saved_dir_info_head -> atime;
803 else acc_upd_times[0] = now; /* Accessed now */
804 acc_upd_times[1] = saved_dir_info_head -> mtime; /* Mod'd */
805 if (utime(saved_dir_info_head -> path, acc_upd_times) < 0) {
806 msg_perror("couldn't change access and modification times of %s",
807 saved_dir_info_head -> path);
808 }
809 if ((!f_keep) || (saved_dir_info_head -> mode & (S_ISUID|S_ISGID|S_ISVTX)))
810 {
811 if (chmod(saved_dir_info_head -> path,
812 notumask & saved_dir_info_head -> mode) < 0) {
813 msg_perror("cannot change mode of file %s to %ld",
814 saved_dir_info_head -> path,
815 notumask & saved_dir_info_head -> mode);
816 }
817 }
818 saved_dir_info_head = saved_dir_info_head -> next;
819 }
820 }
This page took 0.073313 seconds and 5 git commands to generate.