gpt4 book ai didi

用 C 创建我自己的归档工具

转载 作者:行者123 更新时间:2023-11-30 20:05:42 26 4
gpt4 key购买 nike

我刚刚被分配了一个项目来为 UNIX 创建归档工具。所以在创建程序后我会做类似的事情

"./bar -c test_archive.bar file.1"

它将创建一个 test_archive.bar,其中包含 file.1。然后我可以做一些命令,列出里面的文件等等。但是我很难理解制作 test_archive.bar 的概念,我意识到本质上它只是一个文件,但如果你说打开一个.tgz "vi file.tgz"它会给出里面的目录/文件列表,

那么,有没有什么好的方法可以创建一个存档/目录,在其中我可以推断其中的一些文件并列出它们的名称等。

注意:我已经查看了 tar.c 以及其中包含的所有文件,但每个文件都非常抽象,很难理解。

注意:我知道如何读取命令行标志等。

最佳答案

使用旧的(但仍然有效)tar 格式实际上很容易做到。 Wikipedia has a nice explanation of the format here.您需要做的就是:

对于每个文件:

  • 填写 header 并将其发送到 tar 文件
  • 发出文件内容
  • 将文件大小填充为 512 字节的倍数

tar 文件最基本的有效 header 是:(基本上是从维基百科复制的)

  • 100 字节:文件名
  • 8字节:文件模式
  • 8 字节:所有者的数字 ID
  • 8 字节:组的数字 ID
  • 12 字节:文件大小
  • 12字节:上次修改时间的时间戳
  • 8字节:校验和
  • 1字节:文件类型
  • 100 字节:链接文件的名称

文件类型可以是 0(普通文件)、1(硬链接(hard link))或 2(符号链接(symbolic link))。链接文件的名称是链接指向的文件的名称。如果我没记错的话,如果您有硬链接(hard link)或符号链接(symbolic link),则文件内容应该为空。

引用维基百科:

“数值使用 ASCII 数字以八进制编码,并带有前导零。由于历史原因,应使用最终的 NUL 或空格字符。”

“校验和是通过取头记录的无符号字节值之和来计算的,其中八个校验和字节取为ascii空格(十进制值32)。它存储为六位八进制数,后跟前导零由一个 NUL 和一个空格组成。”

这是一个简单的 tarball 生成器。创建提取器、处理自动文件馈送等,留给读者作为练习。

#include<stdio.h>
#include<string.h>


struct tar_header{
char name[100];
char mode[8];
char owner[8];
char group[8];
char size[12];
char modified[12];
char checksum[8];
char type[1];
char link[100];
char padding[255];
};

void fexpand(FILE* f, size_t amount, int value){
while( amount-- ){
fputc( value, f );
}
}

void tar_add(FILE* tar_file, const char* file, const char* internal_name){
//Get current position; round to a multiple of 512 if we aren't there already
size_t index = ftell( tar_file );
size_t offset = index % 512;
if( offset != 0 ){
fexpand( tar_file, 512 - offset, 0);
}
//Store the index for the header to return to later
index = ftell( tar_file );
//Write some space for our header
fexpand( tar_file, sizeof(struct tar_header), 0 );
//Write the input file to the tar file
FILE* input = fopen( file, "rb" );
if( input == NULL ){
fprintf( stderr, "Failed to open %s for reading\n", file);
return;
}
//Copy the file content to the tar file
while( !feof(input) ){
char buffer[2000];
size_t read = fread( buffer, 1, 2000, input );
fwrite( buffer, 1, read, tar_file);
}
//Get the end to calculate the size of the file
size_t end = ftell( tar_file );
//Round the file size to a multiple of 512 bytes
offset = end % 512;
if( end != 0 ){
fexpand( tar_file, 512 - offset, 0);
}
//Fill out a new tar header
struct tar_header header;
memset( &header, 0, sizeof( struct tar_header ) );
snprintf( header.name, 100, "%s", internal_name );
snprintf( header.mode, 8, "%06o ", 0777 ); //You should probably query the input file for this info
snprintf( header.owner, 8, "%06o ", 0 ); //^
snprintf( header.group, 8, "%06o ", 0 ); //^
snprintf( header.size, 12, "%011o", end - 512 - index );
snprintf( header.modified, 12, "%011o ", time(0) ); //Again, get this from the filesystem
memset( header.checksum, ' ', 8);
header.type[0] = '0';

//Calculate the checksum
size_t checksum = 0;
int i;
const unsigned char* bytes = &header;
for( i = 0; i < sizeof( struct tar_header ); ++i ){
checksum += bytes[i];
}

snprintf( header.checksum, 8, "%06o ", checksum );

//Save the new end to return to after writing the header
end = ftell(tar_file);

//Write the header
fseek( tar_file, index, SEEK_SET );
fwrite( bytes, 1, sizeof( struct tar_header ), tar_file );

//Return to the end
fseek( tar_file, end, SEEK_SET );
fclose( input );
}

int main( int argc, char* argv[] ){
if( argc > 1 ){
FILE* tar = fopen( argv[1], "wb" );
if( !tar ){
fprintf( stderr, "Failed to open %s for writing\n", argv[1] );
return 1;
}
int i;
for( i = 2; i < argc; ++i ){
tar_add( tar, argv[i], argv[i] );
}
//Pad out the end of the tar file
fexpand( tar, 1024, 0);
fclose( tar );
return 0;
}
fprintf( stderr, "Please specify some file names!\n" );
return 0;
}

关于用 C 创建我自己的归档工具,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29641965/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com