In guestfs_readdir(), the daemon currently sends each XDR-encoded
"guestfs_int_dirent" to the library with a separate send_file_write()
call.
Determine the largest encoded size (from the longest filename that a
"guestfs_int_dirent" could carry, from readdir()'s "struct dirent"), and
batch up the XDR encodings until the next encoding might not fit in
GUESTFS_MAX_CHUNK_SIZE. Call send_file_write() only then.
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1674392
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20220502085601.15012-3-lersek@redhat.com>
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
Currently the guestfs_readdir() API can not list long directories, due to
it sending back the whole directory listing in a single guestfs protocol
response, which is limited to GUESTFS_MESSAGE_MAX (approx. 4MB) in size.
Introduce the "internal_readdir" action, for transferring the directory
listing from the daemon to the library through a FileOut parameter.
Rewrite guestfs_readdir() on top of this new internal function:
- The new "internal_readdir" action is a daemon action. Do not repurpose
the "readdir" proc_nr (138) for "internal_readdir", as some distros ship
the binary appliance to their users, and reusing the proc_nr could
create a mismatch between library & appliance with obscure symptoms.
Replace the old proc_nr (138) with a new proc_nr (511) instead; a
mismatch would then produce a clear error message. Assume the new action
will first be released in libguestfs-1.48.2.
- Turn "readdir" from a daemon action into a non-daemon one. Call the
daemon action guestfs_internal_readdir() manually, receive the FileOut
parameter into a temp file, then deserialize the dirents array from the
temp file.
This patch sneakily fixes an independent bug, too. In the pre-patch
do_readdir() function [daemon/readdir.c], when readdir() returns NULL, we
don't distinguish "end of directory stream" from "readdir() failed". This
rewrite fixes this problem -- I didn't see much value separating out the
fix for the original do_readdir().
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1674392
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20220502085601.15012-2-lersek@redhat.com>
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
If "strdup (d->d_name)" fails with "i" > 0, then both "p" and
"ret->guestfs_int_dirent_list_val" are non-null pointers, but the latter
is no more valid (since "p" is the new realloc'ed buffer). Hence, trying
to free both will access to invalid memory.
Make sure to free only one of them, "p" if not null or
"ret->guestfs_int_dirent_list_val" otherwise.
inotify: Make this optional on platforms that don't have this interface.
mknod, mkfifo etc.: Make these optional on non-Unix platforms.
readdir: If d_type field is missing on the platform, set the corresponding
field to 'u'.
stat: st_blocks and st_blksize are missing on non-Unix platforms, so
set these fields to -1 in the corresponding structures.
Nearly every file-related function in daemons/*.c is affected:
Remove this pair of statements from each affected do_* function:
- NEED_ROOT (return -1);
- ABS_PATH (dir, return -1);
and change the type of the corresponding parameter to "const char *".
* src/generator.ml: Emit NEED_ROOT just once, even when there are two or
more Pathname args.
This adds a readdir call (mostly intended for programs). The
return value is a list of guestfs_dirent structures.
This adds the new types 'struct guestfs_dirent' and
'struct guestfs_dirent_list', along with all the code to
return these in the different language bindings.
Also includes additional tests for OCaml and Perl bindings
to test this.