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);
|
||||
}
|
||||
|
||||
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 udf_fileident_bh *fibh,
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
struct dentry *dentry,
|
||||
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);
|
||||
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_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 *,
|
||||
struct udf_fileident_bh *,
|
||||
struct fileIdentDesc *,
|
||||
|
|
Loading…
Reference in New Issue