You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
4.0 KiB
140 lines
4.0 KiB
From 6654d41a14da2fc521e889f01669f0dbb89aef15 Mon Sep 17 00:00:00 2001
|
|
From: Zac Medico <zmedico@gentoo.org>
|
|
Date: Tue, 5 Oct 2021 23:21:53 -0700
|
|
Subject: [PATCH] Symlink support
|
|
|
|
Bug: https://bugs.gentoo.org/815823
|
|
Signed-off-by: Zac Medico <zmedico@gentoo.org>
|
|
---
|
|
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
|
|
|