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
MovedFromString()99 absl::Nonnull<const std::string*> Status::MovedFromString() {
100 static const absl::NoDestructor<std::string> kMovedFrom(kMovedFromString);
101 return kMovedFrom.get();
102 }
103
Status(absl::StatusCode code,absl::string_view msg)104 Status::Status(absl::StatusCode code, absl::string_view msg)
105 : rep_(CodeToInlinedRep(code)) {
106 if (code != absl::StatusCode::kOk && !msg.empty()) {
107 rep_ = PointerToRep(new status_internal::StatusRep(code, msg, nullptr));
108 }
109 }
110
PrepareToModify(uintptr_t rep)111 absl::Nonnull<status_internal::StatusRep*> Status::PrepareToModify(
112 uintptr_t rep) {
113 if (IsInlined(rep)) {
114 return new status_internal::StatusRep(InlinedRepToCode(rep),
115 absl::string_view(), nullptr);
116 }
117 return RepToPointer(rep)->CloneAndUnref();
118 }
119
ToStringSlow(uintptr_t rep,StatusToStringMode mode)120 std::string Status::ToStringSlow(uintptr_t rep, StatusToStringMode mode) {
121 if (IsInlined(rep)) {
122 return absl::StrCat(absl::StatusCodeToString(InlinedRepToCode(rep)), ": ");
123 }
124 return RepToPointer(rep)->ToString(mode);
125 }
126
operator <<(std::ostream & os,const Status & x)127 std::ostream& operator<<(std::ostream& os, const Status& x) {
128 os << x.ToString(StatusToStringMode::kWithEverything);
129 return os;
130 }
131
AbortedError(absl::string_view message)132 Status AbortedError(absl::string_view message) {
133 return Status(absl::StatusCode::kAborted, message);
134 }
135
AlreadyExistsError(absl::string_view message)136 Status AlreadyExistsError(absl::string_view message) {
137 return Status(absl::StatusCode::kAlreadyExists, message);
138 }
139
CancelledError(absl::string_view message)140 Status CancelledError(absl::string_view message) {
141 return Status(absl::StatusCode::kCancelled, message);
142 }
143
DataLossError(absl::string_view message)144 Status DataLossError(absl::string_view message) {
145 return Status(absl::StatusCode::kDataLoss, message);
146 }
147
DeadlineExceededError(absl::string_view message)148 Status DeadlineExceededError(absl::string_view message) {
149 return Status(absl::StatusCode::kDeadlineExceeded, message);
150 }
151
FailedPreconditionError(absl::string_view message)152 Status FailedPreconditionError(absl::string_view message) {
153 return Status(absl::StatusCode::kFailedPrecondition, message);
154 }
155
InternalError(absl::string_view message)156 Status InternalError(absl::string_view message) {
157 return Status(absl::StatusCode::kInternal, message);
158 }
159
InvalidArgumentError(absl::string_view message)160 Status InvalidArgumentError(absl::string_view message) {
161 return Status(absl::StatusCode::kInvalidArgument, message);
162 }
163
NotFoundError(absl::string_view message)164 Status NotFoundError(absl::string_view message) {
165 return Status(absl::StatusCode::kNotFound, message);
166 }
167
OutOfRangeError(absl::string_view message)168 Status OutOfRangeError(absl::string_view message) {
169 return Status(absl::StatusCode::kOutOfRange, message);
170 }
171
PermissionDeniedError(absl::string_view message)172 Status PermissionDeniedError(absl::string_view message) {
173 return Status(absl::StatusCode::kPermissionDenied, message);
174 }
175
ResourceExhaustedError(absl::string_view message)176 Status ResourceExhaustedError(absl::string_view message) {
177 return Status(absl::StatusCode::kResourceExhausted, message);
178 }
179
UnauthenticatedError(absl::string_view message)180 Status UnauthenticatedError(absl::string_view message) {
181 return Status(absl::StatusCode::kUnauthenticated, message);
182 }
183
UnavailableError(absl::string_view message)184 Status UnavailableError(absl::string_view message) {
185 return Status(absl::StatusCode::kUnavailable, message);
186 }
187
UnimplementedError(absl::string_view message)188 Status UnimplementedError(absl::string_view message) {
189 return Status(absl::StatusCode::kUnimplemented, message);
190 }
191
UnknownError(absl::string_view message)192 Status UnknownError(absl::string_view message) {
193 return Status(absl::StatusCode::kUnknown, message);
194 }
195
IsAborted(const Status & status)196 bool IsAborted(const Status& status) {
197 return status.code() == absl::StatusCode::kAborted;
198 }
199
IsAlreadyExists(const Status & status)200 bool IsAlreadyExists(const Status& status) {
201 return status.code() == absl::StatusCode::kAlreadyExists;
202 }
203
IsCancelled(const Status & status)204 bool IsCancelled(const Status& status) {
205 return status.code() == absl::StatusCode::kCancelled;
206 }
207
IsDataLoss(const Status & status)208 bool IsDataLoss(const Status& status) {
209 return status.code() == absl::StatusCode::kDataLoss;
210 }
211
IsDeadlineExceeded(const Status & status)212 bool IsDeadlineExceeded(const Status& status) {
213 return status.code() == absl::StatusCode::kDeadlineExceeded;
214 }
215
IsFailedPrecondition(const Status & status)216 bool IsFailedPrecondition(const Status& status) {
217 return status.code() == absl::StatusCode::kFailedPrecondition;
218 }
219
IsInternal(const Status & status)220 bool IsInternal(const Status& status) {
221 return status.code() == absl::StatusCode::kInternal;
222 }
223
IsInvalidArgument(const Status & status)224 bool IsInvalidArgument(const Status& status) {
225 return status.code() == absl::StatusCode::kInvalidArgument;
226 }
227
IsNotFound(const Status & status)228 bool IsNotFound(const Status& status) {
229 return status.code() == absl::StatusCode::kNotFound;
230 }
231
IsOutOfRange(const Status & status)232 bool IsOutOfRange(const Status& status) {
233 return status.code() == absl::StatusCode::kOutOfRange;
234 }
235
IsPermissionDenied(const Status & status)236 bool IsPermissionDenied(const Status& status) {
237 return status.code() == absl::StatusCode::kPermissionDenied;
238 }
239
IsResourceExhausted(const Status & status)240 bool IsResourceExhausted(const Status& status) {
241 return status.code() == absl::StatusCode::kResourceExhausted;
242 }
243
IsUnauthenticated(const Status & status)244 bool IsUnauthenticated(const Status& status) {
245 return status.code() == absl::StatusCode::kUnauthenticated;
246 }
247
IsUnavailable(const Status & status)248 bool IsUnavailable(const Status& status) {
249 return status.code() == absl::StatusCode::kUnavailable;
250 }
251
IsUnimplemented(const Status & status)252 bool IsUnimplemented(const Status& status) {
253 return status.code() == absl::StatusCode::kUnimplemented;
254 }
255
IsUnknown(const Status & status)256 bool IsUnknown(const Status& status) {
257 return status.code() == absl::StatusCode::kUnknown;
258 }
259
ErrnoToStatusCode(int error_number)260 StatusCode ErrnoToStatusCode(int error_number) {
261 switch (error_number) {
262 case 0:
263 return StatusCode::kOk;
264 case EINVAL: // Invalid argument
265 case ENAMETOOLONG: // Filename too long
266 case E2BIG: // Argument list too long
267 case EDESTADDRREQ: // Destination address required
268 case EDOM: // Mathematics argument out of domain of function
269 case EFAULT: // Bad address
270 case EILSEQ: // Illegal byte sequence
271 case ENOPROTOOPT: // Protocol not available
272 case ENOTSOCK: // Not a socket
273 case ENOTTY: // Inappropriate I/O control operation
274 case EPROTOTYPE: // Protocol wrong type for socket
275 case ESPIPE: // Invalid seek
276 return StatusCode::kInvalidArgument;
277 case ETIMEDOUT: // Connection timed out
278 return StatusCode::kDeadlineExceeded;
279 case ENODEV: // No such device
280 case ENOENT: // No such file or directory
281 #ifdef ENOMEDIUM
282 case ENOMEDIUM: // No medium found
283 #endif
284 case ENXIO: // No such device or address
285 case ESRCH: // No such process
286 return StatusCode::kNotFound;
287 case EEXIST: // File exists
288 case EADDRNOTAVAIL: // Address not available
289 case EALREADY: // Connection already in progress
290 #ifdef ENOTUNIQ
291 case ENOTUNIQ: // Name not unique on network
292 #endif
293 return StatusCode::kAlreadyExists;
294 case EPERM: // Operation not permitted
295 case EACCES: // Permission denied
296 #ifdef ENOKEY
297 case ENOKEY: // Required key not available
298 #endif
299 case EROFS: // Read only file system
300 return StatusCode::kPermissionDenied;
301 case ENOTEMPTY: // Directory not empty
302 case EISDIR: // Is a directory
303 case ENOTDIR: // Not a directory
304 case EADDRINUSE: // Address already in use
305 case EBADF: // Invalid file descriptor
306 #ifdef EBADFD
307 case EBADFD: // File descriptor in bad state
308 #endif
309 case EBUSY: // Device or resource busy
310 case ECHILD: // No child processes
311 case EISCONN: // Socket is connected
312 #ifdef EISNAM
313 case EISNAM: // Is a named type file
314 #endif
315 #ifdef ENOTBLK
316 case ENOTBLK: // Block device required
317 #endif
318 case ENOTCONN: // The socket is not connected
319 case EPIPE: // Broken pipe
320 #ifdef ESHUTDOWN
321 case ESHUTDOWN: // Cannot send after transport endpoint shutdown
322 #endif
323 case ETXTBSY: // Text file busy
324 #ifdef EUNATCH
325 case EUNATCH: // Protocol driver not attached
326 #endif
327 return StatusCode::kFailedPrecondition;
328 case ENOSPC: // No space left on device
329 #ifdef EDQUOT
330 case EDQUOT: // Disk quota exceeded
331 #endif
332 case EMFILE: // Too many open files
333 case EMLINK: // Too many links
334 case ENFILE: // Too many open files in system
335 case ENOBUFS: // No buffer space available
336 case ENOMEM: // Not enough space
337 #ifdef EUSERS
338 case EUSERS: // Too many users
339 #endif
340 return StatusCode::kResourceExhausted;
341 #ifdef ECHRNG
342 case ECHRNG: // Channel number out of range
343 #endif
344 case EFBIG: // File too large
345 case EOVERFLOW: // Value too large to be stored in data type
346 case ERANGE: // Result too large
347 return StatusCode::kOutOfRange;
348 #ifdef ENOPKG
349 case ENOPKG: // Package not installed
350 #endif
351 case ENOSYS: // Function not implemented
352 case ENOTSUP: // Operation not supported
353 case EAFNOSUPPORT: // Address family not supported
354 #ifdef EPFNOSUPPORT
355 case EPFNOSUPPORT: // Protocol family not supported
356 #endif
357 case EPROTONOSUPPORT: // Protocol not supported
358 #ifdef ESOCKTNOSUPPORT
359 case ESOCKTNOSUPPORT: // Socket type not supported
360 #endif
361 case EXDEV: // Improper link
362 return StatusCode::kUnimplemented;
363 case EAGAIN: // Resource temporarily unavailable
364 #ifdef ECOMM
365 case ECOMM: // Communication error on send
366 #endif
367 case ECONNREFUSED: // Connection refused
368 case ECONNABORTED: // Connection aborted
369 case ECONNRESET: // Connection reset
370 case EINTR: // Interrupted function call
371 #ifdef EHOSTDOWN
372 case EHOSTDOWN: // Host is down
373 #endif
374 case EHOSTUNREACH: // Host is unreachable
375 case ENETDOWN: // Network is down
376 case ENETRESET: // Connection aborted by network
377 case ENETUNREACH: // Network unreachable
378 case ENOLCK: // No locks available
379 case ENOLINK: // Link has been severed
380 #ifdef ENONET
381 case ENONET: // Machine is not on the network
382 #endif
383 return StatusCode::kUnavailable;
384 case EDEADLK: // Resource deadlock avoided
385 #ifdef ESTALE
386 case ESTALE: // Stale file handle
387 #endif
388 return StatusCode::kAborted;
389 case ECANCELED: // Operation cancelled
390 return StatusCode::kCancelled;
391 default:
392 return StatusCode::kUnknown;
393 }
394 }
395
396 namespace {
MessageForErrnoToStatus(int error_number,absl::string_view message)397 std::string MessageForErrnoToStatus(int error_number,
398 absl::string_view message) {
399 return absl::StrCat(message, ": ",
400 absl::base_internal::StrError(error_number));
401 }
402 } // namespace
403
ErrnoToStatus(int error_number,absl::string_view message)404 Status ErrnoToStatus(int error_number, absl::string_view message) {
405 return Status(ErrnoToStatusCode(error_number),
406 MessageForErrnoToStatus(error_number, message));
407 }
408
StatusMessageAsCStr(const Status & status)409 absl::Nonnull<const char*> StatusMessageAsCStr(const Status& status) {
410 // As an internal implementation detail, we guarantee that if status.message()
411 // is non-empty, then the resulting string_view is null terminated.
412 auto sv_message = status.message();
413 return sv_message.empty() ? "" : sv_message.data();
414 }
415
416 ABSL_NAMESPACE_END
417 } // namespace absl
418