Implementations of 'cat', 'ls', and some cleanups.
[libguestfs.git] / daemon / file.c
index db19918..537618f 100644 (file)
@@ -27,6 +27,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
+#include "../src/guestfs_protocol.h"
 #include "daemon.h"
 #include "actions.h"
 
@@ -35,12 +36,8 @@ do_touch (const char *path)
 {
   int fd;
 
-  NEED_ROOT;
-
-  if (path[0] != '/') {
-    reply_with_error ("touch: path must start with a / character");
-    return -1;
-  }
+  NEED_ROOT (-1);
+  ABS_PATH (path, -1);
 
   CHROOT_IN;
   fd = open (path, O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK, 0666);
@@ -48,7 +45,6 @@ do_touch (const char *path)
 
   if (fd == -1) {
     reply_with_perror ("open: %s", path);
-    close (fd);
     return -1;
   }
 
@@ -65,6 +61,70 @@ do_touch (const char *path)
 char *
 do_cat (const char *path)
 {
-  reply_with_error ("cat command is not yet implemented");
-  return NULL;
+  int fd;
+  int alloc, size, r, max;
+  char *buf, *buf2;
+
+  NEED_ROOT (NULL);
+  ABS_PATH (path,NULL);
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY);
+  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 ("cat: %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 */
 }