libsnapshot: Add an open /dev/null mode for CowWriter.
This will be used by payload_generator to estimate the COW size without using extra storage space. Bug: 168554689 Test: cow_api_test, ota_from_target_files Change-Id: I095c809e7d81eff5321b86f4c6bdfb6e9467e84e
This commit is contained in:
parent
f2609b2b0f
commit
1b9ab3f544
2 changed files with 37 additions and 8 deletions
|
@ -110,15 +110,28 @@ bool CowWriter::ParseOptions() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CowWriter::SetFd(android::base::borrowed_fd fd) {
|
||||
if (fd.get() < 0) {
|
||||
owned_fd_.reset(open("/dev/null", O_RDWR | O_CLOEXEC));
|
||||
if (owned_fd_ < 0) {
|
||||
PLOG(ERROR) << "open /dev/null failed";
|
||||
return false;
|
||||
}
|
||||
fd_ = owned_fd_;
|
||||
is_dev_null_ = true;
|
||||
} else {
|
||||
fd_ = fd;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CowWriter::Initialize(unique_fd&& fd, OpenMode mode) {
|
||||
owned_fd_ = std::move(fd);
|
||||
return Initialize(borrowed_fd{owned_fd_}, mode);
|
||||
}
|
||||
|
||||
bool CowWriter::Initialize(borrowed_fd fd, OpenMode mode) {
|
||||
fd_ = fd;
|
||||
|
||||
if (!ParseOptions()) {
|
||||
if (!SetFd(fd) || !ParseOptions()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -139,9 +152,7 @@ bool CowWriter::InitializeAppend(android::base::unique_fd&& fd, uint64_t label)
|
|||
}
|
||||
|
||||
bool CowWriter::InitializeAppend(android::base::borrowed_fd fd, uint64_t label) {
|
||||
fd_ = fd;
|
||||
|
||||
if (!ParseOptions()) {
|
||||
if (!SetFd(fd) || !ParseOptions()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -304,7 +315,7 @@ bool CowWriter::EmitLabel(uint64_t label) {
|
|||
CowOperation op = {};
|
||||
op.type = kCowLabelOp;
|
||||
op.source = label;
|
||||
return WriteOperation(op) && !fsync(fd_.get());
|
||||
return WriteOperation(op) && Sync();
|
||||
}
|
||||
|
||||
std::basic_string<uint8_t> CowWriter::Compress(const void* data, size_t length) {
|
||||
|
@ -383,7 +394,7 @@ bool CowWriter::Finalize() {
|
|||
PLOG(ERROR) << "lseek ops failed";
|
||||
return false;
|
||||
}
|
||||
return !fsync(fd_.get());
|
||||
return Sync();
|
||||
}
|
||||
|
||||
uint64_t CowWriter::GetCowSize() {
|
||||
|
@ -424,5 +435,16 @@ bool CowWriter::WriteRawData(const void* data, size_t size) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CowWriter::Sync() {
|
||||
if (is_dev_null_) {
|
||||
return true;
|
||||
}
|
||||
if (fsync(fd_.get()) < 0) {
|
||||
PLOG(ERROR) << "fsync failed";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
|
|
@ -90,6 +90,9 @@ class CowWriter : public ICowWriter {
|
|||
// If opening for write, the file starts from the beginning.
|
||||
// If opening for append, if the file has a footer, we start appending to the last op.
|
||||
// If the footer isn't found, the last label is considered corrupt, and dropped.
|
||||
//
|
||||
// If fd is < 0, the CowWriter will be opened against /dev/null. This is for
|
||||
// computing COW sizes without using storage space.
|
||||
bool Initialize(android::base::unique_fd&& fd, OpenMode mode = OpenMode::WRITE);
|
||||
bool Initialize(android::base::borrowed_fd fd, OpenMode mode = OpenMode::WRITE);
|
||||
// Set up a writer, assuming that the given label is the last valid label.
|
||||
|
@ -119,6 +122,9 @@ class CowWriter : public ICowWriter {
|
|||
void AddOperation(const CowOperation& op);
|
||||
std::basic_string<uint8_t> Compress(const void* data, size_t length);
|
||||
|
||||
bool SetFd(android::base::borrowed_fd fd);
|
||||
bool Sync();
|
||||
|
||||
private:
|
||||
android::base::unique_fd owned_fd_;
|
||||
android::base::borrowed_fd fd_;
|
||||
|
@ -126,6 +132,7 @@ class CowWriter : public ICowWriter {
|
|||
CowFooter footer_{};
|
||||
int compression_ = 0;
|
||||
uint64_t next_op_pos_ = 0;
|
||||
bool is_dev_null_ = false;
|
||||
|
||||
// :TODO: this is not efficient, but stringstream ubsan aborts because some
|
||||
// bytes overflow a signed char.
|
||||
|
|
Loading…
Reference in a new issue