/* hardlink */ int tar_extract_hardlink(TAR * t, char *realname, char *prefix) { char *filename; char *linktgt = NULL; char *lnp; libtar_hashptr_t hp; if (!TH_ISLNK(t)) { errno = EINVAL; return -1; } filename = (realname ? realname : th_get_pathname(t)); if (mkdirhier(dirname(filename)) == -1) return -1; libtar_hashptr_reset(&hp); if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t), (libtar_matchfunc_t)libtar_str_match) != 0) { lnp = (char *)libtar_hashptr_data(&hp); linktgt = &lnp[strlen(lnp) + 1]; } else linktgt = th_get_linkname(t); char *newtgt = strdup(linktgt); sprintf(linktgt, "%s/%s", prefix, newtgt); #ifdef DEBUG printf(" ==> extracting: %s (link to %s)\n", filename, linktgt); #endif if (link(linktgt, filename) == -1) { #ifdef DEBUG perror("link()"); #endif printf("Failed restore of hardlink '%s' but returning as if nothing bad happened anyway\n", filename); return 0; // Used to be -1 } return 0; }
/* hardlink */ int tar_extract_hardlink(TAR * t, char *realname) { char *filename; char *linktgt = NULL; char *lnp; libtar_hashptr_t hp; if (!TH_ISLNK(t)) { errno = EINVAL; return -1; } filename = (realname ? realname : th_get_pathname(t)); if (mkdirhier(dirname(filename)) == -1) return -1; libtar_hashptr_reset(&hp); if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t), (libtar_matchfunc_t)libtar_str_match) != 0) { lnp = (char *)libtar_hashptr_data(&hp); linktgt = &lnp[strlen(lnp) + 1]; } else linktgt = th_get_linkname(t); #ifdef DEBUG printf(" ==> extracting: %s (link to %s)\n", filename, linktgt); #endif if (link(linktgt, filename) == -1) { #ifdef DEBUG perror("link()"); #endif 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; }