|
@@ -51,7 +51,6 @@ MODULE_LICENSE("GPL");
|
|
|
|
|
|
static umode_t udf_convert_permissions(struct fileEntry *);
|
|
static umode_t udf_convert_permissions(struct fileEntry *);
|
|
static int udf_update_inode(struct inode *, int);
|
|
static int udf_update_inode(struct inode *, int);
|
|
-static void udf_fill_inode(struct inode *, struct buffer_head *);
|
|
|
|
static int udf_sync_inode(struct inode *inode);
|
|
static int udf_sync_inode(struct inode *inode);
|
|
static int udf_alloc_i_data(struct inode *inode, size_t size);
|
|
static int udf_alloc_i_data(struct inode *inode, size_t size);
|
|
static sector_t inode_getblk(struct inode *, sector_t, int *, int *);
|
|
static sector_t inode_getblk(struct inode *, sector_t, int *, int *);
|
|
@@ -1271,12 +1270,33 @@ update_time:
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void __udf_read_inode(struct inode *inode)
|
|
|
|
|
|
+/*
|
|
|
|
+ * Maximum length of linked list formed by ICB hierarchy. The chosen number is
|
|
|
|
+ * arbitrary - just that we hopefully don't limit any real use of rewritten
|
|
|
|
+ * inode on write-once media but avoid looping for too long on corrupted media.
|
|
|
|
+ */
|
|
|
|
+#define UDF_MAX_ICB_NESTING 1024
|
|
|
|
+
|
|
|
|
+static int udf_read_inode(struct inode *inode)
|
|
{
|
|
{
|
|
struct buffer_head *bh = NULL;
|
|
struct buffer_head *bh = NULL;
|
|
struct fileEntry *fe;
|
|
struct fileEntry *fe;
|
|
|
|
+ struct extendedFileEntry *efe;
|
|
uint16_t ident;
|
|
uint16_t ident;
|
|
struct udf_inode_info *iinfo = UDF_I(inode);
|
|
struct udf_inode_info *iinfo = UDF_I(inode);
|
|
|
|
+ struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
|
|
|
|
+ struct kernel_lb_addr *iloc = &iinfo->i_location;
|
|
|
|
+ unsigned int link_count;
|
|
|
|
+ unsigned int indirections = 0;
|
|
|
|
+ int ret = -EIO;
|
|
|
|
+
|
|
|
|
+reread:
|
|
|
|
+ if (iloc->logicalBlockNum >=
|
|
|
|
+ sbi->s_partmaps[iloc->partitionReferenceNum].s_partition_len) {
|
|
|
|
+ udf_debug("block=%d, partition=%d out of range\n",
|
|
|
|
+ iloc->logicalBlockNum, iloc->partitionReferenceNum);
|
|
|
|
+ return -EIO;
|
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
/*
|
|
* Set defaults, but the inode is still incomplete!
|
|
* Set defaults, but the inode is still incomplete!
|
|
@@ -1290,78 +1310,54 @@ static void __udf_read_inode(struct inode *inode)
|
|
* i_nlink = 1
|
|
* i_nlink = 1
|
|
* i_op = NULL;
|
|
* i_op = NULL;
|
|
*/
|
|
*/
|
|
- bh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 0, &ident);
|
|
|
|
|
|
+ bh = udf_read_ptagged(inode->i_sb, iloc, 0, &ident);
|
|
if (!bh) {
|
|
if (!bh) {
|
|
udf_err(inode->i_sb, "(ino %ld) failed !bh\n", inode->i_ino);
|
|
udf_err(inode->i_sb, "(ino %ld) failed !bh\n", inode->i_ino);
|
|
- make_bad_inode(inode);
|
|
|
|
- return;
|
|
|
|
|
|
+ return -EIO;
|
|
}
|
|
}
|
|
|
|
|
|
if (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE &&
|
|
if (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE &&
|
|
ident != TAG_IDENT_USE) {
|
|
ident != TAG_IDENT_USE) {
|
|
udf_err(inode->i_sb, "(ino %ld) failed ident=%d\n",
|
|
udf_err(inode->i_sb, "(ino %ld) failed ident=%d\n",
|
|
inode->i_ino, ident);
|
|
inode->i_ino, ident);
|
|
- brelse(bh);
|
|
|
|
- make_bad_inode(inode);
|
|
|
|
- return;
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
fe = (struct fileEntry *)bh->b_data;
|
|
fe = (struct fileEntry *)bh->b_data;
|
|
|
|
+ efe = (struct extendedFileEntry *)bh->b_data;
|
|
|
|
|
|
if (fe->icbTag.strategyType == cpu_to_le16(4096)) {
|
|
if (fe->icbTag.strategyType == cpu_to_le16(4096)) {
|
|
struct buffer_head *ibh;
|
|
struct buffer_head *ibh;
|
|
|
|
|
|
- ibh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 1,
|
|
|
|
- &ident);
|
|
|
|
|
|
+ ibh = udf_read_ptagged(inode->i_sb, iloc, 1, &ident);
|
|
if (ident == TAG_IDENT_IE && ibh) {
|
|
if (ident == TAG_IDENT_IE && ibh) {
|
|
- struct buffer_head *nbh = NULL;
|
|
|
|
struct kernel_lb_addr loc;
|
|
struct kernel_lb_addr loc;
|
|
struct indirectEntry *ie;
|
|
struct indirectEntry *ie;
|
|
|
|
|
|
ie = (struct indirectEntry *)ibh->b_data;
|
|
ie = (struct indirectEntry *)ibh->b_data;
|
|
loc = lelb_to_cpu(ie->indirectICB.extLocation);
|
|
loc = lelb_to_cpu(ie->indirectICB.extLocation);
|
|
|
|
|
|
- if (ie->indirectICB.extLength &&
|
|
|
|
- (nbh = udf_read_ptagged(inode->i_sb, &loc, 0,
|
|
|
|
- &ident))) {
|
|
|
|
- if (ident == TAG_IDENT_FE ||
|
|
|
|
- ident == TAG_IDENT_EFE) {
|
|
|
|
- memcpy(&iinfo->i_location,
|
|
|
|
- &loc,
|
|
|
|
- sizeof(struct kernel_lb_addr));
|
|
|
|
- brelse(bh);
|
|
|
|
- brelse(ibh);
|
|
|
|
- brelse(nbh);
|
|
|
|
- __udf_read_inode(inode);
|
|
|
|
- return;
|
|
|
|
|
|
+ if (ie->indirectICB.extLength) {
|
|
|
|
+ brelse(ibh);
|
|
|
|
+ memcpy(&iinfo->i_location, &loc,
|
|
|
|
+ sizeof(struct kernel_lb_addr));
|
|
|
|
+ if (++indirections > UDF_MAX_ICB_NESTING) {
|
|
|
|
+ udf_err(inode->i_sb,
|
|
|
|
+ "too many ICBs in ICB hierarchy"
|
|
|
|
+ " (max %d supported)\n",
|
|
|
|
+ UDF_MAX_ICB_NESTING);
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
- brelse(nbh);
|
|
|
|
|
|
+ brelse(bh);
|
|
|
|
+ goto reread;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
brelse(ibh);
|
|
brelse(ibh);
|
|
} else if (fe->icbTag.strategyType != cpu_to_le16(4)) {
|
|
} else if (fe->icbTag.strategyType != cpu_to_le16(4)) {
|
|
udf_err(inode->i_sb, "unsupported strategy type: %d\n",
|
|
udf_err(inode->i_sb, "unsupported strategy type: %d\n",
|
|
le16_to_cpu(fe->icbTag.strategyType));
|
|
le16_to_cpu(fe->icbTag.strategyType));
|
|
- brelse(bh);
|
|
|
|
- make_bad_inode(inode);
|
|
|
|
- return;
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
- udf_fill_inode(inode, bh);
|
|
|
|
-
|
|
|
|
- brelse(bh);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
|
|
|
|
-{
|
|
|
|
- struct fileEntry *fe;
|
|
|
|
- struct extendedFileEntry *efe;
|
|
|
|
- struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
|
|
|
|
- struct udf_inode_info *iinfo = UDF_I(inode);
|
|
|
|
- unsigned int link_count;
|
|
|
|
-
|
|
|
|
- fe = (struct fileEntry *)bh->b_data;
|
|
|
|
- efe = (struct extendedFileEntry *)bh->b_data;
|
|
|
|
-
|
|
|
|
if (fe->icbTag.strategyType == cpu_to_le16(4))
|
|
if (fe->icbTag.strategyType == cpu_to_le16(4))
|
|
iinfo->i_strat4096 = 0;
|
|
iinfo->i_strat4096 = 0;
|
|
else /* if (fe->icbTag.strategyType == cpu_to_le16(4096)) */
|
|
else /* if (fe->icbTag.strategyType == cpu_to_le16(4096)) */
|
|
@@ -1378,11 +1374,10 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
|
|
if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_EFE)) {
|
|
if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_EFE)) {
|
|
iinfo->i_efe = 1;
|
|
iinfo->i_efe = 1;
|
|
iinfo->i_use = 0;
|
|
iinfo->i_use = 0;
|
|
- if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize -
|
|
|
|
- sizeof(struct extendedFileEntry))) {
|
|
|
|
- make_bad_inode(inode);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ ret = udf_alloc_i_data(inode, inode->i_sb->s_blocksize -
|
|
|
|
+ sizeof(struct extendedFileEntry));
|
|
|
|
+ if (ret)
|
|
|
|
+ goto out;
|
|
memcpy(iinfo->i_ext.i_data,
|
|
memcpy(iinfo->i_ext.i_data,
|
|
bh->b_data + sizeof(struct extendedFileEntry),
|
|
bh->b_data + sizeof(struct extendedFileEntry),
|
|
inode->i_sb->s_blocksize -
|
|
inode->i_sb->s_blocksize -
|
|
@@ -1390,11 +1385,10 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
|
|
} else if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_FE)) {
|
|
} else if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_FE)) {
|
|
iinfo->i_efe = 0;
|
|
iinfo->i_efe = 0;
|
|
iinfo->i_use = 0;
|
|
iinfo->i_use = 0;
|
|
- if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize -
|
|
|
|
- sizeof(struct fileEntry))) {
|
|
|
|
- make_bad_inode(inode);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ ret = udf_alloc_i_data(inode, inode->i_sb->s_blocksize -
|
|
|
|
+ sizeof(struct fileEntry));
|
|
|
|
+ if (ret)
|
|
|
|
+ goto out;
|
|
memcpy(iinfo->i_ext.i_data,
|
|
memcpy(iinfo->i_ext.i_data,
|
|
bh->b_data + sizeof(struct fileEntry),
|
|
bh->b_data + sizeof(struct fileEntry),
|
|
inode->i_sb->s_blocksize - sizeof(struct fileEntry));
|
|
inode->i_sb->s_blocksize - sizeof(struct fileEntry));
|
|
@@ -1404,18 +1398,18 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
|
|
iinfo->i_lenAlloc = le32_to_cpu(
|
|
iinfo->i_lenAlloc = le32_to_cpu(
|
|
((struct unallocSpaceEntry *)bh->b_data)->
|
|
((struct unallocSpaceEntry *)bh->b_data)->
|
|
lengthAllocDescs);
|
|
lengthAllocDescs);
|
|
- if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize -
|
|
|
|
- sizeof(struct unallocSpaceEntry))) {
|
|
|
|
- make_bad_inode(inode);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ ret = udf_alloc_i_data(inode, inode->i_sb->s_blocksize -
|
|
|
|
+ sizeof(struct unallocSpaceEntry));
|
|
|
|
+ if (ret)
|
|
|
|
+ goto out;
|
|
memcpy(iinfo->i_ext.i_data,
|
|
memcpy(iinfo->i_ext.i_data,
|
|
bh->b_data + sizeof(struct unallocSpaceEntry),
|
|
bh->b_data + sizeof(struct unallocSpaceEntry),
|
|
inode->i_sb->s_blocksize -
|
|
inode->i_sb->s_blocksize -
|
|
sizeof(struct unallocSpaceEntry));
|
|
sizeof(struct unallocSpaceEntry));
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ ret = -EIO;
|
|
read_lock(&sbi->s_cred_lock);
|
|
read_lock(&sbi->s_cred_lock);
|
|
i_uid_write(inode, le32_to_cpu(fe->uid));
|
|
i_uid_write(inode, le32_to_cpu(fe->uid));
|
|
if (!uid_valid(inode->i_uid) ||
|
|
if (!uid_valid(inode->i_uid) ||
|
|
@@ -1441,8 +1435,10 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
|
|
read_unlock(&sbi->s_cred_lock);
|
|
read_unlock(&sbi->s_cred_lock);
|
|
|
|
|
|
link_count = le16_to_cpu(fe->fileLinkCount);
|
|
link_count = le16_to_cpu(fe->fileLinkCount);
|
|
- if (!link_count)
|
|
|
|
- link_count = 1;
|
|
|
|
|
|
+ if (!link_count) {
|
|
|
|
+ ret = -ESTALE;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
set_nlink(inode, link_count);
|
|
set_nlink(inode, link_count);
|
|
|
|
|
|
inode->i_size = le64_to_cpu(fe->informationLength);
|
|
inode->i_size = le64_to_cpu(fe->informationLength);
|
|
@@ -1488,6 +1484,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
|
|
iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs);
|
|
iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs);
|
|
iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint);
|
|
iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint);
|
|
}
|
|
}
|
|
|
|
+ inode->i_generation = iinfo->i_unique;
|
|
|
|
|
|
switch (fe->icbTag.fileType) {
|
|
switch (fe->icbTag.fileType) {
|
|
case ICBTAG_FILE_TYPE_DIRECTORY:
|
|
case ICBTAG_FILE_TYPE_DIRECTORY:
|
|
@@ -1537,8 +1534,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
|
|
default:
|
|
default:
|
|
udf_err(inode->i_sb, "(ino %ld) failed unknown file type=%d\n",
|
|
udf_err(inode->i_sb, "(ino %ld) failed unknown file type=%d\n",
|
|
inode->i_ino, fe->icbTag.fileType);
|
|
inode->i_ino, fe->icbTag.fileType);
|
|
- make_bad_inode(inode);
|
|
|
|
- return;
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
|
|
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
|
|
struct deviceSpec *dsea =
|
|
struct deviceSpec *dsea =
|
|
@@ -1549,8 +1545,12 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
|
|
le32_to_cpu(dsea->minorDeviceIdent)));
|
|
le32_to_cpu(dsea->minorDeviceIdent)));
|
|
/* Developer ID ??? */
|
|
/* Developer ID ??? */
|
|
} else
|
|
} else
|
|
- make_bad_inode(inode);
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
+ ret = 0;
|
|
|
|
+out:
|
|
|
|
+ brelse(bh);
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static int udf_alloc_i_data(struct inode *inode, size_t size)
|
|
static int udf_alloc_i_data(struct inode *inode, size_t size)
|
|
@@ -1664,7 +1664,7 @@ static int udf_update_inode(struct inode *inode, int do_sync)
|
|
FE_PERM_U_DELETE | FE_PERM_U_CHATTR));
|
|
FE_PERM_U_DELETE | FE_PERM_U_CHATTR));
|
|
fe->permissions = cpu_to_le32(udfperms);
|
|
fe->permissions = cpu_to_le32(udfperms);
|
|
|
|
|
|
- if (S_ISDIR(inode->i_mode))
|
|
|
|
|
|
+ if (S_ISDIR(inode->i_mode) && inode->i_nlink > 0)
|
|
fe->fileLinkCount = cpu_to_le16(inode->i_nlink - 1);
|
|
fe->fileLinkCount = cpu_to_le16(inode->i_nlink - 1);
|
|
else
|
|
else
|
|
fe->fileLinkCount = cpu_to_le16(inode->i_nlink);
|
|
fe->fileLinkCount = cpu_to_le16(inode->i_nlink);
|
|
@@ -1830,32 +1830,23 @@ struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)
|
|
{
|
|
{
|
|
unsigned long block = udf_get_lb_pblock(sb, ino, 0);
|
|
unsigned long block = udf_get_lb_pblock(sb, ino, 0);
|
|
struct inode *inode = iget_locked(sb, block);
|
|
struct inode *inode = iget_locked(sb, block);
|
|
|
|
+ int err;
|
|
|
|
|
|
if (!inode)
|
|
if (!inode)
|
|
- return NULL;
|
|
|
|
-
|
|
|
|
- if (inode->i_state & I_NEW) {
|
|
|
|
- memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr));
|
|
|
|
- __udf_read_inode(inode);
|
|
|
|
- unlock_new_inode(inode);
|
|
|
|
- }
|
|
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
- if (is_bad_inode(inode))
|
|
|
|
- goto out_iput;
|
|
|
|
|
|
+ if (!(inode->i_state & I_NEW))
|
|
|
|
+ return inode;
|
|
|
|
|
|
- if (ino->logicalBlockNum >= UDF_SB(sb)->
|
|
|
|
- s_partmaps[ino->partitionReferenceNum].s_partition_len) {
|
|
|
|
- udf_debug("block=%d, partition=%d out of range\n",
|
|
|
|
- ino->logicalBlockNum, ino->partitionReferenceNum);
|
|
|
|
- make_bad_inode(inode);
|
|
|
|
- goto out_iput;
|
|
|
|
|
|
+ memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr));
|
|
|
|
+ err = udf_read_inode(inode);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ iget_failed(inode);
|
|
|
|
+ return ERR_PTR(err);
|
|
}
|
|
}
|
|
|
|
+ unlock_new_inode(inode);
|
|
|
|
|
|
return inode;
|
|
return inode;
|
|
-
|
|
|
|
- out_iput:
|
|
|
|
- iput(inode);
|
|
|
|
- return NULL;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
int udf_add_aext(struct inode *inode, struct extent_position *epos,
|
|
int udf_add_aext(struct inode *inode, struct extent_position *epos,
|