162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/blkdev.h>
962306a36Sopenharmony_ci#include <linux/buffer_head.h>
1062306a36Sopenharmony_ci#include <linux/fs.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/nls.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "debug.h"
1562306a36Sopenharmony_ci#include "ntfs.h"
1662306a36Sopenharmony_ci#include "ntfs_fs.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci// clang-format off
1962306a36Sopenharmony_ciconst struct cpu_str NAME_MFT = {
2062306a36Sopenharmony_ci	4, 0, { '$', 'M', 'F', 'T' },
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ciconst struct cpu_str NAME_MIRROR = {
2362306a36Sopenharmony_ci	8, 0, { '$', 'M', 'F', 'T', 'M', 'i', 'r', 'r' },
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ciconst struct cpu_str NAME_LOGFILE = {
2662306a36Sopenharmony_ci	8, 0, { '$', 'L', 'o', 'g', 'F', 'i', 'l', 'e' },
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ciconst struct cpu_str NAME_VOLUME = {
2962306a36Sopenharmony_ci	7, 0, { '$', 'V', 'o', 'l', 'u', 'm', 'e' },
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ciconst struct cpu_str NAME_ATTRDEF = {
3262306a36Sopenharmony_ci	8, 0, { '$', 'A', 't', 't', 'r', 'D', 'e', 'f' },
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ciconst struct cpu_str NAME_ROOT = {
3562306a36Sopenharmony_ci	1, 0, { '.' },
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ciconst struct cpu_str NAME_BITMAP = {
3862306a36Sopenharmony_ci	7, 0, { '$', 'B', 'i', 't', 'm', 'a', 'p' },
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ciconst struct cpu_str NAME_BOOT = {
4162306a36Sopenharmony_ci	5, 0, { '$', 'B', 'o', 'o', 't' },
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ciconst struct cpu_str NAME_BADCLUS = {
4462306a36Sopenharmony_ci	8, 0, { '$', 'B', 'a', 'd', 'C', 'l', 'u', 's' },
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ciconst struct cpu_str NAME_QUOTA = {
4762306a36Sopenharmony_ci	6, 0, { '$', 'Q', 'u', 'o', 't', 'a' },
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ciconst struct cpu_str NAME_SECURE = {
5062306a36Sopenharmony_ci	7, 0, { '$', 'S', 'e', 'c', 'u', 'r', 'e' },
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ciconst struct cpu_str NAME_UPCASE = {
5362306a36Sopenharmony_ci	7, 0, { '$', 'U', 'p', 'C', 'a', 's', 'e' },
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ciconst struct cpu_str NAME_EXTEND = {
5662306a36Sopenharmony_ci	7, 0, { '$', 'E', 'x', 't', 'e', 'n', 'd' },
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ciconst struct cpu_str NAME_OBJID = {
5962306a36Sopenharmony_ci	6, 0, { '$', 'O', 'b', 'j', 'I', 'd' },
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ciconst struct cpu_str NAME_REPARSE = {
6262306a36Sopenharmony_ci	8, 0, { '$', 'R', 'e', 'p', 'a', 'r', 's', 'e' },
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ciconst struct cpu_str NAME_USNJRNL = {
6562306a36Sopenharmony_ci	8, 0, { '$', 'U', 's', 'n', 'J', 'r', 'n', 'l' },
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ciconst __le16 BAD_NAME[4] = {
6862306a36Sopenharmony_ci	cpu_to_le16('$'), cpu_to_le16('B'), cpu_to_le16('a'), cpu_to_le16('d'),
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ciconst __le16 I30_NAME[4] = {
7162306a36Sopenharmony_ci	cpu_to_le16('$'), cpu_to_le16('I'), cpu_to_le16('3'), cpu_to_le16('0'),
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ciconst __le16 SII_NAME[4] = {
7462306a36Sopenharmony_ci	cpu_to_le16('$'), cpu_to_le16('S'), cpu_to_le16('I'), cpu_to_le16('I'),
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ciconst __le16 SDH_NAME[4] = {
7762306a36Sopenharmony_ci	cpu_to_le16('$'), cpu_to_le16('S'), cpu_to_le16('D'), cpu_to_le16('H'),
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ciconst __le16 SDS_NAME[4] = {
8062306a36Sopenharmony_ci	cpu_to_le16('$'), cpu_to_le16('S'), cpu_to_le16('D'), cpu_to_le16('S'),
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ciconst __le16 SO_NAME[2] = {
8362306a36Sopenharmony_ci	cpu_to_le16('$'), cpu_to_le16('O'),
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ciconst __le16 SQ_NAME[2] = {
8662306a36Sopenharmony_ci	cpu_to_le16('$'), cpu_to_le16('Q'),
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ciconst __le16 SR_NAME[2] = {
8962306a36Sopenharmony_ci	cpu_to_le16('$'), cpu_to_le16('R'),
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_LZX_XPRESS
9362306a36Sopenharmony_ciconst __le16 WOF_NAME[17] = {
9462306a36Sopenharmony_ci	cpu_to_le16('W'), cpu_to_le16('o'), cpu_to_le16('f'), cpu_to_le16('C'),
9562306a36Sopenharmony_ci	cpu_to_le16('o'), cpu_to_le16('m'), cpu_to_le16('p'), cpu_to_le16('r'),
9662306a36Sopenharmony_ci	cpu_to_le16('e'), cpu_to_le16('s'), cpu_to_le16('s'), cpu_to_le16('e'),
9762306a36Sopenharmony_ci	cpu_to_le16('d'), cpu_to_le16('D'), cpu_to_le16('a'), cpu_to_le16('t'),
9862306a36Sopenharmony_ci	cpu_to_le16('a'),
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci#endif
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic const __le16 CON_NAME[3] = {
10362306a36Sopenharmony_ci	cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('N'),
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic const __le16 NUL_NAME[3] = {
10762306a36Sopenharmony_ci	cpu_to_le16('N'), cpu_to_le16('U'), cpu_to_le16('L'),
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic const __le16 AUX_NAME[3] = {
11162306a36Sopenharmony_ci	cpu_to_le16('A'), cpu_to_le16('U'), cpu_to_le16('X'),
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic const __le16 PRN_NAME[3] = {
11562306a36Sopenharmony_ci	cpu_to_le16('P'), cpu_to_le16('R'), cpu_to_le16('N'),
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic const __le16 COM_NAME[3] = {
11962306a36Sopenharmony_ci	cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'),
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const __le16 LPT_NAME[3] = {
12362306a36Sopenharmony_ci	cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'),
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci// clang-format on
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/*
12962306a36Sopenharmony_ci * ntfs_fix_pre_write - Insert fixups into @rhdr before writing to disk.
13062306a36Sopenharmony_ci */
13162306a36Sopenharmony_cibool ntfs_fix_pre_write(struct NTFS_RECORD_HEADER *rhdr, size_t bytes)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	u16 *fixup, *ptr;
13462306a36Sopenharmony_ci	u16 sample;
13562306a36Sopenharmony_ci	u16 fo = le16_to_cpu(rhdr->fix_off);
13662306a36Sopenharmony_ci	u16 fn = le16_to_cpu(rhdr->fix_num);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
13962306a36Sopenharmony_ci	    fn * SECTOR_SIZE > bytes) {
14062306a36Sopenharmony_ci		return false;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* Get fixup pointer. */
14462306a36Sopenharmony_ci	fixup = Add2Ptr(rhdr, fo);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (*fixup >= 0x7FFF)
14762306a36Sopenharmony_ci		*fixup = 1;
14862306a36Sopenharmony_ci	else
14962306a36Sopenharmony_ci		*fixup += 1;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	sample = *fixup;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	ptr = Add2Ptr(rhdr, SECTOR_SIZE - sizeof(short));
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	while (fn--) {
15662306a36Sopenharmony_ci		*++fixup = *ptr;
15762306a36Sopenharmony_ci		*ptr = sample;
15862306a36Sopenharmony_ci		ptr += SECTOR_SIZE / sizeof(short);
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci	return true;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/*
16462306a36Sopenharmony_ci * ntfs_fix_post_read - Remove fixups after reading from disk.
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci * Return: < 0 if error, 0 if ok, 1 if need to update fixups.
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_ciint ntfs_fix_post_read(struct NTFS_RECORD_HEADER *rhdr, size_t bytes,
16962306a36Sopenharmony_ci		       bool simple)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	int ret;
17262306a36Sopenharmony_ci	u16 *fixup, *ptr;
17362306a36Sopenharmony_ci	u16 sample, fo, fn;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	fo = le16_to_cpu(rhdr->fix_off);
17662306a36Sopenharmony_ci	fn = simple ? ((bytes >> SECTOR_SHIFT) + 1) :
17762306a36Sopenharmony_ci		      le16_to_cpu(rhdr->fix_num);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* Check errors. */
18062306a36Sopenharmony_ci	if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
18162306a36Sopenharmony_ci	    fn * SECTOR_SIZE > bytes) {
18262306a36Sopenharmony_ci		return -E_NTFS_CORRUPT;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* Get fixup pointer. */
18662306a36Sopenharmony_ci	fixup = Add2Ptr(rhdr, fo);
18762306a36Sopenharmony_ci	sample = *fixup;
18862306a36Sopenharmony_ci	ptr = Add2Ptr(rhdr, SECTOR_SIZE - sizeof(short));
18962306a36Sopenharmony_ci	ret = 0;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	while (fn--) {
19262306a36Sopenharmony_ci		/* Test current word. */
19362306a36Sopenharmony_ci		if (*ptr != sample) {
19462306a36Sopenharmony_ci			/* Fixup does not match! Is it serious error? */
19562306a36Sopenharmony_ci			ret = -E_NTFS_FIXUP;
19662306a36Sopenharmony_ci		}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		/* Replace fixup. */
19962306a36Sopenharmony_ci		*ptr = *++fixup;
20062306a36Sopenharmony_ci		ptr += SECTOR_SIZE / sizeof(short);
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return ret;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/*
20762306a36Sopenharmony_ci * ntfs_extend_init - Load $Extend file.
20862306a36Sopenharmony_ci */
20962306a36Sopenharmony_ciint ntfs_extend_init(struct ntfs_sb_info *sbi)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	int err;
21262306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
21362306a36Sopenharmony_ci	struct inode *inode, *inode2;
21462306a36Sopenharmony_ci	struct MFT_REF ref;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (sbi->volume.major_ver < 3) {
21762306a36Sopenharmony_ci		ntfs_notice(sb, "Skip $Extend 'cause NTFS version");
21862306a36Sopenharmony_ci		return 0;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	ref.low = cpu_to_le32(MFT_REC_EXTEND);
22262306a36Sopenharmony_ci	ref.high = 0;
22362306a36Sopenharmony_ci	ref.seq = cpu_to_le16(MFT_REC_EXTEND);
22462306a36Sopenharmony_ci	inode = ntfs_iget5(sb, &ref, &NAME_EXTEND);
22562306a36Sopenharmony_ci	if (IS_ERR(inode)) {
22662306a36Sopenharmony_ci		err = PTR_ERR(inode);
22762306a36Sopenharmony_ci		ntfs_err(sb, "Failed to load $Extend (%d).", err);
22862306a36Sopenharmony_ci		inode = NULL;
22962306a36Sopenharmony_ci		goto out;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* If ntfs_iget5() reads from disk it never returns bad inode. */
23362306a36Sopenharmony_ci	if (!S_ISDIR(inode->i_mode)) {
23462306a36Sopenharmony_ci		err = -EINVAL;
23562306a36Sopenharmony_ci		goto out;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/* Try to find $ObjId */
23962306a36Sopenharmony_ci	inode2 = dir_search_u(inode, &NAME_OBJID, NULL);
24062306a36Sopenharmony_ci	if (inode2 && !IS_ERR(inode2)) {
24162306a36Sopenharmony_ci		if (is_bad_inode(inode2)) {
24262306a36Sopenharmony_ci			iput(inode2);
24362306a36Sopenharmony_ci		} else {
24462306a36Sopenharmony_ci			sbi->objid.ni = ntfs_i(inode2);
24562306a36Sopenharmony_ci			sbi->objid_no = inode2->i_ino;
24662306a36Sopenharmony_ci		}
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* Try to find $Quota */
25062306a36Sopenharmony_ci	inode2 = dir_search_u(inode, &NAME_QUOTA, NULL);
25162306a36Sopenharmony_ci	if (inode2 && !IS_ERR(inode2)) {
25262306a36Sopenharmony_ci		sbi->quota_no = inode2->i_ino;
25362306a36Sopenharmony_ci		iput(inode2);
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* Try to find $Reparse */
25762306a36Sopenharmony_ci	inode2 = dir_search_u(inode, &NAME_REPARSE, NULL);
25862306a36Sopenharmony_ci	if (inode2 && !IS_ERR(inode2)) {
25962306a36Sopenharmony_ci		sbi->reparse.ni = ntfs_i(inode2);
26062306a36Sopenharmony_ci		sbi->reparse_no = inode2->i_ino;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* Try to find $UsnJrnl */
26462306a36Sopenharmony_ci	inode2 = dir_search_u(inode, &NAME_USNJRNL, NULL);
26562306a36Sopenharmony_ci	if (inode2 && !IS_ERR(inode2)) {
26662306a36Sopenharmony_ci		sbi->usn_jrnl_no = inode2->i_ino;
26762306a36Sopenharmony_ci		iput(inode2);
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	err = 0;
27162306a36Sopenharmony_ciout:
27262306a36Sopenharmony_ci	iput(inode);
27362306a36Sopenharmony_ci	return err;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ciint ntfs_loadlog_and_replay(struct ntfs_inode *ni, struct ntfs_sb_info *sbi)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	int err = 0;
27962306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
28062306a36Sopenharmony_ci	bool initialized = false;
28162306a36Sopenharmony_ci	struct MFT_REF ref;
28262306a36Sopenharmony_ci	struct inode *inode;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* Check for 4GB. */
28562306a36Sopenharmony_ci	if (ni->vfs_inode.i_size >= 0x100000000ull) {
28662306a36Sopenharmony_ci		ntfs_err(sb, "\x24LogFile is large than 4G.");
28762306a36Sopenharmony_ci		err = -EINVAL;
28862306a36Sopenharmony_ci		goto out;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	sbi->flags |= NTFS_FLAGS_LOG_REPLAYING;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	ref.low = cpu_to_le32(MFT_REC_MFT);
29462306a36Sopenharmony_ci	ref.high = 0;
29562306a36Sopenharmony_ci	ref.seq = cpu_to_le16(1);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	inode = ntfs_iget5(sb, &ref, NULL);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (IS_ERR(inode))
30062306a36Sopenharmony_ci		inode = NULL;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!inode) {
30362306a36Sopenharmony_ci		/* Try to use MFT copy. */
30462306a36Sopenharmony_ci		u64 t64 = sbi->mft.lbo;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		sbi->mft.lbo = sbi->mft.lbo2;
30762306a36Sopenharmony_ci		inode = ntfs_iget5(sb, &ref, NULL);
30862306a36Sopenharmony_ci		sbi->mft.lbo = t64;
30962306a36Sopenharmony_ci		if (IS_ERR(inode))
31062306a36Sopenharmony_ci			inode = NULL;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	if (!inode) {
31462306a36Sopenharmony_ci		err = -EINVAL;
31562306a36Sopenharmony_ci		ntfs_err(sb, "Failed to load $MFT.");
31662306a36Sopenharmony_ci		goto out;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	sbi->mft.ni = ntfs_i(inode);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/* LogFile should not contains attribute list. */
32262306a36Sopenharmony_ci	err = ni_load_all_mi(sbi->mft.ni);
32362306a36Sopenharmony_ci	if (!err)
32462306a36Sopenharmony_ci		err = log_replay(ni, &initialized);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	iput(inode);
32762306a36Sopenharmony_ci	sbi->mft.ni = NULL;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	sync_blockdev(sb->s_bdev);
33062306a36Sopenharmony_ci	invalidate_bdev(sb->s_bdev);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (sbi->flags & NTFS_FLAGS_NEED_REPLAY) {
33362306a36Sopenharmony_ci		err = 0;
33462306a36Sopenharmony_ci		goto out;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if (sb_rdonly(sb) || !initialized)
33862306a36Sopenharmony_ci		goto out;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* Fill LogFile by '-1' if it is initialized. */
34162306a36Sopenharmony_ci	err = ntfs_bio_fill_1(sbi, &ni->file.run);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ciout:
34462306a36Sopenharmony_ci	sbi->flags &= ~NTFS_FLAGS_LOG_REPLAYING;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return err;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/*
35062306a36Sopenharmony_ci * ntfs_look_for_free_space - Look for a free space in bitmap.
35162306a36Sopenharmony_ci */
35262306a36Sopenharmony_ciint ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
35362306a36Sopenharmony_ci			     CLST *new_lcn, CLST *new_len,
35462306a36Sopenharmony_ci			     enum ALLOCATE_OPT opt)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	int err;
35762306a36Sopenharmony_ci	CLST alen;
35862306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
35962306a36Sopenharmony_ci	size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
36062306a36Sopenharmony_ci	struct wnd_bitmap *wnd = &sbi->used.bitmap;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
36362306a36Sopenharmony_ci	if (opt & ALLOCATE_MFT) {
36462306a36Sopenharmony_ci		zlen = wnd_zone_len(wnd);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		if (!zlen) {
36762306a36Sopenharmony_ci			err = ntfs_refresh_zone(sbi);
36862306a36Sopenharmony_ci			if (err)
36962306a36Sopenharmony_ci				goto up_write;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci			zlen = wnd_zone_len(wnd);
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		if (!zlen) {
37562306a36Sopenharmony_ci			ntfs_err(sbi->sb, "no free space to extend mft");
37662306a36Sopenharmony_ci			err = -ENOSPC;
37762306a36Sopenharmony_ci			goto up_write;
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		lcn = wnd_zone_bit(wnd);
38162306a36Sopenharmony_ci		alen = min_t(CLST, len, zlen);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		wnd_zone_set(wnd, lcn + alen, zlen - alen);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		err = wnd_set_used(wnd, lcn, alen);
38662306a36Sopenharmony_ci		if (err)
38762306a36Sopenharmony_ci			goto up_write;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		alcn = lcn;
39062306a36Sopenharmony_ci		goto space_found;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci	/*
39362306a36Sopenharmony_ci	 * 'Cause cluster 0 is always used this value means that we should use
39462306a36Sopenharmony_ci	 * cached value of 'next_free_lcn' to improve performance.
39562306a36Sopenharmony_ci	 */
39662306a36Sopenharmony_ci	if (!lcn)
39762306a36Sopenharmony_ci		lcn = sbi->used.next_free_lcn;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (lcn >= wnd->nbits)
40062306a36Sopenharmony_ci		lcn = 0;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	alen = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &alcn);
40362306a36Sopenharmony_ci	if (alen)
40462306a36Sopenharmony_ci		goto space_found;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* Try to use clusters from MftZone. */
40762306a36Sopenharmony_ci	zlen = wnd_zone_len(wnd);
40862306a36Sopenharmony_ci	zeroes = wnd_zeroes(wnd);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/* Check too big request */
41162306a36Sopenharmony_ci	if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE) {
41262306a36Sopenharmony_ci		err = -ENOSPC;
41362306a36Sopenharmony_ci		goto up_write;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	/* How many clusters to cat from zone. */
41762306a36Sopenharmony_ci	zlcn = wnd_zone_bit(wnd);
41862306a36Sopenharmony_ci	zlen2 = zlen >> 1;
41962306a36Sopenharmony_ci	ztrim = clamp_val(len, zlen2, zlen);
42062306a36Sopenharmony_ci	new_zlen = max_t(size_t, zlen - ztrim, NTFS_MIN_MFT_ZONE);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	wnd_zone_set(wnd, zlcn, new_zlen);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* Allocate continues clusters. */
42562306a36Sopenharmony_ci	alen = wnd_find(wnd, len, 0,
42662306a36Sopenharmony_ci			BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn);
42762306a36Sopenharmony_ci	if (!alen) {
42862306a36Sopenharmony_ci		err = -ENOSPC;
42962306a36Sopenharmony_ci		goto up_write;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cispace_found:
43362306a36Sopenharmony_ci	err = 0;
43462306a36Sopenharmony_ci	*new_len = alen;
43562306a36Sopenharmony_ci	*new_lcn = alcn;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	ntfs_unmap_meta(sb, alcn, alen);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/* Set hint for next requests. */
44062306a36Sopenharmony_ci	if (!(opt & ALLOCATE_MFT))
44162306a36Sopenharmony_ci		sbi->used.next_free_lcn = alcn + alen;
44262306a36Sopenharmony_ciup_write:
44362306a36Sopenharmony_ci	up_write(&wnd->rw_lock);
44462306a36Sopenharmony_ci	return err;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci/*
44862306a36Sopenharmony_ci * ntfs_check_for_free_space
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * Check if it is possible to allocate 'clen' clusters and 'mlen' Mft records
45162306a36Sopenharmony_ci */
45262306a36Sopenharmony_cibool ntfs_check_for_free_space(struct ntfs_sb_info *sbi, CLST clen, CLST mlen)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	size_t free, zlen, avail;
45562306a36Sopenharmony_ci	struct wnd_bitmap *wnd;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	wnd = &sbi->used.bitmap;
45862306a36Sopenharmony_ci	down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
45962306a36Sopenharmony_ci	free = wnd_zeroes(wnd);
46062306a36Sopenharmony_ci	zlen = min_t(size_t, NTFS_MIN_MFT_ZONE, wnd_zone_len(wnd));
46162306a36Sopenharmony_ci	up_read(&wnd->rw_lock);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (free < zlen + clen)
46462306a36Sopenharmony_ci		return false;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	avail = free - (zlen + clen);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	wnd = &sbi->mft.bitmap;
46962306a36Sopenharmony_ci	down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
47062306a36Sopenharmony_ci	free = wnd_zeroes(wnd);
47162306a36Sopenharmony_ci	zlen = wnd_zone_len(wnd);
47262306a36Sopenharmony_ci	up_read(&wnd->rw_lock);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (free >= zlen + mlen)
47562306a36Sopenharmony_ci		return true;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return avail >= bytes_to_cluster(sbi, mlen << sbi->record_bits);
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci/*
48162306a36Sopenharmony_ci * ntfs_extend_mft - Allocate additional MFT records.
48262306a36Sopenharmony_ci *
48362306a36Sopenharmony_ci * sbi->mft.bitmap is locked for write.
48462306a36Sopenharmony_ci *
48562306a36Sopenharmony_ci * NOTE: recursive:
48662306a36Sopenharmony_ci *	ntfs_look_free_mft ->
48762306a36Sopenharmony_ci *	ntfs_extend_mft ->
48862306a36Sopenharmony_ci *	attr_set_size ->
48962306a36Sopenharmony_ci *	ni_insert_nonresident ->
49062306a36Sopenharmony_ci *	ni_insert_attr ->
49162306a36Sopenharmony_ci *	ni_ins_attr_ext ->
49262306a36Sopenharmony_ci *	ntfs_look_free_mft ->
49362306a36Sopenharmony_ci *	ntfs_extend_mft
49462306a36Sopenharmony_ci *
49562306a36Sopenharmony_ci * To avoid recursive always allocate space for two new MFT records
49662306a36Sopenharmony_ci * see attrib.c: "at least two MFT to avoid recursive loop".
49762306a36Sopenharmony_ci */
49862306a36Sopenharmony_cistatic int ntfs_extend_mft(struct ntfs_sb_info *sbi)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	int err;
50162306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->mft.ni;
50262306a36Sopenharmony_ci	size_t new_mft_total;
50362306a36Sopenharmony_ci	u64 new_mft_bytes, new_bitmap_bytes;
50462306a36Sopenharmony_ci	struct ATTRIB *attr;
50562306a36Sopenharmony_ci	struct wnd_bitmap *wnd = &sbi->mft.bitmap;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	new_mft_total = ALIGN(wnd->nbits + NTFS_MFT_INCREASE_STEP, 128);
50862306a36Sopenharmony_ci	new_mft_bytes = (u64)new_mft_total << sbi->record_bits;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/* Step 1: Resize $MFT::DATA. */
51162306a36Sopenharmony_ci	down_write(&ni->file.run_lock);
51262306a36Sopenharmony_ci	err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run,
51362306a36Sopenharmony_ci			    new_mft_bytes, NULL, false, &attr);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (err) {
51662306a36Sopenharmony_ci		up_write(&ni->file.run_lock);
51762306a36Sopenharmony_ci		goto out;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	attr->nres.valid_size = attr->nres.data_size;
52162306a36Sopenharmony_ci	new_mft_total = le64_to_cpu(attr->nres.alloc_size) >> sbi->record_bits;
52262306a36Sopenharmony_ci	ni->mi.dirty = true;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* Step 2: Resize $MFT::BITMAP. */
52562306a36Sopenharmony_ci	new_bitmap_bytes = bitmap_size(new_mft_total);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	err = attr_set_size(ni, ATTR_BITMAP, NULL, 0, &sbi->mft.bitmap.run,
52862306a36Sopenharmony_ci			    new_bitmap_bytes, &new_bitmap_bytes, true, NULL);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* Refresh MFT Zone if necessary. */
53162306a36Sopenharmony_ci	down_write_nested(&sbi->used.bitmap.rw_lock, BITMAP_MUTEX_CLUSTERS);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	ntfs_refresh_zone(sbi);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	up_write(&sbi->used.bitmap.rw_lock);
53662306a36Sopenharmony_ci	up_write(&ni->file.run_lock);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	if (err)
53962306a36Sopenharmony_ci		goto out;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	err = wnd_extend(wnd, new_mft_total);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (err)
54462306a36Sopenharmony_ci		goto out;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	ntfs_clear_mft_tail(sbi, sbi->mft.used, new_mft_total);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	err = _ni_write_inode(&ni->vfs_inode, 0);
54962306a36Sopenharmony_ciout:
55062306a36Sopenharmony_ci	return err;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci/*
55462306a36Sopenharmony_ci * ntfs_look_free_mft - Look for a free MFT record.
55562306a36Sopenharmony_ci */
55662306a36Sopenharmony_ciint ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft,
55762306a36Sopenharmony_ci		       struct ntfs_inode *ni, struct mft_inode **mi)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	int err = 0;
56062306a36Sopenharmony_ci	size_t zbit, zlen, from, to, fr;
56162306a36Sopenharmony_ci	size_t mft_total;
56262306a36Sopenharmony_ci	struct MFT_REF ref;
56362306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
56462306a36Sopenharmony_ci	struct wnd_bitmap *wnd = &sbi->mft.bitmap;
56562306a36Sopenharmony_ci	u32 ir;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	static_assert(sizeof(sbi->mft.reserved_bitmap) * 8 >=
56862306a36Sopenharmony_ci		      MFT_REC_FREE - MFT_REC_RESERVED);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (!mft)
57162306a36Sopenharmony_ci		down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	zlen = wnd_zone_len(wnd);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* Always reserve space for MFT. */
57662306a36Sopenharmony_ci	if (zlen) {
57762306a36Sopenharmony_ci		if (mft) {
57862306a36Sopenharmony_ci			zbit = wnd_zone_bit(wnd);
57962306a36Sopenharmony_ci			*rno = zbit;
58062306a36Sopenharmony_ci			wnd_zone_set(wnd, zbit + 1, zlen - 1);
58162306a36Sopenharmony_ci		}
58262306a36Sopenharmony_ci		goto found;
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* No MFT zone. Find the nearest to '0' free MFT. */
58662306a36Sopenharmony_ci	if (!wnd_find(wnd, 1, MFT_REC_FREE, 0, &zbit)) {
58762306a36Sopenharmony_ci		/* Resize MFT */
58862306a36Sopenharmony_ci		mft_total = wnd->nbits;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		err = ntfs_extend_mft(sbi);
59162306a36Sopenharmony_ci		if (!err) {
59262306a36Sopenharmony_ci			zbit = mft_total;
59362306a36Sopenharmony_ci			goto reserve_mft;
59462306a36Sopenharmony_ci		}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		if (!mft || MFT_REC_FREE == sbi->mft.next_reserved)
59762306a36Sopenharmony_ci			goto out;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		err = 0;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		/*
60262306a36Sopenharmony_ci		 * Look for free record reserved area [11-16) ==
60362306a36Sopenharmony_ci		 * [MFT_REC_RESERVED, MFT_REC_FREE ) MFT bitmap always
60462306a36Sopenharmony_ci		 * marks it as used.
60562306a36Sopenharmony_ci		 */
60662306a36Sopenharmony_ci		if (!sbi->mft.reserved_bitmap) {
60762306a36Sopenharmony_ci			/* Once per session create internal bitmap for 5 bits. */
60862306a36Sopenharmony_ci			sbi->mft.reserved_bitmap = 0xFF;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci			ref.high = 0;
61162306a36Sopenharmony_ci			for (ir = MFT_REC_RESERVED; ir < MFT_REC_FREE; ir++) {
61262306a36Sopenharmony_ci				struct inode *i;
61362306a36Sopenharmony_ci				struct ntfs_inode *ni;
61462306a36Sopenharmony_ci				struct MFT_REC *mrec;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci				ref.low = cpu_to_le32(ir);
61762306a36Sopenharmony_ci				ref.seq = cpu_to_le16(ir);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci				i = ntfs_iget5(sb, &ref, NULL);
62062306a36Sopenharmony_ci				if (IS_ERR(i)) {
62162306a36Sopenharmony_cinext:
62262306a36Sopenharmony_ci					ntfs_notice(
62362306a36Sopenharmony_ci						sb,
62462306a36Sopenharmony_ci						"Invalid reserved record %x",
62562306a36Sopenharmony_ci						ref.low);
62662306a36Sopenharmony_ci					continue;
62762306a36Sopenharmony_ci				}
62862306a36Sopenharmony_ci				if (is_bad_inode(i)) {
62962306a36Sopenharmony_ci					iput(i);
63062306a36Sopenharmony_ci					goto next;
63162306a36Sopenharmony_ci				}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci				ni = ntfs_i(i);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci				mrec = ni->mi.mrec;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci				if (!is_rec_base(mrec))
63862306a36Sopenharmony_ci					goto next;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci				if (mrec->hard_links)
64162306a36Sopenharmony_ci					goto next;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci				if (!ni_std(ni))
64462306a36Sopenharmony_ci					goto next;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci				if (ni_find_attr(ni, NULL, NULL, ATTR_NAME,
64762306a36Sopenharmony_ci						 NULL, 0, NULL, NULL))
64862306a36Sopenharmony_ci					goto next;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci				__clear_bit(ir - MFT_REC_RESERVED,
65162306a36Sopenharmony_ci					    &sbi->mft.reserved_bitmap);
65262306a36Sopenharmony_ci			}
65362306a36Sopenharmony_ci		}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		/* Scan 5 bits for zero. Bit 0 == MFT_REC_RESERVED */
65662306a36Sopenharmony_ci		zbit = find_next_zero_bit(&sbi->mft.reserved_bitmap,
65762306a36Sopenharmony_ci					  MFT_REC_FREE, MFT_REC_RESERVED);
65862306a36Sopenharmony_ci		if (zbit >= MFT_REC_FREE) {
65962306a36Sopenharmony_ci			sbi->mft.next_reserved = MFT_REC_FREE;
66062306a36Sopenharmony_ci			goto out;
66162306a36Sopenharmony_ci		}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		zlen = 1;
66462306a36Sopenharmony_ci		sbi->mft.next_reserved = zbit;
66562306a36Sopenharmony_ci	} else {
66662306a36Sopenharmony_cireserve_mft:
66762306a36Sopenharmony_ci		zlen = zbit == MFT_REC_FREE ? (MFT_REC_USER - MFT_REC_FREE) : 4;
66862306a36Sopenharmony_ci		if (zbit + zlen > wnd->nbits)
66962306a36Sopenharmony_ci			zlen = wnd->nbits - zbit;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		while (zlen > 1 && !wnd_is_free(wnd, zbit, zlen))
67262306a36Sopenharmony_ci			zlen -= 1;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		/* [zbit, zbit + zlen) will be used for MFT itself. */
67562306a36Sopenharmony_ci		from = sbi->mft.used;
67662306a36Sopenharmony_ci		if (from < zbit)
67762306a36Sopenharmony_ci			from = zbit;
67862306a36Sopenharmony_ci		to = zbit + zlen;
67962306a36Sopenharmony_ci		if (from < to) {
68062306a36Sopenharmony_ci			ntfs_clear_mft_tail(sbi, from, to);
68162306a36Sopenharmony_ci			sbi->mft.used = to;
68262306a36Sopenharmony_ci		}
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	if (mft) {
68662306a36Sopenharmony_ci		*rno = zbit;
68762306a36Sopenharmony_ci		zbit += 1;
68862306a36Sopenharmony_ci		zlen -= 1;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	wnd_zone_set(wnd, zbit, zlen);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cifound:
69462306a36Sopenharmony_ci	if (!mft) {
69562306a36Sopenharmony_ci		/* The request to get record for general purpose. */
69662306a36Sopenharmony_ci		if (sbi->mft.next_free < MFT_REC_USER)
69762306a36Sopenharmony_ci			sbi->mft.next_free = MFT_REC_USER;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		for (;;) {
70062306a36Sopenharmony_ci			if (sbi->mft.next_free >= sbi->mft.bitmap.nbits) {
70162306a36Sopenharmony_ci			} else if (!wnd_find(wnd, 1, MFT_REC_USER, 0, &fr)) {
70262306a36Sopenharmony_ci				sbi->mft.next_free = sbi->mft.bitmap.nbits;
70362306a36Sopenharmony_ci			} else {
70462306a36Sopenharmony_ci				*rno = fr;
70562306a36Sopenharmony_ci				sbi->mft.next_free = *rno + 1;
70662306a36Sopenharmony_ci				break;
70762306a36Sopenharmony_ci			}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci			err = ntfs_extend_mft(sbi);
71062306a36Sopenharmony_ci			if (err)
71162306a36Sopenharmony_ci				goto out;
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (ni && !ni_add_subrecord(ni, *rno, mi)) {
71662306a36Sopenharmony_ci		err = -ENOMEM;
71762306a36Sopenharmony_ci		goto out;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	/* We have found a record that are not reserved for next MFT. */
72162306a36Sopenharmony_ci	if (*rno >= MFT_REC_FREE)
72262306a36Sopenharmony_ci		wnd_set_used(wnd, *rno, 1);
72362306a36Sopenharmony_ci	else if (*rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited)
72462306a36Sopenharmony_ci		__set_bit(*rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ciout:
72762306a36Sopenharmony_ci	if (!mft)
72862306a36Sopenharmony_ci		up_write(&wnd->rw_lock);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	return err;
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci/*
73462306a36Sopenharmony_ci * ntfs_mark_rec_free - Mark record as free.
73562306a36Sopenharmony_ci * is_mft - true if we are changing MFT
73662306a36Sopenharmony_ci */
73762306a36Sopenharmony_civoid ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	struct wnd_bitmap *wnd = &sbi->mft.bitmap;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (!is_mft)
74262306a36Sopenharmony_ci		down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
74362306a36Sopenharmony_ci	if (rno >= wnd->nbits)
74462306a36Sopenharmony_ci		goto out;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	if (rno >= MFT_REC_FREE) {
74762306a36Sopenharmony_ci		if (!wnd_is_used(wnd, rno, 1))
74862306a36Sopenharmony_ci			ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
74962306a36Sopenharmony_ci		else
75062306a36Sopenharmony_ci			wnd_set_free(wnd, rno, 1);
75162306a36Sopenharmony_ci	} else if (rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited) {
75262306a36Sopenharmony_ci		__clear_bit(rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap);
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (rno < wnd_zone_bit(wnd))
75662306a36Sopenharmony_ci		wnd_zone_set(wnd, rno, 1);
75762306a36Sopenharmony_ci	else if (rno < sbi->mft.next_free && rno >= MFT_REC_USER)
75862306a36Sopenharmony_ci		sbi->mft.next_free = rno;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ciout:
76162306a36Sopenharmony_ci	if (!is_mft)
76262306a36Sopenharmony_ci		up_write(&wnd->rw_lock);
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci/*
76662306a36Sopenharmony_ci * ntfs_clear_mft_tail - Format empty records [from, to).
76762306a36Sopenharmony_ci *
76862306a36Sopenharmony_ci * sbi->mft.bitmap is locked for write.
76962306a36Sopenharmony_ci */
77062306a36Sopenharmony_ciint ntfs_clear_mft_tail(struct ntfs_sb_info *sbi, size_t from, size_t to)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	int err;
77362306a36Sopenharmony_ci	u32 rs;
77462306a36Sopenharmony_ci	u64 vbo;
77562306a36Sopenharmony_ci	struct runs_tree *run;
77662306a36Sopenharmony_ci	struct ntfs_inode *ni;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	if (from >= to)
77962306a36Sopenharmony_ci		return 0;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	rs = sbi->record_size;
78262306a36Sopenharmony_ci	ni = sbi->mft.ni;
78362306a36Sopenharmony_ci	run = &ni->file.run;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	down_read(&ni->file.run_lock);
78662306a36Sopenharmony_ci	vbo = (u64)from * rs;
78762306a36Sopenharmony_ci	for (; from < to; from++, vbo += rs) {
78862306a36Sopenharmony_ci		struct ntfs_buffers nb;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		err = ntfs_get_bh(sbi, run, vbo, rs, &nb);
79162306a36Sopenharmony_ci		if (err)
79262306a36Sopenharmony_ci			goto out;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci		err = ntfs_write_bh(sbi, &sbi->new_rec->rhdr, &nb, 0);
79562306a36Sopenharmony_ci		nb_put(&nb);
79662306a36Sopenharmony_ci		if (err)
79762306a36Sopenharmony_ci			goto out;
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ciout:
80162306a36Sopenharmony_ci	sbi->mft.used = from;
80262306a36Sopenharmony_ci	up_read(&ni->file.run_lock);
80362306a36Sopenharmony_ci	return err;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci/*
80762306a36Sopenharmony_ci * ntfs_refresh_zone - Refresh MFT zone.
80862306a36Sopenharmony_ci *
80962306a36Sopenharmony_ci * sbi->used.bitmap is locked for rw.
81062306a36Sopenharmony_ci * sbi->mft.bitmap is locked for write.
81162306a36Sopenharmony_ci * sbi->mft.ni->file.run_lock for write.
81262306a36Sopenharmony_ci */
81362306a36Sopenharmony_ciint ntfs_refresh_zone(struct ntfs_sb_info *sbi)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	CLST lcn, vcn, len;
81662306a36Sopenharmony_ci	size_t lcn_s, zlen;
81762306a36Sopenharmony_ci	struct wnd_bitmap *wnd = &sbi->used.bitmap;
81862306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->mft.ni;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* Do not change anything unless we have non empty MFT zone. */
82162306a36Sopenharmony_ci	if (wnd_zone_len(wnd))
82262306a36Sopenharmony_ci		return 0;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	vcn = bytes_to_cluster(sbi,
82562306a36Sopenharmony_ci			       (u64)sbi->mft.bitmap.nbits << sbi->record_bits);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	if (!run_lookup_entry(&ni->file.run, vcn - 1, &lcn, &len, NULL))
82862306a36Sopenharmony_ci		lcn = SPARSE_LCN;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	/* We should always find Last Lcn for MFT. */
83162306a36Sopenharmony_ci	if (lcn == SPARSE_LCN)
83262306a36Sopenharmony_ci		return -EINVAL;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	lcn_s = lcn + 1;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* Try to allocate clusters after last MFT run. */
83762306a36Sopenharmony_ci	zlen = wnd_find(wnd, sbi->zone_max, lcn_s, 0, &lcn_s);
83862306a36Sopenharmony_ci	wnd_zone_set(wnd, lcn_s, zlen);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	return 0;
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci/*
84462306a36Sopenharmony_ci * ntfs_update_mftmirr - Update $MFTMirr data.
84562306a36Sopenharmony_ci */
84662306a36Sopenharmony_civoid ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	int err;
84962306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
85062306a36Sopenharmony_ci	u32 blocksize, bytes;
85162306a36Sopenharmony_ci	sector_t block1, block2;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/*
85462306a36Sopenharmony_ci	 * sb can be NULL here. In this case sbi->flags should be 0 too.
85562306a36Sopenharmony_ci	 */
85662306a36Sopenharmony_ci	if (!sb || !(sbi->flags & NTFS_FLAGS_MFTMIRR) ||
85762306a36Sopenharmony_ci	    unlikely(ntfs3_forced_shutdown(sb)))
85862306a36Sopenharmony_ci		return;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	blocksize = sb->s_blocksize;
86162306a36Sopenharmony_ci	bytes = sbi->mft.recs_mirr << sbi->record_bits;
86262306a36Sopenharmony_ci	block1 = sbi->mft.lbo >> sb->s_blocksize_bits;
86362306a36Sopenharmony_ci	block2 = sbi->mft.lbo2 >> sb->s_blocksize_bits;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	for (; bytes >= blocksize; bytes -= blocksize) {
86662306a36Sopenharmony_ci		struct buffer_head *bh1, *bh2;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci		bh1 = sb_bread(sb, block1++);
86962306a36Sopenharmony_ci		if (!bh1)
87062306a36Sopenharmony_ci			return;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		bh2 = sb_getblk(sb, block2++);
87362306a36Sopenharmony_ci		if (!bh2) {
87462306a36Sopenharmony_ci			put_bh(bh1);
87562306a36Sopenharmony_ci			return;
87662306a36Sopenharmony_ci		}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci		if (buffer_locked(bh2))
87962306a36Sopenharmony_ci			__wait_on_buffer(bh2);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci		lock_buffer(bh2);
88262306a36Sopenharmony_ci		memcpy(bh2->b_data, bh1->b_data, blocksize);
88362306a36Sopenharmony_ci		set_buffer_uptodate(bh2);
88462306a36Sopenharmony_ci		mark_buffer_dirty(bh2);
88562306a36Sopenharmony_ci		unlock_buffer(bh2);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci		put_bh(bh1);
88862306a36Sopenharmony_ci		bh1 = NULL;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci		err = wait ? sync_dirty_buffer(bh2) : 0;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci		put_bh(bh2);
89362306a36Sopenharmony_ci		if (err)
89462306a36Sopenharmony_ci			return;
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	sbi->flags &= ~NTFS_FLAGS_MFTMIRR;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci/*
90162306a36Sopenharmony_ci * ntfs_bad_inode
90262306a36Sopenharmony_ci *
90362306a36Sopenharmony_ci * Marks inode as bad and marks fs as 'dirty'
90462306a36Sopenharmony_ci */
90562306a36Sopenharmony_civoid ntfs_bad_inode(struct inode *inode, const char *hint)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	ntfs_inode_err(inode, "%s", hint);
91062306a36Sopenharmony_ci	make_bad_inode(inode);
91162306a36Sopenharmony_ci	ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci/*
91562306a36Sopenharmony_ci * ntfs_set_state
91662306a36Sopenharmony_ci *
91762306a36Sopenharmony_ci * Mount: ntfs_set_state(NTFS_DIRTY_DIRTY)
91862306a36Sopenharmony_ci * Umount: ntfs_set_state(NTFS_DIRTY_CLEAR)
91962306a36Sopenharmony_ci * NTFS error: ntfs_set_state(NTFS_DIRTY_ERROR)
92062306a36Sopenharmony_ci */
92162306a36Sopenharmony_ciint ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	int err;
92462306a36Sopenharmony_ci	struct ATTRIB *attr;
92562306a36Sopenharmony_ci	struct VOLUME_INFO *info;
92662306a36Sopenharmony_ci	struct mft_inode *mi;
92762306a36Sopenharmony_ci	struct ntfs_inode *ni;
92862306a36Sopenharmony_ci	__le16 info_flags;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	/*
93162306a36Sopenharmony_ci	 * Do not change state if fs was real_dirty.
93262306a36Sopenharmony_ci	 * Do not change state if fs already dirty(clear).
93362306a36Sopenharmony_ci	 * Do not change any thing if mounted read only.
93462306a36Sopenharmony_ci	 */
93562306a36Sopenharmony_ci	if (sbi->volume.real_dirty || sb_rdonly(sbi->sb))
93662306a36Sopenharmony_ci		return 0;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	/* Check cached value. */
93962306a36Sopenharmony_ci	if ((dirty == NTFS_DIRTY_CLEAR ? 0 : VOLUME_FLAG_DIRTY) ==
94062306a36Sopenharmony_ci	    (sbi->volume.flags & VOLUME_FLAG_DIRTY))
94162306a36Sopenharmony_ci		return 0;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	ni = sbi->volume.ni;
94462306a36Sopenharmony_ci	if (!ni)
94562306a36Sopenharmony_ci		return -EINVAL;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_DIRTY);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	attr = ni_find_attr(ni, NULL, NULL, ATTR_VOL_INFO, NULL, 0, NULL, &mi);
95062306a36Sopenharmony_ci	if (!attr) {
95162306a36Sopenharmony_ci		err = -EINVAL;
95262306a36Sopenharmony_ci		goto out;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO);
95662306a36Sopenharmony_ci	if (!info) {
95762306a36Sopenharmony_ci		err = -EINVAL;
95862306a36Sopenharmony_ci		goto out;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	info_flags = info->flags;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	switch (dirty) {
96462306a36Sopenharmony_ci	case NTFS_DIRTY_ERROR:
96562306a36Sopenharmony_ci		ntfs_notice(sbi->sb, "Mark volume as dirty due to NTFS errors");
96662306a36Sopenharmony_ci		sbi->volume.real_dirty = true;
96762306a36Sopenharmony_ci		fallthrough;
96862306a36Sopenharmony_ci	case NTFS_DIRTY_DIRTY:
96962306a36Sopenharmony_ci		info->flags |= VOLUME_FLAG_DIRTY;
97062306a36Sopenharmony_ci		break;
97162306a36Sopenharmony_ci	case NTFS_DIRTY_CLEAR:
97262306a36Sopenharmony_ci		info->flags &= ~VOLUME_FLAG_DIRTY;
97362306a36Sopenharmony_ci		break;
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci	/* Cache current volume flags. */
97662306a36Sopenharmony_ci	if (info_flags != info->flags) {
97762306a36Sopenharmony_ci		sbi->volume.flags = info->flags;
97862306a36Sopenharmony_ci		mi->dirty = true;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci	err = 0;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ciout:
98362306a36Sopenharmony_ci	ni_unlock(ni);
98462306a36Sopenharmony_ci	if (err)
98562306a36Sopenharmony_ci		return err;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	mark_inode_dirty_sync(&ni->vfs_inode);
98862306a36Sopenharmony_ci	/* verify(!ntfs_update_mftmirr()); */
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	/* write mft record on disk. */
99162306a36Sopenharmony_ci	err = _ni_write_inode(&ni->vfs_inode, 1);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	return err;
99462306a36Sopenharmony_ci}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci/*
99762306a36Sopenharmony_ci * security_hash - Calculates a hash of security descriptor.
99862306a36Sopenharmony_ci */
99962306a36Sopenharmony_cistatic inline __le32 security_hash(const void *sd, size_t bytes)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	u32 hash = 0;
100262306a36Sopenharmony_ci	const __le32 *ptr = sd;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	bytes >>= 2;
100562306a36Sopenharmony_ci	while (bytes--)
100662306a36Sopenharmony_ci		hash = ((hash >> 0x1D) | (hash << 3)) + le32_to_cpu(*ptr++);
100762306a36Sopenharmony_ci	return cpu_to_le32(hash);
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci/*
101162306a36Sopenharmony_ci * simple wrapper for sb_bread_unmovable.
101262306a36Sopenharmony_ci */
101362306a36Sopenharmony_cistruct buffer_head *ntfs_bread(struct super_block *sb, sector_t block)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = sb->s_fs_info;
101662306a36Sopenharmony_ci	struct buffer_head *bh;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	if (unlikely(block >= sbi->volume.blocks)) {
101962306a36Sopenharmony_ci		/* prevent generic message "attempt to access beyond end of device" */
102062306a36Sopenharmony_ci		ntfs_err(sb, "try to read out of volume at offset 0x%llx",
102162306a36Sopenharmony_ci			 (u64)block << sb->s_blocksize_bits);
102262306a36Sopenharmony_ci		return NULL;
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	bh = sb_bread_unmovable(sb, block);
102662306a36Sopenharmony_ci	if (bh)
102762306a36Sopenharmony_ci		return bh;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	ntfs_err(sb, "failed to read volume at offset 0x%llx",
103062306a36Sopenharmony_ci		 (u64)block << sb->s_blocksize_bits);
103162306a36Sopenharmony_ci	return NULL;
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ciint ntfs_sb_read(struct super_block *sb, u64 lbo, size_t bytes, void *buffer)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	struct block_device *bdev = sb->s_bdev;
103762306a36Sopenharmony_ci	u32 blocksize = sb->s_blocksize;
103862306a36Sopenharmony_ci	u64 block = lbo >> sb->s_blocksize_bits;
103962306a36Sopenharmony_ci	u32 off = lbo & (blocksize - 1);
104062306a36Sopenharmony_ci	u32 op = blocksize - off;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	for (; bytes; block += 1, off = 0, op = blocksize) {
104362306a36Sopenharmony_ci		struct buffer_head *bh = __bread(bdev, block, blocksize);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci		if (!bh)
104662306a36Sopenharmony_ci			return -EIO;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		if (op > bytes)
104962306a36Sopenharmony_ci			op = bytes;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci		memcpy(buffer, bh->b_data + off, op);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci		put_bh(bh);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		bytes -= op;
105662306a36Sopenharmony_ci		buffer = Add2Ptr(buffer, op);
105762306a36Sopenharmony_ci	}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	return 0;
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ciint ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
106362306a36Sopenharmony_ci		  const void *buf, int wait)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	u32 blocksize = sb->s_blocksize;
106662306a36Sopenharmony_ci	struct block_device *bdev = sb->s_bdev;
106762306a36Sopenharmony_ci	sector_t block = lbo >> sb->s_blocksize_bits;
106862306a36Sopenharmony_ci	u32 off = lbo & (blocksize - 1);
106962306a36Sopenharmony_ci	u32 op = blocksize - off;
107062306a36Sopenharmony_ci	struct buffer_head *bh;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	if (!wait && (sb->s_flags & SB_SYNCHRONOUS))
107362306a36Sopenharmony_ci		wait = 1;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	for (; bytes; block += 1, off = 0, op = blocksize) {
107662306a36Sopenharmony_ci		if (op > bytes)
107762306a36Sopenharmony_ci			op = bytes;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		if (op < blocksize) {
108062306a36Sopenharmony_ci			bh = __bread(bdev, block, blocksize);
108162306a36Sopenharmony_ci			if (!bh) {
108262306a36Sopenharmony_ci				ntfs_err(sb, "failed to read block %llx",
108362306a36Sopenharmony_ci					 (u64)block);
108462306a36Sopenharmony_ci				return -EIO;
108562306a36Sopenharmony_ci			}
108662306a36Sopenharmony_ci		} else {
108762306a36Sopenharmony_ci			bh = __getblk(bdev, block, blocksize);
108862306a36Sopenharmony_ci			if (!bh)
108962306a36Sopenharmony_ci				return -ENOMEM;
109062306a36Sopenharmony_ci		}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		if (buffer_locked(bh))
109362306a36Sopenharmony_ci			__wait_on_buffer(bh);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci		lock_buffer(bh);
109662306a36Sopenharmony_ci		if (buf) {
109762306a36Sopenharmony_ci			memcpy(bh->b_data + off, buf, op);
109862306a36Sopenharmony_ci			buf = Add2Ptr(buf, op);
109962306a36Sopenharmony_ci		} else {
110062306a36Sopenharmony_ci			memset(bh->b_data + off, -1, op);
110162306a36Sopenharmony_ci		}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci		set_buffer_uptodate(bh);
110462306a36Sopenharmony_ci		mark_buffer_dirty(bh);
110562306a36Sopenharmony_ci		unlock_buffer(bh);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci		if (wait) {
110862306a36Sopenharmony_ci			int err = sync_dirty_buffer(bh);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci			if (err) {
111162306a36Sopenharmony_ci				ntfs_err(
111262306a36Sopenharmony_ci					sb,
111362306a36Sopenharmony_ci					"failed to sync buffer at block %llx, error %d",
111462306a36Sopenharmony_ci					(u64)block, err);
111562306a36Sopenharmony_ci				put_bh(bh);
111662306a36Sopenharmony_ci				return err;
111762306a36Sopenharmony_ci			}
111862306a36Sopenharmony_ci		}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci		put_bh(bh);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		bytes -= op;
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci	return 0;
112562306a36Sopenharmony_ci}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ciint ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
112862306a36Sopenharmony_ci		      u64 vbo, const void *buf, size_t bytes, int sync)
112962306a36Sopenharmony_ci{
113062306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
113162306a36Sopenharmony_ci	u8 cluster_bits = sbi->cluster_bits;
113262306a36Sopenharmony_ci	u32 off = vbo & sbi->cluster_mask;
113362306a36Sopenharmony_ci	CLST lcn, clen, vcn = vbo >> cluster_bits, vcn_next;
113462306a36Sopenharmony_ci	u64 lbo, len;
113562306a36Sopenharmony_ci	size_t idx;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx))
113862306a36Sopenharmony_ci		return -ENOENT;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	if (lcn == SPARSE_LCN)
114162306a36Sopenharmony_ci		return -EINVAL;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	lbo = ((u64)lcn << cluster_bits) + off;
114462306a36Sopenharmony_ci	len = ((u64)clen << cluster_bits) - off;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	for (;;) {
114762306a36Sopenharmony_ci		u32 op = min_t(u64, len, bytes);
114862306a36Sopenharmony_ci		int err = ntfs_sb_write(sb, lbo, op, buf, sync);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci		if (err)
115162306a36Sopenharmony_ci			return err;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci		bytes -= op;
115462306a36Sopenharmony_ci		if (!bytes)
115562306a36Sopenharmony_ci			break;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci		vcn_next = vcn + clen;
115862306a36Sopenharmony_ci		if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
115962306a36Sopenharmony_ci		    vcn != vcn_next)
116062306a36Sopenharmony_ci			return -ENOENT;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci		if (lcn == SPARSE_LCN)
116362306a36Sopenharmony_ci			return -EINVAL;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		if (buf)
116662306a36Sopenharmony_ci			buf = Add2Ptr(buf, op);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci		lbo = ((u64)lcn << cluster_bits);
116962306a36Sopenharmony_ci		len = ((u64)clen << cluster_bits);
117062306a36Sopenharmony_ci	}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	return 0;
117362306a36Sopenharmony_ci}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_cistruct buffer_head *ntfs_bread_run(struct ntfs_sb_info *sbi,
117662306a36Sopenharmony_ci				   const struct runs_tree *run, u64 vbo)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
117962306a36Sopenharmony_ci	u8 cluster_bits = sbi->cluster_bits;
118062306a36Sopenharmony_ci	CLST lcn;
118162306a36Sopenharmony_ci	u64 lbo;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	if (!run_lookup_entry(run, vbo >> cluster_bits, &lcn, NULL, NULL))
118462306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	lbo = ((u64)lcn << cluster_bits) + (vbo & sbi->cluster_mask);
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	return ntfs_bread(sb, lbo >> sb->s_blocksize_bits);
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ciint ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
119262306a36Sopenharmony_ci		     u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	int err;
119562306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
119662306a36Sopenharmony_ci	u32 blocksize = sb->s_blocksize;
119762306a36Sopenharmony_ci	u8 cluster_bits = sbi->cluster_bits;
119862306a36Sopenharmony_ci	u32 off = vbo & sbi->cluster_mask;
119962306a36Sopenharmony_ci	u32 nbh = 0;
120062306a36Sopenharmony_ci	CLST vcn_next, vcn = vbo >> cluster_bits;
120162306a36Sopenharmony_ci	CLST lcn, clen;
120262306a36Sopenharmony_ci	u64 lbo, len;
120362306a36Sopenharmony_ci	size_t idx;
120462306a36Sopenharmony_ci	struct buffer_head *bh;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (!run) {
120762306a36Sopenharmony_ci		/* First reading of $Volume + $MFTMirr + $LogFile goes here. */
120862306a36Sopenharmony_ci		if (vbo > MFT_REC_VOL * sbi->record_size) {
120962306a36Sopenharmony_ci			err = -ENOENT;
121062306a36Sopenharmony_ci			goto out;
121162306a36Sopenharmony_ci		}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci		/* Use absolute boot's 'MFTCluster' to read record. */
121462306a36Sopenharmony_ci		lbo = vbo + sbi->mft.lbo;
121562306a36Sopenharmony_ci		len = sbi->record_size;
121662306a36Sopenharmony_ci	} else if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
121762306a36Sopenharmony_ci		err = -ENOENT;
121862306a36Sopenharmony_ci		goto out;
121962306a36Sopenharmony_ci	} else {
122062306a36Sopenharmony_ci		if (lcn == SPARSE_LCN) {
122162306a36Sopenharmony_ci			err = -EINVAL;
122262306a36Sopenharmony_ci			goto out;
122362306a36Sopenharmony_ci		}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci		lbo = ((u64)lcn << cluster_bits) + off;
122662306a36Sopenharmony_ci		len = ((u64)clen << cluster_bits) - off;
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	off = lbo & (blocksize - 1);
123062306a36Sopenharmony_ci	if (nb) {
123162306a36Sopenharmony_ci		nb->off = off;
123262306a36Sopenharmony_ci		nb->bytes = bytes;
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	for (;;) {
123662306a36Sopenharmony_ci		u32 len32 = len >= bytes ? bytes : len;
123762306a36Sopenharmony_ci		sector_t block = lbo >> sb->s_blocksize_bits;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci		do {
124062306a36Sopenharmony_ci			u32 op = blocksize - off;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci			if (op > len32)
124362306a36Sopenharmony_ci				op = len32;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci			bh = ntfs_bread(sb, block);
124662306a36Sopenharmony_ci			if (!bh) {
124762306a36Sopenharmony_ci				err = -EIO;
124862306a36Sopenharmony_ci				goto out;
124962306a36Sopenharmony_ci			}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci			if (buf) {
125262306a36Sopenharmony_ci				memcpy(buf, bh->b_data + off, op);
125362306a36Sopenharmony_ci				buf = Add2Ptr(buf, op);
125462306a36Sopenharmony_ci			}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci			if (!nb) {
125762306a36Sopenharmony_ci				put_bh(bh);
125862306a36Sopenharmony_ci			} else if (nbh >= ARRAY_SIZE(nb->bh)) {
125962306a36Sopenharmony_ci				err = -EINVAL;
126062306a36Sopenharmony_ci				goto out;
126162306a36Sopenharmony_ci			} else {
126262306a36Sopenharmony_ci				nb->bh[nbh++] = bh;
126362306a36Sopenharmony_ci				nb->nbufs = nbh;
126462306a36Sopenharmony_ci			}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci			bytes -= op;
126762306a36Sopenharmony_ci			if (!bytes)
126862306a36Sopenharmony_ci				return 0;
126962306a36Sopenharmony_ci			len32 -= op;
127062306a36Sopenharmony_ci			block += 1;
127162306a36Sopenharmony_ci			off = 0;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci		} while (len32);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci		vcn_next = vcn + clen;
127662306a36Sopenharmony_ci		if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
127762306a36Sopenharmony_ci		    vcn != vcn_next) {
127862306a36Sopenharmony_ci			err = -ENOENT;
127962306a36Sopenharmony_ci			goto out;
128062306a36Sopenharmony_ci		}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci		if (lcn == SPARSE_LCN) {
128362306a36Sopenharmony_ci			err = -EINVAL;
128462306a36Sopenharmony_ci			goto out;
128562306a36Sopenharmony_ci		}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci		lbo = ((u64)lcn << cluster_bits);
128862306a36Sopenharmony_ci		len = ((u64)clen << cluster_bits);
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ciout:
129262306a36Sopenharmony_ci	if (!nbh)
129362306a36Sopenharmony_ci		return err;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	while (nbh) {
129662306a36Sopenharmony_ci		put_bh(nb->bh[--nbh]);
129762306a36Sopenharmony_ci		nb->bh[nbh] = NULL;
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	nb->nbufs = 0;
130162306a36Sopenharmony_ci	return err;
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci/*
130562306a36Sopenharmony_ci * ntfs_read_bh
130662306a36Sopenharmony_ci *
130762306a36Sopenharmony_ci * Return: < 0 if error, 0 if ok, -E_NTFS_FIXUP if need to update fixups.
130862306a36Sopenharmony_ci */
130962306a36Sopenharmony_ciint ntfs_read_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
131062306a36Sopenharmony_ci		 struct NTFS_RECORD_HEADER *rhdr, u32 bytes,
131162306a36Sopenharmony_ci		 struct ntfs_buffers *nb)
131262306a36Sopenharmony_ci{
131362306a36Sopenharmony_ci	int err = ntfs_read_run_nb(sbi, run, vbo, rhdr, bytes, nb);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	if (err)
131662306a36Sopenharmony_ci		return err;
131762306a36Sopenharmony_ci	return ntfs_fix_post_read(rhdr, nb->bytes, true);
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ciint ntfs_get_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
132162306a36Sopenharmony_ci		u32 bytes, struct ntfs_buffers *nb)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	int err = 0;
132462306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
132562306a36Sopenharmony_ci	u32 blocksize = sb->s_blocksize;
132662306a36Sopenharmony_ci	u8 cluster_bits = sbi->cluster_bits;
132762306a36Sopenharmony_ci	CLST vcn_next, vcn = vbo >> cluster_bits;
132862306a36Sopenharmony_ci	u32 off;
132962306a36Sopenharmony_ci	u32 nbh = 0;
133062306a36Sopenharmony_ci	CLST lcn, clen;
133162306a36Sopenharmony_ci	u64 lbo, len;
133262306a36Sopenharmony_ci	size_t idx;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	nb->bytes = bytes;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
133762306a36Sopenharmony_ci		err = -ENOENT;
133862306a36Sopenharmony_ci		goto out;
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	off = vbo & sbi->cluster_mask;
134262306a36Sopenharmony_ci	lbo = ((u64)lcn << cluster_bits) + off;
134362306a36Sopenharmony_ci	len = ((u64)clen << cluster_bits) - off;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	nb->off = off = lbo & (blocksize - 1);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	for (;;) {
134862306a36Sopenharmony_ci		u32 len32 = min_t(u64, len, bytes);
134962306a36Sopenharmony_ci		sector_t block = lbo >> sb->s_blocksize_bits;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci		do {
135262306a36Sopenharmony_ci			u32 op;
135362306a36Sopenharmony_ci			struct buffer_head *bh;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci			if (nbh >= ARRAY_SIZE(nb->bh)) {
135662306a36Sopenharmony_ci				err = -EINVAL;
135762306a36Sopenharmony_ci				goto out;
135862306a36Sopenharmony_ci			}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci			op = blocksize - off;
136162306a36Sopenharmony_ci			if (op > len32)
136262306a36Sopenharmony_ci				op = len32;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci			if (op == blocksize) {
136562306a36Sopenharmony_ci				bh = sb_getblk(sb, block);
136662306a36Sopenharmony_ci				if (!bh) {
136762306a36Sopenharmony_ci					err = -ENOMEM;
136862306a36Sopenharmony_ci					goto out;
136962306a36Sopenharmony_ci				}
137062306a36Sopenharmony_ci				if (buffer_locked(bh))
137162306a36Sopenharmony_ci					__wait_on_buffer(bh);
137262306a36Sopenharmony_ci				set_buffer_uptodate(bh);
137362306a36Sopenharmony_ci			} else {
137462306a36Sopenharmony_ci				bh = ntfs_bread(sb, block);
137562306a36Sopenharmony_ci				if (!bh) {
137662306a36Sopenharmony_ci					err = -EIO;
137762306a36Sopenharmony_ci					goto out;
137862306a36Sopenharmony_ci				}
137962306a36Sopenharmony_ci			}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci			nb->bh[nbh++] = bh;
138262306a36Sopenharmony_ci			bytes -= op;
138362306a36Sopenharmony_ci			if (!bytes) {
138462306a36Sopenharmony_ci				nb->nbufs = nbh;
138562306a36Sopenharmony_ci				return 0;
138662306a36Sopenharmony_ci			}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci			block += 1;
138962306a36Sopenharmony_ci			len32 -= op;
139062306a36Sopenharmony_ci			off = 0;
139162306a36Sopenharmony_ci		} while (len32);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci		vcn_next = vcn + clen;
139462306a36Sopenharmony_ci		if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
139562306a36Sopenharmony_ci		    vcn != vcn_next) {
139662306a36Sopenharmony_ci			err = -ENOENT;
139762306a36Sopenharmony_ci			goto out;
139862306a36Sopenharmony_ci		}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci		lbo = ((u64)lcn << cluster_bits);
140162306a36Sopenharmony_ci		len = ((u64)clen << cluster_bits);
140262306a36Sopenharmony_ci	}
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ciout:
140562306a36Sopenharmony_ci	while (nbh) {
140662306a36Sopenharmony_ci		put_bh(nb->bh[--nbh]);
140762306a36Sopenharmony_ci		nb->bh[nbh] = NULL;
140862306a36Sopenharmony_ci	}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	nb->nbufs = 0;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	return err;
141362306a36Sopenharmony_ci}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ciint ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
141662306a36Sopenharmony_ci		  struct ntfs_buffers *nb, int sync)
141762306a36Sopenharmony_ci{
141862306a36Sopenharmony_ci	int err = 0;
141962306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
142062306a36Sopenharmony_ci	u32 block_size = sb->s_blocksize;
142162306a36Sopenharmony_ci	u32 bytes = nb->bytes;
142262306a36Sopenharmony_ci	u32 off = nb->off;
142362306a36Sopenharmony_ci	u16 fo = le16_to_cpu(rhdr->fix_off);
142462306a36Sopenharmony_ci	u16 fn = le16_to_cpu(rhdr->fix_num);
142562306a36Sopenharmony_ci	u32 idx;
142662306a36Sopenharmony_ci	__le16 *fixup;
142762306a36Sopenharmony_ci	__le16 sample;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
143062306a36Sopenharmony_ci	    fn * SECTOR_SIZE > bytes) {
143162306a36Sopenharmony_ci		return -EINVAL;
143262306a36Sopenharmony_ci	}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	for (idx = 0; bytes && idx < nb->nbufs; idx += 1, off = 0) {
143562306a36Sopenharmony_ci		u32 op = block_size - off;
143662306a36Sopenharmony_ci		char *bh_data;
143762306a36Sopenharmony_ci		struct buffer_head *bh = nb->bh[idx];
143862306a36Sopenharmony_ci		__le16 *ptr, *end_data;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci		if (op > bytes)
144162306a36Sopenharmony_ci			op = bytes;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci		if (buffer_locked(bh))
144462306a36Sopenharmony_ci			__wait_on_buffer(bh);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci		lock_buffer(bh);
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci		bh_data = bh->b_data + off;
144962306a36Sopenharmony_ci		end_data = Add2Ptr(bh_data, op);
145062306a36Sopenharmony_ci		memcpy(bh_data, rhdr, op);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci		if (!idx) {
145362306a36Sopenharmony_ci			u16 t16;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci			fixup = Add2Ptr(bh_data, fo);
145662306a36Sopenharmony_ci			sample = *fixup;
145762306a36Sopenharmony_ci			t16 = le16_to_cpu(sample);
145862306a36Sopenharmony_ci			if (t16 >= 0x7FFF) {
145962306a36Sopenharmony_ci				sample = *fixup = cpu_to_le16(1);
146062306a36Sopenharmony_ci			} else {
146162306a36Sopenharmony_ci				sample = cpu_to_le16(t16 + 1);
146262306a36Sopenharmony_ci				*fixup = sample;
146362306a36Sopenharmony_ci			}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci			*(__le16 *)Add2Ptr(rhdr, fo) = sample;
146662306a36Sopenharmony_ci		}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci		ptr = Add2Ptr(bh_data, SECTOR_SIZE - sizeof(short));
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci		do {
147162306a36Sopenharmony_ci			*++fixup = *ptr;
147262306a36Sopenharmony_ci			*ptr = sample;
147362306a36Sopenharmony_ci			ptr += SECTOR_SIZE / sizeof(short);
147462306a36Sopenharmony_ci		} while (ptr < end_data);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci		set_buffer_uptodate(bh);
147762306a36Sopenharmony_ci		mark_buffer_dirty(bh);
147862306a36Sopenharmony_ci		unlock_buffer(bh);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci		if (sync) {
148162306a36Sopenharmony_ci			int err2 = sync_dirty_buffer(bh);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci			if (!err && err2)
148462306a36Sopenharmony_ci				err = err2;
148562306a36Sopenharmony_ci		}
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci		bytes -= op;
148862306a36Sopenharmony_ci		rhdr = Add2Ptr(rhdr, op);
148962306a36Sopenharmony_ci	}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	return err;
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci/*
149562306a36Sopenharmony_ci * ntfs_bio_pages - Read/write pages from/to disk.
149662306a36Sopenharmony_ci */
149762306a36Sopenharmony_ciint ntfs_bio_pages(struct ntfs_sb_info *sbi, const struct runs_tree *run,
149862306a36Sopenharmony_ci		   struct page **pages, u32 nr_pages, u64 vbo, u32 bytes,
149962306a36Sopenharmony_ci		   enum req_op op)
150062306a36Sopenharmony_ci{
150162306a36Sopenharmony_ci	int err = 0;
150262306a36Sopenharmony_ci	struct bio *new, *bio = NULL;
150362306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
150462306a36Sopenharmony_ci	struct block_device *bdev = sb->s_bdev;
150562306a36Sopenharmony_ci	struct page *page;
150662306a36Sopenharmony_ci	u8 cluster_bits = sbi->cluster_bits;
150762306a36Sopenharmony_ci	CLST lcn, clen, vcn, vcn_next;
150862306a36Sopenharmony_ci	u32 add, off, page_idx;
150962306a36Sopenharmony_ci	u64 lbo, len;
151062306a36Sopenharmony_ci	size_t run_idx;
151162306a36Sopenharmony_ci	struct blk_plug plug;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	if (!bytes)
151462306a36Sopenharmony_ci		return 0;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	blk_start_plug(&plug);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	/* Align vbo and bytes to be 512 bytes aligned. */
151962306a36Sopenharmony_ci	lbo = (vbo + bytes + 511) & ~511ull;
152062306a36Sopenharmony_ci	vbo = vbo & ~511ull;
152162306a36Sopenharmony_ci	bytes = lbo - vbo;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	vcn = vbo >> cluster_bits;
152462306a36Sopenharmony_ci	if (!run_lookup_entry(run, vcn, &lcn, &clen, &run_idx)) {
152562306a36Sopenharmony_ci		err = -ENOENT;
152662306a36Sopenharmony_ci		goto out;
152762306a36Sopenharmony_ci	}
152862306a36Sopenharmony_ci	off = vbo & sbi->cluster_mask;
152962306a36Sopenharmony_ci	page_idx = 0;
153062306a36Sopenharmony_ci	page = pages[0];
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	for (;;) {
153362306a36Sopenharmony_ci		lbo = ((u64)lcn << cluster_bits) + off;
153462306a36Sopenharmony_ci		len = ((u64)clen << cluster_bits) - off;
153562306a36Sopenharmony_cinew_bio:
153662306a36Sopenharmony_ci		new = bio_alloc(bdev, nr_pages - page_idx, op, GFP_NOFS);
153762306a36Sopenharmony_ci		if (bio) {
153862306a36Sopenharmony_ci			bio_chain(bio, new);
153962306a36Sopenharmony_ci			submit_bio(bio);
154062306a36Sopenharmony_ci		}
154162306a36Sopenharmony_ci		bio = new;
154262306a36Sopenharmony_ci		bio->bi_iter.bi_sector = lbo >> 9;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci		while (len) {
154562306a36Sopenharmony_ci			off = vbo & (PAGE_SIZE - 1);
154662306a36Sopenharmony_ci			add = off + len > PAGE_SIZE ? (PAGE_SIZE - off) : len;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci			if (bio_add_page(bio, page, add, off) < add)
154962306a36Sopenharmony_ci				goto new_bio;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci			if (bytes <= add)
155262306a36Sopenharmony_ci				goto out;
155362306a36Sopenharmony_ci			bytes -= add;
155462306a36Sopenharmony_ci			vbo += add;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci			if (add + off == PAGE_SIZE) {
155762306a36Sopenharmony_ci				page_idx += 1;
155862306a36Sopenharmony_ci				if (WARN_ON(page_idx >= nr_pages)) {
155962306a36Sopenharmony_ci					err = -EINVAL;
156062306a36Sopenharmony_ci					goto out;
156162306a36Sopenharmony_ci				}
156262306a36Sopenharmony_ci				page = pages[page_idx];
156362306a36Sopenharmony_ci			}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci			if (len <= add)
156662306a36Sopenharmony_ci				break;
156762306a36Sopenharmony_ci			len -= add;
156862306a36Sopenharmony_ci			lbo += add;
156962306a36Sopenharmony_ci		}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci		vcn_next = vcn + clen;
157262306a36Sopenharmony_ci		if (!run_get_entry(run, ++run_idx, &vcn, &lcn, &clen) ||
157362306a36Sopenharmony_ci		    vcn != vcn_next) {
157462306a36Sopenharmony_ci			err = -ENOENT;
157562306a36Sopenharmony_ci			goto out;
157662306a36Sopenharmony_ci		}
157762306a36Sopenharmony_ci		off = 0;
157862306a36Sopenharmony_ci	}
157962306a36Sopenharmony_ciout:
158062306a36Sopenharmony_ci	if (bio) {
158162306a36Sopenharmony_ci		if (!err)
158262306a36Sopenharmony_ci			err = submit_bio_wait(bio);
158362306a36Sopenharmony_ci		bio_put(bio);
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci	blk_finish_plug(&plug);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	return err;
158862306a36Sopenharmony_ci}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci/*
159162306a36Sopenharmony_ci * ntfs_bio_fill_1 - Helper for ntfs_loadlog_and_replay().
159262306a36Sopenharmony_ci *
159362306a36Sopenharmony_ci * Fill on-disk logfile range by (-1)
159462306a36Sopenharmony_ci * this means empty logfile.
159562306a36Sopenharmony_ci */
159662306a36Sopenharmony_ciint ntfs_bio_fill_1(struct ntfs_sb_info *sbi, const struct runs_tree *run)
159762306a36Sopenharmony_ci{
159862306a36Sopenharmony_ci	int err = 0;
159962306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
160062306a36Sopenharmony_ci	struct block_device *bdev = sb->s_bdev;
160162306a36Sopenharmony_ci	u8 cluster_bits = sbi->cluster_bits;
160262306a36Sopenharmony_ci	struct bio *new, *bio = NULL;
160362306a36Sopenharmony_ci	CLST lcn, clen;
160462306a36Sopenharmony_ci	u64 lbo, len;
160562306a36Sopenharmony_ci	size_t run_idx;
160662306a36Sopenharmony_ci	struct page *fill;
160762306a36Sopenharmony_ci	void *kaddr;
160862306a36Sopenharmony_ci	struct blk_plug plug;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	fill = alloc_page(GFP_KERNEL);
161162306a36Sopenharmony_ci	if (!fill)
161262306a36Sopenharmony_ci		return -ENOMEM;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	kaddr = kmap_atomic(fill);
161562306a36Sopenharmony_ci	memset(kaddr, -1, PAGE_SIZE);
161662306a36Sopenharmony_ci	kunmap_atomic(kaddr);
161762306a36Sopenharmony_ci	flush_dcache_page(fill);
161862306a36Sopenharmony_ci	lock_page(fill);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (!run_lookup_entry(run, 0, &lcn, &clen, &run_idx)) {
162162306a36Sopenharmony_ci		err = -ENOENT;
162262306a36Sopenharmony_ci		goto out;
162362306a36Sopenharmony_ci	}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	/*
162662306a36Sopenharmony_ci	 * TODO: Try blkdev_issue_write_same.
162762306a36Sopenharmony_ci	 */
162862306a36Sopenharmony_ci	blk_start_plug(&plug);
162962306a36Sopenharmony_ci	do {
163062306a36Sopenharmony_ci		lbo = (u64)lcn << cluster_bits;
163162306a36Sopenharmony_ci		len = (u64)clen << cluster_bits;
163262306a36Sopenharmony_cinew_bio:
163362306a36Sopenharmony_ci		new = bio_alloc(bdev, BIO_MAX_VECS, REQ_OP_WRITE, GFP_NOFS);
163462306a36Sopenharmony_ci		if (bio) {
163562306a36Sopenharmony_ci			bio_chain(bio, new);
163662306a36Sopenharmony_ci			submit_bio(bio);
163762306a36Sopenharmony_ci		}
163862306a36Sopenharmony_ci		bio = new;
163962306a36Sopenharmony_ci		bio->bi_iter.bi_sector = lbo >> 9;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci		for (;;) {
164262306a36Sopenharmony_ci			u32 add = len > PAGE_SIZE ? PAGE_SIZE : len;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci			if (bio_add_page(bio, fill, add, 0) < add)
164562306a36Sopenharmony_ci				goto new_bio;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci			lbo += add;
164862306a36Sopenharmony_ci			if (len <= add)
164962306a36Sopenharmony_ci				break;
165062306a36Sopenharmony_ci			len -= add;
165162306a36Sopenharmony_ci		}
165262306a36Sopenharmony_ci	} while (run_get_entry(run, ++run_idx, NULL, &lcn, &clen));
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	if (!err)
165562306a36Sopenharmony_ci		err = submit_bio_wait(bio);
165662306a36Sopenharmony_ci	bio_put(bio);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	blk_finish_plug(&plug);
165962306a36Sopenharmony_ciout:
166062306a36Sopenharmony_ci	unlock_page(fill);
166162306a36Sopenharmony_ci	put_page(fill);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	return err;
166462306a36Sopenharmony_ci}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ciint ntfs_vbo_to_lbo(struct ntfs_sb_info *sbi, const struct runs_tree *run,
166762306a36Sopenharmony_ci		    u64 vbo, u64 *lbo, u64 *bytes)
166862306a36Sopenharmony_ci{
166962306a36Sopenharmony_ci	u32 off;
167062306a36Sopenharmony_ci	CLST lcn, len;
167162306a36Sopenharmony_ci	u8 cluster_bits = sbi->cluster_bits;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	if (!run_lookup_entry(run, vbo >> cluster_bits, &lcn, &len, NULL))
167462306a36Sopenharmony_ci		return -ENOENT;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	off = vbo & sbi->cluster_mask;
167762306a36Sopenharmony_ci	*lbo = lcn == SPARSE_LCN ? -1 : (((u64)lcn << cluster_bits) + off);
167862306a36Sopenharmony_ci	*bytes = ((u64)len << cluster_bits) - off;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	return 0;
168162306a36Sopenharmony_ci}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_cistruct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno,
168462306a36Sopenharmony_ci				  enum RECORD_FLAG flag)
168562306a36Sopenharmony_ci{
168662306a36Sopenharmony_ci	int err = 0;
168762306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
168862306a36Sopenharmony_ci	struct inode *inode = new_inode(sb);
168962306a36Sopenharmony_ci	struct ntfs_inode *ni;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	if (!inode)
169262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	ni = ntfs_i(inode);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	err = mi_format_new(&ni->mi, sbi, rno, flag, false);
169762306a36Sopenharmony_ci	if (err)
169862306a36Sopenharmony_ci		goto out;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	inode->i_ino = rno;
170162306a36Sopenharmony_ci	if (insert_inode_locked(inode) < 0) {
170262306a36Sopenharmony_ci		err = -EIO;
170362306a36Sopenharmony_ci		goto out;
170462306a36Sopenharmony_ci	}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ciout:
170762306a36Sopenharmony_ci	if (err) {
170862306a36Sopenharmony_ci		make_bad_inode(inode);
170962306a36Sopenharmony_ci		iput(inode);
171062306a36Sopenharmony_ci		ni = ERR_PTR(err);
171162306a36Sopenharmony_ci	}
171262306a36Sopenharmony_ci	return ni;
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci/*
171662306a36Sopenharmony_ci * O:BAG:BAD:(A;OICI;FA;;;WD)
171762306a36Sopenharmony_ci * Owner S-1-5-32-544 (Administrators)
171862306a36Sopenharmony_ci * Group S-1-5-32-544 (Administrators)
171962306a36Sopenharmony_ci * ACE: allow S-1-1-0 (Everyone) with FILE_ALL_ACCESS
172062306a36Sopenharmony_ci */
172162306a36Sopenharmony_ciconst u8 s_default_security[] __aligned(8) = {
172262306a36Sopenharmony_ci	0x01, 0x00, 0x04, 0x80, 0x30, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
172362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1C, 0x00,
172462306a36Sopenharmony_ci	0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x00, 0xFF, 0x01, 0x1F, 0x00,
172562306a36Sopenharmony_ci	0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
172662306a36Sopenharmony_ci	0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
172762306a36Sopenharmony_ci	0x20, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
172862306a36Sopenharmony_ci	0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00,
172962306a36Sopenharmony_ci};
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_cistatic_assert(sizeof(s_default_security) == 0x50);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_cistatic inline u32 sid_length(const struct SID *sid)
173462306a36Sopenharmony_ci{
173562306a36Sopenharmony_ci	return struct_size(sid, SubAuthority, sid->SubAuthorityCount);
173662306a36Sopenharmony_ci}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci/*
173962306a36Sopenharmony_ci * is_acl_valid
174062306a36Sopenharmony_ci *
174162306a36Sopenharmony_ci * Thanks Mark Harmstone for idea.
174262306a36Sopenharmony_ci */
174362306a36Sopenharmony_cistatic bool is_acl_valid(const struct ACL *acl, u32 len)
174462306a36Sopenharmony_ci{
174562306a36Sopenharmony_ci	const struct ACE_HEADER *ace;
174662306a36Sopenharmony_ci	u32 i;
174762306a36Sopenharmony_ci	u16 ace_count, ace_size;
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	if (acl->AclRevision != ACL_REVISION &&
175062306a36Sopenharmony_ci	    acl->AclRevision != ACL_REVISION_DS) {
175162306a36Sopenharmony_ci		/*
175262306a36Sopenharmony_ci		 * This value should be ACL_REVISION, unless the ACL contains an
175362306a36Sopenharmony_ci		 * object-specific ACE, in which case this value must be ACL_REVISION_DS.
175462306a36Sopenharmony_ci		 * All ACEs in an ACL must be at the same revision level.
175562306a36Sopenharmony_ci		 */
175662306a36Sopenharmony_ci		return false;
175762306a36Sopenharmony_ci	}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	if (acl->Sbz1)
176062306a36Sopenharmony_ci		return false;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	if (le16_to_cpu(acl->AclSize) > len)
176362306a36Sopenharmony_ci		return false;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	if (acl->Sbz2)
176662306a36Sopenharmony_ci		return false;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	len -= sizeof(struct ACL);
176962306a36Sopenharmony_ci	ace = (struct ACE_HEADER *)&acl[1];
177062306a36Sopenharmony_ci	ace_count = le16_to_cpu(acl->AceCount);
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	for (i = 0; i < ace_count; i++) {
177362306a36Sopenharmony_ci		if (len < sizeof(struct ACE_HEADER))
177462306a36Sopenharmony_ci			return false;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci		ace_size = le16_to_cpu(ace->AceSize);
177762306a36Sopenharmony_ci		if (len < ace_size)
177862306a36Sopenharmony_ci			return false;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci		len -= ace_size;
178162306a36Sopenharmony_ci		ace = Add2Ptr(ace, ace_size);
178262306a36Sopenharmony_ci	}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	return true;
178562306a36Sopenharmony_ci}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_cibool is_sd_valid(const struct SECURITY_DESCRIPTOR_RELATIVE *sd, u32 len)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	u32 sd_owner, sd_group, sd_sacl, sd_dacl;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	if (len < sizeof(struct SECURITY_DESCRIPTOR_RELATIVE))
179262306a36Sopenharmony_ci		return false;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	if (sd->Revision != 1)
179562306a36Sopenharmony_ci		return false;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	if (sd->Sbz1)
179862306a36Sopenharmony_ci		return false;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	if (!(sd->Control & SE_SELF_RELATIVE))
180162306a36Sopenharmony_ci		return false;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	sd_owner = le32_to_cpu(sd->Owner);
180462306a36Sopenharmony_ci	if (sd_owner) {
180562306a36Sopenharmony_ci		const struct SID *owner = Add2Ptr(sd, sd_owner);
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci		if (sd_owner + offsetof(struct SID, SubAuthority) > len)
180862306a36Sopenharmony_ci			return false;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci		if (owner->Revision != 1)
181162306a36Sopenharmony_ci			return false;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci		if (sd_owner + sid_length(owner) > len)
181462306a36Sopenharmony_ci			return false;
181562306a36Sopenharmony_ci	}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	sd_group = le32_to_cpu(sd->Group);
181862306a36Sopenharmony_ci	if (sd_group) {
181962306a36Sopenharmony_ci		const struct SID *group = Add2Ptr(sd, sd_group);
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci		if (sd_group + offsetof(struct SID, SubAuthority) > len)
182262306a36Sopenharmony_ci			return false;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci		if (group->Revision != 1)
182562306a36Sopenharmony_ci			return false;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci		if (sd_group + sid_length(group) > len)
182862306a36Sopenharmony_ci			return false;
182962306a36Sopenharmony_ci	}
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	sd_sacl = le32_to_cpu(sd->Sacl);
183262306a36Sopenharmony_ci	if (sd_sacl) {
183362306a36Sopenharmony_ci		const struct ACL *sacl = Add2Ptr(sd, sd_sacl);
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci		if (sd_sacl + sizeof(struct ACL) > len)
183662306a36Sopenharmony_ci			return false;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci		if (!is_acl_valid(sacl, len - sd_sacl))
183962306a36Sopenharmony_ci			return false;
184062306a36Sopenharmony_ci	}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	sd_dacl = le32_to_cpu(sd->Dacl);
184362306a36Sopenharmony_ci	if (sd_dacl) {
184462306a36Sopenharmony_ci		const struct ACL *dacl = Add2Ptr(sd, sd_dacl);
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci		if (sd_dacl + sizeof(struct ACL) > len)
184762306a36Sopenharmony_ci			return false;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci		if (!is_acl_valid(dacl, len - sd_dacl))
185062306a36Sopenharmony_ci			return false;
185162306a36Sopenharmony_ci	}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	return true;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci/*
185762306a36Sopenharmony_ci * ntfs_security_init - Load and parse $Secure.
185862306a36Sopenharmony_ci */
185962306a36Sopenharmony_ciint ntfs_security_init(struct ntfs_sb_info *sbi)
186062306a36Sopenharmony_ci{
186162306a36Sopenharmony_ci	int err;
186262306a36Sopenharmony_ci	struct super_block *sb = sbi->sb;
186362306a36Sopenharmony_ci	struct inode *inode;
186462306a36Sopenharmony_ci	struct ntfs_inode *ni;
186562306a36Sopenharmony_ci	struct MFT_REF ref;
186662306a36Sopenharmony_ci	struct ATTRIB *attr;
186762306a36Sopenharmony_ci	struct ATTR_LIST_ENTRY *le;
186862306a36Sopenharmony_ci	u64 sds_size;
186962306a36Sopenharmony_ci	size_t off;
187062306a36Sopenharmony_ci	struct NTFS_DE *ne;
187162306a36Sopenharmony_ci	struct NTFS_DE_SII *sii_e;
187262306a36Sopenharmony_ci	struct ntfs_fnd *fnd_sii = NULL;
187362306a36Sopenharmony_ci	const struct INDEX_ROOT *root_sii;
187462306a36Sopenharmony_ci	const struct INDEX_ROOT *root_sdh;
187562306a36Sopenharmony_ci	struct ntfs_index *indx_sdh = &sbi->security.index_sdh;
187662306a36Sopenharmony_ci	struct ntfs_index *indx_sii = &sbi->security.index_sii;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	ref.low = cpu_to_le32(MFT_REC_SECURE);
187962306a36Sopenharmony_ci	ref.high = 0;
188062306a36Sopenharmony_ci	ref.seq = cpu_to_le16(MFT_REC_SECURE);
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	inode = ntfs_iget5(sb, &ref, &NAME_SECURE);
188362306a36Sopenharmony_ci	if (IS_ERR(inode)) {
188462306a36Sopenharmony_ci		err = PTR_ERR(inode);
188562306a36Sopenharmony_ci		ntfs_err(sb, "Failed to load $Secure (%d).", err);
188662306a36Sopenharmony_ci		inode = NULL;
188762306a36Sopenharmony_ci		goto out;
188862306a36Sopenharmony_ci	}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	ni = ntfs_i(inode);
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	le = NULL;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SDH_NAME,
189562306a36Sopenharmony_ci			    ARRAY_SIZE(SDH_NAME), NULL, NULL);
189662306a36Sopenharmony_ci	if (!attr ||
189762306a36Sopenharmony_ci	    !(root_sdh = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) ||
189862306a36Sopenharmony_ci	    root_sdh->type != ATTR_ZERO ||
189962306a36Sopenharmony_ci	    root_sdh->rule != NTFS_COLLATION_TYPE_SECURITY_HASH ||
190062306a36Sopenharmony_ci	    offsetof(struct INDEX_ROOT, ihdr) +
190162306a36Sopenharmony_ci			    le32_to_cpu(root_sdh->ihdr.used) >
190262306a36Sopenharmony_ci		    le32_to_cpu(attr->res.data_size)) {
190362306a36Sopenharmony_ci		ntfs_err(sb, "$Secure::$SDH is corrupted.");
190462306a36Sopenharmony_ci		err = -EINVAL;
190562306a36Sopenharmony_ci		goto out;
190662306a36Sopenharmony_ci	}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	err = indx_init(indx_sdh, sbi, attr, INDEX_MUTEX_SDH);
190962306a36Sopenharmony_ci	if (err) {
191062306a36Sopenharmony_ci		ntfs_err(sb, "Failed to initialize $Secure::$SDH (%d).", err);
191162306a36Sopenharmony_ci		goto out;
191262306a36Sopenharmony_ci	}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	attr = ni_find_attr(ni, attr, &le, ATTR_ROOT, SII_NAME,
191562306a36Sopenharmony_ci			    ARRAY_SIZE(SII_NAME), NULL, NULL);
191662306a36Sopenharmony_ci	if (!attr ||
191762306a36Sopenharmony_ci	    !(root_sii = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) ||
191862306a36Sopenharmony_ci	    root_sii->type != ATTR_ZERO ||
191962306a36Sopenharmony_ci	    root_sii->rule != NTFS_COLLATION_TYPE_UINT ||
192062306a36Sopenharmony_ci	    offsetof(struct INDEX_ROOT, ihdr) +
192162306a36Sopenharmony_ci			    le32_to_cpu(root_sii->ihdr.used) >
192262306a36Sopenharmony_ci		    le32_to_cpu(attr->res.data_size)) {
192362306a36Sopenharmony_ci		ntfs_err(sb, "$Secure::$SII is corrupted.");
192462306a36Sopenharmony_ci		err = -EINVAL;
192562306a36Sopenharmony_ci		goto out;
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	err = indx_init(indx_sii, sbi, attr, INDEX_MUTEX_SII);
192962306a36Sopenharmony_ci	if (err) {
193062306a36Sopenharmony_ci		ntfs_err(sb, "Failed to initialize $Secure::$SII (%d).", err);
193162306a36Sopenharmony_ci		goto out;
193262306a36Sopenharmony_ci	}
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	fnd_sii = fnd_get();
193562306a36Sopenharmony_ci	if (!fnd_sii) {
193662306a36Sopenharmony_ci		err = -ENOMEM;
193762306a36Sopenharmony_ci		goto out;
193862306a36Sopenharmony_ci	}
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	sds_size = inode->i_size;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	/* Find the last valid Id. */
194362306a36Sopenharmony_ci	sbi->security.next_id = SECURITY_ID_FIRST;
194462306a36Sopenharmony_ci	/* Always write new security at the end of bucket. */
194562306a36Sopenharmony_ci	sbi->security.next_off =
194662306a36Sopenharmony_ci		ALIGN(sds_size - SecurityDescriptorsBlockSize, 16);
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	off = 0;
194962306a36Sopenharmony_ci	ne = NULL;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	for (;;) {
195262306a36Sopenharmony_ci		u32 next_id;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci		err = indx_find_raw(indx_sii, ni, root_sii, &ne, &off, fnd_sii);
195562306a36Sopenharmony_ci		if (err || !ne)
195662306a36Sopenharmony_ci			break;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci		sii_e = (struct NTFS_DE_SII *)ne;
195962306a36Sopenharmony_ci		if (le16_to_cpu(ne->view.data_size) < sizeof(sii_e->sec_hdr))
196062306a36Sopenharmony_ci			continue;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci		next_id = le32_to_cpu(sii_e->sec_id) + 1;
196362306a36Sopenharmony_ci		if (next_id >= sbi->security.next_id)
196462306a36Sopenharmony_ci			sbi->security.next_id = next_id;
196562306a36Sopenharmony_ci	}
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	sbi->security.ni = ni;
196862306a36Sopenharmony_ci	inode = NULL;
196962306a36Sopenharmony_ciout:
197062306a36Sopenharmony_ci	iput(inode);
197162306a36Sopenharmony_ci	fnd_put(fnd_sii);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	return err;
197462306a36Sopenharmony_ci}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci/*
197762306a36Sopenharmony_ci * ntfs_get_security_by_id - Read security descriptor by id.
197862306a36Sopenharmony_ci */
197962306a36Sopenharmony_ciint ntfs_get_security_by_id(struct ntfs_sb_info *sbi, __le32 security_id,
198062306a36Sopenharmony_ci			    struct SECURITY_DESCRIPTOR_RELATIVE **sd,
198162306a36Sopenharmony_ci			    size_t *size)
198262306a36Sopenharmony_ci{
198362306a36Sopenharmony_ci	int err;
198462306a36Sopenharmony_ci	int diff;
198562306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->security.ni;
198662306a36Sopenharmony_ci	struct ntfs_index *indx = &sbi->security.index_sii;
198762306a36Sopenharmony_ci	void *p = NULL;
198862306a36Sopenharmony_ci	struct NTFS_DE_SII *sii_e;
198962306a36Sopenharmony_ci	struct ntfs_fnd *fnd_sii;
199062306a36Sopenharmony_ci	struct SECURITY_HDR d_security;
199162306a36Sopenharmony_ci	const struct INDEX_ROOT *root_sii;
199262306a36Sopenharmony_ci	u32 t32;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	*sd = NULL;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_SECURITY);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	fnd_sii = fnd_get();
199962306a36Sopenharmony_ci	if (!fnd_sii) {
200062306a36Sopenharmony_ci		err = -ENOMEM;
200162306a36Sopenharmony_ci		goto out;
200262306a36Sopenharmony_ci	}
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	root_sii = indx_get_root(indx, ni, NULL, NULL);
200562306a36Sopenharmony_ci	if (!root_sii) {
200662306a36Sopenharmony_ci		err = -EINVAL;
200762306a36Sopenharmony_ci		goto out;
200862306a36Sopenharmony_ci	}
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	/* Try to find this SECURITY descriptor in SII indexes. */
201162306a36Sopenharmony_ci	err = indx_find(indx, ni, root_sii, &security_id, sizeof(security_id),
201262306a36Sopenharmony_ci			NULL, &diff, (struct NTFS_DE **)&sii_e, fnd_sii);
201362306a36Sopenharmony_ci	if (err)
201462306a36Sopenharmony_ci		goto out;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	if (diff)
201762306a36Sopenharmony_ci		goto out;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	t32 = le32_to_cpu(sii_e->sec_hdr.size);
202062306a36Sopenharmony_ci	if (t32 < sizeof(struct SECURITY_HDR)) {
202162306a36Sopenharmony_ci		err = -EINVAL;
202262306a36Sopenharmony_ci		goto out;
202362306a36Sopenharmony_ci	}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	if (t32 > sizeof(struct SECURITY_HDR) + 0x10000) {
202662306a36Sopenharmony_ci		/* Looks like too big security. 0x10000 - is arbitrary big number. */
202762306a36Sopenharmony_ci		err = -EFBIG;
202862306a36Sopenharmony_ci		goto out;
202962306a36Sopenharmony_ci	}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	*size = t32 - sizeof(struct SECURITY_HDR);
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	p = kmalloc(*size, GFP_NOFS);
203462306a36Sopenharmony_ci	if (!p) {
203562306a36Sopenharmony_ci		err = -ENOMEM;
203662306a36Sopenharmony_ci		goto out;
203762306a36Sopenharmony_ci	}
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	err = ntfs_read_run_nb(sbi, &ni->file.run,
204062306a36Sopenharmony_ci			       le64_to_cpu(sii_e->sec_hdr.off), &d_security,
204162306a36Sopenharmony_ci			       sizeof(d_security), NULL);
204262306a36Sopenharmony_ci	if (err)
204362306a36Sopenharmony_ci		goto out;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	if (memcmp(&d_security, &sii_e->sec_hdr, sizeof(d_security))) {
204662306a36Sopenharmony_ci		err = -EINVAL;
204762306a36Sopenharmony_ci		goto out;
204862306a36Sopenharmony_ci	}
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	err = ntfs_read_run_nb(sbi, &ni->file.run,
205162306a36Sopenharmony_ci			       le64_to_cpu(sii_e->sec_hdr.off) +
205262306a36Sopenharmony_ci				       sizeof(struct SECURITY_HDR),
205362306a36Sopenharmony_ci			       p, *size, NULL);
205462306a36Sopenharmony_ci	if (err)
205562306a36Sopenharmony_ci		goto out;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	*sd = p;
205862306a36Sopenharmony_ci	p = NULL;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ciout:
206162306a36Sopenharmony_ci	kfree(p);
206262306a36Sopenharmony_ci	fnd_put(fnd_sii);
206362306a36Sopenharmony_ci	ni_unlock(ni);
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	return err;
206662306a36Sopenharmony_ci}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci/*
206962306a36Sopenharmony_ci * ntfs_insert_security - Insert security descriptor into $Secure::SDS.
207062306a36Sopenharmony_ci *
207162306a36Sopenharmony_ci * SECURITY Descriptor Stream data is organized into chunks of 256K bytes
207262306a36Sopenharmony_ci * and it contains a mirror copy of each security descriptor.  When writing
207362306a36Sopenharmony_ci * to a security descriptor at location X, another copy will be written at
207462306a36Sopenharmony_ci * location (X+256K).
207562306a36Sopenharmony_ci * When writing a security descriptor that will cross the 256K boundary,
207662306a36Sopenharmony_ci * the pointer will be advanced by 256K to skip
207762306a36Sopenharmony_ci * over the mirror portion.
207862306a36Sopenharmony_ci */
207962306a36Sopenharmony_ciint ntfs_insert_security(struct ntfs_sb_info *sbi,
208062306a36Sopenharmony_ci			 const struct SECURITY_DESCRIPTOR_RELATIVE *sd,
208162306a36Sopenharmony_ci			 u32 size_sd, __le32 *security_id, bool *inserted)
208262306a36Sopenharmony_ci{
208362306a36Sopenharmony_ci	int err, diff;
208462306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->security.ni;
208562306a36Sopenharmony_ci	struct ntfs_index *indx_sdh = &sbi->security.index_sdh;
208662306a36Sopenharmony_ci	struct ntfs_index *indx_sii = &sbi->security.index_sii;
208762306a36Sopenharmony_ci	struct NTFS_DE_SDH *e;
208862306a36Sopenharmony_ci	struct NTFS_DE_SDH sdh_e;
208962306a36Sopenharmony_ci	struct NTFS_DE_SII sii_e;
209062306a36Sopenharmony_ci	struct SECURITY_HDR *d_security;
209162306a36Sopenharmony_ci	u32 new_sec_size = size_sd + sizeof(struct SECURITY_HDR);
209262306a36Sopenharmony_ci	u32 aligned_sec_size = ALIGN(new_sec_size, 16);
209362306a36Sopenharmony_ci	struct SECURITY_KEY hash_key;
209462306a36Sopenharmony_ci	struct ntfs_fnd *fnd_sdh = NULL;
209562306a36Sopenharmony_ci	const struct INDEX_ROOT *root_sdh;
209662306a36Sopenharmony_ci	const struct INDEX_ROOT *root_sii;
209762306a36Sopenharmony_ci	u64 mirr_off, new_sds_size;
209862306a36Sopenharmony_ci	u32 next, left;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	static_assert((1 << Log2OfSecurityDescriptorsBlockSize) ==
210162306a36Sopenharmony_ci		      SecurityDescriptorsBlockSize);
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	hash_key.hash = security_hash(sd, size_sd);
210462306a36Sopenharmony_ci	hash_key.sec_id = SECURITY_ID_INVALID;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	if (inserted)
210762306a36Sopenharmony_ci		*inserted = false;
210862306a36Sopenharmony_ci	*security_id = SECURITY_ID_INVALID;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	/* Allocate a temporal buffer. */
211162306a36Sopenharmony_ci	d_security = kzalloc(aligned_sec_size, GFP_NOFS);
211262306a36Sopenharmony_ci	if (!d_security)
211362306a36Sopenharmony_ci		return -ENOMEM;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_SECURITY);
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	fnd_sdh = fnd_get();
211862306a36Sopenharmony_ci	if (!fnd_sdh) {
211962306a36Sopenharmony_ci		err = -ENOMEM;
212062306a36Sopenharmony_ci		goto out;
212162306a36Sopenharmony_ci	}
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	root_sdh = indx_get_root(indx_sdh, ni, NULL, NULL);
212462306a36Sopenharmony_ci	if (!root_sdh) {
212562306a36Sopenharmony_ci		err = -EINVAL;
212662306a36Sopenharmony_ci		goto out;
212762306a36Sopenharmony_ci	}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	root_sii = indx_get_root(indx_sii, ni, NULL, NULL);
213062306a36Sopenharmony_ci	if (!root_sii) {
213162306a36Sopenharmony_ci		err = -EINVAL;
213262306a36Sopenharmony_ci		goto out;
213362306a36Sopenharmony_ci	}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	/*
213662306a36Sopenharmony_ci	 * Check if such security already exists.
213762306a36Sopenharmony_ci	 * Use "SDH" and hash -> to get the offset in "SDS".
213862306a36Sopenharmony_ci	 */
213962306a36Sopenharmony_ci	err = indx_find(indx_sdh, ni, root_sdh, &hash_key, sizeof(hash_key),
214062306a36Sopenharmony_ci			&d_security->key.sec_id, &diff, (struct NTFS_DE **)&e,
214162306a36Sopenharmony_ci			fnd_sdh);
214262306a36Sopenharmony_ci	if (err)
214362306a36Sopenharmony_ci		goto out;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	while (e) {
214662306a36Sopenharmony_ci		if (le32_to_cpu(e->sec_hdr.size) == new_sec_size) {
214762306a36Sopenharmony_ci			err = ntfs_read_run_nb(sbi, &ni->file.run,
214862306a36Sopenharmony_ci					       le64_to_cpu(e->sec_hdr.off),
214962306a36Sopenharmony_ci					       d_security, new_sec_size, NULL);
215062306a36Sopenharmony_ci			if (err)
215162306a36Sopenharmony_ci				goto out;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci			if (le32_to_cpu(d_security->size) == new_sec_size &&
215462306a36Sopenharmony_ci			    d_security->key.hash == hash_key.hash &&
215562306a36Sopenharmony_ci			    !memcmp(d_security + 1, sd, size_sd)) {
215662306a36Sopenharmony_ci				*security_id = d_security->key.sec_id;
215762306a36Sopenharmony_ci				/* Such security already exists. */
215862306a36Sopenharmony_ci				err = 0;
215962306a36Sopenharmony_ci				goto out;
216062306a36Sopenharmony_ci			}
216162306a36Sopenharmony_ci		}
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci		err = indx_find_sort(indx_sdh, ni, root_sdh,
216462306a36Sopenharmony_ci				     (struct NTFS_DE **)&e, fnd_sdh);
216562306a36Sopenharmony_ci		if (err)
216662306a36Sopenharmony_ci			goto out;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci		if (!e || e->key.hash != hash_key.hash)
216962306a36Sopenharmony_ci			break;
217062306a36Sopenharmony_ci	}
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	/* Zero unused space. */
217362306a36Sopenharmony_ci	next = sbi->security.next_off & (SecurityDescriptorsBlockSize - 1);
217462306a36Sopenharmony_ci	left = SecurityDescriptorsBlockSize - next;
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	/* Zero gap until SecurityDescriptorsBlockSize. */
217762306a36Sopenharmony_ci	if (left < new_sec_size) {
217862306a36Sopenharmony_ci		/* Zero "left" bytes from sbi->security.next_off. */
217962306a36Sopenharmony_ci		sbi->security.next_off += SecurityDescriptorsBlockSize + left;
218062306a36Sopenharmony_ci	}
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	/* Zero tail of previous security. */
218362306a36Sopenharmony_ci	//used = ni->vfs_inode.i_size & (SecurityDescriptorsBlockSize - 1);
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	/*
218662306a36Sopenharmony_ci	 * Example:
218762306a36Sopenharmony_ci	 * 0x40438 == ni->vfs_inode.i_size
218862306a36Sopenharmony_ci	 * 0x00440 == sbi->security.next_off
218962306a36Sopenharmony_ci	 * need to zero [0x438-0x440)
219062306a36Sopenharmony_ci	 * if (next > used) {
219162306a36Sopenharmony_ci	 *  u32 tozero = next - used;
219262306a36Sopenharmony_ci	 *  zero "tozero" bytes from sbi->security.next_off - tozero
219362306a36Sopenharmony_ci	 */
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci	/* Format new security descriptor. */
219662306a36Sopenharmony_ci	d_security->key.hash = hash_key.hash;
219762306a36Sopenharmony_ci	d_security->key.sec_id = cpu_to_le32(sbi->security.next_id);
219862306a36Sopenharmony_ci	d_security->off = cpu_to_le64(sbi->security.next_off);
219962306a36Sopenharmony_ci	d_security->size = cpu_to_le32(new_sec_size);
220062306a36Sopenharmony_ci	memcpy(d_security + 1, sd, size_sd);
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	/* Write main SDS bucket. */
220362306a36Sopenharmony_ci	err = ntfs_sb_write_run(sbi, &ni->file.run, sbi->security.next_off,
220462306a36Sopenharmony_ci				d_security, aligned_sec_size, 0);
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	if (err)
220762306a36Sopenharmony_ci		goto out;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	mirr_off = sbi->security.next_off + SecurityDescriptorsBlockSize;
221062306a36Sopenharmony_ci	new_sds_size = mirr_off + aligned_sec_size;
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	if (new_sds_size > ni->vfs_inode.i_size) {
221362306a36Sopenharmony_ci		err = attr_set_size(ni, ATTR_DATA, SDS_NAME,
221462306a36Sopenharmony_ci				    ARRAY_SIZE(SDS_NAME), &ni->file.run,
221562306a36Sopenharmony_ci				    new_sds_size, &new_sds_size, false, NULL);
221662306a36Sopenharmony_ci		if (err)
221762306a36Sopenharmony_ci			goto out;
221862306a36Sopenharmony_ci	}
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	/* Write copy SDS bucket. */
222162306a36Sopenharmony_ci	err = ntfs_sb_write_run(sbi, &ni->file.run, mirr_off, d_security,
222262306a36Sopenharmony_ci				aligned_sec_size, 0);
222362306a36Sopenharmony_ci	if (err)
222462306a36Sopenharmony_ci		goto out;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	/* Fill SII entry. */
222762306a36Sopenharmony_ci	sii_e.de.view.data_off =
222862306a36Sopenharmony_ci		cpu_to_le16(offsetof(struct NTFS_DE_SII, sec_hdr));
222962306a36Sopenharmony_ci	sii_e.de.view.data_size = cpu_to_le16(sizeof(struct SECURITY_HDR));
223062306a36Sopenharmony_ci	sii_e.de.view.res = 0;
223162306a36Sopenharmony_ci	sii_e.de.size = cpu_to_le16(sizeof(struct NTFS_DE_SII));
223262306a36Sopenharmony_ci	sii_e.de.key_size = cpu_to_le16(sizeof(d_security->key.sec_id));
223362306a36Sopenharmony_ci	sii_e.de.flags = 0;
223462306a36Sopenharmony_ci	sii_e.de.res = 0;
223562306a36Sopenharmony_ci	sii_e.sec_id = d_security->key.sec_id;
223662306a36Sopenharmony_ci	memcpy(&sii_e.sec_hdr, d_security, sizeof(struct SECURITY_HDR));
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL, 0);
223962306a36Sopenharmony_ci	if (err)
224062306a36Sopenharmony_ci		goto out;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	/* Fill SDH entry. */
224362306a36Sopenharmony_ci	sdh_e.de.view.data_off =
224462306a36Sopenharmony_ci		cpu_to_le16(offsetof(struct NTFS_DE_SDH, sec_hdr));
224562306a36Sopenharmony_ci	sdh_e.de.view.data_size = cpu_to_le16(sizeof(struct SECURITY_HDR));
224662306a36Sopenharmony_ci	sdh_e.de.view.res = 0;
224762306a36Sopenharmony_ci	sdh_e.de.size = cpu_to_le16(SIZEOF_SDH_DIRENTRY);
224862306a36Sopenharmony_ci	sdh_e.de.key_size = cpu_to_le16(sizeof(sdh_e.key));
224962306a36Sopenharmony_ci	sdh_e.de.flags = 0;
225062306a36Sopenharmony_ci	sdh_e.de.res = 0;
225162306a36Sopenharmony_ci	sdh_e.key.hash = d_security->key.hash;
225262306a36Sopenharmony_ci	sdh_e.key.sec_id = d_security->key.sec_id;
225362306a36Sopenharmony_ci	memcpy(&sdh_e.sec_hdr, d_security, sizeof(struct SECURITY_HDR));
225462306a36Sopenharmony_ci	sdh_e.magic[0] = cpu_to_le16('I');
225562306a36Sopenharmony_ci	sdh_e.magic[1] = cpu_to_le16('I');
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	fnd_clear(fnd_sdh);
225862306a36Sopenharmony_ci	err = indx_insert_entry(indx_sdh, ni, &sdh_e.de, (void *)(size_t)1,
225962306a36Sopenharmony_ci				fnd_sdh, 0);
226062306a36Sopenharmony_ci	if (err)
226162306a36Sopenharmony_ci		goto out;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	*security_id = d_security->key.sec_id;
226462306a36Sopenharmony_ci	if (inserted)
226562306a36Sopenharmony_ci		*inserted = true;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	/* Update Id and offset for next descriptor. */
226862306a36Sopenharmony_ci	sbi->security.next_id += 1;
226962306a36Sopenharmony_ci	sbi->security.next_off += aligned_sec_size;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ciout:
227262306a36Sopenharmony_ci	fnd_put(fnd_sdh);
227362306a36Sopenharmony_ci	mark_inode_dirty(&ni->vfs_inode);
227462306a36Sopenharmony_ci	ni_unlock(ni);
227562306a36Sopenharmony_ci	kfree(d_security);
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	return err;
227862306a36Sopenharmony_ci}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci/*
228162306a36Sopenharmony_ci * ntfs_reparse_init - Load and parse $Extend/$Reparse.
228262306a36Sopenharmony_ci */
228362306a36Sopenharmony_ciint ntfs_reparse_init(struct ntfs_sb_info *sbi)
228462306a36Sopenharmony_ci{
228562306a36Sopenharmony_ci	int err;
228662306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->reparse.ni;
228762306a36Sopenharmony_ci	struct ntfs_index *indx = &sbi->reparse.index_r;
228862306a36Sopenharmony_ci	struct ATTRIB *attr;
228962306a36Sopenharmony_ci	struct ATTR_LIST_ENTRY *le;
229062306a36Sopenharmony_ci	const struct INDEX_ROOT *root_r;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	if (!ni)
229362306a36Sopenharmony_ci		return 0;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	le = NULL;
229662306a36Sopenharmony_ci	attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SR_NAME,
229762306a36Sopenharmony_ci			    ARRAY_SIZE(SR_NAME), NULL, NULL);
229862306a36Sopenharmony_ci	if (!attr) {
229962306a36Sopenharmony_ci		err = -EINVAL;
230062306a36Sopenharmony_ci		goto out;
230162306a36Sopenharmony_ci	}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	root_r = resident_data(attr);
230462306a36Sopenharmony_ci	if (root_r->type != ATTR_ZERO ||
230562306a36Sopenharmony_ci	    root_r->rule != NTFS_COLLATION_TYPE_UINTS) {
230662306a36Sopenharmony_ci		err = -EINVAL;
230762306a36Sopenharmony_ci		goto out;
230862306a36Sopenharmony_ci	}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	err = indx_init(indx, sbi, attr, INDEX_MUTEX_SR);
231162306a36Sopenharmony_ci	if (err)
231262306a36Sopenharmony_ci		goto out;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ciout:
231562306a36Sopenharmony_ci	return err;
231662306a36Sopenharmony_ci}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci/*
231962306a36Sopenharmony_ci * ntfs_objid_init - Load and parse $Extend/$ObjId.
232062306a36Sopenharmony_ci */
232162306a36Sopenharmony_ciint ntfs_objid_init(struct ntfs_sb_info *sbi)
232262306a36Sopenharmony_ci{
232362306a36Sopenharmony_ci	int err;
232462306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->objid.ni;
232562306a36Sopenharmony_ci	struct ntfs_index *indx = &sbi->objid.index_o;
232662306a36Sopenharmony_ci	struct ATTRIB *attr;
232762306a36Sopenharmony_ci	struct ATTR_LIST_ENTRY *le;
232862306a36Sopenharmony_ci	const struct INDEX_ROOT *root;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	if (!ni)
233162306a36Sopenharmony_ci		return 0;
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	le = NULL;
233462306a36Sopenharmony_ci	attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SO_NAME,
233562306a36Sopenharmony_ci			    ARRAY_SIZE(SO_NAME), NULL, NULL);
233662306a36Sopenharmony_ci	if (!attr) {
233762306a36Sopenharmony_ci		err = -EINVAL;
233862306a36Sopenharmony_ci		goto out;
233962306a36Sopenharmony_ci	}
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	root = resident_data(attr);
234262306a36Sopenharmony_ci	if (root->type != ATTR_ZERO ||
234362306a36Sopenharmony_ci	    root->rule != NTFS_COLLATION_TYPE_UINTS) {
234462306a36Sopenharmony_ci		err = -EINVAL;
234562306a36Sopenharmony_ci		goto out;
234662306a36Sopenharmony_ci	}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	err = indx_init(indx, sbi, attr, INDEX_MUTEX_SO);
234962306a36Sopenharmony_ci	if (err)
235062306a36Sopenharmony_ci		goto out;
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ciout:
235362306a36Sopenharmony_ci	return err;
235462306a36Sopenharmony_ci}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ciint ntfs_objid_remove(struct ntfs_sb_info *sbi, struct GUID *guid)
235762306a36Sopenharmony_ci{
235862306a36Sopenharmony_ci	int err;
235962306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->objid.ni;
236062306a36Sopenharmony_ci	struct ntfs_index *indx = &sbi->objid.index_o;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	if (!ni)
236362306a36Sopenharmony_ci		return -EINVAL;
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_OBJID);
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	err = indx_delete_entry(indx, ni, guid, sizeof(*guid), NULL);
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	mark_inode_dirty(&ni->vfs_inode);
237062306a36Sopenharmony_ci	ni_unlock(ni);
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	return err;
237362306a36Sopenharmony_ci}
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ciint ntfs_insert_reparse(struct ntfs_sb_info *sbi, __le32 rtag,
237662306a36Sopenharmony_ci			const struct MFT_REF *ref)
237762306a36Sopenharmony_ci{
237862306a36Sopenharmony_ci	int err;
237962306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->reparse.ni;
238062306a36Sopenharmony_ci	struct ntfs_index *indx = &sbi->reparse.index_r;
238162306a36Sopenharmony_ci	struct NTFS_DE_R re;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	if (!ni)
238462306a36Sopenharmony_ci		return -EINVAL;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	memset(&re, 0, sizeof(re));
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	re.de.view.data_off = cpu_to_le16(offsetof(struct NTFS_DE_R, zero));
238962306a36Sopenharmony_ci	re.de.size = cpu_to_le16(sizeof(struct NTFS_DE_R));
239062306a36Sopenharmony_ci	re.de.key_size = cpu_to_le16(sizeof(re.key));
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	re.key.ReparseTag = rtag;
239362306a36Sopenharmony_ci	memcpy(&re.key.ref, ref, sizeof(*ref));
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_REPARSE);
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	err = indx_insert_entry(indx, ni, &re.de, NULL, NULL, 0);
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	mark_inode_dirty(&ni->vfs_inode);
240062306a36Sopenharmony_ci	ni_unlock(ni);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	return err;
240362306a36Sopenharmony_ci}
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ciint ntfs_remove_reparse(struct ntfs_sb_info *sbi, __le32 rtag,
240662306a36Sopenharmony_ci			const struct MFT_REF *ref)
240762306a36Sopenharmony_ci{
240862306a36Sopenharmony_ci	int err, diff;
240962306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->reparse.ni;
241062306a36Sopenharmony_ci	struct ntfs_index *indx = &sbi->reparse.index_r;
241162306a36Sopenharmony_ci	struct ntfs_fnd *fnd = NULL;
241262306a36Sopenharmony_ci	struct REPARSE_KEY rkey;
241362306a36Sopenharmony_ci	struct NTFS_DE_R *re;
241462306a36Sopenharmony_ci	struct INDEX_ROOT *root_r;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	if (!ni)
241762306a36Sopenharmony_ci		return -EINVAL;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	rkey.ReparseTag = rtag;
242062306a36Sopenharmony_ci	rkey.ref = *ref;
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_REPARSE);
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	if (rtag) {
242562306a36Sopenharmony_ci		err = indx_delete_entry(indx, ni, &rkey, sizeof(rkey), NULL);
242662306a36Sopenharmony_ci		goto out1;
242762306a36Sopenharmony_ci	}
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	fnd = fnd_get();
243062306a36Sopenharmony_ci	if (!fnd) {
243162306a36Sopenharmony_ci		err = -ENOMEM;
243262306a36Sopenharmony_ci		goto out1;
243362306a36Sopenharmony_ci	}
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	root_r = indx_get_root(indx, ni, NULL, NULL);
243662306a36Sopenharmony_ci	if (!root_r) {
243762306a36Sopenharmony_ci		err = -EINVAL;
243862306a36Sopenharmony_ci		goto out;
243962306a36Sopenharmony_ci	}
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	/* 1 - forces to ignore rkey.ReparseTag when comparing keys. */
244262306a36Sopenharmony_ci	err = indx_find(indx, ni, root_r, &rkey, sizeof(rkey), (void *)1, &diff,
244362306a36Sopenharmony_ci			(struct NTFS_DE **)&re, fnd);
244462306a36Sopenharmony_ci	if (err)
244562306a36Sopenharmony_ci		goto out;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	if (memcmp(&re->key.ref, ref, sizeof(*ref))) {
244862306a36Sopenharmony_ci		/* Impossible. Looks like volume corrupt? */
244962306a36Sopenharmony_ci		goto out;
245062306a36Sopenharmony_ci	}
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	memcpy(&rkey, &re->key, sizeof(rkey));
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	fnd_put(fnd);
245562306a36Sopenharmony_ci	fnd = NULL;
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	err = indx_delete_entry(indx, ni, &rkey, sizeof(rkey), NULL);
245862306a36Sopenharmony_ci	if (err)
245962306a36Sopenharmony_ci		goto out;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ciout:
246262306a36Sopenharmony_ci	fnd_put(fnd);
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ciout1:
246562306a36Sopenharmony_ci	mark_inode_dirty(&ni->vfs_inode);
246662306a36Sopenharmony_ci	ni_unlock(ni);
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	return err;
246962306a36Sopenharmony_ci}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_cistatic inline void ntfs_unmap_and_discard(struct ntfs_sb_info *sbi, CLST lcn,
247262306a36Sopenharmony_ci					  CLST len)
247362306a36Sopenharmony_ci{
247462306a36Sopenharmony_ci	ntfs_unmap_meta(sbi->sb, lcn, len);
247562306a36Sopenharmony_ci	ntfs_discard(sbi, lcn, len);
247662306a36Sopenharmony_ci}
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_civoid mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
247962306a36Sopenharmony_ci{
248062306a36Sopenharmony_ci	CLST end, i, zone_len, zlen;
248162306a36Sopenharmony_ci	struct wnd_bitmap *wnd = &sbi->used.bitmap;
248262306a36Sopenharmony_ci	bool dirty = false;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
248562306a36Sopenharmony_ci	if (!wnd_is_used(wnd, lcn, len)) {
248662306a36Sopenharmony_ci		/* mark volume as dirty out of wnd->rw_lock */
248762306a36Sopenharmony_ci		dirty = true;
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci		end = lcn + len;
249062306a36Sopenharmony_ci		len = 0;
249162306a36Sopenharmony_ci		for (i = lcn; i < end; i++) {
249262306a36Sopenharmony_ci			if (wnd_is_used(wnd, i, 1)) {
249362306a36Sopenharmony_ci				if (!len)
249462306a36Sopenharmony_ci					lcn = i;
249562306a36Sopenharmony_ci				len += 1;
249662306a36Sopenharmony_ci				continue;
249762306a36Sopenharmony_ci			}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci			if (!len)
250062306a36Sopenharmony_ci				continue;
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci			if (trim)
250362306a36Sopenharmony_ci				ntfs_unmap_and_discard(sbi, lcn, len);
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci			wnd_set_free(wnd, lcn, len);
250662306a36Sopenharmony_ci			len = 0;
250762306a36Sopenharmony_ci		}
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci		if (!len)
251062306a36Sopenharmony_ci			goto out;
251162306a36Sopenharmony_ci	}
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	if (trim)
251462306a36Sopenharmony_ci		ntfs_unmap_and_discard(sbi, lcn, len);
251562306a36Sopenharmony_ci	wnd_set_free(wnd, lcn, len);
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	/* append to MFT zone, if possible. */
251862306a36Sopenharmony_ci	zone_len = wnd_zone_len(wnd);
251962306a36Sopenharmony_ci	zlen = min(zone_len + len, sbi->zone_max);
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci	if (zlen == zone_len) {
252262306a36Sopenharmony_ci		/* MFT zone already has maximum size. */
252362306a36Sopenharmony_ci	} else if (!zone_len) {
252462306a36Sopenharmony_ci		/* Create MFT zone only if 'zlen' is large enough. */
252562306a36Sopenharmony_ci		if (zlen == sbi->zone_max)
252662306a36Sopenharmony_ci			wnd_zone_set(wnd, lcn, zlen);
252762306a36Sopenharmony_ci	} else {
252862306a36Sopenharmony_ci		CLST zone_lcn = wnd_zone_bit(wnd);
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci		if (lcn + len == zone_lcn) {
253162306a36Sopenharmony_ci			/* Append into head MFT zone. */
253262306a36Sopenharmony_ci			wnd_zone_set(wnd, lcn, zlen);
253362306a36Sopenharmony_ci		} else if (zone_lcn + zone_len == lcn) {
253462306a36Sopenharmony_ci			/* Append into tail MFT zone. */
253562306a36Sopenharmony_ci			wnd_zone_set(wnd, zone_lcn, zlen);
253662306a36Sopenharmony_ci		}
253762306a36Sopenharmony_ci	}
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ciout:
254062306a36Sopenharmony_ci	up_write(&wnd->rw_lock);
254162306a36Sopenharmony_ci	if (dirty)
254262306a36Sopenharmony_ci		ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
254362306a36Sopenharmony_ci}
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci/*
254662306a36Sopenharmony_ci * run_deallocate - Deallocate clusters.
254762306a36Sopenharmony_ci */
254862306a36Sopenharmony_ciint run_deallocate(struct ntfs_sb_info *sbi, const struct runs_tree *run,
254962306a36Sopenharmony_ci		   bool trim)
255062306a36Sopenharmony_ci{
255162306a36Sopenharmony_ci	CLST lcn, len;
255262306a36Sopenharmony_ci	size_t idx = 0;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	while (run_get_entry(run, idx++, NULL, &lcn, &len)) {
255562306a36Sopenharmony_ci		if (lcn == SPARSE_LCN)
255662306a36Sopenharmony_ci			continue;
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci		mark_as_free_ex(sbi, lcn, len, trim);
255962306a36Sopenharmony_ci	}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	return 0;
256262306a36Sopenharmony_ci}
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_cistatic inline bool name_has_forbidden_chars(const struct le_str *fname)
256562306a36Sopenharmony_ci{
256662306a36Sopenharmony_ci	int i, ch;
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	/* check for forbidden chars */
256962306a36Sopenharmony_ci	for (i = 0; i < fname->len; ++i) {
257062306a36Sopenharmony_ci		ch = le16_to_cpu(fname->name[i]);
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci		/* control chars */
257362306a36Sopenharmony_ci		if (ch < 0x20)
257462306a36Sopenharmony_ci			return true;
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci		switch (ch) {
257762306a36Sopenharmony_ci		/* disallowed by Windows */
257862306a36Sopenharmony_ci		case '\\':
257962306a36Sopenharmony_ci		case '/':
258062306a36Sopenharmony_ci		case ':':
258162306a36Sopenharmony_ci		case '*':
258262306a36Sopenharmony_ci		case '?':
258362306a36Sopenharmony_ci		case '<':
258462306a36Sopenharmony_ci		case '>':
258562306a36Sopenharmony_ci		case '|':
258662306a36Sopenharmony_ci		case '\"':
258762306a36Sopenharmony_ci			return true;
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci		default:
259062306a36Sopenharmony_ci			/* allowed char */
259162306a36Sopenharmony_ci			break;
259262306a36Sopenharmony_ci		}
259362306a36Sopenharmony_ci	}
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci	/* file names cannot end with space or . */
259662306a36Sopenharmony_ci	if (fname->len > 0) {
259762306a36Sopenharmony_ci		ch = le16_to_cpu(fname->name[fname->len - 1]);
259862306a36Sopenharmony_ci		if (ch == ' ' || ch == '.')
259962306a36Sopenharmony_ci			return true;
260062306a36Sopenharmony_ci	}
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	return false;
260362306a36Sopenharmony_ci}
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_cistatic inline bool is_reserved_name(const struct ntfs_sb_info *sbi,
260662306a36Sopenharmony_ci				    const struct le_str *fname)
260762306a36Sopenharmony_ci{
260862306a36Sopenharmony_ci	int port_digit;
260962306a36Sopenharmony_ci	const __le16 *name = fname->name;
261062306a36Sopenharmony_ci	int len = fname->len;
261162306a36Sopenharmony_ci	const u16 *upcase = sbi->upcase;
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	/* check for 3 chars reserved names (device names) */
261462306a36Sopenharmony_ci	/* name by itself or with any extension is forbidden */
261562306a36Sopenharmony_ci	if (len == 3 || (len > 3 && le16_to_cpu(name[3]) == '.'))
261662306a36Sopenharmony_ci		if (!ntfs_cmp_names(name, 3, CON_NAME, 3, upcase, false) ||
261762306a36Sopenharmony_ci		    !ntfs_cmp_names(name, 3, NUL_NAME, 3, upcase, false) ||
261862306a36Sopenharmony_ci		    !ntfs_cmp_names(name, 3, AUX_NAME, 3, upcase, false) ||
261962306a36Sopenharmony_ci		    !ntfs_cmp_names(name, 3, PRN_NAME, 3, upcase, false))
262062306a36Sopenharmony_ci			return true;
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci	/* check for 4 chars reserved names (port name followed by 1..9) */
262362306a36Sopenharmony_ci	/* name by itself or with any extension is forbidden */
262462306a36Sopenharmony_ci	if (len == 4 || (len > 4 && le16_to_cpu(name[4]) == '.')) {
262562306a36Sopenharmony_ci		port_digit = le16_to_cpu(name[3]);
262662306a36Sopenharmony_ci		if (port_digit >= '1' && port_digit <= '9')
262762306a36Sopenharmony_ci			if (!ntfs_cmp_names(name, 3, COM_NAME, 3, upcase,
262862306a36Sopenharmony_ci					    false) ||
262962306a36Sopenharmony_ci			    !ntfs_cmp_names(name, 3, LPT_NAME, 3, upcase,
263062306a36Sopenharmony_ci					    false))
263162306a36Sopenharmony_ci				return true;
263262306a36Sopenharmony_ci	}
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	return false;
263562306a36Sopenharmony_ci}
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci/*
263862306a36Sopenharmony_ci * valid_windows_name - Check if a file name is valid in Windows.
263962306a36Sopenharmony_ci */
264062306a36Sopenharmony_cibool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *fname)
264162306a36Sopenharmony_ci{
264262306a36Sopenharmony_ci	return !name_has_forbidden_chars(fname) &&
264362306a36Sopenharmony_ci	       !is_reserved_name(sbi, fname);
264462306a36Sopenharmony_ci}
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci/*
264762306a36Sopenharmony_ci * ntfs_set_label - updates current ntfs label.
264862306a36Sopenharmony_ci */
264962306a36Sopenharmony_ciint ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len)
265062306a36Sopenharmony_ci{
265162306a36Sopenharmony_ci	int err;
265262306a36Sopenharmony_ci	struct ATTRIB *attr;
265362306a36Sopenharmony_ci	struct ntfs_inode *ni = sbi->volume.ni;
265462306a36Sopenharmony_ci	const u8 max_ulen = 0x80; /* TODO: use attrdef to get maximum length */
265562306a36Sopenharmony_ci	/* Allocate PATH_MAX bytes. */
265662306a36Sopenharmony_ci	struct cpu_str *uni = __getname();
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	if (!uni)
265962306a36Sopenharmony_ci		return -ENOMEM;
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	err = ntfs_nls_to_utf16(sbi, label, len, uni, (PATH_MAX - 2) / 2,
266262306a36Sopenharmony_ci				UTF16_LITTLE_ENDIAN);
266362306a36Sopenharmony_ci	if (err < 0)
266462306a36Sopenharmony_ci		goto out;
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci	if (uni->len > max_ulen) {
266762306a36Sopenharmony_ci		ntfs_warn(sbi->sb, "new label is too long");
266862306a36Sopenharmony_ci		err = -EFBIG;
266962306a36Sopenharmony_ci		goto out;
267062306a36Sopenharmony_ci	}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	ni_lock(ni);
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	/* Ignore any errors. */
267562306a36Sopenharmony_ci	ni_remove_attr(ni, ATTR_LABEL, NULL, 0, false, NULL);
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	err = ni_insert_resident(ni, uni->len * sizeof(u16), ATTR_LABEL, NULL,
267862306a36Sopenharmony_ci				 0, &attr, NULL, NULL);
267962306a36Sopenharmony_ci	if (err < 0)
268062306a36Sopenharmony_ci		goto unlock_out;
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	/* write new label in on-disk struct. */
268362306a36Sopenharmony_ci	memcpy(resident_data(attr), uni->name, uni->len * sizeof(u16));
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	/* update cached value of current label. */
268662306a36Sopenharmony_ci	if (len >= ARRAY_SIZE(sbi->volume.label))
268762306a36Sopenharmony_ci		len = ARRAY_SIZE(sbi->volume.label) - 1;
268862306a36Sopenharmony_ci	memcpy(sbi->volume.label, label, len);
268962306a36Sopenharmony_ci	sbi->volume.label[len] = 0;
269062306a36Sopenharmony_ci	mark_inode_dirty_sync(&ni->vfs_inode);
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ciunlock_out:
269362306a36Sopenharmony_ci	ni_unlock(ni);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	if (!err)
269662306a36Sopenharmony_ci		err = _ni_write_inode(&ni->vfs_inode, 0);
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ciout:
269962306a36Sopenharmony_ci	__putname(uni);
270062306a36Sopenharmony_ci	return err;
270162306a36Sopenharmony_ci}