FileUtil.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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/FileUtil.h>
  17. #include <cerrno>
  18. #include <string>
  19. #include <system_error>
  20. #include <vector>
  21. #include <folly/detail/FileUtilDetail.h>
  22. #include <folly/portability/Fcntl.h>
  23. #include <folly/portability/Sockets.h>
  24. #include <folly/portability/Stdlib.h>
  25. #include <folly/portability/SysFile.h>
  26. #include <folly/portability/SysStat.h>
  27. namespace folly {
  28. using namespace fileutil_detail;
  29. int openNoInt(const char* name, int flags, mode_t mode) {
  30. return int(wrapNoInt(open, name, flags, mode));
  31. }
  32. int closeNoInt(int fd) {
  33. int r = close(fd);
  34. // Ignore EINTR. On Linux, close() may only return EINTR after the file
  35. // descriptor has been closed, so you must not retry close() on EINTR --
  36. // in the best case, you'll get EBADF, and in the worst case, you'll end up
  37. // closing a different file (one opened from another thread).
  38. //
  39. // Interestingly enough, the Single Unix Specification says that the state
  40. // of the file descriptor is unspecified if close returns EINTR. In that
  41. // case, the safe thing to do is also not to retry close() -- leaking a file
  42. // descriptor is definitely better than closing the wrong file.
  43. if (r == -1 && errno == EINTR) {
  44. r = 0;
  45. }
  46. return r;
  47. }
  48. int fsyncNoInt(int fd) {
  49. return int(wrapNoInt(fsync, fd));
  50. }
  51. int dupNoInt(int fd) {
  52. return int(wrapNoInt(dup, fd));
  53. }
  54. int dup2NoInt(int oldfd, int newfd) {
  55. return int(wrapNoInt(dup2, oldfd, newfd));
  56. }
  57. int fdatasyncNoInt(int fd) {
  58. #if defined(__APPLE__)
  59. return int(wrapNoInt(fcntl, fd, F_FULLFSYNC));
  60. #elif defined(__FreeBSD__) || defined(_MSC_VER)
  61. return int(wrapNoInt(fsync, fd));
  62. #else
  63. return int(wrapNoInt(fdatasync, fd));
  64. #endif
  65. }
  66. int ftruncateNoInt(int fd, off_t len) {
  67. return int(wrapNoInt(ftruncate, fd, len));
  68. }
  69. int truncateNoInt(const char* path, off_t len) {
  70. return int(wrapNoInt(truncate, path, len));
  71. }
  72. int flockNoInt(int fd, int operation) {
  73. return int(wrapNoInt(flock, fd, operation));
  74. }
  75. int shutdownNoInt(int fd, int how) {
  76. return int(wrapNoInt(portability::sockets::shutdown, fd, how));
  77. }
  78. ssize_t readNoInt(int fd, void* buf, size_t count) {
  79. return wrapNoInt(read, fd, buf, count);
  80. }
  81. ssize_t preadNoInt(int fd, void* buf, size_t count, off_t offset) {
  82. return wrapNoInt(pread, fd, buf, count, offset);
  83. }
  84. ssize_t readvNoInt(int fd, const iovec* iov, int count) {
  85. return wrapNoInt(readv, fd, iov, count);
  86. }
  87. ssize_t writeNoInt(int fd, const void* buf, size_t count) {
  88. return wrapNoInt(write, fd, buf, count);
  89. }
  90. ssize_t pwriteNoInt(int fd, const void* buf, size_t count, off_t offset) {
  91. return wrapNoInt(pwrite, fd, buf, count, offset);
  92. }
  93. ssize_t writevNoInt(int fd, const iovec* iov, int count) {
  94. return wrapNoInt(writev, fd, iov, count);
  95. }
  96. ssize_t readFull(int fd, void* buf, size_t count) {
  97. return wrapFull(read, fd, buf, count);
  98. }
  99. ssize_t preadFull(int fd, void* buf, size_t count, off_t offset) {
  100. return wrapFull(pread, fd, buf, count, offset);
  101. }
  102. ssize_t writeFull(int fd, const void* buf, size_t count) {
  103. return wrapFull(write, fd, const_cast<void*>(buf), count);
  104. }
  105. ssize_t pwriteFull(int fd, const void* buf, size_t count, off_t offset) {
  106. return wrapFull(pwrite, fd, const_cast<void*>(buf), count, offset);
  107. }
  108. ssize_t readvFull(int fd, iovec* iov, int count) {
  109. return wrapvFull(readv, fd, iov, count);
  110. }
  111. ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset) {
  112. return wrapvFull(preadv, fd, iov, count, offset);
  113. }
  114. ssize_t writevFull(int fd, iovec* iov, int count) {
  115. return wrapvFull(writev, fd, iov, count);
  116. }
  117. ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset) {
  118. return wrapvFull(pwritev, fd, iov, count, offset);
  119. }
  120. int writeFileAtomicNoThrow(
  121. StringPiece filename,
  122. iovec* iov,
  123. int count,
  124. mode_t permissions) {
  125. // We write the data to a temporary file name first, then atomically rename
  126. // it into place. This ensures that the file contents will always be valid,
  127. // even if we crash or are killed partway through writing out data.
  128. //
  129. // Create a buffer that will contain two things:
  130. // - A nul-terminated version of the filename
  131. // - The temporary file name
  132. std::vector<char> pathBuffer;
  133. // Note that we have to explicitly pass in the size here to make
  134. // sure the nul byte gets included in the data.
  135. constexpr folly::StringPiece suffix(".XXXXXX\0", 8);
  136. pathBuffer.resize((2 * filename.size()) + 1 + suffix.size());
  137. // Copy in the filename and then a nul terminator
  138. memcpy(pathBuffer.data(), filename.data(), filename.size());
  139. pathBuffer[filename.size()] = '\0';
  140. const char* const filenameCStr = pathBuffer.data();
  141. // Now prepare the temporary path template
  142. char* const tempPath = pathBuffer.data() + filename.size() + 1;
  143. memcpy(tempPath, filename.data(), filename.size());
  144. memcpy(tempPath + filename.size(), suffix.data(), suffix.size());
  145. auto tmpFD = mkstemp(tempPath);
  146. if (tmpFD == -1) {
  147. return errno;
  148. }
  149. bool success = false;
  150. SCOPE_EXIT {
  151. if (tmpFD != -1) {
  152. close(tmpFD);
  153. }
  154. if (!success) {
  155. unlink(tempPath);
  156. }
  157. };
  158. auto rc = writevFull(tmpFD, iov, count);
  159. if (rc == -1) {
  160. return errno;
  161. }
  162. rc = fchmod(tmpFD, permissions);
  163. if (rc == -1) {
  164. return errno;
  165. }
  166. // Close the file before renaming to make sure all data has
  167. // been successfully written.
  168. rc = close(tmpFD);
  169. tmpFD = -1;
  170. if (rc == -1) {
  171. return errno;
  172. }
  173. rc = rename(tempPath, filenameCStr);
  174. if (rc == -1) {
  175. return errno;
  176. }
  177. success = true;
  178. return 0;
  179. }
  180. void writeFileAtomic(
  181. StringPiece filename,
  182. iovec* iov,
  183. int count,
  184. mode_t permissions) {
  185. auto rc = writeFileAtomicNoThrow(filename, iov, count, permissions);
  186. if (rc != 0) {
  187. auto msg = std::string(__func__) + "() failed to update " + filename.str();
  188. throw std::system_error(rc, std::generic_category(), msg);
  189. }
  190. }
  191. void writeFileAtomic(StringPiece filename, ByteRange data, mode_t permissions) {
  192. iovec iov;
  193. iov.iov_base = const_cast<unsigned char*>(data.data());
  194. iov.iov_len = data.size();
  195. writeFileAtomic(filename, &iov, 1, permissions);
  196. }
  197. void writeFileAtomic(
  198. StringPiece filename,
  199. StringPiece data,
  200. mode_t permissions) {
  201. writeFileAtomic(filename, ByteRange(data), permissions);
  202. }
  203. } // namespace folly