if (iter->fi.descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) {
udf_err(iter->dir->i_sb, "directory (ino %lu) has entry at pos %llu with incorrect tag %x\n",
iter->dir->i_ino, (unsignedlonglong)iter->pos,
le16_to_cpu(iter->fi.descTag.tagIdent)); return -EFSCORRUPTED;
}
len = udf_dir_entry_len(&iter->fi); if (le16_to_cpu(iter->fi.lengthOfImpUse) & 3) {
udf_err(iter->dir->i_sb, "directory (ino %lu) has entry at pos %llu with unaligned length of impUse field\n",
iter->dir->i_ino, (unsignedlonglong)iter->pos); return -EFSCORRUPTED;
} /* * This is in fact allowed by the spec due to long impUse field but * we don't support it. If there is real media with this large impUse * field, support can be added.
*/ if (len > 1 << iter->dir->i_blkbits) {
udf_err(iter->dir->i_sb, "directory (ino %lu) has too big (%u) entry at pos %llu\n",
iter->dir->i_ino, len, (unsignedlonglong)iter->pos); return -EFSCORRUPTED;
} if (iter->pos + len > iter->dir->i_size) {
udf_err(iter->dir->i_sb, "directory (ino %lu) has entry past directory size at pos %llu\n",
iter->dir->i_ino, (unsignedlonglong)iter->pos); return -EFSCORRUPTED;
} if (udf_dir_entry_len(&iter->fi) != sizeof(struct tag) + le16_to_cpu(iter->fi.descTag.descCRCLength)) {
udf_err(iter->dir->i_sb, "directory (ino %lu) has entry where CRC length (%u) does not match entry length (%u)\n",
iter->dir->i_ino,
(unsigned)le16_to_cpu(iter->fi.descTag.descCRCLength),
(unsigned)(udf_dir_entry_len(&iter->fi) - sizeof(struct tag))); return -EFSCORRUPTED;
} return 0;
}
/* * Updates loffset to point to next directory block; eloc, elen & epos are * updated if we need to traverse to the next extent as well.
*/ staticint udf_fiiter_advance_blk(struct udf_fileident_iter *iter)
{
int8_t etype = -1; int err = 0;
iter->loffset++; if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits)) return 0;
iter->loffset = 0;
err = udf_next_aext(iter->dir, &iter->epos, &iter->eloc,
&iter->elen, &etype, 1); if (err < 0) return err; elseif (err == 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) { if (iter->pos == iter->dir->i_size) {
iter->elen = 0; return 0;
}
udf_err(iter->dir->i_sb, "extent after position %llu not allocated in directory (ino %lu)\n",
(unsignedlonglong)iter->pos, iter->dir->i_ino); return -EFSCORRUPTED;
} return 0;
}
staticint udf_fiiter_load_bhs(struct udf_fileident_iter *iter)
{ int blksize = 1 << iter->dir->i_blkbits; int off = iter->pos & (blksize - 1); int err; struct fileIdentDesc *fi;
/* Is there any further extent we can map from? */ if (!iter->bh[0] && iter->elen) {
iter->bh[0] = udf_fiiter_bread_blk(iter); if (!iter->bh[0]) {
err = -ENOMEM; goto out_brelse;
} if (!buffer_uptodate(iter->bh[0])) {
err = -EIO; goto out_brelse;
}
} /* There's no next block so we are done */ if (iter->pos >= iter->dir->i_size) return 0; /* Need to fetch next block as well? */ if (off + sizeof(struct fileIdentDesc) > blksize) goto fetch_next;
fi = (struct fileIdentDesc *)(iter->bh[0]->b_data + off); /* Need to fetch next block to get name? */ if (off + udf_dir_entry_len(fi) > blksize) {
fetch_next:
err = udf_fiiter_advance_blk(iter); if (err) goto out_brelse;
iter->bh[1] = udf_fiiter_bread_blk(iter); if (!iter->bh[1]) {
err = -ENOMEM; goto out_brelse;
} if (!buffer_uptodate(iter->bh[1])) {
err = -EIO; goto out_brelse;
}
} return 0;
out_brelse:
brelse(iter->bh[0]);
brelse(iter->bh[1]);
iter->bh[0] = iter->bh[1] = NULL; return err;
}
iter->dir = dir;
iter->bh[0] = iter->bh[1] = NULL;
iter->pos = pos;
iter->elen = 0;
iter->epos.bh = NULL;
iter->name = NULL; /* * When directory is verified, we don't expect directory iteration to * fail and it can be difficult to undo without corrupting filesystem. * So just do not allow memory allocation failures here.
*/
iter->namebuf = kmalloc(UDF_NAME_LEN_CS0, GFP_KERNEL | __GFP_NOFAIL);
/* 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); elseif (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;
int8_t etype;
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));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.