Whamcloud - gitweb
Many files:
[tools/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 Public
12  * License.
13  * %End-Header%
14  */
15
16 #include <stdio.h>
17 #include <string.h>
18 #if HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif
21 #if HAVE_ERRNO_H
22 #include <errno.h>
23 #endif
24 #include <fcntl.h>
25 #include <time.h>
26 #if HAVE_SYS_STAT_H
27 #include <sys/stat.h>
28 #endif
29 #if HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32
33 #if EXT2_FLAT_INCLUDES
34 #include "ext2_fs.h"
35 #else
36 #include <linux/ext2_fs.h>
37 #endif
38
39 #include "ext2fs.h"
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         blk_t           blk;
67         ssize_t         actual;
68         errcode_t       retval;
69
70         buf = malloc(fs->blocksize * BUF_BLOCKS);
71         if (!buf)
72                 return ENOMEM;
73         
74         for (group = 0; group < fs->group_desc_count; group++) {
75                 blk = fs->group_desc[(unsigned)group].bg_inode_table;
76                 if (!blk)
77                         return EXT2_ET_MISSING_INODE_TABLE;
78                 left = fs->inode_blocks_per_group;
79                 while (left) {
80                         c = BUF_BLOCKS;
81                         if (c > left)
82                                 c = left;
83                         retval = io_channel_read_blk(fs->io, blk, c, buf);
84                         if (retval)
85                                 goto errout;
86                         cp = buf;
87                         while (c) {
88                                 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
89                                         d = c;
90                                         goto skip_sparse;
91                                 }
92                                 /* Skip zero blocks */
93                                 if (check_zero_block(cp, fs->blocksize)) {
94                                         c--;
95                                         blk++;
96                                         left--;
97                                         cp += fs->blocksize;
98                                         lseek(fd, fs->blocksize, SEEK_CUR);
99                                         continue;
100                                 }
101                                 /* Find non-zero blocks */
102                                 for (d=1; d < c; d++) {
103                                         if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
104                                                 break;
105                                 }
106                         skip_sparse:
107                                 actual = write(fd, cp, fs->blocksize * d);
108                                 if (actual == -1) {
109                                         retval = errno;
110                                         goto errout;
111                                 }
112                                 if (actual != fs->blocksize * d) {
113                                         retval = EXT2_ET_SHORT_WRITE;
114                                         goto errout;
115                                 }
116                                 blk += d;
117                                 left -= d;
118                                 cp += fs->blocksize * d;
119                                 c -= d;
120                         }
121                 }
122         }
123         retval = 0;
124
125 errout:
126         free(buf);
127         return retval;
128 }
129
130 /*
131  * Read in the inode table and stuff it into place
132  */
133 errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags)
134 {
135         unsigned int    group, c, left;
136         char            *buf;
137         blk_t           blk;
138         ssize_t         actual;
139         errcode_t       retval;
140
141         buf = malloc(fs->blocksize * BUF_BLOCKS);
142         if (!buf)
143                 return ENOMEM;
144         
145         for (group = 0; group < fs->group_desc_count; group++) {
146                 blk = fs->group_desc[(unsigned)group].bg_inode_table;
147                 if (!blk) {
148                         retval = EXT2_ET_MISSING_INODE_TABLE;
149                         goto errout;
150                 }
151                 left = fs->inode_blocks_per_group;
152                 while (left) {
153                         c = BUF_BLOCKS;
154                         if (c > left)
155                                 c = left;
156                         actual = read(fd, buf, fs->blocksize * c);
157                         if (actual == -1) {
158                                 retval = errno;
159                                 goto errout;
160                         }
161                         if (actual != fs->blocksize * c) {
162                                 retval = EXT2_ET_SHORT_READ;
163                                 goto errout;
164                         }
165                         retval = io_channel_write_blk(fs->io, blk, c, buf);
166                         if (retval)
167                                 goto errout;
168                         
169                         blk += c;
170                         left -= c;
171                 }
172         }
173         retval = ext2fs_flush_icache(fs);
174
175 errout:
176         free(buf);
177         return retval;
178 }
179
180 /*
181  * Write out superblock and group descriptors
182  */
183 errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags)
184 {
185         char            *buf, *cp;
186         ssize_t         actual;
187         errcode_t       retval;
188
189         buf = malloc(fs->blocksize);
190         if (!buf)
191                 return ENOMEM;
192
193         /*
194          * Write out the superblock
195          */
196         memset(buf, 0, fs->blocksize);
197         memcpy(buf, fs->super, SUPERBLOCK_SIZE);
198         actual = write(fd, buf, fs->blocksize);
199         if (actual == -1) {
200                 retval = errno;
201                 goto errout;
202         }
203         if (actual != fs->blocksize) {
204                 retval = EXT2_ET_SHORT_WRITE;
205                 goto errout;
206         }
207
208         /*
209          * Now write out the block group descriptors
210          */
211         cp = (char *) fs->group_desc;
212         actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
213         if (actual == -1) {
214                 retval = errno;
215                 goto errout;
216         }
217         if (actual != fs->blocksize * fs->desc_blocks) {
218                 retval = EXT2_ET_SHORT_WRITE;
219                 goto errout;
220         }
221         
222         retval = 0;
223
224 errout:
225         free(buf);
226         return retval;
227 }
228
229 /*
230  * Read the superblock and group descriptors and overwrite them.
231  */
232 errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags)
233 {
234         char            *buf;
235         ssize_t         actual, size;
236         errcode_t       retval;
237
238         size = fs->blocksize * (fs->group_desc_count + 1);
239         buf = malloc(size);
240         if (!buf)
241                 return ENOMEM;
242
243         /*
244          * Read it all in.
245          */
246         actual = read(fd, buf, size);
247         if (actual == -1) {
248                 retval = errno;
249                 goto errout;
250         }
251         if (actual != size) {
252                 retval = EXT2_ET_SHORT_READ;
253                 goto errout;
254         }
255
256         /*
257          * Now copy in the superblock and group descriptors
258          */
259         memcpy(fs->super, buf, SUPERBLOCK_SIZE);
260
261         memcpy(fs->group_desc, buf + fs->blocksize,
262                fs->blocksize * fs->group_desc_count);
263
264         retval = 0;
265
266 errout:
267         free(buf);
268         return retval;
269 }
270
271 /*
272  * Write the block/inode bitmaps.
273  */
274 errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
275 {
276         char            *ptr;
277         int             c, size;
278         char            zero_buf[1024];
279         ssize_t         actual;
280         errcode_t       retval;
281
282         if (flags & IMAGER_FLAG_INODEMAP) {
283                 if (!fs->inode_map) {
284                         retval = ext2fs_read_inode_bitmap(fs);
285                         if (retval)
286                                 return retval;
287                 }
288                 ptr = fs->inode_map->bitmap;
289                 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
290         } else {
291                 if (!fs->block_map) {
292                         retval = ext2fs_read_block_bitmap(fs);
293                         if (retval)
294                                 return retval;
295                 }
296                 ptr = fs->block_map->bitmap;
297                 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
298         }
299         size = size * fs->group_desc_count;
300
301         actual = write(fd, ptr, size);
302         if (actual == -1) {
303                 retval = errno;
304                 goto errout;
305         }
306         if (actual != size) {
307                 retval = EXT2_ET_SHORT_WRITE;
308                 goto errout;
309         }
310         size = size % fs->blocksize;
311         memset(zero_buf, 0, sizeof(zero_buf));
312         if (size) {
313                 size = fs->blocksize - size;
314                 while (size) {
315                         c = size;
316                         if (c > sizeof(zero_buf))
317                                 c = sizeof(zero_buf);
318                         actual = write(fd, zero_buf, c);
319                         if (actual == -1) {
320                                 retval = errno;
321                                 goto errout;
322                         }
323                         if (actual != c) {
324                                 retval = EXT2_ET_SHORT_WRITE;
325                                 goto errout;
326                         }
327                         size -= c;
328                 }
329         }
330         retval = 0;
331 errout:
332         return (retval);
333 }
334
335
336 /*
337  * Read the block/inode bitmaps.
338  */
339 errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
340 {
341         char            *ptr, *buf = 0;
342         int             size;
343         ssize_t         actual;
344         errcode_t       retval;
345
346         if (flags & IMAGER_FLAG_INODEMAP) {
347                 if (!fs->inode_map) {
348                         retval = ext2fs_read_inode_bitmap(fs);
349                         if (retval)
350                                 return retval;
351                 }
352                 ptr = fs->inode_map->bitmap;
353                 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
354         } else {
355                 if (!fs->block_map) {
356                         retval = ext2fs_read_block_bitmap(fs);
357                         if (retval)
358                                 return retval;
359                 }
360                 ptr = fs->block_map->bitmap;
361                 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
362         }
363         size = size * fs->group_desc_count;
364
365         buf = malloc(size);
366         if (!buf)
367                 return ENOMEM;
368
369         actual = read(fd, buf, size);
370         if (actual == -1) {
371                 retval = errno;
372                 goto errout;
373         }
374         if (actual != size) {
375                 retval = EXT2_ET_SHORT_WRITE;
376                 goto errout;
377         }
378         memcpy(ptr, buf, size);
379         
380         retval = 0;
381 errout:
382         if (buf)
383                 free(buf);
384         return (retval);
385 }