/* * ntfs_load_attr_list * * This method makes sure that the ATTRIB list, if present, * has been properly set up.
*/ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
{ int err;
size_t lsize; void *le = NULL;
if (ni->attr_list.size) return 0;
if (!attr->non_res) {
lsize = le32_to_cpu(attr->res.data_size); /* attr is resident: lsize < record_size (1K or 4K) */
le = kvmalloc(al_aligned(lsize), GFP_KERNEL); if (!le) {
err = -ENOMEM; goto out;
}
memcpy(le, resident_data(attr), lsize);
} elseif (attr->nres.svcn) {
err = -EINVAL; goto out;
} else {
u16 run_off = le16_to_cpu(attr->nres.run_off);
/* attr is nonresident. * The worst case: * 1T (2^40) extremely fragmented file. * cluster = 4K (2^12) => 2^28 fragments * 2^9 fragments per one record => 2^19 records * 2^5 bytes of ATTR_LIST_ENTRY per one record => 2^24 bytes. * * the result is 16M bytes per attribute list. * Use kvmalloc to allocate in range [several Kbytes - dozen Mbytes]
*/
le = kvmalloc(al_aligned(lsize), GFP_KERNEL); if (!le) {
err = -ENOMEM; goto out;
}
err = ntfs_read_run_nb(ni->mi.sbi, &ni->attr_list.run, 0, le,
lsize, NULL); if (err) goto out;
}
/* * al_enumerate * * Return: * * The next list le. * * If @le is NULL then return the first le.
*/ struct ATTR_LIST_ENTRY *al_enumerate(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le)
{
size_t off;
u16 sz; constunsigned le_min_size = le_size(0);
if (!le) {
le = ni->attr_list.le;
} else {
sz = le16_to_cpu(le->size); if (sz < le_min_size) { /* Impossible 'cause we should not return such le. */ return NULL;
}
le = Add2Ptr(le, sz);
}
/* Check boundary. */
off = PtrOffset(ni->attr_list.le, le); if (off + le_min_size > ni->attr_list.size) { /* The regular end of list. */ return NULL;
}
sz = le16_to_cpu(le->size);
/* Check le for errors. */ if (sz < le_min_size || off + sz > ni->attr_list.size ||
sz < le->name_off + le->name_len * sizeof(short)) { return NULL;
}
return le;
}
/* * al_find_le * * Find the first le in the list which matches type, name and VCN. * * Return: NULL if not found.
*/ struct ATTR_LIST_ENTRY *al_find_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le, conststruct ATTRIB *attr)
{
CLST svcn = attr_svcn(attr);
return al_find_ex(ni, le, attr->type, attr_name(attr), attr->name_len,
&svcn);
}
/* * al_find_ex * * Find the first le in the list which matches type, name and VCN. * * Return: NULL if not found.
*/ struct ATTR_LIST_ENTRY *al_find_ex(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le, enum ATTR_TYPE type, const __le16 *name,
u8 name_len, const CLST *vcn)
{ struct ATTR_LIST_ENTRY *ret = NULL;
u32 type_in = le32_to_cpu(type);
while ((le = al_enumerate(ni, le))) {
u64 le_vcn; int diff = le32_to_cpu(le->type) - type_in;
/* List entries are sorted by type, name and VCN. */ if (diff < 0) continue;
if (diff > 0) return ret;
if (le->name_len != name_len) continue;
le_vcn = le64_to_cpu(le->vcn); if (!le_vcn) { /* * Compare entry names only for entry with vcn == 0.
*/
diff = ntfs_cmp_names(le_name(le), name_len, name,
name_len, ni->mi.sbi->upcase, true); if (diff < 0) continue;
if (diff > 0) return ret;
}
if (!vcn) return le;
if (*vcn == le_vcn) return le;
if (*vcn < le_vcn) return ret;
ret = le;
}
return ret;
}
/* * al_find_le_to_insert * * Find the first list entry which matches type, name and VCN.
*/ staticstruct ATTR_LIST_ENTRY *al_find_le_to_insert(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
u8 name_len, CLST vcn)
{ struct ATTR_LIST_ENTRY *le = NULL, *prev;
u32 type_in = le32_to_cpu(type);
/* List entries are sorted by type, name and VCN. */ while ((le = al_enumerate(ni, prev = le))) { int diff = le32_to_cpu(le->type) - type_in;
if (diff < 0) continue;
if (diff > 0) return le;
if (!le->vcn) { /* * Compare entry names only for entry with vcn == 0.
*/
diff = ntfs_cmp_names(le_name(le), le->name_len, name,
name_len, ni->mi.sbi->upcase, true); if (diff < 0) continue;
/* * al_add_le * * Add an "attribute list entry" to the list.
*/ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
u8 name_len, CLST svcn, __le16 id, conststruct MFT_REF *ref, struct ATTR_LIST_ENTRY **new_le)
{ int err; struct ATTRIB *attr; struct ATTR_LIST_ENTRY *le;
size_t off;
u16 sz;
size_t asize, new_asize, old_size;
u64 new_size;
typeof(ni->attr_list) *al = &ni->attr_list;
/* * Compute the size of the new 'le'
*/
sz = le_size(name_len);
old_size = al->size;
new_size = old_size + sz;
asize = al_aligned(old_size);
new_asize = al_aligned(new_size);
/* Scan forward to the point at which the new 'le' should be inserted. */
le = al_find_le_to_insert(ni, type, name, name_len, svcn);
off = PtrOffset(al->le, le);
if (new_size > asize) { void *ptr = kmalloc(new_asize, GFP_NOFS);
if (!ptr) return -ENOMEM;
memcpy(ptr, al->le, off);
memcpy(Add2Ptr(ptr, off + sz), le, old_size - off);
le = Add2Ptr(ptr, off);
kvfree(al->le);
al->le = ptr;
} else {
memmove(Add2Ptr(le, sz), le, old_size - off);
}
*new_le = le;
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.