fastbootd: add support to reset fd by handle

There are cases where the flags the file descriptor was opened with need
to be modified. This CL adds functionality to reset the file descriptor
held by a PartitionHandle, reopening with new flags and repositioning
file offset to previous.

Bug: 225108941
Signed-off-by: Konstantin Vyshetsky <vkon@google.com>
Change-Id: I9adb0e7696bc6af74e14dd61a6cb0ef10b4c98c8
This commit is contained in:
Konstantin Vyshetsky 2022-03-17 17:57:28 -07:00
parent b3e1829421
commit 1cee2ed239
2 changed files with 44 additions and 9 deletions

View file

@ -90,14 +90,7 @@ bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHan
return false;
}
flags |= (O_EXCL | O_CLOEXEC | O_BINARY);
unique_fd fd(TEMP_FAILURE_RETRY(open(handle->path().c_str(), flags)));
if (fd < 0) {
PLOG(ERROR) << "Failed to open block device: " << handle->path();
return false;
}
handle->set_fd(std::move(fd));
return true;
return handle->Open(flags);
}
std::optional<std::string> FindPhysicalPartition(const std::string& name) {

View file

@ -18,6 +18,8 @@
#include <optional>
#include <string>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <android/hardware/boot/1.0/IBootControl.h>
#include <fstab/fstab.h>
@ -44,11 +46,51 @@ class PartitionHandle {
}
const std::string& path() const { return path_; }
int fd() const { return fd_.get(); }
void set_fd(android::base::unique_fd&& fd) { fd_ = std::move(fd); }
bool Open(int flags) {
flags |= (O_EXCL | O_CLOEXEC | O_BINARY);
// Attempts to open a second device can fail with EBUSY if the device is already open.
// Explicitly close any previously opened devices as unique_fd won't close them until
// after the attempt to open.
fd_.reset();
fd_ = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path_.c_str(), flags)));
if (fd_ < 0) {
PLOG(ERROR) << "Failed to open block device: " << path_;
return false;
}
flags_ = flags;
return true;
}
bool Reset(int flags) {
if (fd_.ok() && (flags | O_EXCL | O_CLOEXEC | O_BINARY) == flags_) {
return true;
}
off_t offset = fd_.ok() ? lseek(fd_.get(), 0, SEEK_CUR) : 0;
if (offset < 0) {
PLOG(ERROR) << "Failed lseek on block device: " << path_;
return false;
}
sync();
if (Open(flags) == false) {
return false;
}
if (lseek(fd_.get(), offset, SEEK_SET) != offset) {
PLOG(ERROR) << "Failed lseek on block device: " << path_;
return false;
}
return true;
}
private:
std::string path_;
android::base::unique_fd fd_;
int flags_;
std::function<void()> closer_;
};