]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - lib/ext2fs/imager.c
libext2fs: check return values
[thirdparty/e2fsprogs.git] / lib / ext2fs / imager.c
1 /*
2 * image.c --- writes out the critical parts of the filesystem as a
3 * flat file.
4 *
5 * Copyright (C) 2000 Theodore Ts'o.
6 *
7 * Note: this uses the POSIX IO interfaces, unlike most of the other
8 * functions in this library. So sue me.
9 *
10 * %Begin-Header%
11 * This file may be redistributed under the terms of the GNU Library
12 * General Public License, version 2.
13 * %End-Header%
14 */
15
16 #include "config.h"
17 #include <stdio.h>
18 #include <string.h>
19 #if HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22 #if HAVE_ERRNO_H
23 #include <errno.h>
24 #endif
25 #include <fcntl.h>
26 #include <time.h>
27 #if HAVE_SYS_STAT_H
28 #include <sys/stat.h>
29 #endif
30 #if HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33
34 #include "ext2_fs.h"
35 #include "ext2fs.h"
36
37 #ifndef HAVE_TYPE_SSIZE_T
38 typedef int ssize_t;
39 #endif
40
41 /*
42 * This function returns 1 if the specified block is all zeros
43 */
44 static int check_zero_block(char *buf, int blocksize)
45 {
46 char *cp = buf;
47 int left = blocksize;
48
49 while (left > 0) {
50 if (*cp++)
51 return 0;
52 left--;
53 }
54 return 1;
55 }
56
57 /*
58 * Write the inode table out as a single block.
59 */
60 #define BUF_BLOCKS 32
61
62 errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
63 {
64 unsigned int group, left, c, d;
65 char *buf, *cp;
66 blk64_t blk;
67 ssize_t actual;
68 errcode_t retval;
69 off_t r;
70
71 buf = malloc(fs->blocksize * BUF_BLOCKS);
72 if (!buf)
73 return ENOMEM;
74
75 for (group = 0; group < fs->group_desc_count; group++) {
76 blk = ext2fs_inode_table_loc(fs, (unsigned)group);
77 if (!blk) {
78 retval = EXT2_ET_MISSING_INODE_TABLE;
79 goto errout;
80 }
81 left = fs->inode_blocks_per_group;
82 while (left) {
83 c = BUF_BLOCKS;
84 if (c > left)
85 c = left;
86 retval = io_channel_read_blk64(fs->io, blk, c, buf);
87 if (retval)
88 goto errout;
89 cp = buf;
90 while (c) {
91 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
92 d = c;
93 goto skip_sparse;
94 }
95 /* Skip zero blocks */
96 if (check_zero_block(cp, fs->blocksize)) {
97 c--;
98 blk++;
99 left--;
100 cp += fs->blocksize;
101 r = lseek(fd, fs->blocksize, SEEK_CUR);
102 if (r < 0) {
103 retval = errno;
104 goto errout;
105 }
106 continue;
107 }
108 /* Find non-zero blocks */
109 for (d=1; d < c; d++) {
110 if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
111 break;
112 }
113 skip_sparse:
114 actual = write(fd, cp, fs->blocksize * d);
115 if (actual == -1) {
116 retval = errno;
117 goto errout;
118 }
119 if (actual != (ssize_t) (fs->blocksize * d)) {
120 retval = EXT2_ET_SHORT_WRITE;
121 goto errout;
122 }
123 blk += d;
124 left -= d;
125 cp += fs->blocksize * d;
126 c -= d;
127 }
128 }
129 }
130 retval = 0;
131
132 errout:
133 free(buf);
134 return retval;
135 }
136
137 /*
138 * Read in the inode table and stuff it into place
139 */
140 errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
141 int flags EXT2FS_ATTR((unused)))
142 {
143 unsigned int group, c, left;
144 char *buf;
145 blk64_t blk;
146 ssize_t actual;
147 errcode_t retval;
148
149 buf = malloc(fs->blocksize * BUF_BLOCKS);
150 if (!buf)
151 return ENOMEM;
152
153 for (group = 0; group < fs->group_desc_count; group++) {
154 blk = ext2fs_inode_table_loc(fs, (unsigned)group);
155 if (!blk) {
156 retval = EXT2_ET_MISSING_INODE_TABLE;
157 goto errout;
158 }
159 left = fs->inode_blocks_per_group;
160 while (left) {
161 c = BUF_BLOCKS;
162 if (c > left)
163 c = left;
164 actual = read(fd, buf, fs->blocksize * c);
165 if (actual == -1) {
166 retval = errno;
167 goto errout;
168 }
169 if (actual != (ssize_t) (fs->blocksize * c)) {
170 retval = EXT2_ET_SHORT_READ;
171 goto errout;
172 }
173 retval = io_channel_write_blk64(fs->io, blk, c, buf);
174 if (retval)
175 goto errout;
176
177 blk += c;
178 left -= c;
179 }
180 }
181 retval = ext2fs_flush_icache(fs);
182
183 errout:
184 free(buf);
185 return retval;
186 }
187
188 /*
189 * Write out superblock and group descriptors
190 */
191 errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
192 int flags EXT2FS_ATTR((unused)))
193 {
194 char *buf, *cp;
195 ssize_t actual;
196 errcode_t retval;
197
198 buf = malloc(fs->blocksize);
199 if (!buf)
200 return ENOMEM;
201
202 /*
203 * Write out the superblock
204 */
205 memset(buf, 0, fs->blocksize);
206 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
207 actual = write(fd, buf, fs->blocksize);
208 if (actual == -1) {
209 retval = errno;
210 goto errout;
211 }
212 if (actual != (ssize_t) fs->blocksize) {
213 retval = EXT2_ET_SHORT_WRITE;
214 goto errout;
215 }
216
217 /*
218 * Now write out the block group descriptors
219 */
220 cp = (char *) fs->group_desc;
221 actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
222 if (actual == -1) {
223 retval = errno;
224 goto errout;
225 }
226 if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
227 retval = EXT2_ET_SHORT_WRITE;
228 goto errout;
229 }
230
231 retval = 0;
232
233 errout:
234 free(buf);
235 return retval;
236 }
237
238 /*
239 * Read the superblock and group descriptors and overwrite them.
240 */
241 errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
242 int flags EXT2FS_ATTR((unused)))
243 {
244 char *buf;
245 ssize_t actual, size;
246 errcode_t retval;
247
248 size = fs->blocksize * (fs->group_desc_count + 1);
249 buf = malloc(size);
250 if (!buf)
251 return ENOMEM;
252
253 /*
254 * Read it all in.
255 */
256 actual = read(fd, buf, size);
257 if (actual == -1) {
258 retval = errno;
259 goto errout;
260 }
261 if (actual != size) {
262 retval = EXT2_ET_SHORT_READ;
263 goto errout;
264 }
265
266 /*
267 * Now copy in the superblock and group descriptors
268 */
269 memcpy(fs->super, buf, SUPERBLOCK_SIZE);
270
271 memcpy(fs->group_desc, buf + fs->blocksize,
272 fs->blocksize * fs->group_desc_count);
273
274 retval = 0;
275
276 errout:
277 free(buf);
278 return retval;
279 }
280
281 /*
282 * Write the block/inode bitmaps.
283 */
284 errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
285 {
286 ext2fs_generic_bitmap bmap;
287 errcode_t retval;
288 ssize_t actual;
289 __u32 itr, cnt, size;
290 int c, total_size;
291 char buf[1024];
292
293 if (flags & IMAGER_FLAG_INODEMAP) {
294 if (!fs->inode_map) {
295 retval = ext2fs_read_inode_bitmap(fs);
296 if (retval)
297 return retval;
298 }
299 bmap = fs->inode_map;
300 itr = 1;
301 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
302 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
303 } else {
304 if (!fs->block_map) {
305 retval = ext2fs_read_block_bitmap(fs);
306 if (retval)
307 return retval;
308 }
309 bmap = fs->block_map;
310 itr = fs->super->s_first_data_block;
311 cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
312 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
313 }
314 total_size = size * fs->group_desc_count;
315
316 while (cnt > 0) {
317 size = sizeof(buf);
318 if (size > (cnt >> 3))
319 size = (cnt >> 3);
320
321 retval = ext2fs_get_generic_bmap_range(bmap, itr,
322 size << 3, buf);
323 if (retval)
324 return retval;
325
326 actual = write(fd, buf, size);
327 if (actual == -1)
328 return errno;
329 if (actual != (int) size)
330 return EXT2_ET_SHORT_READ;
331
332 itr += size << 3;
333 cnt -= size << 3;
334 }
335
336 size = total_size % fs->blocksize;
337 memset(buf, 0, sizeof(buf));
338 if (size) {
339 size = fs->blocksize - size;
340 while (size) {
341 c = size;
342 if (c > (int) sizeof(buf))
343 c = sizeof(buf);
344 actual = write(fd, buf, c);
345 if (actual == -1)
346 return errno;
347 if (actual != c)
348 return EXT2_ET_SHORT_WRITE;
349 size -= c;
350 }
351 }
352 return 0;
353 }
354
355
356 /*
357 * Read the block/inode bitmaps.
358 */
359 errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
360 {
361 ext2fs_generic_bitmap bmap;
362 errcode_t retval;
363 __u32 itr, cnt;
364 char buf[1024];
365 unsigned int size;
366 ssize_t actual;
367
368 if (flags & IMAGER_FLAG_INODEMAP) {
369 if (!fs->inode_map) {
370 retval = ext2fs_read_inode_bitmap(fs);
371 if (retval)
372 return retval;
373 }
374 bmap = fs->inode_map;
375 itr = 1;
376 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
377 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
378 } else {
379 if (!fs->block_map) {
380 retval = ext2fs_read_block_bitmap(fs);
381 if (retval)
382 return retval;
383 }
384 bmap = fs->block_map;
385 itr = fs->super->s_first_data_block;
386 cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
387 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
388 }
389
390 while (cnt > 0) {
391 size = sizeof(buf);
392 if (size > (cnt >> 3))
393 size = (cnt >> 3);
394
395 actual = read(fd, buf, size);
396 if (actual == -1)
397 return errno;
398 if (actual != (int) size)
399 return EXT2_ET_SHORT_READ;
400
401 retval = ext2fs_set_generic_bmap_range(bmap, itr,
402 size << 3, buf);
403 if (retval)
404 return retval;
405
406 itr += size << 3;
407 cnt -= size << 3;
408 }
409 return 0;
410 }