mirror of https://github.com/ipxe/ipxe.git
[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 <mcb30@ipxe.org>pull/310/head
parent
1c4917b6a7
commit
65bd5c05db
|
@ -32,6 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Read blocksize */
|
||||||
|
#define LINUX_SYSFS_BLKSIZE 4096
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read file from sysfs
|
* Read file from sysfs
|
||||||
*
|
*
|
||||||
|
@ -40,9 +43,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
* @ret len Length read, or negative error
|
* @ret len Length read, or negative error
|
||||||
*/
|
*/
|
||||||
int linux_sysfs_read ( const char *filename, userptr_t *data ) {
|
int linux_sysfs_read ( const char *filename, userptr_t *data ) {
|
||||||
size_t offset;
|
userptr_t tmp;
|
||||||
size_t len;
|
|
||||||
ssize_t read;
|
ssize_t read;
|
||||||
|
size_t len;
|
||||||
int fd;
|
int fd;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -55,37 +58,27 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) {
|
||||||
goto err_open;
|
goto err_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get file length */
|
/* Read file */
|
||||||
if ( linux_fstat_size ( fd, &len ) == -1 ) {
|
for ( *data = UNULL, len = 0 ; ; len += read ) {
|
||||||
rc = -ELINUX ( linux_errno );
|
|
||||||
DBGC ( filename, "LINUX could not stat %s: %s\n",
|
|
||||||
filename, linux_strerror ( linux_errno ) );
|
|
||||||
goto err_stat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate buffer */
|
/* (Re)allocate space */
|
||||||
*data = umalloc ( len );
|
tmp = urealloc ( *data, ( len + LINUX_SYSFS_BLKSIZE ) );
|
||||||
if ( ! *data ) {
|
if ( ! tmp ) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
DBGC ( filename, "LINUX could not allocate %zd bytes for %s\n",
|
|
||||||
len, filename );
|
|
||||||
goto err_alloc;
|
goto err_alloc;
|
||||||
}
|
}
|
||||||
|
*data = tmp;
|
||||||
|
|
||||||
/* Read file */
|
/* Read from file */
|
||||||
for ( offset = 0 ; offset < len ; offset += read ) {
|
read = linux_read ( fd, user_to_virt ( *data, len ),
|
||||||
read = linux_read ( fd, user_to_virt ( *data, offset ), len );
|
LINUX_SYSFS_BLKSIZE );
|
||||||
|
if ( read == 0 )
|
||||||
|
break;
|
||||||
if ( read < 0 ) {
|
if ( read < 0 ) {
|
||||||
DBGC ( filename, "LINUX could not read %s: %s\n",
|
DBGC ( filename, "LINUX could not read %s: %s\n",
|
||||||
filename, linux_strerror ( linux_errno ) );
|
filename, linux_strerror ( linux_errno ) );
|
||||||
goto err_read;
|
goto err_read;
|
||||||
}
|
}
|
||||||
if ( read == 0 ) {
|
|
||||||
rc = -EIO;
|
|
||||||
DBGC ( filename, "LINUX read underlength %s\n",
|
|
||||||
filename );
|
|
||||||
goto err_eof;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close file */
|
/* Close file */
|
||||||
|
@ -94,11 +87,9 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) {
|
||||||
DBGC ( filename, "LINUX read %s\n", filename );
|
DBGC ( filename, "LINUX read %s\n", filename );
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
err_eof:
|
|
||||||
err_read:
|
err_read:
|
||||||
ufree ( *data );
|
|
||||||
err_alloc:
|
err_alloc:
|
||||||
err_stat:
|
ufree ( *data );
|
||||||
linux_close ( fd );
|
linux_close ( fd );
|
||||||
err_open:
|
err_open:
|
||||||
return rc;
|
return rc;
|
||||||
|
|
Loading…
Reference in New Issue