1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
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
|