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() const10 const char* error_category::name() const noexcept {
11   return "watchman";
12 }
13 
message(int) const14 std::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()19 const std::error_category& error_category() {
20   static class error_category cat;
21   return cat;
22 }
23 
name() const24 const char* inotify_category::name() const noexcept {
25   return "inotify";
26 }
27 
message(int err) const28 std::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()47 const std::error_category& inotify_category() {
48   static class inotify_category cat;
49   return cat;
50 }
51 
equivalent(const std::error_code & code,int condition) const52 bool 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