Comment 10 for bug 120542

John A Meinel (jameinel) wrote :

I'm pretty sure there are duplicates out there, but this is still an important issue.
I haven't found a way on case-preserving but case-insensitive filesystems to find out the real filename. 'stat(foo)' doesn't give back any indication of the real filename.
On Windows, you could use the FindFiles api. Something like:
>>> import win32file
>>> win32file.FindFilesW('BZR')
[(32, <PyTime:1/16/2008 19:09:47>, <PyTime:8/12/2008 20:25:35>, <PyTime:8/12/2008 20:25:35>, 0L, 5418L, 0L, 0L, u'bzr', u'')]

*note that all the way down at the end is u'bzr' which is the win32 unicode filename for the file that matches 'BZR'.

I would guess that OS X would have a similar function, but someone would need to track it down.

At that point, I would just use a function like this to validate all user's input names. So when they do "bzr add foo" we just translate it to Foo. (Everything else added will be found using os.listdir(), which gives us the proper case for all files.)

So in 'bzrlib/mutabletree.py' in the 'smart_add' function:
# validate user file paths and convert all paths to tree
# relative : it's cheaper to make a tree relative path an abspath
# than to convert an abspath to tree relative.
for filepath in file_list:
    rf = _FastPath(self.relpath(filepath))

Just add another entry for:
filepath = osutils.proper_cased_path(filepath)

And then on win32 it uses FindFiles (either via ctypes or via pywin32) and on Mac it uses the appropriate function, and on Linux, it can just be a no-op function.