c++error-codestd-filesystem

What are the possible error codes that can be returned when calling std::filesystem::copy()?


I can't seem to find a list of error codes that might be passed into the ec parameter for std::filesystem::copy.

cppreference.com seems to indicate that the error codes are OS-specific.
Looking at the Microsoft documentation (As I'm specifically interested in Windows error codes, though I'm sure resources for other OSes would be helpful for others) it looks almost like a copy/paste of the same source documentation without any additional information as to anything Windows specific.

My guess is that the error codes will be the same ones listed here, but there's no information there as to which are relevant to the filesystem, or more specifically the copy() function (beyond educated guessing).

Does anyone have any resources as to potential error codes that might be returned, or, if I have to do this the hard way (and manually try and check for different error scenarios), how do I know if I have an exhaustive list?


Solution

  • The system specific error codes used by the filesystem library can be found in the __std_win_error enum. Note how the numerical values map 1:1 to the values returned by the Win32 API function GetLastError:

    enum class __std_win_error : unsigned long {
        _Success                   = 0, // #define ERROR_SUCCESS                    0L
        _Invalid_function          = 1, // #define ERROR_INVALID_FUNCTION           1L
        _File_not_found            = 2, // #define ERROR_FILE_NOT_FOUND             2L
        _Path_not_found            = 3, // #define ERROR_PATH_NOT_FOUND             3L
        _Access_denied             = 5, // #define ERROR_ACCESS_DENIED              5L
        _Not_enough_memory         = 8, // #define ERROR_NOT_ENOUGH_MEMORY          8L
        _No_more_files             = 18, // #define ERROR_NO_MORE_FILES              18L
        _Sharing_violation         = 32, // #define ERROR_SHARING_VIOLATION          32L
        _Not_supported             = 50, // #define ERROR_NOT_SUPPORTED              50L
        _File_exists               = 80, // #define ERROR_FILE_EXISTS                80L
        _Invalid_parameter         = 87, // #define ERROR_INVALID_PARAMETER          87L
        _Insufficient_buffer       = 122, // #define ERROR_INSUFFICIENT_BUFFER        122L
        _Invalid_name              = 123, // #define ERROR_INVALID_NAME               123L
        _Directory_not_empty       = 145, // #define ERROR_DIR_NOT_EMPTY              145L
        _Already_exists            = 183, // #define ERROR_ALREADY_EXISTS             183L
        _Filename_exceeds_range    = 206, // #define ERROR_FILENAME_EXCED_RANGE       206L
        _Directory_name_is_invalid = 267, // #define ERROR_DIRECTORY                  267L
        _Max                       = ~0UL // sentinel not used by Win32
    };
    

    However, you should not ever test against these directly. The whole point of the system_error design is to not have to interpret system specific error_codes directly, but instead only interpret them via their associated error_category.

    In particular, the category maps error_code values to error_conditions. The implementation throws an error_code, but the client application should always check for error_conditions. Unlike error_code, error_conditions are portable and do not rely on implementation details.

    So here's how you should treat those kinds of errors in code: Check the std::errc for values that you would like to handle programmatically. Then check the error_code against those values:

    std::error_code ec;
    std::filesystem::copy("source.txt", "destination.txt", ec);
    if (ec) {
        if (ec == std::errc::file_exists) {
            // special error handling for file_exists
            // [...]
        } else {
            // generic error handling for all other errors
            // that you don't specifically care about
            std::cerr << "Error: " << ec.message() << "\n";
        }
    }
    

    There will likely be some errors left over, but since you almost certainly will not be able to come up with a specialized error handler for those anyway, just put in a catch-all generic error handler for all the error conditions that you don't care about.

    Chris Kohlhoff, one of the original authors of the system error library has a great, if somewhat dated, blog series explaining the design and intended use of the error handling mechanism.