Logo Search packages:      
Sourcecode: yaboot version File versions  Download package

imager.c

/*
 * image.c --- writes out the critical parts of the filesystem as a
 *    flat file.
 *
 * Copyright (C) 2000 Theodore Ts'o.
 *
 * Note: this uses the POSIX IO interfaces, unlike most of the other
 * functions in this library.  So sue me.  
 *
 * %Begin-Header%
 * This file may be redistributed under the terms of the GNU Public
 * License.
 * %End-Header%
 */

#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#include "ext2_fs.h"
#include "ext2fs.h"

/*
 * This function returns 1 if the specified block is all zeros
 */
static int check_zero_block(char *buf, int blocksize)
{
      char  *cp = buf;
      int   left = blocksize;

      while (left > 0) {
            if (*cp++)
                  return 0;
            left--;
      }
      return 1;
}

/*
 * Write the inode table out as a single block.
 */
#define BUF_BLOCKS      32

errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
{
      unsigned int      group, left, c, d;
      char        *buf, *cp;
      blk_t       blk;
      ssize_t           actual;
      errcode_t   retval;

      buf = malloc(fs->blocksize * BUF_BLOCKS);
      if (!buf)
            return ENOMEM;
      
      for (group = 0; group < fs->group_desc_count; group++) {
            blk = fs->group_desc[(unsigned)group].bg_inode_table;
            if (!blk)
                  return EXT2_ET_MISSING_INODE_TABLE;
            left = fs->inode_blocks_per_group;
            while (left) {
                  c = BUF_BLOCKS;
                  if (c > left)
                        c = left;
                  retval = io_channel_read_blk(fs->io, blk, c, buf);
                  if (retval)
                        goto errout;
                  cp = buf;
                  while (c) {
                        if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
                              d = c;
                              goto skip_sparse;
                        }
                        /* Skip zero blocks */
                        if (check_zero_block(cp, fs->blocksize)) {
                              c--;
                              blk++;
                              left--;
                              cp += fs->blocksize;
                              lseek(fd, fs->blocksize, SEEK_CUR);
                              continue;
                        }
                        /* Find non-zero blocks */
                        for (d=1; d < c; d++) {
                              if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
                                    break;
                        }
                  skip_sparse:
                        actual = write(fd, cp, fs->blocksize * d);
                        if (actual == -1) {
                              retval = errno;
                              goto errout;
                        }
                        if (actual != fs->blocksize * d) {
                              retval = EXT2_ET_SHORT_WRITE;
                              goto errout;
                        }
                        blk += d;
                        left -= d;
                        cp += fs->blocksize * d;
                        c -= d;
                  }
            }
      }
      retval = 0;

errout:
      free(buf);
      return retval;
}

/*
 * Read in the inode table and stuff it into place
 */
errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags)
{
      unsigned int      group, c, left;
      char        *buf;
      blk_t       blk;
      ssize_t           actual;
      errcode_t   retval;

      buf = malloc(fs->blocksize * BUF_BLOCKS);
      if (!buf)
            return ENOMEM;
      
      for (group = 0; group < fs->group_desc_count; group++) {
            blk = fs->group_desc[(unsigned)group].bg_inode_table;
            if (!blk) {
                  retval = EXT2_ET_MISSING_INODE_TABLE;
                  goto errout;
            }
            left = fs->inode_blocks_per_group;
            while (left) {
                  c = BUF_BLOCKS;
                  if (c > left)
                        c = left;
                  actual = read(fd, buf, fs->blocksize * c);
                  if (actual == -1) {
                        retval = errno;
                        goto errout;
                  }
                  if (actual != fs->blocksize * c) {
                        retval = EXT2_ET_SHORT_READ;
                        goto errout;
                  }
                  retval = io_channel_write_blk(fs->io, blk, c, buf);
                  if (retval)
                        goto errout;
                  
                  blk += c;
                  left -= c;
            }
      }
      retval = ext2fs_flush_icache(fs);

errout:
      free(buf);
      return retval;
}

/*
 * Write out superblock and group descriptors
 */
errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags)
{
      char        *buf, *cp;
      ssize_t           actual;
      errcode_t   retval;

      buf = malloc(fs->blocksize);
      if (!buf)
            return ENOMEM;

      /*
       * Write out the superblock
       */
      memset(buf, 0, fs->blocksize);
      memcpy(buf, fs->super, SUPERBLOCK_SIZE);
      actual = write(fd, buf, fs->blocksize);
      if (actual == -1) {
            retval = errno;
            goto errout;
      }
      if (actual != fs->blocksize) {
            retval = EXT2_ET_SHORT_WRITE;
            goto errout;
      }

      /*
       * Now write out the block group descriptors
       */
      cp = (char *) fs->group_desc;
      actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
      if (actual == -1) {
            retval = errno;
            goto errout;
      }
      if (actual != fs->blocksize * fs->desc_blocks) {
            retval = EXT2_ET_SHORT_WRITE;
            goto errout;
      }
      
      retval = 0;

errout:
      free(buf);
      return retval;
}

/*
 * Read the superblock and group descriptors and overwrite them.
 */
errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags)
{
      char        *buf;
      ssize_t           actual, size;
      errcode_t   retval;

      size = fs->blocksize * (fs->group_desc_count + 1);
      buf = malloc(size);
      if (!buf)
            return ENOMEM;

      /*
       * Read it all in.
       */
      actual = read(fd, buf, size);
      if (actual == -1) {
            retval = errno;
            goto errout;
      }
      if (actual != size) {
            retval = EXT2_ET_SHORT_READ;
            goto errout;
      }

      /*
       * Now copy in the superblock and group descriptors
       */
      memcpy(fs->super, buf, SUPERBLOCK_SIZE);

      memcpy(fs->group_desc, buf + fs->blocksize,
             fs->blocksize * fs->group_desc_count);

      retval = 0;

errout:
      free(buf);
      return retval;
}

/*
 * Write the block/inode bitmaps.
 */
errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
{
      char        *ptr;
      int         c, size;
      char        zero_buf[1024];
      ssize_t           actual;
      errcode_t   retval;

      if (flags & IMAGER_FLAG_INODEMAP) {
            if (!fs->inode_map) {
                  retval = ext2fs_read_inode_bitmap(fs);
                  if (retval)
                        return retval;
            }
            ptr = fs->inode_map->bitmap;
            size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
      } else {
            if (!fs->block_map) {
                  retval = ext2fs_read_block_bitmap(fs);
                  if (retval)
                        return retval;
            }
            ptr = fs->block_map->bitmap;
            size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
      }
      size = size * fs->group_desc_count;

      actual = write(fd, ptr, size);
      if (actual == -1) {
            retval = errno;
            goto errout;
      }
      if (actual != size) {
            retval = EXT2_ET_SHORT_WRITE;
            goto errout;
      }
      size = size % fs->blocksize;
      memset(zero_buf, 0, sizeof(zero_buf));
      if (size) {
            size = fs->blocksize - size;
            while (size) {
                  c = size;
                  if (c > sizeof(zero_buf))
                        c = sizeof(zero_buf);
                  actual = write(fd, zero_buf, c);
                  if (actual == -1) {
                        retval = errno;
                        goto errout;
                  }
                  if (actual != c) {
                        retval = EXT2_ET_SHORT_WRITE;
                        goto errout;
                  }
                  size -= c;
            }
      }
      retval = 0;
errout:
      return (retval);
}


/*
 * Read the block/inode bitmaps.
 */
errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
{
      char        *ptr, *buf = 0;
      int         size;
      ssize_t           actual;
      errcode_t   retval;

      if (flags & IMAGER_FLAG_INODEMAP) {
            if (!fs->inode_map) {
                  retval = ext2fs_read_inode_bitmap(fs);
                  if (retval)
                        return retval;
            }
            ptr = fs->inode_map->bitmap;
            size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
      } else {
            if (!fs->block_map) {
                  retval = ext2fs_read_block_bitmap(fs);
                  if (retval)
                        return retval;
            }
            ptr = fs->block_map->bitmap;
            size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
      }
      size = size * fs->group_desc_count;

      buf = malloc(size);
      if (!buf)
            return ENOMEM;

      actual = read(fd, buf, size);
      if (actual == -1) {
            retval = errno;
            goto errout;
      }
      if (actual != size) {
            retval = EXT2_ET_SHORT_WRITE;
            goto errout;
      }
      memcpy(ptr, buf, size);
      
      retval = 0;
errout:
      if (buf)
            free(buf);
      return (retval);
}

Generated by  Doxygen 1.6.0   Back to index