summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-08-17 08:15:31 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-08-17 16:08:13 +0100
commit294bee38bcdd38542bf26292365ac27aebb06642 (patch)
treef96889d4319a5647010f9b2a5e8224f64823b4e8
parent50d904c0181d1e714938cc5c702616f5a79c0bd2 (diff)
downloadlibguestfs-294bee38bcdd38542bf26292365ac27aebb06642.tar.gz
libguestfs-294bee38bcdd38542bf26292365ac27aebb06642.tar.xz
libguestfs-294bee38bcdd38542bf26292365ac27aebb06642.zip
guestfs_cat: Reimplement to avoid protocol limits.
-rw-r--r--TODO1
-rw-r--r--daemon/file.c69
-rw-r--r--generator/generator_actions.ml42
-rw-r--r--po/POTFILES1
-rw-r--r--src/Makefile.am1
-rw-r--r--src/file.c97
6 files changed, 123 insertions, 88 deletions
diff --git a/TODO b/TODO
index 3832371c..452b9f7d 100644
--- a/TODO
+++ b/TODO
@@ -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;
+}