1*68252eb5SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2c88da2c9SPhillip Lougher /* 3c88da2c9SPhillip Lougher * Squashfs - a compressed read only filesystem for Linux 4c88da2c9SPhillip Lougher * 5c88da2c9SPhillip Lougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 6d7f2ff67SPhillip Lougher * Phillip Lougher <phillip@squashfs.org.uk> 7c88da2c9SPhillip Lougher * 8c88da2c9SPhillip Lougher * namei.c 9c88da2c9SPhillip Lougher */ 10c88da2c9SPhillip Lougher 11c88da2c9SPhillip Lougher /* 12c88da2c9SPhillip Lougher * This file implements code to do filename lookup in directories. 13c88da2c9SPhillip Lougher * 14c88da2c9SPhillip Lougher * Like inodes, directories are packed into compressed metadata blocks, stored 15c88da2c9SPhillip Lougher * in a directory table. Directories are accessed using the start address of 16c88da2c9SPhillip Lougher * the metablock containing the directory and the offset into the 17c88da2c9SPhillip Lougher * decompressed block (<block, offset>). 18c88da2c9SPhillip Lougher * 19c88da2c9SPhillip Lougher * Directories are organised in a slightly complex way, and are not simply 20c88da2c9SPhillip Lougher * a list of file names. The organisation takes advantage of the 21c88da2c9SPhillip Lougher * fact that (in most cases) the inodes of the files will be in the same 22c88da2c9SPhillip Lougher * compressed metadata block, and therefore, can share the start block. 23c88da2c9SPhillip Lougher * Directories are therefore organised in a two level list, a directory 24c88da2c9SPhillip Lougher * header containing the shared start block value, and a sequence of directory 25c88da2c9SPhillip Lougher * entries, each of which share the shared start block. A new directory header 26c88da2c9SPhillip Lougher * is written once/if the inode start block changes. The directory 27c88da2c9SPhillip Lougher * header/directory entry list is repeated as many times as necessary. 28c88da2c9SPhillip Lougher * 29c88da2c9SPhillip Lougher * Directories are sorted, and can contain a directory index to speed up 30c88da2c9SPhillip Lougher * file lookup. Directory indexes store one entry per metablock, each entry 31c88da2c9SPhillip Lougher * storing the index/filename mapping to the first directory header 32c88da2c9SPhillip Lougher * in each metadata block. Directories are sorted in alphabetical order, 33c88da2c9SPhillip Lougher * and at lookup the index is scanned linearly looking for the first filename 34c88da2c9SPhillip Lougher * alphabetically larger than the filename being looked up. At this point the 35c88da2c9SPhillip Lougher * location of the metadata block the filename is in has been found. 36c88da2c9SPhillip Lougher * The general idea of the index is ensure only one metadata block needs to be 37c88da2c9SPhillip Lougher * decompressed to do a lookup irrespective of the length of the directory. 38c88da2c9SPhillip Lougher * This scheme has the advantage that it doesn't require extra memory overhead 39c88da2c9SPhillip Lougher * and doesn't require much extra storage on disk. 40c88da2c9SPhillip Lougher */ 41c88da2c9SPhillip Lougher 42c88da2c9SPhillip Lougher #include <linux/fs.h> 43c88da2c9SPhillip Lougher #include <linux/vfs.h> 44c88da2c9SPhillip Lougher #include <linux/slab.h> 45c88da2c9SPhillip Lougher #include <linux/string.h> 46c88da2c9SPhillip Lougher #include <linux/dcache.h> 4767f66cc6SPhillip Lougher #include <linux/xattr.h> 48c88da2c9SPhillip Lougher 49c88da2c9SPhillip Lougher #include "squashfs_fs.h" 50c88da2c9SPhillip Lougher #include "squashfs_fs_sb.h" 51c88da2c9SPhillip Lougher #include "squashfs_fs_i.h" 52c88da2c9SPhillip Lougher #include "squashfs.h" 5301e5b4e4SPhillip Lougher #include "xattr.h" 54c88da2c9SPhillip Lougher 55c88da2c9SPhillip Lougher /* 56c88da2c9SPhillip Lougher * Lookup name in the directory index, returning the location of the metadata 57c88da2c9SPhillip Lougher * block containing it, and the directory index this represents. 58c88da2c9SPhillip Lougher * 59c88da2c9SPhillip Lougher * If we get an error reading the index then return the part of the index 60c88da2c9SPhillip Lougher * (if any) we have managed to read - the index isn't essential, just 61c88da2c9SPhillip Lougher * quicker. 62c88da2c9SPhillip Lougher */ 63c88da2c9SPhillip Lougher static int get_dir_index_using_name(struct super_block *sb, 64c88da2c9SPhillip Lougher u64 *next_block, int *next_offset, u64 index_start, 65c88da2c9SPhillip Lougher int index_offset, int i_count, const char *name, 66c88da2c9SPhillip Lougher int len) 67c88da2c9SPhillip Lougher { 68c88da2c9SPhillip Lougher struct squashfs_sb_info *msblk = sb->s_fs_info; 6928d7b568SDan Carpenter int i, length = 0, err; 7028d7b568SDan Carpenter unsigned int size; 71c88da2c9SPhillip Lougher struct squashfs_dir_index *index; 72c88da2c9SPhillip Lougher char *str; 73c88da2c9SPhillip Lougher 74c88da2c9SPhillip Lougher TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); 75c88da2c9SPhillip Lougher 76c88da2c9SPhillip Lougher index = kmalloc(sizeof(*index) + SQUASHFS_NAME_LEN * 2 + 2, GFP_KERNEL); 77c88da2c9SPhillip Lougher if (index == NULL) { 78c88da2c9SPhillip Lougher ERROR("Failed to allocate squashfs_dir_index\n"); 79c88da2c9SPhillip Lougher goto out; 80c88da2c9SPhillip Lougher } 81c88da2c9SPhillip Lougher 82c88da2c9SPhillip Lougher str = &index->name[SQUASHFS_NAME_LEN + 1]; 83c88da2c9SPhillip Lougher strncpy(str, name, len); 84c88da2c9SPhillip Lougher str[len] = '\0'; 85c88da2c9SPhillip Lougher 86c88da2c9SPhillip Lougher for (i = 0; i < i_count; i++) { 87c88da2c9SPhillip Lougher err = squashfs_read_metadata(sb, index, &index_start, 88c88da2c9SPhillip Lougher &index_offset, sizeof(*index)); 89c88da2c9SPhillip Lougher if (err < 0) 90c88da2c9SPhillip Lougher break; 91c88da2c9SPhillip Lougher 92c88da2c9SPhillip Lougher 93c88da2c9SPhillip Lougher size = le32_to_cpu(index->size) + 1; 949dbc41d5SPhillip Lougher if (size > SQUASHFS_NAME_LEN) 9528d7b568SDan Carpenter break; 96c88da2c9SPhillip Lougher 97c88da2c9SPhillip Lougher err = squashfs_read_metadata(sb, index->name, &index_start, 98c88da2c9SPhillip Lougher &index_offset, size); 99c88da2c9SPhillip Lougher if (err < 0) 100c88da2c9SPhillip Lougher break; 101c88da2c9SPhillip Lougher 102c88da2c9SPhillip Lougher index->name[size] = '\0'; 103c88da2c9SPhillip Lougher 104c88da2c9SPhillip Lougher if (strcmp(index->name, str) > 0) 105c88da2c9SPhillip Lougher break; 106c88da2c9SPhillip Lougher 107c88da2c9SPhillip Lougher length = le32_to_cpu(index->index); 108c88da2c9SPhillip Lougher *next_block = le32_to_cpu(index->start_block) + 109c88da2c9SPhillip Lougher msblk->directory_table; 110c88da2c9SPhillip Lougher } 111c88da2c9SPhillip Lougher 112c88da2c9SPhillip Lougher *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; 113c88da2c9SPhillip Lougher kfree(index); 114c88da2c9SPhillip Lougher 115c88da2c9SPhillip Lougher out: 116c88da2c9SPhillip Lougher /* 117c88da2c9SPhillip Lougher * Return index (f_pos) of the looked up metadata block. Translate 118c88da2c9SPhillip Lougher * from internal f_pos to external f_pos which is offset by 3 because 119c88da2c9SPhillip Lougher * we invent "." and ".." entries which are not actually stored in the 120c88da2c9SPhillip Lougher * directory. 121c88da2c9SPhillip Lougher */ 122c88da2c9SPhillip Lougher return length + 3; 123c88da2c9SPhillip Lougher } 124c88da2c9SPhillip Lougher 125c88da2c9SPhillip Lougher 126c88da2c9SPhillip Lougher static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, 12700cd8dd3SAl Viro unsigned int flags) 128c88da2c9SPhillip Lougher { 129c88da2c9SPhillip Lougher const unsigned char *name = dentry->d_name.name; 130c88da2c9SPhillip Lougher int len = dentry->d_name.len; 131c88da2c9SPhillip Lougher struct inode *inode = NULL; 132c88da2c9SPhillip Lougher struct squashfs_sb_info *msblk = dir->i_sb->s_fs_info; 133c88da2c9SPhillip Lougher struct squashfs_dir_header dirh; 134c88da2c9SPhillip Lougher struct squashfs_dir_entry *dire; 135c88da2c9SPhillip Lougher u64 block = squashfs_i(dir)->start + msblk->directory_table; 136c88da2c9SPhillip Lougher int offset = squashfs_i(dir)->offset; 13752e9ce1cSPhillip Lougher int err, length; 13852e9ce1cSPhillip Lougher unsigned int dir_count, size; 139c88da2c9SPhillip Lougher 140c88da2c9SPhillip Lougher TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset); 141c88da2c9SPhillip Lougher 142c88da2c9SPhillip Lougher dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL); 143c88da2c9SPhillip Lougher if (dire == NULL) { 144c88da2c9SPhillip Lougher ERROR("Failed to allocate squashfs_dir_entry\n"); 145c88da2c9SPhillip Lougher return ERR_PTR(-ENOMEM); 146c88da2c9SPhillip Lougher } 147c88da2c9SPhillip Lougher 148c88da2c9SPhillip Lougher if (len > SQUASHFS_NAME_LEN) { 149c88da2c9SPhillip Lougher err = -ENAMETOOLONG; 150c88da2c9SPhillip Lougher goto failed; 151c88da2c9SPhillip Lougher } 152c88da2c9SPhillip Lougher 153c88da2c9SPhillip Lougher length = get_dir_index_using_name(dir->i_sb, &block, &offset, 154c88da2c9SPhillip Lougher squashfs_i(dir)->dir_idx_start, 155c88da2c9SPhillip Lougher squashfs_i(dir)->dir_idx_offset, 156c88da2c9SPhillip Lougher squashfs_i(dir)->dir_idx_cnt, name, len); 157c88da2c9SPhillip Lougher 158c88da2c9SPhillip Lougher while (length < i_size_read(dir)) { 159c88da2c9SPhillip Lougher /* 160c88da2c9SPhillip Lougher * Read directory header. 161c88da2c9SPhillip Lougher */ 162c88da2c9SPhillip Lougher err = squashfs_read_metadata(dir->i_sb, &dirh, &block, 163c88da2c9SPhillip Lougher &offset, sizeof(dirh)); 164c88da2c9SPhillip Lougher if (err < 0) 165c88da2c9SPhillip Lougher goto read_failure; 166c88da2c9SPhillip Lougher 167c88da2c9SPhillip Lougher length += sizeof(dirh); 168c88da2c9SPhillip Lougher 169c88da2c9SPhillip Lougher dir_count = le32_to_cpu(dirh.count) + 1; 17044cff8a9SPhillip Lougher 1714826d83dSAjeet Yadav if (dir_count > SQUASHFS_DIR_COUNT) 17244cff8a9SPhillip Lougher goto data_error; 17344cff8a9SPhillip Lougher 174c88da2c9SPhillip Lougher while (dir_count--) { 175c88da2c9SPhillip Lougher /* 176c88da2c9SPhillip Lougher * Read directory entry. 177c88da2c9SPhillip Lougher */ 178c88da2c9SPhillip Lougher err = squashfs_read_metadata(dir->i_sb, dire, &block, 179c88da2c9SPhillip Lougher &offset, sizeof(*dire)); 180c88da2c9SPhillip Lougher if (err < 0) 181c88da2c9SPhillip Lougher goto read_failure; 182c88da2c9SPhillip Lougher 183c88da2c9SPhillip Lougher size = le16_to_cpu(dire->size) + 1; 184c88da2c9SPhillip Lougher 18544cff8a9SPhillip Lougher /* size should never be larger than SQUASHFS_NAME_LEN */ 18644cff8a9SPhillip Lougher if (size > SQUASHFS_NAME_LEN) 18744cff8a9SPhillip Lougher goto data_error; 18844cff8a9SPhillip Lougher 189c88da2c9SPhillip Lougher err = squashfs_read_metadata(dir->i_sb, dire->name, 190c88da2c9SPhillip Lougher &block, &offset, size); 191c88da2c9SPhillip Lougher if (err < 0) 192c88da2c9SPhillip Lougher goto read_failure; 193c88da2c9SPhillip Lougher 194c88da2c9SPhillip Lougher length += sizeof(*dire) + size; 195c88da2c9SPhillip Lougher 196c88da2c9SPhillip Lougher if (name[0] < dire->name[0]) 197c88da2c9SPhillip Lougher goto exit_lookup; 198c88da2c9SPhillip Lougher 199c88da2c9SPhillip Lougher if (len == size && !strncmp(name, dire->name, len)) { 200c88da2c9SPhillip Lougher unsigned int blk, off, ino_num; 201c88da2c9SPhillip Lougher long long ino; 202c88da2c9SPhillip Lougher blk = le32_to_cpu(dirh.start_block); 203c88da2c9SPhillip Lougher off = le16_to_cpu(dire->offset); 204c88da2c9SPhillip Lougher ino_num = le32_to_cpu(dirh.inode_number) + 205c88da2c9SPhillip Lougher (short) le16_to_cpu(dire->inode_number); 206c88da2c9SPhillip Lougher ino = SQUASHFS_MKINODE(blk, off); 207c88da2c9SPhillip Lougher 208c88da2c9SPhillip Lougher TRACE("calling squashfs_iget for directory " 209c88da2c9SPhillip Lougher "entry %s, inode %x:%x, %d\n", name, 210c88da2c9SPhillip Lougher blk, off, ino_num); 211c88da2c9SPhillip Lougher 212c88da2c9SPhillip Lougher inode = squashfs_iget(dir->i_sb, ino, ino_num); 213c88da2c9SPhillip Lougher goto exit_lookup; 214c88da2c9SPhillip Lougher } 215c88da2c9SPhillip Lougher } 216c88da2c9SPhillip Lougher } 217c88da2c9SPhillip Lougher 218c88da2c9SPhillip Lougher exit_lookup: 219c88da2c9SPhillip Lougher kfree(dire); 220c88da2c9SPhillip Lougher return d_splice_alias(inode, dentry); 221c88da2c9SPhillip Lougher 22244cff8a9SPhillip Lougher data_error: 22344cff8a9SPhillip Lougher err = -EIO; 22444cff8a9SPhillip Lougher 225c88da2c9SPhillip Lougher read_failure: 226c88da2c9SPhillip Lougher ERROR("Unable to read directory block [%llx:%x]\n", 227c88da2c9SPhillip Lougher squashfs_i(dir)->start + msblk->directory_table, 228c88da2c9SPhillip Lougher squashfs_i(dir)->offset); 229c88da2c9SPhillip Lougher failed: 230c88da2c9SPhillip Lougher kfree(dire); 231c88da2c9SPhillip Lougher return ERR_PTR(err); 232c88da2c9SPhillip Lougher } 233c88da2c9SPhillip Lougher 234c88da2c9SPhillip Lougher 235c88da2c9SPhillip Lougher const struct inode_operations squashfs_dir_inode_ops = { 23667f66cc6SPhillip Lougher .lookup = squashfs_lookup, 23767f66cc6SPhillip Lougher .listxattr = squashfs_listxattr 238c88da2c9SPhillip Lougher }; 239