Version 1.7.6.
[libguestfs.git] / fish / edit.c
index c72ad1d..a9539ba 100644 (file)
@@ -1,5 +1,5 @@
 /* guestfish - the filesystem interactive shell
- * Copyright (C) 2009 Red Hat Inc. 
+ * Copyright (C) 2009 Red Hat Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #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, int *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[])
+run_edit (const char *cmd, size_t argc, char *argv[])
 {
-  char filename[] = "/tmp/guestfishXXXXXX";
+  TMP_TEMPLATE_ON_STACK (filename);
   char buf[256];
   const char *editor;
-  char *content, *content_new;
-  int r, fd, size;
+  struct stat oldstat, newstat;
+  int r, fd;
 
   if (argc != 1) {
     fprintf (stderr, _("use '%s filename' to edit a file\n"), cmd);
@@ -88,9 +46,9 @@ do_edit (const char *cmd, int argc, char *argv[])
   }
 
   /* Choose an editor. */
-  if (strcasecmp (cmd, "vi") == 0)
+  if (STRCASEEQ (cmd, "vi"))
     editor = "vi";
-  else if (strcasecmp (cmd, "emacs") == 0)
+  else if (STRCASEEQ (cmd, "emacs"))
     editor = "emacs -nw";
   else {
     editor = getenv ("EDITOR");
@@ -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,35 +92,29 @@ do_edit (const char *cmd, int argc, char *argv[])
   if (r != 0) {
     perror (buf);
     unlink (filename);
-    free (content);
     return -1;
   }
 
-  /* Reload it. */
-  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 && strncmp (content, content_new, size) == 0) {
-    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;
 }