guestfs_read_file: Reimplement to avoid protocol limits.

This commit is contained in:
Richard W.M. Jones
2012-08-17 10:36:23 +01:00
parent 9d85eba3c3
commit 96d3ac28d6
4 changed files with 27 additions and 92 deletions

1
TODO
View File

@@ -567,7 +567,6 @@ the p.o.v of the API and ABI.
- guestfs_lstatlist
- guestfs_lxattrlist
- guestfs_read_file
- guestfs_read_lines
- guestfs_readlinklist
- guestfs_write

View File

@@ -314,65 +314,6 @@ do_write_append (const char *path, const char *content, size_t size)
return 0;
}
char *
do_read_file (const char *path, size_t *size_r)
{
int fd;
struct stat statbuf;
char *r;
CHROOT_IN;
fd = open (path, O_RDONLY|O_CLOEXEC);
CHROOT_OUT;
if (fd == -1) {
reply_with_perror ("open: %s", path);
return NULL;
}
if (fstat (fd, &statbuf) == -1) {
reply_with_perror ("fstat: %s", path);
close (fd);
return NULL;
}
/* The actual limit on messages is smaller than this. This
* check just limits the amount of memory we'll try and allocate
* here. If the message is larger than the real limit, that will
* be caught later when we try to serialize the message.
*/
if (statbuf.st_size >= GUESTFS_MESSAGE_MAX) {
reply_with_error ("%s: file is too large for the protocol, use guestfs_download instead", path);
close (fd);
return NULL;
}
r = malloc (statbuf.st_size);
if (r == NULL) {
reply_with_perror ("malloc");
close (fd);
return NULL;
}
if (xread (fd, r, statbuf.st_size) == -1) {
reply_with_perror ("read: %s", path);
close (fd);
free (r);
return NULL;
}
if (close (fd) == -1) {
reply_with_perror ("close: %s", path);
free (r);
return NULL;
}
/* Mustn't touch *size_r until we are sure that we won't return any
* error (RHBZ#589039).
*/
*size_r = statbuf.st_size;
return r;
}
static char *
pread_fd (int fd, int count, int64_t offset, size_t *size_r,
const char *display_path)

View File

@@ -2044,6 +2044,21 @@ this limit has been lifted and the call can download and
return an arbitrary list of files (limited by the amount of
memory available)." };
{ defaults with
name = "read_file";
style = RBufferOut "content", [Pathname "path"], [];
tests = [
InitISOFS, Always, TestOutputBuffer (
[["read_file"; "/known-4"]], "abc\ndef\nghi")
];
shortdesc = "read a file";
longdesc = "\
This calls returns the contents of the file C<path> as a
buffer.
Unlike C<guestfs_cat>, this function can correctly
handle files that contain embedded ASCII NUL characters." };
]
(* daemon_functions are any functions which cause some action
@@ -5168,38 +5183,6 @@ This calls removes a mountpoint that was previously created
with C<guestfs_mkmountpoint>. See C<guestfs_mkmountpoint>
for full details." };
{ defaults with
name = "read_file";
style = RBufferOut "content", [Pathname "path"], [];
proc_nr = Some 150;
protocol_limit_warning = true;
tests = [
InitISOFS, Always, TestOutputBuffer (
[["read_file"; "/known-4"]], "abc\ndef\nghi");
(* Test various near large, large and too large files (RHBZ#589039). *)
InitScratchFS, Always, TestLastFail (
[["touch"; "/read_file"];
["truncate_size"; "/read_file"; "4194303"]; (* GUESTFS_MESSAGE_MAX - 1 *)
["read_file"; "/read_file"]]);
InitScratchFS, Always, TestLastFail (
[["touch"; "/read_file2"];
["truncate_size"; "/read_file2"; "4194304"]; (* GUESTFS_MESSAGE_MAX *)
["read_file"; "/read_file2"]]);
InitScratchFS, Always, TestLastFail (
[["touch"; "/read_file3"];
["truncate_size"; "/read_file3"; "41943040"]; (* GUESTFS_MESSAGE_MAX * 10 *)
["read_file"; "/read_file3"]])
];
shortdesc = "read a file";
longdesc = "\
This calls returns the contents of the file C<path> as a
buffer.
Unlike C<guestfs_cat>, this function can correctly
handle files that contain embedded ASCII NUL characters.
However unlike C<guestfs_download>, this function is limited
in the total size of file that can be handled." };
{ defaults with
name = "grep";
style = RStringList "lines", [String "regex"; Pathname "path"], [OBool "extended"; OBool "fixed"; OBool "insensitive"; OBool "compressed"];

View File

@@ -50,6 +50,14 @@ sort_strings (char **argv, size_t len)
char *
guestfs__cat (guestfs_h *g, const char *path)
{
size_t size;
return guestfs_read_file (g, path, &size);
}
char *
guestfs__read_file (guestfs_h *g, const char *path, size_t *size_r)
{
int fd = -1;
size_t size;
@@ -97,6 +105,10 @@ guestfs__cat (guestfs_h *g, const char *path)
goto err;
}
/* Mustn't touch *size_r until we are sure that we won't return any
* error (RHBZ#589039).
*/
*size_r = size;
return ret;
err: