14342306fSKonstantin Komarov // SPDX-License-Identifier: GPL-2.0 24342306fSKonstantin Komarov /* 34342306fSKonstantin Komarov * 44342306fSKonstantin Komarov * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. 54342306fSKonstantin Komarov * 64342306fSKonstantin Komarov */ 74342306fSKonstantin Komarov 84342306fSKonstantin Komarov #include <linux/fs.h> 94342306fSKonstantin Komarov 104342306fSKonstantin Komarov #include "debug.h" 114342306fSKonstantin Komarov #include "ntfs.h" 124342306fSKonstantin Komarov #include "ntfs_fs.h" 134342306fSKonstantin Komarov 144342306fSKonstantin Komarov static inline int compare_attr(const struct ATTRIB *left, enum ATTR_TYPE type, 154342306fSKonstantin Komarov const __le16 *name, u8 name_len, 164342306fSKonstantin Komarov const u16 *upcase) 174342306fSKonstantin Komarov { 18e8b8e97fSKari Argillander /* First, compare the type codes. */ 194342306fSKonstantin Komarov int diff = le32_to_cpu(left->type) - le32_to_cpu(type); 204342306fSKonstantin Komarov 214342306fSKonstantin Komarov if (diff) 224342306fSKonstantin Komarov return diff; 234342306fSKonstantin Komarov 24e8b8e97fSKari Argillander /* They have the same type code, so we have to compare the names. */ 254342306fSKonstantin Komarov return ntfs_cmp_names(attr_name(left), left->name_len, name, name_len, 264342306fSKonstantin Komarov upcase, true); 274342306fSKonstantin Komarov } 284342306fSKonstantin Komarov 294342306fSKonstantin Komarov /* 304342306fSKonstantin Komarov * mi_new_attt_id 314342306fSKonstantin Komarov * 32e8b8e97fSKari Argillander * Return: Unused attribute id that is less than mrec->next_attr_id. 334342306fSKonstantin Komarov */ 344342306fSKonstantin Komarov static __le16 mi_new_attt_id(struct mft_inode *mi) 354342306fSKonstantin Komarov { 364342306fSKonstantin Komarov u16 free_id, max_id, t16; 374342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 384342306fSKonstantin Komarov struct ATTRIB *attr; 394342306fSKonstantin Komarov __le16 id; 404342306fSKonstantin Komarov 414342306fSKonstantin Komarov id = rec->next_attr_id; 424342306fSKonstantin Komarov free_id = le16_to_cpu(id); 434342306fSKonstantin Komarov if (free_id < 0x7FFF) { 444342306fSKonstantin Komarov rec->next_attr_id = cpu_to_le16(free_id + 1); 454342306fSKonstantin Komarov return id; 464342306fSKonstantin Komarov } 474342306fSKonstantin Komarov 48e8b8e97fSKari Argillander /* One record can store up to 1024/24 ~= 42 attributes. */ 494342306fSKonstantin Komarov free_id = 0; 504342306fSKonstantin Komarov max_id = 0; 514342306fSKonstantin Komarov 524342306fSKonstantin Komarov attr = NULL; 534342306fSKonstantin Komarov 544342306fSKonstantin Komarov for (;;) { 554342306fSKonstantin Komarov attr = mi_enum_attr(mi, attr); 564342306fSKonstantin Komarov if (!attr) { 574342306fSKonstantin Komarov rec->next_attr_id = cpu_to_le16(max_id + 1); 584342306fSKonstantin Komarov mi->dirty = true; 594342306fSKonstantin Komarov return cpu_to_le16(free_id); 604342306fSKonstantin Komarov } 614342306fSKonstantin Komarov 624342306fSKonstantin Komarov t16 = le16_to_cpu(attr->id); 634342306fSKonstantin Komarov if (t16 == free_id) { 644342306fSKonstantin Komarov free_id += 1; 654342306fSKonstantin Komarov attr = NULL; 664342306fSKonstantin Komarov } else if (max_id < t16) 674342306fSKonstantin Komarov max_id = t16; 684342306fSKonstantin Komarov } 694342306fSKonstantin Komarov } 704342306fSKonstantin Komarov 714342306fSKonstantin Komarov int mi_get(struct ntfs_sb_info *sbi, CLST rno, struct mft_inode **mi) 724342306fSKonstantin Komarov { 734342306fSKonstantin Komarov int err; 74195c52bdSKari Argillander struct mft_inode *m = kzalloc(sizeof(struct mft_inode), GFP_NOFS); 754342306fSKonstantin Komarov 764342306fSKonstantin Komarov if (!m) 774342306fSKonstantin Komarov return -ENOMEM; 784342306fSKonstantin Komarov 794342306fSKonstantin Komarov err = mi_init(m, sbi, rno); 804342306fSKonstantin Komarov if (err) { 81195c52bdSKari Argillander kfree(m); 824342306fSKonstantin Komarov return err; 834342306fSKonstantin Komarov } 844342306fSKonstantin Komarov 854342306fSKonstantin Komarov err = mi_read(m, false); 864342306fSKonstantin Komarov if (err) { 874342306fSKonstantin Komarov mi_put(m); 884342306fSKonstantin Komarov return err; 894342306fSKonstantin Komarov } 904342306fSKonstantin Komarov 914342306fSKonstantin Komarov *mi = m; 924342306fSKonstantin Komarov return 0; 934342306fSKonstantin Komarov } 944342306fSKonstantin Komarov 954342306fSKonstantin Komarov void mi_put(struct mft_inode *mi) 964342306fSKonstantin Komarov { 974342306fSKonstantin Komarov mi_clear(mi); 98195c52bdSKari Argillander kfree(mi); 994342306fSKonstantin Komarov } 1004342306fSKonstantin Komarov 1014342306fSKonstantin Komarov int mi_init(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno) 1024342306fSKonstantin Komarov { 1034342306fSKonstantin Komarov mi->sbi = sbi; 1044342306fSKonstantin Komarov mi->rno = rno; 105195c52bdSKari Argillander mi->mrec = kmalloc(sbi->record_size, GFP_NOFS); 1064342306fSKonstantin Komarov if (!mi->mrec) 1074342306fSKonstantin Komarov return -ENOMEM; 1084342306fSKonstantin Komarov 1094342306fSKonstantin Komarov return 0; 1104342306fSKonstantin Komarov } 1114342306fSKonstantin Komarov 1124342306fSKonstantin Komarov /* 113e8b8e97fSKari Argillander * mi_read - Read MFT data. 1144342306fSKonstantin Komarov */ 1154342306fSKonstantin Komarov int mi_read(struct mft_inode *mi, bool is_mft) 1164342306fSKonstantin Komarov { 1174342306fSKonstantin Komarov int err; 1184342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 1194342306fSKonstantin Komarov struct ntfs_sb_info *sbi = mi->sbi; 1204342306fSKonstantin Komarov u32 bpr = sbi->record_size; 1214342306fSKonstantin Komarov u64 vbo = (u64)mi->rno << sbi->record_bits; 1224342306fSKonstantin Komarov struct ntfs_inode *mft_ni = sbi->mft.ni; 1234342306fSKonstantin Komarov struct runs_tree *run = mft_ni ? &mft_ni->file.run : NULL; 1244342306fSKonstantin Komarov struct rw_semaphore *rw_lock = NULL; 1254342306fSKonstantin Komarov 1264342306fSKonstantin Komarov if (is_mounted(sbi)) { 12797498cd6SJia-Ju Bai if (!is_mft && mft_ni) { 1284342306fSKonstantin Komarov rw_lock = &mft_ni->file.run_lock; 1294342306fSKonstantin Komarov down_read(rw_lock); 1304342306fSKonstantin Komarov } 1314342306fSKonstantin Komarov } 1324342306fSKonstantin Komarov 1334342306fSKonstantin Komarov err = ntfs_read_bh(sbi, run, vbo, &rec->rhdr, bpr, &mi->nb); 1344342306fSKonstantin Komarov if (rw_lock) 1354342306fSKonstantin Komarov up_read(rw_lock); 1364342306fSKonstantin Komarov if (!err) 1374342306fSKonstantin Komarov goto ok; 1384342306fSKonstantin Komarov 1394342306fSKonstantin Komarov if (err == -E_NTFS_FIXUP) { 1404342306fSKonstantin Komarov mi->dirty = true; 1414342306fSKonstantin Komarov goto ok; 1424342306fSKonstantin Komarov } 1434342306fSKonstantin Komarov 1444342306fSKonstantin Komarov if (err != -ENOENT) 1454342306fSKonstantin Komarov goto out; 1464342306fSKonstantin Komarov 1474342306fSKonstantin Komarov if (rw_lock) { 1484342306fSKonstantin Komarov ni_lock(mft_ni); 1494342306fSKonstantin Komarov down_write(rw_lock); 1504342306fSKonstantin Komarov } 15197498cd6SJia-Ju Bai err = attr_load_runs_vcn(mft_ni, ATTR_DATA, NULL, 0, run, 1524342306fSKonstantin Komarov vbo >> sbi->cluster_bits); 1534342306fSKonstantin Komarov if (rw_lock) { 1544342306fSKonstantin Komarov up_write(rw_lock); 1554342306fSKonstantin Komarov ni_unlock(mft_ni); 1564342306fSKonstantin Komarov } 1574342306fSKonstantin Komarov if (err) 1584342306fSKonstantin Komarov goto out; 1594342306fSKonstantin Komarov 1604342306fSKonstantin Komarov if (rw_lock) 1614342306fSKonstantin Komarov down_read(rw_lock); 1624342306fSKonstantin Komarov err = ntfs_read_bh(sbi, run, vbo, &rec->rhdr, bpr, &mi->nb); 1634342306fSKonstantin Komarov if (rw_lock) 1644342306fSKonstantin Komarov up_read(rw_lock); 1654342306fSKonstantin Komarov 1664342306fSKonstantin Komarov if (err == -E_NTFS_FIXUP) { 1674342306fSKonstantin Komarov mi->dirty = true; 1684342306fSKonstantin Komarov goto ok; 1694342306fSKonstantin Komarov } 1704342306fSKonstantin Komarov if (err) 1714342306fSKonstantin Komarov goto out; 1724342306fSKonstantin Komarov 1734342306fSKonstantin Komarov ok: 174e8b8e97fSKari Argillander /* Check field 'total' only here. */ 1754342306fSKonstantin Komarov if (le32_to_cpu(rec->total) != bpr) { 1764342306fSKonstantin Komarov err = -EINVAL; 1774342306fSKonstantin Komarov goto out; 1784342306fSKonstantin Komarov } 1794342306fSKonstantin Komarov 1804342306fSKonstantin Komarov return 0; 1814342306fSKonstantin Komarov 1824342306fSKonstantin Komarov out: 183e0f363a9SKonstantin Komarov if (err == -E_NTFS_CORRUPT) { 184e0f363a9SKonstantin Komarov ntfs_err(sbi->sb, "mft corrupted"); 185e0f363a9SKonstantin Komarov ntfs_set_state(sbi, NTFS_DIRTY_ERROR); 186e0f363a9SKonstantin Komarov err = -EINVAL; 187e0f363a9SKonstantin Komarov } 188e0f363a9SKonstantin Komarov 1894342306fSKonstantin Komarov return err; 1904342306fSKonstantin Komarov } 1914342306fSKonstantin Komarov 192f684073cSKonstantin Komarov /* 193f684073cSKonstantin Komarov * mi_enum_attr - start/continue attributes enumeration in record. 194f684073cSKonstantin Komarov * 195f684073cSKonstantin Komarov * NOTE: mi->mrec - memory of size sbi->record_size 196f684073cSKonstantin Komarov * here we sure that mi->mrec->total == sbi->record_size (see mi_read) 197f684073cSKonstantin Komarov */ 1984342306fSKonstantin Komarov struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) 1994342306fSKonstantin Komarov { 2004342306fSKonstantin Komarov const struct MFT_REC *rec = mi->mrec; 2014342306fSKonstantin Komarov u32 used = le32_to_cpu(rec->used); 202013ff63bSKonstantin Komarov u32 t32, off, asize, prev_type; 2034342306fSKonstantin Komarov u16 t16; 204013ff63bSKonstantin Komarov u64 data_size, alloc_size, tot_size; 2054342306fSKonstantin Komarov 2064342306fSKonstantin Komarov if (!attr) { 2074342306fSKonstantin Komarov u32 total = le32_to_cpu(rec->total); 2084342306fSKonstantin Komarov 2094342306fSKonstantin Komarov off = le16_to_cpu(rec->attr_off); 2104342306fSKonstantin Komarov 2114342306fSKonstantin Komarov if (used > total) 2124342306fSKonstantin Komarov return NULL; 2134342306fSKonstantin Komarov 2144342306fSKonstantin Komarov if (off >= used || off < MFTRECORD_FIXUP_OFFSET_1 || 215fa3cacf5SKari Argillander !IS_ALIGNED(off, 4)) { 2164342306fSKonstantin Komarov return NULL; 2174342306fSKonstantin Komarov } 2184342306fSKonstantin Komarov 219e8b8e97fSKari Argillander /* Skip non-resident records. */ 2204342306fSKonstantin Komarov if (!is_rec_inuse(rec)) 2214342306fSKonstantin Komarov return NULL; 2224342306fSKonstantin Komarov 223013ff63bSKonstantin Komarov prev_type = 0; 2244342306fSKonstantin Komarov attr = Add2Ptr(rec, off); 2254342306fSKonstantin Komarov } else { 226e8b8e97fSKari Argillander /* Check if input attr inside record. */ 2274342306fSKonstantin Komarov off = PtrOffset(rec, attr); 2284342306fSKonstantin Komarov if (off >= used) 2294342306fSKonstantin Komarov return NULL; 2304342306fSKonstantin Komarov 2314342306fSKonstantin Komarov asize = le32_to_cpu(attr->size); 2324342306fSKonstantin Komarov if (asize < SIZEOF_RESIDENT) { 233d3624466SKonstantin Komarov /* Impossible 'cause we should not return such attribute. */ 2344342306fSKonstantin Komarov return NULL; 2354342306fSKonstantin Komarov } 2364342306fSKonstantin Komarov 23730200ef8SKonstantin Komarov /* Overflow check. */ 238013ff63bSKonstantin Komarov if (off + asize < off) 23930200ef8SKonstantin Komarov return NULL; 24030200ef8SKonstantin Komarov 241013ff63bSKonstantin Komarov prev_type = le32_to_cpu(attr->type); 2424342306fSKonstantin Komarov attr = Add2Ptr(attr, asize); 2434342306fSKonstantin Komarov off += asize; 2444342306fSKonstantin Komarov } 2454342306fSKonstantin Komarov 2464342306fSKonstantin Komarov asize = le32_to_cpu(attr->size); 2474342306fSKonstantin Komarov 248e8b8e97fSKari Argillander /* Can we use the first field (attr->type). */ 2494342306fSKonstantin Komarov if (off + 8 > used) { 250fa3cacf5SKari Argillander static_assert(ALIGN(sizeof(enum ATTR_TYPE), 8) == 8); 2514342306fSKonstantin Komarov return NULL; 2524342306fSKonstantin Komarov } 2534342306fSKonstantin Komarov 2544342306fSKonstantin Komarov if (attr->type == ATTR_END) { 255e8b8e97fSKari Argillander /* End of enumeration. */ 2564342306fSKonstantin Komarov return NULL; 2574342306fSKonstantin Komarov } 2584342306fSKonstantin Komarov 259e8b8e97fSKari Argillander /* 0x100 is last known attribute for now. */ 2604342306fSKonstantin Komarov t32 = le32_to_cpu(attr->type); 261013ff63bSKonstantin Komarov if (!t32 || (t32 & 0xf) || (t32 > 0x100)) 262013ff63bSKonstantin Komarov return NULL; 263013ff63bSKonstantin Komarov 264013ff63bSKonstantin Komarov /* attributes in record must be ordered by type */ 265013ff63bSKonstantin Komarov if (t32 < prev_type) 2664342306fSKonstantin Komarov return NULL; 2674342306fSKonstantin Komarov 2684f082a75SEdward Lo /* Check overflow and boundary. */ 2694f082a75SEdward Lo if (off + asize < off || off + asize > used) 2704342306fSKonstantin Komarov return NULL; 2714342306fSKonstantin Komarov 272e8b8e97fSKari Argillander /* Check size of attribute. */ 2734342306fSKonstantin Komarov if (!attr->non_res) { 274013ff63bSKonstantin Komarov /* Check resident fields. */ 2754342306fSKonstantin Komarov if (asize < SIZEOF_RESIDENT) 2764342306fSKonstantin Komarov return NULL; 2774342306fSKonstantin Komarov 2784342306fSKonstantin Komarov t16 = le16_to_cpu(attr->res.data_off); 2794342306fSKonstantin Komarov if (t16 > asize) 2804342306fSKonstantin Komarov return NULL; 2814342306fSKonstantin Komarov 282*652cfeb4SKonstantin Komarov if (le32_to_cpu(attr->res.data_size) > asize - t16) 2834342306fSKonstantin Komarov return NULL; 2844342306fSKonstantin Komarov 28536963cf2SKonstantin Komarov t32 = sizeof(short) * attr->name_len; 28636963cf2SKonstantin Komarov if (t32 && le16_to_cpu(attr->name_off) + t32 > t16) 28754e45702SEdward Lo return NULL; 28854e45702SEdward Lo 2894342306fSKonstantin Komarov return attr; 2904342306fSKonstantin Komarov } 2914342306fSKonstantin Komarov 292013ff63bSKonstantin Komarov /* Check nonresident fields. */ 293013ff63bSKonstantin Komarov if (attr->non_res != 1) 2944342306fSKonstantin Komarov return NULL; 2954342306fSKonstantin Komarov 296013ff63bSKonstantin Komarov t16 = le16_to_cpu(attr->nres.run_off); 297013ff63bSKonstantin Komarov if (t16 > asize) 298013ff63bSKonstantin Komarov return NULL; 299013ff63bSKonstantin Komarov 300013ff63bSKonstantin Komarov t32 = sizeof(short) * attr->name_len; 301013ff63bSKonstantin Komarov if (t32 && le16_to_cpu(attr->name_off) + t32 > t16) 302013ff63bSKonstantin Komarov return NULL; 303013ff63bSKonstantin Komarov 304013ff63bSKonstantin Komarov /* Check start/end vcn. */ 305013ff63bSKonstantin Komarov if (le64_to_cpu(attr->nres.svcn) > le64_to_cpu(attr->nres.evcn) + 1) 306013ff63bSKonstantin Komarov return NULL; 307013ff63bSKonstantin Komarov 308013ff63bSKonstantin Komarov data_size = le64_to_cpu(attr->nres.data_size); 309013ff63bSKonstantin Komarov if (le64_to_cpu(attr->nres.valid_size) > data_size) 310013ff63bSKonstantin Komarov return NULL; 311013ff63bSKonstantin Komarov 312013ff63bSKonstantin Komarov alloc_size = le64_to_cpu(attr->nres.alloc_size); 313013ff63bSKonstantin Komarov if (data_size > alloc_size) 314013ff63bSKonstantin Komarov return NULL; 315013ff63bSKonstantin Komarov 316013ff63bSKonstantin Komarov t32 = mi->sbi->cluster_mask; 317013ff63bSKonstantin Komarov if (alloc_size & t32) 318013ff63bSKonstantin Komarov return NULL; 319013ff63bSKonstantin Komarov 320013ff63bSKonstantin Komarov if (!attr->nres.svcn && is_attr_ext(attr)) { 321013ff63bSKonstantin Komarov /* First segment of sparse/compressed attribute */ 322013ff63bSKonstantin Komarov if (asize + 8 < SIZEOF_NONRESIDENT_EX) 323013ff63bSKonstantin Komarov return NULL; 324013ff63bSKonstantin Komarov 325013ff63bSKonstantin Komarov tot_size = le64_to_cpu(attr->nres.total_size); 326013ff63bSKonstantin Komarov if (tot_size & t32) 327013ff63bSKonstantin Komarov return NULL; 328013ff63bSKonstantin Komarov 329013ff63bSKonstantin Komarov if (tot_size > alloc_size) 330013ff63bSKonstantin Komarov return NULL; 331013ff63bSKonstantin Komarov } else { 3324342306fSKonstantin Komarov if (asize + 8 < SIZEOF_NONRESIDENT) 3334342306fSKonstantin Komarov return NULL; 3344342306fSKonstantin Komarov 3354342306fSKonstantin Komarov if (attr->nres.c_unit) 3364342306fSKonstantin Komarov return NULL; 337013ff63bSKonstantin Komarov } 3384342306fSKonstantin Komarov 3394342306fSKonstantin Komarov return attr; 3404342306fSKonstantin Komarov } 3414342306fSKonstantin Komarov 3424342306fSKonstantin Komarov /* 343e8b8e97fSKari Argillander * mi_find_attr - Find the attribute by type and name and id. 3444342306fSKonstantin Komarov */ 3454342306fSKonstantin Komarov struct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr, 3464342306fSKonstantin Komarov enum ATTR_TYPE type, const __le16 *name, 347a81f47c4SKonstantin Komarov u8 name_len, const __le16 *id) 3484342306fSKonstantin Komarov { 3494342306fSKonstantin Komarov u32 type_in = le32_to_cpu(type); 3504342306fSKonstantin Komarov u32 atype; 3514342306fSKonstantin Komarov 3524342306fSKonstantin Komarov next_attr: 3534342306fSKonstantin Komarov attr = mi_enum_attr(mi, attr); 3544342306fSKonstantin Komarov if (!attr) 3554342306fSKonstantin Komarov return NULL; 3564342306fSKonstantin Komarov 3574342306fSKonstantin Komarov atype = le32_to_cpu(attr->type); 3584342306fSKonstantin Komarov if (atype > type_in) 3594342306fSKonstantin Komarov return NULL; 3604342306fSKonstantin Komarov 3614342306fSKonstantin Komarov if (atype < type_in) 3624342306fSKonstantin Komarov goto next_attr; 3634342306fSKonstantin Komarov 3644342306fSKonstantin Komarov if (attr->name_len != name_len) 3654342306fSKonstantin Komarov goto next_attr; 3664342306fSKonstantin Komarov 3674342306fSKonstantin Komarov if (name_len && memcmp(attr_name(attr), name, name_len * sizeof(short))) 3684342306fSKonstantin Komarov goto next_attr; 3694342306fSKonstantin Komarov 3704342306fSKonstantin Komarov if (id && *id != attr->id) 3714342306fSKonstantin Komarov goto next_attr; 3724342306fSKonstantin Komarov 3734342306fSKonstantin Komarov return attr; 3744342306fSKonstantin Komarov } 3754342306fSKonstantin Komarov 3764342306fSKonstantin Komarov int mi_write(struct mft_inode *mi, int wait) 3774342306fSKonstantin Komarov { 3784342306fSKonstantin Komarov struct MFT_REC *rec; 3794342306fSKonstantin Komarov int err; 3804342306fSKonstantin Komarov struct ntfs_sb_info *sbi; 3814342306fSKonstantin Komarov 3824342306fSKonstantin Komarov if (!mi->dirty) 3834342306fSKonstantin Komarov return 0; 3844342306fSKonstantin Komarov 3854342306fSKonstantin Komarov sbi = mi->sbi; 3864342306fSKonstantin Komarov rec = mi->mrec; 3874342306fSKonstantin Komarov 3884342306fSKonstantin Komarov err = ntfs_write_bh(sbi, &rec->rhdr, &mi->nb, wait); 3894342306fSKonstantin Komarov if (err) 3904342306fSKonstantin Komarov return err; 3914342306fSKonstantin Komarov 3924342306fSKonstantin Komarov if (mi->rno < sbi->mft.recs_mirr) 3934342306fSKonstantin Komarov sbi->flags |= NTFS_FLAGS_MFTMIRR; 3944342306fSKonstantin Komarov 3954342306fSKonstantin Komarov mi->dirty = false; 3964342306fSKonstantin Komarov 3974342306fSKonstantin Komarov return 0; 3984342306fSKonstantin Komarov } 3994342306fSKonstantin Komarov 4004342306fSKonstantin Komarov int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno, 4014342306fSKonstantin Komarov __le16 flags, bool is_mft) 4024342306fSKonstantin Komarov { 4034342306fSKonstantin Komarov int err; 4044342306fSKonstantin Komarov u16 seq = 1; 4054342306fSKonstantin Komarov struct MFT_REC *rec; 4064342306fSKonstantin Komarov u64 vbo = (u64)rno << sbi->record_bits; 4074342306fSKonstantin Komarov 4084342306fSKonstantin Komarov err = mi_init(mi, sbi, rno); 4094342306fSKonstantin Komarov if (err) 4104342306fSKonstantin Komarov return err; 4114342306fSKonstantin Komarov 4124342306fSKonstantin Komarov rec = mi->mrec; 4134342306fSKonstantin Komarov 4144342306fSKonstantin Komarov if (rno == MFT_REC_MFT) { 4154342306fSKonstantin Komarov ; 4164342306fSKonstantin Komarov } else if (rno < MFT_REC_FREE) { 4174342306fSKonstantin Komarov seq = rno; 4184342306fSKonstantin Komarov } else if (rno >= sbi->mft.used) { 4194342306fSKonstantin Komarov ; 4204342306fSKonstantin Komarov } else if (mi_read(mi, is_mft)) { 4214342306fSKonstantin Komarov ; 4224342306fSKonstantin Komarov } else if (rec->rhdr.sign == NTFS_FILE_SIGNATURE) { 423e8b8e97fSKari Argillander /* Record is reused. Update its sequence number. */ 4244342306fSKonstantin Komarov seq = le16_to_cpu(rec->seq) + 1; 4254342306fSKonstantin Komarov if (!seq) 4264342306fSKonstantin Komarov seq = 1; 4274342306fSKonstantin Komarov } 4284342306fSKonstantin Komarov 4294342306fSKonstantin Komarov memcpy(rec, sbi->new_rec, sbi->record_size); 4304342306fSKonstantin Komarov 4314342306fSKonstantin Komarov rec->seq = cpu_to_le16(seq); 4324342306fSKonstantin Komarov rec->flags = RECORD_FLAG_IN_USE | flags; 43333e70701SKonstantin Komarov if (MFTRECORD_FIXUP_OFFSET == MFTRECORD_FIXUP_OFFSET_3) 43433e70701SKonstantin Komarov rec->mft_record = cpu_to_le32(rno); 4354342306fSKonstantin Komarov 4364342306fSKonstantin Komarov mi->dirty = true; 4374342306fSKonstantin Komarov 4384342306fSKonstantin Komarov if (!mi->nb.nbufs) { 4394342306fSKonstantin Komarov struct ntfs_inode *ni = sbi->mft.ni; 4404342306fSKonstantin Komarov bool lock = false; 4414342306fSKonstantin Komarov 4424342306fSKonstantin Komarov if (is_mounted(sbi) && !is_mft) { 4434342306fSKonstantin Komarov down_read(&ni->file.run_lock); 4444342306fSKonstantin Komarov lock = true; 4454342306fSKonstantin Komarov } 4464342306fSKonstantin Komarov 4474342306fSKonstantin Komarov err = ntfs_get_bh(sbi, &ni->file.run, vbo, sbi->record_size, 4484342306fSKonstantin Komarov &mi->nb); 4494342306fSKonstantin Komarov if (lock) 4504342306fSKonstantin Komarov up_read(&ni->file.run_lock); 4514342306fSKonstantin Komarov } 4524342306fSKonstantin Komarov 4534342306fSKonstantin Komarov return err; 4544342306fSKonstantin Komarov } 4554342306fSKonstantin Komarov 4564342306fSKonstantin Komarov /* 457e8b8e97fSKari Argillander * mi_insert_attr - Reserve space for new attribute. 4584342306fSKonstantin Komarov * 459e8b8e97fSKari Argillander * Return: Not full constructed attribute or NULL if not possible to create. 4604342306fSKonstantin Komarov */ 4614342306fSKonstantin Komarov struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, 4624342306fSKonstantin Komarov const __le16 *name, u8 name_len, u32 asize, 4634342306fSKonstantin Komarov u16 name_off) 4644342306fSKonstantin Komarov { 4654342306fSKonstantin Komarov size_t tail; 4664342306fSKonstantin Komarov struct ATTRIB *attr; 4674342306fSKonstantin Komarov __le16 id; 4684342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 4694342306fSKonstantin Komarov struct ntfs_sb_info *sbi = mi->sbi; 4704342306fSKonstantin Komarov u32 used = le32_to_cpu(rec->used); 4714342306fSKonstantin Komarov const u16 *upcase = sbi->upcase; 4724342306fSKonstantin Komarov 4734342306fSKonstantin Komarov /* Can we insert mi attribute? */ 47496de65a9SKonstantin Komarov if (used + asize > sbi->record_size) 4754342306fSKonstantin Komarov return NULL; 4764342306fSKonstantin Komarov 4774342306fSKonstantin Komarov /* 4784342306fSKonstantin Komarov * Scan through the list of attributes to find the point 4794342306fSKonstantin Komarov * at which we should insert it. 4804342306fSKonstantin Komarov */ 4814342306fSKonstantin Komarov attr = NULL; 4824342306fSKonstantin Komarov while ((attr = mi_enum_attr(mi, attr))) { 48396de65a9SKonstantin Komarov int diff = compare_attr(attr, type, name, name_len, upcase); 48419d1b787SKonstantin Komarov 4854342306fSKonstantin Komarov if (diff < 0) 4864342306fSKonstantin Komarov continue; 4874342306fSKonstantin Komarov 48819d1b787SKonstantin Komarov if (!diff && !is_attr_indexed(attr)) 4894342306fSKonstantin Komarov return NULL; 4904342306fSKonstantin Komarov break; 4914342306fSKonstantin Komarov } 4924342306fSKonstantin Komarov 4934342306fSKonstantin Komarov if (!attr) { 49496de65a9SKonstantin Komarov /* Append. */ 49596de65a9SKonstantin Komarov tail = 8; 4964342306fSKonstantin Komarov attr = Add2Ptr(rec, used - 8); 4974342306fSKonstantin Komarov } else { 49896de65a9SKonstantin Komarov /* Insert before 'attr'. */ 4994342306fSKonstantin Komarov tail = used - PtrOffset(rec, attr); 5004342306fSKonstantin Komarov } 5014342306fSKonstantin Komarov 5024342306fSKonstantin Komarov id = mi_new_attt_id(mi); 5034342306fSKonstantin Komarov 5044342306fSKonstantin Komarov memmove(Add2Ptr(attr, asize), attr, tail); 5054342306fSKonstantin Komarov memset(attr, 0, asize); 5064342306fSKonstantin Komarov 5074342306fSKonstantin Komarov attr->type = type; 5084342306fSKonstantin Komarov attr->size = cpu_to_le32(asize); 5094342306fSKonstantin Komarov attr->name_len = name_len; 5104342306fSKonstantin Komarov attr->name_off = cpu_to_le16(name_off); 5114342306fSKonstantin Komarov attr->id = id; 5124342306fSKonstantin Komarov 5134342306fSKonstantin Komarov memmove(Add2Ptr(attr, name_off), name, name_len * sizeof(short)); 5144342306fSKonstantin Komarov rec->used = cpu_to_le32(used + asize); 5154342306fSKonstantin Komarov 5164342306fSKonstantin Komarov mi->dirty = true; 5174342306fSKonstantin Komarov 5184342306fSKonstantin Komarov return attr; 5194342306fSKonstantin Komarov } 5204342306fSKonstantin Komarov 5214342306fSKonstantin Komarov /* 522e8b8e97fSKari Argillander * mi_remove_attr - Remove the attribute from record. 5234342306fSKonstantin Komarov * 524e8b8e97fSKari Argillander * NOTE: The source attr will point to next attribute. 5254342306fSKonstantin Komarov */ 52678ab59feSKonstantin Komarov bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi, 52778ab59feSKonstantin Komarov struct ATTRIB *attr) 5284342306fSKonstantin Komarov { 5294342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 5304342306fSKonstantin Komarov u32 aoff = PtrOffset(rec, attr); 5314342306fSKonstantin Komarov u32 used = le32_to_cpu(rec->used); 5324342306fSKonstantin Komarov u32 asize = le32_to_cpu(attr->size); 5334342306fSKonstantin Komarov 5344342306fSKonstantin Komarov if (aoff + asize > used) 5354342306fSKonstantin Komarov return false; 5364342306fSKonstantin Komarov 53778ab59feSKonstantin Komarov if (ni && is_attr_indexed(attr)) { 5381918c10eSKonstantin Komarov u16 links = le16_to_cpu(ni->mi.mrec->hard_links); 5391918c10eSKonstantin Komarov struct ATTR_FILE_NAME *fname = 5401918c10eSKonstantin Komarov attr->type != ATTR_NAME ? 5411918c10eSKonstantin Komarov NULL : 5421918c10eSKonstantin Komarov resident_data_ex(attr, 5431918c10eSKonstantin Komarov SIZEOF_ATTRIBUTE_FILENAME); 5441918c10eSKonstantin Komarov if (fname && fname->type == FILE_NAME_DOS) { 5451918c10eSKonstantin Komarov /* Do not decrease links count deleting DOS name. */ 5461918c10eSKonstantin Komarov } else if (!links) { 5471918c10eSKonstantin Komarov /* minor error. Not critical. */ 5481918c10eSKonstantin Komarov } else { 5491918c10eSKonstantin Komarov ni->mi.mrec->hard_links = cpu_to_le16(links - 1); 55078ab59feSKonstantin Komarov ni->mi.dirty = true; 55178ab59feSKonstantin Komarov } 5521918c10eSKonstantin Komarov } 55378ab59feSKonstantin Komarov 5544342306fSKonstantin Komarov used -= asize; 5554342306fSKonstantin Komarov memmove(attr, Add2Ptr(attr, asize), used - aoff); 5564342306fSKonstantin Komarov rec->used = cpu_to_le32(used); 5574342306fSKonstantin Komarov mi->dirty = true; 5584342306fSKonstantin Komarov 5594342306fSKonstantin Komarov return true; 5604342306fSKonstantin Komarov } 5614342306fSKonstantin Komarov 5624342306fSKonstantin Komarov /* bytes = "new attribute size" - "old attribute size" */ 5634342306fSKonstantin Komarov bool mi_resize_attr(struct mft_inode *mi, struct ATTRIB *attr, int bytes) 5644342306fSKonstantin Komarov { 5654342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 5664342306fSKonstantin Komarov u32 aoff = PtrOffset(rec, attr); 5674342306fSKonstantin Komarov u32 total, used = le32_to_cpu(rec->used); 5684342306fSKonstantin Komarov u32 nsize, asize = le32_to_cpu(attr->size); 5694342306fSKonstantin Komarov u32 rsize = le32_to_cpu(attr->res.data_size); 5704342306fSKonstantin Komarov int tail = (int)(used - aoff - asize); 5714342306fSKonstantin Komarov int dsize; 5724342306fSKonstantin Komarov char *next; 5734342306fSKonstantin Komarov 5744342306fSKonstantin Komarov if (tail < 0 || aoff >= used) 5754342306fSKonstantin Komarov return false; 5764342306fSKonstantin Komarov 5774342306fSKonstantin Komarov if (!bytes) 5784342306fSKonstantin Komarov return true; 5794342306fSKonstantin Komarov 5804342306fSKonstantin Komarov total = le32_to_cpu(rec->total); 5814342306fSKonstantin Komarov next = Add2Ptr(attr, asize); 5824342306fSKonstantin Komarov 5834342306fSKonstantin Komarov if (bytes > 0) { 584fa3cacf5SKari Argillander dsize = ALIGN(bytes, 8); 5854342306fSKonstantin Komarov if (used + dsize > total) 5864342306fSKonstantin Komarov return false; 5874342306fSKonstantin Komarov nsize = asize + dsize; 588e8b8e97fSKari Argillander /* Move tail */ 5894342306fSKonstantin Komarov memmove(next + dsize, next, tail); 5904342306fSKonstantin Komarov memset(next, 0, dsize); 5914342306fSKonstantin Komarov used += dsize; 5924342306fSKonstantin Komarov rsize += dsize; 5934342306fSKonstantin Komarov } else { 594fa3cacf5SKari Argillander dsize = ALIGN(-bytes, 8); 5954342306fSKonstantin Komarov if (dsize > asize) 5964342306fSKonstantin Komarov return false; 5974342306fSKonstantin Komarov nsize = asize - dsize; 5984342306fSKonstantin Komarov memmove(next - dsize, next, tail); 5994342306fSKonstantin Komarov used -= dsize; 6004342306fSKonstantin Komarov rsize -= dsize; 6014342306fSKonstantin Komarov } 6024342306fSKonstantin Komarov 6034342306fSKonstantin Komarov rec->used = cpu_to_le32(used); 6044342306fSKonstantin Komarov attr->size = cpu_to_le32(nsize); 6054342306fSKonstantin Komarov if (!attr->non_res) 6064342306fSKonstantin Komarov attr->res.data_size = cpu_to_le32(rsize); 6074342306fSKonstantin Komarov mi->dirty = true; 6084342306fSKonstantin Komarov 6094342306fSKonstantin Komarov return true; 6104342306fSKonstantin Komarov } 6114342306fSKonstantin Komarov 612bd6ae049SKonstantin Komarov /* 613bd6ae049SKonstantin Komarov * Pack runs in MFT record. 614bd6ae049SKonstantin Komarov * If failed record is not changed. 615bd6ae049SKonstantin Komarov */ 6164342306fSKonstantin Komarov int mi_pack_runs(struct mft_inode *mi, struct ATTRIB *attr, 6174342306fSKonstantin Komarov struct runs_tree *run, CLST len) 6184342306fSKonstantin Komarov { 6194342306fSKonstantin Komarov int err = 0; 6204342306fSKonstantin Komarov struct ntfs_sb_info *sbi = mi->sbi; 6214342306fSKonstantin Komarov u32 new_run_size; 6224342306fSKonstantin Komarov CLST plen; 6234342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 6244342306fSKonstantin Komarov CLST svcn = le64_to_cpu(attr->nres.svcn); 6254342306fSKonstantin Komarov u32 used = le32_to_cpu(rec->used); 6264342306fSKonstantin Komarov u32 aoff = PtrOffset(rec, attr); 6274342306fSKonstantin Komarov u32 asize = le32_to_cpu(attr->size); 6284342306fSKonstantin Komarov char *next = Add2Ptr(attr, asize); 6294342306fSKonstantin Komarov u16 run_off = le16_to_cpu(attr->nres.run_off); 6304342306fSKonstantin Komarov u32 run_size = asize - run_off; 6314342306fSKonstantin Komarov u32 tail = used - aoff - asize; 6324342306fSKonstantin Komarov u32 dsize = sbi->record_size - used; 6334342306fSKonstantin Komarov 634e8b8e97fSKari Argillander /* Make a maximum gap in current record. */ 6354342306fSKonstantin Komarov memmove(next + dsize, next, tail); 6364342306fSKonstantin Komarov 637e8b8e97fSKari Argillander /* Pack as much as possible. */ 6384342306fSKonstantin Komarov err = run_pack(run, svcn, len, Add2Ptr(attr, run_off), run_size + dsize, 6394342306fSKonstantin Komarov &plen); 6404342306fSKonstantin Komarov if (err < 0) { 6414342306fSKonstantin Komarov memmove(next, next + dsize, tail); 6424342306fSKonstantin Komarov return err; 6434342306fSKonstantin Komarov } 6444342306fSKonstantin Komarov 645fa3cacf5SKari Argillander new_run_size = ALIGN(err, 8); 6464342306fSKonstantin Komarov 6474342306fSKonstantin Komarov memmove(next + new_run_size - run_size, next + dsize, tail); 6484342306fSKonstantin Komarov 6494342306fSKonstantin Komarov attr->size = cpu_to_le32(asize + new_run_size - run_size); 6504342306fSKonstantin Komarov attr->nres.evcn = cpu_to_le64(svcn + plen - 1); 6514342306fSKonstantin Komarov rec->used = cpu_to_le32(used + new_run_size - run_size); 6524342306fSKonstantin Komarov mi->dirty = true; 6534342306fSKonstantin Komarov 6544342306fSKonstantin Komarov return 0; 6554342306fSKonstantin Komarov } 656