mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-10 01:17:44 +03:00
Merge pull request #19157 from keszybz/read-medium-sized-virtual-file
basic/fileio: fix reading of not-too-small virtual files
This commit is contained in:
commit
938bdfc0fa
@ -385,20 +385,10 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
/* Start size for files in /proc/ which usually report a file size of 0. (Files in /sys/ report a
|
||||
* file size of 4K, which is probably OK for sizing our initial buffer, and sysfs attributes can't be
|
||||
* larger anyway.)
|
||||
*
|
||||
* It's one less than 4k, so that the malloc() below allocates exactly 4k. */
|
||||
size = 4095;
|
||||
|
||||
/* Limit the number of attempts to read the number of bytes returned by fstat(). */
|
||||
n_retries = 3;
|
||||
|
||||
for (;;) {
|
||||
if (n_retries <= 0)
|
||||
return -EIO;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
@ -409,24 +399,20 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
|
||||
assert_cc(READ_FULL_BYTES_MAX < SSIZE_MAX);
|
||||
if (st.st_size > 0) {
|
||||
if (st.st_size > READ_FULL_BYTES_MAX)
|
||||
return -E2BIG;
|
||||
return -EFBIG;
|
||||
|
||||
size = st.st_size;
|
||||
n_retries--;
|
||||
} else {
|
||||
/* Double the buffer size */
|
||||
if (size >= READ_FULL_BYTES_MAX)
|
||||
return -E2BIG;
|
||||
if (size > READ_FULL_BYTES_MAX / 2 - 1)
|
||||
size = READ_FULL_BYTES_MAX; /* clamp to max */
|
||||
else
|
||||
size = size * 2 + 1; /* Stay always one less than page size, so we malloc evenly */
|
||||
size = READ_FULL_BYTES_MAX;
|
||||
n_retries = 0;
|
||||
}
|
||||
|
||||
buf = malloc(size + 1);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
size = malloc_usable_size(buf) - 1; /* Use a bigger allocation if we got it anyway */
|
||||
/* Use a bigger allocation if we got it anyway, but not more than the limit. */
|
||||
size = MIN(malloc_usable_size(buf) - 1, READ_FULL_BYTES_MAX);
|
||||
|
||||
for (;;) {
|
||||
ssize_t k;
|
||||
@ -453,6 +439,9 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
|
||||
* processing, let's try again either with a bigger guessed size or the new
|
||||
* file size. */
|
||||
|
||||
if (n_retries <= 0)
|
||||
return st.st_size > 0 ? -EIO : -EFBIG;
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET) < 0)
|
||||
return -errno;
|
||||
|
||||
@ -466,8 +455,7 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
|
||||
p = realloc(buf, n + 1);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = TAKE_PTR(p);
|
||||
buf = p;
|
||||
}
|
||||
|
||||
if (ret_size)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "ctype.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
@ -964,6 +965,24 @@ static void test_read_full_file_offset_size(void) {
|
||||
rbuf = mfree(rbuf);
|
||||
}
|
||||
|
||||
static void test_read_full_virtual_file(void) {
|
||||
const char *filename;
|
||||
int r;
|
||||
|
||||
FOREACH_STRING(filename,
|
||||
"/proc/1/cmdline",
|
||||
"/etc/nsswitch.conf",
|
||||
"/sys/kernel/uevent_seqnum") {
|
||||
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
r = read_full_virtual_file(filename, &buf, &size);
|
||||
log_info_errno(r, "read_full_virtual_file(\"%s\"): %m (%zu bytes)", filename, size);
|
||||
assert_se(r == 0 || ERRNO_IS_PRIVILEGE(r) || r == -ENOENT);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
@ -991,6 +1010,7 @@ int main(int argc, char *argv[]) {
|
||||
test_read_nul_string();
|
||||
test_read_full_file_socket();
|
||||
test_read_full_file_offset_size();
|
||||
test_read_full_virtual_file();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user