Skip to content

<filesystem>: directory_entry{} should throw std::errc::filename_too_long if the filename is longer than the limit #5463

Open
@paulharris

Description

@paulharris

Describe the bug

Environment: with Long Paths DISABLED. Yuck. But test will probably still work due to lack of longPathAware manifest.

__std_fs_get_stats calls GetFileAttributesExW() on a filename that exists, but is too long,
this function returns that it does not exist, and that is the result.

if (!GetFileAttributesExW(_Path, GetFileExInfoStandard, &_Data)) {

However, if the parent path is UNDER the limit by a few characters, and the filename is OVER the limit,
then you can use directory_iterator{parent_dir} to retrieve the details of the filename (and will say it exists),
but, if you call directory_entry{filename}, it will tell you the file does not exist.

Instead, if the filename is too long because of the legacy limits, then please, throw the exception. Don't say the query was successful and the file does not exist.
It is problematic that directory_iterator will still work, but, whatever, this is still better.

Command-line test case

C:\Temp>type test_stat_long.cpp

#include <iostream>
#include <filesystem>
#include <fstream>

int main()
{
   try {
      std::filesystem::path short_base_folder { "c:/Temp/short" };

      std::filesystem::path long_base_folder { "c:/Temp/long long long long long long long long long" };

      std::filesystem::path subfolders { "long long long long long long/long long long long long long/long long long long long long/long long long long long long/long long long long long long/long long long long long long/final long" };

      std::filesystem::path short_folder { short_base_folder / subfolders };
      std::filesystem::path long_folder { long_base_folder / subfolders };

      std::filesystem::create_directories(short_folder);

      std::filesystem::path fn { "long_long_file_name_the_file.txt" };
      std::filesystem::path fn_short_path = short_folder / fn;
      std::filesystem::path fn_long_path = long_folder / fn;

      std::ofstream out;
      out.exceptions(std::ios::badbit | std::ios::failbit);
      out.open(fn_short_path, std::ios::binary);
      out << "Hello world\n";
      out.close();

      std::filesystem::rename(short_base_folder, long_base_folder);

      for ( std::filesystem::directory_entry entry : std::filesystem::directory_iterator { long_folder } )
         std::cout << "Iterator, file: " << entry.path().generic_string() << "\nFile exists? " << (int)entry.exists() << std::endl << std::endl;

      std::filesystem::directory_entry entry { fn_long_path };
      std::cout << "Direct: File exists? " << (int)entry.exists() << std::endl;

      return 0;
   }
   catch (std::exception & e) {
      std::cerr << "Exception: " << e.what() << std::endl;
   }
   catch (...) {
      std::cerr << "Unknown Exception" << std::endl;
   }
      
   return 1;
}

C:\Temp>cl /EHsc /W4 /WX /std:c++latest .\test_stat_long.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.43.34810 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

/std:c++latest is provided as a preview of language features from the latest C++
working draft, and we're eager to hear about bugs and suggestions for improvements.
However, note that these features are provided as-is without support, and subject
to changes or removal as the working draft evolves. See
https://go.microsoft.com/fwlink/?linkid=2045807 for details.

test_stat_long.cpp
Microsoft (R) Incremental Linker Version 14.43.34810.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test_stat_long.exe
test_stat_long.obj

C:\Temp>.\test_stat_long.exe
Iterator, file: c:/Temp/long long long long long long long long long/long long long long long long/long long long long long long/long long long long long long/long long long long long long/long long long long long long/long long long long long long/final long/long_long_file_name_the_file.txt
File exists? 1

Direct: File exists? 0

Expected behavior

If long-paths were enabled in the registry, and the program had a manifest for longPathAware=true,
then I would expect "File exists? 1".

In this case, with long-paths disabled and no program manifest,
I would expect directory_entry to throw a filesystem_error(filename_too_long)

STL version

  • Visual Studio version

Microsoft Visual Studio Community 2022 (64-bit) - Current
Version 17.13.6
```

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfilesystemC++17 filesystem

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions