progress: Make default UTF-8 progress bar less black.
[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 /* Return true iff the buffer is all zero bytes.
32  *
33  * Note that gcc is smart enough to optimize this properly:
34  * http://stackoverflow.com/questions/1493936/faster-means-of-checking-for-an-empty-buffer-in-c/1493989#1493989
35  */
36 static int
37 is_zero (const char *buffer, size_t size)
38 {
39   size_t i;
40
41   for (i = 0; i < size; ++i) {
42     if (buffer[i] != 0)
43       return 0;
44   }
45
46   return 1;
47 }
48
49 static const char zero_buf[4096];
50
51 int
52 do_zero (const char *device)
53 {
54   char buf[sizeof zero_buf];
55   int fd;
56   size_t i, offset;
57
58   fd = open (device, O_RDWR);
59   if (fd == -1) {
60     reply_with_perror ("%s", device);
61     return -1;
62   }
63
64   for (i = 0; i < 32; ++i) {
65     offset = i * sizeof zero_buf;
66
67     /* Check if the block is already zero before overwriting it. */
68     if (pread (fd, buf, sizeof buf, offset) != sizeof buf) {
69       reply_with_perror ("pread: %s", device);
70       close (fd);
71       return -1;
72     }
73
74     if (!is_zero (buf, sizeof buf)) {
75       if (pwrite (fd, zero_buf, sizeof zero_buf, offset) != sizeof zero_buf) {
76         reply_with_perror ("pwrite: %s", device);
77         close (fd);
78         return -1;
79       }
80     }
81
82     notify_progress ((uint64_t) i, 32);
83   }
84
85   if (close (fd) == -1) {
86     reply_with_perror ("close: %s", device);
87     return -1;
88   }
89
90   return 0;
91 }
92
93 int
94 do_zero_device (const char *device)
95 {
96   int64_t ssize = do_blockdev_getsize64 (device);
97   if (ssize == -1)
98     return -1;
99   uint64_t size = (uint64_t) ssize;
100
101   int fd = open (device, O_RDWR);
102   if (fd == -1) {
103     reply_with_perror ("%s", device);
104     return -1;
105   }
106
107   char buf[sizeof zero_buf];
108
109   uint64_t pos = 0;
110
111   while (pos < size) {
112     uint64_t n64 = size - pos;
113     size_t n;
114     if (n64 > sizeof buf)
115       n = sizeof buf;
116     else
117       n = (size_t) n64; /* safe because of if condition */
118
119     /* Check if the block is already zero before overwriting it. */
120     ssize_t r;
121     r = pread (fd, buf, n, pos);
122     if (r == -1) {
123       reply_with_perror ("pread: %s at offset %" PRIu64, device, pos);
124       close (fd);
125       return -1;
126     }
127
128     if (!is_zero (buf, sizeof buf)) {
129       r = pwrite (fd, zero_buf, n, pos);
130       if (r == -1) {
131         reply_with_perror ("pwrite: %s (with %" PRId64 " bytes left to write)",
132                            device, size);
133         close (fd);
134         return -1;
135       }
136       pos += r;
137     }
138     else
139       pos += n;
140
141     notify_progress (pos, size);
142   }
143
144   if (close (fd) == -1) {
145     reply_with_perror ("close: %s", device);
146     return -1;
147   }
148
149   return 0;
150 }
151
152 int
153 do_is_zero (const char *path)
154 {
155   int fd;
156   char buf[1024*1024];
157   ssize_t r;
158
159   CHROOT_IN;
160   fd = open (path, O_RDONLY);
161   CHROOT_OUT;
162
163   if (fd == -1) {
164     reply_with_perror ("open: %s", path);
165     return -1;
166   }
167
168   while ((r = read (fd, buf, sizeof buf)) > 0) {
169     if (!is_zero (buf, r)) {
170       close (fd);
171       return 0;
172     }
173   }
174
175   if (r == -1) {
176     reply_with_perror ("read: %s", path);
177     close (fd);
178     return -1;
179   }
180
181   if (close (fd) == -1) {
182     reply_with_perror ("close: %s", path);
183     return -1;
184   }
185
186   return 1;
187 }
188
189 int
190 do_is_zero_device (const char *device)
191 {
192   int fd;
193   char buf[1024*1024];
194   ssize_t r;
195
196   fd = open (device, O_RDONLY);
197   if (fd == -1) {
198     reply_with_perror ("open: %s", device);
199     return -1;
200   }
201
202   while ((r = read (fd, buf, sizeof buf)) > 0) {
203     if (!is_zero (buf, r)) {
204       close (fd);
205       return 0;
206     }
207   }
208
209   if (r == -1) {
210     reply_with_perror ("read: %s", device);
211     close (fd);
212     return -1;
213   }
214
215   if (close (fd) == -1) {
216     reply_with_perror ("close: %s", device);
217     return -1;
218   }
219
220   return 1;
221 }