From 6654d41a14da2fc521e889f01669f0dbb89aef15 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Tue, 5 Oct 2021 23:21:53 -0700 Subject: [PATCH] Symlink support Bug: https://bugs.gentoo.org/815823 Signed-off-by: Zac Medico --- main.c | 37 +++++++++++++++++++++++++++++++++++-- tar.c | 16 ++++++++++++++-- tar.h | 2 ++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/main.c b/main.c index 2c2da3e..448a9d0 100644 --- a/main.c +++ b/main.c @@ -257,7 +257,14 @@ main(int argc, char **argv) // no need to seek. cfile handles resetting streams as needed for(x=0; x < missing_count; x++) { - if(copy_whole_file(&tar_cfh, missing[x]) != 0) { + if (missing[x]->type == SYMTYPE) { + if(copy_symlink(&tar_cfh, missing[x]) != 0) { + v0printf("failed transfering symlink %s\n", missing[x]->fullname); + exit(9); + } + continue; + } + else if(copy_whole_file(&tar_cfh, missing[x]) != 0) { v0printf("failed transfering file %s\n", missing[x]->fullname); exit(9); } @@ -673,6 +680,8 @@ int check_existing_node(const struct dirent *de, const tar_entry *t, struct stat *st) { int type; + unsigned char linkname[TAR_LINKNAME_LEN]; + ssize_t linkname_len; type = convert_lstat_type_tar_type(de->d_name, st); if(type < 0) return -1; @@ -682,6 +691,15 @@ check_existing_node(const struct dirent *de, const tar_entry *t, struct stat *st return 2; if(REGTYPE == type && (st->st_size != t->size || (check_mtime && t->mtime != st->st_mtime))) return 3; + if (SYMTYPE == type) { + if ((linkname_len = readlink(de->d_name, linkname, TAR_LINKNAME_LEN)) == -1) { + return -1; + } + if(strncmp((const char *)linkname, (const char *)t->linkname, linkname_len) != 0) { + remove_node(de->d_name, st); + return 3; + } + } return 0; } @@ -703,7 +721,22 @@ enforce_owner(const char *path, const tar_entry *t, struct stat *st) } return 0; } - + +int +copy_symlink(cfile *tar_cfh, const tar_entry *ttent) +{ + v1printf("creating %s\n", ttent->fullname); + + if (symlink(ttent->linkname, ttent->fullname) != 0) { + v0printf("failed creating symlink %s -> %s\n", ttent->fullname, ttent->linkname); + return -1; + } + if(lchown(ttent->fullname, ttent->uid, ttent->gid) != 0) { + v0printf("failed chown'ing %s\n", ttent->fullname); + return -1; + } + return 0; +} int copy_whole_file(cfile *tar_cfh, const tar_entry *ttent) diff --git a/tar.c b/tar.c index 42dc8e7..514e5fb 100644 --- a/tar.c +++ b/tar.c @@ -214,8 +214,7 @@ read_entry(cfile *src_cfh, off_u64 start, tar_entry *entry) case AREGTYPE: entry->type = REGTYPE; break; case SYMTYPE: - v0printf("symlinks not supported\n"); - entry->type = TTAR_UNSUPPORTED_TYPE; break; + entry->type = SYMTYPE; break; case LNKTYPE: v0printf("hardlinks not supported!\n"); entry->type = TTAR_UNSUPPORTED_TYPE; break; @@ -242,6 +241,17 @@ read_entry(cfile *src_cfh, off_u64 start, tar_entry *entry) if(get_uid(block + TAR_UNAME_LOC, &entry->uid)) entry->uid = octal_str2long(block + TAR_UID_LOC, TAR_UID_LOC); + if (entry->type == SYMTYPE) { + name_len = strnlen((char *)block + TAR_LINKNAME_LOC, TAR_LINKNAME_LEN); + if((entry->linkname = (char *)malloc(name_len + 1)) == NULL){ + v0printf("unable to allocate needed memory, bailing\n"); + return MEM_ERROR; + } + memcpy(entry->linkname, block + TAR_LINKNAME_LOC, name_len); + entry->linkname[name_len] = '\0'; + entry->linkname_len = name_len; + } + // if(entry->end % 512) // entry->end += 512 - (entry->end % 512); return 0; @@ -256,6 +266,8 @@ convert_lstat_type_tar_type(const char *path, struct stat *st) if(S_ISREG(st->st_mode)) { if(st->st_nlink == 1) return REGTYPE; + } else if(S_ISLNK(st->st_mode)) { + return SYMTYPE; } else if(S_ISDIR(st->st_mode)) return DIRTYPE; diff --git a/tar.h b/tar.h index e9d9ee9..95f957c 100644 --- a/tar.h +++ b/tar.h @@ -78,6 +78,8 @@ typedef struct { off_u64 size; unsigned int fullname_len; char *fullname; + unsigned int linkname_len; + char *linkname; time_t mtime; uid_t uid; gid_t gid; -- 2.32.0