todo: Add notes on inspecting ISO images.
[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 "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 ssize)
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   uint64_t position = 0, size = (uint64_t) ssize;
116
117   while (position < size) {
118     char buf[1024*1024];
119
120     /* Calculate bytes to copy. */
121     uint64_t n64 = size - position;
122     size_t n;
123     if (n64 > sizeof buf)
124       n = sizeof buf;
125     else
126       n = (size_t) n64; /* safe because of if condition */
127
128     ssize_t r = read (src_fd, buf, n);
129     if (r == -1) {
130       reply_with_perror ("%s: read", src);
131       close (src_fd);
132       close (dest_fd);
133       return -1;
134     }
135     if (r == 0) {
136       reply_with_error ("%s: input file too short", src);
137       close (src_fd);
138       close (dest_fd);
139       return -1;
140     }
141
142     if (xwrite (dest_fd, buf, r) == -1) {
143       reply_with_perror ("%s: write", dest);
144       close (src_fd);
145       close (dest_fd);
146       return -1;
147     }
148
149     position += r;
150     notify_progress ((uint64_t) position, (uint64_t) size);
151   }
152
153   if (close (src_fd) == -1) {
154     reply_with_perror ("%s: close", src);
155     close (dest_fd);
156     return -1;
157   }
158   if (close (dest_fd) == -1) {
159     reply_with_perror ("%s: close", dest);
160     return -1;
161   }
162
163   return 0;
164 }