经过一番工作,我自己弄清楚了这一点。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);
. 文件名填充了空值,因此您可以进行检查以确保至少有一个空值,然后如果您想节省空间则不要使用该大小。
现在我们想知道它是文件还是文件夹。“链接指示器”字段包含此信息,因此:
// Note that we're comparing to ascii numbers, not ints
switch(buffer[156]){
case '0': // intentionally dropping through
case '\0':
// normal file
break;
case '1':
// hard link
break;
case '2':
// symbolic link
break;
case '3':
// device file/special file
break;
case '4':
// block device
break;
case '5':
// directory
break;
case '6':
// named pipe
break;
}
至此,我们已经拥有了有关目录所需的所有信息,但我们还需要普通文件中的另一件事:实际的文件内容。
文件的长度可以以两种不同的方式存储,或者作为 0 或空格填充的以空结尾的八进制字符串,或者“通过设置最左边字节的高位来指示的 base-256 编码的数字字段”。
数值使用 ASCII 数字以八进制数编码,前导零。由于历史原因,应使用最终的 NUL 或空格字符。因此,尽管为存储文件大小保留了 12 个字节,但只能存储 11 个八进制数字。这使归档文件的最大文件大小为 8 GB。为了克服这个限制,star 在 2001 年引入了 base-256 编码,通过设置数字字段最左边字节的高位来表示。GNU-tar 和 BSD-tar 遵循了这个想法。此外,1988 年第一个 POSIX 标准之前的 tar 版本用空格而不是零填充值。
以下是您阅读八进制格式的方法,但我还没有为 base-256 版本编写代码:
// in one function
int size_of_file = octal_string_to_int(&buffer[124], 11);
// elsewhere
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;
}
好的,现在我们有了除了实际文件内容之外的所有内容。我们所要做的就是size
从 tar 文件中获取下一个字节的数据,我们将拥有我们的文件内容:
// 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)