Date: Sat, 24 Aug 2019 22:50:55 +0100
>> Sure. Using LLFIO:
>>
>> bool path_equality(path_view a, path_view b)
>> {
>> expected<file_handle, file_io_error> a = catch(file({}, a, :mode::none));
>> expected<file_handle, file_io_error> b = catch(file({}, b, :mode::none));
>> return a.has_value() && b.has_value() && a->unique_id() == b->unique_id();
>> }
>>
>> This is the only feasible, and correct, way of performing filesystem
>> path equality comparison. This is what we ought to do.
>
> Are you opening files and comparing something conceptually similar to
> inodes or global OS thing?
Yes, you open the files, but with no permissions, so it's fast as the OS
doesn't need to allocate resources to do i/o. You then read the unique
identifier of that inode on that system.
This obviously would return true for any hardlink or symbolic link or
combination thereof which led to the same inode. If you want to compare
equality of paths referring only the same hard link, you would:
bool path_equality(path_view a, path_view b)
{
file_handle a = file({}, a, :mode::none);
file_handle b = file({}, b, :mode::none);
return a.unique_id() == b.unique_id() && a.current_path() ==
b.current_path();
}
current_path() asks the kernel for a path uniquely identifying the hard
link originally opened. It can be extremely different to the path
opened, especially on Windows, as we only ever return NT kernel paths,
not DOS paths.
(Interestingly there is no one-one mapping between NT kernel paths and
DOS paths, so turning a NT kernel path into a DOS path is fundamentally
stochastic. Yay. So LLFIO doesn't bother trying)
Anyway the point that I am making here is that the kernel and filesystem
are black boxes. Unknowable. There is no point attempting to replicate
an unknowable black box in C++. Far better to simply ask the black box
to do the path comparison for you, it and only it knows what paths are
equal, and which are not. And that's leaving aside that the filesystem
is fundamentally racy, and what was true a microsecond ago may not be
true now.
Niall
>>
>> bool path_equality(path_view a, path_view b)
>> {
>> expected<file_handle, file_io_error> a = catch(file({}, a, :mode::none));
>> expected<file_handle, file_io_error> b = catch(file({}, b, :mode::none));
>> return a.has_value() && b.has_value() && a->unique_id() == b->unique_id();
>> }
>>
>> This is the only feasible, and correct, way of performing filesystem
>> path equality comparison. This is what we ought to do.
>
> Are you opening files and comparing something conceptually similar to
> inodes or global OS thing?
Yes, you open the files, but with no permissions, so it's fast as the OS
doesn't need to allocate resources to do i/o. You then read the unique
identifier of that inode on that system.
This obviously would return true for any hardlink or symbolic link or
combination thereof which led to the same inode. If you want to compare
equality of paths referring only the same hard link, you would:
bool path_equality(path_view a, path_view b)
{
file_handle a = file({}, a, :mode::none);
file_handle b = file({}, b, :mode::none);
return a.unique_id() == b.unique_id() && a.current_path() ==
b.current_path();
}
current_path() asks the kernel for a path uniquely identifying the hard
link originally opened. It can be extremely different to the path
opened, especially on Windows, as we only ever return NT kernel paths,
not DOS paths.
(Interestingly there is no one-one mapping between NT kernel paths and
DOS paths, so turning a NT kernel path into a DOS path is fundamentally
stochastic. Yay. So LLFIO doesn't bother trying)
Anyway the point that I am making here is that the kernel and filesystem
are black boxes. Unknowable. There is no point attempting to replicate
an unknowable black box in C++. Far better to simply ask the black box
to do the path comparison for you, it and only it knows what paths are
equal, and which are not. And that's leaving aside that the filesystem
is fundamentally racy, and what was true a microsecond ago may not be
true now.
Niall
Received on 2019-08-24 23:51:00