/* FIFO */ int tar_extract_fifo(TAR *t, char *realname) { mode_t mode; char *filename; if (!TH_ISFIFO(t)) { errno = EINVAL; return -1; } filename = (realname ? realname : th_get_pathname(t)); mode = th_get_mode(t); if (mkdirhier(dirname(filename)) == -1) return -1; #ifdef DEBUG printf(" ==> extracting: %s (fifo)\n", filename); #endif if (mkfifo(filename, mode) == -1) { #ifdef DEBUG perror("mkfifo()"); #endif return -1; } return 0; }
/* directory */ int tar_extract_dir(TAR *t, char *realname) { mode_t mode; char *filename; if (!TH_ISDIR(t)) { errno = EINVAL; return -1; } filename = (realname ? realname : th_get_pathname(t)); mode = th_get_mode(t); if (mkdirhier(dirname(filename)) == -1) return -1; #ifdef DEBUG printf(" ==> extracting: %s (mode %04o, directory)\n", filename, mode); #endif if (mkdir(filename, mode) == -1) { if (errno == EEXIST) { if (chmod(filename, mode) == -1) { #ifdef DEBUG perror("chmod()"); #endif return -1; } else { #ifdef DEBUG puts(" *** using existing directory"); #endif return 1; } } else { #ifdef DEBUG perror("mkdir()"); #endif return -1; } } return 0; }
int util_tar_extract(const char *tar_filename, const char* index_file, const char* out_dir) { TAR *tar = NULL; int ret = tar_open(&tar, tar_filename, &gztype, O_RDONLY, 0, TAR_GNU); if (ret != 0) { ERROR_ERRNO("Fail to open tarfile: %s\n", tar_filename); return ret; } //ret = tar_extract_all(tar, tar_prefix); while (th_read(tar) == 0) { char *archive_filename = th_get_pathname(tar); char *out_filename = mem_printf("%s/%s", out_dir, archive_filename); char *mode = mem_alloc0(4*sizeof(char)); int_to_oct(th_get_mode(tar), mode, 4*sizeof(char)); uid_t uid = th_get_uid(tar); gid_t gid = th_get_gid(tar); INFO("Writing file %s to %s", archive_filename, out_filename); if (TH_ISCHR(tar)) { // writing file attributes to index file (TODO use hashmap to handle duplicates) file_printf_append(index_file, "%s c %s %d %d %d %d\n", archive_filename, mode, uid, gid, th_get_devmajor(tar), th_get_devminor(tar)); } else if (TH_ISBLK(tar)) { // writing file attributes to index file (TODO use hashmap to handle duplicates) file_printf_append(index_file, "%s b %s %d %d %d %d\n", archive_filename, mode, uid, gid, th_get_devmajor(tar), th_get_devminor(tar)); } else { if (tar_extract_file(tar, out_filename) != 0) { INFO_ERRNO("Skipping file: %s", archive_filename); } else { // writing file attributes to index file (TODO use hashmap to handle duplicates) file_printf_append(index_file, "%s m %s %d %d\n", archive_filename, mode, uid, gid); } } mem_free(mode); mem_free(archive_filename); mem_free(out_filename); } ret |= tar_close(tar); return ret; }
/* block device */ int tar_extract_blockdev(TAR *t, char *realname) { mode_t mode; unsigned long devmaj, devmin; char *filename; if (!TH_ISBLK(t)) { errno = EINVAL; return -1; } filename = (realname ? realname : th_get_pathname(t)); mode = th_get_mode(t); devmaj = th_get_devmajor(t); devmin = th_get_devminor(t); if (mkdirhier(dirname(filename)) == -1) return -1; #ifdef DEBUG printf(" ==> extracting: %s (block device %ld,%ld)\n", filename, devmaj, devmin); #endif if (mknod(filename, mode | S_IFBLK, makedev(devmaj, devmin)) == -1) { #ifdef DEBUG perror("mknod()"); #endif return -1; } return 0; }
/* character device */ int tar_extract_chardev(TAR *t, char *realname) { mode_t mode; unsigned long devmaj, devmin; char *filename; if (!TH_ISCHR(t)) { errno = EINVAL; return -1; } filename = (realname ? realname : th_get_pathname(t)); mode = th_get_mode(t); devmaj = th_get_devmajor(t); devmin = th_get_devminor(t); if (mkdirhier(dirname(filename)) == -1) return -1; #ifdef DEBUG printf(" ==> extracting: %s (character device %ld,%ld)\n", filename, devmaj, devmin); #endif if (mknod(filename, mode | S_IFCHR, compat_makedev(devmaj, devmin)) == -1) { #ifdef DEBUG printf("mknod() failed, returning good anyway"); #endif return 0; } return 0; }
void th_print_long_ls(TAR *t) { char modestring[12]; struct passwd *pw; struct group *gr; uid_t uid; gid_t gid; char username[_POSIX_LOGIN_NAME_MAX]; char groupname[_POSIX_LOGIN_NAME_MAX]; time_t mtime; struct tm *mtm; #ifdef HAVE_STRFTIME char timebuf[18]; #else const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; #endif uid = th_get_uid(t); pw = getpwuid(uid); if (pw == NULL) snprintf(username, sizeof(username), "%d", uid); else strlcpy(username, pw->pw_name, sizeof(username)); gid = th_get_gid(t); gr = getgrgid(gid); if (gr == NULL) snprintf(groupname, sizeof(groupname), "%d", gid); else strlcpy(groupname, gr->gr_name, sizeof(groupname)); strmode(th_get_mode(t), modestring); printf("%.10s %-8.8s %-8.8s ", modestring, username, groupname); if (TH_ISCHR(t) || TH_ISBLK(t)) printf(" %3d, %3d ", th_get_devmajor(t), th_get_devminor(t)); else printf("%9ld ", (long)th_get_size(t)); mtime = th_get_mtime(t); mtm = localtime(&mtime); #ifdef HAVE_STRFTIME strftime(timebuf, sizeof(timebuf), "%h %e %H:%M %Y", mtm); printf("%s", timebuf); #else printf("%.3s %2d %2d:%02d %4d", months[mtm->tm_mon], mtm->tm_mday, mtm->tm_hour, mtm->tm_min, mtm->tm_year + 1900); #endif printf(" %s", th_get_pathname(t)); if (TH_ISSYM(t) || TH_ISLNK(t)) { if (TH_ISSYM(t)) printf(" -> "); else printf(" link to "); if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL) printf("%s", t->th_buf.gnu_longlink); else printf("%.100s", t->th_buf.linkname); } putchar('\n'); }
static int tar_set_file_perms(TAR *t, char *realname) { mode_t mode; uid_t uid; gid_t gid; struct utimbuf ut; char *filename; filename = (realname ? realname : th_get_pathname(t)); mode = th_get_mode(t); uid = th_get_uid(t); gid = th_get_gid(t); ut.modtime = ut.actime = th_get_mtime(t); /* change owner/group */ if (geteuid() == 0) #ifdef HAVE_LCHOWN if (lchown(filename, uid, gid) == -1) { # ifdef DEBUG fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n", filename, uid, gid, strerror(errno)); # endif #else /* ! HAVE_LCHOWN */ if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1) { # ifdef DEBUG fprintf(stderr, "chown(\"%s\", %d, %d): %s\n", filename, uid, gid, strerror(errno)); # endif #endif /* HAVE_LCHOWN */ return -1; } /* change access/modification time */ if (!TH_ISSYM(t) && utime(filename, &ut) == -1) { #ifdef DEBUG perror("utime()"); #endif return -1; } /* change permissions */ if (!TH_ISSYM(t) && chmod(filename, mode) == -1) { #ifdef DEBUG perror("chmod()"); #endif return -1; } return 0; } /* switchboard */ int tar_extract_file(TAR *t, char *realname) { int i; char *lnp; int pathname_len; int realname_len; if (t->options & TAR_NOOVERWRITE) { struct stat s; if (lstat(realname, &s) == 0 || errno != ENOENT) { errno = EEXIST; return -1; } } if (TH_ISDIR(t)) { i = tar_extract_dir(t, realname); if (i == 1) i = 0; } else if (TH_ISLNK(t)) i = tar_extract_hardlink(t, realname); else if (TH_ISSYM(t)) i = tar_extract_symlink(t, realname); else if (TH_ISCHR(t)) i = tar_extract_chardev(t, realname); else if (TH_ISBLK(t)) i = tar_extract_blockdev(t, realname); else if (TH_ISFIFO(t)) i = tar_extract_fifo(t, realname); else /* if (TH_ISREG(t)) */ i = tar_extract_regfile(t, realname); if (i != 0) return i; i = tar_set_file_perms(t, realname); if (i != 0) return i; pathname_len = strlen(th_get_pathname(t)) + 1; realname_len = strlen(realname) + 1; lnp = (char *)calloc(1, pathname_len + realname_len); if (lnp == NULL) return -1; strcpy(&lnp[0], th_get_pathname(t)); strcpy(&lnp[pathname_len], realname); #ifdef DEBUG printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", " "value=\"%s\"\n", th_get_pathname(t), realname); #endif if (libtar_hash_add(t->h, lnp) != 0) return -1; return 0; }
/* extract regular file */ int tar_extract_regfile(TAR *t, char *realname) { mode_t mode; size_t size; uid_t uid; gid_t gid; int fdout; int i, k; char buf[T_BLOCKSIZE]; char *filename; #ifdef DEBUG printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t, realname); #endif if (!TH_ISREG(t)) { errno = EINVAL; return -1; } filename = (realname ? realname : th_get_pathname(t)); mode = th_get_mode(t); size = th_get_size(t); uid = th_get_uid(t); gid = th_get_gid(t); if (mkdirhier(dirname(filename)) == -1) return -1; #ifdef DEBUG printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n", filename, mode, uid, gid, size); #endif fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC #ifdef O_BINARY | O_BINARY #endif , 0666); if (fdout == -1) { #ifdef DEBUG perror("open()"); #endif return -1; } #if 0 /* change the owner. (will only work if run as root) */ if (fchown(fdout, uid, gid) == -1 && errno != EPERM) { #ifdef DEBUG perror("fchown()"); #endif return -1; } /* make sure the mode isn't inheritted from a file we're overwriting */ if (fchmod(fdout, mode & 07777) == -1) { #ifdef DEBUG perror("fchmod()"); #endif return -1; } #endif /* extract the file */ for (i = size; i > 0; i -= T_BLOCKSIZE) { k = tar_block_read(t, buf); if (k != T_BLOCKSIZE) { if (k != -1) errno = EINVAL; return -1; } /* write block to output file */ if (write(fdout, buf, ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1) return -1; } /* close output file */ if (close(fdout) == -1) return -1; #ifdef DEBUG printf("### done extracting %s\n", filename); #endif return 0; }
static int tar_set_file_perms(TAR *t, char *realname) { mode_t mode; uid_t uid; gid_t gid; struct utimbuf ut; char *filename; filename = (realname ? realname : th_get_pathname(t)); mode = th_get_mode(t); uid = th_get_uid(t); gid = th_get_gid(t); ut.modtime = ut.actime = th_get_mtime(t); #ifdef DEBUG printf(" ==> setting perms: %s (mode %04o, uid %d, gid %d)\n", filename, mode, uid, gid); #endif /* change owner/group */ if (geteuid() == 0) #ifdef HAVE_LCHOWN if (lchown(filename, uid, gid) == -1) { # ifdef DEBUG fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n", filename, uid, gid, strerror(errno)); # endif #else /* ! HAVE_LCHOWN */ if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1) { # ifdef DEBUG fprintf(stderr, "chown(\"%s\", %d, %d): %s\n", filename, uid, gid, strerror(errno)); # endif #endif /* HAVE_LCHOWN */ return -1; } /* change access/modification time */ if (!TH_ISSYM(t) && utime(filename, &ut) == -1) { #ifdef DEBUG perror("utime()"); #endif return -1; } /* change permissions */ if (!TH_ISSYM(t) && chmod(filename, mode) == -1) { #ifdef DEBUG perror("chmod()"); #endif return -1; } return 0; } /* switchboard */ int tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd) { int i; char *lnp; int pathname_len; int realname_len; if (t->options & TAR_NOOVERWRITE) { struct stat s; if (lstat(realname, &s) == 0 || errno != ENOENT) { errno = EEXIST; return -1; } } if (TH_ISDIR(t)) { printf("dir\n"); i = tar_extract_dir(t, realname); if (i == 1) i = 0; } else if (TH_ISLNK(t)) { printf("link\n"); i = tar_extract_hardlink(t, realname, prefix); } else if (TH_ISSYM(t)) { printf("sym\n"); i = tar_extract_symlink(t, realname); } else if (TH_ISCHR(t)) { printf("chr\n"); i = tar_extract_chardev(t, realname); } else if (TH_ISBLK(t)) { printf("blk\n"); i = tar_extract_blockdev(t, realname); } else if (TH_ISFIFO(t)) { printf("fifo\n"); i = tar_extract_fifo(t, realname); } else /* if (TH_ISREG(t)) */ { printf("reg\n"); i = tar_extract_regfile(t, realname, progress_fd); } if (i != 0) { printf("FAILED RESTORE OF FILE i: %s\n", realname); return i; } i = tar_set_file_perms(t, realname); if (i != 0) { printf("FAILED SETTING PERMS: %d\n", i); return i; } #ifdef HAVE_SELINUX if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL) { #ifdef DEBUG printf(" Restoring SELinux context %s to file %s\n", t->th_buf.selinux_context, realname); #endif if (lsetfilecon(realname, t->th_buf.selinux_context) < 0) { fprintf(stderr, "Failed to restore SELinux context %s!\n", strerror(errno)); } } #endif /* pathname_len = strlen(th_get_pathname(t)) + 1; realname_len = strlen(realname) + 1; lnp = (char *)calloc(1, pathname_len + realname_len); if (lnp == NULL) return -1; strcpy(&lnp[0], th_get_pathname(t)); strcpy(&lnp[pathname_len], realname); #ifdef DEBUG printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", " "value=\"%s\"\n", th_get_pathname(t), realname); #endif if (libtar_hash_add(t->h, lnp) != 0) return -1; free(lnp); */ return 0; }