blob: 7f3b25b59a71db730e782209bb3f181684db1a81 [file] [log] [blame]
Theodore Ts'o72ed1262000-11-12 19:32:20 +00001/*
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
Theodore Ts'oefc6f622008-08-27 23:07:54 -04008 * functions in this library. So sue me.
Theodore Ts'o72ed1262000-11-12 19:32:20 +00009 *
10 * %Begin-Header%
Theodore Ts'o543547a2010-05-17 21:31:56 -040011 * This file may be redistributed under the terms of the GNU Library
12 * General Public License, version 2.
Theodore Ts'o72ed1262000-11-12 19:32:20 +000013 * %End-Header%
14 */
15
Theodore Ts'od1154eb2011-09-18 17:34:37 -040016#include "config.h"
Theodore Ts'o72ed1262000-11-12 19:32:20 +000017#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
Theodore Ts'o72ed1262000-11-12 19:32:20 +000034#include "ext2_fs.h"
Theodore Ts'o72ed1262000-11-12 19:32:20 +000035#include "ext2fs.h"
36
Theodore Ts'offf45482003-04-13 00:44:19 -040037#ifndef HAVE_TYPE_SSIZE_T
38typedef int ssize_t;
39#endif
40
Theodore Ts'o72ed1262000-11-12 19:32:20 +000041/*
42 * This function returns 1 if the specified block is all zeros
43 */
44static 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
62errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
63{
64 unsigned int group, left, c, d;
65 char *buf, *cp;
Valerie Aurora Henson6d8b37f2010-06-13 11:00:00 -040066 blk64_t blk;
Theodore Ts'o72ed1262000-11-12 19:32:20 +000067 ssize_t actual;
68 errcode_t retval;
69
70 buf = malloc(fs->blocksize * BUF_BLOCKS);
71 if (!buf)
72 return ENOMEM;
Theodore Ts'oefc6f622008-08-27 23:07:54 -040073
Theodore Ts'o72ed1262000-11-12 19:32:20 +000074 for (group = 0; group < fs->group_desc_count; group++) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -040075 blk = ext2fs_inode_table_loc(fs, (unsigned)group);
Brian Behlendorff93625b2007-03-21 17:43:37 -040076 if (!blk) {
77 retval = EXT2_ET_MISSING_INODE_TABLE;
78 goto errout;
79 }
Theodore Ts'o72ed1262000-11-12 19:32:20 +000080 left = fs->inode_blocks_per_group;
81 while (left) {
82 c = BUF_BLOCKS;
83 if (c > left)
84 c = left;
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -040085 retval = io_channel_read_blk64(fs->io, blk, c, buf);
Theodore Ts'o72ed1262000-11-12 19:32:20 +000086 if (retval)
87 goto errout;
88 cp = buf;
89 while (c) {
90 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
91 d = c;
92 goto skip_sparse;
93 }
94 /* Skip zero blocks */
95 if (check_zero_block(cp, fs->blocksize)) {
96 c--;
97 blk++;
98 left--;
99 cp += fs->blocksize;
100 lseek(fd, fs->blocksize, SEEK_CUR);
101 continue;
102 }
103 /* Find non-zero blocks */
104 for (d=1; d < c; d++) {
105 if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
106 break;
107 }
108 skip_sparse:
109 actual = write(fd, cp, fs->blocksize * d);
110 if (actual == -1) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000111 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000112 goto errout;
113 }
Theodore Ts'o54434922003-12-07 01:28:50 -0500114 if (actual != (ssize_t) (fs->blocksize * d)) {
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000115 retval = EXT2_ET_SHORT_WRITE;
116 goto errout;
117 }
118 blk += d;
119 left -= d;
120 cp += fs->blocksize * d;
121 c -= d;
122 }
123 }
124 }
125 retval = 0;
126
127errout:
128 free(buf);
129 return retval;
130}
131
132/*
133 * Read in the inode table and stuff it into place
134 */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400135errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
Theodore Ts'o54434922003-12-07 01:28:50 -0500136 int flags EXT2FS_ATTR((unused)))
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000137{
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000138 unsigned int group, c, left;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000139 char *buf;
Valerie Aurora Henson6d8b37f2010-06-13 11:00:00 -0400140 blk64_t blk;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000141 ssize_t actual;
142 errcode_t retval;
143
144 buf = malloc(fs->blocksize * BUF_BLOCKS);
145 if (!buf)
146 return ENOMEM;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400147
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000148 for (group = 0; group < fs->group_desc_count; group++) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400149 blk = ext2fs_inode_table_loc(fs, (unsigned)group);
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000150 if (!blk) {
151 retval = EXT2_ET_MISSING_INODE_TABLE;
152 goto errout;
153 }
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000154 left = fs->inode_blocks_per_group;
155 while (left) {
156 c = BUF_BLOCKS;
157 if (c > left)
158 c = left;
159 actual = read(fd, buf, fs->blocksize * c);
160 if (actual == -1) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000161 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000162 goto errout;
163 }
Theodore Ts'o54434922003-12-07 01:28:50 -0500164 if (actual != (ssize_t) (fs->blocksize * c)) {
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000165 retval = EXT2_ET_SHORT_READ;
166 goto errout;
167 }
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -0400168 retval = io_channel_write_blk64(fs->io, blk, c, buf);
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000169 if (retval)
170 goto errout;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400171
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000172 blk += c;
173 left -= c;
174 }
175 }
176 retval = ext2fs_flush_icache(fs);
177
178errout:
179 free(buf);
180 return retval;
181}
182
183/*
184 * Write out superblock and group descriptors
185 */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400186errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
Theodore Ts'o54434922003-12-07 01:28:50 -0500187 int flags EXT2FS_ATTR((unused)))
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000188{
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000189 char *buf, *cp;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000190 ssize_t actual;
191 errcode_t retval;
192
193 buf = malloc(fs->blocksize);
194 if (!buf)
195 return ENOMEM;
196
197 /*
198 * Write out the superblock
199 */
200 memset(buf, 0, fs->blocksize);
201 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
202 actual = write(fd, buf, fs->blocksize);
203 if (actual == -1) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000204 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000205 goto errout;
206 }
Theodore Ts'o54434922003-12-07 01:28:50 -0500207 if (actual != (ssize_t) fs->blocksize) {
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000208 retval = EXT2_ET_SHORT_WRITE;
209 goto errout;
210 }
211
212 /*
213 * Now write out the block group descriptors
214 */
215 cp = (char *) fs->group_desc;
216 actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
217 if (actual == -1) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000218 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000219 goto errout;
220 }
Theodore Ts'o54434922003-12-07 01:28:50 -0500221 if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000222 retval = EXT2_ET_SHORT_WRITE;
223 goto errout;
224 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400225
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000226 retval = 0;
227
228errout:
229 free(buf);
230 return retval;
231}
232
233/*
234 * Read the superblock and group descriptors and overwrite them.
235 */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400236errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
Theodore Ts'o54434922003-12-07 01:28:50 -0500237 int flags EXT2FS_ATTR((unused)))
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000238{
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000239 char *buf;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000240 ssize_t actual, size;
241 errcode_t retval;
242
243 size = fs->blocksize * (fs->group_desc_count + 1);
244 buf = malloc(size);
245 if (!buf)
246 return ENOMEM;
247
248 /*
249 * Read it all in.
250 */
251 actual = read(fd, buf, size);
252 if (actual == -1) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000253 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000254 goto errout;
255 }
256 if (actual != size) {
257 retval = EXT2_ET_SHORT_READ;
258 goto errout;
259 }
260
261 /*
262 * Now copy in the superblock and group descriptors
263 */
264 memcpy(fs->super, buf, SUPERBLOCK_SIZE);
265
266 memcpy(fs->group_desc, buf + fs->blocksize,
267 fs->blocksize * fs->group_desc_count);
268
269 retval = 0;
270
271errout:
272 free(buf);
273 return retval;
274}
275
276/*
277 * Write the block/inode bitmaps.
278 */
279errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
280{
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400281 ext2fs_generic_bitmap bmap;
Theodore Ts'oe3507732013-01-01 13:28:27 -0500282 errcode_t retval;
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400283 ssize_t actual;
284 __u32 itr, cnt, size;
285 int c, total_size;
286 char buf[1024];
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000287
288 if (flags & IMAGER_FLAG_INODEMAP) {
289 if (!fs->inode_map) {
290 retval = ext2fs_read_inode_bitmap(fs);
291 if (retval)
292 return retval;
293 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400294 bmap = fs->inode_map;
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400295 itr = 1;
296 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000297 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000298 } else {
299 if (!fs->block_map) {
300 retval = ext2fs_read_block_bitmap(fs);
301 if (retval)
302 return retval;
303 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400304 bmap = fs->block_map;
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400305 itr = fs->super->s_first_data_block;
306 cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000307 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
308 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400309 total_size = size * fs->group_desc_count;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000310
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400311 while (cnt > 0) {
312 size = sizeof(buf);
313 if (size > (cnt >> 3))
314 size = (cnt >> 3);
315
Valerie Aurora Henson8f82ef92009-08-05 00:27:10 -0400316 retval = ext2fs_get_generic_bmap_range(bmap, itr,
317 size << 3, buf);
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400318 if (retval)
319 return retval;
320
321 actual = write(fd, buf, size);
322 if (actual == -1)
323 return errno;
324 if (actual != (int) size)
325 return EXT2_ET_SHORT_READ;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400326
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400327 itr += size << 3;
328 cnt -= size << 3;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000329 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400330
331 size = total_size % fs->blocksize;
332 memset(buf, 0, sizeof(buf));
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000333 if (size) {
334 size = fs->blocksize - size;
335 while (size) {
336 c = size;
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400337 if (c > (int) sizeof(buf))
338 c = sizeof(buf);
339 actual = write(fd, buf, c);
340 if (actual == -1)
341 return errno;
342 if (actual != c)
343 return EXT2_ET_SHORT_WRITE;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000344 size -= c;
345 }
346 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400347 return 0;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000348}
349
350
351/*
352 * Read the block/inode bitmaps.
353 */
354errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
355{
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400356 ext2fs_generic_bitmap bmap;
Theodore Ts'oe3507732013-01-01 13:28:27 -0500357 errcode_t retval;
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400358 __u32 itr, cnt;
359 char buf[1024];
360 unsigned int size;
361 ssize_t actual;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000362
363 if (flags & IMAGER_FLAG_INODEMAP) {
364 if (!fs->inode_map) {
365 retval = ext2fs_read_inode_bitmap(fs);
366 if (retval)
367 return retval;
368 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400369 bmap = fs->inode_map;
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400370 itr = 1;
371 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000372 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000373 } else {
374 if (!fs->block_map) {
375 retval = ext2fs_read_block_bitmap(fs);
376 if (retval)
377 return retval;
378 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400379 bmap = fs->block_map;
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400380 itr = fs->super->s_first_data_block;
381 cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000382 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
383 }
384
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400385 while (cnt > 0) {
386 size = sizeof(buf);
387 if (size > (cnt >> 3))
388 size = (cnt >> 3);
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000389
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400390 actual = read(fd, buf, size);
391 if (actual == -1)
392 return errno;
393 if (actual != (int) size)
394 return EXT2_ET_SHORT_READ;
395
Valerie Aurora Henson8f82ef92009-08-05 00:27:10 -0400396 retval = ext2fs_set_generic_bmap_range(bmap, itr,
397 size << 3, buf);
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400398 if (retval)
399 return retval;
400
401 itr += size << 3;
402 cnt -= size << 3;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000403 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400404 return 0;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000405}