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 #include <linux/fs.h>
0026 #include <linux/vfs.h>
0027 #include <linux/dcache.h>
0028 #include <linux/exportfs.h>
0029 #include <linux/slab.h>
0030
0031 #include "squashfs_fs.h"
0032 #include "squashfs_fs_sb.h"
0033 #include "squashfs_fs_i.h"
0034 #include "squashfs.h"
0035
0036
0037
0038
0039 static long long squashfs_inode_lookup(struct super_block *sb, int ino_num)
0040 {
0041 struct squashfs_sb_info *msblk = sb->s_fs_info;
0042 int blk = SQUASHFS_LOOKUP_BLOCK(ino_num - 1);
0043 int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino_num - 1);
0044 u64 start;
0045 __le64 ino;
0046 int err;
0047
0048 TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino_num);
0049
0050 if (ino_num == 0 || (ino_num - 1) >= msblk->inodes)
0051 return -EINVAL;
0052
0053 start = le64_to_cpu(msblk->inode_lookup_table[blk]);
0054
0055 err = squashfs_read_metadata(sb, &ino, &start, &offset, sizeof(ino));
0056 if (err < 0)
0057 return err;
0058
0059 TRACE("squashfs_inode_lookup, inode = 0x%llx\n",
0060 (u64) le64_to_cpu(ino));
0061
0062 return le64_to_cpu(ino);
0063 }
0064
0065
0066 static struct dentry *squashfs_export_iget(struct super_block *sb,
0067 unsigned int ino_num)
0068 {
0069 long long ino;
0070 struct dentry *dentry = ERR_PTR(-ENOENT);
0071
0072 TRACE("Entered squashfs_export_iget\n");
0073
0074 ino = squashfs_inode_lookup(sb, ino_num);
0075 if (ino >= 0)
0076 dentry = d_obtain_alias(squashfs_iget(sb, ino, ino_num));
0077
0078 return dentry;
0079 }
0080
0081
0082 static struct dentry *squashfs_fh_to_dentry(struct super_block *sb,
0083 struct fid *fid, int fh_len, int fh_type)
0084 {
0085 if ((fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT)
0086 || fh_len < 2)
0087 return NULL;
0088
0089 return squashfs_export_iget(sb, fid->i32.ino);
0090 }
0091
0092
0093 static struct dentry *squashfs_fh_to_parent(struct super_block *sb,
0094 struct fid *fid, int fh_len, int fh_type)
0095 {
0096 if (fh_type != FILEID_INO32_GEN_PARENT || fh_len < 4)
0097 return NULL;
0098
0099 return squashfs_export_iget(sb, fid->i32.parent_ino);
0100 }
0101
0102
0103 static struct dentry *squashfs_get_parent(struct dentry *child)
0104 {
0105 struct inode *inode = d_inode(child);
0106 unsigned int parent_ino = squashfs_i(inode)->parent;
0107
0108 return squashfs_export_iget(inode->i_sb, parent_ino);
0109 }
0110
0111
0112
0113
0114
0115 __le64 *squashfs_read_inode_lookup_table(struct super_block *sb,
0116 u64 lookup_table_start, u64 next_table, unsigned int inodes)
0117 {
0118 unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes);
0119 unsigned int indexes = SQUASHFS_LOOKUP_BLOCKS(inodes);
0120 int n;
0121 __le64 *table;
0122 u64 start, end;
0123
0124 TRACE("In read_inode_lookup_table, length %d\n", length);
0125
0126
0127
0128
0129 if (inodes == 0)
0130 return ERR_PTR(-EINVAL);
0131
0132
0133
0134
0135
0136 if (length != (next_table - lookup_table_start))
0137 return ERR_PTR(-EINVAL);
0138
0139 table = squashfs_read_table(sb, lookup_table_start, length);
0140 if (IS_ERR(table))
0141 return table;
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151 for (n = 0; n < (indexes - 1); n++) {
0152 start = le64_to_cpu(table[n]);
0153 end = le64_to_cpu(table[n + 1]);
0154
0155 if (start >= end
0156 || (end - start) >
0157 (SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) {
0158 kfree(table);
0159 return ERR_PTR(-EINVAL);
0160 }
0161 }
0162
0163 start = le64_to_cpu(table[indexes - 1]);
0164 if (start >= lookup_table_start ||
0165 (lookup_table_start - start) >
0166 (SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) {
0167 kfree(table);
0168 return ERR_PTR(-EINVAL);
0169 }
0170
0171 return table;
0172 }
0173
0174
0175 const struct export_operations squashfs_export_ops = {
0176 .fh_to_dentry = squashfs_fh_to_dentry,
0177 .fh_to_parent = squashfs_fh_to_parent,
0178 .get_parent = squashfs_get_parent
0179 };