+ int fd, r, is_dev;
+ char buf[GUESTFS_MAX_CHUNK_SIZE];
+
+ NEED_ROOT_OR_IS_DEVICE (filename, -1);
+
+ is_dev = strncmp (filename, "/dev/", 5) == 0;
+
+ if (!is_dev) CHROOT_IN;
+ fd = open (filename, O_RDONLY);
+ if (!is_dev) CHROOT_OUT;
+ if (fd == -1) {
+ reply_with_perror ("%s", filename);
+ return -1;
+ }
+
+ /* Now we must send the reply message, before the file contents. After
+ * this there is no opportunity in the protocol to send any error
+ * message back. Instead we can only cancel the transfer.
+ */
+ reply (NULL, NULL);
+
+ while ((r = read (fd, buf, sizeof buf)) > 0) {
+ if (send_file_write (buf, r) < 0) {
+ close (fd);
+ return -1;
+ }
+ }
+
+ if (r == -1) {
+ perror (filename);
+ send_file_end (1); /* Cancel. */
+ close (fd);
+ return -1;
+ }
+
+ if (close (fd) == -1) {
+ perror (filename);
+ send_file_end (1); /* Cancel. */
+ return -1;
+ }
+
+ send_file_end (0); /* Normal end of file. */
+ return 0;