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