1*68252eb5SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 207972ddeSPhillip Lougher /* 307972ddeSPhillip Lougher * Squashfs - a compressed read only filesystem for Linux 407972ddeSPhillip Lougher * 507972ddeSPhillip Lougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 6d7f2ff67SPhillip Lougher * Phillip Lougher <phillip@squashfs.org.uk> 707972ddeSPhillip Lougher * 807972ddeSPhillip Lougher * dir.c 907972ddeSPhillip Lougher */ 1007972ddeSPhillip Lougher 1107972ddeSPhillip Lougher /* 1207972ddeSPhillip Lougher * This file implements code to read directories from disk. 1307972ddeSPhillip Lougher * 1407972ddeSPhillip Lougher * See namei.c for a description of directory organisation on disk. 1507972ddeSPhillip Lougher */ 1607972ddeSPhillip Lougher 1707972ddeSPhillip Lougher #include <linux/fs.h> 1807972ddeSPhillip Lougher #include <linux/vfs.h> 1907972ddeSPhillip Lougher #include <linux/slab.h> 2007972ddeSPhillip Lougher 2107972ddeSPhillip Lougher #include "squashfs_fs.h" 2207972ddeSPhillip Lougher #include "squashfs_fs_sb.h" 2307972ddeSPhillip Lougher #include "squashfs_fs_i.h" 2407972ddeSPhillip Lougher #include "squashfs.h" 2507972ddeSPhillip Lougher 2607972ddeSPhillip Lougher static const unsigned char squashfs_filetype_table[] = { 2707972ddeSPhillip Lougher DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK 2807972ddeSPhillip Lougher }; 2907972ddeSPhillip Lougher 3007972ddeSPhillip Lougher /* 3107972ddeSPhillip Lougher * Lookup offset (f_pos) in the directory index, returning the 3207972ddeSPhillip Lougher * metadata block containing it. 3307972ddeSPhillip Lougher * 3407972ddeSPhillip Lougher * If we get an error reading the index then return the part of the index 3507972ddeSPhillip Lougher * (if any) we have managed to read - the index isn't essential, just 3607972ddeSPhillip Lougher * quicker. 3707972ddeSPhillip Lougher */ 3807972ddeSPhillip Lougher static int get_dir_index_using_offset(struct super_block *sb, 3907972ddeSPhillip Lougher u64 *next_block, int *next_offset, u64 index_start, int index_offset, 4007972ddeSPhillip Lougher int i_count, u64 f_pos) 4107972ddeSPhillip Lougher { 4207972ddeSPhillip Lougher struct squashfs_sb_info *msblk = sb->s_fs_info; 4307972ddeSPhillip Lougher int err, i, index, length = 0; 44f960cae5SPhillip Lougher unsigned int size; 4507972ddeSPhillip Lougher struct squashfs_dir_index dir_index; 4607972ddeSPhillip Lougher 4707972ddeSPhillip Lougher TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n", 4807972ddeSPhillip Lougher i_count, f_pos); 4907972ddeSPhillip Lougher 5007972ddeSPhillip Lougher /* 5107972ddeSPhillip Lougher * Translate from external f_pos to the internal f_pos. This 5207972ddeSPhillip Lougher * is offset by 3 because we invent "." and ".." entries which are 5307972ddeSPhillip Lougher * not actually stored in the directory. 5407972ddeSPhillip Lougher */ 552158d3fdSPhillip Lougher if (f_pos <= 3) 5607972ddeSPhillip Lougher return f_pos; 5707972ddeSPhillip Lougher f_pos -= 3; 5807972ddeSPhillip Lougher 5907972ddeSPhillip Lougher for (i = 0; i < i_count; i++) { 6007972ddeSPhillip Lougher err = squashfs_read_metadata(sb, &dir_index, &index_start, 6107972ddeSPhillip Lougher &index_offset, sizeof(dir_index)); 6207972ddeSPhillip Lougher if (err < 0) 6307972ddeSPhillip Lougher break; 6407972ddeSPhillip Lougher 6507972ddeSPhillip Lougher index = le32_to_cpu(dir_index.index); 6607972ddeSPhillip Lougher if (index > f_pos) 6707972ddeSPhillip Lougher /* 6807972ddeSPhillip Lougher * Found the index we're looking for. 6907972ddeSPhillip Lougher */ 7007972ddeSPhillip Lougher break; 7107972ddeSPhillip Lougher 72f960cae5SPhillip Lougher size = le32_to_cpu(dir_index.size) + 1; 73f960cae5SPhillip Lougher 74f960cae5SPhillip Lougher /* size should never be larger than SQUASHFS_NAME_LEN */ 75f960cae5SPhillip Lougher if (size > SQUASHFS_NAME_LEN) 76f960cae5SPhillip Lougher break; 77f960cae5SPhillip Lougher 7807972ddeSPhillip Lougher err = squashfs_read_metadata(sb, NULL, &index_start, 79f960cae5SPhillip Lougher &index_offset, size); 8007972ddeSPhillip Lougher if (err < 0) 8107972ddeSPhillip Lougher break; 8207972ddeSPhillip Lougher 8307972ddeSPhillip Lougher length = index; 8407972ddeSPhillip Lougher *next_block = le32_to_cpu(dir_index.start_block) + 8507972ddeSPhillip Lougher msblk->directory_table; 8607972ddeSPhillip Lougher } 8707972ddeSPhillip Lougher 8807972ddeSPhillip Lougher *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; 8907972ddeSPhillip Lougher 9007972ddeSPhillip Lougher /* 9107972ddeSPhillip Lougher * Translate back from internal f_pos to external f_pos. 9207972ddeSPhillip Lougher */ 9307972ddeSPhillip Lougher return length + 3; 9407972ddeSPhillip Lougher } 9507972ddeSPhillip Lougher 9607972ddeSPhillip Lougher 975f6039ceSAl Viro static int squashfs_readdir(struct file *file, struct dir_context *ctx) 9807972ddeSPhillip Lougher { 99496ad9aaSAl Viro struct inode *inode = file_inode(file); 10007972ddeSPhillip Lougher struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 10107972ddeSPhillip Lougher u64 block = squashfs_i(inode)->start + msblk->directory_table; 1029e012423SPhillip Lougher int offset = squashfs_i(inode)->offset, length, err; 1039e012423SPhillip Lougher unsigned int inode_number, dir_count, size, type; 10407972ddeSPhillip Lougher struct squashfs_dir_header dirh; 10507972ddeSPhillip Lougher struct squashfs_dir_entry *dire; 10607972ddeSPhillip Lougher 10707972ddeSPhillip Lougher TRACE("Entered squashfs_readdir [%llx:%x]\n", block, offset); 10807972ddeSPhillip Lougher 10907972ddeSPhillip Lougher dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL); 11007972ddeSPhillip Lougher if (dire == NULL) { 11107972ddeSPhillip Lougher ERROR("Failed to allocate squashfs_dir_entry\n"); 11207972ddeSPhillip Lougher goto finish; 11307972ddeSPhillip Lougher } 11407972ddeSPhillip Lougher 11507972ddeSPhillip Lougher /* 11607972ddeSPhillip Lougher * Return "." and ".." entries as the first two filenames in the 11707972ddeSPhillip Lougher * directory. To maximise compression these two entries are not 11807972ddeSPhillip Lougher * stored in the directory, and so we invent them here. 11907972ddeSPhillip Lougher * 12007972ddeSPhillip Lougher * It also means that the external f_pos is offset by 3 from the 12107972ddeSPhillip Lougher * on-disk directory f_pos. 12207972ddeSPhillip Lougher */ 1235f6039ceSAl Viro while (ctx->pos < 3) { 12407972ddeSPhillip Lougher char *name; 12507972ddeSPhillip Lougher int i_ino; 12607972ddeSPhillip Lougher 1275f6039ceSAl Viro if (ctx->pos == 0) { 12807972ddeSPhillip Lougher name = "."; 12907972ddeSPhillip Lougher size = 1; 13007972ddeSPhillip Lougher i_ino = inode->i_ino; 13107972ddeSPhillip Lougher } else { 13207972ddeSPhillip Lougher name = ".."; 13307972ddeSPhillip Lougher size = 2; 13407972ddeSPhillip Lougher i_ino = squashfs_i(inode)->parent; 13507972ddeSPhillip Lougher } 13607972ddeSPhillip Lougher 1375f6039ceSAl Viro if (!dir_emit(ctx, name, size, i_ino, 1385f6039ceSAl Viro squashfs_filetype_table[1])) 13907972ddeSPhillip Lougher goto finish; 14007972ddeSPhillip Lougher 1415f6039ceSAl Viro ctx->pos += size; 14207972ddeSPhillip Lougher } 14307972ddeSPhillip Lougher 14407972ddeSPhillip Lougher length = get_dir_index_using_offset(inode->i_sb, &block, &offset, 14507972ddeSPhillip Lougher squashfs_i(inode)->dir_idx_start, 14607972ddeSPhillip Lougher squashfs_i(inode)->dir_idx_offset, 14707972ddeSPhillip Lougher squashfs_i(inode)->dir_idx_cnt, 1485f6039ceSAl Viro ctx->pos); 14907972ddeSPhillip Lougher 15007972ddeSPhillip Lougher while (length < i_size_read(inode)) { 15107972ddeSPhillip Lougher /* 15207972ddeSPhillip Lougher * Read directory header 15307972ddeSPhillip Lougher */ 15407972ddeSPhillip Lougher err = squashfs_read_metadata(inode->i_sb, &dirh, &block, 15507972ddeSPhillip Lougher &offset, sizeof(dirh)); 15607972ddeSPhillip Lougher if (err < 0) 15707972ddeSPhillip Lougher goto failed_read; 15807972ddeSPhillip Lougher 15907972ddeSPhillip Lougher length += sizeof(dirh); 16007972ddeSPhillip Lougher 16107972ddeSPhillip Lougher dir_count = le32_to_cpu(dirh.count) + 1; 16244cff8a9SPhillip Lougher 1634826d83dSAjeet Yadav if (dir_count > SQUASHFS_DIR_COUNT) 16444cff8a9SPhillip Lougher goto failed_read; 16544cff8a9SPhillip Lougher 16607972ddeSPhillip Lougher while (dir_count--) { 16707972ddeSPhillip Lougher /* 16807972ddeSPhillip Lougher * Read directory entry. 16907972ddeSPhillip Lougher */ 17007972ddeSPhillip Lougher err = squashfs_read_metadata(inode->i_sb, dire, &block, 17107972ddeSPhillip Lougher &offset, sizeof(*dire)); 17207972ddeSPhillip Lougher if (err < 0) 17307972ddeSPhillip Lougher goto failed_read; 17407972ddeSPhillip Lougher 17507972ddeSPhillip Lougher size = le16_to_cpu(dire->size) + 1; 17607972ddeSPhillip Lougher 17744cff8a9SPhillip Lougher /* size should never be larger than SQUASHFS_NAME_LEN */ 17844cff8a9SPhillip Lougher if (size > SQUASHFS_NAME_LEN) 17944cff8a9SPhillip Lougher goto failed_read; 18044cff8a9SPhillip Lougher 18107972ddeSPhillip Lougher err = squashfs_read_metadata(inode->i_sb, dire->name, 18207972ddeSPhillip Lougher &block, &offset, size); 18307972ddeSPhillip Lougher if (err < 0) 18407972ddeSPhillip Lougher goto failed_read; 18507972ddeSPhillip Lougher 18607972ddeSPhillip Lougher length += sizeof(*dire) + size; 18707972ddeSPhillip Lougher 1885f6039ceSAl Viro if (ctx->pos >= length) 18907972ddeSPhillip Lougher continue; 19007972ddeSPhillip Lougher 19107972ddeSPhillip Lougher dire->name[size] = '\0'; 19207972ddeSPhillip Lougher inode_number = le32_to_cpu(dirh.inode_number) + 19307972ddeSPhillip Lougher ((short) le16_to_cpu(dire->inode_number)); 19407972ddeSPhillip Lougher type = le16_to_cpu(dire->type); 19507972ddeSPhillip Lougher 1969e012423SPhillip Lougher if (type > SQUASHFS_MAX_DIR_TYPE) 1979e012423SPhillip Lougher goto failed_read; 1989e012423SPhillip Lougher 1995f6039ceSAl Viro if (!dir_emit(ctx, dire->name, size, 20007972ddeSPhillip Lougher inode_number, 2015f6039ceSAl Viro squashfs_filetype_table[type])) 20207972ddeSPhillip Lougher goto finish; 20307972ddeSPhillip Lougher 2045f6039ceSAl Viro ctx->pos = length; 20507972ddeSPhillip Lougher } 20607972ddeSPhillip Lougher } 20707972ddeSPhillip Lougher 20807972ddeSPhillip Lougher finish: 20907972ddeSPhillip Lougher kfree(dire); 21007972ddeSPhillip Lougher return 0; 21107972ddeSPhillip Lougher 21207972ddeSPhillip Lougher failed_read: 21307972ddeSPhillip Lougher ERROR("Unable to read directory block [%llx:%x]\n", block, offset); 21407972ddeSPhillip Lougher kfree(dire); 21507972ddeSPhillip Lougher return 0; 21607972ddeSPhillip Lougher } 21707972ddeSPhillip Lougher 21807972ddeSPhillip Lougher 21907972ddeSPhillip Lougher const struct file_operations squashfs_dir_ops = { 22007972ddeSPhillip Lougher .read = generic_read_dir, 221d375570fSAl Viro .iterate_shared = squashfs_readdir, 222d375570fSAl Viro .llseek = generic_file_llseek, 22307972ddeSPhillip Lougher }; 224