From 3920ad95f6b2db8fbf20aa26692877a09070cb04 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Tue, 18 May 2010 21:51:05 +0100 Subject: [PATCH] New API: write for creating files with fixed content (RHBZ#501889). The guestfs_write call can be used to create small files with arbitrary 8 bit content, including \0 bytes. This replaces and deprecates write-file, which cannot be modified to use BufferIn because of an unfortunate choice in the ABI: the size parameter to write-file, if zero, means that the daemon tries to calculate the length of the buffer using strlen. However this fails if we pass a zero-length buffer using BufferIn because then the daemon tries to do strlen on a (really) zero length buffer, not even containing a terminating \0 character, thus segfaulting. --- daemon/file.c | 28 ++++++++++++++ fish/edit.c | 2 +- fish/fish.c | 2 +- fish/guestfish.pod | 4 +- fuse/test-fuse.sh | 4 +- recipes/clone.sh | 4 +- src/MAX_PROC_NR | 2 +- src/generator.ml | 99 ++++++++++++++++++++++++++------------------------ src/guestfs.pod | 4 +- tools/make-test-img.sh | 12 +++--- 10 files changed, 96 insertions(+), 65 deletions(-) diff --git a/daemon/file.c b/daemon/file.c index 2399828..7d37f56 100644 --- a/daemon/file.c +++ b/daemon/file.c @@ -314,6 +314,34 @@ do_write_file (const char *path, const char *content, int size) return 0; } +int +do_write (const char *path, const char *content, size_t size) +{ + int fd; + + CHROOT_IN; + fd = open (path, O_WRONLY | O_TRUNC | O_CREAT | O_NOCTTY, 0666); + CHROOT_OUT; + + if (fd == -1) { + reply_with_perror ("open: %s", path); + return -1; + } + + if (xwrite (fd, content, size) == -1) { + reply_with_perror ("write"); + close (fd); + return -1; + } + + if (close (fd) == -1) { + reply_with_perror ("close: %s", path); + return -1; + } + + return 0; +} + char * do_read_file (const char *path, size_t *size_r) { diff --git a/fish/edit.c b/fish/edit.c index 3fc41fb..a010057 100644 --- a/fish/edit.c +++ b/fish/edit.c @@ -156,7 +156,7 @@ do_edit (const char *cmd, int argc, char *argv[]) } /* Write new content. */ - if (guestfs_write_file (g, argv[0], content_new, size) == -1) { + if (guestfs_write (g, argv[0], content_new, size) == -1) { free (content); free (content_new); return -1; diff --git a/fish/fish.c b/fish/fish.c index 06ce960..a32ed4d 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -1093,7 +1093,7 @@ display_builtin_command (const char *cmd) " This is used to edit a file.\n" "\n" " It is the equivalent of (and is implemented by)\n" - " running \"cat\", editing locally, and then \"write-file\".\n" + " running \"cat\", editing locally, and then \"write\".\n" "\n" " Normally it uses $EDITOR, but if you use the aliases\n" " \"vi\" or \"emacs\" you will get those editors.\n" diff --git a/fish/guestfish.pod b/fish/guestfish.pod index 7260caf..274f1d4 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -41,7 +41,7 @@ Create a new C file in a guest: add disk.img run mount /dev/vg_guest/lv_root / - write_file /etc/motd "Welcome, new users" 0 + write /etc/motd "Welcome, new users" _EOF_ List the LVM logical volumes in a guest: @@ -57,7 +57,7 @@ Update C in a guest: guestfish \ add disk.img : run : mount /dev/vg_guest/lv_root / : \ - write-file /etc/resolv.conf "nameserver 1.2.3.4" 0 + write /etc/resolv.conf "nameserver 1.2.3.4" Edit C interactively: diff --git a/fuse/test-fuse.sh b/fuse/test-fuse.sh index 7dc8e4b..e31ea9d 100755 --- a/fuse/test-fuse.sh +++ b/fuse/test-fuse.sh @@ -93,8 +93,8 @@ $guestfish <, with C megabytes."); [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount_options"; ""; "/dev/sda1"; "/"]; - ["write_file"; "/new"; "new file contents"; "0"]; + ["write"; "/new"; "new file contents"]; ["cat"; "/new"]], "new file contents")], "make a filesystem", "\ @@ -1537,25 +1537,8 @@ the string C<,> (comma). See also: C, C, C"); - ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning], - [InitBasicFS, Always, TestOutput ( - [["write_file"; "/new"; "new file contents"; "0"]; - ["cat"; "/new"]], "new file contents"); - InitBasicFS, Always, TestOutput ( - [["write_file"; "/new"; "\nnew file contents\n"; "0"]; - ["cat"; "/new"]], "\nnew file contents\n"); - InitBasicFS, Always, TestOutput ( - [["write_file"; "/new"; "\n\n"; "0"]; - ["cat"; "/new"]], "\n\n"); - InitBasicFS, Always, TestOutput ( - [["write_file"; "/new"; ""; "0"]; - ["cat"; "/new"]], ""); - InitBasicFS, Always, TestOutput ( - [["write_file"; "/new"; "\n\n\n"; "0"]; - ["cat"; "/new"]], "\n\n\n"); - InitBasicFS, Always, TestOutput ( - [["write_file"; "/new"; "\n"; "0"]; - ["cat"; "/new"]], "\n")], + ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning; DeprecatedBy "write"], + [], "create a file", "\ This call creates a file called C. The contents of the @@ -1567,9 +1550,7 @@ then the length is calculated using C (so in this case the content cannot contain embedded ASCII NULs). I Owing to a bug, writing content containing ASCII NUL -characters does I work, even if the length is specified. -We hope to resolve this bug in a future version. In the meantime -use C."); +characters does I work, even if the length is specified."); ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"], [InitEmpty, Always, TestOutputListOfDevices ( @@ -2088,7 +2069,7 @@ To download an uncompressed tarball, use C."); ["mount_ro"; "/dev/sda1"; "/"]; ["touch"; "/new"]]); InitBasicFS, Always, TestOutput ( - [["write_file"; "/new"; "data"; "0"]; + [["write"; "/new"; "data"]; ["umount"; "/"]; ["mount_ro"; "/dev/sda1"; "/"]; ["cat"; "/new"]], "data")], @@ -2340,15 +2321,15 @@ C, with the root directory being C."); ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [], [InitBasicFS, Always, TestOutput ( - [["write_file"; "/old"; "file content"; "0"]; + [["write"; "/old"; "file content"]; ["cp"; "/old"; "/new"]; ["cat"; "/new"]], "file content"); InitBasicFS, Always, TestOutputTrue ( - [["write_file"; "/old"; "file content"; "0"]; + [["write"; "/old"; "file content"]; ["cp"; "/old"; "/new"]; ["is_file"; "/old"]]); InitBasicFS, Always, TestOutput ( - [["write_file"; "/old"; "file content"; "0"]; + [["write"; "/old"; "file content"]; ["mkdir"; "/dir"]; ["cp"; "/old"; "/dir/new"]; ["cat"; "/dir/new"]], "file content")], @@ -2361,7 +2342,7 @@ either a destination filename or destination directory."); [InitBasicFS, Always, TestOutput ( [["mkdir"; "/olddir"]; ["mkdir"; "/newdir"]; - ["write_file"; "/olddir/file"; "file content"; "0"]; + ["write"; "/olddir/file"; "file content"]; ["cp_a"; "/olddir"; "/newdir"]; ["cat"; "/newdir/olddir/file"]], "file content")], "copy a file or directory recursively", @@ -2371,11 +2352,11 @@ recursively using the C command."); ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [], [InitBasicFS, Always, TestOutput ( - [["write_file"; "/old"; "file content"; "0"]; + [["write"; "/old"; "file content"]; ["mv"; "/old"; "/new"]; ["cat"; "/new"]], "file content"); InitBasicFS, Always, TestOutputFalse ( - [["write_file"; "/old"; "file content"; "0"]; + [["write"; "/old"; "file content"]; ["mv"; "/old"; "/new"]; ["is_file"; "/old"]])], "move a file", @@ -2424,12 +2405,12 @@ or attached block device(s) in any other way."); ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [], [InitBasicFS, Always, TestOutputTrue ( - [["write_file"; "/file1"; "contents of a file"; "0"]; + [["write"; "/file1"; "contents of a file"]; ["cp"; "/file1"; "/file2"]; ["equal"; "/file1"; "/file2"]]); InitBasicFS, Always, TestOutputFalse ( - [["write_file"; "/file1"; "contents of a file"; "0"]; - ["write_file"; "/file2"; "contents of another file"; "0"]; + [["write"; "/file1"; "contents of a file"]; + ["write"; "/file2"; "contents of another file"]; ["equal"; "/file1"; "/file2"]]); InitBasicFS, Always, TestLastFail ( [["equal"; "/file1"; "/file2"]])], @@ -2456,8 +2437,8 @@ the list of printable strings found."); ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning], [InitISOFS, Always, TestOutputList ( [["strings_e"; "b"; "/known-5"]], []); - InitBasicFS, Disabled, TestOutputList ( - [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"]; + InitBasicFS, Always, TestOutputList ( + [["write"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"]; ["strings_e"; "b"; "/new"]], ["hello"; "world"])], "print the printable strings in a file", "\ @@ -2521,7 +2502,7 @@ the human-readable, canonical hex dump of the file."); [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext3"; "/dev/sda1"]; ["mount_options"; ""; "/dev/sda1"; "/"]; - ["write_file"; "/new"; "test file"; "0"]; + ["write"; "/new"; "test file"]; ["umount"; "/dev/sda1"]; ["zerofree"; "/dev/sda1"]; ["mount_options"; ""; "/dev/sda1"; "/"]; @@ -2626,7 +2607,7 @@ are activated or deactivated."); ["lvcreate"; "LV"; "VG"; "10"]; ["mkfs"; "ext2"; "/dev/VG/LV"]; ["mount_options"; ""; "/dev/VG/LV"; "/"]; - ["write_file"; "/new"; "test content"; "0"]; + ["write"; "/new"; "test content"]; ["umount"; "/"]; ["lvresize"; "/dev/VG/LV"; "20"]; ["e2fsck_f"; "/dev/VG/LV"]; @@ -2813,7 +2794,7 @@ manual page for more details."); ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"], [InitBasicFS, Always, TestRun ( - [["write_file"; "/file"; "content"; "0"]; + [["write"; "/file"; "content"]; ["scrub_file"; "/file"]])], "scrub (securely wipe) a file", "\ @@ -3721,7 +3702,7 @@ and C"); [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"]; ["mount_options"; ""; "/dev/sda1"; "/"]; - ["write_file"; "/new"; "new file contents"; "0"]; + ["write"; "/new"; "new file contents"]; ["cat"; "/new"]], "new file contents")], "make a filesystem with block size", "\ @@ -3736,7 +3717,7 @@ are C<1024>, C<2048> or C<4096> only."); ["mke2journal"; "4096"; "/dev/sda1"]; ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"]; ["mount_options"; ""; "/dev/sda2"; "/"]; - ["write_file"; "/new"; "new file contents"; "0"]; + ["write"; "/new"; "new file contents"]; ["cat"; "/new"]], "new file contents")], "make ext2/3/4 external journal", "\ @@ -3751,7 +3732,7 @@ to the command: ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"]; ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"]; ["mount_options"; ""; "/dev/sda2"; "/"]; - ["write_file"; "/new"; "new file contents"; "0"]; + ["write"; "/new"; "new file contents"]; ["cat"; "/new"]], "new file contents")], "make ext2/3/4 external journal with label", "\ @@ -3764,7 +3745,7 @@ This creates an ext2 external journal on C with label C. This call has no limits on file content or size (even files larger than 4 GB). diff --git a/tools/make-test-img.sh b/tools/make-test-img.sh index 9752f1d..fddd8a2 100755 --- a/tools/make-test-img.sh +++ b/tools/make-test-img.sh @@ -68,12 +68,12 @@ mkdir /boot/grub touch /boot/grub/grub.conf # Test files. -write-file /etc/test1 "abcdefg" 0 -write-file /etc/test2 "" 0 -write-file /bin/test1 "abcdefg" 0 -write-file /bin/test2 "zxcvbnm" 0 -write-file /bin/test3 "1234567" 0 -write-file /bin/test4 "" 0 +write /etc/test1 "abcdefg" +write /etc/test2 "" +write /bin/test1 "abcdefg" +write /bin/test2 "zxcvbnm" +write /bin/test3 "1234567" +write /bin/test4 "" ln-s /bin/test1 /bin/test5 mkfifo 0777 /bin/test6 mknod 0777 10 10 /bin/test7 -- 1.8.3.1