我经过一番努力,自己搞清楚了这个问题。
tar文件规范 实际上告诉你所需的一切信息。
首先,每个文件都以512字节的头文件开头,因此您可以使用char[512]或指向较大char数组中某个位置的char*来表示它(例如,如果您将整个文件加载到一个数组中)。
头文件如下:
location size field
0 100 File name
100 8 File mode
108 8 Owner's numeric user ID
116 8 Group's numeric user ID
124 12 File size in bytes
136 12 Last modification time in numeric Unix time format
148 8 Checksum for header block
156 1 Link indicator (file type)
157 100 Name of linked file
如果您想获取文件名,可以使用 string filename(buffer[0], 100);
来获取。文件名是用空格填充的,因此您可以检查是否至少有一个空格,如果要节省空间,则可以省略大小。
现在我们要知道它是文件还是文件夹。"链接指示符"字段包含了这些信息,所以:
switch(buffer[156]){
case '0':
case '\0':
break;
case '1':
break;
case '2':
break;
case '3':
break;
case '4':
break;
case '5':
break;
case '6':
break;
}
此时,我们已经获取了有关目录的所有信息,但是我们还需要从普通文件中获得一个东西:实际的文件内容。
文件长度可以以两种不同的方式存储,一种是作为一个0或空格填充的空终止八进制字符串,另一种是“通过设置数值字段最左边字节的高位比特来表示的基256编码”。
使用ASCII数字将数值编码为八进制数,前导零。由于历史原因,应该使用最后的NUL或空格字符。因此,虽然有12个字节用于存储文件大小,但只能存储11个八进制数字。这给归档文件的最大文件大小为8 GB。为了克服这个限制,2001年星号引入了一种基256编码,它通过设置数值字段最左边字节的高位比特来表示。GNU-tar和BSD-tar遵循了这个想法。此外,在1988年第一个POSIX标准之前的tar版本中,使用空格而不是零填充值。
以下是如何读取八进制格式的方法,但我还没有为基256版本编写代码:
int size_of_file = octal_string_to_int(&buffer[124], 11);
int octal_string_to_int(char *current_char, unsigned int size){
unsigned int output = 0;
while(size > 0){
output = output * 8 + *current_char - '0';
current_char++;
size--;
}
return output;
}
好的,现在我们已经拥有了除实际文件内容之外的所有内容。我们所要做的就是从tar文件中获取下一个size
字节的数据,然后我们就可以得到我们的文件内容:
// Get to the next block after the header ends
location += 512;
file_contents = new char[size];
memcpy(file_contents, &buffer[location], size);
// Go to the next block by rounding up to 512
// This isn't necessarily the most efficient way to do this,
// but it's the most obvious.
location += (int)ceil(size / 512.0)