[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'
But
$ 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
A
$ cat c/a
2
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
here:
http://cygwin.com/ml/cygwin-developers/2007-08/msg00030.html
--
Eric Blake