aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf
diff options
context:
space:
mode:
Diffstat (limited to 'fs/udf')
-rw-r--r--fs/udf/namei.c140
-rw-r--r--fs/udf/super.c1
-rw-r--r--fs/udf/udfdecl.h1
3 files changed, 140 insertions, 2 deletions
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index ba5537d4bc15..47a6589e10b5 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -32,6 +32,7 @@
32#include <linux/buffer_head.h> 32#include <linux/buffer_head.h>
33#include <linux/sched.h> 33#include <linux/sched.h>
34#include <linux/crc-itu-t.h> 34#include <linux/crc-itu-t.h>
35#include <linux/exportfs.h>
35 36
36static inline int udf_match(int len1, const char *name1, int len2, 37static inline int udf_match(int len1, const char *name1, int len2,
37 const char *name2) 38 const char *name2)
@@ -158,6 +159,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
158 sector_t offset; 159 sector_t offset;
159 struct extent_position epos = {}; 160 struct extent_position epos = {};
160 struct udf_inode_info *dinfo = UDF_I(dir); 161 struct udf_inode_info *dinfo = UDF_I(dir);
162 int isdotdot = dentry->d_name.len == 2 &&
163 dentry->d_name.name[0] == '.' && dentry->d_name.name[1] == '.';
161 164
162 size = udf_ext0_offset(dir) + dir->i_size; 165 size = udf_ext0_offset(dir) + dir->i_size;
163 f_pos = udf_ext0_offset(dir); 166 f_pos = udf_ext0_offset(dir);
@@ -225,6 +228,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
225 continue; 228 continue;
226 } 229 }
227 230
231 if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) &&
232 isdotdot) {
233 brelse(epos.bh);
234 return fi;
235 }
236
228 if (!lfi) 237 if (!lfi)
229 continue; 238 continue;
230 239
@@ -286,9 +295,8 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
286 } 295 }
287 } 296 }
288 unlock_kernel(); 297 unlock_kernel();
289 d_add(dentry, inode);
290 298
291 return NULL; 299 return d_splice_alias(inode, dentry);
292} 300}
293 301
294static struct fileIdentDesc *udf_add_entry(struct inode *dir, 302static struct fileIdentDesc *udf_add_entry(struct inode *dir,
@@ -1232,6 +1240,134 @@ end_rename:
1232 return retval; 1240 return retval;
1233} 1241}
1234 1242
1243static struct dentry *udf_get_parent(struct dentry *child)
1244{
1245 struct dentry *parent;
1246 struct inode *inode = NULL;
1247 struct dentry dotdot;
1248 struct fileIdentDesc cfi;
1249 struct udf_fileident_bh fibh;
1250
1251 dotdot.d_name.name = "..";
1252 dotdot.d_name.len = 2;
1253
1254 lock_kernel();
1255 if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi))
1256 goto out_unlock;
1257
1258 if (fibh.sbh != fibh.ebh)
1259 brelse(fibh.ebh);
1260 brelse(fibh.sbh);
1261
1262 inode = udf_iget(child->d_inode->i_sb,
1263 lelb_to_cpu(cfi.icb.extLocation));
1264 if (!inode)
1265 goto out_unlock;
1266 unlock_kernel();
1267
1268 parent = d_alloc_anon(inode);
1269 if (!parent) {
1270 iput(inode);
1271 parent = ERR_PTR(-ENOMEM);
1272 }
1273
1274 return parent;
1275out_unlock:
1276 unlock_kernel();
1277 return ERR_PTR(-EACCES);
1278}
1279
1280
1281static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
1282 u16 partref, __u32 generation)
1283{
1284 struct inode *inode;
1285 struct dentry *result;
1286 kernel_lb_addr loc;
1287
1288 if (block == 0)
1289 return ERR_PTR(-ESTALE);
1290
1291 loc.logicalBlockNum = block;
1292 loc.partitionReferenceNum = partref;
1293 inode = udf_iget(sb, loc);
1294
1295 if (inode == NULL)
1296 return ERR_PTR(-ENOMEM);
1297
1298 if (generation && inode->i_generation != generation) {
1299 iput(inode);
1300 return ERR_PTR(-ESTALE);
1301 }
1302 result = d_alloc_anon(inode);
1303 if (!result) {
1304 iput(inode);
1305 return ERR_PTR(-ENOMEM);
1306 }
1307 return result;
1308}
1309
1310static struct dentry *udf_fh_to_dentry(struct super_block *sb,
1311 struct fid *fid, int fh_len, int fh_type)
1312{
1313 if ((fh_len != 3 && fh_len != 5) ||
1314 (fh_type != FILEID_UDF_WITH_PARENT &&
1315 fh_type != FILEID_UDF_WITHOUT_PARENT))
1316 return NULL;
1317
1318 return udf_nfs_get_inode(sb, fid->udf.block, fid->udf.partref,
1319 fid->udf.generation);
1320}
1321
1322static struct dentry *udf_fh_to_parent(struct super_block *sb,
1323 struct fid *fid, int fh_len, int fh_type)
1324{
1325 if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT)
1326 return NULL;
1327
1328 return udf_nfs_get_inode(sb, fid->udf.parent_block,
1329 fid->udf.parent_partref,
1330 fid->udf.parent_generation);
1331}
1332static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
1333 int connectable)
1334{
1335 int len = *lenp;
1336 struct inode *inode = de->d_inode;
1337 kernel_lb_addr location = UDF_I(inode)->i_location;
1338 struct fid *fid = (struct fid *)fh;
1339 int type = FILEID_UDF_WITHOUT_PARENT;
1340
1341 if (len < 3 || (connectable && len < 5))
1342 return 255;
1343
1344 *lenp = 3;
1345 fid->udf.block = location.logicalBlockNum;
1346 fid->udf.partref = location.partitionReferenceNum;
1347 fid->udf.generation = inode->i_generation;
1348
1349 if (connectable && !S_ISDIR(inode->i_mode)) {
1350 spin_lock(&de->d_lock);
1351 inode = de->d_parent->d_inode;
1352 location = UDF_I(inode)->i_location;
1353 fid->udf.parent_block = location.logicalBlockNum;
1354 fid->udf.parent_partref = location.partitionReferenceNum;
1355 fid->udf.parent_generation = inode->i_generation;
1356 spin_unlock(&de->d_lock);
1357 *lenp = 5;
1358 type = FILEID_UDF_WITH_PARENT;
1359 }
1360
1361 return type;
1362}
1363
1364const struct export_operations udf_export_ops = {
1365 .encode_fh = udf_encode_fh,
1366 .fh_to_dentry = udf_fh_to_dentry,
1367 .fh_to_parent = udf_fh_to_parent,
1368 .get_parent = udf_get_parent,
1369};
1370
1235const struct inode_operations udf_dir_inode_operations = { 1371const struct inode_operations udf_dir_inode_operations = {
1236 .lookup = udf_lookup, 1372 .lookup = udf_lookup,
1237 .create = udf_create, 1373 .create = udf_create,
diff --git a/fs/udf/super.c b/fs/udf/super.c
index b564fc140fe4..260f4b82c799 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1933,6 +1933,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
1933 1933
1934 /* Fill in the rest of the superblock */ 1934 /* Fill in the rest of the superblock */
1935 sb->s_op = &udf_sb_ops; 1935 sb->s_op = &udf_sb_ops;
1936 sb->s_export_op = &udf_export_ops;
1936 sb->dq_op = NULL; 1937 sb->dq_op = NULL;
1937 sb->s_dirt = 0; 1938 sb->s_dirt = 0;
1938 sb->s_magic = UDF_SUPER_MAGIC; 1939 sb->s_magic = UDF_SUPER_MAGIC;
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index f3f45d029277..8fa9c2d70911 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -73,6 +73,7 @@ struct task_struct;
73struct buffer_head; 73struct buffer_head;
74struct super_block; 74struct super_block;
75 75
76extern const struct export_operations udf_export_ops;
76extern const struct inode_operations udf_dir_inode_operations; 77extern const struct inode_operations udf_dir_inode_operations;
77extern const struct file_operations udf_dir_operations; 78extern const struct file_operations udf_dir_operations;
78extern const struct inode_operations udf_file_inode_operations; 79extern const struct inode_operations udf_file_inode_operations;