Subject: Re: [PATCH v2] Allow git mv FileA fILEa on case ignore file systems

From: Torsten Bögershausen <[email-masked]>
Date: Mon, 11 Apr 2011 22:05:54 +0200

On 04/11/2011 06:55 PM, Junio C Hamano wrote:
> Torsten Bögershausen<[email-masked]>  writes:
>
>>> When two different _names_ "A" and "a" refer to a single file, the only
>>> thing that should happen for "git mv A a" is for the cache entry for "A"
>>> to be moved to cache entry for "a", and no rename("A", "a") should be run,
>>> but I don't see any such change in the code. It may happen to work (or be
>>> a no-op) on Windows, but because builtin/mv.c is supposed to be generic
>>> (and that is the reason you introduced the is_same_file() abstraction in
>>> the first place), I'd still see this as a breakage.
>>>
>> Why shouldn't the rename() be done?
>> "git mv A B" changes both the indes and the file system.
>> Isn't it natural to have file name  "a" both in the index and in the
>> file system after "git mv A a"?
>> Note: Windows and MAC OS X allow "mv A a" from command line,
>> while Linux on VFAT gives an error "'A' and 'a' are the same file".
> Yeah, I forgot about the primary thing we are trying to do in this
> discussion.  Sorry about that.  My thinking stopped at 'if we rename "A"
> to "a in the index, that is sufficient.  We already know that we can still
> open("A") because the filesystem is case insensitive.'
>
> In fact, we want both the index entry "A" renamed to "a" _and_ also we
> want to see next "/bin/ls" to show "a", not "A".  For the latter, we do
> want to run rename(2) on them.
>
> There was another thing that made me worry about running rename(2) on two
> equivalent filenames.  You said on Linux VFAT "mv A a" fails.  Does the
> underlying rename(2) fail when you do this?
>
> 	status = rename("A", "a");
>
> If old and new resolve to the same existing directory entry or different
> directory entries for the same existing file, POSIX says that rename(old,
> new) should succeed and perform no other action, so the above should
> succeed on correctly implemented case insensitive filesystems.
>
> But we know not all FS implementations are perfect.  If this can result in
> an unnecessary failure, it would be far better if we are careful to avoid
> running rename("A", "a") and just rename the index entry to make sure "git
> mv A a" succeeds, than trying to fulfil the "we want to see next '/bin/ls'
> to show 'a' not 'A'" wish and make the whole "git mv A a" fail.
>
> But of course we can always blame the breakage on filesystems.  I am
> leaning to prefer running rename("A", "a") unconditionally.
>
> Thanks.
Thanks for reading and for the reply.

>You said on Linux VFAT "mv A a" fails

My excuses for being unclear, as "fails" often means returning -1 and 
setting errno.
But this is not the case here. I should have said:
rename("A", "a") returns 0 but does not rename the file.

Here comes the  long version. I wrote a short program called "rename",  
and run some tests.
The /D is a VFAT partition, mounted writable for root only.
-----------------------------------
tb@wanderer:/D/test> ls
A  B  x
tb@wanderer:/D/test> rename A A
rename A A res=0 Success
tb@wanderer:/D/test> ls
A  B  x
tb@wanderer:/D/test> rename A a
rename A a res=0 Success
tb@wanderer:/D/test> ls
A  B  x
tb@wanderer:/D/test> rename A D
rename A D res=-1 Permission denied
tb@wanderer:/D/test>
------------------------------------

I had a short look into the Linux kernel. A comment in namei_vfat.c 
indicates that
rename "filename" "FILENAME" is not supported for now.
(and all respect and thanks from my side to the people who made VFAT 
working).
(and of course to the git people)