Ulf Lamping wrote:
>
>> Is there some reason why we don't simply check whether eth_stat()
>> returns
>> -1 or not? On UN*X, to test whether a file exists, you would probably
>> try
>> to stat it and, if the stat fails with ENOENT, say it doesn't exist,
>> otherwise (i.e., if it succeeds *or* if it fails and sets errno to
>> something other than ENOENT) say it does (even if we don't have
>> permission
>> to look for it).
>>
>> Would that work on Windows as well?
>>
> I can't remember the exact cause of the hack I've implemented here, but
> I remember that there *was* a real reason that the obvious solution
> didn't worked on WIN32.
At least one problem mentioned in the comments for files_identical() is,
apparently, that "st_ino" isn't guaranteed to be a number that's the same
for identical files and different for different files on Windows (unlike
UN*X, where if you don't do that, even on file systems where it's hard,
you break applications).
The FAT file system doesn't have a notion of an inode number, so I guess
they don't bother providing an st_ino on FAT file systems, and always
leave it as zero. (UN*X systems' FAT implementations tend to synthesize
an inode number, based on, for example, the starting cluster number of the
file, although that doesn't work for empty files. That doesn't guarantee
that the inode number is invariant - truncating and rewriting the file
could change it - but it at least lets you use st_dev and st_ino for
non-empty files.)
The code in files_identical() on UN*X used to set the two st_ino fields to
different values, do unchecked stat() (or eth_stat()) calls, and then
compare the st_ino fields; the fields were set to different values to
handle the case where the stat calls failed. We now just return FALSE if
either one fails, and compare st_dev and st_ino if they both succeed.
The code in file_exists() has a comment that says
/*
* This is a bit tricky on win32. The st_ino field is documented as:
* "The inode, and therefore st_ino, has no meaning in the FAT, ..."
* but it *is* set to zero if stat() returns without an error,
* so this is working, but maybe not quite the way expected. ULFL
*/
but, at least on UN*X, checking whether a file exists doesn't involve
checking st_ino, it involves checking whether stat() fails with ENOENT or
not. As such, I'm not sure why the st_ino issue matters for
file_exists(), even on Windows - it matters for files_identical() (and is
worked around by not even using stat() or eth_stat()), but file_exists()
should just be able to work the same way on Windows and UN*X, i.e. if
eth_stat() fails and errno is ENOENT, the file doesn't exist, otherwise
either it does exist or we don't have permission to check whether it does
exist (perhaps "file_exists()" should return "exists", "doesn't exist", or
"unable to check").