File.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * Copyright 2013-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/File.h>
  17. #include <folly/Exception.h>
  18. #include <folly/FileUtil.h>
  19. #include <folly/Format.h>
  20. #include <folly/ScopeGuard.h>
  21. #include <folly/portability/Fcntl.h>
  22. #include <folly/portability/SysFile.h>
  23. #include <folly/portability/Unistd.h>
  24. #include <system_error>
  25. #include <glog/logging.h>
  26. namespace folly {
  27. File::File() noexcept : fd_(-1), ownsFd_(false) {}
  28. File::File(int fd, bool ownsFd) noexcept : fd_(fd), ownsFd_(ownsFd) {
  29. CHECK_GE(fd, -1) << "fd must be -1 or non-negative";
  30. CHECK(fd != -1 || !ownsFd) << "cannot own -1";
  31. }
  32. File::File(const char* name, int flags, mode_t mode)
  33. : fd_(::open(name, flags, mode)), ownsFd_(false) {
  34. if (fd_ == -1) {
  35. throwSystemError(
  36. folly::format("open(\"{}\", {:#o}, 0{:#o}) failed", name, flags, mode)
  37. .fbstr());
  38. }
  39. ownsFd_ = true;
  40. }
  41. File::File(const std::string& name, int flags, mode_t mode)
  42. : File(name.c_str(), flags, mode) {}
  43. File::File(StringPiece name, int flags, mode_t mode)
  44. : File(name.str(), flags, mode) {}
  45. File::File(File&& other) noexcept : fd_(other.fd_), ownsFd_(other.ownsFd_) {
  46. other.release();
  47. }
  48. File& File::operator=(File&& other) {
  49. closeNoThrow();
  50. swap(other);
  51. return *this;
  52. }
  53. File::~File() {
  54. auto fd = fd_;
  55. if (!closeNoThrow()) { // ignore most errors
  56. DCHECK_NE(errno, EBADF)
  57. << "closing fd " << fd << ", it may already "
  58. << "have been closed. Another time, this might close the wrong FD.";
  59. }
  60. }
  61. /* static */ File File::temporary() {
  62. // make a temp file with tmpfile(), dup the fd, then return it in a File.
  63. FILE* tmpFile = tmpfile();
  64. checkFopenError(tmpFile, "tmpfile() failed");
  65. SCOPE_EXIT {
  66. fclose(tmpFile);
  67. };
  68. int fd = ::dup(fileno(tmpFile));
  69. checkUnixError(fd, "dup() failed");
  70. return File(fd, true);
  71. }
  72. int File::release() noexcept {
  73. int released = fd_;
  74. fd_ = -1;
  75. ownsFd_ = false;
  76. return released;
  77. }
  78. void File::swap(File& other) noexcept {
  79. using std::swap;
  80. swap(fd_, other.fd_);
  81. swap(ownsFd_, other.ownsFd_);
  82. }
  83. void swap(File& a, File& b) noexcept {
  84. a.swap(b);
  85. }
  86. File File::dup() const {
  87. if (fd_ != -1) {
  88. int fd = ::dup(fd_);
  89. checkUnixError(fd, "dup() failed");
  90. return File(fd, true);
  91. }
  92. return File();
  93. }
  94. void File::close() {
  95. if (!closeNoThrow()) {
  96. throwSystemError("close() failed");
  97. }
  98. }
  99. bool File::closeNoThrow() {
  100. int r = ownsFd_ ? ::close(fd_) : 0;
  101. release();
  102. return r == 0;
  103. }
  104. void File::lock() {
  105. doLock(LOCK_EX);
  106. }
  107. bool File::try_lock() {
  108. return doTryLock(LOCK_EX);
  109. }
  110. void File::lock_shared() {
  111. doLock(LOCK_SH);
  112. }
  113. bool File::try_lock_shared() {
  114. return doTryLock(LOCK_SH);
  115. }
  116. void File::doLock(int op) {
  117. checkUnixError(flockNoInt(fd_, op), "flock() failed (lock)");
  118. }
  119. bool File::doTryLock(int op) {
  120. int r = flockNoInt(fd_, op | LOCK_NB);
  121. // flock returns EWOULDBLOCK if already locked
  122. if (r == -1 && errno == EWOULDBLOCK) {
  123. return false;
  124. }
  125. checkUnixError(r, "flock() failed (try_lock)");
  126. return true;
  127. }
  128. void File::unlock() {
  129. checkUnixError(flockNoInt(fd_, LOCK_UN), "flock() failed (unlock)");
  130. }
  131. void File::unlock_shared() {
  132. unlock();
  133. }
  134. } // namespace folly