diff options
author | Bjorn Andersson <bjorn.andersson@linaro.org> | 2019-07-12 21:26:43 -0700 |
---|---|---|
committer | Bjorn Andersson <bjorn.andersson@linaro.org> | 2019-07-17 12:23:02 -0700 |
commit | c35633ab2312393b40bd07c8937a9d66672c89eb (patch) | |
tree | 66422823bca47e1c29442dcb50ea2d4a61bb8a11 | |
parent | e6d703b3c8b85a5d665e0f4fc4ebe43c32903126 (diff) |
storage: Allow read only backing storage
Add a new argument '-r' to prevent writes back to the backing storage.
This is useful for experimenting with the remote storage, without having
the files overwritten.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
-rw-r--r-- | rmtfs.c | 10 | ||||
-rw-r--r-- | rmtfs.h | 4 | ||||
-rw-r--r-- | storage.c | 136 |
3 files changed, 134 insertions, 16 deletions
@@ -449,17 +449,23 @@ static int run_rmtfs(void) int main(int argc, char **argv) { + bool read_only = false; int ret; int option; const char *storage_root = NULL; - while ((option = getopt(argc, argv, "o:v")) != -1) { + while ((option = getopt(argc, argv, "o:rv")) != -1) { switch (option) { /* -o sets the directory where EFS images are stored. */ case 'o': storage_root = optarg; break; + /* -r to avoid writing to storage */ + case 'r': + read_only = true; + break; + /* -v is for verbose */ case 'v': dbgprintf_enabled = 1; @@ -475,7 +481,7 @@ int main(int argc, char **argv) if (!rmem) return 1; - ret = storage_init(storage_root); + ret = storage_init(storage_root, read_only); if (ret) { fprintf(stderr, "failed to initialize storage system\n"); goto close_rmtfs_mem; @@ -25,7 +25,7 @@ ssize_t rmtfs_mem_write(struct rmtfs_mem *rmem, unsigned long phys_address, cons struct rmtfd; -int storage_init(const char *storage_root); +int storage_init(const char *storage_root, bool read_only); struct rmtfd *storage_open(unsigned node, const char *path); struct rmtfd *storage_get(unsigned node, int caller_id); void storage_close(struct rmtfd *rmtfd); @@ -33,6 +33,6 @@ int storage_get_caller_id(const struct rmtfd *rmtfd); int storage_get_error(const struct rmtfd *rmtfd); void storage_exit(void); ssize_t storage_pread(const struct rmtfd *rmtfd, void *buf, size_t nbyte, off_t offset); -ssize_t storage_pwrite(const struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset); +ssize_t storage_pwrite(struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset); #endif @@ -1,3 +1,4 @@ +#include <sys/stat.h> #include <sys/types.h> #include <errno.h> #include <fcntl.h> @@ -8,6 +9,9 @@ #include "rmtfs.h" #define MAX_CALLERS 10 +#define STORAGE_MAX_SIZE (16 * 1024 * 1024) + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) struct partition { const char *path; @@ -20,9 +24,13 @@ struct rmtfd { int fd; unsigned dev_error; const struct partition *partition; + + void *shadow_buf; + size_t shadow_len; }; static const char *storage_dir = "/boot"; +static int storage_read_only; static const struct partition partition_table[] = { { "/boot/modem_fs1", "modem_fs1" }, @@ -34,13 +42,17 @@ static const struct partition partition_table[] = { static struct rmtfd rmtfds[MAX_CALLERS]; -int storage_init(const char *storage_root) +static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file); + +int storage_init(const char *storage_root, bool read_only) { int i; if (storage_root) storage_dir = storage_root; + storage_read_only = read_only; + for (i = 0; i < MAX_CALLERS; i++) { rmtfds[i].id = i; rmtfds[i].fd = -1; @@ -56,6 +68,7 @@ struct rmtfd *storage_open(unsigned node, const char *path) struct rmtfd *rmtfd = NULL; size_t pathlen; int saved_errno; + int ret; int fd; int i; @@ -90,17 +103,29 @@ found: pathlen = strlen(storage_dir) + strlen(part->actual) + 2; fspath = alloca(pathlen); snprintf(fspath, pathlen, "%s/%s", storage_dir, part->actual); - fd = open(fspath, O_RDWR); - if (fd < 0) { - saved_errno = errno; - fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n", - fspath, part->path, strerror(saved_errno)); - errno = saved_errno; - return NULL; + if (!storage_read_only) { + fd = open(fspath, O_RDWR); + if (fd < 0) { + saved_errno = errno; + fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n", + fspath, part->path, strerror(saved_errno)); + errno = saved_errno; + return NULL; + } + rmtfd->fd = fd; + rmtfd->shadow_len = 0; + } else { + ret = storage_populate_shadow_buf(rmtfd, fspath); + if (ret < 0) { + saved_errno = errno; + fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n", + fspath, part->path, strerror(saved_errno)); + errno = saved_errno; + return NULL; + } } rmtfd->node = node; - rmtfd->fd = fd; rmtfd->partition = part; return rmtfd; @@ -110,6 +135,11 @@ void storage_close(struct rmtfd *rmtfd) { close(rmtfd->fd); rmtfd->fd = -1; + + free(rmtfd->shadow_buf); + rmtfd->shadow_buf = NULL; + rmtfd->shadow_len = 0; + rmtfd->partition = NULL; } @@ -149,11 +179,93 @@ void storage_exit(void) ssize_t storage_pread(const struct rmtfd *rmtfd, void *buf, size_t nbyte, off_t offset) { - return pread(rmtfd->fd, buf, nbyte, offset); + ssize_t n; + + if (!storage_read_only) { + n = pread(rmtfd->fd, buf, nbyte, offset); + } else { + n = MIN(nbyte, rmtfd->shadow_len - offset); + if (n > 0) + memcpy(buf, rmtfd->shadow_buf + offset, n); + else + n = 0; + } + + if (n < nbyte) + memset(buf + n, 0, nbyte - n); + + return nbyte; } -ssize_t storage_pwrite(const struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset) +ssize_t storage_pwrite(struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset) { - return pwrite(rmtfd->fd, buf, nbyte, offset); + size_t new_len = offset + nbyte; + void *new_buf; + + if (!storage_read_only) + return pwrite(rmtfd->fd, buf, nbyte, offset); + + if (new_len >= STORAGE_MAX_SIZE) { + fprintf(stderr, "write to %zd bytes exceededs max size\n", new_len); + errno = -EINVAL; + return -1; + } + + if (new_len > rmtfd->shadow_len) { + new_buf = realloc(rmtfd->shadow_buf, new_len); + if (!new_buf) { + errno = -ENOMEM; + return -1; + } + + rmtfd->shadow_buf = new_buf; + rmtfd->shadow_len = new_len; + } + + memcpy(rmtfd->shadow_buf + offset, buf, nbyte); + + return nbyte; } +static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file) +{ + ssize_t len; + ssize_t n; + void *buf; + int ret; + int fd; + + fd = open(file, O_RDONLY); + if (fd < 0) + return -1; + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + ret = -1; + goto err_close_fd; + } + + lseek(fd, 0, SEEK_SET); + + buf = calloc(1, len); + if (!buf) { + ret = -1; + goto err_close_fd; + } + + n = read(fd, buf, len); + if (n < 0) { + ret = -1; + goto err_close_fd; + } + + rmtfd->shadow_buf = buf; + rmtfd->shadow_len = n; + + ret = 0; + +err_close_fd: + close(fd); + + return ret; +} |