static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir) { struct inode *i = file->f_dentry->d_inode; struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; long long next_block = SQUASHFS_I(i)->start_block + sblk->directory_table_start; int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; struct squashfs_dir_header_2 dirh; struct squashfs_dir_entry_2 *dire; TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ERROR("Failed to allocate squashfs_dir_entry\n"); goto finish; } length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, SQUASHFS_I(i)->u.s2.directory_index_start, SQUASHFS_I(i)->u.s2.directory_index_offset, SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos); while (length < i_size_read(i)) { /* read directory header */ if (msblk->swap) { struct squashfs_dir_header_2 sdirh; if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, next_offset, sizeof(sdirh), &next_block, &next_offset)) goto failed_read; length += sizeof(sdirh); SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); } else { if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, next_offset, sizeof(dirh), &next_block, &next_offset)) goto failed_read; length += sizeof(dirh); } dir_count = dirh.count + 1; while (dir_count--) { if (msblk->swap) { struct squashfs_dir_entry_2 sdire; if (!squashfs_get_cached_block(i->i_sb, (char *) &sdire, next_block, next_offset, sizeof(sdire), &next_block, &next_offset)) goto failed_read; length += sizeof(sdire); SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); } else { if (!squashfs_get_cached_block(i->i_sb, (char *) dire, next_block, next_offset, sizeof(*dire), &next_block, &next_offset)) goto failed_read; length += sizeof(*dire); } if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, next_offset, dire->size + 1, &next_block, &next_offset)) goto failed_read; length += dire->size + 1; if (file->f_pos >= length) continue; dire->name[dire->size + 1] = '\0'; TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", (unsigned int) dirent, dire->name, dire->size + 1, (int) file->f_pos, dirh.start_block, dire->offset, squashfs_filetype_table[dire->type]); if (filldir(dirent, dire->name, dire->size + 1, file->f_pos, SQUASHFS_MK_VFS_INODE( dirh.start_block, dire->offset), squashfs_filetype_table[dire->type]) < 0) { TRACE("Filldir returned less than 0\n"); goto finish; } file->f_pos = length; } } finish: kfree(dire); return 0; failed_read: ERROR("Unable to read directory block [%llx:%x]\n", next_block, next_offset); kfree(dire); return 0; }
static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry, struct nameidata *nd) { const unsigned char *name = dentry->d_name.name; int len = dentry->d_name.len; struct inode *inode = NULL; struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; long long next_block = SQUASHFS_I(i)->start_block + sblk->directory_table_start; int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; struct squashfs_dir_header_2 dirh; struct squashfs_dir_entry_2 *dire; int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset); if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ERROR("Failed to allocate squashfs_dir_entry\n"); goto exit_loop; } if (len > SQUASHFS_NAME_LEN) goto exit_loop; length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, SQUASHFS_I(i)->u.s2.directory_index_start, SQUASHFS_I(i)->u.s2.directory_index_offset, SQUASHFS_I(i)->u.s2.directory_index_count, name, len); while (length < i_size_read(i)) { /* read directory header */ if (msblk->swap) { struct squashfs_dir_header_2 sdirh; if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, next_offset, sizeof(sdirh), &next_block, &next_offset)) goto failed_read; length += sizeof(sdirh); SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); } else { if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, next_offset, sizeof(dirh), &next_block, &next_offset)) goto failed_read; length += sizeof(dirh); } dir_count = dirh.count + 1; while (dir_count--) { if (msblk->swap) { struct squashfs_dir_entry_2 sdire; if (!squashfs_get_cached_block(i->i_sb, (char *) &sdire, next_block,next_offset, sizeof(sdire), &next_block, &next_offset)) goto failed_read; length += sizeof(sdire); SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); } else { if (!squashfs_get_cached_block(i->i_sb, (char *) dire, next_block,next_offset, sizeof(*dire), &next_block, &next_offset)) goto failed_read; length += sizeof(*dire); } if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, next_offset, dire->size + 1, &next_block, &next_offset)) goto failed_read; length += dire->size + 1; if (sorted && name[0] < dire->name[0]) goto exit_loop; if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) { squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, dire->offset); unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block, dire->offset); TRACE("calling squashfs_iget for directory " "entry %s, inode %x:%x, %lld\n", name, dirh.start_block, dire->offset, ino); inode = squashfs_iget(i->i_sb, ino, inode_number); goto exit_loop; } } } exit_loop: kfree(dire); d_add(dentry, inode); return ERR_PTR(0); failed_read: ERROR("Unable to read directory block [%llx:%x]\n", next_block, next_offset); goto exit_loop; }
static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) { struct super_block *s = i->i_sb; struct squashfs_sb_info *msblk = s->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; unsigned int block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start; unsigned int offset = SQUASHFS_INODE_OFFSET(inode); unsigned int ino = SQUASHFS_MK_VFS_INODE(block - sblk->inode_table_start, offset); long long next_block; unsigned int next_offset; union squashfs_inode_header_2 id, sid; struct squashfs_base_inode_header_2 *inodeb = &id.base, *sinodeb = &sid.base; TRACE("Entered squashfs_read_inode_2\n"); if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodeb, block, offset, sizeof(*sinodeb), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, sizeof(*sinodeb)); } else if (!squashfs_get_cached_block(s, (char *) inodeb, block, offset, sizeof(*inodeb), &next_block, &next_offset)) goto failed_read; squashfs_new_inode(msblk, i, inodeb, ino); switch(inodeb->inode_type) { case SQUASHFS_FILE_TYPE: { struct squashfs_reg_inode_header_2 *inodep = &id.reg; struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; long long frag_blk; unsigned int frag_size = 0; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; frag_blk = SQUASHFS_INVALID_BLK; if (inodep->fragment != SQUASHFS_INVALID_FRAG && !get_fragment_location_2(s, inodep->fragment, &frag_blk, &frag_size)) goto failed_read; i->i_size = inodep->file_size; i->i_fop = &generic_ro_fops; i->i_mode |= S_IFREG; i->i_mtime.tv_sec = inodep->mtime; i->i_atime.tv_sec = inodep->mtime; i->i_ctime.tv_sec = inodep->mtime; i->i_blocks = ((i->i_size - 1) >> 9) + 1; i->i_blksize = PAGE_CACHE_SIZE; SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; SQUASHFS_I(i)->u.s1.fragment_size = frag_size; SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; SQUASHFS_I(i)->start_block = inodep->start_block; SQUASHFS_I(i)->u.s1.block_list_start = next_block; SQUASHFS_I(i)->offset = next_offset; i->i_data.a_ops = &squashfs_aops; TRACE("File inode %x:%x, start_block %x, " "block_list_start %llx, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep->start_block, next_block, next_offset); break; } case SQUASHFS_DIR_TYPE: { struct squashfs_dir_inode_header_2 *inodep = &id.dir; struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; i->i_size = inodep->file_size; i->i_op = &squashfs_dir_inode_ops_2; i->i_fop = &squashfs_dir_ops_2; i->i_mode |= S_IFDIR; i->i_mtime.tv_sec = inodep->mtime; i->i_atime.tv_sec = inodep->mtime; i->i_ctime.tv_sec = inodep->mtime; SQUASHFS_I(i)->start_block = inodep->start_block; SQUASHFS_I(i)->offset = inodep->offset; SQUASHFS_I(i)->u.s2.directory_index_count = 0; SQUASHFS_I(i)->u.s2.parent_inode = 0; TRACE("Directory inode %x:%x, start_block %x, offset " "%x\n", SQUASHFS_INODE_BLK(inode), offset, inodep->start_block, inodep->offset); break; } case SQUASHFS_LDIR_TYPE: { struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; i->i_size = inodep->file_size; i->i_op = &squashfs_dir_inode_ops_2; i->i_fop = &squashfs_dir_ops_2; i->i_mode |= S_IFDIR; i->i_mtime.tv_sec = inodep->mtime; i->i_atime.tv_sec = inodep->mtime; i->i_ctime.tv_sec = inodep->mtime; SQUASHFS_I(i)->start_block = inodep->start_block; SQUASHFS_I(i)->offset = inodep->offset; SQUASHFS_I(i)->u.s2.directory_index_start = next_block; SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset; SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count; SQUASHFS_I(i)->u.s2.parent_inode = 0; TRACE("Long directory inode %x:%x, start_block %x, " "offset %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep->start_block, inodep->offset); break; } case SQUASHFS_SYMLINK_TYPE: { struct squashfs_symlink_inode_header_2 *inodep = &id.symlink; struct squashfs_symlink_inode_header_2 *sinodep = &sid.symlink; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; i->i_size = inodep->symlink_size; i->i_op = &page_symlink_inode_operations; i->i_data.a_ops = &squashfs_symlink_aops; i->i_mode |= S_IFLNK; SQUASHFS_I(i)->start_block = next_block; SQUASHFS_I(i)->offset = next_offset; TRACE("Symbolic link inode %x:%x, start_block %llx, " "offset %x\n", SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: { struct squashfs_dev_inode_header_2 *inodep = &id.dev; struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodep, block, offset, sizeof(*sinodep), &next_block, &next_offset)) goto failed_read; SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); } else if (!squashfs_get_cached_block(s, (char *) inodep, block, offset, sizeof(*inodep), &next_block, &next_offset)) goto failed_read; i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev)); TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep->rdev); break; } case SQUASHFS_FIFO_TYPE: case SQUASHFS_SOCKET_TYPE: { i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; init_special_inode(i, i->i_mode, 0); break; } default: ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb->inode_type); goto failed_read1; } return 1; failed_read: ERROR("Unable to read inode [%x:%x]\n", block, offset); failed_read1: return 0; }