我正在编写一个从标准 UNIX 存档 ar 中提取并创建它存储的文件的 C 程序。
以下是我在 vim 中打开 ar 的示例:
!<arch>
yo 1382105439 501 20 100644 10 `
test1 lol
yo2 1382105444 501 20 100644 10 `
test2 lol
...其中 "test1 lol" 和 "test2 lol" 是每个文件的内容,"yo" 和 "yo2" 是两个不同的文件名,其余的是以与标准 ar.h 对应的格式存储的元数据(在这里阅读更多信息:http: //www.lehman.cuny.edu/cgi-bin/man-cgi?ar.h+ 3 )
无论如何,我仍在编写函数,但这是我目前所拥有的:
static void extract_files (int argc, char *argv[])
{
int fd;
int new_file_fd;
int num_read = 0;
int new_file_size;
struct ar_hdr current_header;
char name_buffer[16];
char date_buffer[12];
char uid_buffer[6];
char gid_buffer[6];
char mode_buffer[8];
char size_buffer[10];
char fmag_buffer[2];
// grab the fd #
fd = open(argv[2], O_RDWR | O_CREAT, 0666);
// go to the first header
lseek(fd, SARMAG, SEEK_CUR);
// store the number of bits read in a struct current_header
// until its size equal to the size of the entire
// header, or in other words, until the entire
// header is read
while ((num_read = read(fd, (char*) ¤t_header,
sizeof(struct ar_hdr))) == sizeof(struct ar_hdr))
{
// scans the current string in header and stores
// in nameStr array
sscanf(current_header.ar_name, "%s", name_buffer);
sscanf(current_header.ar_date, "%s", date_buffer);
sscanf(current_header.ar_uid, "%s", uid_buffer);
sscanf(current_header.ar_gid, "%s", gid_buffer);
int mode;
sscanf(current_header.ar_mode, "%o", &mode);
sscanf(current_header.ar_size, "%s", size_buffer);
int size = atoi(size_buffer);
sscanf(current_header.ar_fmag, "%s", fmag_buffer);
// Create a new file
new_file_fd = creat(name_buffer, mode);
// Grab new file size
new_file_size = atoi(size_buffer);
int io_size; // buffer size
char buff[size];
int read_cntr = 0;
// from copy.c
while ((io_size = read (fd, buff, new_file_size)) > 0)
{
read_cntr++;
if (read_cntr > new_file_size)
break;
write (new_file_fd, buff, new_file_size);
}
close(new_file_fd);
printf("%s\n", name_buffer);
printf("%s\n", date_buffer);
printf("%s\n", uid_buffer);
printf("%s\n", gid_buffer);
printf("%s\n", mode_buffer);
printf("%s\n", size_buffer);
printf("%s\n", fmag_buffer);
/* Seek to next header. */
lseek(fd, atoi(current_header.ar_size) + (atoi(current_header.ar_size)%2), SEEK_CUR);
}
}
我遇到的问题在于上述代码中的第二个 while 循环:
// from copy.c
while ((io_size = read (fd, buff, new_file_size)) > 0)
{
read_cntr++;
if (read_cntr > new_file_size)
break;
write (new_file_fd, buff, new_file_size);
}
由于某种原因,在此 while 循环中写入的文件不会运行到 write 指定的长度。标准 read()/write() 的第三个参数应该是要写入的字节数。但由于某种原因,我的代码导致整个档案被读入并写入第一个文件。
如果我打开生成的“yo”文件,我发现整个存档文件已写入其中
test1 lol
yo2 1382105444 501 20 100644 10 `
test2 lol
而不是在读取 10 个字节并给出预期结果“test1 lol”后终止。
我还可以确认“new_file_size”值确实是 10。所以我的问题是:关于这个 while 循环,我读错了什么?
注意:预期的输入将是一个类似于以下内容的命令行参数:./extractor.c -x name_of_archive_file
我认为我需要在此函数中处理的唯一相关信息是存档文件的名称,我在 extract_files 的开头获取 fd。
补充:杂项——运行时的输出:
yo
1382105439
501
20
X
10
`
如您所见,它永远不会看到 yo2 文件或打印出它的标题,因为它会在此之前被写入“yo”......因为这个流浪的 while 循环:(