| Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 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 | |
| Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 17 | #include <linux/ext2_fs.h> |
| 18 | |
| 19 | #include "ext2fs.h" |
| 20 | |
| 21 | /* |
| 22 | * Note: if superblock is non-zero, block-size must also be non-zero. |
| 23 | * Superblock and block_size can be zero to use the default size. |
| 24 | */ |
| 25 | errcode_t ext2fs_open(const char *name, int flags, int superblock, |
| 26 | int block_size, io_manager manager, ext2_filsys *ret_fs) |
| 27 | { |
| 28 | ext2_filsys fs; |
| 29 | errcode_t retval; |
| 30 | int i, group_block; |
| 31 | char *dest; |
| 32 | |
| Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame^] | 33 | EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER); |
| 34 | |
| Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 35 | fs = (ext2_filsys) malloc(sizeof(struct struct_ext2_filsys)); |
| 36 | if (!fs) |
| 37 | return ENOMEM; |
| 38 | |
| 39 | memset(fs, 0, sizeof(struct struct_ext2_filsys)); |
| Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame^] | 40 | fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS; |
| Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 41 | fs->flags = flags; |
| 42 | retval = manager->open(name, (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0, |
| 43 | &fs->io); |
| 44 | if (retval) |
| 45 | goto cleanup; |
| 46 | fs->device_name = malloc(strlen(name)+1); |
| 47 | if (!fs->device_name) { |
| 48 | retval = ENOMEM; |
| 49 | goto cleanup; |
| 50 | } |
| 51 | strcpy(fs->device_name, name); |
| 52 | fs->super = malloc(SUPERBLOCK_SIZE); |
| 53 | if (!fs->super) { |
| 54 | retval = ENOMEM; |
| 55 | goto cleanup; |
| 56 | } |
| 57 | |
| 58 | /* |
| 59 | * If the user specifies a specific block # for the |
| 60 | * superblock, then he/she must also specify the block size! |
| 61 | * Otherwise, read the master superblock located at offset |
| 62 | * SUPERBLOCK_OFFSET from the start of the partition. |
| 63 | */ |
| 64 | if (superblock) { |
| 65 | if (!block_size) { |
| 66 | retval = EINVAL; |
| 67 | goto cleanup; |
| 68 | } |
| 69 | io_channel_set_blksize(fs->io, block_size); |
| Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame^] | 70 | group_block = superblock + 1; |
| Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 71 | } else { |
| 72 | io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); |
| 73 | superblock = 1; |
| Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame^] | 74 | group_block = 0; |
| Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 75 | } |
| 76 | retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE, |
| 77 | fs->super); |
| 78 | if (retval) |
| 79 | goto cleanup; |
| 80 | |
| 81 | if (fs->super->s_magic != EXT2_SUPER_MAGIC) { |
| 82 | retval = EXT2_ET_BAD_MAGIC; |
| 83 | goto cleanup; |
| 84 | } |
| Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame^] | 85 | #ifdef EXT2_CURRENT_REV |
| 86 | if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) { |
| 87 | retval = EXT2_ET_REV_TOO_HIGH; |
| 88 | goto cleanup; |
| 89 | } |
| 90 | #endif |
| Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 91 | fs->blocksize = EXT2_BLOCK_SIZE(fs->super); |
| 92 | fs->fragsize = EXT2_FRAG_SIZE(fs->super); |
| 93 | fs->inode_blocks_per_group = (fs->super->s_inodes_per_group / |
| 94 | EXT2_INODES_PER_BLOCK(fs->super)); |
| 95 | if (block_size) { |
| 96 | if (block_size != fs->blocksize) { |
| 97 | retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE; |
| 98 | goto cleanup; |
| 99 | } |
| 100 | } |
| 101 | /* |
| 102 | * Set the blocksize to the filesystem's blocksize. |
| 103 | */ |
| 104 | io_channel_set_blksize(fs->io, fs->blocksize); |
| 105 | |
| 106 | /* |
| 107 | * Read group descriptors |
| 108 | */ |
| 109 | fs->group_desc_count = (fs->super->s_blocks_count - |
| 110 | fs->super->s_first_data_block + |
| 111 | EXT2_BLOCKS_PER_GROUP(fs->super) - 1) |
| 112 | / EXT2_BLOCKS_PER_GROUP(fs->super); |
| 113 | fs->desc_blocks = (fs->group_desc_count + |
| 114 | EXT2_DESC_PER_BLOCK(fs->super) - 1) |
| 115 | / EXT2_DESC_PER_BLOCK(fs->super); |
| 116 | fs->group_desc = malloc(fs->desc_blocks * fs->blocksize); |
| 117 | if (!fs->group_desc) { |
| 118 | retval = ENOMEM; |
| 119 | goto cleanup; |
| 120 | } |
| Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame^] | 121 | if (!group_block) |
| 122 | group_block = fs->super->s_first_data_block + 1; |
| Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 123 | dest = (char *) fs->group_desc; |
| 124 | for (i=0 ; i < fs->desc_blocks; i++) { |
| 125 | retval = io_channel_read_blk(fs->io, group_block, 1, dest); |
| 126 | if (retval) |
| 127 | goto cleanup; |
| 128 | group_block++; |
| 129 | dest += fs->blocksize; |
| 130 | } |
| 131 | |
| 132 | *ret_fs = fs; |
| 133 | return 0; |
| 134 | cleanup: |
| 135 | ext2fs_free(fs); |
| 136 | return retval; |
| 137 | } |
| 138 | |