diff options
Diffstat (limited to 'test/util/file_descriptor.h')
-rw-r--r-- | test/util/file_descriptor.h | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/test/util/file_descriptor.h b/test/util/file_descriptor.h new file mode 100644 index 000000000..be8812d01 --- /dev/null +++ b/test/util/file_descriptor.h @@ -0,0 +1,134 @@ +// Copyright 2018 Google LLC +// +// 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 GVISOR_TEST_UTIL_FILE_DESCRIPTOR_H_ +#define GVISOR_TEST_UTIL_FILE_DESCRIPTOR_H_ + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <algorithm> +#include <string> + +#include "gmock/gmock.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "test/util/logging.h" +#include "test/util/posix_error.h" +#include "test/util/save_util.h" + +namespace gvisor { +namespace testing { + +// FileDescriptor is an RAII type class which takes ownership of a file +// descriptor. It will close the FD when this object goes out of scope. +class FileDescriptor { + public: + // Constructs an empty FileDescriptor (one that does not own a file + // descriptor). + FileDescriptor() = default; + + // Constructs a FileDescriptor that owns fd. If fd is negative, constructs an + // empty FileDescriptor. + explicit FileDescriptor(int fd) { set_fd(fd); } + + FileDescriptor(FileDescriptor&& orig) : fd_(orig.release()) {} + + FileDescriptor& operator=(FileDescriptor&& orig) { + reset(orig.release()); + return *this; + } + + PosixErrorOr<FileDescriptor> Dup() const { + if (fd_ < 0) { + return PosixError(EINVAL, "Attempting to Dup unset fd"); + } + + int fd = dup(fd_); + if (fd < 0) { + return PosixError(errno, absl::StrCat("dup ", fd_)); + } + MaybeSave(); + return FileDescriptor(fd); + } + + FileDescriptor(FileDescriptor const& other) = delete; + FileDescriptor& operator=(FileDescriptor const& other) = delete; + + ~FileDescriptor() { reset(); } + + // If this object is non-empty, returns the owned file descriptor. (Ownership + // is retained by the FileDescriptor.) Otherwise returns -1. + int get() const { return fd_; } + + // If this object is non-empty, transfers ownership of the file descriptor to + // the caller and returns it. Otherwise returns -1. + int release() { + int const fd = fd_; + fd_ = -1; + return fd; + } + + // If this object is non-empty, closes the owned file descriptor (recording a + // test failure if the close fails). + void reset() { reset(-1); } + + // Like no-arg reset(), but the FileDescriptor takes ownership of fd after + // closing its existing file descriptor. + void reset(int fd) { + if (fd_ >= 0) { + TEST_PCHECK(close(fd_) == 0); + MaybeSave(); + } + set_fd(fd); + } + + private: + // Wrapper that coerces negative fd values other than -1 to -1 so that get() + // etc. return -1. + void set_fd(int fd) { fd_ = std::max(fd, -1); } + + int fd_ = -1; +}; + +// Wrapper around open(2) that returns a FileDescriptor. +inline PosixErrorOr<FileDescriptor> Open(std::string const& path, int flags, + mode_t mode = 0) { + int fd = open(path.c_str(), flags, mode); + if (fd < 0) { + return PosixError(errno, absl::StrFormat("open(%s, %#x, %#o)", path.c_str(), + flags, mode)); + } + MaybeSave(); + return FileDescriptor(fd); +} + +// Wrapper around openat(2) that returns a FileDescriptor. +inline PosixErrorOr<FileDescriptor> OpenAt(int dirfd, std::string const& path, + int flags, mode_t mode = 0) { + int fd = openat(dirfd, path.c_str(), flags, mode); + if (fd < 0) { + return PosixError(errno, absl::StrFormat("openat(%d, %s, %#x, %#o)", dirfd, + path, flags, mode)); + } + MaybeSave(); + return FileDescriptor(fd); +} + +} // namespace testing +} // namespace gvisor + +#endif // GVISOR_TEST_UTIL_FILE_DESCRIPTOR_H_ |