|
|
1.1 ! root 1: /* ! 2: * ! 3: * (c) 2008-2009 Laurent Vivier <[email protected]> ! 4: * ! 5: * This file has been copied from EMILE, http://emile.sf.net ! 6: * ! 7: */ ! 8: ! 9: #include "libext2.h" ! 10: #include "ext2_utils.h" ! 11: #include "libopenbios/bindings.h" ! 12: #include "libc/diskio.h" ! 13: #include "libc/byteorder.h" ! 14: ! 15: int ext2_probe(int fd, long long offset) ! 16: { ! 17: struct ext2_super_block *super; ! 18: ! 19: super = (struct ext2_super_block*)malloc(sizeof(struct ext2_super_block)); ! 20: seek_io(fd, 2 * 512 + offset); ! 21: read_io(fd, super, sizeof (*super)); ! 22: ! 23: if (__le16_to_cpu(super->s_magic) != EXT2_SUPER_MAGIC) { ! 24: free(super); ! 25: return 0; ! 26: } ! 27: ! 28: free(super); ! 29: return -1; ! 30: } ! 31: ! 32: void ext2_get_super(int fd, struct ext2_super_block *super) ! 33: { ! 34: seek_io(fd, 2 * 512); ! 35: read_io(fd, super, sizeof (*super)); ! 36: ! 37: super->s_inodes_count = __le32_to_cpu(super->s_inodes_count); ! 38: super->s_blocks_count = __le32_to_cpu(super->s_blocks_count); ! 39: super->s_r_blocks_count = __le32_to_cpu(super->s_r_blocks_count); ! 40: super->s_free_blocks_count = __le32_to_cpu(super->s_free_blocks_count); ! 41: super->s_free_inodes_count = __le32_to_cpu(super->s_free_inodes_count); ! 42: super->s_first_data_block = __le32_to_cpu(super->s_first_data_block); ! 43: super->s_log_block_size = __le32_to_cpu(super->s_log_block_size); ! 44: super->s_log_frag_size = __le32_to_cpu(super->s_log_frag_size); ! 45: super->s_blocks_per_group = __le32_to_cpu(super->s_blocks_per_group); ! 46: super->s_frags_per_group = __le32_to_cpu(super->s_frags_per_group); ! 47: super->s_inodes_per_group = __le32_to_cpu(super->s_inodes_per_group); ! 48: super->s_mtime = __le32_to_cpu(super->s_mtime); ! 49: super->s_wtime = __le32_to_cpu(super->s_wtime); ! 50: super->s_mnt_count = __le16_to_cpu(super->s_mnt_count); ! 51: super->s_max_mnt_count = __le16_to_cpu(super->s_max_mnt_count); ! 52: super->s_magic = __le16_to_cpu(super->s_magic); ! 53: super->s_state = __le16_to_cpu(super->s_state); ! 54: super->s_errors = __le16_to_cpu(super->s_errors); ! 55: super->s_minor_rev_level = __le16_to_cpu(super->s_minor_rev_level); ! 56: super->s_lastcheck = __le32_to_cpu(super->s_lastcheck); ! 57: super->s_checkinterval = __le32_to_cpu(super->s_checkinterval); ! 58: super->s_creator_os = __le32_to_cpu(super->s_creator_os); ! 59: super->s_rev_level = __le32_to_cpu(super->s_rev_level); ! 60: super->s_def_resuid = __le16_to_cpu(super->s_def_resuid); ! 61: super->s_def_resgid = __le16_to_cpu(super->s_def_resgid); ! 62: super->s_first_ino = __le32_to_cpu(super->s_first_ino); ! 63: super->s_inode_size = __le16_to_cpu(super->s_inode_size); ! 64: super->s_block_group_nr = __le16_to_cpu(super->s_block_group_nr); ! 65: super->s_feature_compat = __le32_to_cpu(super->s_feature_compat); ! 66: super->s_feature_incompat = __le32_to_cpu(super->s_feature_incompat); ! 67: super->s_feature_ro_compat = __le32_to_cpu(super->s_feature_ro_compat); ! 68: super->s_algorithm_usage_bitmap = ! 69: __le32_to_cpu(super->s_algorithm_usage_bitmap); ! 70: super->s_journal_inum = __le32_to_cpu(super->s_journal_inum); ! 71: super->s_journal_dev = __le32_to_cpu(super->s_journal_dev); ! 72: super->s_last_orphan = __le32_to_cpu(super->s_last_orphan); ! 73: super->s_hash_seed[0] = __le32_to_cpu(super->s_hash_seed[0]); ! 74: super->s_hash_seed[1] = __le32_to_cpu(super->s_hash_seed[1]); ! 75: super->s_hash_seed[2] = __le32_to_cpu(super->s_hash_seed[2]); ! 76: super->s_hash_seed[3] = __le32_to_cpu(super->s_hash_seed[3]); ! 77: super->s_default_mount_opts = ! 78: __le32_to_cpu(super->s_default_mount_opts); ! 79: super->s_first_meta_bg = __le32_to_cpu(super->s_first_meta_bg); ! 80: } ! 81: ! 82: void ext2_read_block(ext2_VOLUME* volume, unsigned int fsblock) ! 83: { ! 84: long long offset; ! 85: ! 86: if (fsblock == volume->current) ! 87: return; ! 88: ! 89: volume->current = fsblock; ! 90: offset = fsblock * EXT2_BLOCK_SIZE(volume->super); ! 91: ! 92: seek_io(volume->fd, offset); ! 93: read_io(volume->fd, volume->buffer, EXT2_BLOCK_SIZE(volume->super)); ! 94: } ! 95: ! 96: void ext2_get_group_desc(ext2_VOLUME* volume, ! 97: int group_id, struct ext2_group_desc *gdp) ! 98: { ! 99: unsigned int block, offset; ! 100: struct ext2_group_desc *le_gdp; ! 101: ! 102: block = 1 + volume->super->s_first_data_block; ! 103: block += group_id / EXT2_DESC_PER_BLOCK(volume->super); ! 104: ext2_read_block(volume, block); ! 105: ! 106: offset = group_id % EXT2_DESC_PER_BLOCK(volume->super); ! 107: offset *= sizeof(*gdp); ! 108: ! 109: le_gdp = (struct ext2_group_desc *)(volume->buffer + offset); ! 110: ! 111: gdp->bg_block_bitmap = __le32_to_cpu(le_gdp->bg_block_bitmap); ! 112: gdp->bg_inode_bitmap = __le32_to_cpu(le_gdp->bg_inode_bitmap); ! 113: gdp->bg_inode_table = __le32_to_cpu(le_gdp->bg_inode_table); ! 114: gdp->bg_free_blocks_count = __le16_to_cpu(le_gdp->bg_free_blocks_count); ! 115: gdp->bg_free_inodes_count = __le16_to_cpu(le_gdp->bg_free_inodes_count); ! 116: gdp->bg_used_dirs_count = __le16_to_cpu(le_gdp->bg_used_dirs_count); ! 117: } ! 118: ! 119: int ext2_get_inode(ext2_VOLUME* volume, ! 120: unsigned int ino, struct ext2_inode *inode) ! 121: { ! 122: struct ext2_group_desc desc; ! 123: unsigned int block; ! 124: unsigned int group_id; ! 125: unsigned int offset; ! 126: struct ext2_inode *le_inode; ! 127: int i; ! 128: ! 129: ino--; ! 130: ! 131: group_id = ino / EXT2_INODES_PER_GROUP(volume->super); ! 132: ext2_get_group_desc(volume, group_id, &desc); ! 133: ! 134: ino %= EXT2_INODES_PER_GROUP(volume->super); ! 135: ! 136: block = desc.bg_inode_table; ! 137: block += ino / (EXT2_BLOCK_SIZE(volume->super) / ! 138: EXT2_INODE_SIZE(volume->super)); ! 139: ext2_read_block(volume, block); ! 140: ! 141: offset = ino % (EXT2_BLOCK_SIZE(volume->super) / ! 142: EXT2_INODE_SIZE(volume->super)); ! 143: offset *= EXT2_INODE_SIZE(volume->super); ! 144: ! 145: le_inode = (struct ext2_inode *)(volume->buffer + offset); ! 146: ! 147: inode->i_mode = __le16_to_cpu(le_inode->i_mode); ! 148: inode->i_uid = __le16_to_cpu(le_inode->i_uid); ! 149: inode->i_size = __le32_to_cpu(le_inode->i_size); ! 150: inode->i_atime = __le32_to_cpu(le_inode->i_atime); ! 151: inode->i_ctime = __le32_to_cpu(le_inode->i_ctime); ! 152: inode->i_mtime = __le32_to_cpu(le_inode->i_mtime); ! 153: inode->i_dtime = __le32_to_cpu(le_inode->i_dtime); ! 154: inode->i_gid = __le16_to_cpu(le_inode->i_gid); ! 155: inode->i_links_count = __le16_to_cpu(le_inode->i_links_count); ! 156: inode->i_blocks = __le32_to_cpu(le_inode->i_blocks); ! 157: inode->i_flags = __le32_to_cpu(le_inode->i_flags); ! 158: if (S_ISLNK(inode->i_mode)) { ! 159: memcpy(inode->i_block, le_inode->i_block, EXT2_N_BLOCKS * 4); ! 160: } else { ! 161: for (i = 0; i < EXT2_N_BLOCKS; i++) ! 162: inode->i_block[i] = __le32_to_cpu(le_inode->i_block[i]); ! 163: } ! 164: inode->i_generation = __le32_to_cpu(le_inode->i_generation); ! 165: inode->i_file_acl = __le32_to_cpu(le_inode->i_file_acl); ! 166: inode->i_dir_acl = __le32_to_cpu(le_inode->i_dir_acl); ! 167: inode->i_faddr = __le32_to_cpu(le_inode->i_faddr); ! 168: inode->osd2.linux2.l_i_frag = le_inode->osd2.linux2.l_i_frag; ! 169: inode->osd2.linux2.l_i_fsize = le_inode->osd2.linux2.l_i_fsize; ! 170: inode->osd2.linux2.l_i_uid_high = ! 171: __le16_to_cpu(le_inode->osd2.linux2.l_i_uid_high); ! 172: inode->osd2.linux2.l_i_gid_high = ! 173: __le16_to_cpu(le_inode->osd2.linux2.l_i_gid_high); ! 174: return 0; ! 175: } ! 176: ! 177: unsigned int ext2_get_block_addr(ext2_VOLUME* volume, struct ext2_inode *inode, ! 178: unsigned int logical) ! 179: { ! 180: unsigned int physical; ! 181: unsigned int addr_per_block; ! 182: ! 183: /* direct */ ! 184: ! 185: if (logical < EXT2_NDIR_BLOCKS) { ! 186: physical = inode->i_block[logical]; ! 187: return physical; ! 188: } ! 189: ! 190: /* indirect */ ! 191: ! 192: logical -= EXT2_NDIR_BLOCKS; ! 193: ! 194: addr_per_block = EXT2_ADDR_PER_BLOCK (volume->super); ! 195: if (logical < addr_per_block) { ! 196: ext2_read_block(volume, inode->i_block[EXT2_IND_BLOCK]); ! 197: physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical]); ! 198: return physical; ! 199: } ! 200: ! 201: /* double indirect */ ! 202: ! 203: logical -= addr_per_block; ! 204: ! 205: if (logical < addr_per_block * addr_per_block) { ! 206: ext2_read_block(volume, inode->i_block[EXT2_DIND_BLOCK]); ! 207: physical = __le32_to_cpu(((unsigned int *)volume->buffer) ! 208: [logical / addr_per_block]); ! 209: ext2_read_block(volume, physical); ! 210: physical = __le32_to_cpu(((unsigned int *)volume->buffer) ! 211: [logical % addr_per_block]); ! 212: return physical; ! 213: } ! 214: ! 215: /* triple indirect */ ! 216: ! 217: logical -= addr_per_block * addr_per_block; ! 218: ext2_read_block(volume, inode->i_block[EXT2_DIND_BLOCK]); ! 219: physical = __le32_to_cpu(((unsigned int *)volume->buffer) ! 220: [logical / (addr_per_block * addr_per_block)]); ! 221: ext2_read_block(volume, physical); ! 222: logical = logical % (addr_per_block * addr_per_block); ! 223: physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical / addr_per_block]); ! 224: ext2_read_block(volume, physical); ! 225: physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical % addr_per_block]); ! 226: return physical; ! 227: } ! 228: ! 229: int ext2_read_data(ext2_VOLUME* volume, struct ext2_inode *inode, ! 230: off_t offset, char *buffer, size_t length) ! 231: { ! 232: unsigned int logical, physical; ! 233: int blocksize = EXT2_BLOCK_SIZE(volume->super); ! 234: int shift; ! 235: size_t read; ! 236: ! 237: if (offset >= inode->i_size) ! 238: return -1; ! 239: ! 240: if (offset + length >= inode->i_size) ! 241: length = inode->i_size - offset; ! 242: ! 243: read = 0; ! 244: logical = offset / blocksize; ! 245: shift = offset % blocksize; ! 246: ! 247: if (shift) { ! 248: physical = ext2_get_block_addr(volume, inode, logical); ! 249: ext2_read_block(volume, physical); ! 250: ! 251: if (length < blocksize - shift) { ! 252: memcpy(buffer, volume->buffer + shift, length); ! 253: return length; ! 254: } ! 255: read += blocksize - shift; ! 256: memcpy(buffer, volume->buffer + shift, read); ! 257: ! 258: buffer += read; ! 259: length -= read; ! 260: logical++; ! 261: } ! 262: ! 263: while (length) { ! 264: physical = ext2_get_block_addr(volume, inode, logical); ! 265: ext2_read_block(volume, physical); ! 266: ! 267: if (length < blocksize) { ! 268: memcpy(buffer, volume->buffer, length); ! 269: read += length; ! 270: return read; ! 271: } ! 272: memcpy(buffer, volume->buffer, blocksize); ! 273: ! 274: buffer += blocksize; ! 275: length -= blocksize; ! 276: read += blocksize; ! 277: logical++; ! 278: } ! 279: ! 280: return read; ! 281: } ! 282: ! 283: off_t ext2_dir_entry(ext2_VOLUME *volume, struct ext2_inode *inode, ! 284: off_t index, struct ext2_dir_entry_2 *entry) ! 285: { ! 286: int ret; ! 287: ! 288: ret = ext2_read_data(volume, inode, index, ! 289: (char*)entry, sizeof(*entry)); ! 290: if (ret == -1) ! 291: return -1; ! 292: ! 293: entry->inode = __le32_to_cpu(entry->inode); ! 294: entry->rec_len = __le16_to_cpu(entry->rec_len); ! 295: return index + entry->rec_len; ! 296: } ! 297: ! 298: unsigned int ext2_seek_name(ext2_VOLUME *volume, const char *name) ! 299: { ! 300: struct ext2_inode inode; ! 301: int ret; ! 302: unsigned int ino; ! 303: off_t index; ! 304: struct ext2_dir_entry_2 entry; ! 305: ! 306: ino = EXT2_ROOT_INO; ! 307: while(1) { ! 308: while (*name == '\\') ! 309: name++; ! 310: if (!*name) ! 311: break; ! 312: ret = ext2_get_inode(volume, ino, &inode); ! 313: if (ret == -1) ! 314: return 0; ! 315: index = 0; ! 316: while (1) { ! 317: index = ext2_dir_entry(volume, &inode, index, &entry); ! 318: if (index == -1) ! 319: return 0; ! 320: ret = strncmp(name, entry.name, entry.name_len); ! 321: if (ret == 0 && ! 322: (name[entry.name_len] == 0 || ! 323: name[entry.name_len] == '\\')) { ! 324: ino = entry.inode; ! 325: break; ! 326: } ! 327: } ! 328: name += entry.name_len; ! 329: } ! 330: ! 331: return ino; ! 332: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.