New API: Implement pwrite system call (partial fix for RHBZ#592883).
[libguestfs.git] / daemon / dd.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <fcntl.h>
25
26 #include "../src/guestfs_protocol.h"
27 #include "daemon.h"
28 #include "actions.h"
29
30 int
31 do_dd (const char *src, const char *dest)
32 {
33   int src_is_dev, dest_is_dev;
34   char *if_arg, *of_arg;
35   char *err;
36   int r;
37
38   src_is_dev = STRPREFIX (src, "/dev/");
39
40   if (src_is_dev)
41     r = asprintf (&if_arg, "if=%s", src);
42   else
43     r = asprintf (&if_arg, "if=%s%s", sysroot, src);
44   if (r == -1) {
45     reply_with_perror ("asprintf");
46     return -1;
47   }
48
49   dest_is_dev = STRPREFIX (dest, "/dev/");
50
51   if (dest_is_dev)
52     r = asprintf (&of_arg, "of=%s", dest);
53   else
54     r = asprintf (&of_arg, "of=%s%s", sysroot, dest);
55   if (r == -1) {
56     reply_with_perror ("asprintf");
57     free (if_arg);
58     return -1;
59   }
60
61   r = command (NULL, &err, "dd", "bs=1024K", if_arg, of_arg, NULL);
62   free (if_arg);
63   free (of_arg);
64
65   if (r == -1) {
66     reply_with_error ("%s: %s: %s", src, dest, err);
67     free (err);
68     return -1;
69   }
70   free (err);
71
72   return 0;
73 }
74
75 int
76 do_copy_size (const char *src, const char *dest, int64_t size)
77 {
78   char *buf;
79   int src_fd, dest_fd;
80
81   if (STRPREFIX (src, "/dev/"))
82     src_fd = open (src, O_RDONLY);
83   else {
84     buf = sysroot_path (src);
85     if (!buf) {
86       reply_with_perror ("malloc");
87       return -1;
88     }
89     src_fd = open (buf, O_RDONLY);
90     free (buf);
91   }
92   if (src_fd == -1) {
93     reply_with_perror ("%s", src);
94     return -1;
95   }
96
97   if (STRPREFIX (dest, "/dev/"))
98     dest_fd = open (dest, O_WRONLY);
99   else {
100     buf = sysroot_path (dest);
101     if (!buf) {
102       reply_with_perror ("malloc");
103       close (src_fd);
104       return -1;
105     }
106     dest_fd = open (buf, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
107     free (buf);
108   }
109   if (dest_fd == -1) {
110     reply_with_perror ("%s", dest);
111     close (src_fd);
112     return -1;
113   }
114
115   while (size > 0) {
116     char buf[1024*1024];
117     size_t n = size > (int64_t) (sizeof buf) ? sizeof buf : (size_t) size;
118     ssize_t r = read (src_fd, buf, n);
119     if (r == -1) {
120       reply_with_perror ("%s: read", src);
121       close (src_fd);
122       close (dest_fd);
123       return -1;
124     }
125     if (r == 0) {
126       reply_with_error ("%s: input file too short", src);
127       close (src_fd);
128       close (dest_fd);
129       return -1;
130     }
131
132     if (xwrite (dest_fd, buf, r) == -1) {
133       reply_with_perror ("%s: write", dest);
134       close (src_fd);
135       close (dest_fd);
136       return -1;
137     }
138
139     size -= r;
140   }
141
142   if (close (src_fd) == -1) {
143     reply_with_perror ("%s: close", src);
144     close (dest_fd);
145     return -1;
146   }
147   if (close (dest_fd) == -1) {
148     reply_with_perror ("%s: close", dest);
149     return -1;
150   }
151
152   return 0;
153 }