udf: Implement adding of dir entries using new iteration code
Implement function udf_fiiter_add_entry() adding new directory entries using new directory iteration code. Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
parent
6ec01a8020
commit
f284480340
@ -413,6 +413,63 @@ void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse)
|
|||||||
inode_inc_iversion(iter->dir);
|
inode_inc_iversion(iter->dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen)
|
||||||
|
{
|
||||||
|
struct udf_inode_info *iinfo = UDF_I(iter->dir);
|
||||||
|
int diff = new_elen - iter->elen;
|
||||||
|
|
||||||
|
/* Skip update when we already went past the last extent */
|
||||||
|
if (!iter->elen)
|
||||||
|
return;
|
||||||
|
iter->elen = new_elen;
|
||||||
|
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
|
||||||
|
iter->epos.offset -= sizeof(struct short_ad);
|
||||||
|
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
|
||||||
|
iter->epos.offset -= sizeof(struct long_ad);
|
||||||
|
udf_write_aext(iter->dir, &iter->epos, &iter->eloc, iter->elen, 1);
|
||||||
|
iinfo->i_lenExtents += diff;
|
||||||
|
mark_inode_dirty(iter->dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append new block to directory. @iter is expected to point at EOF */
|
||||||
|
int udf_fiiter_append_blk(struct udf_fileident_iter *iter)
|
||||||
|
{
|
||||||
|
struct udf_inode_info *iinfo = UDF_I(iter->dir);
|
||||||
|
int blksize = 1 << iter->dir->i_blkbits;
|
||||||
|
struct buffer_head *bh;
|
||||||
|
sector_t block;
|
||||||
|
uint32_t old_elen = iter->elen;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Round up last extent in the file */
|
||||||
|
udf_fiiter_update_elen(iter, ALIGN(iter->elen, blksize));
|
||||||
|
|
||||||
|
/* Allocate new block and refresh mapping information */
|
||||||
|
block = iinfo->i_lenExtents >> iter->dir->i_blkbits;
|
||||||
|
bh = udf_bread(iter->dir, block, 1, &err);
|
||||||
|
if (!bh) {
|
||||||
|
udf_fiiter_update_elen(iter, old_elen);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen,
|
||||||
|
&iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) {
|
||||||
|
udf_err(iter->dir->i_sb,
|
||||||
|
"block %llu not allocated in directory (ino %lu)\n",
|
||||||
|
(unsigned long long)block, iter->dir->i_ino);
|
||||||
|
return -EFSCORRUPTED;
|
||||||
|
}
|
||||||
|
if (!(iter->pos & (blksize - 1))) {
|
||||||
|
brelse(iter->bh[0]);
|
||||||
|
iter->bh[0] = bh;
|
||||||
|
} else {
|
||||||
|
iter->bh[1] = bh;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
|
struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
|
||||||
struct udf_fileident_bh *fibh,
|
struct udf_fileident_bh *fibh,
|
||||||
struct fileIdentDesc *cfi,
|
struct fileIdentDesc *cfi,
|
||||||
|
110
fs/udf/namei.c
110
fs/udf/namei.c
@ -472,6 +472,116 @@ static struct buffer_head *udf_expand_dir_adinicb(struct inode *inode,
|
|||||||
return dbh;
|
return dbh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int udf_fiiter_add_entry(struct inode *dir, struct dentry *dentry,
|
||||||
|
struct udf_fileident_iter *iter)
|
||||||
|
{
|
||||||
|
struct udf_inode_info *dinfo = UDF_I(dir);
|
||||||
|
int nfidlen, namelen = 0;
|
||||||
|
int ret;
|
||||||
|
int off, blksize = 1 << dir->i_blkbits;
|
||||||
|
udf_pblk_t block;
|
||||||
|
char name[UDF_NAME_LEN_CS0];
|
||||||
|
|
||||||
|
if (dentry) {
|
||||||
|
if (!dentry->d_name.len)
|
||||||
|
return -EINVAL;
|
||||||
|
namelen = udf_put_filename(dir->i_sb, dentry->d_name.name,
|
||||||
|
dentry->d_name.len,
|
||||||
|
name, UDF_NAME_LEN_CS0);
|
||||||
|
if (!namelen)
|
||||||
|
return -ENAMETOOLONG;
|
||||||
|
}
|
||||||
|
nfidlen = ALIGN(sizeof(struct fileIdentDesc) + namelen, UDF_NAME_PAD);
|
||||||
|
|
||||||
|
for (ret = udf_fiiter_init(iter, dir, 0);
|
||||||
|
!ret && iter->pos < dir->i_size;
|
||||||
|
ret = udf_fiiter_advance(iter)) {
|
||||||
|
if (iter->fi.fileCharacteristics & FID_FILE_CHAR_DELETED) {
|
||||||
|
if (udf_dir_entry_len(&iter->fi) == nfidlen) {
|
||||||
|
iter->fi.descTag.tagSerialNum = cpu_to_le16(1);
|
||||||
|
iter->fi.fileVersionNum = cpu_to_le16(1);
|
||||||
|
iter->fi.fileCharacteristics = 0;
|
||||||
|
iter->fi.lengthFileIdent = namelen;
|
||||||
|
iter->fi.lengthOfImpUse = cpu_to_le16(0);
|
||||||
|
memcpy(iter->namebuf, name, namelen);
|
||||||
|
iter->name = iter->namebuf;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
udf_fiiter_release(iter);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
|
||||||
|
blksize - udf_ext0_offset(dir) - iter->pos < nfidlen) {
|
||||||
|
struct buffer_head *retbh;
|
||||||
|
|
||||||
|
udf_fiiter_release(iter);
|
||||||
|
/*
|
||||||
|
* FIXME: udf_expand_dir_adinicb does not need to return bh
|
||||||
|
* once other users are gone
|
||||||
|
*/
|
||||||
|
retbh = udf_expand_dir_adinicb(dir, &block, &ret);
|
||||||
|
if (!retbh)
|
||||||
|
return ret;
|
||||||
|
brelse(retbh);
|
||||||
|
ret = udf_fiiter_init(iter, dir, dir->i_size);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get blocknumber to use for entry tag */
|
||||||
|
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
|
||||||
|
block = dinfo->i_location.logicalBlockNum;
|
||||||
|
} else {
|
||||||
|
block = iter->eloc.logicalBlockNum +
|
||||||
|
((iter->elen - 1) >> dir->i_blkbits);
|
||||||
|
}
|
||||||
|
off = iter->pos & (blksize - 1);
|
||||||
|
if (!off)
|
||||||
|
off = blksize;
|
||||||
|
/* Entry fits into current block? */
|
||||||
|
if (blksize - udf_ext0_offset(dir) - off >= nfidlen)
|
||||||
|
goto store_fi;
|
||||||
|
|
||||||
|
ret = udf_fiiter_append_blk(iter);
|
||||||
|
if (ret) {
|
||||||
|
udf_fiiter_release(iter);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Entry will be completely in the new block? Update tag location... */
|
||||||
|
if (!(iter->pos & (blksize - 1)))
|
||||||
|
block = iter->eloc.logicalBlockNum +
|
||||||
|
((iter->elen - 1) >> dir->i_blkbits);
|
||||||
|
store_fi:
|
||||||
|
memset(&iter->fi, 0, sizeof(struct fileIdentDesc));
|
||||||
|
if (UDF_SB(dir->i_sb)->s_udfrev >= 0x0200)
|
||||||
|
udf_new_tag((char *)(&iter->fi), TAG_IDENT_FID, 3, 1, block,
|
||||||
|
sizeof(struct tag));
|
||||||
|
else
|
||||||
|
udf_new_tag((char *)(&iter->fi), TAG_IDENT_FID, 2, 1, block,
|
||||||
|
sizeof(struct tag));
|
||||||
|
iter->fi.fileVersionNum = cpu_to_le16(1);
|
||||||
|
iter->fi.lengthFileIdent = namelen;
|
||||||
|
iter->fi.lengthOfImpUse = cpu_to_le16(0);
|
||||||
|
memcpy(iter->namebuf, name, namelen);
|
||||||
|
iter->name = iter->namebuf;
|
||||||
|
|
||||||
|
dir->i_size += nfidlen;
|
||||||
|
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
|
||||||
|
dinfo->i_lenAlloc += nfidlen;
|
||||||
|
} else {
|
||||||
|
/* Truncate last extent to proper size */
|
||||||
|
udf_fiiter_update_elen(iter, iter->elen -
|
||||||
|
(dinfo->i_lenExtents - dir->i_size));
|
||||||
|
}
|
||||||
|
mark_inode_dirty(dir);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct fileIdentDesc *udf_add_entry(struct inode *dir,
|
static struct fileIdentDesc *udf_add_entry(struct inode *dir,
|
||||||
struct dentry *dentry,
|
struct dentry *dentry,
|
||||||
struct udf_fileident_bh *fibh,
|
struct udf_fileident_bh *fibh,
|
||||||
|
@ -264,6 +264,8 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
|
|||||||
int udf_fiiter_advance(struct udf_fileident_iter *iter);
|
int udf_fiiter_advance(struct udf_fileident_iter *iter);
|
||||||
void udf_fiiter_release(struct udf_fileident_iter *iter);
|
void udf_fiiter_release(struct udf_fileident_iter *iter);
|
||||||
void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse);
|
void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse);
|
||||||
|
void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen);
|
||||||
|
int udf_fiiter_append_blk(struct udf_fileident_iter *iter);
|
||||||
extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
|
extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
|
||||||
struct udf_fileident_bh *,
|
struct udf_fileident_bh *,
|
||||||
struct fileIdentDesc *,
|
struct fileIdentDesc *,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user