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 <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 ext2fs_generic_bitmap bmap; 281 errcode_t err, retval; 282 ssize_t actual; 283 __u32 itr, cnt, size; 284 int c, total_size; 285 char buf[1024]; 286 287 if (flags & IMAGER_FLAG_INODEMAP) { 288 if (!fs->inode_map) { 289 retval = ext2fs_read_inode_bitmap(fs); 290 if (retval) 291 return retval; 292 } 293 bmap = fs->inode_map; 294 err = EXT2_ET_MAGIC_INODE_BITMAP; 295 itr = 1; 296 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count; 297 size = (EXT2_INODES_PER_GROUP(fs->super) / 8); 298 } else { 299 if (!fs->block_map) { 300 retval = ext2fs_read_block_bitmap(fs); 301 if (retval) 302 return retval; 303 } 304 bmap = fs->block_map; 305 err = EXT2_ET_MAGIC_BLOCK_BITMAP; 306 itr = fs->super->s_first_data_block; 307 cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count; 308 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; 309 } 310 total_size = size * fs->group_desc_count; 311 312 while (cnt > 0) { 313 size = sizeof(buf); 314 if (size > (cnt >> 3)) 315 size = (cnt >> 3); 316 317 retval = ext2fs_get_generic_bitmap_range(bmap, 318 err, itr, size << 3, buf); 319 if (retval) 320 return retval; 321 322 actual = write(fd, buf, size); 323 if (actual == -1) 324 return errno; 325 if (actual != (int) size) 326 return EXT2_ET_SHORT_READ; 327 328 itr += size << 3; 329 cnt -= size << 3; 330 } 331 332 size = total_size % fs->blocksize; 333 memset(buf, 0, sizeof(buf)); 334 if (size) { 335 size = fs->blocksize - size; 336 while (size) { 337 c = size; 338 if (c > (int) sizeof(buf)) 339 c = sizeof(buf); 340 actual = write(fd, buf, c); 341 if (actual == -1) 342 return errno; 343 if (actual != c) 344 return EXT2_ET_SHORT_WRITE; 345 size -= c; 346 } 347 } 348 return 0; 349 } 350 351 352 /* 353 * Read the block/inode bitmaps. 354 */ 355 errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags) 356 { 357 ext2fs_generic_bitmap bmap; 358 errcode_t err, retval; 359 __u32 itr, cnt; 360 char buf[1024]; 361 unsigned int size; 362 ssize_t actual; 363 364 if (flags & IMAGER_FLAG_INODEMAP) { 365 if (!fs->inode_map) { 366 retval = ext2fs_read_inode_bitmap(fs); 367 if (retval) 368 return retval; 369 } 370 bmap = fs->inode_map; 371 err = EXT2_ET_MAGIC_INODE_BITMAP; 372 itr = 1; 373 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count; 374 size = (EXT2_INODES_PER_GROUP(fs->super) / 8); 375 } else { 376 if (!fs->block_map) { 377 retval = ext2fs_read_block_bitmap(fs); 378 if (retval) 379 return retval; 380 } 381 bmap = fs->block_map; 382 err = EXT2_ET_MAGIC_BLOCK_BITMAP; 383 itr = fs->super->s_first_data_block; 384 cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count; 385 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; 386 } 387 388 while (cnt > 0) { 389 size = sizeof(buf); 390 if (size > (cnt >> 3)) 391 size = (cnt >> 3); 392 393 actual = read(fd, buf, size); 394 if (actual == -1) 395 return errno; 396 if (actual != (int) size) 397 return EXT2_ET_SHORT_READ; 398 399 retval = ext2fs_set_generic_bitmap_range(bmap, 400 err, itr, size << 3, buf); 401 if (retval) 402 return retval; 403 404 itr += size << 3; 405 cnt -= size << 3; 406 } 407 return 0; 408 } 409