STL icon indicating copy to clipboard operation
STL copied to clipboard

<filesystem>: std::filesystem::exists fails when testing path naming unix socket

Open vasama opened this issue 2 years ago • 6 comments
trafficstars

Description

std::filesystem::exists(p), where p is a path pointing to a unix socket (e.g. p = "./test.sock"), throws an exception with the message exists: unknown error: "./test.sock".

Command-line test case

C:\temp> cat test.cpp
#include <exception>
#include <filesystem>
#include <iostream>
#include <cassert>

#ifndef _WINSOCKAPI_
#       define _WINSOCKAPI_
#endif

#include <WinSock2.h>
#include <ws2ipdef.h>
#include <afunix.h>

#pragma comment(lib, "ws2_32.lib")

int main()
{
        WSADATA wsa_data;
        assert(WSAStartup(MAKEWORD(2, 2), &wsa_data) == 0);

        auto socket = WSASocketW(AF_UNIX, SOCK_STREAM, 0, 0, 0, 0);
        assert(socket != SOCKET_ERROR);
        sockaddr_un addr;
        addr.sun_family = AF_UNIX;
        strncpy(addr.sun_path, "./test.sock", sizeof(addr.sun_path));
        assert(bind(socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != SOCKET_ERROR);
        assert(listen(socket, 1) != SOCKET_ERROR);

        try
        {
                (void)std::filesystem::exists("./test.sock");
        }
        catch (std::exception const& e)
        {
                std::cout << e.what() << std::endl;
        }
}
​C:\temp> cl /std:c++17 /EHsc /Gr test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.37.32822 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
Microsoft (R) Incremental Linker Version 14.37.32822.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj
​C:\temp> ./test.exe
exists: unknown error: "./test.sock"

Expected behavior

I expect the call to std::filesystem::exists to return true.

STL version

Microsoft Visual Studio Community 2022
Version 17.8.0 Preview 1.0

vasama avatar Oct 07 '23 17:10 vasama

@strega-nil-ms

vasama avatar Oct 07 '23 17:10 vasama

The error code is 1920 ("The file cannot be accessed by the system.") on my machine, reported by CreateFileW.

Can we just return true when error code 1920 (and it friends) is encountered?

frederick-vs-ja avatar Oct 09 '23 17:10 frederick-vs-ja

Does std::filesystem::exists even call CreateFileW? If so, it should not -- should use GetFileAttributesW or FindFirstFileW.

AlexGuteniev avatar Oct 09 '23 17:10 AlexGuteniev

Does std::filesystem::exists even call CreateFileW? If so, it should not -- should use GetFileAttributesW or FindFirstFileW.

It must, because for some reason, unix sockets are considered reparse points. I'm not sure how to solve this, to be quite honest. This seems to be a failing of the standard's interaction with Windows' APIs.

strega-nil-ms avatar Oct 09 '23 18:10 strega-nil-ms

We talked about this at the weekly maintainer meeting. Nicole debugged into this and says that the problem is happening here:

https://github.com/microsoft/STL/blob/f362f7d7bea87bd199c927a89718e929ed89b187/stl/src/filesystem.cpp#L910-L918

This is where __std_fs_get_stats() calls CreateFileW() (via _Fs_file). It appears that we need to do something like add extra logic here to detect reparse points, and then to further detect Unix sockets. From quickly searching ~~MSDN~~ Microsoft Learn, https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-point-tags mentions something that looks like it might be relevant: IO_REPARSE_TAG_AF_UNIX resembles the AF_UNIX used in the repro (which curiously isn't mentioned in WSASocketW documentation).

This would add extra calls to the filesystem::exists() codepath, but we currently don't see a better way to avoid this, if we want to handle this aspect of the filesystem.

We might want to ask internal mailing lists (e.g. win32prg) if there's some better way to achieve this with the public APIs that we can use.

StephanTLavavej avatar Oct 11 '23 21:10 StephanTLavavej

You may just need to use IsReparseTagNameSurrogate on the reparse tag to test if it's some kind of link or not.

ChrisDenton avatar Oct 12 '23 01:10 ChrisDenton