gpt4 book ai didi

c - 尽管多次成功写入,但 Write() 仍导致 EBADF 失败

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

希望大家指出我明显的错误;

系统是嵌入式linux,代码是c语言

我们在cgi脚本中有一些代码,它接受来自(Boa)网络服务器的STDIN_FILENO数据流(文件上传)并将其写入临时文件(“/tmp/file.txt”)。

下面的代码是一个非常简化的代码片段,但基本上显示了事物的顺序:

  1. 打开临时文件 fd 进行写入
  2. 从 STDIN 获取 N 个字节
  3. 将 N 个字节写入临时文件
  4. 起泡沫,冲洗,重复,直到不再有字节(或错误)

预期的文件是一个二进制文件,大约 20Mb,但写入总是在大约 1.4Mb 时失败,并出现 errno 9 (EBADF),这表明文件描述符已以某种方式关闭。

有足够的磁盘空间,并且 Web 服务器不会限制 POST 文件大小或截断数据。

代码:

char buffer[1024];
mode_t fd_mode=S_IRWXU;
if ((targ_fd = open("/tmp/file.txt", O_WRONLY | O_CREAT, fd_mode)) == -1)
{
OUTPUT("Error opening file\n");
return FAIL;
}

while(total < maxlen)
{
count = read(STDIN_FILENO, buffer, 1024);
if(count > 0)
{
if(write(targ_fd, buffer, count) < 0)
{
perror("Failed to write to file");
close(targ_fd);
return FAIL;
}
total += count;
}
else
{
return FAIL;
// Or success if EOF, code omitted for clarity
}
}

对于较小的文件(但大到足以需要多次写入),它可以完美地工作。

非常感谢任何想法!

编辑添加:更新代码,以及:

我们确实捕获了 read() 返回 0,但为了清楚起见我省略了它。程序是单线程的,在最初从第一个 read() 数据中修剪 MIME header 后,它只是将其读入缓冲区,然后将缓冲区写入临时文件,直到达到 maxlen 或输入结束。

附加说明:写入最初会成功,创建一个包含正确内容的文件,直到失败时的大小。

通过进一步测试进行更新:以下有用的评论/建议:

  • count 是一个 int,符号性没有问题。

  • 我忘记检查 write() 的返回值,失败前的最后一个 write() 未能写入请求的全部字节数。更改 open() 以添加标志 O_SYNC 没有任何区别。

  • 我添加了 fstat() 并在 open() 和失败时进行调试打印:

代码:

printf("File type:                ");
switch (filestat.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}

printf("I-node number: %ld\n", (long) filestat.st_ino);
printf("Mode: %lo (octal)\n",
(unsigned long) filestat.st_mode);
printf("Link count: %ld\n", (long) filestat.st_nlink);
printf("Ownership: UID=%ld GID=%ld\n",
(long) filestat.st_uid, (long) filestat.st_gid);
printf("Preferred I/O block size: %ld bytes\n",
(long) filestat.st_blksize);
printf("File size: %lld bytes\n",
(long long) filestat.st_size);
printf("Blocks allocated: %lld\n",
(long long) filestat.st_blocks);
printf("Last status change: %s", ctime(&filestat.st_ctime));
printf("Last file access: %s", ctime(&filestat.st_atime));
printf("Last file modification: %s", ctime(&filestat.st_mtime));

打开时的结果是:

Fd = 5
File type: regular file
I-node number: 486
Mode: 100600 (octal)
Link count: 1
Ownership: UID=0 GID=0
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Thu Jan 1 00:00:51 1970
Last file access: Thu Jan 1 00:00:51 1970
Last file modification: Thu Jan 1 00:00:51 1970

错误结果:

Fd = 5
Failed to write to the pipe (errno = 9), managed 273 / 4096 bytes
File type: regular file
I-node number: 486
Mode: 100600 (octal)
Link count: 1
Ownership: UID=0 GID=0
Preferred I/O block size: 4096 bytes
File size: 1499136 bytes
Blocks allocated: 2944
Last status change: Thu Jan 1 00:00:51 1970
Last file access: Thu Jan 1 00:00:51 1970
Last file modification: Thu Jan 1 00:00:51 1970

是的,系统时钟未设置。

更多信息:失败后:

root@IPNC:~# df -i /tmp
Filesystem Inodes Used Available Use% Mounted on
none 5664 7 5657 0% /tmp
root@IPNC:~# df /tmp
Filesystem 1K-blocks Used Available Use% Mounted on
none 25600 1508 24092 6% /tmp

根据要求提供更多信息:

正在进行的 MIME 修剪只是跳过第一个到达的数据,直到数据之前的“\r\n\r\n”,因此第一次写入开始从缓冲区的中途读取。我已经检查过,这是从正确的点开始并在正确的点结束,并且使用较小的测试文件(~50k),整个文件都被正确接收和写入,没有错误、重载或欠载。

进一步测试的结果:

嗯,还没解决。故障点随着不同的输入数据(文件大小和类型)而移动,但似乎不会绊倒任何特定的模式或数据(例如:一个文件在一大块 0xFF 的中间发生故障)。

我尝试过使用 fcntl() 来锁定 fd,使用 dup() 并处理新的 fd,以防另一个 fd 以某种方式从外部关闭,两者都没有任何区别。

我将尝试插入虚拟数据,看看是否可以成功写入 filesize 字节的虚拟数据。

**终于接近尾声了...**

看起来 Boa 以一种奇怪的方式处理 HTTP POST 请求,将它们写入临时文件,并将其复制到 objective-c GI 脚本的 STDIN。如果/tmp 中有足够的空间容纳两个副本,那就没问题,但没有(我们是嵌入的)。仍然存在一些奇怪的地方:它创建的文件永远不会出现在文件列表中,并且写入失败并不表示“空间不足”。肯定会发生一些奇怪的事情,但现在我认为这并不完全是 write() 的失败,而是父代码中的一些更大的问题。

最佳答案

好吧,我想我应该关闭这个......

答案有点复杂。

最初我说“我们有足够的磁盘空间”,我们确实这么做了,直到 Boa 决定将整个 POST 数据(约 20Mb)缓冲在/tmp 文件夹中(总可用空间约 25Mb),这使得写入将数据文件写入/tmp 非常棘手,并解释了为什么 write() 文件越小(大约 25Mb 减去文件大小)就越失败,大概如果文件​​是 12.5Mb,它就会成功。

无论如何,奇怪的返回代码(EBADF)而不是任何类型的空间不足指示使鹅追逐变得更加疯狂。

令人失望的结果是我们必须制定其他方案将文件直接上传到设备,无论是通过其他方式(tftp、wget)还是使用上传页面中的脚本来拆分文件分成 block 并一次上传一个 block 。

关于c - 尽管多次成功写入,但 Write() 仍导致 EBADF 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25722339/

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