diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-08-17 08:15:31 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-08-17 16:08:13 +0100 |
commit | 294bee38bcdd38542bf26292365ac27aebb06642 (patch) | |
tree | f96889d4319a5647010f9b2a5e8224f64823b4e8 | |
parent | 50d904c0181d1e714938cc5c702616f5a79c0bd2 (diff) | |
download | libguestfs-294bee38bcdd38542bf26292365ac27aebb06642.tar.gz libguestfs-294bee38bcdd38542bf26292365ac27aebb06642.tar.xz libguestfs-294bee38bcdd38542bf26292365ac27aebb06642.zip |
guestfs_cat: Reimplement to avoid protocol limits.
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | daemon/file.c | 69 | ||||
-rw-r--r-- | generator/generator_actions.ml | 42 | ||||
-rw-r--r-- | po/POTFILES | 1 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/file.c | 97 |
6 files changed, 123 insertions, 88 deletions
@@ -565,7 +565,6 @@ with the non-daemon versions implemented using guestfs_upload and guestfs_download (and others). This change should be transparent from the p.o.v of the API and ABI. - - guestfs_cat - guestfs_find - guestfs_lstatlist - guestfs_lxattrlist diff --git a/daemon/file.c b/daemon/file.c index cdf6b1bc..2ea8b738 100644 --- a/daemon/file.c +++ b/daemon/file.c @@ -85,75 +85,6 @@ do_touch (const char *path) return 0; } -char * -do_cat (const char *path) -{ - int fd; - size_t alloc, size, max; - ssize_t r; - char *buf, *buf2; - - CHROOT_IN; - fd = open (path, O_RDONLY|O_CLOEXEC); - CHROOT_OUT; - - if (fd == -1) { - reply_with_perror ("open: %s", path); - return NULL; - } - - /* Read up to GUESTFS_MESSAGE_MAX - <overhead> bytes. If it's - * larger than that, we need to return an error instead (for - * correctness). - */ - max = GUESTFS_MESSAGE_MAX - 1000; - buf = NULL; - size = alloc = 0; - - for (;;) { - if (size >= alloc) { - alloc += 8192; - if (alloc > max) { - reply_with_error ("%s: file is too large for message buffer", - path); - free (buf); - close (fd); - return NULL; - } - buf2 = realloc (buf, alloc); - if (buf2 == NULL) { - reply_with_perror ("realloc"); - free (buf); - close (fd); - return NULL; - } - buf = buf2; - } - - r = read (fd, buf + size, alloc - size); - if (r == -1) { - reply_with_perror ("read: %s", path); - free (buf); - close (fd); - return NULL; - } - if (r == 0) { - buf[size] = '\0'; - break; - } - if (r > 0) - size += r; - } - - if (close (fd) == -1) { - reply_with_perror ("close: %s", path); - free (buf); - return NULL; - } - - return buf; /* caller will free */ -} - char ** do_read_lines (const char *path) { diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index f370b795..2d9dbc9d 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -1970,6 +1970,30 @@ need to call C<guestfs_close> afterwards. C<guestfs_close> will call this if you don't do it explicitly, but note that any errors are ignored in that case." }; + { defaults with + name = "cat"; + style = RString "content", [Pathname "path"], []; + tests = [ + InitISOFS, Always, TestOutput ( + [["cat"; "/known-2"]], "abcdef\n") + ]; + shortdesc = "list the contents of a file"; + longdesc = "\ +Return the contents of the file named C<path>. + +Because, in C, this function returns a C<char *>, there is no +way to differentiate between a C<\\0> character in a file and +end of string. To handle binary files, use the C<guestfs_read_file> +or C<guestfs_download> functions. + +In libguestfs E<lt> 1.19.32, this API was also subject to +a limit in the protocol which limited the effective size of +a file that it could read. In later versions of libguestfs, +this limit has been lifted and the call can download and +return arbitrary sized files (limited by the amount of +memory available). In either case you should check the size +of the file before downloading it or consider alternate APIs." }; + ] (* daemon_functions are any functions which cause some action @@ -2046,24 +2070,6 @@ This command only works on regular files, and will fail on other file types such as directories, symbolic links, block special etc." }; { defaults with - name = "cat"; - style = RString "content", [Pathname "path"], []; - proc_nr = Some 4; - protocol_limit_warning = true; - tests = [ - InitISOFS, Always, TestOutput ( - [["cat"; "/known-2"]], "abcdef\n") - ]; - shortdesc = "list the contents of a file"; - longdesc = "\ -Return the contents of the file named C<path>. - -Note that this function cannot correctly handle binary files -(specifically, files containing C<\\0> character which is treated -as end of string). For those you need to use the C<guestfs_read_file> -or C<guestfs_download> functions which have a more complex interface." }; - - { defaults with name = "ll"; style = RString "listing", [Pathname "directory"], []; proc_nr = Some 5; diff --git a/po/POTFILES b/po/POTFILES index 08d2ab86..60887dc2 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -209,6 +209,7 @@ src/dbdump.c src/errnostring-gperf.c src/errnostring.c src/events.c +src/file.c src/filearch.c src/fuse.c src/guestfs.c diff --git a/src/Makefile.am b/src/Makefile.am index 750c07be..ff6149c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -127,6 +127,7 @@ libguestfs_la_SOURCES = \ bindtests.c \ dbdump.c \ events.c \ + file.c \ filearch.c \ fuse.c \ inspect.c \ diff --git a/src/file.c b/src/file.c new file mode 100644 index 00000000..b76900d2 --- /dev/null +++ b/src/file.c @@ -0,0 +1,97 @@ +/* libguestfs + * Copyright (C) 2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "full-read.h" + +#include "guestfs.h" +#include "guestfs-internal.h" +#include "guestfs-internal-actions.h" +#include "guestfs_protocol.h" + +char * +guestfs__cat (guestfs_h *g, const char *path) +{ + int fd = -1; + size_t size; + char *tmpfile = NULL, *ret = NULL; + struct stat statbuf; + + tmpfile = safe_asprintf (g, "%s/cat%d", g->tmpdir, ++g->unique); + + if (guestfs_download (g, path, tmpfile) == -1) + goto err; + + fd = open (tmpfile, O_RDONLY|O_CLOEXEC); + if (fd == -1) { + perrorf (g, "open: %s", tmpfile); + goto err; + } + + unlink (tmpfile); + free (tmpfile); + tmpfile = NULL; + + /* Read the whole file into memory. */ + if (fstat (fd, &statbuf) == -1) { + perrorf (g, "stat: %s", tmpfile); + goto err; + } + + /* Don't use safe_malloc, because we want to return an errno to the caller. */ + size = statbuf.st_size; + ret = malloc (size + 1); + if (!ret) { + perrorf (g, "malloc: %zu bytes", size + 1); + goto err; + } + + if (full_read (fd, ret, size) != size) { + perrorf (g, "full-read: %s: %zu bytes", tmpfile, size + 1); + goto err; + } + + ret[size] = '\0'; + + if (close (fd) == -1) { + perrorf (g, "close: %s", tmpfile); + goto err; + } + + return ret; + + err: + free (ret); + if (fd >= 0) + close (fd); + if (tmpfile) { + unlink (tmpfile); + free (tmpfile); + } + return NULL; +} |