jjazzboss
jjazzboss

Reputation: 1422

cygwin cp can't copy file "abc" because destination dir. contains file "abc.exe"

I'm under Win10/x64 using cygwin64 bash.

I have a problem copying a simple directory (../bin below) which only contains 2 files, a Win10 executable and the corresponding executable for Linux (same file name with no extension).

$ ls  ../bin
abc  abc.exe*

$ cp -rf ../bin .
cp: cannot create regular file './bin/abc': File exists

$ ls bin
abc.exe*

Why the file abc is not copied !?

If I rename abc.exe to abcd.exe in ../bin, then it works and the 2 files are copied.

How to tell bash/cp to not consider abc and abc.exe as the same file ? I tried various cp options (-f, -p, -H) it does not solve the problem.

Thanks.

Upvotes: 2

Views: 943

Answers (1)

Graeme
Graeme

Reputation: 3041

This issue is to do with the special way in which Cygwin handles .exe files. If you have a file in your current directory say, test.exe, Cygwin has always allowed it to be executed by running ./test without the .exe extension.

It does this inside its implementation of certain system calls which take a file name by checking if a file with the same name, but with the .exe extension exists, then operating on that instead. From a post on the Cygwin mailing list:

Cygwin always handled the .exe suffix transparently in terms of stat(2) calls, but Cygwin 1.7 also handles them transparently in terms of open(2) and any other call. Therefore, if a file foo.exe exists, and an application calls stat("foo"), it will get told that, yes, "foo" exists. That's a basic component of being able to call foo.exe from bash by just typing foo. POSIX systems just don't have the .exe suffix for executables.

However, this creates an issue where if a file already exists with the .exe extension, problems will arise if you try to create a file of the same name in the same directory without an extension.

Seemingly (as per the mailing list post), this usually occurs when extracting a tar file. In the case of the OP, it occurred when using the cp -r command to copy from a different directory where the files were created by a Windows IDE.

The workaround is to always create the file without the extension first, the create the .exe file. For this, instead of using cp -r it is possible to use the pax utility to copy non .exe files first. From within the source directory, do:

find . \! -name '*.exe' -print0 | pax -0drw dest_dir
find . -name '*.exe' -print0 | pax -0drw dest_dir

Note that the Cygwin find command does not support using + with -exec (which otherwise would be used for the preferred way to do this). Alternatively GNU cpio can be used:

find . \! -name '*.exe' -print0 | cpio -p --null dest_dir
find . -name '*.exe' -print0 | cpio -p --null dest_dir

Upvotes: 3

Related Questions