1 /* Copyright 2016-present Facebook, Inc. 2 * Licensed under the Apache License, Version 2.0 */ 3 #include "watchman.h" 4 #include "watchman_error_category.h" 5 6 using std::generic_category; 7 8 namespace watchman { 9 name() const10const char* error_category::name() const noexcept { 11 return "watchman"; 12 } 13 message(int) const14std::string error_category::message(int) const { 15 return "the programmer should not be trying to render an error message " 16 "using watchman::error_category, please report this bug!"; 17 } 18 error_category()19const std::error_category& error_category() { 20 static class error_category cat; 21 return cat; 22 } 23 name() const24const char* inotify_category::name() const noexcept { 25 return "inotify"; 26 } 27 message(int err) const28std::string inotify_category::message(int err) const { 29 switch (err) { 30 case EMFILE: 31 return "The user limit on the total number of inotify " 32 "instances has been reached; increase the " 33 "fs.inotify.max_user_instances sysctl"; 34 case ENFILE: 35 return "The system limit on the total number of file descriptors " 36 "has been reached"; 37 case ENOMEM: 38 return "Insufficient kernel memory is available"; 39 case ENOSPC: 40 return "The user limit on the total number of inotify watches " 41 "was reached; increase the fs.inotify.max_user_watches sysctl"; 42 default: 43 return std::generic_category().message(err); 44 } 45 } 46 inotify_category()47const std::error_category& inotify_category() { 48 static class inotify_category cat; 49 return cat; 50 } 51 equivalent(const std::error_code & code,int condition) const52bool error_category::equivalent(const std::error_code& code, int condition) 53 const noexcept { 54 if (code.category() == inotify_category()) { 55 // Treat inotify the same as the generic category for the purposes of 56 // equivalence; it is the same namespace, we just provide different 57 // renditions of the error messages. 58 return equivalent( 59 std::error_code(code.value(), std::generic_category()), condition); 60 } 61 62 switch (static_cast<error_code>(condition)) { 63 case error_code::no_such_file_or_directory: 64 return 65 #ifdef _WIN32 66 code == windows_error_code(ERROR_FILE_NOT_FOUND) || 67 code == windows_error_code(ERROR_DEV_NOT_EXIST) || 68 #endif 69 code == make_error_code(std::errc::no_such_file_or_directory); 70 71 case error_code::not_a_directory: 72 return 73 #ifdef _WIN32 74 code == windows_error_code(ERROR_PATH_NOT_FOUND) || 75 code == windows_error_code(ERROR_DIRECTORY) || 76 #endif 77 code == make_error_code(std::errc::not_a_directory); 78 79 case error_code::too_many_symbolic_link_levels: 80 // POSIX says open with O_NOFOLLOW should set errno to ELOOP if the path 81 // is a symlink. However, FreeBSD (which ironically originated O_NOFOLLOW) 82 // sets it to EMLINK. So we check for either condition here. 83 return code == 84 make_error_code(std::errc::too_many_symbolic_link_levels) || 85 code == make_error_code(std::errc::too_many_links); 86 87 case error_code::permission_denied: 88 return 89 #ifdef _WIN32 90 code == windows_error_code(ERROR_ACCESS_DENIED) || 91 code == windows_error_code(ERROR_INVALID_ACCESS) || 92 code == windows_error_code(ERROR_WRITE_PROTECT) || 93 code == windows_error_code(ERROR_SHARING_VIOLATION) || 94 #endif 95 code == make_error_code(std::errc::permission_denied) || 96 code == make_error_code(std::errc::operation_not_permitted); 97 98 case error_code::system_limits_exceeded: 99 return 100 #ifdef _WIN32 101 code == windows_error_code(ERROR_TOO_MANY_OPEN_FILES) || 102 #endif 103 code == make_error_code(std::errc::too_many_files_open_in_system) || 104 code == make_error_code(std::errc::too_many_files_open); 105 106 case error_code::timed_out: 107 return 108 #ifdef _WIN32 109 code == windows_error_code(ERROR_TIMEOUT) || 110 code == windows_error_code(WAIT_TIMEOUT) || 111 #endif 112 code == make_error_code(std::errc::timed_out); 113 114 case error_code::not_a_symlink: 115 return 116 #ifdef _WIN32 117 code == windows_error_code(ERROR_NOT_A_REPARSE_POINT) || 118 #endif 119 code == make_error_code(std::errc::invalid_argument); 120 121 default: 122 return false; 123 } 124 } 125 } 126