diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-02-10 10:12:45 +0000 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-02-10 11:27:13 +0000 |
commit | ddae5abf80f65fc149eec253f14f073d397b49c2 (patch) | |
tree | 1fb3f7e40c31592d34a5c18c7cbb37b76e24cd6c | |
parent | ca80e4490463d646de4504fc2bcb4e4a722bedb8 (diff) | |
download | libguestfs-ddae5abf80f65fc149eec253f14f073d397b49c2.tar.gz libguestfs-ddae5abf80f65fc149eec253f14f073d397b49c2.tar.xz libguestfs-ddae5abf80f65fc149eec253f14f073d397b49c2.zip |
fish: In edit command, upload to a new file.
If the upload fails, this means we don't leave a partially
written file.
Also add a test for the edit command.
-rw-r--r-- | fish/Makefile.am | 1 | ||||
-rw-r--r-- | fish/edit.c | 58 | ||||
-rw-r--r-- | fish/fish.c | 3 | ||||
-rwxr-xr-x | fish/test-edit.sh | 51 |
4 files changed, 110 insertions, 3 deletions
diff --git a/fish/Makefile.am b/fish/Makefile.am index 8a6f88b2..badb04dd 100644 --- a/fish/Makefile.am +++ b/fish/Makefile.am @@ -247,6 +247,7 @@ TESTS = \ if ENABLE_APPLIANCE TESTS += \ test-copy.sh \ + test-edit.sh \ test-find0.sh \ test-read_file.sh \ test-remote.sh \ diff --git a/fish/edit.c b/fish/edit.c index e0204b0b..908a3a3a 100644 --- a/fish/edit.c +++ b/fish/edit.c @@ -26,9 +26,12 @@ #include <inttypes.h> #include <sys/types.h> #include <sys/stat.h> +#include <assert.h> #include "fish.h" +static char *generate_random_name (const char *filename); + /* guestfish edit command, suggested by Ján Ondrej, implemented by RWMJ */ int @@ -37,7 +40,7 @@ run_edit (const char *cmd, size_t argc, char *argv[]) TMP_TEMPLATE_ON_STACK (filename); char buf[256]; const char *editor; - char *remotefilename; + char *remotefilename, *newname; struct stat oldstat, newstat; int r, fd; @@ -111,14 +114,29 @@ run_edit (const char *cmd, size_t argc, char *argv[]) return 0; } - /* Write new content. */ - if (guestfs_upload (g, filename, remotefilename) == -1) + /* Upload to a new file in the same directory, so if it fails we + * don't end up with a partially written file. Give the new file + * a completely random name so we have only a tiny chance of + * overwriting some existing file. + */ + newname = generate_random_name (remotefilename); + if (!newname) goto error2; + /* Write new content. */ + if (guestfs_upload (g, filename, newname) == -1) + goto error3; + + if (guestfs_mv (g, newname, remotefilename) == -1) + goto error3; + + free (newname); unlink (filename); free (remotefilename); return 0; + error3: + free (newname); error2: unlink (filename); error1: @@ -126,3 +144,37 @@ run_edit (const char *cmd, size_t argc, char *argv[]) error0: return -1; } + +static char +random_char (void) +{ + char c[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + return c[random () % (sizeof c - 1)]; +} + +static char * +generate_random_name (const char *filename) +{ + char *ret, *p; + size_t i; + + ret = malloc (strlen (filename) + 16); + if (!ret) { + perror ("malloc"); + return NULL; + } + strcpy (ret, filename); + + p = strrchr (ret, '/'); + assert (p); + p++; + + /* Because of "+ 16" above, there should be enough space in the + * output buffer to write 8 random characters here. + */ + for (i = 0; i < 8; ++i) + *p++ = random_char (); + *p++ = '\0'; + + return ret; /* caller will free */ +} diff --git a/fish/fish.c b/fish/fish.c index e388832e..575fe99d 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -163,6 +163,9 @@ main (int argc, char *argv[]) bindtextdomain (PACKAGE, LOCALEBASEDIR); textdomain (PACKAGE); + /* We use random(3) in edit.c. */ + srandom (time (NULL)); + parse_config (); enum { HELP_OPTION = CHAR_MAX + 1 }; diff --git a/fish/test-edit.sh b/fish/test-edit.sh new file mode 100755 index 00000000..ff38d1cd --- /dev/null +++ b/fish/test-edit.sh @@ -0,0 +1,51 @@ +#!/bin/bash - +# libguestfs +# Copyright (C) 2012 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Test guestfish edit command. + +# This test fails on some versions of mock which lack /dev/fd +# directory. Skip this test in that case. + +test -d /dev/fd || { + echo "$0: Skipping this test because /dev/fd is missing." + exit 0 +} + +set -e + +rm -f test1.img + +# The command will be 'echo ... >>/tmp/tmpfile' +export EDITOR="echo second line of text >>" + +output=$( +../fish/guestfish -N fs -m /dev/sda1 <<EOF +write /file.txt "this is a test\n" +edit /file.txt +cat /file.txt +EOF +) + +if [ "$output" != "this is a test +second line of text" ]; then + echo "$0: error: output of guestfish after edit command did not match expected output" + echo "$output" + exit 1 +fi + +rm -f test1.img |