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