Whamcloud - gitweb
Remove the a.out DLL support, since it's been obsolete and unmaintained
[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                         return EXT2_ET_MISSING_INODE_TABLE;
77                 left = fs->inode_blocks_per_group;
78                 while (left) {
79                         c = BUF_BLOCKS;
80                         if (c > left)
81                                 c = left;
82                         retval = io_channel_read_blk(fs->io, blk, c, buf);
83                         if (retval)
84                                 goto errout;
85                         cp = buf;
86                         while (c) {
87                                 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
88                                         d = c;
89                                         goto skip_sparse;
90                                 }
91                                 /* Skip zero blocks */
92                                 if (check_zero_block(cp, fs->blocksize)) {
93                                         c--;
94                                         blk++;
95                                         left--;
96                                         cp += fs->blocksize;
97                                         lseek(fd, fs->blocksize, SEEK_CUR);
98                                         continue;
99                                 }
100                                 /* Find non-zero blocks */
101                                 for (d=1; d < c; d++) {
102                                         if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
103                                                 break;
104                                 }
105                         skip_sparse:
106                                 actual = write(fd, cp, fs->blocksize * d);
107                                 if (actual == -1) {
108                                         retval = errno;
109                                         goto errout;
110                                 }
111                                 if (actual != (ssize_t) (fs->blocksize * d)) {
112                                         retval = EXT2_ET_SHORT_WRITE;
113                                         goto errout;
114                                 }
115                                 blk += d;
116                                 left -= d;
117                                 cp += fs->blocksize * d;
118                                 c -= d;
119                         }
120                 }
121         }
122         retval = 0;
123
124 errout:
125         free(buf);
126         return retval;
127 }
128
129 /*
130  * Read in the inode table and stuff it into place
131  */
132 errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, 
133                                   int flags EXT2FS_ATTR((unused)))
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 != (ssize_t) (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, 
184                                    int flags EXT2FS_ATTR((unused)))
185 {
186         char            *buf, *cp;
187         ssize_t         actual;
188         errcode_t       retval;
189
190         buf = malloc(fs->blocksize);
191         if (!buf)
192                 return ENOMEM;
193
194         /*
195          * Write out the superblock
196          */
197         memset(buf, 0, fs->blocksize);
198         memcpy(buf, fs->super, SUPERBLOCK_SIZE);
199         actual = write(fd, buf, fs->blocksize);
200         if (actual == -1) {
201                 retval = errno;
202                 goto errout;
203         }
204         if (actual != (ssize_t) fs->blocksize) {
205                 retval = EXT2_ET_SHORT_WRITE;
206                 goto errout;
207         }
208
209         /*
210          * Now write out the block group descriptors
211          */
212         cp = (char *) fs->group_desc;
213         actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
214         if (actual == -1) {
215                 retval = errno;
216                 goto errout;
217         }
218         if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
219                 retval = EXT2_ET_SHORT_WRITE;
220                 goto errout;
221         }
222         
223         retval = 0;
224
225 errout:
226         free(buf);
227         return retval;
228 }
229
230 /*
231  * Read the superblock and group descriptors and overwrite them.
232  */
233 errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, 
234                                   int flags EXT2FS_ATTR((unused)))
235 {
236         char            *buf;
237         ssize_t         actual, size;
238         errcode_t       retval;
239
240         size = fs->blocksize * (fs->group_desc_count + 1);
241         buf = malloc(size);
242         if (!buf)
243                 return ENOMEM;
244
245         /*
246          * Read it all in.
247          */
248         actual = read(fd, buf, size);
249         if (actual == -1) {
250                 retval = errno;
251                 goto errout;
252         }
253         if (actual != size) {
254                 retval = EXT2_ET_SHORT_READ;
255                 goto errout;
256         }
257
258         /*
259          * Now copy in the superblock and group descriptors
260          */
261         memcpy(fs->super, buf, SUPERBLOCK_SIZE);
262
263         memcpy(fs->group_desc, buf + fs->blocksize,
264                fs->blocksize * fs->group_desc_count);
265
266         retval = 0;
267
268 errout:
269         free(buf);
270         return retval;
271 }
272
273 /*
274  * Write the block/inode bitmaps.
275  */
276 errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
277 {
278         char            *ptr;
279         int             c, size;
280         char            zero_buf[1024];
281         ssize_t         actual;
282         errcode_t       retval;
283
284         if (flags & IMAGER_FLAG_INODEMAP) {
285                 if (!fs->inode_map) {
286                         retval = ext2fs_read_inode_bitmap(fs);
287                         if (retval)
288                                 return retval;
289                 }
290                 ptr = fs->inode_map->bitmap;
291                 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
292         } else {
293                 if (!fs->block_map) {
294                         retval = ext2fs_read_block_bitmap(fs);
295                         if (retval)
296                                 return retval;
297                 }
298                 ptr = fs->block_map->bitmap;
299                 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
300         }
301         size = size * fs->group_desc_count;
302
303         actual = write(fd, ptr, size);
304         if (actual == -1) {
305                 retval = errno;
306                 goto errout;
307         }
308         if (actual != size) {
309                 retval = EXT2_ET_SHORT_WRITE;
310                 goto errout;
311         }
312         size = size % fs->blocksize;
313         memset(zero_buf, 0, sizeof(zero_buf));
314         if (size) {
315                 size = fs->blocksize - size;
316                 while (size) {
317                         c = size;
318                         if (c > (int) sizeof(zero_buf))
319                                 c = sizeof(zero_buf);
320                         actual = write(fd, zero_buf, c);
321                         if (actual == -1) {
322                                 retval = errno;
323                                 goto errout;
324                         }
325                         if (actual != c) {
326                                 retval = EXT2_ET_SHORT_WRITE;
327                                 goto errout;
328                         }
329                         size -= c;
330                 }
331         }
332         retval = 0;
333 errout:
334         return (retval);
335 }
336
337
338 /*
339  * Read the block/inode bitmaps.
340  */
341 errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
342 {
343         char            *ptr, *buf = 0;
344         int             size;
345         ssize_t         actual;
346         errcode_t       retval;
347
348         if (flags & IMAGER_FLAG_INODEMAP) {
349                 if (!fs->inode_map) {
350                         retval = ext2fs_read_inode_bitmap(fs);
351                         if (retval)
352                                 return retval;
353                 }
354                 ptr = fs->inode_map->bitmap;
355                 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
356         } else {
357                 if (!fs->block_map) {
358                         retval = ext2fs_read_block_bitmap(fs);
359                         if (retval)
360                                 return retval;
361                 }
362                 ptr = fs->block_map->bitmap;
363                 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
364         }
365         size = size * fs->group_desc_count;
366
367         buf = malloc(size);
368         if (!buf)
369                 return ENOMEM;
370
371         actual = read(fd, buf, size);
372         if (actual == -1) {
373                 retval = errno;
374                 goto errout;
375         }
376         if (actual != size) {
377                 retval = EXT2_ET_SHORT_WRITE;
378                 goto errout;
379         }
380         memcpy(ptr, buf, size);
381         
382         retval = 0;
383 errout:
384         if (buf)
385                 free(buf);
386         return (retval);
387 }