- if (dest_exists) {
- if (flags & FILEUTILS_INTERACTIVE) {
- fprintf(stderr, "%s: overwrite `%s'? ", bb_applet_name, dest);
- if (!bb_ask_confirmation()) {
- close (src_fd);
- return 0;
- }
- }
-
- dst_fd = open(dest, O_WRONLY|O_TRUNC);
- if (dst_fd == -1) {
- if (!(flags & FILEUTILS_FORCE)) {
- bb_perror_msg("unable to open `%s'", dest);
- close(src_fd);
- return -1;
- }
-
- if (unlink(dest) < 0) {
- bb_perror_msg("unable to remove `%s'", dest);
- close(src_fd);
- return -1;
- }
-
- goto dest_removed;
+ // 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;