char *ext4fs_read_symlink(struct ext2fs_node *node) { char *symlink; struct ext2fs_node *diro = node; int status, ret; if (!diro->inode_read) { ret = ext4fs_read_inode(diro->data, diro->ino, &diro->inode); if (ret) return NULL; } symlink = zalloc(__le32_to_cpu(diro->inode.size) + 1); if (!symlink) return 0; if (__le32_to_cpu(diro->inode.size) <= 60) { strncpy(symlink, diro->inode.b.symlink, __le32_to_cpu(diro->inode.size)); } else { status = ext4fs_read_file(diro, 0, __le32_to_cpu(diro->inode.size), symlink); if (status == 0) { free(symlink); return NULL; } } symlink[__le32_to_cpu(diro->inode.size)] = '\0'; return symlink; }
int ext4fs_open(struct ext2_data *data, const char *filename, struct ext2fs_node **inode) { struct ext2fs_node *fdiro = NULL; int status, ret; int type; status = ext4fs_find_file(filename, &data->diropen, &fdiro, &type); if (status) goto fail; if (type != FILETYPE_REG) return -EINVAL; if (!fdiro->inode_read) { ret = ext4fs_read_inode(fdiro->data, fdiro->ino, &fdiro->inode); if (ret) goto fail; } *inode = fdiro; return 0; fail: ext4fs_free_node(fdiro, &data->diropen); return -ENOENT; }
static DIR *ext_opendir(struct device_d *dev, const char *pathname) { struct ext_filesystem *fs = dev->priv; struct ext4fs_dir *ext4_dir; int type, ret; ext4_dir = xzalloc(sizeof(*ext4_dir)); ret = ext4fs_find_file(pathname, &fs->data->diropen, &ext4_dir->dirnode, &type); if (ret) { free(ext4_dir); return NULL; } if (type != FILETYPE_DIRECTORY) return NULL; ext4_dir->dir.priv = ext4_dir; ret = ext4fs_read_inode(ext4_dir->dirnode->data, ext4_dir->dirnode->ino, &ext4_dir->dirnode->inode); if (ret) { ext4fs_free_node(ext4_dir->dirnode, &fs->data->diropen); free(ext4_dir); return NULL; } return &ext4_dir->dir; }
static void update_commit_block(long int blknr) { struct journal_header_t jdb; struct ext_filesystem *fs = get_fs(); char *buf = NULL; struct ext2_inode inode_journal; struct journal_superblock_t *jsb; long int jsb_blknr; char *temp_buff = zalloc(fs->blksz); if (!temp_buff) return; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK); jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); jdb.h_sequence = jsb->s_sequence; buf = zalloc(fs->blksz); if (!buf) { free(temp_buff); return; } memcpy(buf, &jdb, sizeof(struct journal_header_t)); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz); free(temp_buff); free(buf); }
int ext4fs_open(const char *filename) { struct ext2fs_node *fdiro = NULL; int status; int len; if (ext4fs_root == NULL) return -1; ext4fs_file = NULL; status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro, FILETYPE_REG); if (status == 0) goto fail; if (!fdiro->inode_read) { status = ext4fs_read_inode(fdiro->data, fdiro->ino, &fdiro->inode); if (status == 0) goto fail; } len = __le32_to_cpu(fdiro->inode.size); ext4fs_file = fdiro; return len; fail: ext4fs_free_node(fdiro, &ext4fs_root->diropen); return -1; }
int ext4fs_mount(struct ext_filesystem *fs) { struct ext2_data *data; int ret, blksz; data = zalloc(sizeof(struct ext2_data)); if (!data) return -ENOMEM; /* Read the superblock. */ ret = ext4fs_devread(fs, 1 * 2, 0, sizeof(struct ext2_sblock), (char *)&data->sblock); if (ret) goto fail; /* Make sure this is an ext2 filesystem. */ if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC) { ret = -EINVAL; goto fail; } if (__le32_to_cpu(data->sblock.revision_level == 0)) fs->inodesz = 128; else fs->inodesz = __le16_to_cpu(data->sblock.inode_size); dev_info(fs->dev, "EXT2 rev %d, inode_size %d\n", __le32_to_cpu(data->sblock.revision_level), fs->inodesz); data->diropen.data = data; data->diropen.ino = 2; data->diropen.inode_read = 1; data->inode = &data->diropen.inode; data->fs = fs; fs->data = data; blksz = EXT2_BLOCK_SIZE(data); fs->data->indir1.data = malloc(blksz); fs->data->indir2.data = malloc(blksz); fs->data->indir3.data = malloc(blksz); if (!fs->data->indir1.data || !fs->data->indir2.data || !fs->data->indir3.data) { ret = -ENOMEM; goto fail; } ret = ext4fs_read_inode(data, 2, data->inode); if (ret) goto fail; return 0; fail: free(data); return ret; }
static void update_descriptor_block(long int blknr) { int i; long int jsb_blknr; struct journal_header_t jdb; struct ext3_journal_block_tag tag; struct ext2_inode inode_journal; struct journal_superblock_t *jsb = NULL; char *buf = NULL; char *temp = NULL; struct ext_filesystem *fs = get_fs(); char *temp_buff = zalloc(fs->blksz); if (!temp_buff) return; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK); jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); jdb.h_sequence = jsb->s_sequence; buf = zalloc(fs->blksz); if (!buf) { free(temp_buff); return; } temp = buf; memcpy(buf, &jdb, sizeof(struct journal_header_t)); temp += sizeof(struct journal_header_t); for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { if (journal_ptr[i]->blknr == -1) break; tag.block = cpu_to_be32(journal_ptr[i]->blknr); tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID); memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag)); temp = temp + sizeof(struct ext3_journal_block_tag); } tag.block = cpu_to_be32(journal_ptr[--i]->blknr); tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG); memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag, sizeof(struct ext3_journal_block_tag)); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz); free(temp_buff); free(buf); }
/* * This function parses the journal blocks and replays the * suceessful transactions. A transaction is successfull * if commit block is found for a descriptor block * The tags in descriptor block contain the disk block * numbers of the metadata to be replayed */ void recover_transaction(int prev_desc_logical_no) { struct ext2_inode inode_journal; struct ext_filesystem *fs = get_fs(); struct journal_header_t *jdb; long int blknr; char *p_jdb; int ofs, flags; int i; struct ext3_journal_block_tag *tag; char *temp_buff = zalloc(fs->blksz); char *metadata_buff = zalloc(fs->blksz); if (!temp_buff || !metadata_buff) goto fail; i = prev_desc_logical_no; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, (struct ext2_inode *)&inode_journal); blknr = read_allocated_block((struct ext2_inode *) &inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); p_jdb = (char *)temp_buff; jdb = (struct journal_header_t *) temp_buff; ofs = sizeof(struct journal_header_t); do { tag = (struct ext3_journal_block_tag *)(p_jdb + ofs); ofs += sizeof(struct ext3_journal_block_tag); if (ofs > fs->blksz) break; flags = be32_to_cpu(tag->flags); if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) ofs += 16; i++; debug("\t\ttag %u\n", be32_to_cpu(tag->block)); if (revk_blk_list != NULL) { if (check_blknr_for_revoke(be32_to_cpu(tag->block), be32_to_cpu(jdb->h_sequence)) == 0) continue; } blknr = read_allocated_block(&inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, metadata_buff); put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz), metadata_buff, (uint32_t) fs->blksz); } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); fail: free(temp_buff); free(metadata_buff); }
int ext4fs_mount(unsigned part_length) { struct ext2_data *data; int status; struct ext_filesystem *fs = get_fs(); data = zalloc(sizeof(struct ext2_data)); if (!data) return 0; /* Read the superblock. */ status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock), (char *)&data->sblock); if (status == 0) goto fail; /* Make sure this is an ext2 filesystem. */ if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC) goto fail; if (__le32_to_cpu(data->sblock.revision_level == 0)) fs->inodesz = 128; else fs->inodesz = __le16_to_cpu(data->sblock.inode_size); debug("EXT2 rev %d, inode_size %d\n", __le32_to_cpu(data->sblock.revision_level), fs->inodesz); data->diropen.data = data; data->diropen.ino = 2; data->diropen.inode_read = 1; data->inode = &data->diropen.inode; status = ext4fs_read_inode(data, 2, data->inode); if (status == 0) goto fail; ext4fs_root = data; return 1; fail: printf("Failed to mount ext2 filesystem...\n"); free(data); ext4fs_root = NULL; return 0; }
void ext4fs_update_journal(void) { struct ext2_inode inode_journal; struct ext_filesystem *fs = get_fs(); long int blknr; int i; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); update_descriptor_block(blknr); for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { if (journal_ptr[i]->blknr == -1) break; blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), journal_ptr[i]->buf, fs->blksz); } blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); update_commit_block(blknr); printf("update journal finished\n"); }
static int ext_stat(struct device_d *dev, const char *filename, struct stat *s) { struct ext_filesystem *fs = dev->priv; struct ext2fs_node *node; int status, ret; status = ext4fs_find_file(filename, &fs->data->diropen, &node, NULL); if (status) return -ENOENT; ret = ext4fs_read_inode(node->data, node->ino, &node->inode); if (ret) return ret; s->st_size = __le32_to_cpu(node->inode.size); s->st_mode = __le16_to_cpu(node->inode.mode); ext4fs_free_node(node, &fs->data->diropen); return 0; }
int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, struct ext2fs_node **fnode, int *ftype) { unsigned int fpos = 0; int status, ret; struct ext2fs_node *diro = (struct ext2fs_node *) dir; struct ext_filesystem *fs = dir->data->fs; if (name != NULL) dev_dbg(fs->dev, "Iterate dir %s\n", name); if (!diro->inode_read) { ret = ext4fs_read_inode(diro->data, diro->ino, &diro->inode); if (ret) return ret; } /* Search the file. */ while (fpos < __le32_to_cpu(diro->inode.size)) { struct ext2_dirent dirent; status = ext4fs_read_file(diro, fpos, sizeof(struct ext2_dirent), (char *) &dirent); if (status < 1) return -EINVAL; if (dirent.namelen != 0) { char filename[dirent.namelen + 1]; struct ext2fs_node *fdiro; int type = FILETYPE_UNKNOWN; status = ext4fs_read_file(diro, fpos + sizeof(struct ext2_dirent), dirent.namelen, filename); if (status < 1) return -EINVAL; fdiro = zalloc(sizeof(struct ext2fs_node)); if (!fdiro) return -ENOMEM; fdiro->data = diro->data; fdiro->ino = __le32_to_cpu(dirent.inode); filename[dirent.namelen] = '\0'; if (dirent.filetype != FILETYPE_UNKNOWN) { fdiro->inode_read = 0; if (dirent.filetype == FILETYPE_DIRECTORY) type = FILETYPE_DIRECTORY; else if (dirent.filetype == FILETYPE_SYMLINK) type = FILETYPE_SYMLINK; else if (dirent.filetype == FILETYPE_REG) type = FILETYPE_REG; } else { ret = ext4fs_read_inode(diro->data, __le32_to_cpu (dirent.inode), &fdiro->inode); if (ret) { free(fdiro); return ret; } fdiro->inode_read = 1; if ((__le16_to_cpu(fdiro->inode.mode) & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY) { type = FILETYPE_DIRECTORY; } else if ((__le16_to_cpu(fdiro->inode.mode) & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK) { type = FILETYPE_SYMLINK; } else if ((__le16_to_cpu(fdiro->inode.mode) & FILETYPE_INO_MASK) == FILETYPE_INO_REG) { type = FILETYPE_REG; } } dev_dbg(fs->dev, "iterate >%s<\n", filename); if (strcmp(filename, name) == 0) { *ftype = type; *fnode = fdiro; return 0; } free(fdiro); } fpos += __le16_to_cpu(dirent.direntlen); } return -ENOENT; }
int ext4fs_check_journal_state(int recovery_flag) { int i; int DB_FOUND = NO; long int blknr; int transaction_state = TRANSACTION_COMPLETE; int prev_desc_logical_no = 0; int curr_desc_logical_no = 0; int ofs, flags; struct ext2_inode inode_journal; struct journal_superblock_t *jsb = NULL; struct journal_header_t *jdb = NULL; char *p_jdb = NULL; struct ext3_journal_block_tag *tag = NULL; char *temp_buff = NULL; char *temp_buff1 = NULL; struct ext_filesystem *fs = get_fs(); temp_buff = zalloc(fs->blksz); if (!temp_buff) return -ENOMEM; temp_buff1 = zalloc(fs->blksz); if (!temp_buff1) { free(temp_buff); return -ENOMEM; } ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; if (le32_to_cpu(fs->sb->feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) { if (recovery_flag == RECOVER) printf("Recovery required\n"); } else { if (recovery_flag == RECOVER) printf("File System is consistent\n"); goto end; } if (be32_to_cpu(jsb->s_start) == 0) goto end; if (!(jsb->s_feature_compat & cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM))) jsb->s_feature_compat |= cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); i = be32_to_cpu(jsb->s_first); while (1) { blknr = read_allocated_block(&inode_journal, i, NULL); memset(temp_buff1, '\0', fs->blksz); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff1); jdb = (struct journal_header_t *) temp_buff1; if (be32_to_cpu(jdb->h_blocktype) == EXT3_JOURNAL_DESCRIPTOR_BLOCK) { if (be32_to_cpu(jdb->h_sequence) != be32_to_cpu(jsb->s_sequence)) { print_jrnl_status(recovery_flag); break; } curr_desc_logical_no = i; if (transaction_state == TRANSACTION_COMPLETE) transaction_state = TRANSACTION_RUNNING; else return -1; p_jdb = (char *)temp_buff1; ofs = sizeof(struct journal_header_t); do { tag = (struct ext3_journal_block_tag *) (p_jdb + ofs); ofs += sizeof(struct ext3_journal_block_tag); if (ofs > fs->blksz) break; flags = be32_to_cpu(tag->flags); if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) ofs += 16; i++; debug("\t\ttag %u\n", be32_to_cpu(tag->block)); } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); i++; DB_FOUND = YES; } else if (be32_to_cpu(jdb->h_blocktype) == EXT3_JOURNAL_COMMIT_BLOCK) { if (be32_to_cpu(jdb->h_sequence) != be32_to_cpu(jsb->s_sequence)) { print_jrnl_status(recovery_flag); break; } if (transaction_state == TRANSACTION_RUNNING || (DB_FOUND == NO)) { transaction_state = TRANSACTION_COMPLETE; i++; jsb->s_sequence = cpu_to_be32(be32_to_cpu( jsb->s_sequence) + 1); } prev_desc_logical_no = curr_desc_logical_no; if ((recovery_flag == RECOVER) && (DB_FOUND == YES)) recover_transaction(prev_desc_logical_no); DB_FOUND = NO; } else if (be32_to_cpu(jdb->h_blocktype) == EXT3_JOURNAL_REVOKE_BLOCK) { if (be32_to_cpu(jdb->h_sequence) != be32_to_cpu(jsb->s_sequence)) { print_jrnl_status(recovery_flag); break; } if (recovery_flag == SCAN) ext4fs_push_revoke_blk((char *)jdb); i++; } else { debug("Else Case\n"); if (be32_to_cpu(jdb->h_sequence) != be32_to_cpu(jsb->s_sequence)) { print_jrnl_status(recovery_flag); break; } } } end: if (recovery_flag == RECOVER) { uint32_t new_feature_incompat; jsb->s_start = cpu_to_be32(1); jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1); /* get the superblock */ ext4_read_superblock((char *)fs->sb); new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat); new_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER; fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat); /* Update the super block */ put_ext4((uint64_t) (SUPERBLOCK_SIZE), (struct ext2_sblock *)fs->sb, (uint32_t) SUPERBLOCK_SIZE); ext4_read_superblock((char *)fs->sb); blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, NULL); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), (struct journal_superblock_t *)temp_buff, (uint32_t) fs->blksz); ext4fs_free_revoke_blks(); } free(temp_buff); free(temp_buff1); return 0; }
int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, struct ext2fs_node **fnode, int *ftype) { unsigned int fpos = 0; int status; struct ext2fs_node *diro = (struct ext2fs_node *)dir; #ifdef DEBUG if (name != NULL) printf("Iterate dir %s\n", name); #endif /* of DEBUG */ if (!diro->inode_read) { status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode); if (status == 0) return 0; } /* Search the file. */ while (fpos < __le32_to_cpu(diro->inode.size)) { struct ext2_dirent dirent; status = ext4fs_read_file(diro, fpos, sizeof(struct ext2_dirent), (char *)&dirent); if (status < 1) return 0; if (dirent.namelen != 0) { char filename[dirent.namelen + 1]; struct ext2fs_node *fdiro; int type = FILETYPE_UNKNOWN; status = ext4fs_read_file(diro, fpos + sizeof(struct ext2_dirent), dirent.namelen, filename); if (status < 1) return 0; fdiro = zalloc(sizeof(struct ext2fs_node)); if (!fdiro) return 0; fdiro->data = diro->data; fdiro->ino = __le32_to_cpu(dirent.inode); filename[dirent.namelen] = '\0'; if (dirent.filetype != FILETYPE_UNKNOWN) { fdiro->inode_read = 0; if (dirent.filetype == FILETYPE_DIRECTORY) type = FILETYPE_DIRECTORY; else if (dirent.filetype == FILETYPE_SYMLINK) type = FILETYPE_SYMLINK; else if (dirent.filetype == FILETYPE_REG) type = FILETYPE_REG; } else { status = ext4fs_read_inode(diro->data, __le32_to_cpu (dirent.inode), &fdiro->inode); if (status == 0) { free(fdiro); return 0; } fdiro->inode_read = 1; if ((__le16_to_cpu(fdiro->inode.mode) & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY) { type = FILETYPE_DIRECTORY; } else if ((__le16_to_cpu(fdiro->inode.mode) & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK) { type = FILETYPE_SYMLINK; } else if ((__le16_to_cpu(fdiro->inode.mode) & FILETYPE_INO_MASK) == FILETYPE_INO_REG) { type = FILETYPE_REG; } } #ifdef DEBUG printf("iterate >%s<\n", filename); #endif /* of DEBUG */ if ((name != NULL) && (fnode != NULL) && (ftype != NULL)) { if (strcmp(filename, name) == 0) { *ftype = type; *fnode = fdiro; return 1; } } else { if (fdiro->inode_read == 0) { status = ext4fs_read_inode(diro->data, __le32_to_cpu( dirent.inode), &fdiro->inode); if (status == 0) { free(fdiro); return 0; } fdiro->inode_read = 1; } switch (type) { case FILETYPE_DIRECTORY: printf("<DIR> "); break; case FILETYPE_SYMLINK: printf("<SYM> "); break; case FILETYPE_REG: printf(" "); break; default: printf("< ? > "); break; } printf("%10d %s\n", __le32_to_cpu(fdiro->inode.size), filename); } free(fdiro); } fpos += __le16_to_cpu(dirent.direntlen); } return 0; }