1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "absl/status/status.h"
15
16 #include <errno.h>
17
18 #include <atomic>
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22 #include <memory>
23 #include <ostream>
24 #include <string>
25
26 #include "absl/base/attributes.h"
27 #include "absl/base/config.h"
28 #include "absl/base/internal/raw_logging.h"
29 #include "absl/base/internal/strerror.h"
30 #include "absl/base/macros.h"
31 #include "absl/base/no_destructor.h"
32 #include "absl/base/nullability.h"
33 #include "absl/debugging/stacktrace.h"
34 #include "absl/debugging/symbolize.h"
35 #include "absl/status/internal/status_internal.h"
36 #include "absl/strings/str_cat.h"
37 #include "absl/strings/str_format.h"
38 #include "absl/strings/str_split.h"
39 #include "absl/strings/string_view.h"
40 #include "absl/types/optional.h"
41
42 namespace absl {
43 ABSL_NAMESPACE_BEGIN
44
45 static_assert(
46 alignof(status_internal::StatusRep) >= 4,
47 "absl::Status assumes it can use the bottom 2 bits of a StatusRep*.");
48
StatusCodeToString(StatusCode code)49 std::string StatusCodeToString(StatusCode code) {
50 switch (code) {
51 case StatusCode::kOk:
52 return "OK";
53 case StatusCode::kCancelled:
54 return "CANCELLED";
55 case StatusCode::kUnknown:
56 return "UNKNOWN";
57 case StatusCode::kInvalidArgument:
58 return "INVALID_ARGUMENT";
59 case StatusCode::kDeadlineExceeded:
60 return "DEADLINE_EXCEEDED";
61 case StatusCode::kNotFound:
62 return "NOT_FOUND";
63 case StatusCode::kAlreadyExists:
64 return "ALREADY_EXISTS";
65 case StatusCode::kPermissionDenied:
66 return "PERMISSION_DENIED";
67 case StatusCode::kUnauthenticated:
68 return "UNAUTHENTICATED";
69 case StatusCode::kResourceExhausted:
70 return "RESOURCE_EXHAUSTED";
71 case StatusCode::kFailedPrecondition:
72 return "FAILED_PRECONDITION";
73 case StatusCode::kAborted:
74 return "ABORTED";
75 case StatusCode::kOutOfRange:
76 return "OUT_OF_RANGE";
77 case StatusCode::kUnimplemented:
78 return "UNIMPLEMENTED";
79 case StatusCode::kInternal:
80 return "INTERNAL";
81 case StatusCode::kUnavailable:
82 return "UNAVAILABLE";
83 case StatusCode::kDataLoss:
84 return "DATA_LOSS";
85 default:
86 return "";
87 }
88 }
89
operator <<(std::ostream & os,StatusCode code)90 std::ostream& operator<<(std::ostream& os, StatusCode code) {
91 return os << StatusCodeToString(code);
92 }
93
EmptyString()94 absl::Nonnull<const std::string*> Status::EmptyString() {
95 static const absl::NoDestructor<std::string> kEmpty;
96 return kEmpty.get();
97 }
98
99 #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
100 constexpr const char Status::kMovedFromString[];
101 #endif
102
MovedFromString()103 absl::Nonnull<const std::string*> Status::MovedFromString() {
104 static const absl::NoDestructor<std::string> kMovedFrom(kMovedFromString);
105 return kMovedFrom.get();
106 }
107
Status(absl::StatusCode code,absl::string_view msg)108 Status::Status(absl::StatusCode code, absl::string_view msg)
109 : rep_(CodeToInlinedRep(code)) {
110 if (code != absl::StatusCode::kOk && !msg.empty()) {
111 rep_ = PointerToRep(new status_internal::StatusRep(code, msg, nullptr));
112 }
113 }
114
PrepareToModify(uintptr_t rep)115 absl::Nonnull<status_internal::StatusRep*> Status::PrepareToModify(
116 uintptr_t rep) {
117 if (IsInlined(rep)) {
118 return new status_internal::StatusRep(InlinedRepToCode(rep),
119 absl::string_view(), nullptr);
120 }
121 return RepToPointer(rep)->CloneAndUnref();
122 }
123
ToStringSlow(uintptr_t rep,StatusToStringMode mode)124 std::string Status::ToStringSlow(uintptr_t rep, StatusToStringMode mode) {
125 if (IsInlined(rep)) {
126 return absl::StrCat(absl::StatusCodeToString(InlinedRepToCode(rep)), ": ");
127 }
128 return RepToPointer(rep)->ToString(mode);
129 }
130
operator <<(std::ostream & os,const Status & x)131 std::ostream& operator<<(std::ostream& os, const Status& x) {
132 os << x.ToString(StatusToStringMode::kWithEverything);
133 return os;
134 }
135
AbortedError(absl::string_view message)136 Status AbortedError(absl::string_view message) {
137 return Status(absl::StatusCode::kAborted, message);
138 }
139
AlreadyExistsError(absl::string_view message)140 Status AlreadyExistsError(absl::string_view message) {
141 return Status(absl::StatusCode::kAlreadyExists, message);
142 }
143
CancelledError(absl::string_view message)144 Status CancelledError(absl::string_view message) {
145 return Status(absl::StatusCode::kCancelled, message);
146 }
147
DataLossError(absl::string_view message)148 Status DataLossError(absl::string_view message) {
149 return Status(absl::StatusCode::kDataLoss, message);
150 }
151
DeadlineExceededError(absl::string_view message)152 Status DeadlineExceededError(absl::string_view message) {
153 return Status(absl::StatusCode::kDeadlineExceeded, message);
154 }
155
FailedPreconditionError(absl::string_view message)156 Status FailedPreconditionError(absl::string_view message) {
157 return Status(absl::StatusCode::kFailedPrecondition, message);
158 }
159
InternalError(absl::string_view message)160 Status InternalError(absl::string_view message) {
161 return Status(absl::StatusCode::kInternal, message);
162 }
163
InvalidArgumentError(absl::string_view message)164 Status InvalidArgumentError(absl::string_view message) {
165 return Status(absl::StatusCode::kInvalidArgument, message);
166 }
167
NotFoundError(absl::string_view message)168 Status NotFoundError(absl::string_view message) {
169 return Status(absl::StatusCode::kNotFound, message);
170 }
171
OutOfRangeError(absl::string_view message)172 Status OutOfRangeError(absl::string_view message) {
173 return Status(absl::StatusCode::kOutOfRange, message);
174 }
175
PermissionDeniedError(absl::string_view message)176 Status PermissionDeniedError(absl::string_view message) {
177 return Status(absl::StatusCode::kPermissionDenied, message);
178 }
179
ResourceExhaustedError(absl::string_view message)180 Status ResourceExhaustedError(absl::string_view message) {
181 return Status(absl::StatusCode::kResourceExhausted, message);
182 }
183
UnauthenticatedError(absl::string_view message)184 Status UnauthenticatedError(absl::string_view message) {
185 return Status(absl::StatusCode::kUnauthenticated, message);
186 }
187
UnavailableError(absl::string_view message)188 Status UnavailableError(absl::string_view message) {
189 return Status(absl::StatusCode::kUnavailable, message);
190 }
191
UnimplementedError(absl::string_view message)192 Status UnimplementedError(absl::string_view message) {
193 return Status(absl::StatusCode::kUnimplemented, message);
194 }
195
UnknownError(absl::string_view message)196 Status UnknownError(absl::string_view message) {
197 return Status(absl::StatusCode::kUnknown, message);
198 }
199
IsAborted(const Status & status)200 bool IsAborted(const Status& status) {
201 return status.code() == absl::StatusCode::kAborted;
202 }
203
IsAlreadyExists(const Status & status)204 bool IsAlreadyExists(const Status& status) {
205 return status.code() == absl::StatusCode::kAlreadyExists;
206 }
207
IsCancelled(const Status & status)208 bool IsCancelled(const Status& status) {
209 return status.code() == absl::StatusCode::kCancelled;
210 }
211
IsDataLoss(const Status & status)212 bool IsDataLoss(const Status& status) {
213 return status.code() == absl::StatusCode::kDataLoss;
214 }
215
IsDeadlineExceeded(const Status & status)216 bool IsDeadlineExceeded(const Status& status) {
217 return status.code() == absl::StatusCode::kDeadlineExceeded;
218 }
219
IsFailedPrecondition(const Status & status)220 bool IsFailedPrecondition(const Status& status) {
221 return status.code() == absl::StatusCode::kFailedPrecondition;
222 }
223
IsInternal(const Status & status)224 bool IsInternal(const Status& status) {
225 return status.code() == absl::StatusCode::kInternal;
226 }
227
IsInvalidArgument(const Status & status)228 bool IsInvalidArgument(const Status& status) {
229 return status.code() == absl::StatusCode::kInvalidArgument;
230 }
231
IsNotFound(const Status & status)232 bool IsNotFound(const Status& status) {
233 return status.code() == absl::StatusCode::kNotFound;
234 }
235
IsOutOfRange(const Status & status)236 bool IsOutOfRange(const Status& status) {
237 return status.code() == absl::StatusCode::kOutOfRange;
238 }
239
IsPermissionDenied(const Status & status)240 bool IsPermissionDenied(const Status& status) {
241 return status.code() == absl::StatusCode::kPermissionDenied;
242 }
243
IsResourceExhausted(const Status & status)244 bool IsResourceExhausted(const Status& status) {
245 return status.code() == absl::StatusCode::kResourceExhausted;
246 }
247
IsUnauthenticated(const Status & status)248 bool IsUnauthenticated(const Status& status) {
249 return status.code() == absl::StatusCode::kUnauthenticated;
250 }
251
IsUnavailable(const Status & status)252 bool IsUnavailable(const Status& status) {
253 return status.code() == absl::StatusCode::kUnavailable;
254 }
255
IsUnimplemented(const Status & status)256 bool IsUnimplemented(const Status& status) {
257 return status.code() == absl::StatusCode::kUnimplemented;
258 }
259
IsUnknown(const Status & status)260 bool IsUnknown(const Status& status) {
261 return status.code() == absl::StatusCode::kUnknown;
262 }
263
ErrnoToStatusCode(int error_number)264 StatusCode ErrnoToStatusCode(int error_number) {
265 switch (error_number) {
266 case 0:
267 return StatusCode::kOk;
268 case EINVAL: // Invalid argument
269 case ENAMETOOLONG: // Filename too long
270 case E2BIG: // Argument list too long
271 case EDESTADDRREQ: // Destination address required
272 case EDOM: // Mathematics argument out of domain of function
273 case EFAULT: // Bad address
274 case EILSEQ: // Illegal byte sequence
275 case ENOPROTOOPT: // Protocol not available
276 case ENOTSOCK: // Not a socket
277 case ENOTTY: // Inappropriate I/O control operation
278 case EPROTOTYPE: // Protocol wrong type for socket
279 case ESPIPE: // Invalid seek
280 return StatusCode::kInvalidArgument;
281 case ETIMEDOUT: // Connection timed out
282 return StatusCode::kDeadlineExceeded;
283 case ENODEV: // No such device
284 case ENOENT: // No such file or directory
285 #ifdef ENOMEDIUM
286 case ENOMEDIUM: // No medium found
287 #endif
288 case ENXIO: // No such device or address
289 case ESRCH: // No such process
290 return StatusCode::kNotFound;
291 case EEXIST: // File exists
292 case EADDRNOTAVAIL: // Address not available
293 case EALREADY: // Connection already in progress
294 #ifdef ENOTUNIQ
295 case ENOTUNIQ: // Name not unique on network
296 #endif
297 return StatusCode::kAlreadyExists;
298 case EPERM: // Operation not permitted
299 case EACCES: // Permission denied
300 #ifdef ENOKEY
301 case ENOKEY: // Required key not available
302 #endif
303 case EROFS: // Read only file system
304 return StatusCode::kPermissionDenied;
305 case ENOTEMPTY: // Directory not empty
306 case EISDIR: // Is a directory
307 case ENOTDIR: // Not a directory
308 case EADDRINUSE: // Address already in use
309 case EBADF: // Invalid file descriptor
310 #ifdef EBADFD
311 case EBADFD: // File descriptor in bad state
312 #endif
313 case EBUSY: // Device or resource busy
314 case ECHILD: // No child processes
315 case EISCONN: // Socket is connected
316 #ifdef EISNAM
317 case EISNAM: // Is a named type file
318 #endif
319 #ifdef ENOTBLK
320 case ENOTBLK: // Block device required
321 #endif
322 case ENOTCONN: // The socket is not connected
323 case EPIPE: // Broken pipe
324 #ifdef ESHUTDOWN
325 case ESHUTDOWN: // Cannot send after transport endpoint shutdown
326 #endif
327 case ETXTBSY: // Text file busy
328 #ifdef EUNATCH
329 case EUNATCH: // Protocol driver not attached
330 #endif
331 return StatusCode::kFailedPrecondition;
332 case ENOSPC: // No space left on device
333 #ifdef EDQUOT
334 case EDQUOT: // Disk quota exceeded
335 #endif
336 case EMFILE: // Too many open files
337 case EMLINK: // Too many links
338 case ENFILE: // Too many open files in system
339 case ENOBUFS: // No buffer space available
340 case ENOMEM: // Not enough space
341 #ifdef EUSERS
342 case EUSERS: // Too many users
343 #endif
344 return StatusCode::kResourceExhausted;
345 #ifdef ECHRNG
346 case ECHRNG: // Channel number out of range
347 #endif
348 case EFBIG: // File too large
349 case EOVERFLOW: // Value too large to be stored in data type
350 case ERANGE: // Result too large
351 return StatusCode::kOutOfRange;
352 #ifdef ENOPKG
353 case ENOPKG: // Package not installed
354 #endif
355 case ENOSYS: // Function not implemented
356 case ENOTSUP: // Operation not supported
357 case EAFNOSUPPORT: // Address family not supported
358 #ifdef EPFNOSUPPORT
359 case EPFNOSUPPORT: // Protocol family not supported
360 #endif
361 case EPROTONOSUPPORT: // Protocol not supported
362 #ifdef ESOCKTNOSUPPORT
363 case ESOCKTNOSUPPORT: // Socket type not supported
364 #endif
365 case EXDEV: // Improper link
366 return StatusCode::kUnimplemented;
367 case EAGAIN: // Resource temporarily unavailable
368 #ifdef ECOMM
369 case ECOMM: // Communication error on send
370 #endif
371 case ECONNREFUSED: // Connection refused
372 case ECONNABORTED: // Connection aborted
373 case ECONNRESET: // Connection reset
374 case EINTR: // Interrupted function call
375 #ifdef EHOSTDOWN
376 case EHOSTDOWN: // Host is down
377 #endif
378 case EHOSTUNREACH: // Host is unreachable
379 case ENETDOWN: // Network is down
380 case ENETRESET: // Connection aborted by network
381 case ENETUNREACH: // Network unreachable
382 case ENOLCK: // No locks available
383 case ENOLINK: // Link has been severed
384 #ifdef ENONET
385 case ENONET: // Machine is not on the network
386 #endif
387 return StatusCode::kUnavailable;
388 case EDEADLK: // Resource deadlock avoided
389 #ifdef ESTALE
390 case ESTALE: // Stale file handle
391 #endif
392 return StatusCode::kAborted;
393 case ECANCELED: // Operation cancelled
394 return StatusCode::kCancelled;
395 default:
396 return StatusCode::kUnknown;
397 }
398 }
399
400 namespace {
MessageForErrnoToStatus(int error_number,absl::string_view message)401 std::string MessageForErrnoToStatus(int error_number,
402 absl::string_view message) {
403 return absl::StrCat(message, ": ",
404 absl::base_internal::StrError(error_number));
405 }
406 } // namespace
407
ErrnoToStatus(int error_number,absl::string_view message)408 Status ErrnoToStatus(int error_number, absl::string_view message) {
409 return Status(ErrnoToStatusCode(error_number),
410 MessageForErrnoToStatus(error_number, message));
411 }
412
StatusMessageAsCStr(const Status & status)413 absl::Nonnull<const char*> StatusMessageAsCStr(const Status& status) {
414 // As an internal implementation detail, we guarantee that if status.message()
415 // is non-empty, then the resulting string_view is null terminated.
416 auto sv_message = status.message();
417 return sv_message.empty() ? "" : sv_message.data();
418 }
419
420 ABSL_NAMESPACE_END
421 } // namespace absl
422