aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/udf/namei.c')
-rw-r--r--fs/udf/namei.c140
1 files changed, 138 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,