[英]mmap invalid argument - reading multiple files from command line and writing to one output file
我正在编写一个 C 程序,它从命令行获取多个文件并将它们组合成一个 output 文件。 如果没有给出 output 文件,则创建它。 我使用 mmap 复制文件内容。
但是,当我运行以下代码时,我得到“mmap:无效参数”,我不知道为什么。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char *argv[])
{
int opt, output=0, len;
int fd_o, fd_i;
char *addr=NULL;
struct stat stat_input;
const char *errmsg="Invalid argument:\n";
const char *usage=
"combine to one\n";
while((opt = getopt(argc, argv, "o"))!= -1) {
switch(opt){
case 'o':
output=1;
fd_o=open(argv[argc-1], O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd_o == -1){
perror("open");
exit(1);
}
break;
case '?':
write(2, errmsg, strlen(errmsg));
write(2, usage, strlen(usage));
exit(1);
}
}
if (output==0){
write(2, errmsg, strlen(errmsg));
write(2, usage, strlen(usage));
exit(1);
}
for(; optind < argc; optind++){
fd_i=open(argv[optind], O_RDONLY);
if (fd_i == -1){
perror("open");
exit(1);
}
fstat(fd_i, &stat_input);
len=stat_input.st_size;
addr=mmap(0, len, PROT_READ, MAP_SHARED, fd_i, 0);
if (addr == MAP_FAILED) {
close(fd_i);
perror("mmap");
exit(1);
}
write(fd_o, *addr, len);
close(fd_i);
munmap(addr,len);
}
close(fd_o);
}
我认为问题实际上是您的选项解析。 就目前而言,如果完全指定了-o
,则始终使用最后一个参数作为 output 文件。 因此,如果您运行./myprog f1 f2 -o out
,则所有f1, f2, out
都将用作输入文件。 如果你运行./myprog -o out f1 f2
那么 all of out, f1, f2
将是输入, output 将 go 到f2
。
我想您没想到会使用 output 文件作为输入,如果它是空的,您将尝试创建长度为 0 的 map,这将失败并显示“无效参数”。 我的猜测是这是你的问题的原因。
使用getopt
处理带有参数的选项的正确方法是使用"o:"
作为选项字符串,然后当getopt
返回'o'
时,变量optarg
将指向选项的参数; 这就是您应该用作 output 文件名而不是argv[argc-1]
的文件名。
其他几个错误:
write(fd_o, *addr, len);
应该是write(fd_o, addr, len);
因为write
需要一个指向其数据的指针。 你应该得到一个关于这个的编译器警告。
您需要在调用mmap
之前测试len != 0
,以防有人真的在空输入文件上运行程序。
我不确定您为什么将write()
用于使用消息,而不仅仅是fprintf(stderr, ...)
。 如果由于某种原因 stdio 函数不可接受(即使您在其他地方似乎对perror()
没有问题),那么标准的 function dprintf
可能会让您的生活更轻松一些。
从手册页mmap()
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
EINVAL(无效参数错误)的可能原因:
1) We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary).
2) (since Linux 2.6.12) length was 0.
3) flags contained none of MAP_PRIVATE, MAP_SHARED or MAP_SHARED_VALIDATE.
我认为len
in len = stat_input.st_size;
为零。 这可能是原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.