fish: Fix 'edit' command to work with any file.
authorRichard Jones <rjones@redhat.com>
Thu, 9 Sep 2010 13:11:20 +0000 (14:11 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Sat, 23 Oct 2010 11:09:44 +0000 (12:09 +0100)
Cherry picked from commit b5c287bcd456bdb02d8ec0443483df34f4fd6b5d.

fish/edit.c
fish/guestfish.pod

index 3fc41fb..10950f9 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include "fish.h"
 
 /* guestfish edit command, suggested by Ján Ondrej, implemented by RWMJ */
 
-static char *
-load_file (const char *filename, size_t *len_r)
-{
-  int fd, r, start;
-  char *content = NULL, *p;
-  char buf[65536];
-
-  *len_r = 0;
-
-  fd = open (filename, O_RDONLY);
-  if (fd == -1) {
-    perror (filename);
-    return NULL;
-  }
-
-  while ((r = read (fd, buf, sizeof buf)) > 0) {
-    start = *len_r;
-    *len_r += r;
-    p = realloc (content, *len_r + 1);
-    if (p == NULL) {
-      perror ("realloc");
-      free (content);
-      return NULL;
-    }
-    content = p;
-    memcpy (content + start, buf, r);
-    content[start+r] = '\0';
-  }
-
-  if (r == -1) {
-    perror (filename);
-    free (content);
-    return NULL;
-  }
-
-  if (close (fd) == -1) {
-    perror (filename);
-    free (content);
-    return NULL;
-  }
-
-  return content;
-}
-
 int
 do_edit (const char *cmd, int argc, char *argv[])
 {
   char filename[] = "/tmp/guestfishXXXXXX";
   char buf[256];
   const char *editor;
-  char *content, *content_new;
+  struct stat oldstat, newstat;
   int r, fd;
 
   if (argc != 1) {
@@ -105,23 +63,24 @@ do_edit (const char *cmd, int argc, char *argv[])
     return -1;
   }
 
-  if ((content = guestfs_cat (g, argv[0])) == NULL) {
+  snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
+
+  if (guestfs_download (g, argv[0], buf) == -1) {
     close (fd);
     unlink (filename);
     return -1;
   }
 
-  if (xwrite (fd, content, strlen (content)) == -1) {
-    close (fd);
+  if (close (fd) == -1) {
+    perror (filename);
     unlink (filename);
-    free (content);
     return -1;
   }
 
-  if (close (fd) == -1) {
+  /* Get the old stat. */
+  if (stat (filename, &oldstat) == -1) {
     perror (filename);
     unlink (filename);
-    free (content);
     return -1;
   }
 
@@ -133,36 +92,29 @@ do_edit (const char *cmd, int argc, char *argv[])
   if (r != 0) {
     perror (buf);
     unlink (filename);
-    free (content);
     return -1;
   }
 
-  /* Reload it. */
-  size_t size;
-  content_new = load_file (filename, &size);
-  if (content_new == NULL) {
+  /* Get the new stat. */
+  if (stat (filename, &newstat) == -1) {
+    perror (filename);
     unlink (filename);
-    free (content);
     return -1;
   }
 
-  unlink (filename);
-
   /* Changed? */
-  if (strlen (content) == size && STREQLEN (content, content_new, size)) {
-    free (content);
-    free (content_new);
+  if (oldstat.st_ctime == newstat.st_ctime &&
+      oldstat.st_size == newstat.st_size) {
+    unlink (filename);
     return 0;
   }
 
   /* Write new content. */
-  if (guestfs_write_file (g, argv[0], content_new, size) == -1) {
-    free (content);
-    free (content_new);
+  if (guestfs_upload (g, filename, argv[0]) == -1) {
+    unlink (filename);
     return -1;
   }
 
-  free (content);
-  free (content_new);
+  unlink (filename);
   return 0;
 }
index 6477647..66e3e67 100644 (file)
@@ -570,9 +570,6 @@ The editor is C<$EDITOR>.  However if you use the alternate
 commands C<vi> or C<emacs> you will get those corresponding
 editors.
 
-NOTE: This will not work reliably for large files
-(> 2 MB) or binary files containing \0 bytes.
-
 =head2 glob
 
  glob command args...