- return FALSE;
- }
- } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
- || S_ISSOCK(srcStatBuf.st_mode)) {
- //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
- if (mknod(dst_name, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) {
- if (!quiet_flag) {
- perror_msg("%s", dst_name);
+ // TODO: probably is_in_.. and add_to_...
+ // can be combined: find_or_add_...
+ add_to_ino_dev_hashtable(&source_stat, dest);
+ }
+
+ src_fd = open(source, O_RDONLY);
+ if (src_fd == -1) {
+ bb_perror_msg("cannot open '%s'", source);
+ return -1;
+ }
+
+ // POSIX: if exists and -i, ask (w/o -i assume yes).
+ // Then open w/o EXCL.
+ // If open still fails and -f, try unlink, then try open again.
+ // Result: a mess:
+ // If dest is a softlink, we overwrite softlink's destination!
+ // (or fail, if it points to dir/nonexistent location/etc).
+ // This is strange, but POSIX-correct.
+ // coreutils cp has --remove-destination to override this...
+ dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE)
+ ? O_WRONLY|O_CREAT|O_TRUNC|O_EXCL
+ : O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode);
+ if (dst_fd == -1) {
+ // We would not do POSIX insanity. -i asks,
+ // then _unlinks_ the offender. Presto.
+ // Or else we will end up having 3 open()s!
+ ovr = retry_overwrite(dest, flags);
+ if (ovr <= 0) {
+ close(src_fd);
+ return ovr;