diff options
-rw-r--r-- | mboxd_windows.c | 7 | ||||
-rw-r--r-- | pnor_partition.cpp | 61 | ||||
-rw-r--r-- | pnor_partition.hpp | 36 | ||||
-rw-r--r-- | pnor_partition_table.cpp | 4 | ||||
-rw-r--r-- | test/vpnor/Makefile.am.include | 3 |
5 files changed, 77 insertions, 34 deletions
diff --git a/mboxd_windows.c b/mboxd_windows.c index fd679bc..9742180 100644 --- a/mboxd_windows.c +++ b/mboxd_windows.c @@ -619,7 +619,12 @@ int create_map_window(struct mbox_context *context, reset_window(context, cur); return rc; } - /* rc isn't guaranteed to be aligned, so align up */ + /* + * rc isn't guaranteed to be aligned, so align up + * + * FIXME: This should only be the case for the vpnor ToC now, so handle + * it there + */ cur->size = align_up(rc, (1ULL << context->block_size_shift)); /* Would like a known value, pick 0xFF to it looks like erased flash */ memset(cur->mem + rc, 0xFF, cur->size - rc); diff --git a/pnor_partition.cpp b/pnor_partition.cpp index 390c4d5..84aeb3f 100644 --- a/pnor_partition.cpp +++ b/pnor_partition.cpp @@ -10,11 +10,14 @@ #include <phosphor-logging/elog-errors.hpp> #include <assert.h> +#include <fcntl.h> #include <stdint.h> #include <stdlib.h> #include <syslog.h> +#include <sys/types.h> #include <sys/ioctl.h> #include <sys/mman.h> +#include <unistd.h> #include "common.h" @@ -86,7 +89,31 @@ fs::path Request::getPartitionFilePath(int flags) return dst; } -ssize_t Request::fulfil(void *buf, size_t len, int flags) +size_t Request::clamp(size_t len) +{ + size_t maxAccess = offset + len; + size_t partSize = partition.data.size << ctx->block_size_shift; + return std::min(maxAccess, partSize) - offset; +} + +void Request::resize(const fs::path &path, size_t len) +{ + size_t maxAccess = offset + len; + size_t fileSize = fs::file_size(path); + if (maxAccess < fileSize) + { + return; + } + MSG_DBG("Resizing %s to %zu bytes\n", path.c_str(), maxAccess); + int rc = truncate(path.c_str(), maxAccess); + if (rc == -1) + { + MSG_ERR("Failed to resize %s: %d\n", path.c_str(), errno); + throw std::system_error(errno, std::system_category()); + } +} + +size_t Request::fulfil(const fs::path &path, int flags, void *buf, size_t len) { if (!(flags == O_RDONLY || flags == O_RDWR)) { @@ -96,8 +123,6 @@ ssize_t Request::fulfil(void *buf, size_t len, int flags) throw std::invalid_argument(err.str()); } - fs::path path = getPartitionFilePath(flags); - int fd = ::open(path.c_str(), flags); if (fd == -1) { @@ -106,45 +131,29 @@ ssize_t Request::fulfil(void *buf, size_t len, int flags) throw std::system_error(errno, std::system_category()); } + size_t fileSize = fs::file_size(path); int mprot = PROT_READ | ((flags == O_RDWR) ? PROT_WRITE : 0); - auto map = mmap(NULL, partition.data.actual, mprot, MAP_SHARED, fd, 0); + auto map = mmap(NULL, fileSize, mprot, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { close(fd); - MSG_ERR("Failed to map backing file '%s' for %d bytes: %d\n", - path.c_str(), partition.data.actual, errno); + MSG_ERR("Failed to map backing file '%s' for %zd bytes: %d\n", + path.c_str(), fileSize, errno); throw std::system_error(errno, std::system_category()); } // copy to the reserved memory area if (flags == O_RDONLY) { - len = std::min(partition.data.actual - offset, len); - memcpy(buf, (char *)map + offset, len); + memset(buf, 0xff, len); + memcpy(buf, (char *)map + offset, std::min(len, fileSize)); } else { - // if the asked offset + no of bytes to read is greater - // then size of the partition file then throw error. - // - // FIXME: Don't use .actual, use (.size << ctx->block_size_shift), - // otherwise we can't grow the size of the data to fill the partition - if ((base + offset + len) > (base + partition.data.actual)) - { - munmap(map, partition.data.actual); - close(fd); - - /* FIXME: offset calculation */ - std::stringstream err; - err << "Request size 0x" << std::hex << len << " from offset 0x" - << std::hex << offset << " exceeds the partition size 0x" - << std::hex << partition.data.actual; - throw OutOfBoundsOffset(err.str()); - } memcpy((char *)map + offset, buf, len); set_flash_bytemap(ctx, base + offset, len, FLASH_DIRTY); } - munmap(map, partition.data.actual); + munmap(map, fileSize); close(fd); return len; diff --git a/pnor_partition.hpp b/pnor_partition.hpp index 80777ce..eb63a39 100644 --- a/pnor_partition.hpp +++ b/pnor_partition.hpp @@ -48,15 +48,44 @@ class Request ssize_t read(void* dst, size_t len) { - return fulfil(dst, len, O_RDONLY); + len = clamp(len); + constexpr auto flags = O_RDONLY; + fs::path path = getPartitionFilePath(flags); + return fulfil(path, flags, dst, len); } ssize_t write(void* dst, size_t len) { - return fulfil(dst, len, O_RDWR); + if (len != clamp(len)) + { + std::stringstream err; + err << "Request size 0x" << std::hex << len << " from offset 0x" + << std::hex << offset << " exceeds the partition size 0x" + << std::hex << (partition.data.size << ctx->block_size_shift); + throw OutOfBoundsOffset(err.str()); + } + constexpr auto flags = O_RDWR; + /* Ensure file is at least the size of the maximum access */ + fs::path path = getPartitionFilePath(flags); + resize(path, len); + return fulfil(path, flags, dst, len); } private: + /** @brief Clamp the access length to the maximum supported by the ToC */ + size_t clamp(size_t len); + + /** @brief Ensure the backing file is sized appropriately for the access + * + * We need to ensure the file is big enough to satisfy the request so that + * mmap() will succeed for the required size. + * + * @return The valid access length + * + * Throws: std::system_error + */ + void resize(const std::experimental::filesystem::path& path, size_t len); + /** @brief Returns the partition file path associated with the offset. * * The search strategy for the partition file depends on the value of the @@ -97,7 +126,8 @@ class Request * @param[out] dst - The buffer to fill with partition data * @param[in] len - The length of the destination buffer */ - ssize_t fulfil(void* dst, size_t len, int flags); + size_t fulfil(const std::experimental::filesystem::path& path, int flags, + void* dst, size_t len); struct mbox_context* ctx; const pnor_partition& partition; diff --git a/pnor_partition_table.cpp b/pnor_partition_table.cpp index 376b191..4ad07bc 100644 --- a/pnor_partition_table.cpp +++ b/pnor_partition_table.cpp @@ -154,8 +154,10 @@ const pnor_partition& Table::partition(size_t offset) const for (decltype(numParts) i{}; i < numParts; ++i) { const struct pnor_partition& part = table.partitions[i]; + size_t len = part.data.size; + if ((blockOffset >= part.data.base) && - (blockOffset < (part.data.base + part.data.size))) + (blockOffset < (part.data.base + len))) { return part; } diff --git a/test/vpnor/Makefile.am.include b/test/vpnor/Makefile.am.include index 8d0dd65..09a4cc8 100644 --- a/test/vpnor/Makefile.am.include +++ b/test/vpnor/Makefile.am.include @@ -274,7 +274,4 @@ check_PROGRAMS += \ %reldir%/create_read_window_partition_invalid \ %reldir%/read_patch \ %reldir%/write_patch_resize - -XFAIL_TESTS += %reldir%/read_patch -XFAIL_TESTS += %reldir%/write_patch_resize endif |