blob: 3eed878d005bc6b9c9cf32efb578de4a8653c57a [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/storage/volume_image/utils/fd_reader.h"
#include <fcntl.h>
#include <lib/fit/result.h>
#include <sys/stat.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fbl/span.h>
#include <fbl/unique_fd.h>
#include <safemath/safe_conversions.h>
namespace storage::volume_image {
fit::result<FdReader, std::string> FdReader::Create(std::string_view path) {
if (path.empty()) {
return fit::error("Cannot obtain file descriptor from empty path.");
}
std::string pathname(path);
fbl::unique_fd fd(open(pathname.c_str(), O_RDONLY));
if (!fd.is_valid()) {
std::string error = "Failed to obtain file descriptor from ";
error.append(pathname).append(". More specifically ").append(strerror(errno));
return fit::error(error);
}
struct stat file_stats = {};
if (fstat(fd.get(), &file_stats) != 0) {
return fit::error("Failed to obtain size for file descriptor at " + std::string(path) +
". More specifically: " + strerror(errno));
}
return fit::ok(FdReader(std::move(fd), path, file_stats.st_size));
}
fit::result<void, std::string> FdReader::Read(uint64_t offset, fbl::Span<uint8_t> buffer) const {
size_t bytes_read = 0;
while (bytes_read < buffer.size()) {
uint8_t* destination = buffer.data() + bytes_read;
size_t remaining_bytes = buffer.size() - bytes_read;
off_t source_offset = offset + bytes_read;
ssize_t result = pread(fd_.get(), destination, remaining_bytes, source_offset);
if (result < 0) {
std::string_view error_description(strerror(errno));
std::string error = "Read failed from ";
error.append(name_).append(". More specifically ").append(error_description);
return fit::error(error);
}
if (result == 0) {
std::string_view error_description(strerror(errno));
std::string error = "Read failed from ";
error.append(name_).append(". End of file reached before reading requested bytes.");
return fit::error(error);
}
bytes_read += result;
}
return fit::ok();
}
} // namespace storage::volume_image