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; }
/* appends a file to the tar archive */ int tar_append_file(TAR *t, char *realname, char *savename) { struct stat s; int i; libtar_hashptr_t hp; tar_dev_t *td = NULL; tar_ino_t *ti = NULL; char path[MAXPATHLEN]; #ifdef DEBUG printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", " "savename=\"%s\")\n", t, t->pathname, realname, (savename ? savename : "[NULL]")); #endif if (lstat(realname, &s) != 0) { #ifdef DEBUG perror("lstat()"); #endif return -1; } /* set header block */ #ifdef DEBUG puts(" tar_append_file(): setting header block..."); #endif memset(&(t->th_buf), 0, sizeof(struct tar_header)); th_set_from_stat(t, &s); /* set the header path */ #ifdef DEBUG puts(" tar_append_file(): setting header path..."); #endif th_set_path(t, (savename ? savename : realname)); #ifdef HAVE_SELINUX /* get selinux context */ if(t->options & TAR_STORE_SELINUX) { if(t->th_buf.selinux_context != NULL) { free(t->th_buf.selinux_context); t->th_buf.selinux_context = NULL; } security_context_t selinux_context = NULL; if (lgetfilecon(realname, &selinux_context) >= 0) { t->th_buf.selinux_context = strdup(selinux_context); printf("setting selinux context: %s\n", selinux_context); freecon(selinux_context); } else perror("Failed to get selinux context"); } #endif /* check if it's a hardlink */ #ifdef DEBUG puts(" tar_append_file(): checking inode cache for hardlink..."); #endif libtar_hashptr_reset(&hp); if (libtar_hash_getkey(t->h, &hp, &(s.st_dev), (libtar_matchfunc_t)dev_match) != 0) td = (tar_dev_t *)libtar_hashptr_data(&hp); else { #ifdef DEBUG printf("+++ adding hash for device (0x%lx, 0x%lx)...\n", major(s.st_dev), minor(s.st_dev)); #endif td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t)); td->td_dev = s.st_dev; td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash); if (td->td_h == NULL) return -1; if (libtar_hash_add(t->h, td) == -1) return -1; } libtar_hashptr_reset(&hp); if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino), (libtar_matchfunc_t)ino_match) != 0) { ti = (tar_ino_t *)libtar_hashptr_data(&hp); #ifdef DEBUG printf(" tar_append_file(): encoding hard link \"%s\" " "to \"%s\"...\n", realname, ti->ti_name); #endif t->th_buf.typeflag = LNKTYPE; th_set_link(t, ti->ti_name); } else { #ifdef DEBUG printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld " "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev), s.st_ino, realname); #endif ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t)); if (ti == NULL) return -1; ti->ti_ino = s.st_ino; snprintf(ti->ti_name, sizeof(ti->ti_name), "%s", savename ? savename : realname); libtar_hash_add(td->td_h, ti); } /* check if it's a symlink */ if (TH_ISSYM(t)) { i = readlink(realname, path, sizeof(path)); if (i == -1) return -1; if (i >= MAXPATHLEN) i = MAXPATHLEN - 1; path[i] = '\0'; #ifdef DEBUG printf(" tar_append_file(): encoding symlink \"%s\" -> " "\"%s\"...\n", realname, path); #endif th_set_link(t, path); } /* print file info */ if (t->options & TAR_VERBOSE) th_print_long_ls(t); #ifdef DEBUG puts(" tar_append_file(): writing header"); #endif /* write header */ if (th_write(t) != 0) { #ifdef DEBUG printf("t->fd = %d\n", t->fd); #endif return -1; } #ifdef DEBUG puts(" tar_append_file(): back from th_write()"); #endif /* if it's a regular file, write the contents as well */ if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0) return -1; return 0; }
int main(int argc, char **argv) { struct eub eub; struct eubfile file; int opt_P = 0; TAR *tarp; char buf[512]; libtar_hash_t *lthash = NULL; eub_init(&eub); ARGBEGIN { case 'P' : opt_P = 1; break; default : usage(); } ARGEND; if (argc == 0) usage(); if (eub_open(&eub, argv[0], "r")) return(eub.err); if (argc > 1) { lthash = libtar_hash_new(3, (libtar_hashfunc_t) hash_path); while (--argc) libtar_hash_add(lthash, ++argv); } if (tar_fdopen(&tarp, 1, "/dev/stdout", NULL, O_WRONLY, 0600, TAR_GNU) != 0) return(eub_err(&eub, errno, "Can't start tar output")); while (eub_read_meta(&eub, &file)) { unsigned long long len, remlen; struct libtar_node lp = { file.path, 0, 0 }; libtar_hashptr_t hp; hp.bucket = -1; hp.node = NULL; /* if (lthash && !libtar_hash_search(lthash, &hp, &lp, (libtar_matchfunc_t) compare_paths)) */ if (lthash && !libtar_hash_getkey(lthash, &hp, &lp, (libtar_matchfunc_t) compare_paths)) continue; if (eub_meta_to_stat(&eub, &file)) return(eub.err); th_set_from_stat(tarp, &file.stat); th_set_path(tarp, file.path); if (file.typechar == 'f') { /* XXX Hack! len = strlen(tarp->th_buf.name); if (tarp->th_buf.name[len-1] == '/') tarp->th_buf.name[len-1] = 0; */ if (eub_read_dataref(&eub, &file)) return(eub.err); } else if (file.typechar == 'l') { if (eub_read_dataref(&eub, &file)) return(eub.err); if (eub_seek_data(&eub, &file)) return(eub.err); if (eub_read_data(&eub, &file, eub.linkbuf, file.size)) return(eub_err(&eub, errno, "Can't read link: %s", file.path)); eub.linkbuf[file.size] = 0; th_set_link(tarp, eub.linkbuf); } th_finish(tarp); if (th_write(tarp)) return(eub_err(&eub, errno, "Can't write tar header for %s", file.path)); fflush(stdout); if (file.typechar == 'f') { if (eub_seek_data(&eub, &file)) return(eub.err); for (remlen = file.size; remlen; remlen -= len) { len = remlen < sizeof(buf) ? remlen : sizeof(buf); if (eub_read_data(&eub, &file, buf, len)) return(eub_err(&eub, errno, "Can't read file contents: %s", file.path)); if (len < sizeof(buf)) bzero(buf+len, sizeof(buf)-len); if (!tar_block_write(tarp, buf)) return(eub_err(&eub, errno, "Can't write to tar: %s", file.path)); fflush(stdout); } if (eub.err) return(eub.err); } } if (tar_append_eof(tarp)) return(eub_err(&eub, errno, "Can't finish tar")); fflush(stdout); return(eub.err); }