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