182cae269SKonstantin Komarov // SPDX-License-Identifier: GPL-2.0
282cae269SKonstantin Komarov /*
382cae269SKonstantin Komarov *
482cae269SKonstantin Komarov * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
582cae269SKonstantin Komarov *
682cae269SKonstantin Komarov */
782cae269SKonstantin Komarov
882cae269SKonstantin Komarov #include <linux/blkdev.h>
982cae269SKonstantin Komarov #include <linux/buffer_head.h>
1082cae269SKonstantin Komarov #include <linux/fs.h>
11b5322eb1SKari Argillander #include <linux/kernel.h>
127832e123SKonstantin Komarov #include <linux/nls.h>
1382cae269SKonstantin Komarov
1482cae269SKonstantin Komarov #include "debug.h"
1582cae269SKonstantin Komarov #include "ntfs.h"
1682cae269SKonstantin Komarov #include "ntfs_fs.h"
1782cae269SKonstantin Komarov
1882cae269SKonstantin Komarov // clang-format off
1982cae269SKonstantin Komarov const struct cpu_str NAME_MFT = {
2082cae269SKonstantin Komarov 4, 0, { '$', 'M', 'F', 'T' },
2182cae269SKonstantin Komarov };
2282cae269SKonstantin Komarov const struct cpu_str NAME_MIRROR = {
2382cae269SKonstantin Komarov 8, 0, { '$', 'M', 'F', 'T', 'M', 'i', 'r', 'r' },
2482cae269SKonstantin Komarov };
2582cae269SKonstantin Komarov const struct cpu_str NAME_LOGFILE = {
2682cae269SKonstantin Komarov 8, 0, { '$', 'L', 'o', 'g', 'F', 'i', 'l', 'e' },
2782cae269SKonstantin Komarov };
2882cae269SKonstantin Komarov const struct cpu_str NAME_VOLUME = {
2982cae269SKonstantin Komarov 7, 0, { '$', 'V', 'o', 'l', 'u', 'm', 'e' },
3082cae269SKonstantin Komarov };
3182cae269SKonstantin Komarov const struct cpu_str NAME_ATTRDEF = {
3282cae269SKonstantin Komarov 8, 0, { '$', 'A', 't', 't', 'r', 'D', 'e', 'f' },
3382cae269SKonstantin Komarov };
3482cae269SKonstantin Komarov const struct cpu_str NAME_ROOT = {
3582cae269SKonstantin Komarov 1, 0, { '.' },
3682cae269SKonstantin Komarov };
3782cae269SKonstantin Komarov const struct cpu_str NAME_BITMAP = {
3882cae269SKonstantin Komarov 7, 0, { '$', 'B', 'i', 't', 'm', 'a', 'p' },
3982cae269SKonstantin Komarov };
4082cae269SKonstantin Komarov const struct cpu_str NAME_BOOT = {
4182cae269SKonstantin Komarov 5, 0, { '$', 'B', 'o', 'o', 't' },
4282cae269SKonstantin Komarov };
4382cae269SKonstantin Komarov const struct cpu_str NAME_BADCLUS = {
4482cae269SKonstantin Komarov 8, 0, { '$', 'B', 'a', 'd', 'C', 'l', 'u', 's' },
4582cae269SKonstantin Komarov };
4682cae269SKonstantin Komarov const struct cpu_str NAME_QUOTA = {
4782cae269SKonstantin Komarov 6, 0, { '$', 'Q', 'u', 'o', 't', 'a' },
4882cae269SKonstantin Komarov };
4982cae269SKonstantin Komarov const struct cpu_str NAME_SECURE = {
5082cae269SKonstantin Komarov 7, 0, { '$', 'S', 'e', 'c', 'u', 'r', 'e' },
5182cae269SKonstantin Komarov };
5282cae269SKonstantin Komarov const struct cpu_str NAME_UPCASE = {
5382cae269SKonstantin Komarov 7, 0, { '$', 'U', 'p', 'C', 'a', 's', 'e' },
5482cae269SKonstantin Komarov };
5582cae269SKonstantin Komarov const struct cpu_str NAME_EXTEND = {
5682cae269SKonstantin Komarov 7, 0, { '$', 'E', 'x', 't', 'e', 'n', 'd' },
5782cae269SKonstantin Komarov };
5882cae269SKonstantin Komarov const struct cpu_str NAME_OBJID = {
5982cae269SKonstantin Komarov 6, 0, { '$', 'O', 'b', 'j', 'I', 'd' },
6082cae269SKonstantin Komarov };
6182cae269SKonstantin Komarov const struct cpu_str NAME_REPARSE = {
6282cae269SKonstantin Komarov 8, 0, { '$', 'R', 'e', 'p', 'a', 'r', 's', 'e' },
6382cae269SKonstantin Komarov };
6482cae269SKonstantin Komarov const struct cpu_str NAME_USNJRNL = {
6582cae269SKonstantin Komarov 8, 0, { '$', 'U', 's', 'n', 'J', 'r', 'n', 'l' },
6682cae269SKonstantin Komarov };
6782cae269SKonstantin Komarov const __le16 BAD_NAME[4] = {
6882cae269SKonstantin Komarov cpu_to_le16('$'), cpu_to_le16('B'), cpu_to_le16('a'), cpu_to_le16('d'),
6982cae269SKonstantin Komarov };
7082cae269SKonstantin Komarov const __le16 I30_NAME[4] = {
7182cae269SKonstantin Komarov cpu_to_le16('$'), cpu_to_le16('I'), cpu_to_le16('3'), cpu_to_le16('0'),
7282cae269SKonstantin Komarov };
7382cae269SKonstantin Komarov const __le16 SII_NAME[4] = {
7482cae269SKonstantin Komarov cpu_to_le16('$'), cpu_to_le16('S'), cpu_to_le16('I'), cpu_to_le16('I'),
7582cae269SKonstantin Komarov };
7682cae269SKonstantin Komarov const __le16 SDH_NAME[4] = {
7782cae269SKonstantin Komarov cpu_to_le16('$'), cpu_to_le16('S'), cpu_to_le16('D'), cpu_to_le16('H'),
7882cae269SKonstantin Komarov };
7982cae269SKonstantin Komarov const __le16 SDS_NAME[4] = {
8082cae269SKonstantin Komarov cpu_to_le16('$'), cpu_to_le16('S'), cpu_to_le16('D'), cpu_to_le16('S'),
8182cae269SKonstantin Komarov };
8282cae269SKonstantin Komarov const __le16 SO_NAME[2] = {
8382cae269SKonstantin Komarov cpu_to_le16('$'), cpu_to_le16('O'),
8482cae269SKonstantin Komarov };
8582cae269SKonstantin Komarov const __le16 SQ_NAME[2] = {
8682cae269SKonstantin Komarov cpu_to_le16('$'), cpu_to_le16('Q'),
8782cae269SKonstantin Komarov };
8882cae269SKonstantin Komarov const __le16 SR_NAME[2] = {
8982cae269SKonstantin Komarov cpu_to_le16('$'), cpu_to_le16('R'),
9082cae269SKonstantin Komarov };
9182cae269SKonstantin Komarov
9282cae269SKonstantin Komarov #ifdef CONFIG_NTFS3_LZX_XPRESS
9382cae269SKonstantin Komarov const __le16 WOF_NAME[17] = {
9482cae269SKonstantin Komarov cpu_to_le16('W'), cpu_to_le16('o'), cpu_to_le16('f'), cpu_to_le16('C'),
9582cae269SKonstantin Komarov cpu_to_le16('o'), cpu_to_le16('m'), cpu_to_le16('p'), cpu_to_le16('r'),
9682cae269SKonstantin Komarov cpu_to_le16('e'), cpu_to_le16('s'), cpu_to_le16('s'), cpu_to_le16('e'),
9782cae269SKonstantin Komarov cpu_to_le16('d'), cpu_to_le16('D'), cpu_to_le16('a'), cpu_to_le16('t'),
9882cae269SKonstantin Komarov cpu_to_le16('a'),
9982cae269SKonstantin Komarov };
10082cae269SKonstantin Komarov #endif
10182cae269SKonstantin Komarov
1021d07a9dfSDaniel Pinto static const __le16 CON_NAME[3] = {
1031d07a9dfSDaniel Pinto cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('N'),
1041d07a9dfSDaniel Pinto };
1051d07a9dfSDaniel Pinto
1061d07a9dfSDaniel Pinto static const __le16 NUL_NAME[3] = {
1071d07a9dfSDaniel Pinto cpu_to_le16('N'), cpu_to_le16('U'), cpu_to_le16('L'),
1081d07a9dfSDaniel Pinto };
1091d07a9dfSDaniel Pinto
1101d07a9dfSDaniel Pinto static const __le16 AUX_NAME[3] = {
1111d07a9dfSDaniel Pinto cpu_to_le16('A'), cpu_to_le16('U'), cpu_to_le16('X'),
1121d07a9dfSDaniel Pinto };
1131d07a9dfSDaniel Pinto
1141d07a9dfSDaniel Pinto static const __le16 PRN_NAME[3] = {
1151d07a9dfSDaniel Pinto cpu_to_le16('P'), cpu_to_le16('R'), cpu_to_le16('N'),
1161d07a9dfSDaniel Pinto };
1171d07a9dfSDaniel Pinto
1181d07a9dfSDaniel Pinto static const __le16 COM_NAME[3] = {
1191d07a9dfSDaniel Pinto cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'),
1201d07a9dfSDaniel Pinto };
1211d07a9dfSDaniel Pinto
1221d07a9dfSDaniel Pinto static const __le16 LPT_NAME[3] = {
1231d07a9dfSDaniel Pinto cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'),
1241d07a9dfSDaniel Pinto };
1251d07a9dfSDaniel Pinto
12682cae269SKonstantin Komarov // clang-format on
12782cae269SKonstantin Komarov
12882cae269SKonstantin Komarov /*
129e8b8e97fSKari Argillander * ntfs_fix_pre_write - Insert fixups into @rhdr before writing to disk.
13082cae269SKonstantin Komarov */
ntfs_fix_pre_write(struct NTFS_RECORD_HEADER * rhdr,size_t bytes)13182cae269SKonstantin Komarov bool ntfs_fix_pre_write(struct NTFS_RECORD_HEADER *rhdr, size_t bytes)
13282cae269SKonstantin Komarov {
13382cae269SKonstantin Komarov u16 *fixup, *ptr;
13482cae269SKonstantin Komarov u16 sample;
13582cae269SKonstantin Komarov u16 fo = le16_to_cpu(rhdr->fix_off);
13682cae269SKonstantin Komarov u16 fn = le16_to_cpu(rhdr->fix_num);
13782cae269SKonstantin Komarov
13882cae269SKonstantin Komarov if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
13982cae269SKonstantin Komarov fn * SECTOR_SIZE > bytes) {
14082cae269SKonstantin Komarov return false;
14182cae269SKonstantin Komarov }
14282cae269SKonstantin Komarov
143e8b8e97fSKari Argillander /* Get fixup pointer. */
14482cae269SKonstantin Komarov fixup = Add2Ptr(rhdr, fo);
14582cae269SKonstantin Komarov
14682cae269SKonstantin Komarov if (*fixup >= 0x7FFF)
14782cae269SKonstantin Komarov *fixup = 1;
14882cae269SKonstantin Komarov else
14982cae269SKonstantin Komarov *fixup += 1;
15082cae269SKonstantin Komarov
15182cae269SKonstantin Komarov sample = *fixup;
15282cae269SKonstantin Komarov
15382cae269SKonstantin Komarov ptr = Add2Ptr(rhdr, SECTOR_SIZE - sizeof(short));
15482cae269SKonstantin Komarov
15582cae269SKonstantin Komarov while (fn--) {
15682cae269SKonstantin Komarov *++fixup = *ptr;
15782cae269SKonstantin Komarov *ptr = sample;
15882cae269SKonstantin Komarov ptr += SECTOR_SIZE / sizeof(short);
15982cae269SKonstantin Komarov }
16082cae269SKonstantin Komarov return true;
16182cae269SKonstantin Komarov }
16282cae269SKonstantin Komarov
16382cae269SKonstantin Komarov /*
164e8b8e97fSKari Argillander * ntfs_fix_post_read - Remove fixups after reading from disk.
16582cae269SKonstantin Komarov *
166e8b8e97fSKari Argillander * Return: < 0 if error, 0 if ok, 1 if need to update fixups.
16782cae269SKonstantin Komarov */
ntfs_fix_post_read(struct NTFS_RECORD_HEADER * rhdr,size_t bytes,bool simple)16882cae269SKonstantin Komarov int ntfs_fix_post_read(struct NTFS_RECORD_HEADER *rhdr, size_t bytes,
16982cae269SKonstantin Komarov bool simple)
17082cae269SKonstantin Komarov {
17182cae269SKonstantin Komarov int ret;
17282cae269SKonstantin Komarov u16 *fixup, *ptr;
17382cae269SKonstantin Komarov u16 sample, fo, fn;
17482cae269SKonstantin Komarov
17582cae269SKonstantin Komarov fo = le16_to_cpu(rhdr->fix_off);
17696de65a9SKonstantin Komarov fn = simple ? ((bytes >> SECTOR_SHIFT) + 1) :
17796de65a9SKonstantin Komarov le16_to_cpu(rhdr->fix_num);
17882cae269SKonstantin Komarov
179e8b8e97fSKari Argillander /* Check errors. */
18082cae269SKonstantin Komarov if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
18182cae269SKonstantin Komarov fn * SECTOR_SIZE > bytes) {
182e0f363a9SKonstantin Komarov return -E_NTFS_CORRUPT;
18382cae269SKonstantin Komarov }
18482cae269SKonstantin Komarov
185e8b8e97fSKari Argillander /* Get fixup pointer. */
18682cae269SKonstantin Komarov fixup = Add2Ptr(rhdr, fo);
18782cae269SKonstantin Komarov sample = *fixup;
18882cae269SKonstantin Komarov ptr = Add2Ptr(rhdr, SECTOR_SIZE - sizeof(short));
18982cae269SKonstantin Komarov ret = 0;
19082cae269SKonstantin Komarov
19182cae269SKonstantin Komarov while (fn--) {
192e8b8e97fSKari Argillander /* Test current word. */
19382cae269SKonstantin Komarov if (*ptr != sample) {
19482cae269SKonstantin Komarov /* Fixup does not match! Is it serious error? */
19582cae269SKonstantin Komarov ret = -E_NTFS_FIXUP;
19682cae269SKonstantin Komarov }
19782cae269SKonstantin Komarov
198e8b8e97fSKari Argillander /* Replace fixup. */
19982cae269SKonstantin Komarov *ptr = *++fixup;
20082cae269SKonstantin Komarov ptr += SECTOR_SIZE / sizeof(short);
20182cae269SKonstantin Komarov }
20282cae269SKonstantin Komarov
20382cae269SKonstantin Komarov return ret;
20482cae269SKonstantin Komarov }
20582cae269SKonstantin Komarov
20682cae269SKonstantin Komarov /*
207e8b8e97fSKari Argillander * ntfs_extend_init - Load $Extend file.
20882cae269SKonstantin Komarov */
ntfs_extend_init(struct ntfs_sb_info * sbi)20982cae269SKonstantin Komarov int ntfs_extend_init(struct ntfs_sb_info *sbi)
21082cae269SKonstantin Komarov {
21182cae269SKonstantin Komarov int err;
21282cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
21382cae269SKonstantin Komarov struct inode *inode, *inode2;
21482cae269SKonstantin Komarov struct MFT_REF ref;
21582cae269SKonstantin Komarov
21682cae269SKonstantin Komarov if (sbi->volume.major_ver < 3) {
21782cae269SKonstantin Komarov ntfs_notice(sb, "Skip $Extend 'cause NTFS version");
21882cae269SKonstantin Komarov return 0;
21982cae269SKonstantin Komarov }
22082cae269SKonstantin Komarov
22182cae269SKonstantin Komarov ref.low = cpu_to_le32(MFT_REC_EXTEND);
22282cae269SKonstantin Komarov ref.high = 0;
22382cae269SKonstantin Komarov ref.seq = cpu_to_le16(MFT_REC_EXTEND);
22482cae269SKonstantin Komarov inode = ntfs_iget5(sb, &ref, &NAME_EXTEND);
22582cae269SKonstantin Komarov if (IS_ERR(inode)) {
22682cae269SKonstantin Komarov err = PTR_ERR(inode);
227e43f6ec2SKonstantin Komarov ntfs_err(sb, "Failed to load $Extend (%d).", err);
22882cae269SKonstantin Komarov inode = NULL;
22982cae269SKonstantin Komarov goto out;
23082cae269SKonstantin Komarov }
23182cae269SKonstantin Komarov
232e8b8e97fSKari Argillander /* If ntfs_iget5() reads from disk it never returns bad inode. */
23382cae269SKonstantin Komarov if (!S_ISDIR(inode->i_mode)) {
23482cae269SKonstantin Komarov err = -EINVAL;
23582cae269SKonstantin Komarov goto out;
23682cae269SKonstantin Komarov }
23782cae269SKonstantin Komarov
23882cae269SKonstantin Komarov /* Try to find $ObjId */
23982cae269SKonstantin Komarov inode2 = dir_search_u(inode, &NAME_OBJID, NULL);
24082cae269SKonstantin Komarov if (inode2 && !IS_ERR(inode2)) {
24182cae269SKonstantin Komarov if (is_bad_inode(inode2)) {
24282cae269SKonstantin Komarov iput(inode2);
24382cae269SKonstantin Komarov } else {
24482cae269SKonstantin Komarov sbi->objid.ni = ntfs_i(inode2);
24582cae269SKonstantin Komarov sbi->objid_no = inode2->i_ino;
24682cae269SKonstantin Komarov }
24782cae269SKonstantin Komarov }
24882cae269SKonstantin Komarov
24982cae269SKonstantin Komarov /* Try to find $Quota */
25082cae269SKonstantin Komarov inode2 = dir_search_u(inode, &NAME_QUOTA, NULL);
25182cae269SKonstantin Komarov if (inode2 && !IS_ERR(inode2)) {
25282cae269SKonstantin Komarov sbi->quota_no = inode2->i_ino;
25382cae269SKonstantin Komarov iput(inode2);
25482cae269SKonstantin Komarov }
25582cae269SKonstantin Komarov
25682cae269SKonstantin Komarov /* Try to find $Reparse */
25782cae269SKonstantin Komarov inode2 = dir_search_u(inode, &NAME_REPARSE, NULL);
25882cae269SKonstantin Komarov if (inode2 && !IS_ERR(inode2)) {
25982cae269SKonstantin Komarov sbi->reparse.ni = ntfs_i(inode2);
26082cae269SKonstantin Komarov sbi->reparse_no = inode2->i_ino;
26182cae269SKonstantin Komarov }
26282cae269SKonstantin Komarov
26382cae269SKonstantin Komarov /* Try to find $UsnJrnl */
26482cae269SKonstantin Komarov inode2 = dir_search_u(inode, &NAME_USNJRNL, NULL);
26582cae269SKonstantin Komarov if (inode2 && !IS_ERR(inode2)) {
26682cae269SKonstantin Komarov sbi->usn_jrnl_no = inode2->i_ino;
26782cae269SKonstantin Komarov iput(inode2);
26882cae269SKonstantin Komarov }
26982cae269SKonstantin Komarov
27082cae269SKonstantin Komarov err = 0;
27182cae269SKonstantin Komarov out:
27282cae269SKonstantin Komarov iput(inode);
27382cae269SKonstantin Komarov return err;
27482cae269SKonstantin Komarov }
27582cae269SKonstantin Komarov
ntfs_loadlog_and_replay(struct ntfs_inode * ni,struct ntfs_sb_info * sbi)27682cae269SKonstantin Komarov int ntfs_loadlog_and_replay(struct ntfs_inode *ni, struct ntfs_sb_info *sbi)
27782cae269SKonstantin Komarov {
27882cae269SKonstantin Komarov int err = 0;
27982cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
28082cae269SKonstantin Komarov bool initialized = false;
28182cae269SKonstantin Komarov struct MFT_REF ref;
28282cae269SKonstantin Komarov struct inode *inode;
28382cae269SKonstantin Komarov
284e8b8e97fSKari Argillander /* Check for 4GB. */
28582cae269SKonstantin Komarov if (ni->vfs_inode.i_size >= 0x100000000ull) {
286e43f6ec2SKonstantin Komarov ntfs_err(sb, "\x24LogFile is large than 4G.");
28782cae269SKonstantin Komarov err = -EINVAL;
28882cae269SKonstantin Komarov goto out;
28982cae269SKonstantin Komarov }
29082cae269SKonstantin Komarov
29182cae269SKonstantin Komarov sbi->flags |= NTFS_FLAGS_LOG_REPLAYING;
29282cae269SKonstantin Komarov
29382cae269SKonstantin Komarov ref.low = cpu_to_le32(MFT_REC_MFT);
29482cae269SKonstantin Komarov ref.high = 0;
29582cae269SKonstantin Komarov ref.seq = cpu_to_le16(1);
29682cae269SKonstantin Komarov
29782cae269SKonstantin Komarov inode = ntfs_iget5(sb, &ref, NULL);
29882cae269SKonstantin Komarov
29982cae269SKonstantin Komarov if (IS_ERR(inode))
30082cae269SKonstantin Komarov inode = NULL;
30182cae269SKonstantin Komarov
30282cae269SKonstantin Komarov if (!inode) {
303e8b8e97fSKari Argillander /* Try to use MFT copy. */
30482cae269SKonstantin Komarov u64 t64 = sbi->mft.lbo;
30582cae269SKonstantin Komarov
30682cae269SKonstantin Komarov sbi->mft.lbo = sbi->mft.lbo2;
30782cae269SKonstantin Komarov inode = ntfs_iget5(sb, &ref, NULL);
30882cae269SKonstantin Komarov sbi->mft.lbo = t64;
30982cae269SKonstantin Komarov if (IS_ERR(inode))
31082cae269SKonstantin Komarov inode = NULL;
31182cae269SKonstantin Komarov }
31282cae269SKonstantin Komarov
31382cae269SKonstantin Komarov if (!inode) {
31482cae269SKonstantin Komarov err = -EINVAL;
31582cae269SKonstantin Komarov ntfs_err(sb, "Failed to load $MFT.");
31682cae269SKonstantin Komarov goto out;
31782cae269SKonstantin Komarov }
31882cae269SKonstantin Komarov
31982cae269SKonstantin Komarov sbi->mft.ni = ntfs_i(inode);
32082cae269SKonstantin Komarov
321e8b8e97fSKari Argillander /* LogFile should not contains attribute list. */
32282cae269SKonstantin Komarov err = ni_load_all_mi(sbi->mft.ni);
32382cae269SKonstantin Komarov if (!err)
32482cae269SKonstantin Komarov err = log_replay(ni, &initialized);
32582cae269SKonstantin Komarov
32682cae269SKonstantin Komarov iput(inode);
32782cae269SKonstantin Komarov sbi->mft.ni = NULL;
32882cae269SKonstantin Komarov
32982cae269SKonstantin Komarov sync_blockdev(sb->s_bdev);
33082cae269SKonstantin Komarov invalidate_bdev(sb->s_bdev);
33182cae269SKonstantin Komarov
33282cae269SKonstantin Komarov if (sbi->flags & NTFS_FLAGS_NEED_REPLAY) {
33382cae269SKonstantin Komarov err = 0;
33482cae269SKonstantin Komarov goto out;
33582cae269SKonstantin Komarov }
33682cae269SKonstantin Komarov
33782cae269SKonstantin Komarov if (sb_rdonly(sb) || !initialized)
33882cae269SKonstantin Komarov goto out;
33982cae269SKonstantin Komarov
340d3624466SKonstantin Komarov /* Fill LogFile by '-1' if it is initialized. */
34182cae269SKonstantin Komarov err = ntfs_bio_fill_1(sbi, &ni->file.run);
34282cae269SKonstantin Komarov
34382cae269SKonstantin Komarov out:
34482cae269SKonstantin Komarov sbi->flags &= ~NTFS_FLAGS_LOG_REPLAYING;
34582cae269SKonstantin Komarov
34682cae269SKonstantin Komarov return err;
34782cae269SKonstantin Komarov }
34882cae269SKonstantin Komarov
34982cae269SKonstantin Komarov /*
350e8b8e97fSKari Argillander * ntfs_look_for_free_space - Look for a free space in bitmap.
35182cae269SKonstantin Komarov */
ntfs_look_for_free_space(struct ntfs_sb_info * sbi,CLST lcn,CLST len,CLST * new_lcn,CLST * new_len,enum ALLOCATE_OPT opt)35282cae269SKonstantin Komarov int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
35382cae269SKonstantin Komarov CLST *new_lcn, CLST *new_len,
35482cae269SKonstantin Komarov enum ALLOCATE_OPT opt)
35582cae269SKonstantin Komarov {
35682cae269SKonstantin Komarov int err;
357edb853ffSKari Argillander CLST alen;
35882cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
35978ab59feSKonstantin Komarov size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
36082cae269SKonstantin Komarov struct wnd_bitmap *wnd = &sbi->used.bitmap;
36182cae269SKonstantin Komarov
36282cae269SKonstantin Komarov down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
36382cae269SKonstantin Komarov if (opt & ALLOCATE_MFT) {
36482cae269SKonstantin Komarov zlen = wnd_zone_len(wnd);
36582cae269SKonstantin Komarov
36682cae269SKonstantin Komarov if (!zlen) {
36782cae269SKonstantin Komarov err = ntfs_refresh_zone(sbi);
36882cae269SKonstantin Komarov if (err)
369edb853ffSKari Argillander goto up_write;
370edb853ffSKari Argillander
37182cae269SKonstantin Komarov zlen = wnd_zone_len(wnd);
37278ab59feSKonstantin Komarov }
37382cae269SKonstantin Komarov
37482cae269SKonstantin Komarov if (!zlen) {
37578ab59feSKonstantin Komarov ntfs_err(sbi->sb, "no free space to extend mft");
376edb853ffSKari Argillander err = -ENOSPC;
377edb853ffSKari Argillander goto up_write;
37882cae269SKonstantin Komarov }
37982cae269SKonstantin Komarov
38082cae269SKonstantin Komarov lcn = wnd_zone_bit(wnd);
3816e3331eeSKari Argillander alen = min_t(CLST, len, zlen);
38282cae269SKonstantin Komarov
38382cae269SKonstantin Komarov wnd_zone_set(wnd, lcn + alen, zlen - alen);
38482cae269SKonstantin Komarov
38582cae269SKonstantin Komarov err = wnd_set_used(wnd, lcn, alen);
386edb853ffSKari Argillander if (err)
387edb853ffSKari Argillander goto up_write;
388edb853ffSKari Argillander
38978ab59feSKonstantin Komarov alcn = lcn;
390edb853ffSKari Argillander goto space_found;
39178ab59feSKonstantin Komarov }
39282cae269SKonstantin Komarov /*
39382cae269SKonstantin Komarov * 'Cause cluster 0 is always used this value means that we should use
394e8b8e97fSKari Argillander * cached value of 'next_free_lcn' to improve performance.
39582cae269SKonstantin Komarov */
39682cae269SKonstantin Komarov if (!lcn)
39782cae269SKonstantin Komarov lcn = sbi->used.next_free_lcn;
39882cae269SKonstantin Komarov
39982cae269SKonstantin Komarov if (lcn >= wnd->nbits)
40082cae269SKonstantin Komarov lcn = 0;
40182cae269SKonstantin Komarov
40278ab59feSKonstantin Komarov alen = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &alcn);
40378ab59feSKonstantin Komarov if (alen)
404edb853ffSKari Argillander goto space_found;
40582cae269SKonstantin Komarov
406e8b8e97fSKari Argillander /* Try to use clusters from MftZone. */
40782cae269SKonstantin Komarov zlen = wnd_zone_len(wnd);
40882cae269SKonstantin Komarov zeroes = wnd_zeroes(wnd);
40982cae269SKonstantin Komarov
41078ab59feSKonstantin Komarov /* Check too big request */
411edb853ffSKari Argillander if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE) {
412edb853ffSKari Argillander err = -ENOSPC;
413edb853ffSKari Argillander goto up_write;
414edb853ffSKari Argillander }
41582cae269SKonstantin Komarov
416e8b8e97fSKari Argillander /* How many clusters to cat from zone. */
41782cae269SKonstantin Komarov zlcn = wnd_zone_bit(wnd);
41882cae269SKonstantin Komarov zlen2 = zlen >> 1;
419b5322eb1SKari Argillander ztrim = clamp_val(len, zlen2, zlen);
420b5322eb1SKari Argillander new_zlen = max_t(size_t, zlen - ztrim, NTFS_MIN_MFT_ZONE);
42182cae269SKonstantin Komarov
42282cae269SKonstantin Komarov wnd_zone_set(wnd, zlcn, new_zlen);
42382cae269SKonstantin Komarov
424e8b8e97fSKari Argillander /* Allocate continues clusters. */
42578ab59feSKonstantin Komarov alen = wnd_find(wnd, len, 0,
42678ab59feSKonstantin Komarov BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn);
427edb853ffSKari Argillander if (!alen) {
428edb853ffSKari Argillander err = -ENOSPC;
429edb853ffSKari Argillander goto up_write;
430edb853ffSKari Argillander }
43182cae269SKonstantin Komarov
432edb853ffSKari Argillander space_found:
43378ab59feSKonstantin Komarov err = 0;
43478ab59feSKonstantin Komarov *new_len = alen;
43578ab59feSKonstantin Komarov *new_lcn = alcn;
43678ab59feSKonstantin Komarov
43778ab59feSKonstantin Komarov ntfs_unmap_meta(sb, alcn, alen);
43878ab59feSKonstantin Komarov
43978ab59feSKonstantin Komarov /* Set hint for next requests. */
44078ab59feSKonstantin Komarov if (!(opt & ALLOCATE_MFT))
44178ab59feSKonstantin Komarov sbi->used.next_free_lcn = alcn + alen;
442edb853ffSKari Argillander up_write:
44382cae269SKonstantin Komarov up_write(&wnd->rw_lock);
44482cae269SKonstantin Komarov return err;
44582cae269SKonstantin Komarov }
44682cae269SKonstantin Komarov
44782cae269SKonstantin Komarov /*
448910013f7SKonstantin Komarov * ntfs_check_for_free_space
449910013f7SKonstantin Komarov *
450910013f7SKonstantin Komarov * Check if it is possible to allocate 'clen' clusters and 'mlen' Mft records
451910013f7SKonstantin Komarov */
ntfs_check_for_free_space(struct ntfs_sb_info * sbi,CLST clen,CLST mlen)452910013f7SKonstantin Komarov bool ntfs_check_for_free_space(struct ntfs_sb_info *sbi, CLST clen, CLST mlen)
453910013f7SKonstantin Komarov {
454910013f7SKonstantin Komarov size_t free, zlen, avail;
455910013f7SKonstantin Komarov struct wnd_bitmap *wnd;
456910013f7SKonstantin Komarov
457910013f7SKonstantin Komarov wnd = &sbi->used.bitmap;
458910013f7SKonstantin Komarov down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
459910013f7SKonstantin Komarov free = wnd_zeroes(wnd);
4606f80ed14SKonstantin Komarov zlen = min_t(size_t, NTFS_MIN_MFT_ZONE, wnd_zone_len(wnd));
461910013f7SKonstantin Komarov up_read(&wnd->rw_lock);
462910013f7SKonstantin Komarov
463910013f7SKonstantin Komarov if (free < zlen + clen)
464910013f7SKonstantin Komarov return false;
465910013f7SKonstantin Komarov
466910013f7SKonstantin Komarov avail = free - (zlen + clen);
467910013f7SKonstantin Komarov
468910013f7SKonstantin Komarov wnd = &sbi->mft.bitmap;
469910013f7SKonstantin Komarov down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
470910013f7SKonstantin Komarov free = wnd_zeroes(wnd);
471910013f7SKonstantin Komarov zlen = wnd_zone_len(wnd);
472910013f7SKonstantin Komarov up_read(&wnd->rw_lock);
473910013f7SKonstantin Komarov
474910013f7SKonstantin Komarov if (free >= zlen + mlen)
475910013f7SKonstantin Komarov return true;
476910013f7SKonstantin Komarov
477910013f7SKonstantin Komarov return avail >= bytes_to_cluster(sbi, mlen << sbi->record_bits);
478910013f7SKonstantin Komarov }
479910013f7SKonstantin Komarov
480910013f7SKonstantin Komarov /*
481e8b8e97fSKari Argillander * ntfs_extend_mft - Allocate additional MFT records.
48282cae269SKonstantin Komarov *
483e8b8e97fSKari Argillander * sbi->mft.bitmap is locked for write.
48482cae269SKonstantin Komarov *
48582cae269SKonstantin Komarov * NOTE: recursive:
48682cae269SKonstantin Komarov * ntfs_look_free_mft ->
48782cae269SKonstantin Komarov * ntfs_extend_mft ->
48882cae269SKonstantin Komarov * attr_set_size ->
48982cae269SKonstantin Komarov * ni_insert_nonresident ->
49082cae269SKonstantin Komarov * ni_insert_attr ->
49182cae269SKonstantin Komarov * ni_ins_attr_ext ->
49282cae269SKonstantin Komarov * ntfs_look_free_mft ->
49382cae269SKonstantin Komarov * ntfs_extend_mft
494e8b8e97fSKari Argillander *
495e8b8e97fSKari Argillander * To avoid recursive always allocate space for two new MFT records
496e8b8e97fSKari Argillander * see attrib.c: "at least two MFT to avoid recursive loop".
49782cae269SKonstantin Komarov */
ntfs_extend_mft(struct ntfs_sb_info * sbi)49882cae269SKonstantin Komarov static int ntfs_extend_mft(struct ntfs_sb_info *sbi)
49982cae269SKonstantin Komarov {
50082cae269SKonstantin Komarov int err;
50182cae269SKonstantin Komarov struct ntfs_inode *ni = sbi->mft.ni;
50282cae269SKonstantin Komarov size_t new_mft_total;
50382cae269SKonstantin Komarov u64 new_mft_bytes, new_bitmap_bytes;
50482cae269SKonstantin Komarov struct ATTRIB *attr;
50582cae269SKonstantin Komarov struct wnd_bitmap *wnd = &sbi->mft.bitmap;
50682cae269SKonstantin Komarov
50797a6815eSKonstantin Komarov new_mft_total = ALIGN(wnd->nbits + NTFS_MFT_INCREASE_STEP, 128);
50882cae269SKonstantin Komarov new_mft_bytes = (u64)new_mft_total << sbi->record_bits;
50982cae269SKonstantin Komarov
510e8b8e97fSKari Argillander /* Step 1: Resize $MFT::DATA. */
51182cae269SKonstantin Komarov down_write(&ni->file.run_lock);
51282cae269SKonstantin Komarov err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run,
51382cae269SKonstantin Komarov new_mft_bytes, NULL, false, &attr);
51482cae269SKonstantin Komarov
51582cae269SKonstantin Komarov if (err) {
51682cae269SKonstantin Komarov up_write(&ni->file.run_lock);
51782cae269SKonstantin Komarov goto out;
51882cae269SKonstantin Komarov }
51982cae269SKonstantin Komarov
52082cae269SKonstantin Komarov attr->nres.valid_size = attr->nres.data_size;
52182cae269SKonstantin Komarov new_mft_total = le64_to_cpu(attr->nres.alloc_size) >> sbi->record_bits;
52282cae269SKonstantin Komarov ni->mi.dirty = true;
52382cae269SKonstantin Komarov
524e8b8e97fSKari Argillander /* Step 2: Resize $MFT::BITMAP. */
525*706cc802SAlexander Lobakin new_bitmap_bytes = ntfs3_bitmap_size(new_mft_total);
52682cae269SKonstantin Komarov
52782cae269SKonstantin Komarov err = attr_set_size(ni, ATTR_BITMAP, NULL, 0, &sbi->mft.bitmap.run,
52882cae269SKonstantin Komarov new_bitmap_bytes, &new_bitmap_bytes, true, NULL);
52982cae269SKonstantin Komarov
530e8b8e97fSKari Argillander /* Refresh MFT Zone if necessary. */
53182cae269SKonstantin Komarov down_write_nested(&sbi->used.bitmap.rw_lock, BITMAP_MUTEX_CLUSTERS);
53282cae269SKonstantin Komarov
53382cae269SKonstantin Komarov ntfs_refresh_zone(sbi);
53482cae269SKonstantin Komarov
53582cae269SKonstantin Komarov up_write(&sbi->used.bitmap.rw_lock);
53682cae269SKonstantin Komarov up_write(&ni->file.run_lock);
53782cae269SKonstantin Komarov
53882cae269SKonstantin Komarov if (err)
53982cae269SKonstantin Komarov goto out;
54082cae269SKonstantin Komarov
54182cae269SKonstantin Komarov err = wnd_extend(wnd, new_mft_total);
54282cae269SKonstantin Komarov
54382cae269SKonstantin Komarov if (err)
54482cae269SKonstantin Komarov goto out;
54582cae269SKonstantin Komarov
54682cae269SKonstantin Komarov ntfs_clear_mft_tail(sbi, sbi->mft.used, new_mft_total);
54782cae269SKonstantin Komarov
54882cae269SKonstantin Komarov err = _ni_write_inode(&ni->vfs_inode, 0);
54982cae269SKonstantin Komarov out:
55082cae269SKonstantin Komarov return err;
55182cae269SKonstantin Komarov }
55282cae269SKonstantin Komarov
55382cae269SKonstantin Komarov /*
554e8b8e97fSKari Argillander * ntfs_look_free_mft - Look for a free MFT record.
55582cae269SKonstantin Komarov */
ntfs_look_free_mft(struct ntfs_sb_info * sbi,CLST * rno,bool mft,struct ntfs_inode * ni,struct mft_inode ** mi)55682cae269SKonstantin Komarov int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft,
55782cae269SKonstantin Komarov struct ntfs_inode *ni, struct mft_inode **mi)
55882cae269SKonstantin Komarov {
55982cae269SKonstantin Komarov int err = 0;
56082cae269SKonstantin Komarov size_t zbit, zlen, from, to, fr;
56182cae269SKonstantin Komarov size_t mft_total;
56282cae269SKonstantin Komarov struct MFT_REF ref;
56382cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
56482cae269SKonstantin Komarov struct wnd_bitmap *wnd = &sbi->mft.bitmap;
56582cae269SKonstantin Komarov u32 ir;
56682cae269SKonstantin Komarov
56782cae269SKonstantin Komarov static_assert(sizeof(sbi->mft.reserved_bitmap) * 8 >=
56882cae269SKonstantin Komarov MFT_REC_FREE - MFT_REC_RESERVED);
56982cae269SKonstantin Komarov
57082cae269SKonstantin Komarov if (!mft)
57182cae269SKonstantin Komarov down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
57282cae269SKonstantin Komarov
57382cae269SKonstantin Komarov zlen = wnd_zone_len(wnd);
57482cae269SKonstantin Komarov
575e8b8e97fSKari Argillander /* Always reserve space for MFT. */
57682cae269SKonstantin Komarov if (zlen) {
57782cae269SKonstantin Komarov if (mft) {
57882cae269SKonstantin Komarov zbit = wnd_zone_bit(wnd);
57982cae269SKonstantin Komarov *rno = zbit;
58082cae269SKonstantin Komarov wnd_zone_set(wnd, zbit + 1, zlen - 1);
58182cae269SKonstantin Komarov }
58282cae269SKonstantin Komarov goto found;
58382cae269SKonstantin Komarov }
58482cae269SKonstantin Komarov
585e8b8e97fSKari Argillander /* No MFT zone. Find the nearest to '0' free MFT. */
58682cae269SKonstantin Komarov if (!wnd_find(wnd, 1, MFT_REC_FREE, 0, &zbit)) {
58782cae269SKonstantin Komarov /* Resize MFT */
58882cae269SKonstantin Komarov mft_total = wnd->nbits;
58982cae269SKonstantin Komarov
59082cae269SKonstantin Komarov err = ntfs_extend_mft(sbi);
59182cae269SKonstantin Komarov if (!err) {
59282cae269SKonstantin Komarov zbit = mft_total;
59382cae269SKonstantin Komarov goto reserve_mft;
59482cae269SKonstantin Komarov }
59582cae269SKonstantin Komarov
59682cae269SKonstantin Komarov if (!mft || MFT_REC_FREE == sbi->mft.next_reserved)
59782cae269SKonstantin Komarov goto out;
59882cae269SKonstantin Komarov
59982cae269SKonstantin Komarov err = 0;
60082cae269SKonstantin Komarov
60182cae269SKonstantin Komarov /*
60282cae269SKonstantin Komarov * Look for free record reserved area [11-16) ==
60382cae269SKonstantin Komarov * [MFT_REC_RESERVED, MFT_REC_FREE ) MFT bitmap always
604e8b8e97fSKari Argillander * marks it as used.
60582cae269SKonstantin Komarov */
60682cae269SKonstantin Komarov if (!sbi->mft.reserved_bitmap) {
607e8b8e97fSKari Argillander /* Once per session create internal bitmap for 5 bits. */
60882cae269SKonstantin Komarov sbi->mft.reserved_bitmap = 0xFF;
60982cae269SKonstantin Komarov
61082cae269SKonstantin Komarov ref.high = 0;
61182cae269SKonstantin Komarov for (ir = MFT_REC_RESERVED; ir < MFT_REC_FREE; ir++) {
61282cae269SKonstantin Komarov struct inode *i;
61382cae269SKonstantin Komarov struct ntfs_inode *ni;
61482cae269SKonstantin Komarov struct MFT_REC *mrec;
61582cae269SKonstantin Komarov
61682cae269SKonstantin Komarov ref.low = cpu_to_le32(ir);
61782cae269SKonstantin Komarov ref.seq = cpu_to_le16(ir);
61882cae269SKonstantin Komarov
61982cae269SKonstantin Komarov i = ntfs_iget5(sb, &ref, NULL);
62082cae269SKonstantin Komarov if (IS_ERR(i)) {
62182cae269SKonstantin Komarov next:
62282cae269SKonstantin Komarov ntfs_notice(
62382cae269SKonstantin Komarov sb,
62482cae269SKonstantin Komarov "Invalid reserved record %x",
62582cae269SKonstantin Komarov ref.low);
62682cae269SKonstantin Komarov continue;
62782cae269SKonstantin Komarov }
62882cae269SKonstantin Komarov if (is_bad_inode(i)) {
62982cae269SKonstantin Komarov iput(i);
63082cae269SKonstantin Komarov goto next;
63182cae269SKonstantin Komarov }
63282cae269SKonstantin Komarov
63382cae269SKonstantin Komarov ni = ntfs_i(i);
63482cae269SKonstantin Komarov
63582cae269SKonstantin Komarov mrec = ni->mi.mrec;
63682cae269SKonstantin Komarov
63782cae269SKonstantin Komarov if (!is_rec_base(mrec))
63882cae269SKonstantin Komarov goto next;
63982cae269SKonstantin Komarov
64082cae269SKonstantin Komarov if (mrec->hard_links)
64182cae269SKonstantin Komarov goto next;
64282cae269SKonstantin Komarov
64382cae269SKonstantin Komarov if (!ni_std(ni))
64482cae269SKonstantin Komarov goto next;
64582cae269SKonstantin Komarov
64682cae269SKonstantin Komarov if (ni_find_attr(ni, NULL, NULL, ATTR_NAME,
64782cae269SKonstantin Komarov NULL, 0, NULL, NULL))
64882cae269SKonstantin Komarov goto next;
64982cae269SKonstantin Komarov
650e483783cSKonstantin Komarov __clear_bit(ir - MFT_REC_RESERVED,
65182cae269SKonstantin Komarov &sbi->mft.reserved_bitmap);
65282cae269SKonstantin Komarov }
65382cae269SKonstantin Komarov }
65482cae269SKonstantin Komarov
65582cae269SKonstantin Komarov /* Scan 5 bits for zero. Bit 0 == MFT_REC_RESERVED */
656e483783cSKonstantin Komarov zbit = find_next_zero_bit(&sbi->mft.reserved_bitmap,
65782cae269SKonstantin Komarov MFT_REC_FREE, MFT_REC_RESERVED);
65882cae269SKonstantin Komarov if (zbit >= MFT_REC_FREE) {
65982cae269SKonstantin Komarov sbi->mft.next_reserved = MFT_REC_FREE;
66082cae269SKonstantin Komarov goto out;
66182cae269SKonstantin Komarov }
66282cae269SKonstantin Komarov
66382cae269SKonstantin Komarov zlen = 1;
66482cae269SKonstantin Komarov sbi->mft.next_reserved = zbit;
66582cae269SKonstantin Komarov } else {
66682cae269SKonstantin Komarov reserve_mft:
66782cae269SKonstantin Komarov zlen = zbit == MFT_REC_FREE ? (MFT_REC_USER - MFT_REC_FREE) : 4;
66882cae269SKonstantin Komarov if (zbit + zlen > wnd->nbits)
66982cae269SKonstantin Komarov zlen = wnd->nbits - zbit;
67082cae269SKonstantin Komarov
67182cae269SKonstantin Komarov while (zlen > 1 && !wnd_is_free(wnd, zbit, zlen))
67282cae269SKonstantin Komarov zlen -= 1;
67382cae269SKonstantin Komarov
674e8b8e97fSKari Argillander /* [zbit, zbit + zlen) will be used for MFT itself. */
67582cae269SKonstantin Komarov from = sbi->mft.used;
67682cae269SKonstantin Komarov if (from < zbit)
67782cae269SKonstantin Komarov from = zbit;
67882cae269SKonstantin Komarov to = zbit + zlen;
67982cae269SKonstantin Komarov if (from < to) {
68082cae269SKonstantin Komarov ntfs_clear_mft_tail(sbi, from, to);
68182cae269SKonstantin Komarov sbi->mft.used = to;
68282cae269SKonstantin Komarov }
68382cae269SKonstantin Komarov }
68482cae269SKonstantin Komarov
68582cae269SKonstantin Komarov if (mft) {
68682cae269SKonstantin Komarov *rno = zbit;
68782cae269SKonstantin Komarov zbit += 1;
68882cae269SKonstantin Komarov zlen -= 1;
68982cae269SKonstantin Komarov }
69082cae269SKonstantin Komarov
69182cae269SKonstantin Komarov wnd_zone_set(wnd, zbit, zlen);
69282cae269SKonstantin Komarov
69382cae269SKonstantin Komarov found:
69482cae269SKonstantin Komarov if (!mft) {
695e8b8e97fSKari Argillander /* The request to get record for general purpose. */
69682cae269SKonstantin Komarov if (sbi->mft.next_free < MFT_REC_USER)
69782cae269SKonstantin Komarov sbi->mft.next_free = MFT_REC_USER;
69882cae269SKonstantin Komarov
69982cae269SKonstantin Komarov for (;;) {
70082cae269SKonstantin Komarov if (sbi->mft.next_free >= sbi->mft.bitmap.nbits) {
70182cae269SKonstantin Komarov } else if (!wnd_find(wnd, 1, MFT_REC_USER, 0, &fr)) {
70282cae269SKonstantin Komarov sbi->mft.next_free = sbi->mft.bitmap.nbits;
70382cae269SKonstantin Komarov } else {
70482cae269SKonstantin Komarov *rno = fr;
70582cae269SKonstantin Komarov sbi->mft.next_free = *rno + 1;
70682cae269SKonstantin Komarov break;
70782cae269SKonstantin Komarov }
70882cae269SKonstantin Komarov
70982cae269SKonstantin Komarov err = ntfs_extend_mft(sbi);
71082cae269SKonstantin Komarov if (err)
71182cae269SKonstantin Komarov goto out;
71282cae269SKonstantin Komarov }
71382cae269SKonstantin Komarov }
71482cae269SKonstantin Komarov
71582cae269SKonstantin Komarov if (ni && !ni_add_subrecord(ni, *rno, mi)) {
71682cae269SKonstantin Komarov err = -ENOMEM;
71782cae269SKonstantin Komarov goto out;
71882cae269SKonstantin Komarov }
71982cae269SKonstantin Komarov
720e8b8e97fSKari Argillander /* We have found a record that are not reserved for next MFT. */
72182cae269SKonstantin Komarov if (*rno >= MFT_REC_FREE)
72282cae269SKonstantin Komarov wnd_set_used(wnd, *rno, 1);
72382cae269SKonstantin Komarov else if (*rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited)
724e483783cSKonstantin Komarov __set_bit(*rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap);
72582cae269SKonstantin Komarov
72682cae269SKonstantin Komarov out:
72782cae269SKonstantin Komarov if (!mft)
72882cae269SKonstantin Komarov up_write(&wnd->rw_lock);
72982cae269SKonstantin Komarov
73082cae269SKonstantin Komarov return err;
73182cae269SKonstantin Komarov }
73282cae269SKonstantin Komarov
73382cae269SKonstantin Komarov /*
734e8b8e97fSKari Argillander * ntfs_mark_rec_free - Mark record as free.
735071100eaSKonstantin Komarov * is_mft - true if we are changing MFT
73682cae269SKonstantin Komarov */
ntfs_mark_rec_free(struct ntfs_sb_info * sbi,CLST rno,bool is_mft)737071100eaSKonstantin Komarov void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft)
73882cae269SKonstantin Komarov {
73982cae269SKonstantin Komarov struct wnd_bitmap *wnd = &sbi->mft.bitmap;
74082cae269SKonstantin Komarov
741071100eaSKonstantin Komarov if (!is_mft)
74282cae269SKonstantin Komarov down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
74382cae269SKonstantin Komarov if (rno >= wnd->nbits)
74482cae269SKonstantin Komarov goto out;
74582cae269SKonstantin Komarov
74682cae269SKonstantin Komarov if (rno >= MFT_REC_FREE) {
74782cae269SKonstantin Komarov if (!wnd_is_used(wnd, rno, 1))
74882cae269SKonstantin Komarov ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
74982cae269SKonstantin Komarov else
75082cae269SKonstantin Komarov wnd_set_free(wnd, rno, 1);
75182cae269SKonstantin Komarov } else if (rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited) {
752e483783cSKonstantin Komarov __clear_bit(rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap);
75382cae269SKonstantin Komarov }
75482cae269SKonstantin Komarov
75582cae269SKonstantin Komarov if (rno < wnd_zone_bit(wnd))
75682cae269SKonstantin Komarov wnd_zone_set(wnd, rno, 1);
75782cae269SKonstantin Komarov else if (rno < sbi->mft.next_free && rno >= MFT_REC_USER)
75882cae269SKonstantin Komarov sbi->mft.next_free = rno;
75982cae269SKonstantin Komarov
76082cae269SKonstantin Komarov out:
761071100eaSKonstantin Komarov if (!is_mft)
76282cae269SKonstantin Komarov up_write(&wnd->rw_lock);
76382cae269SKonstantin Komarov }
76482cae269SKonstantin Komarov
76582cae269SKonstantin Komarov /*
766e8b8e97fSKari Argillander * ntfs_clear_mft_tail - Format empty records [from, to).
76782cae269SKonstantin Komarov *
768e8b8e97fSKari Argillander * sbi->mft.bitmap is locked for write.
76982cae269SKonstantin Komarov */
ntfs_clear_mft_tail(struct ntfs_sb_info * sbi,size_t from,size_t to)77082cae269SKonstantin Komarov int ntfs_clear_mft_tail(struct ntfs_sb_info *sbi, size_t from, size_t to)
77182cae269SKonstantin Komarov {
77282cae269SKonstantin Komarov int err;
77382cae269SKonstantin Komarov u32 rs;
77482cae269SKonstantin Komarov u64 vbo;
77582cae269SKonstantin Komarov struct runs_tree *run;
77682cae269SKonstantin Komarov struct ntfs_inode *ni;
77782cae269SKonstantin Komarov
77882cae269SKonstantin Komarov if (from >= to)
77982cae269SKonstantin Komarov return 0;
78082cae269SKonstantin Komarov
78182cae269SKonstantin Komarov rs = sbi->record_size;
78282cae269SKonstantin Komarov ni = sbi->mft.ni;
78382cae269SKonstantin Komarov run = &ni->file.run;
78482cae269SKonstantin Komarov
78582cae269SKonstantin Komarov down_read(&ni->file.run_lock);
78682cae269SKonstantin Komarov vbo = (u64)from * rs;
78782cae269SKonstantin Komarov for (; from < to; from++, vbo += rs) {
78882cae269SKonstantin Komarov struct ntfs_buffers nb;
78982cae269SKonstantin Komarov
79082cae269SKonstantin Komarov err = ntfs_get_bh(sbi, run, vbo, rs, &nb);
79182cae269SKonstantin Komarov if (err)
79282cae269SKonstantin Komarov goto out;
79382cae269SKonstantin Komarov
79482cae269SKonstantin Komarov err = ntfs_write_bh(sbi, &sbi->new_rec->rhdr, &nb, 0);
79582cae269SKonstantin Komarov nb_put(&nb);
79682cae269SKonstantin Komarov if (err)
79782cae269SKonstantin Komarov goto out;
79882cae269SKonstantin Komarov }
79982cae269SKonstantin Komarov
80082cae269SKonstantin Komarov out:
80182cae269SKonstantin Komarov sbi->mft.used = from;
80282cae269SKonstantin Komarov up_read(&ni->file.run_lock);
80382cae269SKonstantin Komarov return err;
80482cae269SKonstantin Komarov }
80582cae269SKonstantin Komarov
80682cae269SKonstantin Komarov /*
807e8b8e97fSKari Argillander * ntfs_refresh_zone - Refresh MFT zone.
80882cae269SKonstantin Komarov *
809e8b8e97fSKari Argillander * sbi->used.bitmap is locked for rw.
810e8b8e97fSKari Argillander * sbi->mft.bitmap is locked for write.
811e8b8e97fSKari Argillander * sbi->mft.ni->file.run_lock for write.
81282cae269SKonstantin Komarov */
ntfs_refresh_zone(struct ntfs_sb_info * sbi)81382cae269SKonstantin Komarov int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
81482cae269SKonstantin Komarov {
8158335ebe1SKonstantin Komarov CLST lcn, vcn, len;
81682cae269SKonstantin Komarov size_t lcn_s, zlen;
81782cae269SKonstantin Komarov struct wnd_bitmap *wnd = &sbi->used.bitmap;
81882cae269SKonstantin Komarov struct ntfs_inode *ni = sbi->mft.ni;
81982cae269SKonstantin Komarov
820e8b8e97fSKari Argillander /* Do not change anything unless we have non empty MFT zone. */
82182cae269SKonstantin Komarov if (wnd_zone_len(wnd))
82282cae269SKonstantin Komarov return 0;
82382cae269SKonstantin Komarov
82482cae269SKonstantin Komarov vcn = bytes_to_cluster(sbi,
82582cae269SKonstantin Komarov (u64)sbi->mft.bitmap.nbits << sbi->record_bits);
82682cae269SKonstantin Komarov
82782cae269SKonstantin Komarov if (!run_lookup_entry(&ni->file.run, vcn - 1, &lcn, &len, NULL))
82882cae269SKonstantin Komarov lcn = SPARSE_LCN;
82982cae269SKonstantin Komarov
830e8b8e97fSKari Argillander /* We should always find Last Lcn for MFT. */
83182cae269SKonstantin Komarov if (lcn == SPARSE_LCN)
83282cae269SKonstantin Komarov return -EINVAL;
83382cae269SKonstantin Komarov
83482cae269SKonstantin Komarov lcn_s = lcn + 1;
83582cae269SKonstantin Komarov
836e8b8e97fSKari Argillander /* Try to allocate clusters after last MFT run. */
8378335ebe1SKonstantin Komarov zlen = wnd_find(wnd, sbi->zone_max, lcn_s, 0, &lcn_s);
83882cae269SKonstantin Komarov wnd_zone_set(wnd, lcn_s, zlen);
83982cae269SKonstantin Komarov
84082cae269SKonstantin Komarov return 0;
84182cae269SKonstantin Komarov }
84282cae269SKonstantin Komarov
84382cae269SKonstantin Komarov /*
844e8b8e97fSKari Argillander * ntfs_update_mftmirr - Update $MFTMirr data.
84582cae269SKonstantin Komarov */
ntfs_update_mftmirr(struct ntfs_sb_info * sbi,int wait)846e66af07cSPavel Skripkin void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
84782cae269SKonstantin Komarov {
84882cae269SKonstantin Komarov int err;
84982cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
850e483783cSKonstantin Komarov u32 blocksize, bytes;
85182cae269SKonstantin Komarov sector_t block1, block2;
85282cae269SKonstantin Komarov
85396de65a9SKonstantin Komarov /*
85496de65a9SKonstantin Komarov * sb can be NULL here. In this case sbi->flags should be 0 too.
85596de65a9SKonstantin Komarov */
856323b0ab3SKonstantin Komarov if (!sb || !(sbi->flags & NTFS_FLAGS_MFTMIRR) ||
857323b0ab3SKonstantin Komarov unlikely(ntfs3_forced_shutdown(sb)))
858e66af07cSPavel Skripkin return;
859321460caSPavel Skripkin
860321460caSPavel Skripkin blocksize = sb->s_blocksize;
86182cae269SKonstantin Komarov bytes = sbi->mft.recs_mirr << sbi->record_bits;
86282cae269SKonstantin Komarov block1 = sbi->mft.lbo >> sb->s_blocksize_bits;
86382cae269SKonstantin Komarov block2 = sbi->mft.lbo2 >> sb->s_blocksize_bits;
86482cae269SKonstantin Komarov
86582cae269SKonstantin Komarov for (; bytes >= blocksize; bytes -= blocksize) {
86682cae269SKonstantin Komarov struct buffer_head *bh1, *bh2;
86782cae269SKonstantin Komarov
86882cae269SKonstantin Komarov bh1 = sb_bread(sb, block1++);
869e66af07cSPavel Skripkin if (!bh1)
870e66af07cSPavel Skripkin return;
87182cae269SKonstantin Komarov
87282cae269SKonstantin Komarov bh2 = sb_getblk(sb, block2++);
87382cae269SKonstantin Komarov if (!bh2) {
87482cae269SKonstantin Komarov put_bh(bh1);
875e66af07cSPavel Skripkin return;
87682cae269SKonstantin Komarov }
87782cae269SKonstantin Komarov
87882cae269SKonstantin Komarov if (buffer_locked(bh2))
87982cae269SKonstantin Komarov __wait_on_buffer(bh2);
88082cae269SKonstantin Komarov
88182cae269SKonstantin Komarov lock_buffer(bh2);
88282cae269SKonstantin Komarov memcpy(bh2->b_data, bh1->b_data, blocksize);
88382cae269SKonstantin Komarov set_buffer_uptodate(bh2);
88482cae269SKonstantin Komarov mark_buffer_dirty(bh2);
88582cae269SKonstantin Komarov unlock_buffer(bh2);
88682cae269SKonstantin Komarov
88782cae269SKonstantin Komarov put_bh(bh1);
88882cae269SKonstantin Komarov bh1 = NULL;
88982cae269SKonstantin Komarov
890ba118928SKonstantin Komarov err = wait ? sync_dirty_buffer(bh2) : 0;
89182cae269SKonstantin Komarov
89282cae269SKonstantin Komarov put_bh(bh2);
89382cae269SKonstantin Komarov if (err)
894e66af07cSPavel Skripkin return;
89582cae269SKonstantin Komarov }
89682cae269SKonstantin Komarov
89782cae269SKonstantin Komarov sbi->flags &= ~NTFS_FLAGS_MFTMIRR;
89882cae269SKonstantin Komarov }
89982cae269SKonstantin Komarov
90082cae269SKonstantin Komarov /*
901c12df45eSKonstantin Komarov * ntfs_bad_inode
902c12df45eSKonstantin Komarov *
903c12df45eSKonstantin Komarov * Marks inode as bad and marks fs as 'dirty'
904c12df45eSKonstantin Komarov */
ntfs_bad_inode(struct inode * inode,const char * hint)905c12df45eSKonstantin Komarov void ntfs_bad_inode(struct inode *inode, const char *hint)
906c12df45eSKonstantin Komarov {
907c12df45eSKonstantin Komarov struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
908c12df45eSKonstantin Komarov
909c12df45eSKonstantin Komarov ntfs_inode_err(inode, "%s", hint);
910c12df45eSKonstantin Komarov make_bad_inode(inode);
911c12df45eSKonstantin Komarov ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
91282cae269SKonstantin Komarov }
91382cae269SKonstantin Komarov
91482cae269SKonstantin Komarov /*
91582cae269SKonstantin Komarov * ntfs_set_state
91682cae269SKonstantin Komarov *
917e8b8e97fSKari Argillander * Mount: ntfs_set_state(NTFS_DIRTY_DIRTY)
918e8b8e97fSKari Argillander * Umount: ntfs_set_state(NTFS_DIRTY_CLEAR)
919e8b8e97fSKari Argillander * NTFS error: ntfs_set_state(NTFS_DIRTY_ERROR)
92082cae269SKonstantin Komarov */
ntfs_set_state(struct ntfs_sb_info * sbi,enum NTFS_DIRTY_FLAGS dirty)92182cae269SKonstantin Komarov int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty)
92282cae269SKonstantin Komarov {
92382cae269SKonstantin Komarov int err;
92482cae269SKonstantin Komarov struct ATTRIB *attr;
92582cae269SKonstantin Komarov struct VOLUME_INFO *info;
92682cae269SKonstantin Komarov struct mft_inode *mi;
92782cae269SKonstantin Komarov struct ntfs_inode *ni;
92862560248SKonstantin Komarov __le16 info_flags;
92982cae269SKonstantin Komarov
93082cae269SKonstantin Komarov /*
931e8b8e97fSKari Argillander * Do not change state if fs was real_dirty.
932e8b8e97fSKari Argillander * Do not change state if fs already dirty(clear).
933e8b8e97fSKari Argillander * Do not change any thing if mounted read only.
93482cae269SKonstantin Komarov */
93582cae269SKonstantin Komarov if (sbi->volume.real_dirty || sb_rdonly(sbi->sb))
93682cae269SKonstantin Komarov return 0;
93782cae269SKonstantin Komarov
938e8b8e97fSKari Argillander /* Check cached value. */
93982cae269SKonstantin Komarov if ((dirty == NTFS_DIRTY_CLEAR ? 0 : VOLUME_FLAG_DIRTY) ==
94082cae269SKonstantin Komarov (sbi->volume.flags & VOLUME_FLAG_DIRTY))
94182cae269SKonstantin Komarov return 0;
94282cae269SKonstantin Komarov
94382cae269SKonstantin Komarov ni = sbi->volume.ni;
94482cae269SKonstantin Komarov if (!ni)
94582cae269SKonstantin Komarov return -EINVAL;
94682cae269SKonstantin Komarov
94782cae269SKonstantin Komarov mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_DIRTY);
94882cae269SKonstantin Komarov
94982cae269SKonstantin Komarov attr = ni_find_attr(ni, NULL, NULL, ATTR_VOL_INFO, NULL, 0, NULL, &mi);
95082cae269SKonstantin Komarov if (!attr) {
95182cae269SKonstantin Komarov err = -EINVAL;
95282cae269SKonstantin Komarov goto out;
95382cae269SKonstantin Komarov }
95482cae269SKonstantin Komarov
95582cae269SKonstantin Komarov info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO);
95682cae269SKonstantin Komarov if (!info) {
95782cae269SKonstantin Komarov err = -EINVAL;
95882cae269SKonstantin Komarov goto out;
95982cae269SKonstantin Komarov }
96082cae269SKonstantin Komarov
96162560248SKonstantin Komarov info_flags = info->flags;
96262560248SKonstantin Komarov
96382cae269SKonstantin Komarov switch (dirty) {
96482cae269SKonstantin Komarov case NTFS_DIRTY_ERROR:
96582cae269SKonstantin Komarov ntfs_notice(sbi->sb, "Mark volume as dirty due to NTFS errors");
96682cae269SKonstantin Komarov sbi->volume.real_dirty = true;
96782cae269SKonstantin Komarov fallthrough;
96882cae269SKonstantin Komarov case NTFS_DIRTY_DIRTY:
96982cae269SKonstantin Komarov info->flags |= VOLUME_FLAG_DIRTY;
97082cae269SKonstantin Komarov break;
97182cae269SKonstantin Komarov case NTFS_DIRTY_CLEAR:
97282cae269SKonstantin Komarov info->flags &= ~VOLUME_FLAG_DIRTY;
97382cae269SKonstantin Komarov break;
97482cae269SKonstantin Komarov }
975e8b8e97fSKari Argillander /* Cache current volume flags. */
97662560248SKonstantin Komarov if (info_flags != info->flags) {
97782cae269SKonstantin Komarov sbi->volume.flags = info->flags;
97882cae269SKonstantin Komarov mi->dirty = true;
97962560248SKonstantin Komarov }
98082cae269SKonstantin Komarov err = 0;
98182cae269SKonstantin Komarov
98282cae269SKonstantin Komarov out:
98382cae269SKonstantin Komarov ni_unlock(ni);
98482cae269SKonstantin Komarov if (err)
98582cae269SKonstantin Komarov return err;
98682cae269SKonstantin Komarov
98706ccfb00SKonstantin Komarov mark_inode_dirty_sync(&ni->vfs_inode);
98882cae269SKonstantin Komarov /* verify(!ntfs_update_mftmirr()); */
98982cae269SKonstantin Komarov
99006ccfb00SKonstantin Komarov /* write mft record on disk. */
99106ccfb00SKonstantin Komarov err = _ni_write_inode(&ni->vfs_inode, 1);
99282cae269SKonstantin Komarov
99382cae269SKonstantin Komarov return err;
99482cae269SKonstantin Komarov }
99582cae269SKonstantin Komarov
99682cae269SKonstantin Komarov /*
997e8b8e97fSKari Argillander * security_hash - Calculates a hash of security descriptor.
99882cae269SKonstantin Komarov */
security_hash(const void * sd,size_t bytes)99982cae269SKonstantin Komarov static inline __le32 security_hash(const void *sd, size_t bytes)
100082cae269SKonstantin Komarov {
100182cae269SKonstantin Komarov u32 hash = 0;
100282cae269SKonstantin Komarov const __le32 *ptr = sd;
100382cae269SKonstantin Komarov
100482cae269SKonstantin Komarov bytes >>= 2;
100582cae269SKonstantin Komarov while (bytes--)
100682cae269SKonstantin Komarov hash = ((hash >> 0x1D) | (hash << 3)) + le32_to_cpu(*ptr++);
100782cae269SKonstantin Komarov return cpu_to_le32(hash);
100882cae269SKonstantin Komarov }
100982cae269SKonstantin Komarov
1010c55deec3SKonstantin Komarov /*
1011c55deec3SKonstantin Komarov * simple wrapper for sb_bread_unmovable.
1012c55deec3SKonstantin Komarov */
ntfs_bread(struct super_block * sb,sector_t block)1013c55deec3SKonstantin Komarov struct buffer_head *ntfs_bread(struct super_block *sb, sector_t block)
1014c55deec3SKonstantin Komarov {
1015c55deec3SKonstantin Komarov struct ntfs_sb_info *sbi = sb->s_fs_info;
1016c55deec3SKonstantin Komarov struct buffer_head *bh;
1017c55deec3SKonstantin Komarov
1018c55deec3SKonstantin Komarov if (unlikely(block >= sbi->volume.blocks)) {
1019c55deec3SKonstantin Komarov /* prevent generic message "attempt to access beyond end of device" */
1020c55deec3SKonstantin Komarov ntfs_err(sb, "try to read out of volume at offset 0x%llx",
1021c55deec3SKonstantin Komarov (u64)block << sb->s_blocksize_bits);
1022c55deec3SKonstantin Komarov return NULL;
1023c55deec3SKonstantin Komarov }
1024c55deec3SKonstantin Komarov
1025c55deec3SKonstantin Komarov bh = sb_bread_unmovable(sb, block);
1026c55deec3SKonstantin Komarov if (bh)
1027c55deec3SKonstantin Komarov return bh;
1028c55deec3SKonstantin Komarov
1029c55deec3SKonstantin Komarov ntfs_err(sb, "failed to read volume at offset 0x%llx",
1030c55deec3SKonstantin Komarov (u64)block << sb->s_blocksize_bits);
1031c55deec3SKonstantin Komarov return NULL;
1032c55deec3SKonstantin Komarov }
1033c55deec3SKonstantin Komarov
ntfs_sb_read(struct super_block * sb,u64 lbo,size_t bytes,void * buffer)103482cae269SKonstantin Komarov int ntfs_sb_read(struct super_block *sb, u64 lbo, size_t bytes, void *buffer)
103582cae269SKonstantin Komarov {
103682cae269SKonstantin Komarov struct block_device *bdev = sb->s_bdev;
103782cae269SKonstantin Komarov u32 blocksize = sb->s_blocksize;
103882cae269SKonstantin Komarov u64 block = lbo >> sb->s_blocksize_bits;
103982cae269SKonstantin Komarov u32 off = lbo & (blocksize - 1);
104082cae269SKonstantin Komarov u32 op = blocksize - off;
104182cae269SKonstantin Komarov
104282cae269SKonstantin Komarov for (; bytes; block += 1, off = 0, op = blocksize) {
104382cae269SKonstantin Komarov struct buffer_head *bh = __bread(bdev, block, blocksize);
104482cae269SKonstantin Komarov
104582cae269SKonstantin Komarov if (!bh)
104682cae269SKonstantin Komarov return -EIO;
104782cae269SKonstantin Komarov
104882cae269SKonstantin Komarov if (op > bytes)
104982cae269SKonstantin Komarov op = bytes;
105082cae269SKonstantin Komarov
105182cae269SKonstantin Komarov memcpy(buffer, bh->b_data + off, op);
105282cae269SKonstantin Komarov
105382cae269SKonstantin Komarov put_bh(bh);
105482cae269SKonstantin Komarov
105582cae269SKonstantin Komarov bytes -= op;
105682cae269SKonstantin Komarov buffer = Add2Ptr(buffer, op);
105782cae269SKonstantin Komarov }
105882cae269SKonstantin Komarov
105982cae269SKonstantin Komarov return 0;
106082cae269SKonstantin Komarov }
106182cae269SKonstantin Komarov
ntfs_sb_write(struct super_block * sb,u64 lbo,size_t bytes,const void * buf,int wait)106282cae269SKonstantin Komarov int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
106382cae269SKonstantin Komarov const void *buf, int wait)
106482cae269SKonstantin Komarov {
106582cae269SKonstantin Komarov u32 blocksize = sb->s_blocksize;
106682cae269SKonstantin Komarov struct block_device *bdev = sb->s_bdev;
106782cae269SKonstantin Komarov sector_t block = lbo >> sb->s_blocksize_bits;
106882cae269SKonstantin Komarov u32 off = lbo & (blocksize - 1);
106982cae269SKonstantin Komarov u32 op = blocksize - off;
107082cae269SKonstantin Komarov struct buffer_head *bh;
107182cae269SKonstantin Komarov
107282cae269SKonstantin Komarov if (!wait && (sb->s_flags & SB_SYNCHRONOUS))
107382cae269SKonstantin Komarov wait = 1;
107482cae269SKonstantin Komarov
107582cae269SKonstantin Komarov for (; bytes; block += 1, off = 0, op = blocksize) {
107682cae269SKonstantin Komarov if (op > bytes)
107782cae269SKonstantin Komarov op = bytes;
107882cae269SKonstantin Komarov
107982cae269SKonstantin Komarov if (op < blocksize) {
108082cae269SKonstantin Komarov bh = __bread(bdev, block, blocksize);
108182cae269SKonstantin Komarov if (!bh) {
108282cae269SKonstantin Komarov ntfs_err(sb, "failed to read block %llx",
108382cae269SKonstantin Komarov (u64)block);
108482cae269SKonstantin Komarov return -EIO;
108582cae269SKonstantin Komarov }
108682cae269SKonstantin Komarov } else {
108782cae269SKonstantin Komarov bh = __getblk(bdev, block, blocksize);
108882cae269SKonstantin Komarov if (!bh)
108982cae269SKonstantin Komarov return -ENOMEM;
109082cae269SKonstantin Komarov }
109182cae269SKonstantin Komarov
109282cae269SKonstantin Komarov if (buffer_locked(bh))
109382cae269SKonstantin Komarov __wait_on_buffer(bh);
109482cae269SKonstantin Komarov
109582cae269SKonstantin Komarov lock_buffer(bh);
109682cae269SKonstantin Komarov if (buf) {
109782cae269SKonstantin Komarov memcpy(bh->b_data + off, buf, op);
109882cae269SKonstantin Komarov buf = Add2Ptr(buf, op);
109982cae269SKonstantin Komarov } else {
110082cae269SKonstantin Komarov memset(bh->b_data + off, -1, op);
110182cae269SKonstantin Komarov }
110282cae269SKonstantin Komarov
110382cae269SKonstantin Komarov set_buffer_uptodate(bh);
110482cae269SKonstantin Komarov mark_buffer_dirty(bh);
110582cae269SKonstantin Komarov unlock_buffer(bh);
110682cae269SKonstantin Komarov
110782cae269SKonstantin Komarov if (wait) {
110882cae269SKonstantin Komarov int err = sync_dirty_buffer(bh);
110982cae269SKonstantin Komarov
111082cae269SKonstantin Komarov if (err) {
111182cae269SKonstantin Komarov ntfs_err(
111282cae269SKonstantin Komarov sb,
111382cae269SKonstantin Komarov "failed to sync buffer at block %llx, error %d",
111482cae269SKonstantin Komarov (u64)block, err);
111582cae269SKonstantin Komarov put_bh(bh);
111682cae269SKonstantin Komarov return err;
111782cae269SKonstantin Komarov }
111882cae269SKonstantin Komarov }
111982cae269SKonstantin Komarov
112082cae269SKonstantin Komarov put_bh(bh);
112182cae269SKonstantin Komarov
112282cae269SKonstantin Komarov bytes -= op;
112382cae269SKonstantin Komarov }
112482cae269SKonstantin Komarov return 0;
112582cae269SKonstantin Komarov }
112682cae269SKonstantin Komarov
ntfs_sb_write_run(struct ntfs_sb_info * sbi,const struct runs_tree * run,u64 vbo,const void * buf,size_t bytes,int sync)112782cae269SKonstantin Komarov int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
112863544672SKonstantin Komarov u64 vbo, const void *buf, size_t bytes, int sync)
112982cae269SKonstantin Komarov {
113082cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
113182cae269SKonstantin Komarov u8 cluster_bits = sbi->cluster_bits;
113282cae269SKonstantin Komarov u32 off = vbo & sbi->cluster_mask;
113382cae269SKonstantin Komarov CLST lcn, clen, vcn = vbo >> cluster_bits, vcn_next;
113482cae269SKonstantin Komarov u64 lbo, len;
113582cae269SKonstantin Komarov size_t idx;
113682cae269SKonstantin Komarov
113782cae269SKonstantin Komarov if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx))
113882cae269SKonstantin Komarov return -ENOENT;
113982cae269SKonstantin Komarov
114082cae269SKonstantin Komarov if (lcn == SPARSE_LCN)
114182cae269SKonstantin Komarov return -EINVAL;
114282cae269SKonstantin Komarov
114382cae269SKonstantin Komarov lbo = ((u64)lcn << cluster_bits) + off;
114482cae269SKonstantin Komarov len = ((u64)clen << cluster_bits) - off;
114582cae269SKonstantin Komarov
114682cae269SKonstantin Komarov for (;;) {
11476e3331eeSKari Argillander u32 op = min_t(u64, len, bytes);
114863544672SKonstantin Komarov int err = ntfs_sb_write(sb, lbo, op, buf, sync);
114982cae269SKonstantin Komarov
115082cae269SKonstantin Komarov if (err)
115182cae269SKonstantin Komarov return err;
115282cae269SKonstantin Komarov
115382cae269SKonstantin Komarov bytes -= op;
115482cae269SKonstantin Komarov if (!bytes)
115582cae269SKonstantin Komarov break;
115682cae269SKonstantin Komarov
115782cae269SKonstantin Komarov vcn_next = vcn + clen;
115882cae269SKonstantin Komarov if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
115982cae269SKonstantin Komarov vcn != vcn_next)
116082cae269SKonstantin Komarov return -ENOENT;
116182cae269SKonstantin Komarov
116282cae269SKonstantin Komarov if (lcn == SPARSE_LCN)
116382cae269SKonstantin Komarov return -EINVAL;
116482cae269SKonstantin Komarov
116582cae269SKonstantin Komarov if (buf)
116682cae269SKonstantin Komarov buf = Add2Ptr(buf, op);
116782cae269SKonstantin Komarov
116882cae269SKonstantin Komarov lbo = ((u64)lcn << cluster_bits);
116982cae269SKonstantin Komarov len = ((u64)clen << cluster_bits);
117082cae269SKonstantin Komarov }
117182cae269SKonstantin Komarov
117282cae269SKonstantin Komarov return 0;
117382cae269SKonstantin Komarov }
117482cae269SKonstantin Komarov
ntfs_bread_run(struct ntfs_sb_info * sbi,const struct runs_tree * run,u64 vbo)117582cae269SKonstantin Komarov struct buffer_head *ntfs_bread_run(struct ntfs_sb_info *sbi,
117682cae269SKonstantin Komarov const struct runs_tree *run, u64 vbo)
117782cae269SKonstantin Komarov {
117882cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
117982cae269SKonstantin Komarov u8 cluster_bits = sbi->cluster_bits;
118082cae269SKonstantin Komarov CLST lcn;
118182cae269SKonstantin Komarov u64 lbo;
118282cae269SKonstantin Komarov
118382cae269SKonstantin Komarov if (!run_lookup_entry(run, vbo >> cluster_bits, &lcn, NULL, NULL))
118482cae269SKonstantin Komarov return ERR_PTR(-ENOENT);
118582cae269SKonstantin Komarov
118682cae269SKonstantin Komarov lbo = ((u64)lcn << cluster_bits) + (vbo & sbi->cluster_mask);
118782cae269SKonstantin Komarov
118882cae269SKonstantin Komarov return ntfs_bread(sb, lbo >> sb->s_blocksize_bits);
118982cae269SKonstantin Komarov }
119082cae269SKonstantin Komarov
ntfs_read_run_nb(struct ntfs_sb_info * sbi,const struct runs_tree * run,u64 vbo,void * buf,u32 bytes,struct ntfs_buffers * nb)119182cae269SKonstantin Komarov int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
119282cae269SKonstantin Komarov u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb)
119382cae269SKonstantin Komarov {
119482cae269SKonstantin Komarov int err;
119582cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
119682cae269SKonstantin Komarov u32 blocksize = sb->s_blocksize;
119782cae269SKonstantin Komarov u8 cluster_bits = sbi->cluster_bits;
119882cae269SKonstantin Komarov u32 off = vbo & sbi->cluster_mask;
119982cae269SKonstantin Komarov u32 nbh = 0;
120082cae269SKonstantin Komarov CLST vcn_next, vcn = vbo >> cluster_bits;
120182cae269SKonstantin Komarov CLST lcn, clen;
120282cae269SKonstantin Komarov u64 lbo, len;
120382cae269SKonstantin Komarov size_t idx;
120482cae269SKonstantin Komarov struct buffer_head *bh;
120582cae269SKonstantin Komarov
120682cae269SKonstantin Komarov if (!run) {
1207e8b8e97fSKari Argillander /* First reading of $Volume + $MFTMirr + $LogFile goes here. */
120882cae269SKonstantin Komarov if (vbo > MFT_REC_VOL * sbi->record_size) {
120982cae269SKonstantin Komarov err = -ENOENT;
121082cae269SKonstantin Komarov goto out;
121182cae269SKonstantin Komarov }
121282cae269SKonstantin Komarov
1213e8b8e97fSKari Argillander /* Use absolute boot's 'MFTCluster' to read record. */
121482cae269SKonstantin Komarov lbo = vbo + sbi->mft.lbo;
121582cae269SKonstantin Komarov len = sbi->record_size;
121682cae269SKonstantin Komarov } else if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
121782cae269SKonstantin Komarov err = -ENOENT;
121882cae269SKonstantin Komarov goto out;
121982cae269SKonstantin Komarov } else {
122082cae269SKonstantin Komarov if (lcn == SPARSE_LCN) {
122182cae269SKonstantin Komarov err = -EINVAL;
122282cae269SKonstantin Komarov goto out;
122382cae269SKonstantin Komarov }
122482cae269SKonstantin Komarov
122582cae269SKonstantin Komarov lbo = ((u64)lcn << cluster_bits) + off;
122682cae269SKonstantin Komarov len = ((u64)clen << cluster_bits) - off;
122782cae269SKonstantin Komarov }
122882cae269SKonstantin Komarov
122982cae269SKonstantin Komarov off = lbo & (blocksize - 1);
123082cae269SKonstantin Komarov if (nb) {
123182cae269SKonstantin Komarov nb->off = off;
123282cae269SKonstantin Komarov nb->bytes = bytes;
123382cae269SKonstantin Komarov }
123482cae269SKonstantin Komarov
123582cae269SKonstantin Komarov for (;;) {
123682cae269SKonstantin Komarov u32 len32 = len >= bytes ? bytes : len;
123782cae269SKonstantin Komarov sector_t block = lbo >> sb->s_blocksize_bits;
123882cae269SKonstantin Komarov
123982cae269SKonstantin Komarov do {
124082cae269SKonstantin Komarov u32 op = blocksize - off;
124182cae269SKonstantin Komarov
124282cae269SKonstantin Komarov if (op > len32)
124382cae269SKonstantin Komarov op = len32;
124482cae269SKonstantin Komarov
124582cae269SKonstantin Komarov bh = ntfs_bread(sb, block);
124682cae269SKonstantin Komarov if (!bh) {
124782cae269SKonstantin Komarov err = -EIO;
124882cae269SKonstantin Komarov goto out;
124982cae269SKonstantin Komarov }
125082cae269SKonstantin Komarov
125182cae269SKonstantin Komarov if (buf) {
125282cae269SKonstantin Komarov memcpy(buf, bh->b_data + off, op);
125382cae269SKonstantin Komarov buf = Add2Ptr(buf, op);
125482cae269SKonstantin Komarov }
125582cae269SKonstantin Komarov
125682cae269SKonstantin Komarov if (!nb) {
125782cae269SKonstantin Komarov put_bh(bh);
125882cae269SKonstantin Komarov } else if (nbh >= ARRAY_SIZE(nb->bh)) {
125982cae269SKonstantin Komarov err = -EINVAL;
126082cae269SKonstantin Komarov goto out;
126182cae269SKonstantin Komarov } else {
126282cae269SKonstantin Komarov nb->bh[nbh++] = bh;
126382cae269SKonstantin Komarov nb->nbufs = nbh;
126482cae269SKonstantin Komarov }
126582cae269SKonstantin Komarov
126682cae269SKonstantin Komarov bytes -= op;
126782cae269SKonstantin Komarov if (!bytes)
126882cae269SKonstantin Komarov return 0;
126982cae269SKonstantin Komarov len32 -= op;
127082cae269SKonstantin Komarov block += 1;
127182cae269SKonstantin Komarov off = 0;
127282cae269SKonstantin Komarov
127382cae269SKonstantin Komarov } while (len32);
127482cae269SKonstantin Komarov
127582cae269SKonstantin Komarov vcn_next = vcn + clen;
127682cae269SKonstantin Komarov if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
127782cae269SKonstantin Komarov vcn != vcn_next) {
127882cae269SKonstantin Komarov err = -ENOENT;
127982cae269SKonstantin Komarov goto out;
128082cae269SKonstantin Komarov }
128182cae269SKonstantin Komarov
128282cae269SKonstantin Komarov if (lcn == SPARSE_LCN) {
128382cae269SKonstantin Komarov err = -EINVAL;
128482cae269SKonstantin Komarov goto out;
128582cae269SKonstantin Komarov }
128682cae269SKonstantin Komarov
128782cae269SKonstantin Komarov lbo = ((u64)lcn << cluster_bits);
128882cae269SKonstantin Komarov len = ((u64)clen << cluster_bits);
128982cae269SKonstantin Komarov }
129082cae269SKonstantin Komarov
129182cae269SKonstantin Komarov out:
129282cae269SKonstantin Komarov if (!nbh)
129382cae269SKonstantin Komarov return err;
129482cae269SKonstantin Komarov
129582cae269SKonstantin Komarov while (nbh) {
129682cae269SKonstantin Komarov put_bh(nb->bh[--nbh]);
129782cae269SKonstantin Komarov nb->bh[nbh] = NULL;
129882cae269SKonstantin Komarov }
129982cae269SKonstantin Komarov
130082cae269SKonstantin Komarov nb->nbufs = 0;
130182cae269SKonstantin Komarov return err;
130282cae269SKonstantin Komarov }
130382cae269SKonstantin Komarov
1304e8b8e97fSKari Argillander /*
1305e8b8e97fSKari Argillander * ntfs_read_bh
1306e8b8e97fSKari Argillander *
1307e8b8e97fSKari Argillander * Return: < 0 if error, 0 if ok, -E_NTFS_FIXUP if need to update fixups.
1308e8b8e97fSKari Argillander */
ntfs_read_bh(struct ntfs_sb_info * sbi,const struct runs_tree * run,u64 vbo,struct NTFS_RECORD_HEADER * rhdr,u32 bytes,struct ntfs_buffers * nb)130982cae269SKonstantin Komarov int ntfs_read_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
131082cae269SKonstantin Komarov struct NTFS_RECORD_HEADER *rhdr, u32 bytes,
131182cae269SKonstantin Komarov struct ntfs_buffers *nb)
131282cae269SKonstantin Komarov {
131382cae269SKonstantin Komarov int err = ntfs_read_run_nb(sbi, run, vbo, rhdr, bytes, nb);
131482cae269SKonstantin Komarov
131582cae269SKonstantin Komarov if (err)
131682cae269SKonstantin Komarov return err;
131782cae269SKonstantin Komarov return ntfs_fix_post_read(rhdr, nb->bytes, true);
131882cae269SKonstantin Komarov }
131982cae269SKonstantin Komarov
ntfs_get_bh(struct ntfs_sb_info * sbi,const struct runs_tree * run,u64 vbo,u32 bytes,struct ntfs_buffers * nb)132082cae269SKonstantin Komarov int ntfs_get_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
132182cae269SKonstantin Komarov u32 bytes, struct ntfs_buffers *nb)
132282cae269SKonstantin Komarov {
132382cae269SKonstantin Komarov int err = 0;
132482cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
132582cae269SKonstantin Komarov u32 blocksize = sb->s_blocksize;
132682cae269SKonstantin Komarov u8 cluster_bits = sbi->cluster_bits;
132782cae269SKonstantin Komarov CLST vcn_next, vcn = vbo >> cluster_bits;
132882cae269SKonstantin Komarov u32 off;
132982cae269SKonstantin Komarov u32 nbh = 0;
133082cae269SKonstantin Komarov CLST lcn, clen;
133182cae269SKonstantin Komarov u64 lbo, len;
133282cae269SKonstantin Komarov size_t idx;
133382cae269SKonstantin Komarov
133482cae269SKonstantin Komarov nb->bytes = bytes;
133582cae269SKonstantin Komarov
133682cae269SKonstantin Komarov if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
133782cae269SKonstantin Komarov err = -ENOENT;
133882cae269SKonstantin Komarov goto out;
133982cae269SKonstantin Komarov }
134082cae269SKonstantin Komarov
134182cae269SKonstantin Komarov off = vbo & sbi->cluster_mask;
134282cae269SKonstantin Komarov lbo = ((u64)lcn << cluster_bits) + off;
134382cae269SKonstantin Komarov len = ((u64)clen << cluster_bits) - off;
134482cae269SKonstantin Komarov
134582cae269SKonstantin Komarov nb->off = off = lbo & (blocksize - 1);
134682cae269SKonstantin Komarov
134782cae269SKonstantin Komarov for (;;) {
13486e3331eeSKari Argillander u32 len32 = min_t(u64, len, bytes);
134982cae269SKonstantin Komarov sector_t block = lbo >> sb->s_blocksize_bits;
135082cae269SKonstantin Komarov
135182cae269SKonstantin Komarov do {
135282cae269SKonstantin Komarov u32 op;
135382cae269SKonstantin Komarov struct buffer_head *bh;
135482cae269SKonstantin Komarov
135582cae269SKonstantin Komarov if (nbh >= ARRAY_SIZE(nb->bh)) {
135682cae269SKonstantin Komarov err = -EINVAL;
135782cae269SKonstantin Komarov goto out;
135882cae269SKonstantin Komarov }
135982cae269SKonstantin Komarov
136082cae269SKonstantin Komarov op = blocksize - off;
136182cae269SKonstantin Komarov if (op > len32)
136282cae269SKonstantin Komarov op = len32;
136382cae269SKonstantin Komarov
136482cae269SKonstantin Komarov if (op == blocksize) {
136582cae269SKonstantin Komarov bh = sb_getblk(sb, block);
136682cae269SKonstantin Komarov if (!bh) {
136782cae269SKonstantin Komarov err = -ENOMEM;
136882cae269SKonstantin Komarov goto out;
136982cae269SKonstantin Komarov }
137082cae269SKonstantin Komarov if (buffer_locked(bh))
137182cae269SKonstantin Komarov __wait_on_buffer(bh);
137282cae269SKonstantin Komarov set_buffer_uptodate(bh);
137382cae269SKonstantin Komarov } else {
137482cae269SKonstantin Komarov bh = ntfs_bread(sb, block);
137582cae269SKonstantin Komarov if (!bh) {
137682cae269SKonstantin Komarov err = -EIO;
137782cae269SKonstantin Komarov goto out;
137882cae269SKonstantin Komarov }
137982cae269SKonstantin Komarov }
138082cae269SKonstantin Komarov
138182cae269SKonstantin Komarov nb->bh[nbh++] = bh;
138282cae269SKonstantin Komarov bytes -= op;
138382cae269SKonstantin Komarov if (!bytes) {
138482cae269SKonstantin Komarov nb->nbufs = nbh;
138582cae269SKonstantin Komarov return 0;
138682cae269SKonstantin Komarov }
138782cae269SKonstantin Komarov
138882cae269SKonstantin Komarov block += 1;
138982cae269SKonstantin Komarov len32 -= op;
139082cae269SKonstantin Komarov off = 0;
139182cae269SKonstantin Komarov } while (len32);
139282cae269SKonstantin Komarov
139382cae269SKonstantin Komarov vcn_next = vcn + clen;
139482cae269SKonstantin Komarov if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
139582cae269SKonstantin Komarov vcn != vcn_next) {
139682cae269SKonstantin Komarov err = -ENOENT;
139782cae269SKonstantin Komarov goto out;
139882cae269SKonstantin Komarov }
139982cae269SKonstantin Komarov
140082cae269SKonstantin Komarov lbo = ((u64)lcn << cluster_bits);
140182cae269SKonstantin Komarov len = ((u64)clen << cluster_bits);
140282cae269SKonstantin Komarov }
140382cae269SKonstantin Komarov
140482cae269SKonstantin Komarov out:
140582cae269SKonstantin Komarov while (nbh) {
140682cae269SKonstantin Komarov put_bh(nb->bh[--nbh]);
140782cae269SKonstantin Komarov nb->bh[nbh] = NULL;
140882cae269SKonstantin Komarov }
140982cae269SKonstantin Komarov
141082cae269SKonstantin Komarov nb->nbufs = 0;
141182cae269SKonstantin Komarov
141282cae269SKonstantin Komarov return err;
141382cae269SKonstantin Komarov }
141482cae269SKonstantin Komarov
ntfs_write_bh(struct ntfs_sb_info * sbi,struct NTFS_RECORD_HEADER * rhdr,struct ntfs_buffers * nb,int sync)141582cae269SKonstantin Komarov int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
141682cae269SKonstantin Komarov struct ntfs_buffers *nb, int sync)
141782cae269SKonstantin Komarov {
141882cae269SKonstantin Komarov int err = 0;
141982cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
142082cae269SKonstantin Komarov u32 block_size = sb->s_blocksize;
142182cae269SKonstantin Komarov u32 bytes = nb->bytes;
142282cae269SKonstantin Komarov u32 off = nb->off;
142382cae269SKonstantin Komarov u16 fo = le16_to_cpu(rhdr->fix_off);
142482cae269SKonstantin Komarov u16 fn = le16_to_cpu(rhdr->fix_num);
142582cae269SKonstantin Komarov u32 idx;
142682cae269SKonstantin Komarov __le16 *fixup;
142782cae269SKonstantin Komarov __le16 sample;
142882cae269SKonstantin Komarov
142982cae269SKonstantin Komarov if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
143082cae269SKonstantin Komarov fn * SECTOR_SIZE > bytes) {
143182cae269SKonstantin Komarov return -EINVAL;
143282cae269SKonstantin Komarov }
143382cae269SKonstantin Komarov
143482cae269SKonstantin Komarov for (idx = 0; bytes && idx < nb->nbufs; idx += 1, off = 0) {
143582cae269SKonstantin Komarov u32 op = block_size - off;
143682cae269SKonstantin Komarov char *bh_data;
143782cae269SKonstantin Komarov struct buffer_head *bh = nb->bh[idx];
143882cae269SKonstantin Komarov __le16 *ptr, *end_data;
143982cae269SKonstantin Komarov
144082cae269SKonstantin Komarov if (op > bytes)
144182cae269SKonstantin Komarov op = bytes;
144282cae269SKonstantin Komarov
144382cae269SKonstantin Komarov if (buffer_locked(bh))
144482cae269SKonstantin Komarov __wait_on_buffer(bh);
144582cae269SKonstantin Komarov
14468335ebe1SKonstantin Komarov lock_buffer(bh);
144782cae269SKonstantin Komarov
144882cae269SKonstantin Komarov bh_data = bh->b_data + off;
144982cae269SKonstantin Komarov end_data = Add2Ptr(bh_data, op);
145082cae269SKonstantin Komarov memcpy(bh_data, rhdr, op);
145182cae269SKonstantin Komarov
145282cae269SKonstantin Komarov if (!idx) {
145382cae269SKonstantin Komarov u16 t16;
145482cae269SKonstantin Komarov
145582cae269SKonstantin Komarov fixup = Add2Ptr(bh_data, fo);
145682cae269SKonstantin Komarov sample = *fixup;
145782cae269SKonstantin Komarov t16 = le16_to_cpu(sample);
145882cae269SKonstantin Komarov if (t16 >= 0x7FFF) {
145982cae269SKonstantin Komarov sample = *fixup = cpu_to_le16(1);
146082cae269SKonstantin Komarov } else {
146182cae269SKonstantin Komarov sample = cpu_to_le16(t16 + 1);
146282cae269SKonstantin Komarov *fixup = sample;
146382cae269SKonstantin Komarov }
146482cae269SKonstantin Komarov
146582cae269SKonstantin Komarov *(__le16 *)Add2Ptr(rhdr, fo) = sample;
146682cae269SKonstantin Komarov }
146782cae269SKonstantin Komarov
146882cae269SKonstantin Komarov ptr = Add2Ptr(bh_data, SECTOR_SIZE - sizeof(short));
146982cae269SKonstantin Komarov
147082cae269SKonstantin Komarov do {
147182cae269SKonstantin Komarov *++fixup = *ptr;
147282cae269SKonstantin Komarov *ptr = sample;
147382cae269SKonstantin Komarov ptr += SECTOR_SIZE / sizeof(short);
147482cae269SKonstantin Komarov } while (ptr < end_data);
147582cae269SKonstantin Komarov
147682cae269SKonstantin Komarov set_buffer_uptodate(bh);
147782cae269SKonstantin Komarov mark_buffer_dirty(bh);
147882cae269SKonstantin Komarov unlock_buffer(bh);
147982cae269SKonstantin Komarov
148082cae269SKonstantin Komarov if (sync) {
148182cae269SKonstantin Komarov int err2 = sync_dirty_buffer(bh);
148282cae269SKonstantin Komarov
148382cae269SKonstantin Komarov if (!err && err2)
148482cae269SKonstantin Komarov err = err2;
148582cae269SKonstantin Komarov }
148682cae269SKonstantin Komarov
148782cae269SKonstantin Komarov bytes -= op;
148882cae269SKonstantin Komarov rhdr = Add2Ptr(rhdr, op);
148982cae269SKonstantin Komarov }
149082cae269SKonstantin Komarov
149182cae269SKonstantin Komarov return err;
149282cae269SKonstantin Komarov }
149382cae269SKonstantin Komarov
1494e8b8e97fSKari Argillander /*
1495e8b8e97fSKari Argillander * ntfs_bio_pages - Read/write pages from/to disk.
1496e8b8e97fSKari Argillander */
ntfs_bio_pages(struct ntfs_sb_info * sbi,const struct runs_tree * run,struct page ** pages,u32 nr_pages,u64 vbo,u32 bytes,enum req_op op)149782cae269SKonstantin Komarov int ntfs_bio_pages(struct ntfs_sb_info *sbi, const struct runs_tree *run,
149882cae269SKonstantin Komarov struct page **pages, u32 nr_pages, u64 vbo, u32 bytes,
1499ce6b5315SBart Van Assche enum req_op op)
150082cae269SKonstantin Komarov {
150182cae269SKonstantin Komarov int err = 0;
150282cae269SKonstantin Komarov struct bio *new, *bio = NULL;
150382cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
150482cae269SKonstantin Komarov struct block_device *bdev = sb->s_bdev;
150582cae269SKonstantin Komarov struct page *page;
150682cae269SKonstantin Komarov u8 cluster_bits = sbi->cluster_bits;
150782cae269SKonstantin Komarov CLST lcn, clen, vcn, vcn_next;
150882cae269SKonstantin Komarov u32 add, off, page_idx;
150982cae269SKonstantin Komarov u64 lbo, len;
151082cae269SKonstantin Komarov size_t run_idx;
151182cae269SKonstantin Komarov struct blk_plug plug;
151282cae269SKonstantin Komarov
151382cae269SKonstantin Komarov if (!bytes)
151482cae269SKonstantin Komarov return 0;
151582cae269SKonstantin Komarov
151682cae269SKonstantin Komarov blk_start_plug(&plug);
151782cae269SKonstantin Komarov
1518e8b8e97fSKari Argillander /* Align vbo and bytes to be 512 bytes aligned. */
151982cae269SKonstantin Komarov lbo = (vbo + bytes + 511) & ~511ull;
152082cae269SKonstantin Komarov vbo = vbo & ~511ull;
152182cae269SKonstantin Komarov bytes = lbo - vbo;
152282cae269SKonstantin Komarov
152382cae269SKonstantin Komarov vcn = vbo >> cluster_bits;
152482cae269SKonstantin Komarov if (!run_lookup_entry(run, vcn, &lcn, &clen, &run_idx)) {
152582cae269SKonstantin Komarov err = -ENOENT;
152682cae269SKonstantin Komarov goto out;
152782cae269SKonstantin Komarov }
152882cae269SKonstantin Komarov off = vbo & sbi->cluster_mask;
152982cae269SKonstantin Komarov page_idx = 0;
153082cae269SKonstantin Komarov page = pages[0];
153182cae269SKonstantin Komarov
153282cae269SKonstantin Komarov for (;;) {
153382cae269SKonstantin Komarov lbo = ((u64)lcn << cluster_bits) + off;
153482cae269SKonstantin Komarov len = ((u64)clen << cluster_bits) - off;
153582cae269SKonstantin Komarov new_bio:
153607888c66SChristoph Hellwig new = bio_alloc(bdev, nr_pages - page_idx, op, GFP_NOFS);
153782cae269SKonstantin Komarov if (bio) {
153882cae269SKonstantin Komarov bio_chain(bio, new);
153982cae269SKonstantin Komarov submit_bio(bio);
154082cae269SKonstantin Komarov }
154182cae269SKonstantin Komarov bio = new;
154282cae269SKonstantin Komarov bio->bi_iter.bi_sector = lbo >> 9;
154382cae269SKonstantin Komarov
154482cae269SKonstantin Komarov while (len) {
154582cae269SKonstantin Komarov off = vbo & (PAGE_SIZE - 1);
154682cae269SKonstantin Komarov add = off + len > PAGE_SIZE ? (PAGE_SIZE - off) : len;
154782cae269SKonstantin Komarov
154882cae269SKonstantin Komarov if (bio_add_page(bio, page, add, off) < add)
154982cae269SKonstantin Komarov goto new_bio;
155082cae269SKonstantin Komarov
155182cae269SKonstantin Komarov if (bytes <= add)
155282cae269SKonstantin Komarov goto out;
155382cae269SKonstantin Komarov bytes -= add;
155482cae269SKonstantin Komarov vbo += add;
155582cae269SKonstantin Komarov
155682cae269SKonstantin Komarov if (add + off == PAGE_SIZE) {
155782cae269SKonstantin Komarov page_idx += 1;
155882cae269SKonstantin Komarov if (WARN_ON(page_idx >= nr_pages)) {
155982cae269SKonstantin Komarov err = -EINVAL;
156082cae269SKonstantin Komarov goto out;
156182cae269SKonstantin Komarov }
156282cae269SKonstantin Komarov page = pages[page_idx];
156382cae269SKonstantin Komarov }
156482cae269SKonstantin Komarov
156582cae269SKonstantin Komarov if (len <= add)
156682cae269SKonstantin Komarov break;
156782cae269SKonstantin Komarov len -= add;
156882cae269SKonstantin Komarov lbo += add;
156982cae269SKonstantin Komarov }
157082cae269SKonstantin Komarov
157182cae269SKonstantin Komarov vcn_next = vcn + clen;
157282cae269SKonstantin Komarov if (!run_get_entry(run, ++run_idx, &vcn, &lcn, &clen) ||
157382cae269SKonstantin Komarov vcn != vcn_next) {
157482cae269SKonstantin Komarov err = -ENOENT;
157582cae269SKonstantin Komarov goto out;
157682cae269SKonstantin Komarov }
157782cae269SKonstantin Komarov off = 0;
157882cae269SKonstantin Komarov }
157982cae269SKonstantin Komarov out:
158082cae269SKonstantin Komarov if (bio) {
158182cae269SKonstantin Komarov if (!err)
158282cae269SKonstantin Komarov err = submit_bio_wait(bio);
158382cae269SKonstantin Komarov bio_put(bio);
158482cae269SKonstantin Komarov }
158582cae269SKonstantin Komarov blk_finish_plug(&plug);
158682cae269SKonstantin Komarov
158782cae269SKonstantin Komarov return err;
158882cae269SKonstantin Komarov }
158982cae269SKonstantin Komarov
159082cae269SKonstantin Komarov /*
1591e8b8e97fSKari Argillander * ntfs_bio_fill_1 - Helper for ntfs_loadlog_and_replay().
1592e8b8e97fSKari Argillander *
1593e8b8e97fSKari Argillander * Fill on-disk logfile range by (-1)
1594e8b8e97fSKari Argillander * this means empty logfile.
159582cae269SKonstantin Komarov */
ntfs_bio_fill_1(struct ntfs_sb_info * sbi,const struct runs_tree * run)159682cae269SKonstantin Komarov int ntfs_bio_fill_1(struct ntfs_sb_info *sbi, const struct runs_tree *run)
159782cae269SKonstantin Komarov {
159882cae269SKonstantin Komarov int err = 0;
159982cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
160082cae269SKonstantin Komarov struct block_device *bdev = sb->s_bdev;
160182cae269SKonstantin Komarov u8 cluster_bits = sbi->cluster_bits;
160282cae269SKonstantin Komarov struct bio *new, *bio = NULL;
160382cae269SKonstantin Komarov CLST lcn, clen;
160482cae269SKonstantin Komarov u64 lbo, len;
160582cae269SKonstantin Komarov size_t run_idx;
160682cae269SKonstantin Komarov struct page *fill;
160782cae269SKonstantin Komarov void *kaddr;
160882cae269SKonstantin Komarov struct blk_plug plug;
160982cae269SKonstantin Komarov
161082cae269SKonstantin Komarov fill = alloc_page(GFP_KERNEL);
161182cae269SKonstantin Komarov if (!fill)
161282cae269SKonstantin Komarov return -ENOMEM;
161382cae269SKonstantin Komarov
161482cae269SKonstantin Komarov kaddr = kmap_atomic(fill);
161582cae269SKonstantin Komarov memset(kaddr, -1, PAGE_SIZE);
161682cae269SKonstantin Komarov kunmap_atomic(kaddr);
161782cae269SKonstantin Komarov flush_dcache_page(fill);
161882cae269SKonstantin Komarov lock_page(fill);
161982cae269SKonstantin Komarov
162082cae269SKonstantin Komarov if (!run_lookup_entry(run, 0, &lcn, &clen, &run_idx)) {
162182cae269SKonstantin Komarov err = -ENOENT;
162282cae269SKonstantin Komarov goto out;
162382cae269SKonstantin Komarov }
162482cae269SKonstantin Komarov
162582cae269SKonstantin Komarov /*
1626e8b8e97fSKari Argillander * TODO: Try blkdev_issue_write_same.
162782cae269SKonstantin Komarov */
162882cae269SKonstantin Komarov blk_start_plug(&plug);
162982cae269SKonstantin Komarov do {
163082cae269SKonstantin Komarov lbo = (u64)lcn << cluster_bits;
163182cae269SKonstantin Komarov len = (u64)clen << cluster_bits;
163282cae269SKonstantin Komarov new_bio:
163307888c66SChristoph Hellwig new = bio_alloc(bdev, BIO_MAX_VECS, REQ_OP_WRITE, GFP_NOFS);
163482cae269SKonstantin Komarov if (bio) {
163582cae269SKonstantin Komarov bio_chain(bio, new);
163682cae269SKonstantin Komarov submit_bio(bio);
163782cae269SKonstantin Komarov }
163882cae269SKonstantin Komarov bio = new;
163982cae269SKonstantin Komarov bio->bi_iter.bi_sector = lbo >> 9;
164082cae269SKonstantin Komarov
164182cae269SKonstantin Komarov for (;;) {
164282cae269SKonstantin Komarov u32 add = len > PAGE_SIZE ? PAGE_SIZE : len;
164382cae269SKonstantin Komarov
164482cae269SKonstantin Komarov if (bio_add_page(bio, fill, add, 0) < add)
164582cae269SKonstantin Komarov goto new_bio;
164682cae269SKonstantin Komarov
164782cae269SKonstantin Komarov lbo += add;
164882cae269SKonstantin Komarov if (len <= add)
164982cae269SKonstantin Komarov break;
165082cae269SKonstantin Komarov len -= add;
165182cae269SKonstantin Komarov }
165282cae269SKonstantin Komarov } while (run_get_entry(run, ++run_idx, NULL, &lcn, &clen));
165382cae269SKonstantin Komarov
165482cae269SKonstantin Komarov if (!err)
165582cae269SKonstantin Komarov err = submit_bio_wait(bio);
165682cae269SKonstantin Komarov bio_put(bio);
1657365ab499SDan Carpenter
165882cae269SKonstantin Komarov blk_finish_plug(&plug);
165982cae269SKonstantin Komarov out:
166082cae269SKonstantin Komarov unlock_page(fill);
166182cae269SKonstantin Komarov put_page(fill);
166282cae269SKonstantin Komarov
166382cae269SKonstantin Komarov return err;
166482cae269SKonstantin Komarov }
166582cae269SKonstantin Komarov
ntfs_vbo_to_lbo(struct ntfs_sb_info * sbi,const struct runs_tree * run,u64 vbo,u64 * lbo,u64 * bytes)166682cae269SKonstantin Komarov int ntfs_vbo_to_lbo(struct ntfs_sb_info *sbi, const struct runs_tree *run,
166782cae269SKonstantin Komarov u64 vbo, u64 *lbo, u64 *bytes)
166882cae269SKonstantin Komarov {
166982cae269SKonstantin Komarov u32 off;
167082cae269SKonstantin Komarov CLST lcn, len;
167182cae269SKonstantin Komarov u8 cluster_bits = sbi->cluster_bits;
167282cae269SKonstantin Komarov
167382cae269SKonstantin Komarov if (!run_lookup_entry(run, vbo >> cluster_bits, &lcn, &len, NULL))
167482cae269SKonstantin Komarov return -ENOENT;
167582cae269SKonstantin Komarov
167682cae269SKonstantin Komarov off = vbo & sbi->cluster_mask;
167782cae269SKonstantin Komarov *lbo = lcn == SPARSE_LCN ? -1 : (((u64)lcn << cluster_bits) + off);
167882cae269SKonstantin Komarov *bytes = ((u64)len << cluster_bits) - off;
167982cae269SKonstantin Komarov
168082cae269SKonstantin Komarov return 0;
168182cae269SKonstantin Komarov }
168282cae269SKonstantin Komarov
ntfs_new_inode(struct ntfs_sb_info * sbi,CLST rno,enum RECORD_FLAG flag)1683a81f47c4SKonstantin Komarov struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno,
1684a81f47c4SKonstantin Komarov enum RECORD_FLAG flag)
168582cae269SKonstantin Komarov {
168682cae269SKonstantin Komarov int err = 0;
168782cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
168882cae269SKonstantin Komarov struct inode *inode = new_inode(sb);
168982cae269SKonstantin Komarov struct ntfs_inode *ni;
169082cae269SKonstantin Komarov
169182cae269SKonstantin Komarov if (!inode)
169282cae269SKonstantin Komarov return ERR_PTR(-ENOMEM);
169382cae269SKonstantin Komarov
169482cae269SKonstantin Komarov ni = ntfs_i(inode);
169582cae269SKonstantin Komarov
1696a81f47c4SKonstantin Komarov err = mi_format_new(&ni->mi, sbi, rno, flag, false);
169782cae269SKonstantin Komarov if (err)
169882cae269SKonstantin Komarov goto out;
169982cae269SKonstantin Komarov
170082cae269SKonstantin Komarov inode->i_ino = rno;
170182cae269SKonstantin Komarov if (insert_inode_locked(inode) < 0) {
170282cae269SKonstantin Komarov err = -EIO;
170382cae269SKonstantin Komarov goto out;
170482cae269SKonstantin Komarov }
170582cae269SKonstantin Komarov
170682cae269SKonstantin Komarov out:
170782cae269SKonstantin Komarov if (err) {
1708db2a3cc6SYe Bin make_bad_inode(inode);
170982cae269SKonstantin Komarov iput(inode);
171082cae269SKonstantin Komarov ni = ERR_PTR(err);
171182cae269SKonstantin Komarov }
171282cae269SKonstantin Komarov return ni;
171382cae269SKonstantin Komarov }
171482cae269SKonstantin Komarov
171582cae269SKonstantin Komarov /*
171682cae269SKonstantin Komarov * O:BAG:BAD:(A;OICI;FA;;;WD)
1717e8b8e97fSKari Argillander * Owner S-1-5-32-544 (Administrators)
1718e8b8e97fSKari Argillander * Group S-1-5-32-544 (Administrators)
171982cae269SKonstantin Komarov * ACE: allow S-1-1-0 (Everyone) with FILE_ALL_ACCESS
172082cae269SKonstantin Komarov */
172182cae269SKonstantin Komarov const u8 s_default_security[] __aligned(8) = {
172282cae269SKonstantin Komarov 0x01, 0x00, 0x04, 0x80, 0x30, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
172382cae269SKonstantin Komarov 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1C, 0x00,
172482cae269SKonstantin Komarov 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x00, 0xFF, 0x01, 0x1F, 0x00,
172582cae269SKonstantin Komarov 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
172682cae269SKonstantin Komarov 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
172782cae269SKonstantin Komarov 0x20, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
172882cae269SKonstantin Komarov 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00,
172982cae269SKonstantin Komarov };
173082cae269SKonstantin Komarov
173182cae269SKonstantin Komarov static_assert(sizeof(s_default_security) == 0x50);
173282cae269SKonstantin Komarov
sid_length(const struct SID * sid)173382cae269SKonstantin Komarov static inline u32 sid_length(const struct SID *sid)
173482cae269SKonstantin Komarov {
173582cae269SKonstantin Komarov return struct_size(sid, SubAuthority, sid->SubAuthorityCount);
173682cae269SKonstantin Komarov }
173782cae269SKonstantin Komarov
173882cae269SKonstantin Komarov /*
1739e8b8e97fSKari Argillander * is_acl_valid
1740e8b8e97fSKari Argillander *
1741e8b8e97fSKari Argillander * Thanks Mark Harmstone for idea.
174282cae269SKonstantin Komarov */
is_acl_valid(const struct ACL * acl,u32 len)174382cae269SKonstantin Komarov static bool is_acl_valid(const struct ACL *acl, u32 len)
174482cae269SKonstantin Komarov {
174582cae269SKonstantin Komarov const struct ACE_HEADER *ace;
174682cae269SKonstantin Komarov u32 i;
174782cae269SKonstantin Komarov u16 ace_count, ace_size;
174882cae269SKonstantin Komarov
174982cae269SKonstantin Komarov if (acl->AclRevision != ACL_REVISION &&
175082cae269SKonstantin Komarov acl->AclRevision != ACL_REVISION_DS) {
175182cae269SKonstantin Komarov /*
175282cae269SKonstantin Komarov * This value should be ACL_REVISION, unless the ACL contains an
175382cae269SKonstantin Komarov * object-specific ACE, in which case this value must be ACL_REVISION_DS.
175482cae269SKonstantin Komarov * All ACEs in an ACL must be at the same revision level.
175582cae269SKonstantin Komarov */
175682cae269SKonstantin Komarov return false;
175782cae269SKonstantin Komarov }
175882cae269SKonstantin Komarov
175982cae269SKonstantin Komarov if (acl->Sbz1)
176082cae269SKonstantin Komarov return false;
176182cae269SKonstantin Komarov
176282cae269SKonstantin Komarov if (le16_to_cpu(acl->AclSize) > len)
176382cae269SKonstantin Komarov return false;
176482cae269SKonstantin Komarov
176582cae269SKonstantin Komarov if (acl->Sbz2)
176682cae269SKonstantin Komarov return false;
176782cae269SKonstantin Komarov
176882cae269SKonstantin Komarov len -= sizeof(struct ACL);
176982cae269SKonstantin Komarov ace = (struct ACE_HEADER *)&acl[1];
177082cae269SKonstantin Komarov ace_count = le16_to_cpu(acl->AceCount);
177182cae269SKonstantin Komarov
177282cae269SKonstantin Komarov for (i = 0; i < ace_count; i++) {
177382cae269SKonstantin Komarov if (len < sizeof(struct ACE_HEADER))
177482cae269SKonstantin Komarov return false;
177582cae269SKonstantin Komarov
177682cae269SKonstantin Komarov ace_size = le16_to_cpu(ace->AceSize);
177782cae269SKonstantin Komarov if (len < ace_size)
177882cae269SKonstantin Komarov return false;
177982cae269SKonstantin Komarov
178082cae269SKonstantin Komarov len -= ace_size;
178182cae269SKonstantin Komarov ace = Add2Ptr(ace, ace_size);
178282cae269SKonstantin Komarov }
178382cae269SKonstantin Komarov
178482cae269SKonstantin Komarov return true;
178582cae269SKonstantin Komarov }
178682cae269SKonstantin Komarov
is_sd_valid(const struct SECURITY_DESCRIPTOR_RELATIVE * sd,u32 len)178782cae269SKonstantin Komarov bool is_sd_valid(const struct SECURITY_DESCRIPTOR_RELATIVE *sd, u32 len)
178882cae269SKonstantin Komarov {
178982cae269SKonstantin Komarov u32 sd_owner, sd_group, sd_sacl, sd_dacl;
179082cae269SKonstantin Komarov
179182cae269SKonstantin Komarov if (len < sizeof(struct SECURITY_DESCRIPTOR_RELATIVE))
179282cae269SKonstantin Komarov return false;
179382cae269SKonstantin Komarov
179482cae269SKonstantin Komarov if (sd->Revision != 1)
179582cae269SKonstantin Komarov return false;
179682cae269SKonstantin Komarov
179782cae269SKonstantin Komarov if (sd->Sbz1)
179882cae269SKonstantin Komarov return false;
179982cae269SKonstantin Komarov
180082cae269SKonstantin Komarov if (!(sd->Control & SE_SELF_RELATIVE))
180182cae269SKonstantin Komarov return false;
180282cae269SKonstantin Komarov
180382cae269SKonstantin Komarov sd_owner = le32_to_cpu(sd->Owner);
180482cae269SKonstantin Komarov if (sd_owner) {
180582cae269SKonstantin Komarov const struct SID *owner = Add2Ptr(sd, sd_owner);
180682cae269SKonstantin Komarov
180782cae269SKonstantin Komarov if (sd_owner + offsetof(struct SID, SubAuthority) > len)
180882cae269SKonstantin Komarov return false;
180982cae269SKonstantin Komarov
181082cae269SKonstantin Komarov if (owner->Revision != 1)
181182cae269SKonstantin Komarov return false;
181282cae269SKonstantin Komarov
181382cae269SKonstantin Komarov if (sd_owner + sid_length(owner) > len)
181482cae269SKonstantin Komarov return false;
181582cae269SKonstantin Komarov }
181682cae269SKonstantin Komarov
181782cae269SKonstantin Komarov sd_group = le32_to_cpu(sd->Group);
181882cae269SKonstantin Komarov if (sd_group) {
181982cae269SKonstantin Komarov const struct SID *group = Add2Ptr(sd, sd_group);
182082cae269SKonstantin Komarov
182182cae269SKonstantin Komarov if (sd_group + offsetof(struct SID, SubAuthority) > len)
182282cae269SKonstantin Komarov return false;
182382cae269SKonstantin Komarov
182482cae269SKonstantin Komarov if (group->Revision != 1)
182582cae269SKonstantin Komarov return false;
182682cae269SKonstantin Komarov
182782cae269SKonstantin Komarov if (sd_group + sid_length(group) > len)
182882cae269SKonstantin Komarov return false;
182982cae269SKonstantin Komarov }
183082cae269SKonstantin Komarov
183182cae269SKonstantin Komarov sd_sacl = le32_to_cpu(sd->Sacl);
183282cae269SKonstantin Komarov if (sd_sacl) {
183382cae269SKonstantin Komarov const struct ACL *sacl = Add2Ptr(sd, sd_sacl);
183482cae269SKonstantin Komarov
183582cae269SKonstantin Komarov if (sd_sacl + sizeof(struct ACL) > len)
183682cae269SKonstantin Komarov return false;
183782cae269SKonstantin Komarov
183882cae269SKonstantin Komarov if (!is_acl_valid(sacl, len - sd_sacl))
183982cae269SKonstantin Komarov return false;
184082cae269SKonstantin Komarov }
184182cae269SKonstantin Komarov
184282cae269SKonstantin Komarov sd_dacl = le32_to_cpu(sd->Dacl);
184382cae269SKonstantin Komarov if (sd_dacl) {
184482cae269SKonstantin Komarov const struct ACL *dacl = Add2Ptr(sd, sd_dacl);
184582cae269SKonstantin Komarov
184682cae269SKonstantin Komarov if (sd_dacl + sizeof(struct ACL) > len)
184782cae269SKonstantin Komarov return false;
184882cae269SKonstantin Komarov
184982cae269SKonstantin Komarov if (!is_acl_valid(dacl, len - sd_dacl))
185082cae269SKonstantin Komarov return false;
185182cae269SKonstantin Komarov }
185282cae269SKonstantin Komarov
185382cae269SKonstantin Komarov return true;
185482cae269SKonstantin Komarov }
185582cae269SKonstantin Komarov
185682cae269SKonstantin Komarov /*
1857e8b8e97fSKari Argillander * ntfs_security_init - Load and parse $Secure.
185882cae269SKonstantin Komarov */
ntfs_security_init(struct ntfs_sb_info * sbi)185982cae269SKonstantin Komarov int ntfs_security_init(struct ntfs_sb_info *sbi)
186082cae269SKonstantin Komarov {
186182cae269SKonstantin Komarov int err;
186282cae269SKonstantin Komarov struct super_block *sb = sbi->sb;
186382cae269SKonstantin Komarov struct inode *inode;
186482cae269SKonstantin Komarov struct ntfs_inode *ni;
186582cae269SKonstantin Komarov struct MFT_REF ref;
186682cae269SKonstantin Komarov struct ATTRIB *attr;
186782cae269SKonstantin Komarov struct ATTR_LIST_ENTRY *le;
186882cae269SKonstantin Komarov u64 sds_size;
18698c01308bSNathan Chancellor size_t off;
187082cae269SKonstantin Komarov struct NTFS_DE *ne;
187182cae269SKonstantin Komarov struct NTFS_DE_SII *sii_e;
187282cae269SKonstantin Komarov struct ntfs_fnd *fnd_sii = NULL;
187382cae269SKonstantin Komarov const struct INDEX_ROOT *root_sii;
187482cae269SKonstantin Komarov const struct INDEX_ROOT *root_sdh;
187582cae269SKonstantin Komarov struct ntfs_index *indx_sdh = &sbi->security.index_sdh;
187682cae269SKonstantin Komarov struct ntfs_index *indx_sii = &sbi->security.index_sii;
187782cae269SKonstantin Komarov
187882cae269SKonstantin Komarov ref.low = cpu_to_le32(MFT_REC_SECURE);
187982cae269SKonstantin Komarov ref.high = 0;
188082cae269SKonstantin Komarov ref.seq = cpu_to_le16(MFT_REC_SECURE);
188182cae269SKonstantin Komarov
188282cae269SKonstantin Komarov inode = ntfs_iget5(sb, &ref, &NAME_SECURE);
188382cae269SKonstantin Komarov if (IS_ERR(inode)) {
188482cae269SKonstantin Komarov err = PTR_ERR(inode);
1885e43f6ec2SKonstantin Komarov ntfs_err(sb, "Failed to load $Secure (%d).", err);
188682cae269SKonstantin Komarov inode = NULL;
188782cae269SKonstantin Komarov goto out;
188882cae269SKonstantin Komarov }
188982cae269SKonstantin Komarov
189082cae269SKonstantin Komarov ni = ntfs_i(inode);
189182cae269SKonstantin Komarov
189282cae269SKonstantin Komarov le = NULL;
189382cae269SKonstantin Komarov
189482cae269SKonstantin Komarov attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SDH_NAME,
189582cae269SKonstantin Komarov ARRAY_SIZE(SDH_NAME), NULL, NULL);
1896e43f6ec2SKonstantin Komarov if (!attr ||
1897e43f6ec2SKonstantin Komarov !(root_sdh = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) ||
1898fc499245SKonstantin Komarov root_sdh->type != ATTR_ZERO ||
1899bfcdbae0SEdward Lo root_sdh->rule != NTFS_COLLATION_TYPE_SECURITY_HASH ||
1900fc499245SKonstantin Komarov offsetof(struct INDEX_ROOT, ihdr) +
1901fc499245SKonstantin Komarov le32_to_cpu(root_sdh->ihdr.used) >
1902fc499245SKonstantin Komarov le32_to_cpu(attr->res.data_size)) {
1903e43f6ec2SKonstantin Komarov ntfs_err(sb, "$Secure::$SDH is corrupted.");
190482cae269SKonstantin Komarov err = -EINVAL;
190582cae269SKonstantin Komarov goto out;
190682cae269SKonstantin Komarov }
190782cae269SKonstantin Komarov
190882cae269SKonstantin Komarov err = indx_init(indx_sdh, sbi, attr, INDEX_MUTEX_SDH);
1909e43f6ec2SKonstantin Komarov if (err) {
1910e43f6ec2SKonstantin Komarov ntfs_err(sb, "Failed to initialize $Secure::$SDH (%d).", err);
191182cae269SKonstantin Komarov goto out;
191282cae269SKonstantin Komarov }
191382cae269SKonstantin Komarov
1914e43f6ec2SKonstantin Komarov attr = ni_find_attr(ni, attr, &le, ATTR_ROOT, SII_NAME,
1915e43f6ec2SKonstantin Komarov ARRAY_SIZE(SII_NAME), NULL, NULL);
1916e43f6ec2SKonstantin Komarov if (!attr ||
1917e43f6ec2SKonstantin Komarov !(root_sii = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) ||
1918fc499245SKonstantin Komarov root_sii->type != ATTR_ZERO ||
1919bfcdbae0SEdward Lo root_sii->rule != NTFS_COLLATION_TYPE_UINT ||
1920fc499245SKonstantin Komarov offsetof(struct INDEX_ROOT, ihdr) +
1921fc499245SKonstantin Komarov le32_to_cpu(root_sii->ihdr.used) >
1922fc499245SKonstantin Komarov le32_to_cpu(attr->res.data_size)) {
1923e43f6ec2SKonstantin Komarov ntfs_err(sb, "$Secure::$SII is corrupted.");
192482cae269SKonstantin Komarov err = -EINVAL;
192582cae269SKonstantin Komarov goto out;
192682cae269SKonstantin Komarov }
192782cae269SKonstantin Komarov
192882cae269SKonstantin Komarov err = indx_init(indx_sii, sbi, attr, INDEX_MUTEX_SII);
1929e43f6ec2SKonstantin Komarov if (err) {
1930e43f6ec2SKonstantin Komarov ntfs_err(sb, "Failed to initialize $Secure::$SII (%d).", err);
193182cae269SKonstantin Komarov goto out;
1932e43f6ec2SKonstantin Komarov }
193382cae269SKonstantin Komarov
193482cae269SKonstantin Komarov fnd_sii = fnd_get();
193582cae269SKonstantin Komarov if (!fnd_sii) {
193682cae269SKonstantin Komarov err = -ENOMEM;
193782cae269SKonstantin Komarov goto out;
193882cae269SKonstantin Komarov }
193982cae269SKonstantin Komarov
194082cae269SKonstantin Komarov sds_size = inode->i_size;
194182cae269SKonstantin Komarov
1942e8b8e97fSKari Argillander /* Find the last valid Id. */
194382cae269SKonstantin Komarov sbi->security.next_id = SECURITY_ID_FIRST;
1944e8b8e97fSKari Argillander /* Always write new security at the end of bucket. */
194582cae269SKonstantin Komarov sbi->security.next_off =
1946fa3cacf5SKari Argillander ALIGN(sds_size - SecurityDescriptorsBlockSize, 16);
194782cae269SKonstantin Komarov
194882cae269SKonstantin Komarov off = 0;
194982cae269SKonstantin Komarov ne = NULL;
195082cae269SKonstantin Komarov
195182cae269SKonstantin Komarov for (;;) {
195282cae269SKonstantin Komarov u32 next_id;
195382cae269SKonstantin Komarov
195482cae269SKonstantin Komarov err = indx_find_raw(indx_sii, ni, root_sii, &ne, &off, fnd_sii);
195582cae269SKonstantin Komarov if (err || !ne)
195682cae269SKonstantin Komarov break;
195782cae269SKonstantin Komarov
195882cae269SKonstantin Komarov sii_e = (struct NTFS_DE_SII *)ne;
1959a81f47c4SKonstantin Komarov if (le16_to_cpu(ne->view.data_size) < sizeof(sii_e->sec_hdr))
196082cae269SKonstantin Komarov continue;
196182cae269SKonstantin Komarov
196282cae269SKonstantin Komarov next_id = le32_to_cpu(sii_e->sec_id) + 1;
196382cae269SKonstantin Komarov if (next_id >= sbi->security.next_id)
196482cae269SKonstantin Komarov sbi->security.next_id = next_id;
196582cae269SKonstantin Komarov }
196682cae269SKonstantin Komarov
196782cae269SKonstantin Komarov sbi->security.ni = ni;
196882cae269SKonstantin Komarov inode = NULL;
196982cae269SKonstantin Komarov out:
197082cae269SKonstantin Komarov iput(inode);
197182cae269SKonstantin Komarov fnd_put(fnd_sii);
197282cae269SKonstantin Komarov
197382cae269SKonstantin Komarov return err;
197482cae269SKonstantin Komarov }
197582cae269SKonstantin Komarov
197682cae269SKonstantin Komarov /*
1977e8b8e97fSKari Argillander * ntfs_get_security_by_id - Read security descriptor by id.
197882cae269SKonstantin Komarov */
ntfs_get_security_by_id(struct ntfs_sb_info * sbi,__le32 security_id,struct SECURITY_DESCRIPTOR_RELATIVE ** sd,size_t * size)197982cae269SKonstantin Komarov int ntfs_get_security_by_id(struct ntfs_sb_info *sbi, __le32 security_id,
198082cae269SKonstantin Komarov struct SECURITY_DESCRIPTOR_RELATIVE **sd,
198182cae269SKonstantin Komarov size_t *size)
198282cae269SKonstantin Komarov {
198382cae269SKonstantin Komarov int err;
198482cae269SKonstantin Komarov int diff;
198582cae269SKonstantin Komarov struct ntfs_inode *ni = sbi->security.ni;
198682cae269SKonstantin Komarov struct ntfs_index *indx = &sbi->security.index_sii;
198782cae269SKonstantin Komarov void *p = NULL;
198882cae269SKonstantin Komarov struct NTFS_DE_SII *sii_e;
198982cae269SKonstantin Komarov struct ntfs_fnd *fnd_sii;
199082cae269SKonstantin Komarov struct SECURITY_HDR d_security;
199182cae269SKonstantin Komarov const struct INDEX_ROOT *root_sii;
199282cae269SKonstantin Komarov u32 t32;
199382cae269SKonstantin Komarov
199482cae269SKonstantin Komarov *sd = NULL;
199582cae269SKonstantin Komarov
199682cae269SKonstantin Komarov mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_SECURITY);
199782cae269SKonstantin Komarov
199882cae269SKonstantin Komarov fnd_sii = fnd_get();
199982cae269SKonstantin Komarov if (!fnd_sii) {
200082cae269SKonstantin Komarov err = -ENOMEM;
200182cae269SKonstantin Komarov goto out;
200282cae269SKonstantin Komarov }
200382cae269SKonstantin Komarov
200482cae269SKonstantin Komarov root_sii = indx_get_root(indx, ni, NULL, NULL);
200582cae269SKonstantin Komarov if (!root_sii) {
200682cae269SKonstantin Komarov err = -EINVAL;
200782cae269SKonstantin Komarov goto out;
200882cae269SKonstantin Komarov }
200982cae269SKonstantin Komarov
2010e8b8e97fSKari Argillander /* Try to find this SECURITY descriptor in SII indexes. */
201182cae269SKonstantin Komarov err = indx_find(indx, ni, root_sii, &security_id, sizeof(security_id),
201282cae269SKonstantin Komarov NULL, &diff, (struct NTFS_DE **)&sii_e, fnd_sii);
201382cae269SKonstantin Komarov if (err)
201482cae269SKonstantin Komarov goto out;
201582cae269SKonstantin Komarov
201682cae269SKonstantin Komarov if (diff)
201782cae269SKonstantin Komarov goto out;
201882cae269SKonstantin Komarov
201982cae269SKonstantin Komarov t32 = le32_to_cpu(sii_e->sec_hdr.size);
2020a81f47c4SKonstantin Komarov if (t32 < sizeof(struct SECURITY_HDR)) {
202182cae269SKonstantin Komarov err = -EINVAL;
202282cae269SKonstantin Komarov goto out;
202382cae269SKonstantin Komarov }
202482cae269SKonstantin Komarov
2025a81f47c4SKonstantin Komarov if (t32 > sizeof(struct SECURITY_HDR) + 0x10000) {
2026e8b8e97fSKari Argillander /* Looks like too big security. 0x10000 - is arbitrary big number. */
202782cae269SKonstantin Komarov err = -EFBIG;
202882cae269SKonstantin Komarov goto out;
202982cae269SKonstantin Komarov }
203082cae269SKonstantin Komarov
2031a81f47c4SKonstantin Komarov *size = t32 - sizeof(struct SECURITY_HDR);
203282cae269SKonstantin Komarov
2033195c52bdSKari Argillander p = kmalloc(*size, GFP_NOFS);
203482cae269SKonstantin Komarov if (!p) {
203582cae269SKonstantin Komarov err = -ENOMEM;
203682cae269SKonstantin Komarov goto out;
203782cae269SKonstantin Komarov }
203882cae269SKonstantin Komarov
203982cae269SKonstantin Komarov err = ntfs_read_run_nb(sbi, &ni->file.run,
204082cae269SKonstantin Komarov le64_to_cpu(sii_e->sec_hdr.off), &d_security,
204182cae269SKonstantin Komarov sizeof(d_security), NULL);
204282cae269SKonstantin Komarov if (err)
204382cae269SKonstantin Komarov goto out;
204482cae269SKonstantin Komarov
2045a81f47c4SKonstantin Komarov if (memcmp(&d_security, &sii_e->sec_hdr, sizeof(d_security))) {
204682cae269SKonstantin Komarov err = -EINVAL;
204782cae269SKonstantin Komarov goto out;
204882cae269SKonstantin Komarov }
204982cae269SKonstantin Komarov
205082cae269SKonstantin Komarov err = ntfs_read_run_nb(sbi, &ni->file.run,
205182cae269SKonstantin Komarov le64_to_cpu(sii_e->sec_hdr.off) +
2052a81f47c4SKonstantin Komarov sizeof(struct SECURITY_HDR),
205382cae269SKonstantin Komarov p, *size, NULL);
205482cae269SKonstantin Komarov if (err)
205582cae269SKonstantin Komarov goto out;
205682cae269SKonstantin Komarov
205782cae269SKonstantin Komarov *sd = p;
205882cae269SKonstantin Komarov p = NULL;
205982cae269SKonstantin Komarov
206082cae269SKonstantin Komarov out:
2061195c52bdSKari Argillander kfree(p);
206282cae269SKonstantin Komarov fnd_put(fnd_sii);
206382cae269SKonstantin Komarov ni_unlock(ni);
206482cae269SKonstantin Komarov
206582cae269SKonstantin Komarov return err;
206682cae269SKonstantin Komarov }
206782cae269SKonstantin Komarov
206882cae269SKonstantin Komarov /*
2069e8b8e97fSKari Argillander * ntfs_insert_security - Insert security descriptor into $Secure::SDS.
207082cae269SKonstantin Komarov *
207182cae269SKonstantin Komarov * SECURITY Descriptor Stream data is organized into chunks of 256K bytes
207282cae269SKonstantin Komarov * and it contains a mirror copy of each security descriptor. When writing
207382cae269SKonstantin Komarov * to a security descriptor at location X, another copy will be written at
207482cae269SKonstantin Komarov * location (X+256K).
207582cae269SKonstantin Komarov * When writing a security descriptor that will cross the 256K boundary,
207682cae269SKonstantin Komarov * the pointer will be advanced by 256K to skip
207782cae269SKonstantin Komarov * over the mirror portion.
207882cae269SKonstantin Komarov */
ntfs_insert_security(struct ntfs_sb_info * sbi,const struct SECURITY_DESCRIPTOR_RELATIVE * sd,u32 size_sd,__le32 * security_id,bool * inserted)207982cae269SKonstantin Komarov int ntfs_insert_security(struct ntfs_sb_info *sbi,
208082cae269SKonstantin Komarov const struct SECURITY_DESCRIPTOR_RELATIVE *sd,
208182cae269SKonstantin Komarov u32 size_sd, __le32 *security_id, bool *inserted)
208282cae269SKonstantin Komarov {
208382cae269SKonstantin Komarov int err, diff;
208482cae269SKonstantin Komarov struct ntfs_inode *ni = sbi->security.ni;
208582cae269SKonstantin Komarov struct ntfs_index *indx_sdh = &sbi->security.index_sdh;
208682cae269SKonstantin Komarov struct ntfs_index *indx_sii = &sbi->security.index_sii;
208782cae269SKonstantin Komarov struct NTFS_DE_SDH *e;
208882cae269SKonstantin Komarov struct NTFS_DE_SDH sdh_e;
208982cae269SKonstantin Komarov struct NTFS_DE_SII sii_e;
209082cae269SKonstantin Komarov struct SECURITY_HDR *d_security;
2091a81f47c4SKonstantin Komarov u32 new_sec_size = size_sd + sizeof(struct SECURITY_HDR);
2092fa3cacf5SKari Argillander u32 aligned_sec_size = ALIGN(new_sec_size, 16);
209382cae269SKonstantin Komarov struct SECURITY_KEY hash_key;
209482cae269SKonstantin Komarov struct ntfs_fnd *fnd_sdh = NULL;
209582cae269SKonstantin Komarov const struct INDEX_ROOT *root_sdh;
209682cae269SKonstantin Komarov const struct INDEX_ROOT *root_sii;
209782cae269SKonstantin Komarov u64 mirr_off, new_sds_size;
209882cae269SKonstantin Komarov u32 next, left;
209982cae269SKonstantin Komarov
210082cae269SKonstantin Komarov static_assert((1 << Log2OfSecurityDescriptorsBlockSize) ==
210182cae269SKonstantin Komarov SecurityDescriptorsBlockSize);
210282cae269SKonstantin Komarov
210382cae269SKonstantin Komarov hash_key.hash = security_hash(sd, size_sd);
210482cae269SKonstantin Komarov hash_key.sec_id = SECURITY_ID_INVALID;
210582cae269SKonstantin Komarov
210682cae269SKonstantin Komarov if (inserted)
210782cae269SKonstantin Komarov *inserted = false;
210882cae269SKonstantin Komarov *security_id = SECURITY_ID_INVALID;
210982cae269SKonstantin Komarov
2110e8b8e97fSKari Argillander /* Allocate a temporal buffer. */
2111195c52bdSKari Argillander d_security = kzalloc(aligned_sec_size, GFP_NOFS);
211282cae269SKonstantin Komarov if (!d_security)
211382cae269SKonstantin Komarov return -ENOMEM;
211482cae269SKonstantin Komarov
211582cae269SKonstantin Komarov mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_SECURITY);
211682cae269SKonstantin Komarov
211782cae269SKonstantin Komarov fnd_sdh = fnd_get();
211882cae269SKonstantin Komarov if (!fnd_sdh) {
211982cae269SKonstantin Komarov err = -ENOMEM;
212082cae269SKonstantin Komarov goto out;
212182cae269SKonstantin Komarov }
212282cae269SKonstantin Komarov
212382cae269SKonstantin Komarov root_sdh = indx_get_root(indx_sdh, ni, NULL, NULL);
212482cae269SKonstantin Komarov if (!root_sdh) {
212582cae269SKonstantin Komarov err = -EINVAL;
212682cae269SKonstantin Komarov goto out;
212782cae269SKonstantin Komarov }
212882cae269SKonstantin Komarov
212982cae269SKonstantin Komarov root_sii = indx_get_root(indx_sii, ni, NULL, NULL);
213082cae269SKonstantin Komarov if (!root_sii) {
213182cae269SKonstantin Komarov err = -EINVAL;
213282cae269SKonstantin Komarov goto out;
213382cae269SKonstantin Komarov }
213482cae269SKonstantin Komarov
213582cae269SKonstantin Komarov /*
2136e8b8e97fSKari Argillander * Check if such security already exists.
2137e8b8e97fSKari Argillander * Use "SDH" and hash -> to get the offset in "SDS".
213882cae269SKonstantin Komarov */
213982cae269SKonstantin Komarov err = indx_find(indx_sdh, ni, root_sdh, &hash_key, sizeof(hash_key),
214082cae269SKonstantin Komarov &d_security->key.sec_id, &diff, (struct NTFS_DE **)&e,
214182cae269SKonstantin Komarov fnd_sdh);
214282cae269SKonstantin Komarov if (err)
214382cae269SKonstantin Komarov goto out;
214482cae269SKonstantin Komarov
214582cae269SKonstantin Komarov while (e) {
214682cae269SKonstantin Komarov if (le32_to_cpu(e->sec_hdr.size) == new_sec_size) {
214782cae269SKonstantin Komarov err = ntfs_read_run_nb(sbi, &ni->file.run,
214882cae269SKonstantin Komarov le64_to_cpu(e->sec_hdr.off),
214982cae269SKonstantin Komarov d_security, new_sec_size, NULL);
215082cae269SKonstantin Komarov if (err)
215182cae269SKonstantin Komarov goto out;
215282cae269SKonstantin Komarov
215382cae269SKonstantin Komarov if (le32_to_cpu(d_security->size) == new_sec_size &&
215482cae269SKonstantin Komarov d_security->key.hash == hash_key.hash &&
215582cae269SKonstantin Komarov !memcmp(d_security + 1, sd, size_sd)) {
215682cae269SKonstantin Komarov *security_id = d_security->key.sec_id;
2157e8b8e97fSKari Argillander /* Such security already exists. */
215882cae269SKonstantin Komarov err = 0;
215982cae269SKonstantin Komarov goto out;
216082cae269SKonstantin Komarov }
216182cae269SKonstantin Komarov }
216282cae269SKonstantin Komarov
216382cae269SKonstantin Komarov err = indx_find_sort(indx_sdh, ni, root_sdh,
216482cae269SKonstantin Komarov (struct NTFS_DE **)&e, fnd_sdh);
216582cae269SKonstantin Komarov if (err)
216682cae269SKonstantin Komarov goto out;
216782cae269SKonstantin Komarov
216882cae269SKonstantin Komarov if (!e || e->key.hash != hash_key.hash)
216982cae269SKonstantin Komarov break;
217082cae269SKonstantin Komarov }
217182cae269SKonstantin Komarov
2172e8b8e97fSKari Argillander /* Zero unused space. */
217382cae269SKonstantin Komarov next = sbi->security.next_off & (SecurityDescriptorsBlockSize - 1);
217482cae269SKonstantin Komarov left = SecurityDescriptorsBlockSize - next;
217582cae269SKonstantin Komarov
2176e8b8e97fSKari Argillander /* Zero gap until SecurityDescriptorsBlockSize. */
217782cae269SKonstantin Komarov if (left < new_sec_size) {
2178e8b8e97fSKari Argillander /* Zero "left" bytes from sbi->security.next_off. */
217982cae269SKonstantin Komarov sbi->security.next_off += SecurityDescriptorsBlockSize + left;
218082cae269SKonstantin Komarov }
218182cae269SKonstantin Komarov
2182e8b8e97fSKari Argillander /* Zero tail of previous security. */
218382cae269SKonstantin Komarov //used = ni->vfs_inode.i_size & (SecurityDescriptorsBlockSize - 1);
218482cae269SKonstantin Komarov
218582cae269SKonstantin Komarov /*
218682cae269SKonstantin Komarov * Example:
218782cae269SKonstantin Komarov * 0x40438 == ni->vfs_inode.i_size
218882cae269SKonstantin Komarov * 0x00440 == sbi->security.next_off
218982cae269SKonstantin Komarov * need to zero [0x438-0x440)
219082cae269SKonstantin Komarov * if (next > used) {
219182cae269SKonstantin Komarov * u32 tozero = next - used;
219282cae269SKonstantin Komarov * zero "tozero" bytes from sbi->security.next_off - tozero
219382cae269SKonstantin Komarov */
219482cae269SKonstantin Komarov
2195e8b8e97fSKari Argillander /* Format new security descriptor. */
219682cae269SKonstantin Komarov d_security->key.hash = hash_key.hash;
219782cae269SKonstantin Komarov d_security->key.sec_id = cpu_to_le32(sbi->security.next_id);
219882cae269SKonstantin Komarov d_security->off = cpu_to_le64(sbi->security.next_off);
219982cae269SKonstantin Komarov d_security->size = cpu_to_le32(new_sec_size);
220082cae269SKonstantin Komarov memcpy(d_security + 1, sd, size_sd);
220182cae269SKonstantin Komarov
2202e8b8e97fSKari Argillander /* Write main SDS bucket. */
220382cae269SKonstantin Komarov err = ntfs_sb_write_run(sbi, &ni->file.run, sbi->security.next_off,
220463544672SKonstantin Komarov d_security, aligned_sec_size, 0);
220582cae269SKonstantin Komarov
220682cae269SKonstantin Komarov if (err)
220782cae269SKonstantin Komarov goto out;
220882cae269SKonstantin Komarov
220982cae269SKonstantin Komarov mirr_off = sbi->security.next_off + SecurityDescriptorsBlockSize;
221082cae269SKonstantin Komarov new_sds_size = mirr_off + aligned_sec_size;
221182cae269SKonstantin Komarov
221282cae269SKonstantin Komarov if (new_sds_size > ni->vfs_inode.i_size) {
221382cae269SKonstantin Komarov err = attr_set_size(ni, ATTR_DATA, SDS_NAME,
221482cae269SKonstantin Komarov ARRAY_SIZE(SDS_NAME), &ni->file.run,
221582cae269SKonstantin Komarov new_sds_size, &new_sds_size, false, NULL);
221682cae269SKonstantin Komarov if (err)
221782cae269SKonstantin Komarov goto out;
221882cae269SKonstantin Komarov }
221982cae269SKonstantin Komarov
2220e8b8e97fSKari Argillander /* Write copy SDS bucket. */
222182cae269SKonstantin Komarov err = ntfs_sb_write_run(sbi, &ni->file.run, mirr_off, d_security,
222263544672SKonstantin Komarov aligned_sec_size, 0);
222382cae269SKonstantin Komarov if (err)
222482cae269SKonstantin Komarov goto out;
222582cae269SKonstantin Komarov
2226e8b8e97fSKari Argillander /* Fill SII entry. */
222782cae269SKonstantin Komarov sii_e.de.view.data_off =
222882cae269SKonstantin Komarov cpu_to_le16(offsetof(struct NTFS_DE_SII, sec_hdr));
2229a81f47c4SKonstantin Komarov sii_e.de.view.data_size = cpu_to_le16(sizeof(struct SECURITY_HDR));
223082cae269SKonstantin Komarov sii_e.de.view.res = 0;
2231a81f47c4SKonstantin Komarov sii_e.de.size = cpu_to_le16(sizeof(struct NTFS_DE_SII));
223282cae269SKonstantin Komarov sii_e.de.key_size = cpu_to_le16(sizeof(d_security->key.sec_id));
223382cae269SKonstantin Komarov sii_e.de.flags = 0;
223482cae269SKonstantin Komarov sii_e.de.res = 0;
223582cae269SKonstantin Komarov sii_e.sec_id = d_security->key.sec_id;
2236a81f47c4SKonstantin Komarov memcpy(&sii_e.sec_hdr, d_security, sizeof(struct SECURITY_HDR));
223782cae269SKonstantin Komarov
223878ab59feSKonstantin Komarov err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL, 0);
223982cae269SKonstantin Komarov if (err)
224082cae269SKonstantin Komarov goto out;
224182cae269SKonstantin Komarov
2242e8b8e97fSKari Argillander /* Fill SDH entry. */
224382cae269SKonstantin Komarov sdh_e.de.view.data_off =
224482cae269SKonstantin Komarov cpu_to_le16(offsetof(struct NTFS_DE_SDH, sec_hdr));
2245a81f47c4SKonstantin Komarov sdh_e.de.view.data_size = cpu_to_le16(sizeof(struct SECURITY_HDR));
224682cae269SKonstantin Komarov sdh_e.de.view.res = 0;
224782cae269SKonstantin Komarov sdh_e.de.size = cpu_to_le16(SIZEOF_SDH_DIRENTRY);
224882cae269SKonstantin Komarov sdh_e.de.key_size = cpu_to_le16(sizeof(sdh_e.key));
224982cae269SKonstantin Komarov sdh_e.de.flags = 0;
225082cae269SKonstantin Komarov sdh_e.de.res = 0;
225182cae269SKonstantin Komarov sdh_e.key.hash = d_security->key.hash;
225282cae269SKonstantin Komarov sdh_e.key.sec_id = d_security->key.sec_id;
2253a81f47c4SKonstantin Komarov memcpy(&sdh_e.sec_hdr, d_security, sizeof(struct SECURITY_HDR));
225482cae269SKonstantin Komarov sdh_e.magic[0] = cpu_to_le16('I');
225582cae269SKonstantin Komarov sdh_e.magic[1] = cpu_to_le16('I');
225682cae269SKonstantin Komarov
225782cae269SKonstantin Komarov fnd_clear(fnd_sdh);
225882cae269SKonstantin Komarov err = indx_insert_entry(indx_sdh, ni, &sdh_e.de, (void *)(size_t)1,
225978ab59feSKonstantin Komarov fnd_sdh, 0);
226082cae269SKonstantin Komarov if (err)
226182cae269SKonstantin Komarov goto out;
226282cae269SKonstantin Komarov
226382cae269SKonstantin Komarov *security_id = d_security->key.sec_id;
226482cae269SKonstantin Komarov if (inserted)
226582cae269SKonstantin Komarov *inserted = true;
226682cae269SKonstantin Komarov
2267e8b8e97fSKari Argillander /* Update Id and offset for next descriptor. */
226882cae269SKonstantin Komarov sbi->security.next_id += 1;
226982cae269SKonstantin Komarov sbi->security.next_off += aligned_sec_size;
227082cae269SKonstantin Komarov
227182cae269SKonstantin Komarov out:
227282cae269SKonstantin Komarov fnd_put(fnd_sdh);
227382cae269SKonstantin Komarov mark_inode_dirty(&ni->vfs_inode);
227482cae269SKonstantin Komarov ni_unlock(ni);
2275195c52bdSKari Argillander kfree(d_security);
227682cae269SKonstantin Komarov
227782cae269SKonstantin Komarov return err;
227882cae269SKonstantin Komarov }
227982cae269SKonstantin Komarov
228082cae269SKonstantin Komarov /*
2281e8b8e97fSKari Argillander * ntfs_reparse_init - Load and parse $Extend/$Reparse.
228282cae269SKonstantin Komarov */
ntfs_reparse_init(struct ntfs_sb_info * sbi)228382cae269SKonstantin Komarov int ntfs_reparse_init(struct ntfs_sb_info *sbi)
228482cae269SKonstantin Komarov {
228582cae269SKonstantin Komarov int err;
228682cae269SKonstantin Komarov struct ntfs_inode *ni = sbi->reparse.ni;
228782cae269SKonstantin Komarov struct ntfs_index *indx = &sbi->reparse.index_r;
228882cae269SKonstantin Komarov struct ATTRIB *attr;
228982cae269SKonstantin Komarov struct ATTR_LIST_ENTRY *le;
229082cae269SKonstantin Komarov const struct INDEX_ROOT *root_r;
229182cae269SKonstantin Komarov
229282cae269SKonstantin Komarov if (!ni)
229382cae269SKonstantin Komarov return 0;
229482cae269SKonstantin Komarov
229582cae269SKonstantin Komarov le = NULL;
229682cae269SKonstantin Komarov attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SR_NAME,
229782cae269SKonstantin Komarov ARRAY_SIZE(SR_NAME), NULL, NULL);
229882cae269SKonstantin Komarov if (!attr) {
229982cae269SKonstantin Komarov err = -EINVAL;
230082cae269SKonstantin Komarov goto out;
230182cae269SKonstantin Komarov }
230282cae269SKonstantin Komarov
230382cae269SKonstantin Komarov root_r = resident_data(attr);
230482cae269SKonstantin Komarov if (root_r->type != ATTR_ZERO ||
230582cae269SKonstantin Komarov root_r->rule != NTFS_COLLATION_TYPE_UINTS) {
230682cae269SKonstantin Komarov err = -EINVAL;
230782cae269SKonstantin Komarov goto out;
230882cae269SKonstantin Komarov }
230982cae269SKonstantin Komarov
231082cae269SKonstantin Komarov err = indx_init(indx, sbi, attr, INDEX_MUTEX_SR);
231182cae269SKonstantin Komarov if (err)
231282cae269SKonstantin Komarov goto out;
231382cae269SKonstantin Komarov
231482cae269SKonstantin Komarov out:
231582cae269SKonstantin Komarov return err;
231682cae269SKonstantin Komarov }
231782cae269SKonstantin Komarov
231882cae269SKonstantin Komarov /*
2319e8b8e97fSKari Argillander * ntfs_objid_init - Load and parse $Extend/$ObjId.
232082cae269SKonstantin Komarov */
ntfs_objid_init(struct ntfs_sb_info * sbi)232182cae269SKonstantin Komarov int ntfs_objid_init(struct ntfs_sb_info *sbi)
232282cae269SKonstantin Komarov {
232382cae269SKonstantin Komarov int err;
232482cae269SKonstantin Komarov struct ntfs_inode *ni = sbi->objid.ni;
232582cae269SKonstantin Komarov struct ntfs_index *indx = &sbi->objid.index_o;
232682cae269SKonstantin Komarov struct ATTRIB *attr;
232782cae269SKonstantin Komarov struct ATTR_LIST_ENTRY *le;
232882cae269SKonstantin Komarov const struct INDEX_ROOT *root;
232982cae269SKonstantin Komarov
233082cae269SKonstantin Komarov if (!ni)
233182cae269SKonstantin Komarov return 0;
233282cae269SKonstantin Komarov
233382cae269SKonstantin Komarov le = NULL;
233482cae269SKonstantin Komarov attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SO_NAME,
233582cae269SKonstantin Komarov ARRAY_SIZE(SO_NAME), NULL, NULL);
233682cae269SKonstantin Komarov if (!attr) {
233782cae269SKonstantin Komarov err = -EINVAL;
233882cae269SKonstantin Komarov goto out;
233982cae269SKonstantin Komarov }
234082cae269SKonstantin Komarov
234182cae269SKonstantin Komarov root = resident_data(attr);
234282cae269SKonstantin Komarov if (root->type != ATTR_ZERO ||
234382cae269SKonstantin Komarov root->rule != NTFS_COLLATION_TYPE_UINTS) {
234482cae269SKonstantin Komarov err = -EINVAL;
234582cae269SKonstantin Komarov goto out;
234682cae269SKonstantin Komarov }
234782cae269SKonstantin Komarov
234882cae269SKonstantin Komarov err = indx_init(indx, sbi, attr, INDEX_MUTEX_SO);
234982cae269SKonstantin Komarov if (err)
235082cae269SKonstantin Komarov goto out;
235182cae269SKonstantin Komarov
235282cae269SKonstantin Komarov out:
235382cae269SKonstantin Komarov return err;
235482cae269SKonstantin Komarov }
235582cae269SKonstantin Komarov
ntfs_objid_remove(struct ntfs_sb_info * sbi,struct GUID * guid)235682cae269SKonstantin Komarov int ntfs_objid_remove(struct ntfs_sb_info *sbi, struct GUID *guid)
235782cae269SKonstantin Komarov {
235882cae269SKonstantin Komarov int err;
235982cae269SKonstantin Komarov struct ntfs_inode *ni = sbi->objid.ni;
236082cae269SKonstantin Komarov struct ntfs_index *indx = &sbi->objid.index_o;
236182cae269SKonstantin Komarov
236282cae269SKonstantin Komarov if (!ni)
236382cae269SKonstantin Komarov return -EINVAL;
236482cae269SKonstantin Komarov
236582cae269SKonstantin Komarov mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_OBJID);
236682cae269SKonstantin Komarov
236782cae269SKonstantin Komarov err = indx_delete_entry(indx, ni, guid, sizeof(*guid), NULL);
236882cae269SKonstantin Komarov
236982cae269SKonstantin Komarov mark_inode_dirty(&ni->vfs_inode);
237082cae269SKonstantin Komarov ni_unlock(ni);
237182cae269SKonstantin Komarov
237282cae269SKonstantin Komarov return err;
237382cae269SKonstantin Komarov }
237482cae269SKonstantin Komarov
ntfs_insert_reparse(struct ntfs_sb_info * sbi,__le32 rtag,const struct MFT_REF * ref)237582cae269SKonstantin Komarov int ntfs_insert_reparse(struct ntfs_sb_info *sbi, __le32 rtag,
237682cae269SKonstantin Komarov const struct MFT_REF *ref)
237782cae269SKonstantin Komarov {
237882cae269SKonstantin Komarov int err;
237982cae269SKonstantin Komarov struct ntfs_inode *ni = sbi->reparse.ni;
238082cae269SKonstantin Komarov struct ntfs_index *indx = &sbi->reparse.index_r;
238182cae269SKonstantin Komarov struct NTFS_DE_R re;
238282cae269SKonstantin Komarov
238382cae269SKonstantin Komarov if (!ni)
238482cae269SKonstantin Komarov return -EINVAL;
238582cae269SKonstantin Komarov
238682cae269SKonstantin Komarov memset(&re, 0, sizeof(re));
238782cae269SKonstantin Komarov
238882cae269SKonstantin Komarov re.de.view.data_off = cpu_to_le16(offsetof(struct NTFS_DE_R, zero));
238982cae269SKonstantin Komarov re.de.size = cpu_to_le16(sizeof(struct NTFS_DE_R));
239082cae269SKonstantin Komarov re.de.key_size = cpu_to_le16(sizeof(re.key));
239182cae269SKonstantin Komarov
239282cae269SKonstantin Komarov re.key.ReparseTag = rtag;
239382cae269SKonstantin Komarov memcpy(&re.key.ref, ref, sizeof(*ref));
239482cae269SKonstantin Komarov
239582cae269SKonstantin Komarov mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_REPARSE);
239682cae269SKonstantin Komarov
239778ab59feSKonstantin Komarov err = indx_insert_entry(indx, ni, &re.de, NULL, NULL, 0);
239882cae269SKonstantin Komarov
239982cae269SKonstantin Komarov mark_inode_dirty(&ni->vfs_inode);
240082cae269SKonstantin Komarov ni_unlock(ni);
240182cae269SKonstantin Komarov
240282cae269SKonstantin Komarov return err;
240382cae269SKonstantin Komarov }
240482cae269SKonstantin Komarov
ntfs_remove_reparse(struct ntfs_sb_info * sbi,__le32 rtag,const struct MFT_REF * ref)240582cae269SKonstantin Komarov int ntfs_remove_reparse(struct ntfs_sb_info *sbi, __le32 rtag,
240682cae269SKonstantin Komarov const struct MFT_REF *ref)
240782cae269SKonstantin Komarov {
240882cae269SKonstantin Komarov int err, diff;
240982cae269SKonstantin Komarov struct ntfs_inode *ni = sbi->reparse.ni;
241082cae269SKonstantin Komarov struct ntfs_index *indx = &sbi->reparse.index_r;
241182cae269SKonstantin Komarov struct ntfs_fnd *fnd = NULL;
241282cae269SKonstantin Komarov struct REPARSE_KEY rkey;
241382cae269SKonstantin Komarov struct NTFS_DE_R *re;
241482cae269SKonstantin Komarov struct INDEX_ROOT *root_r;
241582cae269SKonstantin Komarov
241682cae269SKonstantin Komarov if (!ni)
241782cae269SKonstantin Komarov return -EINVAL;
241882cae269SKonstantin Komarov
241982cae269SKonstantin Komarov rkey.ReparseTag = rtag;
242082cae269SKonstantin Komarov rkey.ref = *ref;
242182cae269SKonstantin Komarov
242282cae269SKonstantin Komarov mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_REPARSE);
242382cae269SKonstantin Komarov
242482cae269SKonstantin Komarov if (rtag) {
242582cae269SKonstantin Komarov err = indx_delete_entry(indx, ni, &rkey, sizeof(rkey), NULL);
242682cae269SKonstantin Komarov goto out1;
242782cae269SKonstantin Komarov }
242882cae269SKonstantin Komarov
242982cae269SKonstantin Komarov fnd = fnd_get();
243082cae269SKonstantin Komarov if (!fnd) {
243182cae269SKonstantin Komarov err = -ENOMEM;
243282cae269SKonstantin Komarov goto out1;
243382cae269SKonstantin Komarov }
243482cae269SKonstantin Komarov
243582cae269SKonstantin Komarov root_r = indx_get_root(indx, ni, NULL, NULL);
243682cae269SKonstantin Komarov if (!root_r) {
243782cae269SKonstantin Komarov err = -EINVAL;
243882cae269SKonstantin Komarov goto out;
243982cae269SKonstantin Komarov }
244082cae269SKonstantin Komarov
2441e8b8e97fSKari Argillander /* 1 - forces to ignore rkey.ReparseTag when comparing keys. */
244282cae269SKonstantin Komarov err = indx_find(indx, ni, root_r, &rkey, sizeof(rkey), (void *)1, &diff,
244382cae269SKonstantin Komarov (struct NTFS_DE **)&re, fnd);
244482cae269SKonstantin Komarov if (err)
244582cae269SKonstantin Komarov goto out;
244682cae269SKonstantin Komarov
244782cae269SKonstantin Komarov if (memcmp(&re->key.ref, ref, sizeof(*ref))) {
244882cae269SKonstantin Komarov /* Impossible. Looks like volume corrupt? */
244982cae269SKonstantin Komarov goto out;
245082cae269SKonstantin Komarov }
245182cae269SKonstantin Komarov
245282cae269SKonstantin Komarov memcpy(&rkey, &re->key, sizeof(rkey));
245382cae269SKonstantin Komarov
245482cae269SKonstantin Komarov fnd_put(fnd);
245582cae269SKonstantin Komarov fnd = NULL;
245682cae269SKonstantin Komarov
245782cae269SKonstantin Komarov err = indx_delete_entry(indx, ni, &rkey, sizeof(rkey), NULL);
245882cae269SKonstantin Komarov if (err)
245982cae269SKonstantin Komarov goto out;
246082cae269SKonstantin Komarov
246182cae269SKonstantin Komarov out:
246282cae269SKonstantin Komarov fnd_put(fnd);
246382cae269SKonstantin Komarov
246482cae269SKonstantin Komarov out1:
246582cae269SKonstantin Komarov mark_inode_dirty(&ni->vfs_inode);
246682cae269SKonstantin Komarov ni_unlock(ni);
246782cae269SKonstantin Komarov
246882cae269SKonstantin Komarov return err;
246982cae269SKonstantin Komarov }
247082cae269SKonstantin Komarov
ntfs_unmap_and_discard(struct ntfs_sb_info * sbi,CLST lcn,CLST len)247182cae269SKonstantin Komarov static inline void ntfs_unmap_and_discard(struct ntfs_sb_info *sbi, CLST lcn,
247282cae269SKonstantin Komarov CLST len)
247382cae269SKonstantin Komarov {
247482cae269SKonstantin Komarov ntfs_unmap_meta(sbi->sb, lcn, len);
247582cae269SKonstantin Komarov ntfs_discard(sbi, lcn, len);
247682cae269SKonstantin Komarov }
247782cae269SKonstantin Komarov
mark_as_free_ex(struct ntfs_sb_info * sbi,CLST lcn,CLST len,bool trim)247882cae269SKonstantin Komarov void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
247982cae269SKonstantin Komarov {
24808335ebe1SKonstantin Komarov CLST end, i, zone_len, zlen;
248182cae269SKonstantin Komarov struct wnd_bitmap *wnd = &sbi->used.bitmap;
2482bfbe5b31SKonstantin Komarov bool dirty = false;
248382cae269SKonstantin Komarov
248482cae269SKonstantin Komarov down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
248582cae269SKonstantin Komarov if (!wnd_is_used(wnd, lcn, len)) {
2486bfbe5b31SKonstantin Komarov /* mark volume as dirty out of wnd->rw_lock */
2487bfbe5b31SKonstantin Komarov dirty = true;
248882cae269SKonstantin Komarov
248982cae269SKonstantin Komarov end = lcn + len;
249082cae269SKonstantin Komarov len = 0;
249182cae269SKonstantin Komarov for (i = lcn; i < end; i++) {
249282cae269SKonstantin Komarov if (wnd_is_used(wnd, i, 1)) {
249382cae269SKonstantin Komarov if (!len)
249482cae269SKonstantin Komarov lcn = i;
249582cae269SKonstantin Komarov len += 1;
249682cae269SKonstantin Komarov continue;
249782cae269SKonstantin Komarov }
249882cae269SKonstantin Komarov
249982cae269SKonstantin Komarov if (!len)
250082cae269SKonstantin Komarov continue;
250182cae269SKonstantin Komarov
250282cae269SKonstantin Komarov if (trim)
250382cae269SKonstantin Komarov ntfs_unmap_and_discard(sbi, lcn, len);
250482cae269SKonstantin Komarov
250582cae269SKonstantin Komarov wnd_set_free(wnd, lcn, len);
250682cae269SKonstantin Komarov len = 0;
250782cae269SKonstantin Komarov }
250882cae269SKonstantin Komarov
250982cae269SKonstantin Komarov if (!len)
251082cae269SKonstantin Komarov goto out;
251182cae269SKonstantin Komarov }
251282cae269SKonstantin Komarov
251382cae269SKonstantin Komarov if (trim)
251482cae269SKonstantin Komarov ntfs_unmap_and_discard(sbi, lcn, len);
251582cae269SKonstantin Komarov wnd_set_free(wnd, lcn, len);
251682cae269SKonstantin Komarov
25178335ebe1SKonstantin Komarov /* append to MFT zone, if possible. */
25188335ebe1SKonstantin Komarov zone_len = wnd_zone_len(wnd);
25198335ebe1SKonstantin Komarov zlen = min(zone_len + len, sbi->zone_max);
25208335ebe1SKonstantin Komarov
25218335ebe1SKonstantin Komarov if (zlen == zone_len) {
25228335ebe1SKonstantin Komarov /* MFT zone already has maximum size. */
25238335ebe1SKonstantin Komarov } else if (!zone_len) {
25248039edbaSKonstantin Komarov /* Create MFT zone only if 'zlen' is large enough. */
25258039edbaSKonstantin Komarov if (zlen == sbi->zone_max)
25268335ebe1SKonstantin Komarov wnd_zone_set(wnd, lcn, zlen);
25278335ebe1SKonstantin Komarov } else {
25288335ebe1SKonstantin Komarov CLST zone_lcn = wnd_zone_bit(wnd);
25298335ebe1SKonstantin Komarov
25308335ebe1SKonstantin Komarov if (lcn + len == zone_lcn) {
25318335ebe1SKonstantin Komarov /* Append into head MFT zone. */
25328335ebe1SKonstantin Komarov wnd_zone_set(wnd, lcn, zlen);
25338335ebe1SKonstantin Komarov } else if (zone_lcn + zone_len == lcn) {
25348335ebe1SKonstantin Komarov /* Append into tail MFT zone. */
25358335ebe1SKonstantin Komarov wnd_zone_set(wnd, zone_lcn, zlen);
25368335ebe1SKonstantin Komarov }
25378335ebe1SKonstantin Komarov }
25388335ebe1SKonstantin Komarov
253982cae269SKonstantin Komarov out:
254082cae269SKonstantin Komarov up_write(&wnd->rw_lock);
2541bfbe5b31SKonstantin Komarov if (dirty)
2542bfbe5b31SKonstantin Komarov ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
254382cae269SKonstantin Komarov }
254482cae269SKonstantin Komarov
254582cae269SKonstantin Komarov /*
2546e8b8e97fSKari Argillander * run_deallocate - Deallocate clusters.
254782cae269SKonstantin Komarov */
run_deallocate(struct ntfs_sb_info * sbi,const struct runs_tree * run,bool trim)2548a81f47c4SKonstantin Komarov int run_deallocate(struct ntfs_sb_info *sbi, const struct runs_tree *run,
2549a81f47c4SKonstantin Komarov bool trim)
255082cae269SKonstantin Komarov {
255182cae269SKonstantin Komarov CLST lcn, len;
255282cae269SKonstantin Komarov size_t idx = 0;
255382cae269SKonstantin Komarov
255482cae269SKonstantin Komarov while (run_get_entry(run, idx++, NULL, &lcn, &len)) {
255582cae269SKonstantin Komarov if (lcn == SPARSE_LCN)
255682cae269SKonstantin Komarov continue;
255782cae269SKonstantin Komarov
255882cae269SKonstantin Komarov mark_as_free_ex(sbi, lcn, len, trim);
255982cae269SKonstantin Komarov }
256082cae269SKonstantin Komarov
256182cae269SKonstantin Komarov return 0;
256282cae269SKonstantin Komarov }
25631d07a9dfSDaniel Pinto
name_has_forbidden_chars(const struct le_str * fname)25641d07a9dfSDaniel Pinto static inline bool name_has_forbidden_chars(const struct le_str *fname)
25651d07a9dfSDaniel Pinto {
25661d07a9dfSDaniel Pinto int i, ch;
25671d07a9dfSDaniel Pinto
25681d07a9dfSDaniel Pinto /* check for forbidden chars */
25691d07a9dfSDaniel Pinto for (i = 0; i < fname->len; ++i) {
25701d07a9dfSDaniel Pinto ch = le16_to_cpu(fname->name[i]);
25711d07a9dfSDaniel Pinto
25721d07a9dfSDaniel Pinto /* control chars */
25731d07a9dfSDaniel Pinto if (ch < 0x20)
25741d07a9dfSDaniel Pinto return true;
25751d07a9dfSDaniel Pinto
25761d07a9dfSDaniel Pinto switch (ch) {
25771d07a9dfSDaniel Pinto /* disallowed by Windows */
25781d07a9dfSDaniel Pinto case '\\':
25791d07a9dfSDaniel Pinto case '/':
25801d07a9dfSDaniel Pinto case ':':
25811d07a9dfSDaniel Pinto case '*':
25821d07a9dfSDaniel Pinto case '?':
25831d07a9dfSDaniel Pinto case '<':
25841d07a9dfSDaniel Pinto case '>':
25851d07a9dfSDaniel Pinto case '|':
25861d07a9dfSDaniel Pinto case '\"':
25871d07a9dfSDaniel Pinto return true;
25881d07a9dfSDaniel Pinto
25891d07a9dfSDaniel Pinto default:
25901d07a9dfSDaniel Pinto /* allowed char */
25911d07a9dfSDaniel Pinto break;
25921d07a9dfSDaniel Pinto }
25931d07a9dfSDaniel Pinto }
25941d07a9dfSDaniel Pinto
25951d07a9dfSDaniel Pinto /* file names cannot end with space or . */
25961d07a9dfSDaniel Pinto if (fname->len > 0) {
25971d07a9dfSDaniel Pinto ch = le16_to_cpu(fname->name[fname->len - 1]);
25981d07a9dfSDaniel Pinto if (ch == ' ' || ch == '.')
25991d07a9dfSDaniel Pinto return true;
26001d07a9dfSDaniel Pinto }
26011d07a9dfSDaniel Pinto
26021d07a9dfSDaniel Pinto return false;
26031d07a9dfSDaniel Pinto }
26041d07a9dfSDaniel Pinto
is_reserved_name(const struct ntfs_sb_info * sbi,const struct le_str * fname)2605a81f47c4SKonstantin Komarov static inline bool is_reserved_name(const struct ntfs_sb_info *sbi,
26061d07a9dfSDaniel Pinto const struct le_str *fname)
26071d07a9dfSDaniel Pinto {
26081d07a9dfSDaniel Pinto int port_digit;
26091d07a9dfSDaniel Pinto const __le16 *name = fname->name;
26101d07a9dfSDaniel Pinto int len = fname->len;
2611a81f47c4SKonstantin Komarov const u16 *upcase = sbi->upcase;
26121d07a9dfSDaniel Pinto
26131d07a9dfSDaniel Pinto /* check for 3 chars reserved names (device names) */
26141d07a9dfSDaniel Pinto /* name by itself or with any extension is forbidden */
26151d07a9dfSDaniel Pinto if (len == 3 || (len > 3 && le16_to_cpu(name[3]) == '.'))
26161d07a9dfSDaniel Pinto if (!ntfs_cmp_names(name, 3, CON_NAME, 3, upcase, false) ||
26171d07a9dfSDaniel Pinto !ntfs_cmp_names(name, 3, NUL_NAME, 3, upcase, false) ||
26181d07a9dfSDaniel Pinto !ntfs_cmp_names(name, 3, AUX_NAME, 3, upcase, false) ||
26191d07a9dfSDaniel Pinto !ntfs_cmp_names(name, 3, PRN_NAME, 3, upcase, false))
26201d07a9dfSDaniel Pinto return true;
26211d07a9dfSDaniel Pinto
26221d07a9dfSDaniel Pinto /* check for 4 chars reserved names (port name followed by 1..9) */
26231d07a9dfSDaniel Pinto /* name by itself or with any extension is forbidden */
26241d07a9dfSDaniel Pinto if (len == 4 || (len > 4 && le16_to_cpu(name[4]) == '.')) {
26251d07a9dfSDaniel Pinto port_digit = le16_to_cpu(name[3]);
26261d07a9dfSDaniel Pinto if (port_digit >= '1' && port_digit <= '9')
26276827d50bSKonstantin Komarov if (!ntfs_cmp_names(name, 3, COM_NAME, 3, upcase,
26286827d50bSKonstantin Komarov false) ||
26296827d50bSKonstantin Komarov !ntfs_cmp_names(name, 3, LPT_NAME, 3, upcase,
26306827d50bSKonstantin Komarov false))
26311d07a9dfSDaniel Pinto return true;
26321d07a9dfSDaniel Pinto }
26331d07a9dfSDaniel Pinto
26341d07a9dfSDaniel Pinto return false;
26351d07a9dfSDaniel Pinto }
26361d07a9dfSDaniel Pinto
26371d07a9dfSDaniel Pinto /*
26381d07a9dfSDaniel Pinto * valid_windows_name - Check if a file name is valid in Windows.
26391d07a9dfSDaniel Pinto */
valid_windows_name(struct ntfs_sb_info * sbi,const struct le_str * fname)26401d07a9dfSDaniel Pinto bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *fname)
26411d07a9dfSDaniel Pinto {
26421d07a9dfSDaniel Pinto return !name_has_forbidden_chars(fname) &&
26431d07a9dfSDaniel Pinto !is_reserved_name(sbi, fname);
26441d07a9dfSDaniel Pinto }
26457832e123SKonstantin Komarov
26467832e123SKonstantin Komarov /*
26477832e123SKonstantin Komarov * ntfs_set_label - updates current ntfs label.
26487832e123SKonstantin Komarov */
ntfs_set_label(struct ntfs_sb_info * sbi,u8 * label,int len)26497832e123SKonstantin Komarov int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len)
26507832e123SKonstantin Komarov {
26517832e123SKonstantin Komarov int err;
26527832e123SKonstantin Komarov struct ATTRIB *attr;
26537832e123SKonstantin Komarov struct ntfs_inode *ni = sbi->volume.ni;
26547832e123SKonstantin Komarov const u8 max_ulen = 0x80; /* TODO: use attrdef to get maximum length */
26557832e123SKonstantin Komarov /* Allocate PATH_MAX bytes. */
26567832e123SKonstantin Komarov struct cpu_str *uni = __getname();
26577832e123SKonstantin Komarov
26587832e123SKonstantin Komarov if (!uni)
26597832e123SKonstantin Komarov return -ENOMEM;
26607832e123SKonstantin Komarov
26617832e123SKonstantin Komarov err = ntfs_nls_to_utf16(sbi, label, len, uni, (PATH_MAX - 2) / 2,
26627832e123SKonstantin Komarov UTF16_LITTLE_ENDIAN);
26637832e123SKonstantin Komarov if (err < 0)
26647832e123SKonstantin Komarov goto out;
26657832e123SKonstantin Komarov
26667832e123SKonstantin Komarov if (uni->len > max_ulen) {
26677832e123SKonstantin Komarov ntfs_warn(sbi->sb, "new label is too long");
26687832e123SKonstantin Komarov err = -EFBIG;
26697832e123SKonstantin Komarov goto out;
26707832e123SKonstantin Komarov }
26717832e123SKonstantin Komarov
26727832e123SKonstantin Komarov ni_lock(ni);
26737832e123SKonstantin Komarov
26747832e123SKonstantin Komarov /* Ignore any errors. */
26757832e123SKonstantin Komarov ni_remove_attr(ni, ATTR_LABEL, NULL, 0, false, NULL);
26767832e123SKonstantin Komarov
26777832e123SKonstantin Komarov err = ni_insert_resident(ni, uni->len * sizeof(u16), ATTR_LABEL, NULL,
26787832e123SKonstantin Komarov 0, &attr, NULL, NULL);
26797832e123SKonstantin Komarov if (err < 0)
26807832e123SKonstantin Komarov goto unlock_out;
26817832e123SKonstantin Komarov
26827832e123SKonstantin Komarov /* write new label in on-disk struct. */
26837832e123SKonstantin Komarov memcpy(resident_data(attr), uni->name, uni->len * sizeof(u16));
26847832e123SKonstantin Komarov
26857832e123SKonstantin Komarov /* update cached value of current label. */
26867832e123SKonstantin Komarov if (len >= ARRAY_SIZE(sbi->volume.label))
26877832e123SKonstantin Komarov len = ARRAY_SIZE(sbi->volume.label) - 1;
26887832e123SKonstantin Komarov memcpy(sbi->volume.label, label, len);
26897832e123SKonstantin Komarov sbi->volume.label[len] = 0;
26907832e123SKonstantin Komarov mark_inode_dirty_sync(&ni->vfs_inode);
26917832e123SKonstantin Komarov
26927832e123SKonstantin Komarov unlock_out:
26937832e123SKonstantin Komarov ni_unlock(ni);
26947832e123SKonstantin Komarov
26957832e123SKonstantin Komarov if (!err)
26967832e123SKonstantin Komarov err = _ni_write_inode(&ni->vfs_inode, 0);
26977832e123SKonstantin Komarov
26987832e123SKonstantin Komarov out:
26997832e123SKonstantin Komarov __putname(uni);
27007832e123SKonstantin Komarov return err;
27017832e123SKonstantin Komarov }