162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/fs.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "debug.h" 1162306a36Sopenharmony_ci#include "ntfs.h" 1262306a36Sopenharmony_ci#include "ntfs_fs.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic inline int compare_attr(const struct ATTRIB *left, enum ATTR_TYPE type, 1562306a36Sopenharmony_ci const __le16 *name, u8 name_len, 1662306a36Sopenharmony_ci const u16 *upcase) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci /* First, compare the type codes. */ 1962306a36Sopenharmony_ci int diff = le32_to_cpu(left->type) - le32_to_cpu(type); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci if (diff) 2262306a36Sopenharmony_ci return diff; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci /* They have the same type code, so we have to compare the names. */ 2562306a36Sopenharmony_ci return ntfs_cmp_names(attr_name(left), left->name_len, name, name_len, 2662306a36Sopenharmony_ci upcase, true); 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * mi_new_attt_id 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * Return: Unused attribute id that is less than mrec->next_attr_id. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistatic __le16 mi_new_attt_id(struct mft_inode *mi) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci u16 free_id, max_id, t16; 3762306a36Sopenharmony_ci struct MFT_REC *rec = mi->mrec; 3862306a36Sopenharmony_ci struct ATTRIB *attr; 3962306a36Sopenharmony_ci __le16 id; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci id = rec->next_attr_id; 4262306a36Sopenharmony_ci free_id = le16_to_cpu(id); 4362306a36Sopenharmony_ci if (free_id < 0x7FFF) { 4462306a36Sopenharmony_ci rec->next_attr_id = cpu_to_le16(free_id + 1); 4562306a36Sopenharmony_ci return id; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* One record can store up to 1024/24 ~= 42 attributes. */ 4962306a36Sopenharmony_ci free_id = 0; 5062306a36Sopenharmony_ci max_id = 0; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci attr = NULL; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci for (;;) { 5562306a36Sopenharmony_ci attr = mi_enum_attr(mi, attr); 5662306a36Sopenharmony_ci if (!attr) { 5762306a36Sopenharmony_ci rec->next_attr_id = cpu_to_le16(max_id + 1); 5862306a36Sopenharmony_ci mi->dirty = true; 5962306a36Sopenharmony_ci return cpu_to_le16(free_id); 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci t16 = le16_to_cpu(attr->id); 6362306a36Sopenharmony_ci if (t16 == free_id) { 6462306a36Sopenharmony_ci free_id += 1; 6562306a36Sopenharmony_ci attr = NULL; 6662306a36Sopenharmony_ci } else if (max_id < t16) 6762306a36Sopenharmony_ci max_id = t16; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciint mi_get(struct ntfs_sb_info *sbi, CLST rno, struct mft_inode **mi) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci int err; 7462306a36Sopenharmony_ci struct mft_inode *m = kzalloc(sizeof(struct mft_inode), GFP_NOFS); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (!m) 7762306a36Sopenharmony_ci return -ENOMEM; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci err = mi_init(m, sbi, rno); 8062306a36Sopenharmony_ci if (err) { 8162306a36Sopenharmony_ci kfree(m); 8262306a36Sopenharmony_ci return err; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci err = mi_read(m, false); 8662306a36Sopenharmony_ci if (err) { 8762306a36Sopenharmony_ci mi_put(m); 8862306a36Sopenharmony_ci return err; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci *mi = m; 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_civoid mi_put(struct mft_inode *mi) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci mi_clear(mi); 9862306a36Sopenharmony_ci kfree(mi); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciint mi_init(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci mi->sbi = sbi; 10462306a36Sopenharmony_ci mi->rno = rno; 10562306a36Sopenharmony_ci mi->mrec = kmalloc(sbi->record_size, GFP_NOFS); 10662306a36Sopenharmony_ci if (!mi->mrec) 10762306a36Sopenharmony_ci return -ENOMEM; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* 11362306a36Sopenharmony_ci * mi_read - Read MFT data. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ciint mi_read(struct mft_inode *mi, bool is_mft) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int err; 11862306a36Sopenharmony_ci struct MFT_REC *rec = mi->mrec; 11962306a36Sopenharmony_ci struct ntfs_sb_info *sbi = mi->sbi; 12062306a36Sopenharmony_ci u32 bpr = sbi->record_size; 12162306a36Sopenharmony_ci u64 vbo = (u64)mi->rno << sbi->record_bits; 12262306a36Sopenharmony_ci struct ntfs_inode *mft_ni = sbi->mft.ni; 12362306a36Sopenharmony_ci struct runs_tree *run = mft_ni ? &mft_ni->file.run : NULL; 12462306a36Sopenharmony_ci struct rw_semaphore *rw_lock = NULL; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (is_mounted(sbi)) { 12762306a36Sopenharmony_ci if (!is_mft && mft_ni) { 12862306a36Sopenharmony_ci rw_lock = &mft_ni->file.run_lock; 12962306a36Sopenharmony_ci down_read(rw_lock); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci err = ntfs_read_bh(sbi, run, vbo, &rec->rhdr, bpr, &mi->nb); 13462306a36Sopenharmony_ci if (rw_lock) 13562306a36Sopenharmony_ci up_read(rw_lock); 13662306a36Sopenharmony_ci if (!err) 13762306a36Sopenharmony_ci goto ok; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (err == -E_NTFS_FIXUP) { 14062306a36Sopenharmony_ci mi->dirty = true; 14162306a36Sopenharmony_ci goto ok; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (err != -ENOENT) 14562306a36Sopenharmony_ci goto out; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (rw_lock) { 14862306a36Sopenharmony_ci ni_lock(mft_ni); 14962306a36Sopenharmony_ci down_write(rw_lock); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci err = attr_load_runs_vcn(mft_ni, ATTR_DATA, NULL, 0, run, 15262306a36Sopenharmony_ci vbo >> sbi->cluster_bits); 15362306a36Sopenharmony_ci if (rw_lock) { 15462306a36Sopenharmony_ci up_write(rw_lock); 15562306a36Sopenharmony_ci ni_unlock(mft_ni); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci if (err) 15862306a36Sopenharmony_ci goto out; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (rw_lock) 16162306a36Sopenharmony_ci down_read(rw_lock); 16262306a36Sopenharmony_ci err = ntfs_read_bh(sbi, run, vbo, &rec->rhdr, bpr, &mi->nb); 16362306a36Sopenharmony_ci if (rw_lock) 16462306a36Sopenharmony_ci up_read(rw_lock); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (err == -E_NTFS_FIXUP) { 16762306a36Sopenharmony_ci mi->dirty = true; 16862306a36Sopenharmony_ci goto ok; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci if (err) 17162306a36Sopenharmony_ci goto out; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciok: 17462306a36Sopenharmony_ci /* Check field 'total' only here. */ 17562306a36Sopenharmony_ci if (le32_to_cpu(rec->total) != bpr) { 17662306a36Sopenharmony_ci err = -EINVAL; 17762306a36Sopenharmony_ci goto out; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ciout: 18362306a36Sopenharmony_ci if (err == -E_NTFS_CORRUPT) { 18462306a36Sopenharmony_ci ntfs_err(sbi->sb, "mft corrupted"); 18562306a36Sopenharmony_ci ntfs_set_state(sbi, NTFS_DIRTY_ERROR); 18662306a36Sopenharmony_ci err = -EINVAL; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return err; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* 19362306a36Sopenharmony_ci * mi_enum_attr - start/continue attributes enumeration in record. 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * NOTE: mi->mrec - memory of size sbi->record_size 19662306a36Sopenharmony_ci * here we sure that mi->mrec->total == sbi->record_size (see mi_read) 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_cistruct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci const struct MFT_REC *rec = mi->mrec; 20162306a36Sopenharmony_ci u32 used = le32_to_cpu(rec->used); 20262306a36Sopenharmony_ci u32 t32, off, asize, prev_type; 20362306a36Sopenharmony_ci u16 t16; 20462306a36Sopenharmony_ci u64 data_size, alloc_size, tot_size; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (!attr) { 20762306a36Sopenharmony_ci u32 total = le32_to_cpu(rec->total); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci off = le16_to_cpu(rec->attr_off); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (used > total) 21262306a36Sopenharmony_ci return NULL; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (off >= used || off < MFTRECORD_FIXUP_OFFSET_1 || 21562306a36Sopenharmony_ci !IS_ALIGNED(off, 4)) { 21662306a36Sopenharmony_ci return NULL; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* Skip non-resident records. */ 22062306a36Sopenharmony_ci if (!is_rec_inuse(rec)) 22162306a36Sopenharmony_ci return NULL; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci prev_type = 0; 22462306a36Sopenharmony_ci attr = Add2Ptr(rec, off); 22562306a36Sopenharmony_ci } else { 22662306a36Sopenharmony_ci /* Check if input attr inside record. */ 22762306a36Sopenharmony_ci off = PtrOffset(rec, attr); 22862306a36Sopenharmony_ci if (off >= used) 22962306a36Sopenharmony_ci return NULL; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci asize = le32_to_cpu(attr->size); 23262306a36Sopenharmony_ci if (asize < SIZEOF_RESIDENT) { 23362306a36Sopenharmony_ci /* Impossible 'cause we should not return such attribute. */ 23462306a36Sopenharmony_ci return NULL; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Overflow check. */ 23862306a36Sopenharmony_ci if (off + asize < off) 23962306a36Sopenharmony_ci return NULL; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci prev_type = le32_to_cpu(attr->type); 24262306a36Sopenharmony_ci attr = Add2Ptr(attr, asize); 24362306a36Sopenharmony_ci off += asize; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci asize = le32_to_cpu(attr->size); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Can we use the first field (attr->type). */ 24962306a36Sopenharmony_ci if (off + 8 > used) { 25062306a36Sopenharmony_ci static_assert(ALIGN(sizeof(enum ATTR_TYPE), 8) == 8); 25162306a36Sopenharmony_ci return NULL; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (attr->type == ATTR_END) { 25562306a36Sopenharmony_ci /* End of enumeration. */ 25662306a36Sopenharmony_ci return NULL; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* 0x100 is last known attribute for now. */ 26062306a36Sopenharmony_ci t32 = le32_to_cpu(attr->type); 26162306a36Sopenharmony_ci if (!t32 || (t32 & 0xf) || (t32 > 0x100)) 26262306a36Sopenharmony_ci return NULL; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* attributes in record must be ordered by type */ 26562306a36Sopenharmony_ci if (t32 < prev_type) 26662306a36Sopenharmony_ci return NULL; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* Check overflow and boundary. */ 26962306a36Sopenharmony_ci if (off + asize < off || off + asize > used) 27062306a36Sopenharmony_ci return NULL; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Check size of attribute. */ 27362306a36Sopenharmony_ci if (!attr->non_res) { 27462306a36Sopenharmony_ci /* Check resident fields. */ 27562306a36Sopenharmony_ci if (asize < SIZEOF_RESIDENT) 27662306a36Sopenharmony_ci return NULL; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci t16 = le16_to_cpu(attr->res.data_off); 27962306a36Sopenharmony_ci if (t16 > asize) 28062306a36Sopenharmony_ci return NULL; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (le32_to_cpu(attr->res.data_size) > asize - t16) 28362306a36Sopenharmony_ci return NULL; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci t32 = sizeof(short) * attr->name_len; 28662306a36Sopenharmony_ci if (t32 && le16_to_cpu(attr->name_off) + t32 > t16) 28762306a36Sopenharmony_ci return NULL; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return attr; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Check nonresident fields. */ 29362306a36Sopenharmony_ci if (attr->non_res != 1) 29462306a36Sopenharmony_ci return NULL; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci t16 = le16_to_cpu(attr->nres.run_off); 29762306a36Sopenharmony_ci if (t16 > asize) 29862306a36Sopenharmony_ci return NULL; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci t32 = sizeof(short) * attr->name_len; 30162306a36Sopenharmony_ci if (t32 && le16_to_cpu(attr->name_off) + t32 > t16) 30262306a36Sopenharmony_ci return NULL; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Check start/end vcn. */ 30562306a36Sopenharmony_ci if (le64_to_cpu(attr->nres.svcn) > le64_to_cpu(attr->nres.evcn) + 1) 30662306a36Sopenharmony_ci return NULL; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci data_size = le64_to_cpu(attr->nres.data_size); 30962306a36Sopenharmony_ci if (le64_to_cpu(attr->nres.valid_size) > data_size) 31062306a36Sopenharmony_ci return NULL; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci alloc_size = le64_to_cpu(attr->nres.alloc_size); 31362306a36Sopenharmony_ci if (data_size > alloc_size) 31462306a36Sopenharmony_ci return NULL; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci t32 = mi->sbi->cluster_mask; 31762306a36Sopenharmony_ci if (alloc_size & t32) 31862306a36Sopenharmony_ci return NULL; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (!attr->nres.svcn && is_attr_ext(attr)) { 32162306a36Sopenharmony_ci /* First segment of sparse/compressed attribute */ 32262306a36Sopenharmony_ci if (asize + 8 < SIZEOF_NONRESIDENT_EX) 32362306a36Sopenharmony_ci return NULL; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci tot_size = le64_to_cpu(attr->nres.total_size); 32662306a36Sopenharmony_ci if (tot_size & t32) 32762306a36Sopenharmony_ci return NULL; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (tot_size > alloc_size) 33062306a36Sopenharmony_ci return NULL; 33162306a36Sopenharmony_ci } else { 33262306a36Sopenharmony_ci if (asize + 8 < SIZEOF_NONRESIDENT) 33362306a36Sopenharmony_ci return NULL; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (attr->nres.c_unit) 33662306a36Sopenharmony_ci return NULL; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return attr; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/* 34362306a36Sopenharmony_ci * mi_find_attr - Find the attribute by type and name and id. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_cistruct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr, 34662306a36Sopenharmony_ci enum ATTR_TYPE type, const __le16 *name, 34762306a36Sopenharmony_ci u8 name_len, const __le16 *id) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci u32 type_in = le32_to_cpu(type); 35062306a36Sopenharmony_ci u32 atype; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cinext_attr: 35362306a36Sopenharmony_ci attr = mi_enum_attr(mi, attr); 35462306a36Sopenharmony_ci if (!attr) 35562306a36Sopenharmony_ci return NULL; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci atype = le32_to_cpu(attr->type); 35862306a36Sopenharmony_ci if (atype > type_in) 35962306a36Sopenharmony_ci return NULL; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (atype < type_in) 36262306a36Sopenharmony_ci goto next_attr; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (attr->name_len != name_len) 36562306a36Sopenharmony_ci goto next_attr; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (name_len && memcmp(attr_name(attr), name, name_len * sizeof(short))) 36862306a36Sopenharmony_ci goto next_attr; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (id && *id != attr->id) 37162306a36Sopenharmony_ci goto next_attr; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci return attr; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ciint mi_write(struct mft_inode *mi, int wait) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct MFT_REC *rec; 37962306a36Sopenharmony_ci int err; 38062306a36Sopenharmony_ci struct ntfs_sb_info *sbi; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (!mi->dirty) 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci sbi = mi->sbi; 38662306a36Sopenharmony_ci rec = mi->mrec; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci err = ntfs_write_bh(sbi, &rec->rhdr, &mi->nb, wait); 38962306a36Sopenharmony_ci if (err) 39062306a36Sopenharmony_ci return err; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (mi->rno < sbi->mft.recs_mirr) 39362306a36Sopenharmony_ci sbi->flags |= NTFS_FLAGS_MFTMIRR; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci mi->dirty = false; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ciint mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno, 40162306a36Sopenharmony_ci __le16 flags, bool is_mft) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci int err; 40462306a36Sopenharmony_ci u16 seq = 1; 40562306a36Sopenharmony_ci struct MFT_REC *rec; 40662306a36Sopenharmony_ci u64 vbo = (u64)rno << sbi->record_bits; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci err = mi_init(mi, sbi, rno); 40962306a36Sopenharmony_ci if (err) 41062306a36Sopenharmony_ci return err; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci rec = mi->mrec; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (rno == MFT_REC_MFT) { 41562306a36Sopenharmony_ci ; 41662306a36Sopenharmony_ci } else if (rno < MFT_REC_FREE) { 41762306a36Sopenharmony_ci seq = rno; 41862306a36Sopenharmony_ci } else if (rno >= sbi->mft.used) { 41962306a36Sopenharmony_ci ; 42062306a36Sopenharmony_ci } else if (mi_read(mi, is_mft)) { 42162306a36Sopenharmony_ci ; 42262306a36Sopenharmony_ci } else if (rec->rhdr.sign == NTFS_FILE_SIGNATURE) { 42362306a36Sopenharmony_ci /* Record is reused. Update its sequence number. */ 42462306a36Sopenharmony_ci seq = le16_to_cpu(rec->seq) + 1; 42562306a36Sopenharmony_ci if (!seq) 42662306a36Sopenharmony_ci seq = 1; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci memcpy(rec, sbi->new_rec, sbi->record_size); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci rec->seq = cpu_to_le16(seq); 43262306a36Sopenharmony_ci rec->flags = RECORD_FLAG_IN_USE | flags; 43362306a36Sopenharmony_ci if (MFTRECORD_FIXUP_OFFSET == MFTRECORD_FIXUP_OFFSET_3) 43462306a36Sopenharmony_ci rec->mft_record = cpu_to_le32(rno); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci mi->dirty = true; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (!mi->nb.nbufs) { 43962306a36Sopenharmony_ci struct ntfs_inode *ni = sbi->mft.ni; 44062306a36Sopenharmony_ci bool lock = false; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (is_mounted(sbi) && !is_mft) { 44362306a36Sopenharmony_ci down_read(&ni->file.run_lock); 44462306a36Sopenharmony_ci lock = true; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci err = ntfs_get_bh(sbi, &ni->file.run, vbo, sbi->record_size, 44862306a36Sopenharmony_ci &mi->nb); 44962306a36Sopenharmony_ci if (lock) 45062306a36Sopenharmony_ci up_read(&ni->file.run_lock); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return err; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/* 45762306a36Sopenharmony_ci * mi_insert_attr - Reserve space for new attribute. 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci * Return: Not full constructed attribute or NULL if not possible to create. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_cistruct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, 46262306a36Sopenharmony_ci const __le16 *name, u8 name_len, u32 asize, 46362306a36Sopenharmony_ci u16 name_off) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci size_t tail; 46662306a36Sopenharmony_ci struct ATTRIB *attr; 46762306a36Sopenharmony_ci __le16 id; 46862306a36Sopenharmony_ci struct MFT_REC *rec = mi->mrec; 46962306a36Sopenharmony_ci struct ntfs_sb_info *sbi = mi->sbi; 47062306a36Sopenharmony_ci u32 used = le32_to_cpu(rec->used); 47162306a36Sopenharmony_ci const u16 *upcase = sbi->upcase; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* Can we insert mi attribute? */ 47462306a36Sopenharmony_ci if (used + asize > sbi->record_size) 47562306a36Sopenharmony_ci return NULL; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * Scan through the list of attributes to find the point 47962306a36Sopenharmony_ci * at which we should insert it. 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_ci attr = NULL; 48262306a36Sopenharmony_ci while ((attr = mi_enum_attr(mi, attr))) { 48362306a36Sopenharmony_ci int diff = compare_attr(attr, type, name, name_len, upcase); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (diff < 0) 48662306a36Sopenharmony_ci continue; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (!diff && !is_attr_indexed(attr)) 48962306a36Sopenharmony_ci return NULL; 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!attr) { 49462306a36Sopenharmony_ci /* Append. */ 49562306a36Sopenharmony_ci tail = 8; 49662306a36Sopenharmony_ci attr = Add2Ptr(rec, used - 8); 49762306a36Sopenharmony_ci } else { 49862306a36Sopenharmony_ci /* Insert before 'attr'. */ 49962306a36Sopenharmony_ci tail = used - PtrOffset(rec, attr); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci id = mi_new_attt_id(mi); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci memmove(Add2Ptr(attr, asize), attr, tail); 50562306a36Sopenharmony_ci memset(attr, 0, asize); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci attr->type = type; 50862306a36Sopenharmony_ci attr->size = cpu_to_le32(asize); 50962306a36Sopenharmony_ci attr->name_len = name_len; 51062306a36Sopenharmony_ci attr->name_off = cpu_to_le16(name_off); 51162306a36Sopenharmony_ci attr->id = id; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci memmove(Add2Ptr(attr, name_off), name, name_len * sizeof(short)); 51462306a36Sopenharmony_ci rec->used = cpu_to_le32(used + asize); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci mi->dirty = true; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return attr; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/* 52262306a36Sopenharmony_ci * mi_remove_attr - Remove the attribute from record. 52362306a36Sopenharmony_ci * 52462306a36Sopenharmony_ci * NOTE: The source attr will point to next attribute. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_cibool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi, 52762306a36Sopenharmony_ci struct ATTRIB *attr) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct MFT_REC *rec = mi->mrec; 53062306a36Sopenharmony_ci u32 aoff = PtrOffset(rec, attr); 53162306a36Sopenharmony_ci u32 used = le32_to_cpu(rec->used); 53262306a36Sopenharmony_ci u32 asize = le32_to_cpu(attr->size); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (aoff + asize > used) 53562306a36Sopenharmony_ci return false; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (ni && is_attr_indexed(attr)) { 53862306a36Sopenharmony_ci u16 links = le16_to_cpu(ni->mi.mrec->hard_links); 53962306a36Sopenharmony_ci struct ATTR_FILE_NAME *fname = 54062306a36Sopenharmony_ci attr->type != ATTR_NAME ? 54162306a36Sopenharmony_ci NULL : 54262306a36Sopenharmony_ci resident_data_ex(attr, 54362306a36Sopenharmony_ci SIZEOF_ATTRIBUTE_FILENAME); 54462306a36Sopenharmony_ci if (fname && fname->type == FILE_NAME_DOS) { 54562306a36Sopenharmony_ci /* Do not decrease links count deleting DOS name. */ 54662306a36Sopenharmony_ci } else if (!links) { 54762306a36Sopenharmony_ci /* minor error. Not critical. */ 54862306a36Sopenharmony_ci } else { 54962306a36Sopenharmony_ci ni->mi.mrec->hard_links = cpu_to_le16(links - 1); 55062306a36Sopenharmony_ci ni->mi.dirty = true; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci used -= asize; 55562306a36Sopenharmony_ci memmove(attr, Add2Ptr(attr, asize), used - aoff); 55662306a36Sopenharmony_ci rec->used = cpu_to_le32(used); 55762306a36Sopenharmony_ci mi->dirty = true; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return true; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci/* bytes = "new attribute size" - "old attribute size" */ 56362306a36Sopenharmony_cibool mi_resize_attr(struct mft_inode *mi, struct ATTRIB *attr, int bytes) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct MFT_REC *rec = mi->mrec; 56662306a36Sopenharmony_ci u32 aoff = PtrOffset(rec, attr); 56762306a36Sopenharmony_ci u32 total, used = le32_to_cpu(rec->used); 56862306a36Sopenharmony_ci u32 nsize, asize = le32_to_cpu(attr->size); 56962306a36Sopenharmony_ci u32 rsize = le32_to_cpu(attr->res.data_size); 57062306a36Sopenharmony_ci int tail = (int)(used - aoff - asize); 57162306a36Sopenharmony_ci int dsize; 57262306a36Sopenharmony_ci char *next; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (tail < 0 || aoff >= used) 57562306a36Sopenharmony_ci return false; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (!bytes) 57862306a36Sopenharmony_ci return true; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci total = le32_to_cpu(rec->total); 58162306a36Sopenharmony_ci next = Add2Ptr(attr, asize); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (bytes > 0) { 58462306a36Sopenharmony_ci dsize = ALIGN(bytes, 8); 58562306a36Sopenharmony_ci if (used + dsize > total) 58662306a36Sopenharmony_ci return false; 58762306a36Sopenharmony_ci nsize = asize + dsize; 58862306a36Sopenharmony_ci /* Move tail */ 58962306a36Sopenharmony_ci memmove(next + dsize, next, tail); 59062306a36Sopenharmony_ci memset(next, 0, dsize); 59162306a36Sopenharmony_ci used += dsize; 59262306a36Sopenharmony_ci rsize += dsize; 59362306a36Sopenharmony_ci } else { 59462306a36Sopenharmony_ci dsize = ALIGN(-bytes, 8); 59562306a36Sopenharmony_ci if (dsize > asize) 59662306a36Sopenharmony_ci return false; 59762306a36Sopenharmony_ci nsize = asize - dsize; 59862306a36Sopenharmony_ci memmove(next - dsize, next, tail); 59962306a36Sopenharmony_ci used -= dsize; 60062306a36Sopenharmony_ci rsize -= dsize; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci rec->used = cpu_to_le32(used); 60462306a36Sopenharmony_ci attr->size = cpu_to_le32(nsize); 60562306a36Sopenharmony_ci if (!attr->non_res) 60662306a36Sopenharmony_ci attr->res.data_size = cpu_to_le32(rsize); 60762306a36Sopenharmony_ci mi->dirty = true; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return true; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/* 61362306a36Sopenharmony_ci * Pack runs in MFT record. 61462306a36Sopenharmony_ci * If failed record is not changed. 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ciint mi_pack_runs(struct mft_inode *mi, struct ATTRIB *attr, 61762306a36Sopenharmony_ci struct runs_tree *run, CLST len) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci int err = 0; 62062306a36Sopenharmony_ci struct ntfs_sb_info *sbi = mi->sbi; 62162306a36Sopenharmony_ci u32 new_run_size; 62262306a36Sopenharmony_ci CLST plen; 62362306a36Sopenharmony_ci struct MFT_REC *rec = mi->mrec; 62462306a36Sopenharmony_ci CLST svcn = le64_to_cpu(attr->nres.svcn); 62562306a36Sopenharmony_ci u32 used = le32_to_cpu(rec->used); 62662306a36Sopenharmony_ci u32 aoff = PtrOffset(rec, attr); 62762306a36Sopenharmony_ci u32 asize = le32_to_cpu(attr->size); 62862306a36Sopenharmony_ci char *next = Add2Ptr(attr, asize); 62962306a36Sopenharmony_ci u16 run_off = le16_to_cpu(attr->nres.run_off); 63062306a36Sopenharmony_ci u32 run_size = asize - run_off; 63162306a36Sopenharmony_ci u32 tail = used - aoff - asize; 63262306a36Sopenharmony_ci u32 dsize = sbi->record_size - used; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* Make a maximum gap in current record. */ 63562306a36Sopenharmony_ci memmove(next + dsize, next, tail); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Pack as much as possible. */ 63862306a36Sopenharmony_ci err = run_pack(run, svcn, len, Add2Ptr(attr, run_off), run_size + dsize, 63962306a36Sopenharmony_ci &plen); 64062306a36Sopenharmony_ci if (err < 0) { 64162306a36Sopenharmony_ci memmove(next, next + dsize, tail); 64262306a36Sopenharmony_ci return err; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci new_run_size = ALIGN(err, 8); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci memmove(next + new_run_size - run_size, next + dsize, tail); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci attr->size = cpu_to_le32(asize + new_run_size - run_size); 65062306a36Sopenharmony_ci attr->nres.evcn = cpu_to_le64(svcn + plen - 1); 65162306a36Sopenharmony_ci rec->used = cpu_to_le32(used + new_run_size - run_size); 65262306a36Sopenharmony_ci mi->dirty = true; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci return 0; 65562306a36Sopenharmony_ci} 656