staticinlineint compare_attr(conststruct ATTRIB *left, enum ATTR_TYPE type, const __le16 *name, u8 name_len, const u16 *upcase)
{ /* First, compare the type codes. */ int diff = le32_to_cpu(left->type) - le32_to_cpu(type);
if (diff) return diff;
/* They have the same type code, so we have to compare the names. */ return ntfs_cmp_names(attr_name(left), left->name_len, name, name_len,
upcase, true);
}
/* * mi_new_attt_id * * Return: Unused attribute id that is less than mrec->next_attr_id.
*/ static __le16 mi_new_attt_id(struct ntfs_inode *ni, struct mft_inode *mi)
{
u16 free_id, max_id, t16; struct MFT_REC *rec = mi->mrec; struct ATTRIB *attr;
__le16 id;
id = rec->next_attr_id;
free_id = le16_to_cpu(id); if (free_id < 0x7FFF) {
rec->next_attr_id = cpu_to_le16(free_id + 1); return id;
}
/* One record can store up to 1024/24 ~= 42 attributes. */
free_id = 0;
max_id = 0;
/* * mi_enum_attr - start/continue attributes enumeration in record. * * NOTE: mi->mrec - memory of size sbi->record_size * here we sure that mi->mrec->total == sbi->record_size (see mi_read)
*/ struct ATTRIB *mi_enum_attr(struct ntfs_inode *ni, struct mft_inode *mi, struct ATTRIB *attr)
{ conststruct MFT_REC *rec = mi->mrec;
u32 used = le32_to_cpu(rec->used);
u32 t32, off, asize, prev_type;
u16 t16;
u64 data_size, alloc_size, tot_size;
if (!attr) {
u32 total = le32_to_cpu(rec->total);
off = le16_to_cpu(rec->attr_off);
if (used > total) goto out;
if (off >= used || off < MFTRECORD_FIXUP_OFFSET_1 ||
!IS_ALIGNED(off, 8)) { goto out;
}
/* Skip non-resident records. */ if (!is_rec_inuse(rec)) return NULL;
prev_type = 0;
attr = Add2Ptr(rec, off);
} else { /* * We don't need to check previous attr here. There is * a bounds checking in the previous round.
*/
off = PtrOffset(rec, attr);
/* * Can we use the first fields: * attr->type, * attr->size
*/ if (off + 8 > used) {
static_assert(ALIGN(sizeof(enum ATTR_TYPE), 8) == 8); goto out;
}
if (attr->type == ATTR_END) { /* End of enumeration. */ return NULL;
}
/* 0x100 is last known attribute for now. */
t32 = le32_to_cpu(attr->type); if (!t32 || (t32 & 0xf) || (t32 > 0x100)) goto out;
/* attributes in record must be ordered by type */ if (t32 < prev_type) goto out;
asize = le32_to_cpu(attr->size);
if (!IS_ALIGNED(asize, 8)) goto out;
/* Check overflow and boundary. */ if (off + asize < off || off + asize > used) goto out;
/* Can we use the field attr->non_res. */ if (off + 9 > used) goto out;
/* Check size of attribute. */ if (!attr->non_res) { /* Check resident fields. */ if (asize < SIZEOF_RESIDENT) goto out;
t16 = le16_to_cpu(attr->res.data_off); if (t16 > asize) goto out;
if (le32_to_cpu(attr->res.data_size) > asize - t16) goto out;
data_size = le64_to_cpu(attr->nres.data_size); if (le64_to_cpu(attr->nres.valid_size) > data_size) goto out;
alloc_size = le64_to_cpu(attr->nres.alloc_size); if (data_size > alloc_size) goto out;
t32 = mi->sbi->cluster_mask; if (alloc_size & t32) goto out;
if (!attr->nres.svcn && is_attr_ext(attr)) { /* First segment of sparse/compressed attribute */ /* Can we use memory including attr->nres.total_size? */ if (asize < SIZEOF_NONRESIDENT_EX) goto out;
tot_size = le64_to_cpu(attr->nres.total_size); if (tot_size & t32) goto out;
if (tot_size > alloc_size) goto out;
} else { if (attr->nres.c_unit) goto out;
if (alloc_size > mi->sbi->volume.size) goto out;
}
/* * mi_insert_attr - Reserve space for new attribute. * * Return: Not full constructed attribute or NULL if not possible to create.
*/ struct ATTRIB *mi_insert_attr(struct ntfs_inode *ni, struct mft_inode *mi, enum ATTR_TYPE type, const __le16 *name,
u8 name_len, u32 asize, u16 name_off)
{
size_t tail; struct ATTRIB *attr;
__le16 id; struct MFT_REC *rec = mi->mrec; struct ntfs_sb_info *sbi = mi->sbi;
u32 used = le32_to_cpu(rec->used); const u16 *upcase = sbi->upcase;
/* Can we insert mi attribute? */ if (used + asize > sbi->record_size) return NULL;
/* * Scan through the list of attributes to find the point * at which we should insert it.
*/
attr = NULL; while ((attr = mi_enum_attr(ni, mi, attr))) { int diff = compare_attr(attr, type, name, name_len, upcase);
if (diff < 0) continue;
if (!diff && !is_attr_indexed(attr)) return NULL; break;
}
if (!attr) { /* Append. */
tail = 8;
attr = Add2Ptr(rec, used - 8);
} else { /* Insert before 'attr'. */
tail = used - PtrOffset(rec, attr);
}
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.