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