aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase
diff options
context:
space:
mode:
authorGravatar Gil <mcg@google.com>2018-06-12 09:36:08 -0700
committerGravatar GitHub <noreply@github.com>2018-06-12 09:36:08 -0700
commit9e14b80e0716c2be71c6100cad7aa7c61ac46c6e (patch)
tree09d4d4583571b56feb89f809a24626cef14a3356 /Firestore/core/src/firebase
parentf5bf0a37a7dd40e7538a1aed77af05471b7fe713 (diff)
Create Status objects from errno (#1374)
* Add a portable interface to strerror * Add Status::FromErrno * Add strerror_test.cc to the Xcode project * Use glibc feature selection macros instead of return-type overloads * Fix tensorflow references
Diffstat (limited to 'Firestore/core/src/firebase')
-rw-r--r--Firestore/core/src/firebase/firestore/util/CMakeLists.txt9
-rw-r--r--Firestore/core/src/firebase/firestore/util/status.cc151
-rw-r--r--Firestore/core/src/firebase/firestore/util/status.h7
-rw-r--r--Firestore/core/src/firebase/firestore/util/status_apple.mm45
-rw-r--r--Firestore/core/src/firebase/firestore/util/statusor.h5
-rw-r--r--Firestore/core/src/firebase/firestore/util/strerror.cc92
-rw-r--r--Firestore/core/src/firebase/firestore/util/strerror.h36
7 files changed, 343 insertions, 2 deletions
diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
index b2c4195..5b38b2e 100644
--- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
@@ -193,6 +193,8 @@ cc_library(
statusor.cc
statusor.h
statusor_internals.h
+ strerror.cc
+ strerror.h
string_util.cc
string_util.h
type_traits.h
@@ -203,3 +205,10 @@ cc_library(
${FIREBASE_FIRESTORE_UTIL_LOG}
${FIREBASE_FIRESTORE_UTIL_RANDOM}
)
+
+if(APPLE)
+ target_sources(
+ firebase_firestore_util PRIVATE
+ status_apple.mm
+ )
+endif()
diff --git a/Firestore/core/src/firebase/firestore/util/status.cc b/Firestore/core/src/firebase/firestore/util/status.cc
index 46f3ce6..3e8585a 100644
--- a/Firestore/core/src/firebase/firestore/util/status.cc
+++ b/Firestore/core/src/firebase/firestore/util/status.cc
@@ -16,6 +16,9 @@
#include "Firestore/core/src/firebase/firestore/util/status.h"
+#include <cerrno>
+
+#include "Firestore/core/src/firebase/firestore/util/strerror.h"
#include "Firestore/core/src/firebase/firestore/util/string_format.h"
namespace firebase {
@@ -29,6 +32,154 @@ Status::Status(FirestoreErrorCode code, absl::string_view msg) {
state_->msg = static_cast<std::string>(msg);
}
+/// Returns the Canonical error code for the given errno value.
+static FirestoreErrorCode CodeForErrno(int errno_code) {
+ switch (errno_code) {
+ case 0:
+ return FirestoreErrorCode::Ok;
+
+ // Internal canonical mappings call these failed preconditions, but for
+ // our purposes these must indicate an internal error in file handling.
+ case EBADF: // Invalid file descriptor
+#if defined(EBADFD)
+ case EBADFD: // File descriptor in bad state
+#endif
+ return FirestoreErrorCode::Internal;
+
+ case EINVAL: // Invalid argument
+ case ENAMETOOLONG: // Filename too long
+ case E2BIG: // Argument list too long
+ case EDESTADDRREQ: // Destination address required
+ case EDOM: // Mathematics argument out of domain of function
+ case EFAULT: // Bad address
+ case EILSEQ: // Illegal byte sequence
+ case ENOPROTOOPT: // Protocol not available
+ case ENOSTR: // Not a STREAM
+ case ENOTSOCK: // Not a socket
+ case ENOTTY: // Inappropriate I/O control operation
+ case EPROTOTYPE: // Protocol wrong type for socket
+ case ESPIPE: // Invalid seek
+ return FirestoreErrorCode::InvalidArgument;
+
+ case ETIMEDOUT: // Connection timed out
+ case ETIME: // Timer expired
+ return FirestoreErrorCode::DeadlineExceeded;
+
+ case ENODEV: // No such device
+ case ENOENT: // No such file or directory
+#if defined(ENOMEDIUM)
+ case ENOMEDIUM: // No medium found
+#endif
+ case ENXIO: // No such device or address
+ case ESRCH: // No such process
+ return FirestoreErrorCode::NotFound;
+
+ case EEXIST: // File exists
+ case EADDRNOTAVAIL: // Address not available
+ case EALREADY: // Connection already in progress
+#if defined(ENOTUNIQ)
+ case ENOTUNIQ: // Name not unique on network
+#endif
+ return FirestoreErrorCode::AlreadyExists;
+
+ case EPERM: // Operation not permitted
+ case EACCES: // Permission denied
+#if defined(ENOKEY)
+ case ENOKEY: // Required key not available
+#endif
+ case EROFS: // Read only file system
+ return FirestoreErrorCode::PermissionDenied;
+
+ case ENOTEMPTY: // Directory not empty
+ case EISDIR: // Is a directory
+ case ENOTDIR: // Not a directory
+ case EADDRINUSE: // Address already in use
+ case EBUSY: // Device or resource busy
+ case ECHILD: // No child processes
+ case EISCONN: // Socket is connected
+#if defined(EISNAM)
+ case EISNAM: // Is a named type file
+#endif
+ case ENOTBLK: // Block device required
+ case ENOTCONN: // The socket is not connected
+ case EPIPE: // Broken pipe
+ case ESHUTDOWN: // Cannot send after transport endpoint shutdown
+ case ETXTBSY: // Text file busy
+#if defined(EUNATCH)
+ case EUNATCH: // Protocol driver not attached
+#endif
+ return FirestoreErrorCode::FailedPrecondition;
+
+ case ENOSPC: // No space left on device
+ case EDQUOT: // Disk quota exceeded
+ case EMFILE: // Too many open files
+ case EMLINK: // Too many links
+ case ENFILE: // Too many open files in system
+ case ENOBUFS: // No buffer space available
+ case ENODATA: // No message is available on the STREAM read queue
+ case ENOMEM: // Not enough space
+ case ENOSR: // No STREAM resources
+ case EUSERS: // Too many users
+ return FirestoreErrorCode::ResourceExhausted;
+
+#if defined(ECHRNG)
+ case ECHRNG: // Channel number out of range
+#endif
+ case EFBIG: // File too large
+ case EOVERFLOW: // Value too large to be stored in data type
+ case ERANGE: // Result too large
+ return FirestoreErrorCode::OutOfRange;
+
+#if defined(ENOPKG)
+ case ENOPKG: // Package not installed
+#endif
+ case ENOSYS: // Function not implemented
+ case ENOTSUP: // Operation not supported
+ case EAFNOSUPPORT: // Address family not supported
+ case EPFNOSUPPORT: // Protocol family not supported
+ case EPROTONOSUPPORT: // Protocol not supported
+ case ESOCKTNOSUPPORT: // Socket type not supported
+ case EXDEV: // Improper link
+ return FirestoreErrorCode::Unimplemented;
+
+ case EAGAIN: // Resource temporarily unavailable
+#if defined(ECOMM)
+ case ECOMM: // Communication error on send
+#endif
+ case ECONNREFUSED: // Connection refused
+ case ECONNABORTED: // Connection aborted
+ case ECONNRESET: // Connection reset
+ case EINTR: // Interrupted function call
+ case EHOSTDOWN: // Host is down
+ case EHOSTUNREACH: // Host is unreachable
+ case ENETDOWN: // Network is down
+ case ENETRESET: // Connection aborted by network
+ case ENETUNREACH: // Network unreachable
+ case ENOLCK: // No locks available
+ case ENOLINK: // Link has been severed
+#if defined(ENONET)
+ case ENONET: // Machine is not on the network
+#endif
+ return FirestoreErrorCode::Unavailable;
+
+ case EDEADLK: // Resource deadlock avoided
+ case ESTALE: // Stale file handle
+ return FirestoreErrorCode::Aborted;
+
+ case ECANCELED: // Operation cancelled
+ return FirestoreErrorCode::Cancelled;
+
+ default: { return FirestoreErrorCode::Unknown; }
+ }
+}
+
+Status Status::FromErrno(int errno_code, absl::string_view msg) {
+ FirestoreErrorCode canonical_code = CodeForErrno(errno_code);
+ return Status{canonical_code,
+ util::StringFormat("%s (errno %s: %s)", msg, errno_code,
+ StrError(errno_code))};
+}
+
void Status::Update(const Status& new_status) {
if (ok()) {
*this = new_status;
diff --git a/Firestore/core/src/firebase/firestore/util/status.h b/Firestore/core/src/firebase/firestore/util/status.h
index 9121b36..5247c92 100644
--- a/Firestore/core/src/firebase/firestore/util/status.h
+++ b/Firestore/core/src/firebase/firestore/util/status.h
@@ -50,6 +50,13 @@ class ABSL_MUST_USE_RESULT Status {
return Status();
}
+ /// Creates a status object from the given errno error code and message.
+ static Status FromErrno(int errno_code, absl::string_view msg);
+
+#if defined(__OBJC__)
+ static Status FromNSError(NSError* error);
+#endif // defined(__OBJC__)
+
/// Returns true iff the status indicates success.
bool ok() const {
return (state_ == nullptr);
diff --git a/Firestore/core/src/firebase/firestore/util/status_apple.mm b/Firestore/core/src/firebase/firestore/util/status_apple.mm
new file mode 100644
index 0000000..2e2bb07
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/status_apple.mm
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015, 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/status.h"
+
+#include <cerrno>
+
+#include "Firestore/core/src/firebase/firestore/util/string_format.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+Status Status::FromNSError(NSError* error) {
+ NSError* original = error;
+
+ while (error) {
+ if ([error.domain isEqualToString:NSPOSIXErrorDomain]) {
+ return FromErrno(static_cast<int>(error.code),
+ MakeStringView(original.localizedDescription));
+ }
+
+ error = error.userInfo[NSUnderlyingErrorKey];
+ }
+
+ return Status{FirestoreErrorCode::Unknown,
+ StringFormat("Unknown error: %s", original)};
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/statusor.h b/Firestore/core/src/firebase/firestore/util/statusor.h
index dc5644a..9985956 100644
--- a/Firestore/core/src/firebase/firestore/util/statusor.h
+++ b/Firestore/core/src/firebase/firestore/util/statusor.h
@@ -59,7 +59,8 @@
//
// StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
// if (arg <= 0) {
-// return tensorflow::InvalidArgument("Arg must be positive");
+// return Status(FirestoreErrorCode::InvalidArgument,
+// "Arg must be positive");
// } else {
// return new Foo(arg);
// }
@@ -149,7 +150,7 @@ class ABSL_MUST_USE_RESULT StatusOr
//
// REQUIRES: !status.ok(). This requirement is DCHECKed.
// In optimized builds, passing Status::OK() here will have the effect
- // of passing tensorflow::error::INTERNAL as a fallback.
+ // of passing FirestoreErrorCode::Internal as a fallback.
StatusOr(const Status& status); // NOLINT: allow non-explicit 1-param ctor
StatusOr& operator=(const Status& status);
diff --git a/Firestore/core/src/firebase/firestore/util/strerror.cc b/Firestore/core/src/firebase/firestore/util/strerror.cc
new file mode 100644
index 0000000..ab1bbbb
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/strerror.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Implementation note:
+//
+// This is ported from //base/strerror.cc, with several local modifications:
+//
+// * Removed non-portable optimization around to use sys_errlist where
+// available without warnings.
+// * Added __attribute__((unused)) to compile with -Wno-unused-functions.
+// * Conformed to style/lint rules.
+
+#include "Firestore/core/src/firebase/firestore/util/strerror.h"
+
+#include <cerrno>
+#include <cstring>
+
+#if defined(_WIN32)
+#define HAVE_STRERROR_S 1
+
+#elif defined(__GLIBC__)
+#if (_POSIX_C_SOURCE >= 200112L) && !_GNU_SOURCE
+#define HAVE_POSIX_STRERROR_R 1
+#else
+#define HAVE_GNU_STRERROR_R 1
+#endif
+
+#else
+#define HAVE_POSIX_STRERROR_R 1
+
+#endif
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+namespace {
+
+inline const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
+#if HAVE_STRERROR_S
+ int rc = strerror_s(buf, buflen, errnum);
+ buf[buflen - 1] = '\0'; // guarantee NUL termination
+
+ if (rc == 0 && strcmp(buf, "Unknown error") == 0) {
+ *buf = '\0';
+ }
+ return buf;
+
+#elif HAVE_POSIX_STRERROR_R
+ if (strerror_r(errnum, buf, buflen)) {
+ *buf = '\0';
+ }
+ return buf;
+
+#elif HAVE_GNU_STRERROR_R
+ return strerror_r(errnum, buf, buflen);
+
+#endif // HAVE_STRERROR_S
+}
+
+} // namespace
+
+std::string StrError(int errnum) {
+ const int saved_errno = errno;
+
+ char buf[100];
+ const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
+ if (*str == '\0') {
+ snprintf(buf, sizeof buf, "Unknown error %d", errnum);
+ str = buf;
+ }
+
+ errno = saved_errno;
+ return str;
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/strerror.h b/Firestore/core/src/firebase/firestore/util/strerror.h
new file mode 100644
index 0000000..72c0300
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/strerror.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRERROR_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRERROR_H_
+
+#include <string>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+// A portable and thread-safe alternative to strerror().
+// Returns a human-readable string describing the given POSIX error
+// code. If the error code is not translatable, the string will be
+// "Unknown error nnn". errno will not be modified by this call.
+std::string StrError(int errnum);
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRERROR_H_