36357e7123ee9f18c4ad6ac5befd5e25ef2d69cc
2 ** Copyright 1998-2003 University of Illinois Board of Trustees
3 ** Copyright 1998-2003 Mark D. Roth
4 ** All rights reserved.
6 ** extract.c - libtar code to extract a file from a tar archive
8 ** Mark D. Roth <roth@uiuc.edu>
9 ** Campus Information Technologies and Educational Services
10 ** University of Illinois at Urbana-Champaign
17 #include <sys/param.h>
18 #include <sys/types.h>
33 tar_set_file_perms(TAR
*t
, char *realname
)
41 filename
= (realname
? realname
: th_get_pathname(t
));
42 mode
= th_get_mode(t
);
45 ut
.modtime
= ut
.actime
= th_get_mtime(t
);
47 /* change owner/group */
50 if (lchown(filename
, uid
, gid
) == -1)
53 fprintf(stderr
, "lchown(\"%s\", %d, %d): %s\n",
54 filename
, uid
, gid
, strerror(errno
));
56 #else /* ! HAVE_LCHOWN */
57 if (!TH_ISSYM(t
) && chown(filename
, uid
, gid
) == -1)
60 fprintf(stderr
, "chown(\"%s\", %d, %d): %s\n",
61 filename
, uid
, gid
, strerror(errno
));
63 #endif /* HAVE_LCHOWN */
67 /* change access/modification time */
68 if (!TH_ISSYM(t
) && utime(filename
, &ut
) == -1)
76 /* change permissions */
77 if (!TH_ISSYM(t
) && chmod(filename
, mode
) == -1)
91 tar_extract_file(TAR
*t
, char *realname
)
98 if (t
->options
& TAR_NOOVERWRITE
)
102 if (lstat(realname
, &s
) == 0 || errno
!= ENOENT
)
111 i
= tar_extract_dir(t
, realname
);
115 else if (TH_ISLNK(t
))
116 i
= tar_extract_hardlink(t
, realname
);
117 else if (TH_ISSYM(t
))
118 i
= tar_extract_symlink(t
, realname
);
119 else if (TH_ISCHR(t
))
120 i
= tar_extract_chardev(t
, realname
);
121 else if (TH_ISBLK(t
))
122 i
= tar_extract_blockdev(t
, realname
);
123 else if (TH_ISFIFO(t
))
124 i
= tar_extract_fifo(t
, realname
);
125 else /* if (TH_ISREG(t)) */
126 i
= tar_extract_regfile(t
, realname
);
131 i
= tar_set_file_perms(t
, realname
);
135 pathname_len
= strlen(th_get_pathname(t
)) + 1;
136 realname_len
= strlen(realname
) + 1;
137 lnp
= (char *)calloc(1, pathname_len
+ realname_len
);
140 strcpy(&lnp
[0], th_get_pathname(t
));
141 strcpy(&lnp
[pathname_len
], realname
);
143 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
144 "value=\"%s\"\n", th_get_pathname(t
), realname
);
146 if (libtar_hash_add(t
->h
, lnp
) != 0)
153 /* extract regular file */
155 tar_extract_regfile(TAR
*t
, char *realname
)
163 char buf
[T_BLOCKSIZE
];
167 printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t
,
177 filename
= (realname
? realname
: th_get_pathname(t
));
178 mode
= th_get_mode(t
);
179 size
= th_get_size(t
);
183 if (mkdirhier(dirname(filename
)) == -1)
187 printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n",
188 filename
, mode
, uid
, gid
, size
);
190 fdout
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
204 /* change the owner. (will only work if run as root) */
205 if (fchown(fdout
, uid
, gid
) == -1 && errno
!= EPERM
)
213 /* make sure the mode isn't inheritted from a file we're overwriting */
214 if (fchmod(fdout
, mode
& 07777) == -1)
223 /* extract the file */
224 for (i
= size
; i
> 0; i
-= T_BLOCKSIZE
)
226 k
= tar_block_read(t
, buf
);
227 if (k
!= T_BLOCKSIZE
)
234 /* write block to output file */
235 if (write(fdout
, buf
,
236 ((i
> T_BLOCKSIZE
) ? T_BLOCKSIZE
: i
)) == -1)
240 /* close output file */
241 if (close(fdout
) == -1)
245 printf("### done extracting %s\n", filename
);
254 tar_skip_regfile(TAR
*t
)
258 char buf
[T_BLOCKSIZE
];
266 size
= th_get_size(t
);
267 for (i
= size
; i
> 0; i
-= T_BLOCKSIZE
)
269 k
= tar_block_read(t
, buf
);
270 if (k
!= T_BLOCKSIZE
)
284 tar_extract_hardlink(TAR
* t
, char *realname
)
287 char *linktgt
= NULL
;
297 filename
= (realname
? realname
: th_get_pathname(t
));
298 if (mkdirhier(dirname(filename
)) == -1)
300 libtar_hashptr_reset(&hp
);
301 if (libtar_hash_getkey(t
->h
, &hp
, th_get_linkname(t
),
302 (libtar_matchfunc_t
)libtar_str_match
) != 0)
304 lnp
= (char *)libtar_hashptr_data(&hp
);
305 linktgt
= &lnp
[strlen(lnp
) + 1];
308 linktgt
= th_get_linkname(t
);
311 printf(" ==> extracting: %s (link to %s)\n", filename
, linktgt
);
313 if (link(linktgt
, filename
) == -1)
327 tar_extract_symlink(TAR
*t
, char *realname
)
337 filename
= (realname
? realname
: th_get_pathname(t
));
338 if (mkdirhier(dirname(filename
)) == -1)
341 if (unlink(filename
) == -1 && errno
!= ENOENT
)
345 printf(" ==> extracting: %s (symlink to %s)\n",
346 filename
, th_get_linkname(t
));
348 if (symlink(th_get_linkname(t
), filename
) == -1)
360 /* character device */
362 tar_extract_chardev(TAR
*t
, char *realname
)
365 unsigned long devmaj
, devmin
;
374 filename
= (realname
? realname
: th_get_pathname(t
));
375 mode
= th_get_mode(t
);
376 devmaj
= th_get_devmajor(t
);
377 devmin
= th_get_devminor(t
);
379 if (mkdirhier(dirname(filename
)) == -1)
383 printf(" ==> extracting: %s (character device %ld,%ld)\n",
384 filename
, devmaj
, devmin
);
386 if (mknod(filename
, mode
| S_IFCHR
,
387 compat_makedev(devmaj
, devmin
)) == -1)
401 tar_extract_blockdev(TAR
*t
, char *realname
)
404 unsigned long devmaj
, devmin
;
413 filename
= (realname
? realname
: th_get_pathname(t
));
414 mode
= th_get_mode(t
);
415 devmaj
= th_get_devmajor(t
);
416 devmin
= th_get_devminor(t
);
418 if (mkdirhier(dirname(filename
)) == -1)
422 printf(" ==> extracting: %s (block device %ld,%ld)\n",
423 filename
, devmaj
, devmin
);
425 if (mknod(filename
, mode
| S_IFBLK
,
426 compat_makedev(devmaj
, devmin
)) == -1)
440 tar_extract_dir(TAR
*t
, char *realname
)
451 filename
= (realname
? realname
: th_get_pathname(t
));
452 mode
= th_get_mode(t
);
454 if (mkdirhier(dirname(filename
)) == -1)
458 printf(" ==> extracting: %s (mode %04o, directory)\n", filename
,
461 if (mkdir(filename
, mode
) == -1)
465 if (chmod(filename
, mode
) == -1)
475 puts(" *** using existing directory");
495 tar_extract_fifo(TAR
*t
, char *realname
)
506 filename
= (realname
? realname
: th_get_pathname(t
));
507 mode
= th_get_mode(t
);
509 if (mkdirhier(dirname(filename
)) == -1)
513 printf(" ==> extracting: %s (fifo)\n", filename
);
515 if (mkfifo(filename
, mode
) == -1)