From 65bd5c05db2a050a4c0f26ccc0b1e9828b00abbf Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 3 Mar 2021 02:24:32 +0000 Subject: [linux] Do not assume that stat() works on sysfs files Linux kernel 3.12 and earlier report a zero size via stat() for all ACPI table files in sysfs. There is no way to determine the file size other than by reading the file until EOF. Signed-off-by: Michael Brown --- src/interface/linux/linux_sysfs.c | 49 ++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/src/interface/linux/linux_sysfs.c b/src/interface/linux/linux_sysfs.c index 463bc2a..4f0027c 100644 --- a/src/interface/linux/linux_sysfs.c +++ b/src/interface/linux/linux_sysfs.c @@ -32,6 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** Read blocksize */ +#define LINUX_SYSFS_BLKSIZE 4096 + /** * Read file from sysfs * @@ -40,9 +43,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret len Length read, or negative error */ int linux_sysfs_read ( const char *filename, userptr_t *data ) { - size_t offset; - size_t len; + userptr_t tmp; ssize_t read; + size_t len; int fd; int rc; @@ -55,37 +58,27 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) { goto err_open; } - /* Get file length */ - if ( linux_fstat_size ( fd, &len ) == -1 ) { - rc = -ELINUX ( linux_errno ); - DBGC ( filename, "LINUX could not stat %s: %s\n", - filename, linux_strerror ( linux_errno ) ); - goto err_stat; - } + /* Read file */ + for ( *data = UNULL, len = 0 ; ; len += read ) { - /* Allocate buffer */ - *data = umalloc ( len ); - if ( ! *data ) { - rc = -ENOMEM; - DBGC ( filename, "LINUX could not allocate %zd bytes for %s\n", - len, filename ); - goto err_alloc; - } + /* (Re)allocate space */ + tmp = urealloc ( *data, ( len + LINUX_SYSFS_BLKSIZE ) ); + if ( ! tmp ) { + rc = -ENOMEM; + goto err_alloc; + } + *data = tmp; - /* Read file */ - for ( offset = 0 ; offset < len ; offset += read ) { - read = linux_read ( fd, user_to_virt ( *data, offset ), len ); + /* Read from file */ + read = linux_read ( fd, user_to_virt ( *data, len ), + LINUX_SYSFS_BLKSIZE ); + if ( read == 0 ) + break; if ( read < 0 ) { DBGC ( filename, "LINUX could not read %s: %s\n", filename, linux_strerror ( linux_errno ) ); goto err_read; } - if ( read == 0 ) { - rc = -EIO; - DBGC ( filename, "LINUX read underlength %s\n", - filename ); - goto err_eof; - } } /* Close file */ @@ -94,11 +87,9 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) { DBGC ( filename, "LINUX read %s\n", filename ); return len; - err_eof: err_read: - ufree ( *data ); err_alloc: - err_stat: + ufree ( *data ); linux_close ( fd ); err_open: return rc; -- cgit v1.1