0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <linux/fs.h>
0043 #include <linux/vfs.h>
0044 #include <linux/slab.h>
0045 #include <linux/string.h>
0046 #include <linux/dcache.h>
0047 #include <linux/xattr.h>
0048
0049 #include "squashfs_fs.h"
0050 #include "squashfs_fs_sb.h"
0051 #include "squashfs_fs_i.h"
0052 #include "squashfs.h"
0053 #include "xattr.h"
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 static int get_dir_index_using_name(struct super_block *sb,
0064 u64 *next_block, int *next_offset, u64 index_start,
0065 int index_offset, int i_count, const char *name,
0066 int len)
0067 {
0068 struct squashfs_sb_info *msblk = sb->s_fs_info;
0069 int i, length = 0, err;
0070 unsigned int size;
0071 struct squashfs_dir_index *index;
0072 char *str;
0073
0074 TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
0075
0076 index = kmalloc(sizeof(*index) + SQUASHFS_NAME_LEN * 2 + 2, GFP_KERNEL);
0077 if (index == NULL) {
0078 ERROR("Failed to allocate squashfs_dir_index\n");
0079 goto out;
0080 }
0081
0082 str = &index->name[SQUASHFS_NAME_LEN + 1];
0083 strncpy(str, name, len);
0084 str[len] = '\0';
0085
0086 for (i = 0; i < i_count; i++) {
0087 err = squashfs_read_metadata(sb, index, &index_start,
0088 &index_offset, sizeof(*index));
0089 if (err < 0)
0090 break;
0091
0092
0093 size = le32_to_cpu(index->size) + 1;
0094 if (size > SQUASHFS_NAME_LEN)
0095 break;
0096
0097 err = squashfs_read_metadata(sb, index->name, &index_start,
0098 &index_offset, size);
0099 if (err < 0)
0100 break;
0101
0102 index->name[size] = '\0';
0103
0104 if (strcmp(index->name, str) > 0)
0105 break;
0106
0107 length = le32_to_cpu(index->index);
0108 *next_block = le32_to_cpu(index->start_block) +
0109 msblk->directory_table;
0110 }
0111
0112 *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
0113 kfree(index);
0114
0115 out:
0116
0117
0118
0119
0120
0121
0122 return length + 3;
0123 }
0124
0125
0126 static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
0127 unsigned int flags)
0128 {
0129 const unsigned char *name = dentry->d_name.name;
0130 int len = dentry->d_name.len;
0131 struct inode *inode = NULL;
0132 struct squashfs_sb_info *msblk = dir->i_sb->s_fs_info;
0133 struct squashfs_dir_header dirh;
0134 struct squashfs_dir_entry *dire;
0135 u64 block = squashfs_i(dir)->start + msblk->directory_table;
0136 int offset = squashfs_i(dir)->offset;
0137 int err, length;
0138 unsigned int dir_count, size;
0139
0140 TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset);
0141
0142 dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
0143 if (dire == NULL) {
0144 ERROR("Failed to allocate squashfs_dir_entry\n");
0145 return ERR_PTR(-ENOMEM);
0146 }
0147
0148 if (len > SQUASHFS_NAME_LEN) {
0149 err = -ENAMETOOLONG;
0150 goto failed;
0151 }
0152
0153 length = get_dir_index_using_name(dir->i_sb, &block, &offset,
0154 squashfs_i(dir)->dir_idx_start,
0155 squashfs_i(dir)->dir_idx_offset,
0156 squashfs_i(dir)->dir_idx_cnt, name, len);
0157
0158 while (length < i_size_read(dir)) {
0159
0160
0161
0162 err = squashfs_read_metadata(dir->i_sb, &dirh, &block,
0163 &offset, sizeof(dirh));
0164 if (err < 0)
0165 goto read_failure;
0166
0167 length += sizeof(dirh);
0168
0169 dir_count = le32_to_cpu(dirh.count) + 1;
0170
0171 if (dir_count > SQUASHFS_DIR_COUNT)
0172 goto data_error;
0173
0174 while (dir_count--) {
0175
0176
0177
0178 err = squashfs_read_metadata(dir->i_sb, dire, &block,
0179 &offset, sizeof(*dire));
0180 if (err < 0)
0181 goto read_failure;
0182
0183 size = le16_to_cpu(dire->size) + 1;
0184
0185
0186 if (size > SQUASHFS_NAME_LEN)
0187 goto data_error;
0188
0189 err = squashfs_read_metadata(dir->i_sb, dire->name,
0190 &block, &offset, size);
0191 if (err < 0)
0192 goto read_failure;
0193
0194 length += sizeof(*dire) + size;
0195
0196 if (name[0] < dire->name[0])
0197 goto exit_lookup;
0198
0199 if (len == size && !strncmp(name, dire->name, len)) {
0200 unsigned int blk, off, ino_num;
0201 long long ino;
0202 blk = le32_to_cpu(dirh.start_block);
0203 off = le16_to_cpu(dire->offset);
0204 ino_num = le32_to_cpu(dirh.inode_number) +
0205 (short) le16_to_cpu(dire->inode_number);
0206 ino = SQUASHFS_MKINODE(blk, off);
0207
0208 TRACE("calling squashfs_iget for directory "
0209 "entry %s, inode %x:%x, %d\n", name,
0210 blk, off, ino_num);
0211
0212 inode = squashfs_iget(dir->i_sb, ino, ino_num);
0213 goto exit_lookup;
0214 }
0215 }
0216 }
0217
0218 exit_lookup:
0219 kfree(dire);
0220 return d_splice_alias(inode, dentry);
0221
0222 data_error:
0223 err = -EIO;
0224
0225 read_failure:
0226 ERROR("Unable to read directory block [%llx:%x]\n",
0227 squashfs_i(dir)->start + msblk->directory_table,
0228 squashfs_i(dir)->offset);
0229 failed:
0230 kfree(dire);
0231 return ERR_PTR(err);
0232 }
0233
0234
0235 const struct inode_operations squashfs_dir_inode_ops = {
0236 .lookup = squashfs_lookup,
0237 .listxattr = squashfs_listxattr
0238 };