>From 8a1762d865cca34f7625985ed67d060367544057 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 10 Feb 2012 10:12:45 +0000 Subject: [PATCH 2/3] 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. --- fish/Makefile.am | 1 + fish/edit.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++-- fish/fish.c | 3 ++ fish/test-edit.sh | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 3 deletions(-) create mode 100755 fish/test-edit.sh diff --git a/fish/Makefile.am b/fish/Makefile.am index 8a6f88b..badb04d 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 e0204b0..908a3a3 100644 --- a/fish/edit.c +++ b/fish/edit.c @@ -26,9 +26,12 @@ #include #include #include +#include #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 e388832..575fe99 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 0000000..ff38d1c --- /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 <