diff options
Diffstat (limited to 'fs/udf/namei.c')
-rw-r--r-- | fs/udf/namei.c | 140 |
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 | ||
36 | static inline int udf_match(int len1, const char *name1, int len2, | 37 | static 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 | ||
294 | static struct fileIdentDesc *udf_add_entry(struct inode *dir, | 302 | static struct fileIdentDesc *udf_add_entry(struct inode *dir, |
@@ -1232,6 +1240,134 @@ end_rename: | |||
1232 | return retval; | 1240 | return retval; |
1233 | } | 1241 | } |
1234 | 1242 | ||
1243 | static 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; | ||
1275 | out_unlock: | ||
1276 | unlock_kernel(); | ||
1277 | return ERR_PTR(-EACCES); | ||
1278 | } | ||
1279 | |||
1280 | |||
1281 | static 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 | |||
1310 | static 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 | |||
1322 | static 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 | } | ||
1332 | static 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 | |||
1364 | const 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 | |||
1235 | const struct inode_operations udf_dir_inode_operations = { | 1371 | const struct inode_operations udf_dir_inode_operations = { |
1236 | .lookup = udf_lookup, | 1372 | .lookup = udf_lookup, |
1237 | .create = udf_create, | 1373 | .create = udf_create, |