[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: mv can't change filename case on case-insensitive file systems

From: Eric Blake
Subject: Re: mv can't change filename case on case-insensitive file systems
Date: Fri, 17 Aug 2007 17:09:04 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Jonathan Lennox <lennox <at> cs.columbia.edu> writes:

> On Cygwin using non-managed mounts (and presumably other operating systems
> when using a case-insensitive file system), it's not possible to use
> Coreutils mv to change the case of a filename; mv reports that they are the
> same file.

There is another case-insensitive file system issue that I hope we can clean up 
in the process, which affects both mv and cp:

$ mkdir a b c
$ touch a/a b/a
$ cp -vR a/* b/* c
`a/a' -> `c/a'
cp: will not overwrite just-created `c/a' with `b/a'


$ mkdir a b c
$ echo 1 > a/A
$ echo 2 > b/a
$ cp -vR a/* b/* c
`a/A' -> `c/A'
`b/a' -> `c/a'
$ ls c
$ cat c/a

Oops - we got the spelling of a/A but the contents of b/a (the result is 
corrupted), because we did not detect the clash in the case-insensitive 
filenames.  And had we used 'mv -v' instead of 'cp -vR', the result is the 
silent loss of data, which is contrary to the goal of mv.

Maybe a first step is teaching same_name in gnulib's same.c about case-
insensitive directories.  But it would sure be a lot easier if there were a 
reliable way to tell if a directory entry of a different case in a case-
insensitive directory already exists (or, put another way, it would be nice if 
something like realpath could be used to fess up to the canonical case spelling 
of a directory entry but without dereferencing the final symlink; 
canonicalize_filename_mode(CAN_ALL_BUT_LAST) doesn't cut it as currently 
implemented).  Even something like pathconf(dir, _PC_CASE_INSENSITIVE) would be 
useful, but again, that is not standardized.

Lacking an efficient standardized API, checks for case-insensitivity are only 
needed when stricmp() succeeds when strcmp() fails (actually, I'm not sure 
whether choice of locale can affect case-insensitive equality of filenames?).  
So a first-order approximation is doing a stricmp()/strcmp() filter, and when 
that shows a possible clash, use stat() on both spellings and declare that the 
directory is case-insensitive if the inodes match and the link count is 1.  But 
that still doesn't solve the ambiguity when foo and Foo have the same inode, 
but link count > 1, because we still can't tell if foo and Foo are case-
sensitive hard links to each other or if foo is a hardlink to bar and Foo is a 
case-insensitive reference to foo.  At this point, about the only way I can see 
to portably resolve that ambiguity is with a readdir() search.  You can see 
where this is headed - it is adding a LOT of overhead into checking for the 
corner-case of case-insensitivity, where such overhead is unnecessary if you 
comply with POSIX and have no case-insensitive file systems in the first place.

Maybe now is the time to start lobbying for cygwin, Mac, and Linux to agree on 
a way to efficiently identify case-insensitive directories?

On the other hand, since gnulib doesn't mind platform-specific code inside 
generic APIs, I could easily prepare a gnulib patch for same_name() that 
answers the question correctly for cygwin (it won't help for Mac or Linux, or 
any other system that has a way to mount FAT, HFS, or NTFS systems case-
insensitively, but support for additional systems can be added to gnulib as 
solutions are encountered).  Christian Franke proposed an idea for such a patch 


Eric Blake

reply via email to

[Prev in Thread] Current Thread [Next in Thread]