imager.c revision fff45483ede7fe38a31b3364a9c07e2418776dee
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 37typedef int ssize_t; 38#endif 39 40/* 41 * This function returns 1 if the specified block is all zeros 42 */ 43static 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 61errcode_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 != 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 124errout: 125 free(buf); 126 return retval; 127} 128 129/* 130 * Read in the inode table and stuff it into place 131 */ 132errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags) 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 = malloc(fs->blocksize * BUF_BLOCKS); 141 if (!buf) 142 return ENOMEM; 143 144 for (group = 0; group < fs->group_desc_count; group++) { 145 blk = fs->group_desc[(unsigned)group].bg_inode_table; 146 if (!blk) { 147 retval = EXT2_ET_MISSING_INODE_TABLE; 148 goto errout; 149 } 150 left = fs->inode_blocks_per_group; 151 while (left) { 152 c = BUF_BLOCKS; 153 if (c > left) 154 c = left; 155 actual = read(fd, buf, fs->blocksize * c); 156 if (actual == -1) { 157 retval = errno; 158 goto errout; 159 } 160 if (actual != fs->blocksize * c) { 161 retval = EXT2_ET_SHORT_READ; 162 goto errout; 163 } 164 retval = io_channel_write_blk(fs->io, blk, c, buf); 165 if (retval) 166 goto errout; 167 168 blk += c; 169 left -= c; 170 } 171 } 172 retval = ext2fs_flush_icache(fs); 173 174errout: 175 free(buf); 176 return retval; 177} 178 179/* 180 * Write out superblock and group descriptors 181 */ 182errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags) 183{ 184 char *buf, *cp; 185 ssize_t actual; 186 errcode_t retval; 187 188 buf = malloc(fs->blocksize); 189 if (!buf) 190 return ENOMEM; 191 192 /* 193 * Write out the superblock 194 */ 195 memset(buf, 0, fs->blocksize); 196 memcpy(buf, fs->super, SUPERBLOCK_SIZE); 197 actual = write(fd, buf, fs->blocksize); 198 if (actual == -1) { 199 retval = errno; 200 goto errout; 201 } 202 if (actual != fs->blocksize) { 203 retval = EXT2_ET_SHORT_WRITE; 204 goto errout; 205 } 206 207 /* 208 * Now write out the block group descriptors 209 */ 210 cp = (char *) fs->group_desc; 211 actual = write(fd, cp, fs->blocksize * fs->desc_blocks); 212 if (actual == -1) { 213 retval = errno; 214 goto errout; 215 } 216 if (actual != fs->blocksize * fs->desc_blocks) { 217 retval = EXT2_ET_SHORT_WRITE; 218 goto errout; 219 } 220 221 retval = 0; 222 223errout: 224 free(buf); 225 return retval; 226} 227 228/* 229 * Read the superblock and group descriptors and overwrite them. 230 */ 231errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags) 232{ 233 char *buf; 234 ssize_t actual, size; 235 errcode_t retval; 236 237 size = fs->blocksize * (fs->group_desc_count + 1); 238 buf = malloc(size); 239 if (!buf) 240 return ENOMEM; 241 242 /* 243 * Read it all in. 244 */ 245 actual = read(fd, buf, size); 246 if (actual == -1) { 247 retval = errno; 248 goto errout; 249 } 250 if (actual != size) { 251 retval = EXT2_ET_SHORT_READ; 252 goto errout; 253 } 254 255 /* 256 * Now copy in the superblock and group descriptors 257 */ 258 memcpy(fs->super, buf, SUPERBLOCK_SIZE); 259 260 memcpy(fs->group_desc, buf + fs->blocksize, 261 fs->blocksize * fs->group_desc_count); 262 263 retval = 0; 264 265errout: 266 free(buf); 267 return retval; 268} 269 270/* 271 * Write the block/inode bitmaps. 272 */ 273errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags) 274{ 275 char *ptr; 276 int c, size; 277 char zero_buf[1024]; 278 ssize_t actual; 279 errcode_t retval; 280 281 if (flags & IMAGER_FLAG_INODEMAP) { 282 if (!fs->inode_map) { 283 retval = ext2fs_read_inode_bitmap(fs); 284 if (retval) 285 return retval; 286 } 287 ptr = fs->inode_map->bitmap; 288 size = (EXT2_INODES_PER_GROUP(fs->super) / 8); 289 } else { 290 if (!fs->block_map) { 291 retval = ext2fs_read_block_bitmap(fs); 292 if (retval) 293 return retval; 294 } 295 ptr = fs->block_map->bitmap; 296 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; 297 } 298 size = size * fs->group_desc_count; 299 300 actual = write(fd, ptr, size); 301 if (actual == -1) { 302 retval = errno; 303 goto errout; 304 } 305 if (actual != size) { 306 retval = EXT2_ET_SHORT_WRITE; 307 goto errout; 308 } 309 size = size % fs->blocksize; 310 memset(zero_buf, 0, sizeof(zero_buf)); 311 if (size) { 312 size = fs->blocksize - size; 313 while (size) { 314 c = size; 315 if (c > sizeof(zero_buf)) 316 c = sizeof(zero_buf); 317 actual = write(fd, zero_buf, c); 318 if (actual == -1) { 319 retval = errno; 320 goto errout; 321 } 322 if (actual != c) { 323 retval = EXT2_ET_SHORT_WRITE; 324 goto errout; 325 } 326 size -= c; 327 } 328 } 329 retval = 0; 330errout: 331 return (retval); 332} 333 334 335/* 336 * Read the block/inode bitmaps. 337 */ 338errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags) 339{ 340 char *ptr, *buf = 0; 341 int size; 342 ssize_t actual; 343 errcode_t retval; 344 345 if (flags & IMAGER_FLAG_INODEMAP) { 346 if (!fs->inode_map) { 347 retval = ext2fs_read_inode_bitmap(fs); 348 if (retval) 349 return retval; 350 } 351 ptr = fs->inode_map->bitmap; 352 size = (EXT2_INODES_PER_GROUP(fs->super) / 8); 353 } else { 354 if (!fs->block_map) { 355 retval = ext2fs_read_block_bitmap(fs); 356 if (retval) 357 return retval; 358 } 359 ptr = fs->block_map->bitmap; 360 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; 361 } 362 size = size * fs->group_desc_count; 363 364 buf = malloc(size); 365 if (!buf) 366 return ENOMEM; 367 368 actual = read(fd, buf, size); 369 if (actual == -1) { 370 retval = errno; 371 goto errout; 372 } 373 if (actual != size) { 374 retval = EXT2_ET_SHORT_WRITE; 375 goto errout; 376 } 377 memcpy(ptr, buf, size); 378 379 retval = 0; 380errout: 381 if (buf) 382 free(buf); 383 return (retval); 384} 385