daemon: Move useful is_zero function to header file.
[libguestfs.git] / daemon / zero.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009-2011 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 <inttypes.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27
28 #include "daemon.h"
29 #include "actions.h"
30
31 static const char zero_buf[4096];
32
33 int
34 do_zero (const char *device)
35 {
36   char buf[sizeof zero_buf];
37   int fd;
38   size_t i, offset;
39
40   fd = open (device, O_RDWR);
41   if (fd == -1) {
42     reply_with_perror ("%s", device);
43     return -1;
44   }
45
46   for (i = 0; i < 32; ++i) {
47     offset = i * sizeof zero_buf;
48
49     /* Check if the block is already zero before overwriting it. */
50     if (pread (fd, buf, sizeof buf, offset) != sizeof buf) {
51       reply_with_perror ("pread: %s", device);
52       close (fd);
53       return -1;
54     }
55
56     if (!is_zero (buf, sizeof buf)) {
57       if (pwrite (fd, zero_buf, sizeof zero_buf, offset) != sizeof zero_buf) {
58         reply_with_perror ("pwrite: %s", device);
59         close (fd);
60         return -1;
61       }
62     }
63
64     notify_progress ((uint64_t) i, 32);
65   }
66
67   if (close (fd) == -1) {
68     reply_with_perror ("close: %s", device);
69     return -1;
70   }
71
72   return 0;
73 }
74
75 int
76 do_zero_device (const char *device)
77 {
78   int64_t ssize = do_blockdev_getsize64 (device);
79   if (ssize == -1)
80     return -1;
81   uint64_t size = (uint64_t) ssize;
82
83   int fd = open (device, O_RDWR);
84   if (fd == -1) {
85     reply_with_perror ("%s", device);
86     return -1;
87   }
88
89   char buf[sizeof zero_buf];
90
91   uint64_t pos = 0;
92
93   while (pos < size) {
94     uint64_t n64 = size - pos;
95     size_t n;
96     if (n64 > sizeof buf)
97       n = sizeof buf;
98     else
99       n = (size_t) n64; /* safe because of if condition */
100
101     /* Check if the block is already zero before overwriting it. */
102     ssize_t r;
103     r = pread (fd, buf, n, pos);
104     if (r == -1) {
105       reply_with_perror ("pread: %s at offset %" PRIu64, device, pos);
106       close (fd);
107       return -1;
108     }
109
110     if (!is_zero (buf, sizeof buf)) {
111       r = pwrite (fd, zero_buf, n, pos);
112       if (r == -1) {
113         reply_with_perror ("pwrite: %s (with %" PRId64 " bytes left to write)",
114                            device, size);
115         close (fd);
116         return -1;
117       }
118       pos += r;
119     }
120     else
121       pos += n;
122
123     notify_progress (pos, size);
124   }
125
126   if (close (fd) == -1) {
127     reply_with_perror ("close: %s", device);
128     return -1;
129   }
130
131   return 0;
132 }
133
134 int
135 do_is_zero (const char *path)
136 {
137   int fd;
138   char buf[1024*1024];
139   ssize_t r;
140
141   CHROOT_IN;
142   fd = open (path, O_RDONLY);
143   CHROOT_OUT;
144
145   if (fd == -1) {
146     reply_with_perror ("open: %s", path);
147     return -1;
148   }
149
150   while ((r = read (fd, buf, sizeof buf)) > 0) {
151     if (!is_zero (buf, r)) {
152       close (fd);
153       return 0;
154     }
155   }
156
157   if (r == -1) {
158     reply_with_perror ("read: %s", path);
159     close (fd);
160     return -1;
161   }
162
163   if (close (fd) == -1) {
164     reply_with_perror ("close: %s", path);
165     return -1;
166   }
167
168   return 1;
169 }
170
171 int
172 do_is_zero_device (const char *device)
173 {
174   int fd;
175   char buf[1024*1024];
176   ssize_t r;
177
178   fd = open (device, O_RDONLY);
179   if (fd == -1) {
180     reply_with_perror ("open: %s", device);
181     return -1;
182   }
183
184   while ((r = read (fd, buf, sizeof buf)) > 0) {
185     if (!is_zero (buf, r)) {
186       close (fd);
187       return 0;
188     }
189   }
190
191   if (r == -1) {
192     reply_with_perror ("read: %s", device);
193     close (fd);
194     return -1;
195   }
196
197   if (close (fd) == -1) {
198     reply_with_perror ("close: %s", device);
199     return -1;
200   }
201
202   return 1;
203 }