blob: a0fb81e425b6fd2acf89150ac6505a76ea02af0b [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;
282 errcode_t err, retval;
283 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;
295 err = EXT2_ET_MAGIC_INODE_BITMAP;
296 itr = 1;
297 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000298 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000299 } else {
300 if (!fs->block_map) {
301 retval = ext2fs_read_block_bitmap(fs);
302 if (retval)
303 return retval;
304 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400305 bmap = fs->block_map;
306 err = EXT2_ET_MAGIC_BLOCK_BITMAP;
307 itr = fs->super->s_first_data_block;
308 cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000309 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
310 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400311 total_size = size * fs->group_desc_count;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000312
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400313 while (cnt > 0) {
314 size = sizeof(buf);
315 if (size > (cnt >> 3))
316 size = (cnt >> 3);
317
Valerie Aurora Henson8f82ef92009-08-05 00:27:10 -0400318 retval = ext2fs_get_generic_bmap_range(bmap, itr,
319 size << 3, buf);
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400320 if (retval)
321 return retval;
322
323 actual = write(fd, buf, size);
324 if (actual == -1)
325 return errno;
326 if (actual != (int) size)
327 return EXT2_ET_SHORT_READ;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400328
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400329 itr += size << 3;
330 cnt -= size << 3;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000331 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400332
333 size = total_size % fs->blocksize;
334 memset(buf, 0, sizeof(buf));
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000335 if (size) {
336 size = fs->blocksize - size;
337 while (size) {
338 c = size;
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400339 if (c > (int) sizeof(buf))
340 c = sizeof(buf);
341 actual = write(fd, buf, c);
342 if (actual == -1)
343 return errno;
344 if (actual != c)
345 return EXT2_ET_SHORT_WRITE;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000346 size -= c;
347 }
348 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400349 return 0;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000350}
351
352
353/*
354 * Read the block/inode bitmaps.
355 */
356errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
357{
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400358 ext2fs_generic_bitmap bmap;
359 errcode_t err, retval;
360 __u32 itr, cnt;
361 char buf[1024];
362 unsigned int size;
363 ssize_t actual;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000364
365 if (flags & IMAGER_FLAG_INODEMAP) {
366 if (!fs->inode_map) {
367 retval = ext2fs_read_inode_bitmap(fs);
368 if (retval)
369 return retval;
370 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400371 bmap = fs->inode_map;
372 err = EXT2_ET_MAGIC_INODE_BITMAP;
373 itr = 1;
374 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000375 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000376 } else {
377 if (!fs->block_map) {
378 retval = ext2fs_read_block_bitmap(fs);
379 if (retval)
380 return retval;
381 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400382 bmap = fs->block_map;
383 err = EXT2_ET_MAGIC_BLOCK_BITMAP;
384 itr = fs->super->s_first_data_block;
385 cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000386 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
387 }
388
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400389 while (cnt > 0) {
390 size = sizeof(buf);
391 if (size > (cnt >> 3))
392 size = (cnt >> 3);
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000393
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400394 actual = read(fd, buf, size);
395 if (actual == -1)
396 return errno;
397 if (actual != (int) size)
398 return EXT2_ET_SHORT_READ;
399
Valerie Aurora Henson8f82ef92009-08-05 00:27:10 -0400400 retval = ext2fs_set_generic_bmap_range(bmap, itr,
401 size << 3, buf);
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400402 if (retval)
403 return retval;
404
405 itr += size << 3;
406 cnt -= size << 3;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000407 }
Theodore Ts'of1f115a2007-07-23 04:32:48 -0400408 return 0;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000409}