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)) { 1274342306fSKonstantin Komarov if (!is_mft) { 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 } 1514342306fSKonstantin Komarov err = attr_load_runs_vcn(mft_ni, ATTR_DATA, NULL, 0, &mft_ni->file.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: 1834342306fSKonstantin Komarov return err; 1844342306fSKonstantin Komarov } 1854342306fSKonstantin Komarov 1864342306fSKonstantin Komarov struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) 1874342306fSKonstantin Komarov { 1884342306fSKonstantin Komarov const struct MFT_REC *rec = mi->mrec; 1894342306fSKonstantin Komarov u32 used = le32_to_cpu(rec->used); 1904342306fSKonstantin Komarov u32 t32, off, asize; 1914342306fSKonstantin Komarov u16 t16; 1924342306fSKonstantin Komarov 1934342306fSKonstantin Komarov if (!attr) { 1944342306fSKonstantin Komarov u32 total = le32_to_cpu(rec->total); 1954342306fSKonstantin Komarov 1964342306fSKonstantin Komarov off = le16_to_cpu(rec->attr_off); 1974342306fSKonstantin Komarov 1984342306fSKonstantin Komarov if (used > total) 1994342306fSKonstantin Komarov return NULL; 2004342306fSKonstantin Komarov 2014342306fSKonstantin Komarov if (off >= used || off < MFTRECORD_FIXUP_OFFSET_1 || 202fa3cacf5SKari Argillander !IS_ALIGNED(off, 4)) { 2034342306fSKonstantin Komarov return NULL; 2044342306fSKonstantin Komarov } 2054342306fSKonstantin Komarov 206e8b8e97fSKari Argillander /* Skip non-resident records. */ 2074342306fSKonstantin Komarov if (!is_rec_inuse(rec)) 2084342306fSKonstantin Komarov return NULL; 2094342306fSKonstantin Komarov 2104342306fSKonstantin Komarov attr = Add2Ptr(rec, off); 2114342306fSKonstantin Komarov } else { 212e8b8e97fSKari Argillander /* Check if input attr inside record. */ 2134342306fSKonstantin Komarov off = PtrOffset(rec, attr); 2144342306fSKonstantin Komarov if (off >= used) 2154342306fSKonstantin Komarov return NULL; 2164342306fSKonstantin Komarov 2174342306fSKonstantin Komarov asize = le32_to_cpu(attr->size); 2184342306fSKonstantin Komarov if (asize < SIZEOF_RESIDENT) { 219d3624466SKonstantin Komarov /* Impossible 'cause we should not return such attribute. */ 2204342306fSKonstantin Komarov return NULL; 2214342306fSKonstantin Komarov } 2224342306fSKonstantin Komarov 2234342306fSKonstantin Komarov attr = Add2Ptr(attr, asize); 2244342306fSKonstantin Komarov off += asize; 2254342306fSKonstantin Komarov } 2264342306fSKonstantin Komarov 2274342306fSKonstantin Komarov asize = le32_to_cpu(attr->size); 2284342306fSKonstantin Komarov 229e8b8e97fSKari Argillander /* Can we use the first field (attr->type). */ 2304342306fSKonstantin Komarov if (off + 8 > used) { 231fa3cacf5SKari Argillander static_assert(ALIGN(sizeof(enum ATTR_TYPE), 8) == 8); 2324342306fSKonstantin Komarov return NULL; 2334342306fSKonstantin Komarov } 2344342306fSKonstantin Komarov 2354342306fSKonstantin Komarov if (attr->type == ATTR_END) { 236e8b8e97fSKari Argillander /* End of enumeration. */ 2374342306fSKonstantin Komarov return NULL; 2384342306fSKonstantin Komarov } 2394342306fSKonstantin Komarov 240e8b8e97fSKari Argillander /* 0x100 is last known attribute for now. */ 2414342306fSKonstantin Komarov t32 = le32_to_cpu(attr->type); 2424342306fSKonstantin Komarov if ((t32 & 0xf) || (t32 > 0x100)) 2434342306fSKonstantin Komarov return NULL; 2444342306fSKonstantin Komarov 245e8b8e97fSKari Argillander /* Check boundary. */ 2464342306fSKonstantin Komarov if (off + asize > used) 2474342306fSKonstantin Komarov return NULL; 2484342306fSKonstantin Komarov 249e8b8e97fSKari Argillander /* Check size of attribute. */ 2504342306fSKonstantin Komarov if (!attr->non_res) { 2514342306fSKonstantin Komarov if (asize < SIZEOF_RESIDENT) 2524342306fSKonstantin Komarov return NULL; 2534342306fSKonstantin Komarov 2544342306fSKonstantin Komarov t16 = le16_to_cpu(attr->res.data_off); 2554342306fSKonstantin Komarov 2564342306fSKonstantin Komarov if (t16 > asize) 2574342306fSKonstantin Komarov return NULL; 2584342306fSKonstantin Komarov 2594342306fSKonstantin Komarov t32 = le32_to_cpu(attr->res.data_size); 2604342306fSKonstantin Komarov if (t16 + t32 > asize) 2614342306fSKonstantin Komarov return NULL; 2624342306fSKonstantin Komarov 2634342306fSKonstantin Komarov return attr; 2644342306fSKonstantin Komarov } 2654342306fSKonstantin Komarov 266e8b8e97fSKari Argillander /* Check some nonresident fields. */ 2674342306fSKonstantin Komarov if (attr->name_len && 2684342306fSKonstantin Komarov le16_to_cpu(attr->name_off) + sizeof(short) * attr->name_len > 2694342306fSKonstantin Komarov le16_to_cpu(attr->nres.run_off)) { 2704342306fSKonstantin Komarov return NULL; 2714342306fSKonstantin Komarov } 2724342306fSKonstantin Komarov 2734342306fSKonstantin Komarov if (attr->nres.svcn || !is_attr_ext(attr)) { 2744342306fSKonstantin Komarov if (asize + 8 < SIZEOF_NONRESIDENT) 2754342306fSKonstantin Komarov return NULL; 2764342306fSKonstantin Komarov 2774342306fSKonstantin Komarov if (attr->nres.c_unit) 2784342306fSKonstantin Komarov return NULL; 2794342306fSKonstantin Komarov } else if (asize + 8 < SIZEOF_NONRESIDENT_EX) 2804342306fSKonstantin Komarov return NULL; 2814342306fSKonstantin Komarov 2824342306fSKonstantin Komarov return attr; 2834342306fSKonstantin Komarov } 2844342306fSKonstantin Komarov 2854342306fSKonstantin Komarov /* 286e8b8e97fSKari Argillander * mi_find_attr - Find the attribute by type and name and id. 2874342306fSKonstantin Komarov */ 2884342306fSKonstantin Komarov struct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr, 2894342306fSKonstantin Komarov enum ATTR_TYPE type, const __le16 *name, 2904342306fSKonstantin Komarov size_t name_len, const __le16 *id) 2914342306fSKonstantin Komarov { 2924342306fSKonstantin Komarov u32 type_in = le32_to_cpu(type); 2934342306fSKonstantin Komarov u32 atype; 2944342306fSKonstantin Komarov 2954342306fSKonstantin Komarov next_attr: 2964342306fSKonstantin Komarov attr = mi_enum_attr(mi, attr); 2974342306fSKonstantin Komarov if (!attr) 2984342306fSKonstantin Komarov return NULL; 2994342306fSKonstantin Komarov 3004342306fSKonstantin Komarov atype = le32_to_cpu(attr->type); 3014342306fSKonstantin Komarov if (atype > type_in) 3024342306fSKonstantin Komarov return NULL; 3034342306fSKonstantin Komarov 3044342306fSKonstantin Komarov if (atype < type_in) 3054342306fSKonstantin Komarov goto next_attr; 3064342306fSKonstantin Komarov 3074342306fSKonstantin Komarov if (attr->name_len != name_len) 3084342306fSKonstantin Komarov goto next_attr; 3094342306fSKonstantin Komarov 3104342306fSKonstantin Komarov if (name_len && memcmp(attr_name(attr), name, name_len * sizeof(short))) 3114342306fSKonstantin Komarov goto next_attr; 3124342306fSKonstantin Komarov 3134342306fSKonstantin Komarov if (id && *id != attr->id) 3144342306fSKonstantin Komarov goto next_attr; 3154342306fSKonstantin Komarov 3164342306fSKonstantin Komarov return attr; 3174342306fSKonstantin Komarov } 3184342306fSKonstantin Komarov 3194342306fSKonstantin Komarov int mi_write(struct mft_inode *mi, int wait) 3204342306fSKonstantin Komarov { 3214342306fSKonstantin Komarov struct MFT_REC *rec; 3224342306fSKonstantin Komarov int err; 3234342306fSKonstantin Komarov struct ntfs_sb_info *sbi; 3244342306fSKonstantin Komarov 3254342306fSKonstantin Komarov if (!mi->dirty) 3264342306fSKonstantin Komarov return 0; 3274342306fSKonstantin Komarov 3284342306fSKonstantin Komarov sbi = mi->sbi; 3294342306fSKonstantin Komarov rec = mi->mrec; 3304342306fSKonstantin Komarov 3314342306fSKonstantin Komarov err = ntfs_write_bh(sbi, &rec->rhdr, &mi->nb, wait); 3324342306fSKonstantin Komarov if (err) 3334342306fSKonstantin Komarov return err; 3344342306fSKonstantin Komarov 3354342306fSKonstantin Komarov if (mi->rno < sbi->mft.recs_mirr) 3364342306fSKonstantin Komarov sbi->flags |= NTFS_FLAGS_MFTMIRR; 3374342306fSKonstantin Komarov 3384342306fSKonstantin Komarov mi->dirty = false; 3394342306fSKonstantin Komarov 3404342306fSKonstantin Komarov return 0; 3414342306fSKonstantin Komarov } 3424342306fSKonstantin Komarov 3434342306fSKonstantin Komarov int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno, 3444342306fSKonstantin Komarov __le16 flags, bool is_mft) 3454342306fSKonstantin Komarov { 3464342306fSKonstantin Komarov int err; 3474342306fSKonstantin Komarov u16 seq = 1; 3484342306fSKonstantin Komarov struct MFT_REC *rec; 3494342306fSKonstantin Komarov u64 vbo = (u64)rno << sbi->record_bits; 3504342306fSKonstantin Komarov 3514342306fSKonstantin Komarov err = mi_init(mi, sbi, rno); 3524342306fSKonstantin Komarov if (err) 3534342306fSKonstantin Komarov return err; 3544342306fSKonstantin Komarov 3554342306fSKonstantin Komarov rec = mi->mrec; 3564342306fSKonstantin Komarov 3574342306fSKonstantin Komarov if (rno == MFT_REC_MFT) { 3584342306fSKonstantin Komarov ; 3594342306fSKonstantin Komarov } else if (rno < MFT_REC_FREE) { 3604342306fSKonstantin Komarov seq = rno; 3614342306fSKonstantin Komarov } else if (rno >= sbi->mft.used) { 3624342306fSKonstantin Komarov ; 3634342306fSKonstantin Komarov } else if (mi_read(mi, is_mft)) { 3644342306fSKonstantin Komarov ; 3654342306fSKonstantin Komarov } else if (rec->rhdr.sign == NTFS_FILE_SIGNATURE) { 366e8b8e97fSKari Argillander /* Record is reused. Update its sequence number. */ 3674342306fSKonstantin Komarov seq = le16_to_cpu(rec->seq) + 1; 3684342306fSKonstantin Komarov if (!seq) 3694342306fSKonstantin Komarov seq = 1; 3704342306fSKonstantin Komarov } 3714342306fSKonstantin Komarov 3724342306fSKonstantin Komarov memcpy(rec, sbi->new_rec, sbi->record_size); 3734342306fSKonstantin Komarov 3744342306fSKonstantin Komarov rec->seq = cpu_to_le16(seq); 3754342306fSKonstantin Komarov rec->flags = RECORD_FLAG_IN_USE | flags; 3764342306fSKonstantin Komarov 3774342306fSKonstantin Komarov mi->dirty = true; 3784342306fSKonstantin Komarov 3794342306fSKonstantin Komarov if (!mi->nb.nbufs) { 3804342306fSKonstantin Komarov struct ntfs_inode *ni = sbi->mft.ni; 3814342306fSKonstantin Komarov bool lock = false; 3824342306fSKonstantin Komarov 3834342306fSKonstantin Komarov if (is_mounted(sbi) && !is_mft) { 3844342306fSKonstantin Komarov down_read(&ni->file.run_lock); 3854342306fSKonstantin Komarov lock = true; 3864342306fSKonstantin Komarov } 3874342306fSKonstantin Komarov 3884342306fSKonstantin Komarov err = ntfs_get_bh(sbi, &ni->file.run, vbo, sbi->record_size, 3894342306fSKonstantin Komarov &mi->nb); 3904342306fSKonstantin Komarov if (lock) 3914342306fSKonstantin Komarov up_read(&ni->file.run_lock); 3924342306fSKonstantin Komarov } 3934342306fSKonstantin Komarov 3944342306fSKonstantin Komarov return err; 3954342306fSKonstantin Komarov } 3964342306fSKonstantin Komarov 3974342306fSKonstantin Komarov /* 398e8b8e97fSKari Argillander * mi_mark_free - Mark record as unused and marks it as free in bitmap. 3994342306fSKonstantin Komarov */ 4004342306fSKonstantin Komarov void mi_mark_free(struct mft_inode *mi) 4014342306fSKonstantin Komarov { 4024342306fSKonstantin Komarov CLST rno = mi->rno; 4034342306fSKonstantin Komarov struct ntfs_sb_info *sbi = mi->sbi; 4044342306fSKonstantin Komarov 4054342306fSKonstantin Komarov if (rno >= MFT_REC_RESERVED && rno < MFT_REC_FREE) { 4064342306fSKonstantin Komarov ntfs_clear_mft_tail(sbi, rno, rno + 1); 4074342306fSKonstantin Komarov mi->dirty = false; 4084342306fSKonstantin Komarov return; 4094342306fSKonstantin Komarov } 4104342306fSKonstantin Komarov 4114342306fSKonstantin Komarov if (mi->mrec) { 4124342306fSKonstantin Komarov clear_rec_inuse(mi->mrec); 4134342306fSKonstantin Komarov mi->dirty = true; 4144342306fSKonstantin Komarov mi_write(mi, 0); 4154342306fSKonstantin Komarov } 4164342306fSKonstantin Komarov ntfs_mark_rec_free(sbi, rno); 4174342306fSKonstantin Komarov } 4184342306fSKonstantin Komarov 4194342306fSKonstantin Komarov /* 420e8b8e97fSKari Argillander * mi_insert_attr - Reserve space for new attribute. 4214342306fSKonstantin Komarov * 422e8b8e97fSKari Argillander * Return: Not full constructed attribute or NULL if not possible to create. 4234342306fSKonstantin Komarov */ 4244342306fSKonstantin Komarov struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, 4254342306fSKonstantin Komarov const __le16 *name, u8 name_len, u32 asize, 4264342306fSKonstantin Komarov u16 name_off) 4274342306fSKonstantin Komarov { 4284342306fSKonstantin Komarov size_t tail; 4294342306fSKonstantin Komarov struct ATTRIB *attr; 4304342306fSKonstantin Komarov __le16 id; 4314342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 4324342306fSKonstantin Komarov struct ntfs_sb_info *sbi = mi->sbi; 4334342306fSKonstantin Komarov u32 used = le32_to_cpu(rec->used); 4344342306fSKonstantin Komarov const u16 *upcase = sbi->upcase; 4354342306fSKonstantin Komarov int diff; 4364342306fSKonstantin Komarov 4374342306fSKonstantin Komarov /* Can we insert mi attribute? */ 4384342306fSKonstantin Komarov if (used + asize > mi->sbi->record_size) 4394342306fSKonstantin Komarov return NULL; 4404342306fSKonstantin Komarov 4414342306fSKonstantin Komarov /* 4424342306fSKonstantin Komarov * Scan through the list of attributes to find the point 4434342306fSKonstantin Komarov * at which we should insert it. 4444342306fSKonstantin Komarov */ 4454342306fSKonstantin Komarov attr = NULL; 4464342306fSKonstantin Komarov while ((attr = mi_enum_attr(mi, attr))) { 4474342306fSKonstantin Komarov diff = compare_attr(attr, type, name, name_len, upcase); 448*19d1b787SKonstantin Komarov 4494342306fSKonstantin Komarov if (diff < 0) 4504342306fSKonstantin Komarov continue; 4514342306fSKonstantin Komarov 452*19d1b787SKonstantin Komarov if (!diff && !is_attr_indexed(attr)) 4534342306fSKonstantin Komarov return NULL; 4544342306fSKonstantin Komarov break; 4554342306fSKonstantin Komarov } 4564342306fSKonstantin Komarov 4574342306fSKonstantin Komarov if (!attr) { 458e8b8e97fSKari Argillander tail = 8; /* Not used, just to suppress warning. */ 4594342306fSKonstantin Komarov attr = Add2Ptr(rec, used - 8); 4604342306fSKonstantin Komarov } else { 4614342306fSKonstantin Komarov tail = used - PtrOffset(rec, attr); 4624342306fSKonstantin Komarov } 4634342306fSKonstantin Komarov 4644342306fSKonstantin Komarov id = mi_new_attt_id(mi); 4654342306fSKonstantin Komarov 4664342306fSKonstantin Komarov memmove(Add2Ptr(attr, asize), attr, tail); 4674342306fSKonstantin Komarov memset(attr, 0, asize); 4684342306fSKonstantin Komarov 4694342306fSKonstantin Komarov attr->type = type; 4704342306fSKonstantin Komarov attr->size = cpu_to_le32(asize); 4714342306fSKonstantin Komarov attr->name_len = name_len; 4724342306fSKonstantin Komarov attr->name_off = cpu_to_le16(name_off); 4734342306fSKonstantin Komarov attr->id = id; 4744342306fSKonstantin Komarov 4754342306fSKonstantin Komarov memmove(Add2Ptr(attr, name_off), name, name_len * sizeof(short)); 4764342306fSKonstantin Komarov rec->used = cpu_to_le32(used + asize); 4774342306fSKonstantin Komarov 4784342306fSKonstantin Komarov mi->dirty = true; 4794342306fSKonstantin Komarov 4804342306fSKonstantin Komarov return attr; 4814342306fSKonstantin Komarov } 4824342306fSKonstantin Komarov 4834342306fSKonstantin Komarov /* 484e8b8e97fSKari Argillander * mi_remove_attr - Remove the attribute from record. 4854342306fSKonstantin Komarov * 486e8b8e97fSKari Argillander * NOTE: The source attr will point to next attribute. 4874342306fSKonstantin Komarov */ 48878ab59feSKonstantin Komarov bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi, 48978ab59feSKonstantin Komarov struct ATTRIB *attr) 4904342306fSKonstantin Komarov { 4914342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 4924342306fSKonstantin Komarov u32 aoff = PtrOffset(rec, attr); 4934342306fSKonstantin Komarov u32 used = le32_to_cpu(rec->used); 4944342306fSKonstantin Komarov u32 asize = le32_to_cpu(attr->size); 4954342306fSKonstantin Komarov 4964342306fSKonstantin Komarov if (aoff + asize > used) 4974342306fSKonstantin Komarov return false; 4984342306fSKonstantin Komarov 49978ab59feSKonstantin Komarov if (ni && is_attr_indexed(attr)) { 50078ab59feSKonstantin Komarov le16_add_cpu(&ni->mi.mrec->hard_links, -1); 50178ab59feSKonstantin Komarov ni->mi.dirty = true; 50278ab59feSKonstantin Komarov } 50378ab59feSKonstantin Komarov 5044342306fSKonstantin Komarov used -= asize; 5054342306fSKonstantin Komarov memmove(attr, Add2Ptr(attr, asize), used - aoff); 5064342306fSKonstantin Komarov rec->used = cpu_to_le32(used); 5074342306fSKonstantin Komarov mi->dirty = true; 5084342306fSKonstantin Komarov 5094342306fSKonstantin Komarov return true; 5104342306fSKonstantin Komarov } 5114342306fSKonstantin Komarov 5124342306fSKonstantin Komarov /* bytes = "new attribute size" - "old attribute size" */ 5134342306fSKonstantin Komarov bool mi_resize_attr(struct mft_inode *mi, struct ATTRIB *attr, int bytes) 5144342306fSKonstantin Komarov { 5154342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 5164342306fSKonstantin Komarov u32 aoff = PtrOffset(rec, attr); 5174342306fSKonstantin Komarov u32 total, used = le32_to_cpu(rec->used); 5184342306fSKonstantin Komarov u32 nsize, asize = le32_to_cpu(attr->size); 5194342306fSKonstantin Komarov u32 rsize = le32_to_cpu(attr->res.data_size); 5204342306fSKonstantin Komarov int tail = (int)(used - aoff - asize); 5214342306fSKonstantin Komarov int dsize; 5224342306fSKonstantin Komarov char *next; 5234342306fSKonstantin Komarov 5244342306fSKonstantin Komarov if (tail < 0 || aoff >= used) 5254342306fSKonstantin Komarov return false; 5264342306fSKonstantin Komarov 5274342306fSKonstantin Komarov if (!bytes) 5284342306fSKonstantin Komarov return true; 5294342306fSKonstantin Komarov 5304342306fSKonstantin Komarov total = le32_to_cpu(rec->total); 5314342306fSKonstantin Komarov next = Add2Ptr(attr, asize); 5324342306fSKonstantin Komarov 5334342306fSKonstantin Komarov if (bytes > 0) { 534fa3cacf5SKari Argillander dsize = ALIGN(bytes, 8); 5354342306fSKonstantin Komarov if (used + dsize > total) 5364342306fSKonstantin Komarov return false; 5374342306fSKonstantin Komarov nsize = asize + dsize; 538e8b8e97fSKari Argillander /* Move tail */ 5394342306fSKonstantin Komarov memmove(next + dsize, next, tail); 5404342306fSKonstantin Komarov memset(next, 0, dsize); 5414342306fSKonstantin Komarov used += dsize; 5424342306fSKonstantin Komarov rsize += dsize; 5434342306fSKonstantin Komarov } else { 544fa3cacf5SKari Argillander dsize = ALIGN(-bytes, 8); 5454342306fSKonstantin Komarov if (dsize > asize) 5464342306fSKonstantin Komarov return false; 5474342306fSKonstantin Komarov nsize = asize - dsize; 5484342306fSKonstantin Komarov memmove(next - dsize, next, tail); 5494342306fSKonstantin Komarov used -= dsize; 5504342306fSKonstantin Komarov rsize -= dsize; 5514342306fSKonstantin Komarov } 5524342306fSKonstantin Komarov 5534342306fSKonstantin Komarov rec->used = cpu_to_le32(used); 5544342306fSKonstantin Komarov attr->size = cpu_to_le32(nsize); 5554342306fSKonstantin Komarov if (!attr->non_res) 5564342306fSKonstantin Komarov attr->res.data_size = cpu_to_le32(rsize); 5574342306fSKonstantin Komarov mi->dirty = true; 5584342306fSKonstantin Komarov 5594342306fSKonstantin Komarov return true; 5604342306fSKonstantin Komarov } 5614342306fSKonstantin Komarov 5624342306fSKonstantin Komarov int mi_pack_runs(struct mft_inode *mi, struct ATTRIB *attr, 5634342306fSKonstantin Komarov struct runs_tree *run, CLST len) 5644342306fSKonstantin Komarov { 5654342306fSKonstantin Komarov int err = 0; 5664342306fSKonstantin Komarov struct ntfs_sb_info *sbi = mi->sbi; 5674342306fSKonstantin Komarov u32 new_run_size; 5684342306fSKonstantin Komarov CLST plen; 5694342306fSKonstantin Komarov struct MFT_REC *rec = mi->mrec; 5704342306fSKonstantin Komarov CLST svcn = le64_to_cpu(attr->nres.svcn); 5714342306fSKonstantin Komarov u32 used = le32_to_cpu(rec->used); 5724342306fSKonstantin Komarov u32 aoff = PtrOffset(rec, attr); 5734342306fSKonstantin Komarov u32 asize = le32_to_cpu(attr->size); 5744342306fSKonstantin Komarov char *next = Add2Ptr(attr, asize); 5754342306fSKonstantin Komarov u16 run_off = le16_to_cpu(attr->nres.run_off); 5764342306fSKonstantin Komarov u32 run_size = asize - run_off; 5774342306fSKonstantin Komarov u32 tail = used - aoff - asize; 5784342306fSKonstantin Komarov u32 dsize = sbi->record_size - used; 5794342306fSKonstantin Komarov 580e8b8e97fSKari Argillander /* Make a maximum gap in current record. */ 5814342306fSKonstantin Komarov memmove(next + dsize, next, tail); 5824342306fSKonstantin Komarov 583e8b8e97fSKari Argillander /* Pack as much as possible. */ 5844342306fSKonstantin Komarov err = run_pack(run, svcn, len, Add2Ptr(attr, run_off), run_size + dsize, 5854342306fSKonstantin Komarov &plen); 5864342306fSKonstantin Komarov if (err < 0) { 5874342306fSKonstantin Komarov memmove(next, next + dsize, tail); 5884342306fSKonstantin Komarov return err; 5894342306fSKonstantin Komarov } 5904342306fSKonstantin Komarov 591fa3cacf5SKari Argillander new_run_size = ALIGN(err, 8); 5924342306fSKonstantin Komarov 5934342306fSKonstantin Komarov memmove(next + new_run_size - run_size, next + dsize, tail); 5944342306fSKonstantin Komarov 5954342306fSKonstantin Komarov attr->size = cpu_to_le32(asize + new_run_size - run_size); 5964342306fSKonstantin Komarov attr->nres.evcn = cpu_to_le64(svcn + plen - 1); 5974342306fSKonstantin Komarov rec->used = cpu_to_le32(used + new_run_size - run_size); 5984342306fSKonstantin Komarov mi->dirty = true; 5994342306fSKonstantin Komarov 6004342306fSKonstantin Komarov return 0; 6014342306fSKonstantin Komarov } 602