From 967dd0d48eb0f0c2bf57d58b887e691daea7bd1e Mon Sep 17 00:00:00 2001 From: Nico Huber Date: Sun, 9 Jul 2017 15:51:08 +0200 Subject: [PATCH] posix file: Add an `Offset` parameter and make `Len` optional Give Map() an `Offset` parameter that will be passed to mmap(). Make the `Len` parameter of Map() optional. If it's left at the default, `0`, map until the end of the file (up to SIZE_MAX bytes). Change-Id: I7b062ce1e9cddab87a66a2aedc8b64e4e8524d9f Signed-off-by: Nico Huber Reviewed-on: https://review.coreboot.org/20553 Reviewed-by: Stefan Reinauer --- ada/posix/hw-file.adb | 5 +++- c/hw-file.c | 59 +++++++++++++++++++++++++++++++++---------- common/hw-file.ads | 11 +++++--- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/ada/posix/hw-file.adb b/ada/posix/hw-file.adb index d9b15ba776..e2384bee85 100644 --- a/ada/posix/hw-file.adb +++ b/ada/posix/hw-file.adb @@ -29,6 +29,7 @@ package body HW.File is (addr : out Word64; path : chars_ptr; len : Word32; + off : Word32; mode : Word32; copy : int) return int; @@ -37,7 +38,8 @@ package body HW.File is procedure Map (Addr : out Word64; Path : in String; - Len : in Natural; + Len : in Natural := 0; + Offset : in Natural := 0; Readable : in Boolean := False; Writable : in Boolean := False; Map_Copy : in Boolean := False; @@ -50,6 +52,7 @@ package body HW.File is (addr => Addr, path => cpath, len => Word32 (Len), + off => Word32 (Offset), mode => (if Readable then READ else 0) or (if Writable then WRITE else 0), copy => (if Map_Copy then 1 else 0)); diff --git a/c/hw-file.c b/c/hw-file.c index 7a9478d829..afa62a0374 100644 --- a/c/hw-file.c +++ b/c/hw-file.c @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include #include @@ -21,9 +23,26 @@ #define HW_FILE_READ 0x01 #define HW_FILE_WRITE 0x02 +static size_t stat_length(size_t *const len, const size_t off, const int fd) +{ + struct stat statbuf; + + if (*len == 0 && !fstat(fd, &statbuf)) { + if (statbuf.st_size == 0) + errno = EINVAL; + else if (statbuf.st_size - (off_t)off <= SIZE_MAX) + *len = (size_t)(statbuf.st_size - (off_t)off); + else + *len = SIZE_MAX; + } + + return *len; +} + static int map_file(uint64_t *const addr, const char *const path, - const uint32_t len, + size_t len, + const size_t off, const uint32_t mode) { const int prot = (mode & HW_FILE_READ ? PROT_READ : 0) | @@ -37,7 +56,12 @@ static int map_file(uint64_t *const addr, if (fd < 0) return errno; - void *const mapped = mmap(NULL, len, prot, MAP_SHARED, fd, (off_t)0); + if (!stat_length(&len, off, fd)) { + close(fd); + return errno; + } + + void *const mapped = mmap(NULL, len, prot, MAP_SHARED, fd, (off_t)off); close(fd); if (mapped == MAP_FAILED) return errno; @@ -48,23 +72,27 @@ static int map_file(uint64_t *const addr, static int map_fill_from_file(uint64_t *const addr, const char *const path, - const uint32_t len, + size_t len, + const size_t off, const uint32_t mode) { - uint32_t xferred; + size_t xferred; ssize_t read_ret; if (mode != HW_FILE_READ) return EINVAL; - void *const mapped = mmap(NULL, len, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, (off_t)0); - if (mapped == MAP_FAILED) - return errno; - const int fd = open(path, O_RDONLY); if (fd < 0) - goto _munmap; + return errno; + + if (!stat_length(&len, off, fd)) + goto _close; + + void *const mapped = mmap(NULL, len, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, (off_t)off); + if (mapped == MAP_FAILED) + goto _close; xferred = 0; do { @@ -73,7 +101,6 @@ static int map_fill_from_file(uint64_t *const addr, xferred += read_ret; } while ((read_ret > 0 || (read_ret == -1 && errno == EINTR)) && xferred < len); - close(fd); if (xferred < len) goto _munmap; @@ -81,22 +108,28 @@ static int map_fill_from_file(uint64_t *const addr, if (mprotect(mapped, len, PROT_READ)) goto _munmap; + close(fd); + *addr = (uint64_t)(uintptr_t)mapped; return 0; _munmap: munmap(mapped, len); +_close: + close(fd); return errno; } int hw_file_map(uint64_t *const addr, const char *const path, const uint32_t len, + const uint32_t off, const uint32_t mode, const int copy) { if (copy) - return map_fill_from_file(addr, path, len, mode); + return map_fill_from_file( + addr, path, (size_t)len, (size_t)off, mode); else - return map_file(addr, path, len, mode); + return map_file(addr, path, (size_t)len, (size_t)off, mode); } diff --git a/common/hw-file.ads b/common/hw-file.ads index 57cf42978a..9dbfcf77d7 100644 --- a/common/hw-file.ads +++ b/common/hw-file.ads @@ -17,17 +17,20 @@ package HW.File is -- -- Map a file's content into our address space -- - -- If `Map_Copy` is `False`, `Len` bytes from the start of the file - -- given by `Path` shall be mapped into the application's address - -- space using mmap(). + -- If `Map_Copy` is `False`, `Len` bytes at `Offset` from the start + -- of the file given by `Path` should be mapped into the application's + -- address space using mmap(). -- -- If `Map_Copy` is `True`, anonymous memory should be mapped instead -- and be filled with a copy of the file's content using read(). -- + -- If `Len` is zero, the whole file should be mapped. + -- procedure Map (Addr : out Word64; Path : in String; - Len : in Natural; + Len : in Natural := 0; + Offset : in Natural := 0; Readable : in Boolean := False; Writable : in Boolean := False; Map_Copy : in Boolean := False;