busybox/e2fsprogs/old_e2fsprogs/ext2fs/imager.c
<<
>>
Prefs
   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