openfs.c revision 3839e65723771b85975f4263102dd3ceec4523c0
1/* 2 * openfs.c --- open an ext2 filesystem 3 * 4 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be redistributed 5 * under the terms of the GNU Public License. 6 */ 7 8#include <stdio.h> 9#include <string.h> 10#include <unistd.h> 11#include <stdlib.h> 12#include <fcntl.h> 13#include <time.h> 14#include <sys/stat.h> 15#include <sys/types.h> 16 17#include <linux/fs.h> 18#include <linux/ext2_fs.h> 19 20#include "ext2fs.h" 21 22/* 23 * Note: if superblock is non-zero, block-size must also be non-zero. 24 * Superblock and block_size can be zero to use the default size. 25 */ 26errcode_t ext2fs_open(const char *name, int flags, int superblock, 27 int block_size, io_manager manager, ext2_filsys *ret_fs) 28{ 29 ext2_filsys fs; 30 errcode_t retval; 31 int i, group_block; 32 char *dest; 33 34 fs = (ext2_filsys) malloc(sizeof(struct struct_ext2_filsys)); 35 if (!fs) 36 return ENOMEM; 37 38 memset(fs, 0, sizeof(struct struct_ext2_filsys)); 39 fs->flags = flags; 40 retval = manager->open(name, (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0, 41 &fs->io); 42 if (retval) 43 goto cleanup; 44 fs->device_name = malloc(strlen(name)+1); 45 if (!fs->device_name) { 46 retval = ENOMEM; 47 goto cleanup; 48 } 49 strcpy(fs->device_name, name); 50 fs->super = malloc(SUPERBLOCK_SIZE); 51 if (!fs->super) { 52 retval = ENOMEM; 53 goto cleanup; 54 } 55 56 /* 57 * If the user specifies a specific block # for the 58 * superblock, then he/she must also specify the block size! 59 * Otherwise, read the master superblock located at offset 60 * SUPERBLOCK_OFFSET from the start of the partition. 61 */ 62 if (superblock) { 63 if (!block_size) { 64 retval = EINVAL; 65 goto cleanup; 66 } 67 io_channel_set_blksize(fs->io, block_size); 68 } else { 69 io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); 70 superblock = 1; 71 } 72 retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE, 73 fs->super); 74 if (retval) 75 goto cleanup; 76 77 if (fs->super->s_magic != EXT2_SUPER_MAGIC) { 78 retval = EXT2_ET_BAD_MAGIC; 79 goto cleanup; 80 } 81 fs->blocksize = EXT2_BLOCK_SIZE(fs->super); 82 fs->fragsize = EXT2_FRAG_SIZE(fs->super); 83 fs->inode_blocks_per_group = (fs->super->s_inodes_per_group / 84 EXT2_INODES_PER_BLOCK(fs->super)); 85 if (block_size) { 86 if (block_size != fs->blocksize) { 87 retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE; 88 goto cleanup; 89 } 90 } 91 /* 92 * Set the blocksize to the filesystem's blocksize. 93 */ 94 io_channel_set_blksize(fs->io, fs->blocksize); 95 96 /* 97 * Read group descriptors 98 */ 99 fs->group_desc_count = (fs->super->s_blocks_count - 100 fs->super->s_first_data_block + 101 EXT2_BLOCKS_PER_GROUP(fs->super) - 1) 102 / EXT2_BLOCKS_PER_GROUP(fs->super); 103 fs->desc_blocks = (fs->group_desc_count + 104 EXT2_DESC_PER_BLOCK(fs->super) - 1) 105 / EXT2_DESC_PER_BLOCK(fs->super); 106 fs->group_desc = malloc(fs->desc_blocks * fs->blocksize); 107 if (!fs->group_desc) { 108 retval = ENOMEM; 109 goto cleanup; 110 } 111 group_block = fs->super->s_first_data_block + 1; 112 dest = (char *) fs->group_desc; 113 for (i=0 ; i < fs->desc_blocks; i++) { 114 retval = io_channel_read_blk(fs->io, group_block, 1, dest); 115 if (retval) 116 goto cleanup; 117 group_block++; 118 dest += fs->blocksize; 119 } 120 121 *ret_fs = fs; 122 return 0; 123cleanup: 124 ext2fs_free(fs); 125 return retval; 126} 127 128/* 129 * This routine sanity checks the group descriptors 130 */ 131errcode_t ext2fs_check_desc(ext2_filsys fs) 132{ 133 int i; 134 int block = fs->super->s_first_data_block; 135 int next, inode_blocks_per_group; 136 137 inode_blocks_per_group = fs->super->s_inodes_per_group / 138 EXT2_INODES_PER_BLOCK (fs->super); 139 140 for (i = 0; i < fs->group_desc_count; i++) { 141 next = block + fs->super->s_blocks_per_group; 142 /* 143 * Check to make sure block bitmap for group is 144 * located within the group. 145 */ 146 if (fs->group_desc[i].bg_block_bitmap < block || 147 fs->group_desc[i].bg_block_bitmap >= next) 148 return EXT2_ET_GDESC_BAD_BLOCK_MAP; 149 /* 150 * Check to make sure inode bitmap for group is 151 * located within the group 152 */ 153 if (fs->group_desc[i].bg_inode_bitmap < block || 154 fs->group_desc[i].bg_inode_bitmap >= next) 155 return EXT2_ET_GDESC_BAD_INODE_MAP; 156 /* 157 * Check to make sure inode table for group is located 158 * within the group 159 */ 160 if (fs->group_desc[i].bg_inode_table < block || 161 fs->group_desc[i].bg_inode_table+inode_blocks_per_group >= 162 next) 163 return EXT2_ET_GDESC_BAD_INODE_TABLE; 164 165 block = next; 166 } 167 return 0; 168} 169 170