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?
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_code
s directly, but instead only interpret them via their associated error_category
.
In particular, the category maps error_code
values to error_condition
s. The implementation throws an error_code
, but the client application should always check for error_condition
s. Unlike error_code
, error_condition
s 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.