/
tar.h
151 lines (122 loc) · 3.89 KB
/
tar.h
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
140
141
142
143
144
145
146
147
148
149
150
// by elliot kroo (http://elliot.kroo.net/)
// thanks!
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#define UNTAR_BUFFER_SIZE 512
#define UNTAR_DEBUG 0
static long long int untar_numBytes = 0;
typedef struct struct_FileHeader {
char filename[100];
char mode[8];
char owner[8];
char group[8];
char filesize[12];
char lastmodified[12];
char checksum[8];
char linkindicator;
char linkedfile[100];
char padding[255];
} FileHeader;
int isNull(FileHeader *header) {
long long int *iheader = (long long int *)header;
int i;
for(i=0; i<sizeof(FileHeader) / sizeof(long long int); i++) {
if(iheader[i] != 0) {
return 0;
}
}
return 1;
}
void untar_create_link_(char * fullpath, char * linkpath, int filesize, FILE* fp){
int result = symlink(linkpath, fullpath);
if(result != 0) {
fprintf(stderr, "Could not create symlink %s (%d)\n", fullpath, result);
perror("having trouble creating symlink");
return;
}
}
void untar_create_directory_(char * fullpath, mode_t mode, int filesize, FILE* fp){
int result = mkdir(fullpath, mode);
if(result != 0) {
if(!errno == EEXIST)
fprintf(stderr, "Could not create directory %s (%d)\n", fullpath, result);
perror("having trouble creating directory");
return;
}
}
void untar_create_file_(char * fullpath, mode_t mode, int filesize, FILE*fp){
FILE *out = fopen(fullpath, "wb+");
if(!out) {
fprintf(stderr, "Could not create file %s\n", fullpath);
perror("having trouble creating file");
}
char buffer[UNTAR_BUFFER_SIZE]; // read until we run out of filled blocks
while (filesize / UNTAR_BUFFER_SIZE != 0) {
fread(buffer, 1, UNTAR_BUFFER_SIZE, fp);
untar_numBytes += UNTAR_BUFFER_SIZE;
if(out)
fwrite(buffer, 1, UNTAR_BUFFER_SIZE, out);
filesize -= UNTAR_BUFFER_SIZE;
}
if(filesize > 0) {
// now read in and write the last block...
fread(buffer, 1, UNTAR_BUFFER_SIZE, fp);
untar_numBytes += UNTAR_BUFFER_SIZE;
if(out)
fwrite(buffer, 1, filesize, out);
}
if(out) fclose(out);
chmod(fullpath, mode);
}
void untar(char *filename, char *basepath) {
FILE *fp = fopen(filename, "r");
int consecutive_zero_fields = 0;
untar_numBytes = 0;
if(fp) {
for(;;) {
FileHeader header;
fread(&header, 1, sizeof(FileHeader), fp);
untar_numBytes += sizeof(FileHeader);
if(feof(fp)) /* if at end of file */
break; /* we are done */
if(isNull(&header)) {
consecutive_zero_fields++;
continue;
}
if(UNTAR_DEBUG)
printf("type: %c\t filename: %s\tmode: %s \towner: %s\tgroup: %s\tfilesize: %s\tlastmodified: %s\tchecksum: %s\tlinkedfile: %s\n",
header.linkindicator, header.filename, header.mode, header.owner, header.group, header.filesize, header.lastmodified,
header.checksum, header.linkedfile);
// build the full path
char fullpath[strlen(basepath)+strlen(header.filename)+1];
strcpy(fullpath, basepath);
strcpy(fullpath+strlen(basepath), header.filename);
// build the full linkpath
char linkpath[strlen(basepath)+strlen(header.linkedfile)+1];
strcpy(linkpath, basepath);
strcpy(linkpath+strlen(basepath), header.linkedfile);
mode_t mode = strtoul(header.mode, 0, 8);
long int filesize = strtoul(header.filesize, 0, 8);
switch(header.linkindicator) {
case '0':
untar_create_file_(fullpath, mode, filesize, fp);
break;
case '2':
untar_create_link_(fullpath, header.linkedfile, filesize, fp);
break;
case '5':
untar_create_directory_(fullpath, mode, filesize, fp);
break;
default:
fprintf(stderr, "Unsupported file type %c; skipping.\n", header.linkindicator);
}
}
}
fprintf(stderr, "finished!");
}