diff options
author | Richard W.M. Jones <[email protected]> | 2012-02-10 10:12:45 +0000 |
---|---|---|
committer | Richard W.M. Jones <[email protected]> | 2012-02-10 11:27:13 +0000 |
commit | ddae5abf80f65fc149eec253f14f073d397b49c2 (patch) | |
tree | 1fb3f7e40c31592d34a5c18c7cbb37b76e24cd6c /fish/edit.c | |
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.
Diffstat (limited to 'fish/edit.c')
-rw-r--r-- | fish/edit.c | 58 |
1 files changed, 55 insertions, 3 deletions
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 */ +} |