Initial public busybox upstream commit
[busybox4maemo] / e2fsprogs / old_e2fsprogs / ext2fs / imager.c
1 /* 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
38 typedef int ssize_t;
39 #endif
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 = 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
123 errout:
124         free(buf);
125         return retval;
126 }
127
128 /*
129  * Read in the inode table and stuff it into place
130  */
131 errcode_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
172 errout:
173         free(buf);
174         return retval;
175 }
176
177 /*
178  * Write out superblock and group descriptors
179  */
180 errcode_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
220 errout:
221         free(buf);
222         return retval;
223 }
224
225 /*
226  * Read the superblock and group descriptors and overwrite them.
227  */
228 errcode_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
261 errout:
262         free(buf);
263         return retval;
264 }
265
266 /*
267  * Write the block/inode bitmaps.
268  */
269 errcode_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;
326 errout:
327         return retval;
328 }
329
330
331 /*
332  * Read the block/inode bitmaps.
333  */
334 errcode_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;
374 errout:
375         free(buf);
376         return retval;
377 }