blob: e82321efac1bc71177d78072df298be546211b76 [file] [log] [blame]
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001/* vi: set sw=4 ts=4: */
2/*
3 * image.c --- writes out the critical parts of the filesystem as a
4 * flat file.
5 *
6 * Copyright (C) 2000 Theodore Ts'o.
7 *
8 * Note: this uses the POSIX IO interfaces, unlike most of the other
9 * functions in this library. So sue me.
10 *
11 * %Begin-Header%
12 * This file may be redistributed under the terms of the GNU Public
13 * License.
14 * %End-Header%
15 */
16
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
38typedef int ssize_t;
39#endif
40
41/*
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;
66 blk_t blk;
67 ssize_t actual;
68 errcode_t retval;
69
70 buf = xmalloc(fs->blocksize * BUF_BLOCKS);
71
72 for (group = 0; group < fs->group_desc_count; group++) {
73 blk = fs->group_desc[(unsigned)group].bg_inode_table;
74 if (!blk)
75 return EXT2_ET_MISSING_INODE_TABLE;
76 left = fs->inode_blocks_per_group;
77 while (left) {
78 c = BUF_BLOCKS;
79 if (c > left)
80 c = left;
81 retval = io_channel_read_blk(fs->io, blk, c, buf);
82 if (retval)
83 goto errout;
84 cp = buf;
85 while (c) {
86 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
87 d = c;
88 goto skip_sparse;
89 }
90 /* Skip zero blocks */
91 if (check_zero_block(cp, fs->blocksize)) {
92 c--;
93 blk++;
94 left--;
95 cp += fs->blocksize;
96 lseek(fd, fs->blocksize, SEEK_CUR);
97 continue;
98 }
99 /* Find non-zero blocks */
100 for (d=1; d < c; d++) {
101 if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
102 break;
103 }
104 skip_sparse:
105 actual = write(fd, cp, fs->blocksize * d);
106 if (actual == -1) {
107 retval = errno;
108 goto errout;
109 }
110 if (actual != (ssize_t) (fs->blocksize * d)) {
111 retval = EXT2_ET_SHORT_WRITE;
112 goto errout;
113 }
114 blk += d;
115 left -= d;
116 cp += fs->blocksize * d;
117 c -= d;
118 }
119 }
120 }
121 retval = 0;
122
123errout:
124 free(buf);
125 return retval;
126}
127
128/*
129 * Read in the inode table and stuff it into place
130 */
131errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
132 int flags EXT2FS_ATTR((unused)))
133{
134 unsigned int group, c, left;
135 char *buf;
136 blk_t blk;
137 ssize_t actual;
138 errcode_t retval;
139
140 buf = xmalloc(fs->blocksize * BUF_BLOCKS);
141
142 for (group = 0; group < fs->group_desc_count; group++) {
143 blk = fs->group_desc[(unsigned)group].bg_inode_table;
144 if (!blk) {
145 retval = EXT2_ET_MISSING_INODE_TABLE;
146 goto errout;
147 }
148 left = fs->inode_blocks_per_group;
149 while (left) {
150 c = BUF_BLOCKS;
151 if (c > left)
152 c = left;
153 actual = read(fd, buf, fs->blocksize * c);
154 if (actual == -1) {
155 retval = errno;
156 goto errout;
157 }
158 if (actual != (ssize_t) (fs->blocksize * c)) {
159 retval = EXT2_ET_SHORT_READ;
160 goto errout;
161 }
162 retval = io_channel_write_blk(fs->io, blk, c, buf);
163 if (retval)
164 goto errout;
165
166 blk += c;
167 left -= c;
168 }
169 }
170 retval = ext2fs_flush_icache(fs);
171
172errout:
173 free(buf);
174 return retval;
175}
176
177/*
178 * Write out superblock and group descriptors
179 */
180errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
181 int flags EXT2FS_ATTR((unused)))
182{
183 char *buf, *cp;
184 ssize_t actual;
185 errcode_t retval;
186
187 buf = xmalloc(fs->blocksize);
188
189 /*
190 * Write out the superblock
191 */
192 memset(buf, 0, fs->blocksize);
193 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
194 actual = write(fd, buf, fs->blocksize);
195 if (actual == -1) {
196 retval = errno;
197 goto errout;
198 }
199 if (actual != (ssize_t) fs->blocksize) {
200 retval = EXT2_ET_SHORT_WRITE;
201 goto errout;
202 }
203
204 /*
205 * Now write out the block group descriptors
206 */
207 cp = (char *) fs->group_desc;
208 actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
209 if (actual == -1) {
210 retval = errno;
211 goto errout;
212 }
213 if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
214 retval = EXT2_ET_SHORT_WRITE;
215 goto errout;
216 }
217
218 retval = 0;
219
220errout:
221 free(buf);
222 return retval;
223}
224
225/*
226 * Read the superblock and group descriptors and overwrite them.
227 */
228errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
229 int flags EXT2FS_ATTR((unused)))
230{
231 char *buf;
232 ssize_t actual, size;
233 errcode_t retval;
234
235 size = fs->blocksize * (fs->group_desc_count + 1);
236 buf = xmalloc(size);
237
238 /*
239 * Read it all in.
240 */
241 actual = read(fd, buf, size);
242 if (actual == -1) {
243 retval = errno;
244 goto errout;
245 }
246 if (actual != size) {
247 retval = EXT2_ET_SHORT_READ;
248 goto errout;
249 }
250
251 /*
252 * Now copy in the superblock and group descriptors
253 */
254 memcpy(fs->super, buf, SUPERBLOCK_SIZE);
255
256 memcpy(fs->group_desc, buf + fs->blocksize,
257 fs->blocksize * fs->group_desc_count);
258
259 retval = 0;
260
261errout:
262 free(buf);
263 return retval;
264}
265
266/*
267 * Write the block/inode bitmaps.
268 */
269errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
270{
271 char *ptr;
272 int c, size;
273 char zero_buf[1024];
274 ssize_t actual;
275 errcode_t retval;
276
277 if (flags & IMAGER_FLAG_INODEMAP) {
278 if (!fs->inode_map) {
279 retval = ext2fs_read_inode_bitmap(fs);
280 if (retval)
281 return retval;
282 }
283 ptr = fs->inode_map->bitmap;
284 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
285 } else {
286 if (!fs->block_map) {
287 retval = ext2fs_read_block_bitmap(fs);
288 if (retval)
289 return retval;
290 }
291 ptr = fs->block_map->bitmap;
292 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
293 }
294 size = size * fs->group_desc_count;
295
296 actual = write(fd, ptr, size);
297 if (actual == -1) {
298 retval = errno;
299 goto errout;
300 }
301 if (actual != size) {
302 retval = EXT2_ET_SHORT_WRITE;
303 goto errout;
304 }
305 size = size % fs->blocksize;
306 memset(zero_buf, 0, sizeof(zero_buf));
307 if (size) {
308 size = fs->blocksize - size;
309 while (size) {
310 c = size;
311 if (c > (int) sizeof(zero_buf))
312 c = sizeof(zero_buf);
313 actual = write(fd, zero_buf, c);
314 if (actual == -1) {
315 retval = errno;
316 goto errout;
317 }
318 if (actual != c) {
319 retval = EXT2_ET_SHORT_WRITE;
320 goto errout;
321 }
322 size -= c;
323 }
324 }
325 retval = 0;
326errout:
327 return retval;
328}
329
330
331/*
332 * Read the block/inode bitmaps.
333 */
334errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
335{
336 char *ptr, *buf = 0;
337 int size;
338 ssize_t actual;
339 errcode_t retval;
340
341 if (flags & IMAGER_FLAG_INODEMAP) {
342 if (!fs->inode_map) {
343 retval = ext2fs_read_inode_bitmap(fs);
344 if (retval)
345 return retval;
346 }
347 ptr = fs->inode_map->bitmap;
348 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
349 } else {
350 if (!fs->block_map) {
351 retval = ext2fs_read_block_bitmap(fs);
352 if (retval)
353 return retval;
354 }
355 ptr = fs->block_map->bitmap;
356 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
357 }
358 size = size * fs->group_desc_count;
359
360 buf = xmalloc(size);
361
362 actual = read(fd, buf, size);
363 if (actual == -1) {
364 retval = errno;
365 goto errout;
366 }
367 if (actual != size) {
368 retval = EXT2_ET_SHORT_WRITE;
369 goto errout;
370 }
371 memcpy(ptr, buf, size);
372
373 retval = 0;
374errout:
375 free(buf);
376 return retval;
377}