diff options
author | Richard Jones <rjones@redhat.com> | 2010-05-18 21:51:05 +0100 |
---|---|---|
committer | Richard Jones <rjones@redhat.com> | 2010-05-20 10:30:12 +0100 |
commit | 3920ad95f6b2db8fbf20aa26692877a09070cb04 (patch) | |
tree | eb3ffe5779f720c96a33506d1b50807c430ca977 | |
parent | bda6cf75f259992bcba23c3c4c2339c50552f491 (diff) | |
download | libguestfs-3920ad95f6b2db8fbf20aa26692877a09070cb04.tar.gz libguestfs-3920ad95f6b2db8fbf20aa26692877a09070cb04.tar.xz libguestfs-3920ad95f6b2db8fbf20aa26692877a09070cb04.zip |
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.
-rw-r--r-- | daemon/file.c | 28 | ||||
-rw-r--r-- | fish/edit.c | 2 | ||||
-rw-r--r-- | fish/fish.c | 2 | ||||
-rw-r--r-- | fish/guestfish.pod | 4 | ||||
-rwxr-xr-x | fuse/test-fuse.sh | 4 | ||||
-rwxr-xr-x | recipes/clone.sh | 4 | ||||
-rw-r--r-- | src/MAX_PROC_NR | 2 | ||||
-rwxr-xr-x | src/generator.ml | 99 | ||||
-rw-r--r-- | src/guestfs.pod | 4 | ||||
-rwxr-xr-x | tools/make-test-img.sh | 12 |
10 files changed, 96 insertions, 65 deletions
diff --git a/daemon/file.c b/daemon/file.c index 2399828e..7d37f569 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 3fc41fb1..a010057d 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 06ce960d..a32ed4d0 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 7260caf0..274f1d41 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -41,7 +41,7 @@ Create a new C</etc/motd> 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</etc/resolv.conf> 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</boot/grub/grub.conf> interactively: diff --git a/fuse/test-fuse.sh b/fuse/test-fuse.sh index 7dc8e4b8..e31ea9d7 100755 --- a/fuse/test-fuse.sh +++ b/fuse/test-fuse.sh @@ -93,8 +93,8 @@ $guestfish <<EOF part-disk /dev/sda mbr mkfs ext2 /dev/sda1 mount /dev/sda1 / - write-file /hello.txt hello 0 - write-file /world.txt "hello world" 0 + write /hello.txt hello + write /world.txt "hello world" touch /empty EOF diff --git a/recipes/clone.sh b/recipes/clone.sh index e3fc11cf..d2b9d99d 100755 --- a/recipes/clone.sh +++ b/recipes/clone.sh @@ -9,7 +9,7 @@ hostname="$5" dd if="$preimage" of="$newimage" guestfish -a "$newimage" -m "$root" <<EOF -write-file /etc/resolv.conf "nameserver $nameserver" 0 -write-file /etc/HOSTNAME "$hostname" 0 +write /etc/resolv.conf "nameserver $nameserver" +write /etc/HOSTNAME "$hostname" sync EOF diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 2c2b1af8..5d165ff2 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -245 +246 diff --git a/src/generator.ml b/src/generator.ml index 090c2800..dfab8dcd 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -938,7 +938,7 @@ let daemon_functions = [ [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; - ["write_file"; "/new"; "new file contents"; "0"]; + ["write"; "/new"; "new file contents"]; ["cat"; "/new"]], "new file contents")], "mount a guest disk at a position in the filesystem", "\ @@ -1500,7 +1500,7 @@ on the volume group C<volgroup>, with C<size> 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<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>, C<guestfs_part_init>"); - ("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<path>. The contents of the @@ -1567,9 +1550,7 @@ then the length is calculated using C<strlen> (so in this case the content cannot contain embedded ASCII NULs). I<NB.> Owing to a bug, writing content containing ASCII NUL -characters does I<not> work, even if the length is specified. -We hope to resolve this bug in a future version. In the meantime -use C<guestfs_upload>."); +characters does I<not> 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<guestfs_tar_out>."); ["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<device>, with the root directory being C<root>."); ("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<cp -a> 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<guestfs_setcon>"); [["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<device> with label C<label>."); ["mke2journal_U"; "4096"; uuid; "/dev/sda1"]; ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid]; ["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 UUID", "\ @@ -3927,7 +3908,7 @@ if you used the C<guestfs_mount> call)."); ("truncate", (RErr, [Pathname "path"]), 199, [], [InitBasicFS, Always, TestOutputStruct ( - [["write_file"; "/test"; "some stuff so size is not zero"; "0"]; + [["write"; "/test"; "some stuff so size is not zero"]; ["truncate"; "/test"]; ["stat"; "/test"]], [CompareWithInt ("size", 0)])], "truncate a file to zero size", @@ -4345,7 +4326,7 @@ See also C<guestfs_version>. ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [], [InitBasicFS, Always, TestOutputBuffer ( - [["write_file"; "/src"; "hello, world"; "0"]; + [["write"; "/src"; "hello, world"]; ["dd"; "/src"; "/dest"]; ["read_file"; "/dest"]], "hello, world")], "copy from source to destination using dd", @@ -4361,7 +4342,7 @@ This command cannot do partial copies (see C<guestfs_copy_size>)."); ("filesize", (RInt64 "size", [Pathname "file"]), 218, [], [InitBasicFS, Always, TestOutputInt ( - [["write_file"; "/file"; "hello, world"; "0"]; + [["write"; "/file"; "hello, world"]; ["filesize"; "/file"]], 12)], "return the size of the file in bytes", "\ @@ -4452,7 +4433,7 @@ See also C<guestfs_vgpvuuids>."); ("copy_size", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"; Int64 "size"]), 227, [], [InitBasicFS, Always, TestOutputBuffer ( - [["write_file"; "/src"; "hello, world"; "0"]; + [["write"; "/src"; "hello, world"]; ["copy_size"; "/src"; "/dest"; "5"]; ["read_file"; "/dest"]], "hello")], "copy size bytes from source to destination using dd", @@ -4653,6 +4634,30 @@ a new file of length C<len> containing the repeating pattern of bytes in C<pattern>. The pattern is truncated if necessary to ensure the length of the file is exactly C<len> bytes."); + ("write", (RErr, [Pathname "path"; BufferIn "content"]), 246, [ProtocolLimitWarning], + [InitBasicFS, Always, TestOutput ( + [["write"; "/new"; "new file contents"]; + ["cat"; "/new"]], "new file contents"); + InitBasicFS, Always, TestOutput ( + [["write"; "/new"; "\nnew file contents\n"]; + ["cat"; "/new"]], "\nnew file contents\n"); + InitBasicFS, Always, TestOutput ( + [["write"; "/new"; "\n\n"]; + ["cat"; "/new"]], "\n\n"); + InitBasicFS, Always, TestOutput ( + [["write"; "/new"; ""]; + ["cat"; "/new"]], ""); + InitBasicFS, Always, TestOutput ( + [["write"; "/new"; "\n\n\n"]; + ["cat"; "/new"]], "\n\n\n"); + InitBasicFS, Always, TestOutput ( + [["write"; "/new"; "\n"]; + ["cat"; "/new"]], "\n")], + "create a new file", + "\ +This call creates a file called C<path>. The content of the +file is the string C<content> (which can contain any 8 bit data)."); + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/src/guestfs.pod b/src/guestfs.pod index e1fa4f5a..8404e742 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -258,9 +258,7 @@ L</guestfs_tgz_out>. It's often the case that you want to write a file or files to the disk image. -For small, single files, use L</guestfs_write_file>. This call -currently contains a bug which limits the call to plain text files -(not containing ASCII NUL characters). +For small, single files, use L</guestfs_write>. To upload a single file, use L</guestfs_upload>. 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 9752f1dc..fddd8a2d 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 |