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 38typedef int ssize_t; 39#endif 40 41/* 42 * This function returns 1 if the specified block is all zeros 43 */ 44static 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 62errcode_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 123errout: 124 free(buf); 125 return retval; 126} 127 128/* 129 * Read in the inode table and stuff it into place 130 */ 131errcode_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 172errout: 173 free(buf); 174 return retval; 175} 176 177/* 178 * Write out superblock and group descriptors 179 */ 180errcode_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 220errout: 221 free(buf); 222 return retval; 223} 224 225/* 226 * Read the superblock and group descriptors and overwrite them. 227 */ 228errcode_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 261errout: 262 free(buf); 263 return retval; 264} 265 266/* 267 * Write the block/inode bitmaps. 268 */ 269errcode_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; 326errout: 327 return retval; 328} 329 330 331/* 332 * Read the block/inode bitmaps. 333 */ 334errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags) 335{ 336 char *ptr, *buf = NULL; 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; 374errout: 375 free(buf); 376 return retval; 377} 378