tar: support GNU Tar's L type

This commit is contained in:
K. Lange 2020-03-29 14:35:56 +09:00
parent dd2a323fe8
commit b85263b698

View File

@ -101,6 +101,7 @@ static unsigned int interpret_size(struct ustar * file) {
} }
static const char * type_to_string(char type) { static const char * type_to_string(char type) {
static char unknown[100];
switch (type) { switch (type) {
case '\0': case '\0':
case '0': case '0':
@ -122,7 +123,8 @@ static const char * type_to_string(char type) {
case 'x': case 'x':
return "Extended preheader"; return "Extended preheader";
default: default:
return "Unknown"; sprintf(unknown, "Uknown: %c", type);
return unknown;
} }
} }
@ -218,6 +220,9 @@ int main(int argc, char * argv[]) {
size_t length = ftell(f); size_t length = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
char tmpname[1024] = {0};
int last_was_long = 0;
size_t off = 0; size_t off = 0;
while (!feof(f)) { while (!feof(f)) {
struct ustar * file = file_from_offset(f, off); struct ustar * file = file_from_offset(f, off);
@ -231,9 +236,14 @@ int main(int argc, char * argv[]) {
} }
if (action == TAR_ACTION_EXTRACT) { if (action == TAR_ACTION_EXTRACT) {
char name[256] = {0}; char name[1024] = {0};
strncat(name, file->prefix, 155); if (last_was_long) {
strncat(name, file->filename, 100); strncat(name, tmpname, 1023);
last_was_long = 0;
} else {
strncat(name, file->prefix, 155);
strncat(name, file->filename, 100);
}
if (file->type[0] == '0' || file->type[0] == 0) { if (file->type[0] == '0' || file->type[0] == 0) {
FILE * mf = fopen(name,"w"); FILE * mf = fopen(name,"w");
@ -275,6 +285,14 @@ int main(int argc, char * argv[]) {
if (symlink(tmp, name) < 0) { if (symlink(tmp, name) < 0) {
fprintf(stderr, "%s: %s: %s: %s: %s\n", argv[0], fname, name, tmp, strerror(errno)); fprintf(stderr, "%s: %s: %s: %s: %s\n", argv[0], fname, name, tmp, strerror(errno));
} }
} else if (file->type[0] == 'L') {
/* This is a GNU Long Name block; store its contents as a file name */
size_t s = interpret_size(file);
fseek(f, off + 512, SEEK_SET);
fread(tmpname, 1, s, f);
tmpname[s] = '\0';
fseek(f, off, SEEK_SET);
last_was_long = 1;
} else { } else {
fprintf(stderr, "%s: %s: %s: %s\n", argv[0], fname, name, type_to_string(file->type[0])); fprintf(stderr, "%s: %s: %s: %s\n", argv[0], fname, name, type_to_string(file->type[0]));
} }