如何修复Windows下C文件复制程序的"copy: Bad file descriptor"错误?
mycp Program Let's walk through the issues in your code that are causing that frustrating error, plus fix other bits to meet your original requirements:
1. Operator Precedence Bug (Main Cause of the Error)
This is the root of your "Bad file descriptor" problem. Look at this line in your source file loop:
if (fds = _open(argv[i], _O_RDONLY) < 0)
The < operator has higher precedence than =, so this actually evaluates to:
fds = (_open(...) < 0)
That means fds gets assigned a boolean value (0 or 1) instead of the valid file descriptor from _open. When you try to read from this invalid descriptor, the error is thrown.
Fix: Wrap the assignment in parentheses to force the correct order:
if ((fds = _open(argv[i], _O_RDONLY)) < 0)
2. Reversed Parameters in copy_file Call
Your copy_file function expects the destination file descriptor first, then the source:
int copy_file(int fdd, int fds) { // fdd = destination, fds = source while ((n = read(fds, buf, BUFSIZE)) > 0) { _write(fdd, buf, n); } }
But in your loop, you're passing the source first and destination second:
if (copy_file(fds, fdd) < 0)
This swaps your read/write targets, which would cause errors even if the descriptor was valid.
Fix: Swap the parameters in the call:
if (copy_file(fdd, fds) < 0)
3. Loop Starts at the Wrong Index
Your original loop starts at i=0, which points to argv[0]—the program's own executable (mycp.exe). You didn't intend to copy the executable itself, so this is a wasteful (and potentially confusing) mistake.
Fix: Start the loop at i=1, since source files begin at argv[1]:
for (i = 1; i < dest_idx; ++i) // dest_idx = argc - 1 (destination file index)
4. Incorrect Handling of Missing Source Files
Your requirement says if a source file doesn't exist, the program should print a warning and continue—not exit. Right now, any failed _open triggers an immediate exit.
Fix: Check the errno value when _open fails. If it's ENOENT (file not found), print a warning and skip to the next file. For other errors, exit as intended:
if ((fds = _open(argv[i], _O_RDONLY)) < 0) { if (errno == ENOENT) { fprintf(stderr, "Warning: File %s does not exist, skipping.\n", argv[i]); continue; } else { remove_dest_file(fdd, argv, dest_idx); exit_sys("open source file"); } }
5. Minor Polish & Robustness
- Check
_writereturn value: Yourcopy_filefunction didn't verify if writes succeeded. Add a check to catch write failures:while ((n = read(fds, buf, BUFSIZE)) > 0) { if (_write(fdd, buf, n) != n) { return -1; // Indicate write failure } } - Fix typo:
printf("Succes");→printf("Success!\n"); - Clarify usage message: Update the error message to reflect correct syntax more clearly.
Fixed Full Code
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #define BUFSIZE 1024 void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } void exit_fail(const char* msg) { fprintf(stderr, "%s\n", msg); exit(EXIT_FAILURE); } void remove_dest_file(int fd, char** argv, int dest_idx) { _close(fd); unlink(argv[dest_idx]); } int copy_file(int fdd, int fds) { char buf[BUFSIZE]; int n; while ((n = read(fds, buf, BUFSIZE)) > 0) { if (_write(fdd, buf, n) != n) { return -1; } } return n < 0 ? -1 : 0; } int main(int argc, char** argv) { int fds, fdd; int ch; int flags; int dest_idx; int i; flags = _O_WRONLY | _O_CREAT; if (argc < 3) { exit_fail("usage: mycp.exe source1.txt [source2.txt ...] dest.txt"); } dest_idx = argc - 1; if (!access(argv[dest_idx], F_OK)) { printf("The file %s exists. Do you want to overwrite? [y/N]\n", argv[dest_idx]); ch = getchar(); if (ch == 'y' || ch == 'Y') { flags |= _O_TRUNC; } else { exit(EXIT_SUCCESS); } } if ((fdd = _open(argv[dest_idx], flags, _S_IREAD | _S_IWRITE)) < 0) { exit_sys("open destination file"); } for (i = 1; i < dest_idx; ++i) { if ((fds = _open(argv[i], _O_RDONLY)) < 0) { if (errno == ENOENT) { fprintf(stderr, "Warning: File %s not found, skipping.\n", argv[i]); continue; } else { remove_dest_file(fdd, argv, dest_idx); exit_sys("open source file"); } } if (copy_file(fdd, fds) < 0) { remove_dest_file(fdd, argv, dest_idx); exit_sys("copy file"); } _close(fds); } printf("Success!\n"); _close(fdd); return 0; }
内容的提问来源于stack exchange,提问作者user13575644

