1 #ifndef UTIL_FILE_H 2 #define UTIL_FILE_H 3 4 #include "util/exception.hh" 5 #include "util/scoped.hh" 6 #include "util/string_piece.hh" 7 8 #include <cstddef> 9 #include <cstdio> 10 #include <string> 11 #include <stdint.h> 12 13 namespace util { 14 15 class scoped_fd { 16 public: scoped_fd()17 scoped_fd() : fd_(-1) {} 18 scoped_fd(int fd)19 explicit scoped_fd(int fd) : fd_(fd) {} 20 21 ~scoped_fd(); 22 23 #if __cplusplus >= 201103L scoped_fd(scoped_fd && from)24 scoped_fd(scoped_fd &&from) noexcept : fd_(from.fd_) { 25 from.fd_ = -1; 26 } 27 #endif 28 reset(int to=-1)29 void reset(int to = -1) { 30 scoped_fd other(fd_); 31 fd_ = to; 32 } 33 get() const34 int get() const { return fd_; } 35 operator *() const36 int operator*() const { return fd_; } 37 release()38 int release() { 39 int ret = fd_; 40 fd_ = -1; 41 return ret; 42 } 43 44 private: 45 int fd_; 46 47 scoped_fd(const scoped_fd &); 48 scoped_fd &operator=(const scoped_fd &); 49 }; 50 51 struct scoped_FILE_closer { 52 static void Close(std::FILE *file); 53 }; 54 typedef scoped<std::FILE, scoped_FILE_closer> scoped_FILE; 55 56 /* Thrown for any operation where the fd is known. */ 57 class FDException : public ErrnoException { 58 public: 59 explicit FDException(int fd) throw(); 60 61 virtual ~FDException() throw(); 62 63 // This may no longer be valid if the exception was thrown past open. FD() const64 int FD() const { return fd_; } 65 66 // Guess from NameFromFD. NameGuess() const67 const std::string &NameGuess() const { return name_guess_; } 68 69 private: 70 int fd_; 71 72 std::string name_guess_; 73 }; 74 75 // End of file reached. 76 class EndOfFileException : public Exception { 77 public: 78 EndOfFileException() throw(); 79 ~EndOfFileException() throw(); 80 }; 81 82 class UnsupportedOSException : public Exception {}; 83 84 // Open for read only. 85 int OpenReadOrThrow(const char *name); 86 // Create file if it doesn't exist, truncate if it does. Opened for write. 87 int CreateOrThrow(const char *name); 88 89 /** Does the given input file path denote standard input? 90 * 91 * Returns true if, and only if, path is either "-" or "/dev/stdin". 92 * 93 * Opening standard input as a file may need some special treatment for 94 * portability. There's a convention that a dash ("-") in place of an input 95 * file path denotes standard input, but opening "/dev/stdin" may need to be 96 * special as well. 97 */ 98 bool InputPathIsStdin(StringPiece path); 99 100 /** Does the given output file path denote standard output? 101 * 102 * Returns true if, and only if, path is either "-" or "/dev/stdout". 103 * 104 * Opening standard output as a file may need some special treatment for 105 * portability. There's a convention that a dash ("-") in place of an output 106 * file path denotes standard output, but opening "/dev/stdout" may need to be 107 * special as well. 108 */ 109 bool OutputPathIsStdout(StringPiece path); 110 111 // Return value for SizeFile when it can't size properly. 112 const uint64_t kBadSize = (uint64_t)-1; 113 uint64_t SizeFile(int fd); 114 uint64_t SizeOrThrow(int fd); 115 116 void ResizeOrThrow(int fd, uint64_t to); 117 118 // It bothers me that fallocate has offset before size while pread has size 119 // before offset. But best to follow the call. 120 void HolePunch(int fd, uint64_t offset, uint64_t size); 121 122 std::size_t PartialRead(int fd, void *to, std::size_t size); 123 void ReadOrThrow(int fd, void *to, std::size_t size); 124 std::size_t ReadOrEOF(int fd, void *to_void, std::size_t size); 125 126 void WriteOrThrow(int fd, const void *data_void, std::size_t size); 127 void WriteOrThrow(FILE *to, const void *data, std::size_t size); 128 129 /* These call pread/pwrite in a loop. However, on Windows they call ReadFile/ 130 * WriteFile which changes the file pointer. So it's safe to call ErsatzPRead 131 * and ErsatzPWrite concurrently (or any combination thereof). But it changes 132 * the file pointer on windows, so it's not safe to call concurrently with 133 * anything that uses the implicit file pointer e.g. the Read/Write functions 134 * above. 135 */ 136 void ErsatzPRead(int fd, void *to, std::size_t size, uint64_t off); 137 void ErsatzPWrite(int fd, const void *data_void, std::size_t size, uint64_t off); 138 139 void FSyncOrThrow(int fd); 140 141 // Seeking: returns offset 142 uint64_t SeekOrThrow(int fd, uint64_t off); 143 uint64_t AdvanceOrThrow(int fd, int64_t off); 144 uint64_t SeekEnd(int fd); 145 146 std::FILE *FDOpenOrThrow(scoped_fd &file); 147 std::FILE *FDOpenReadOrThrow(scoped_fd &file); 148 149 // Temporary files 150 // Append a / if base is a directory. 151 void NormalizeTempPrefix(std::string &base); 152 int MakeTemp(const StringPiece &prefix); 153 std::FILE *FMakeTemp(const StringPiece &prefix); 154 155 // Where should we put temporary files? Handles all the windows/POSIX defaults fun. 156 std::string DefaultTempDirectory(); 157 158 // dup an fd. 159 int DupOrThrow(int fd); 160 161 /* Attempt get file name from fd. This won't always work (i.e. on Windows or 162 * a pipe). The file might have been renamed. It's intended for diagnostics 163 * and logging only. 164 */ 165 std::string NameFromFD(int fd); 166 167 } // namespace util 168 169 #endif // UTIL_FILE_H 170