Blame SOURCES/0028-fs-ntfs3-Rework-file-operations.patch

Kmods SIG 63c143
From 78ab59fee07f22464f32eafebab2bd97ba94ff2d Mon Sep 17 00:00:00 2001
Kmods SIG 63c143
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Kmods SIG 63c143
Date: Tue, 31 Aug 2021 18:52:39 +0300
Kmods SIG 63c143
Subject: [Backport 78ab59fee07f] src: Rework file operations
Kmods SIG 63c143
Kmods SIG 63c143
Rename now works "Add new name and remove old name".
Kmods SIG 63c143
"Remove old name and add new name" may result in bad inode
Kmods SIG 63c143
if we can't add new name and then can't restore (add) old name.
Kmods SIG 63c143
Kmods SIG 63c143
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Kmods SIG 63c143
---
Kmods SIG 63c143
 src/attrib.c   |  17 +--
Kmods SIG 63c143
 src/attrlist.c |  26 ++--
Kmods SIG 63c143
 src/frecord.c  | 342 ++++++++++++++++++++++++++++++++++++--------
Kmods SIG 63c143
 src/fsntfs.c   |  87 +++++------
Kmods SIG 63c143
 src/index.c    |  45 +++---
Kmods SIG 63c143
 src/inode.c    | 275 ++++++++++++-----------------------
Kmods SIG 63c143
 src/namei.c    | 236 ++++++++----------------------
Kmods SIG 63c143
 src/ntfs_fs.h  |  31 +++-
Kmods SIG 63c143
 src/record.c   |   8 +-
Kmods SIG 63c143
 src/xattr.c    |  25 ++--
Kmods SIG 63c143
 10 files changed, 563 insertions(+), 529 deletions(-)
Kmods SIG 63c143
Kmods SIG 63c143
diff --git a/src/attrib.c b/src/attrib.c
Kmods SIG 63c143
index 4b285f704e621ef5cbba11f1a006622e6387ea09..ffc323bacc9fe63683395d9535ec65849137551a 100644
Kmods SIG 63c143
--- a/src/attrib.c
Kmods SIG 63c143
+++ b/src/attrib.c
Kmods SIG 63c143
@@ -218,9 +218,11 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 out:
Kmods SIG 63c143
-	/* Undo. */
Kmods SIG 63c143
-	run_deallocate_ex(sbi, run, vcn0, vcn - vcn0, NULL, false);
Kmods SIG 63c143
-	run_truncate(run, vcn0);
Kmods SIG 63c143
+	/* Undo 'ntfs_look_for_free_space' */
Kmods SIG 63c143
+	if (vcn - vcn0) {
Kmods SIG 63c143
+		run_deallocate_ex(sbi, run, vcn0, vcn - vcn0, NULL, false);
Kmods SIG 63c143
+		run_truncate(run, vcn0);
Kmods SIG 63c143
+	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 	return err;
Kmods SIG 63c143
 }
Kmods SIG 63c143
@@ -701,7 +703,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 			 * (list entry for std attribute always first).
Kmods SIG 63c143
 			 * So it is safe to step back.
Kmods SIG 63c143
 			 */
Kmods SIG 63c143
-			mi_remove_attr(mi, attr);
Kmods SIG 63c143
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG 63c143
 
Kmods SIG 63c143
 			if (!al_remove_le(ni, le)) {
Kmods SIG 63c143
 				err = -EINVAL;
Kmods SIG 63c143
@@ -1004,7 +1006,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
Kmods SIG 63c143
 			end = next_svcn;
Kmods SIG 63c143
 		while (end > evcn) {
Kmods SIG 63c143
 			/* Remove segment [svcn : evcn). */
Kmods SIG 63c143
-			mi_remove_attr(mi, attr);
Kmods SIG 63c143
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG 63c143
 
Kmods SIG 63c143
 			if (!al_remove_le(ni, le)) {
Kmods SIG 63c143
 				err = -EINVAL;
Kmods SIG 63c143
@@ -1600,7 +1602,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
Kmods SIG 63c143
 			end = next_svcn;
Kmods SIG 63c143
 		while (end > evcn) {
Kmods SIG 63c143
 			/* Remove segment [svcn : evcn). */
Kmods SIG 63c143
-			mi_remove_attr(mi, attr);
Kmods SIG 63c143
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG 63c143
 
Kmods SIG 63c143
 			if (!al_remove_le(ni, le)) {
Kmods SIG 63c143
 				err = -EINVAL;
Kmods SIG 63c143
@@ -1836,13 +1838,12 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
Kmods SIG 63c143
 			u16 le_sz;
Kmods SIG 63c143
 			u16 roff = le16_to_cpu(attr->nres.run_off);
Kmods SIG 63c143
 
Kmods SIG 63c143
-			/* run==1 means unpack and deallocate. */
Kmods SIG 63c143
 			run_unpack_ex(RUN_DEALLOCATE, sbi, ni->mi.rno, svcn,
Kmods SIG 63c143
 				      evcn1 - 1, svcn, Add2Ptr(attr, roff),
Kmods SIG 63c143
 				      le32_to_cpu(attr->size) - roff);
Kmods SIG 63c143
 
Kmods SIG 63c143
 			/* Delete this attribute segment. */
Kmods SIG 63c143
-			mi_remove_attr(mi, attr);
Kmods SIG 63c143
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG 63c143
 			if (!le)
Kmods SIG 63c143
 				break;
Kmods SIG 63c143
 
Kmods SIG 63c143
diff --git a/src/attrlist.c b/src/attrlist.c
Kmods SIG 63c143
index 32ca990af64b53b4e9572d5dd0d6ae5f057760c4..fa32399eb5171ce25f037fbd1bd8e483a37b839c 100644
Kmods SIG 63c143
--- a/src/attrlist.c
Kmods SIG 63c143
+++ b/src/attrlist.c
Kmods SIG 63c143
@@ -279,7 +279,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
Kmods SIG 63c143
 	struct ATTR_LIST_ENTRY *le;
Kmods SIG 63c143
 	size_t off;
Kmods SIG 63c143
 	u16 sz;
Kmods SIG 63c143
-	size_t asize, new_asize;
Kmods SIG 63c143
+	size_t asize, new_asize, old_size;
Kmods SIG 63c143
 	u64 new_size;
Kmods SIG 63c143
 	typeof(ni->attr_list) *al = &ni->attr_list;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -287,8 +287,9 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
Kmods SIG 63c143
 	 * Compute the size of the new 'le'
Kmods SIG 63c143
 	 */
Kmods SIG 63c143
 	sz = le_size(name_len);
Kmods SIG 63c143
-	new_size = al->size + sz;
Kmods SIG 63c143
-	asize = al_aligned(al->size);
Kmods SIG 63c143
+	old_size = al->size;
Kmods SIG 63c143
+	new_size = old_size + sz;
Kmods SIG 63c143
+	asize = al_aligned(old_size);
Kmods SIG 63c143
 	new_asize = al_aligned(new_size);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/* Scan forward to the point at which the new 'le' should be inserted. */
Kmods SIG 63c143
@@ -302,13 +303,14 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
Kmods SIG 63c143
 			return -ENOMEM;
Kmods SIG 63c143
 
Kmods SIG 63c143
 		memcpy(ptr, al->le, off);
Kmods SIG 63c143
-		memcpy(Add2Ptr(ptr, off + sz), le, al->size - off);
Kmods SIG 63c143
+		memcpy(Add2Ptr(ptr, off + sz), le, old_size - off);
Kmods SIG 63c143
 		le = Add2Ptr(ptr, off);
Kmods SIG 63c143
 		kfree(al->le);
Kmods SIG 63c143
 		al->le = ptr;
Kmods SIG 63c143
 	} else {
Kmods SIG 63c143
-		memmove(Add2Ptr(le, sz), le, al->size - off);
Kmods SIG 63c143
+		memmove(Add2Ptr(le, sz), le, old_size - off);
Kmods SIG 63c143
 	}
Kmods SIG 63c143
+	*new_le = le;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	al->size = new_size;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -321,23 +323,25 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
Kmods SIG 63c143
 	le->id = id;
Kmods SIG 63c143
 	memcpy(le->name, name, sizeof(short) * name_len);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	al->dirty = true;
Kmods SIG 63c143
-
Kmods SIG 63c143
 	err = attr_set_size(ni, ATTR_LIST, NULL, 0, &al->run, new_size,
Kmods SIG 63c143
 			    &new_size, true, &attr);
Kmods SIG 63c143
-	if (err)
Kmods SIG 63c143
+	if (err) {
Kmods SIG 63c143
+		/* Undo memmove above. */
Kmods SIG 63c143
+		memmove(le, Add2Ptr(le, sz), old_size - off);
Kmods SIG 63c143
+		al->size = old_size;
Kmods SIG 63c143
 		return err;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
+
Kmods SIG 63c143
+	al->dirty = true;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (attr && attr->non_res) {
Kmods SIG 63c143
 		err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
Kmods SIG 63c143
 					al->size);
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
 			return err;
Kmods SIG 63c143
+		al->dirty = false;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-	al->dirty = false;
Kmods SIG 63c143
-	*new_le = le;
Kmods SIG 63c143
-
Kmods SIG 63c143
 	return 0;
Kmods SIG 63c143
 }
Kmods SIG 63c143
 
Kmods SIG 63c143
diff --git a/src/frecord.c b/src/frecord.c
Kmods SIG 63c143
index 9d374827750b2b39261f5985ec2fbb554ac8f6df..3f48b612ec962c6720fb3d3b3e0d63312f389c81 100644
Kmods SIG 63c143
--- a/src/frecord.c
Kmods SIG 63c143
+++ b/src/frecord.c
Kmods SIG 63c143
@@ -163,7 +163,7 @@ int ni_load_mi_ex(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi)
Kmods SIG 63c143
 /*
Kmods SIG 63c143
  * ni_load_mi - Load mft_inode corresponded list_entry.
Kmods SIG 63c143
  */
Kmods SIG 63c143
-int ni_load_mi(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG 63c143
+int ni_load_mi(struct ntfs_inode *ni, const struct ATTR_LIST_ENTRY *le,
Kmods SIG 63c143
 	       struct mft_inode **mi)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	CLST rno;
Kmods SIG 63c143
@@ -402,7 +402,7 @@ int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 		if (!attr)
Kmods SIG 63c143
 			return -ENOENT;
Kmods SIG 63c143
 
Kmods SIG 63c143
-		mi_remove_attr(&ni->mi, attr);
Kmods SIG 63c143
+		mi_remove_attr(ni, &ni->mi, attr);
Kmods SIG 63c143
 		return 0;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -441,7 +441,7 @@ int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 		if (!attr)
Kmods SIG 63c143
 			return -ENOENT;
Kmods SIG 63c143
 
Kmods SIG 63c143
-		mi_remove_attr(mi, attr);
Kmods SIG 63c143
+		mi_remove_attr(ni, mi, attr);
Kmods SIG 63c143
 
Kmods SIG 63c143
 		if (PtrOffset(ni->attr_list.le, le) >= ni->attr_list.size)
Kmods SIG 63c143
 			return 0;
Kmods SIG 63c143
@@ -454,12 +454,11 @@ int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
  *
Kmods SIG 63c143
  * Return: Not full constructed attribute or NULL if not possible to create.
Kmods SIG 63c143
  */
Kmods SIG 63c143
-static struct ATTRIB *ni_ins_new_attr(struct ntfs_inode *ni,
Kmods SIG 63c143
-				      struct mft_inode *mi,
Kmods SIG 63c143
-				      struct ATTR_LIST_ENTRY *le,
Kmods SIG 63c143
-				      enum ATTR_TYPE type, const __le16 *name,
Kmods SIG 63c143
-				      u8 name_len, u32 asize, u16 name_off,
Kmods SIG 63c143
-				      CLST svcn)
Kmods SIG 63c143
+static struct ATTRIB *
Kmods SIG 63c143
+ni_ins_new_attr(struct ntfs_inode *ni, struct mft_inode *mi,
Kmods SIG 63c143
+		struct ATTR_LIST_ENTRY *le, enum ATTR_TYPE type,
Kmods SIG 63c143
+		const __le16 *name, u8 name_len, u32 asize, u16 name_off,
Kmods SIG 63c143
+		CLST svcn, struct ATTR_LIST_ENTRY **ins_le)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
 	struct ATTRIB *attr;
Kmods SIG 63c143
@@ -507,6 +506,8 @@ static struct ATTRIB *ni_ins_new_attr(struct ntfs_inode *ni,
Kmods SIG 63c143
 	le->ref = ref;
Kmods SIG 63c143
 
Kmods SIG 63c143
 out:
Kmods SIG 63c143
+	if (ins_le)
Kmods SIG 63c143
+		*ins_le = le;
Kmods SIG 63c143
 	return attr;
Kmods SIG 63c143
 }
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -599,7 +600,7 @@ static int ni_repack(struct ntfs_inode *ni)
Kmods SIG 63c143
 		if (next_svcn >= evcn + 1) {
Kmods SIG 63c143
 			/* We can remove this attribute segment. */
Kmods SIG 63c143
 			al_remove_le(ni, le);
Kmods SIG 63c143
-			mi_remove_attr(mi, attr);
Kmods SIG 63c143
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG 63c143
 			le = le_p;
Kmods SIG 63c143
 			continue;
Kmods SIG 63c143
 		}
Kmods SIG 63c143
@@ -695,8 +696,8 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
Kmods SIG 63c143
 		free -= asize;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-	/* Is seems that attribute list can be removed from primary record. */
Kmods SIG 63c143
-	mi_remove_attr(&ni->mi, attr_list);
Kmods SIG 63c143
+	/* It seems that attribute list can be removed from primary record. */
Kmods SIG 63c143
+	mi_remove_attr(NULL, &ni->mi, attr_list);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/*
Kmods SIG 63c143
 	 * Repeat the cycle above and move all attributes to primary record.
Kmods SIG 63c143
@@ -724,7 +725,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
Kmods SIG 63c143
 		attr_ins->id = id;
Kmods SIG 63c143
 
Kmods SIG 63c143
 		/* Remove from original record. */
Kmods SIG 63c143
-		mi_remove_attr(mi, attr);
Kmods SIG 63c143
+		mi_remove_attr(NULL, mi, attr);
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 	run_deallocate(sbi, &ni->attr_list.run, true);
Kmods SIG 63c143
@@ -842,7 +843,8 @@ int ni_create_attr_list(struct ntfs_inode *ni)
Kmods SIG 63c143
 		memcpy(attr, b, asize);
Kmods SIG 63c143
 		attr->id = le_b[nb]->id;
Kmods SIG 63c143
 
Kmods SIG 63c143
-		WARN_ON(!mi_remove_attr(&ni->mi, b));
Kmods SIG 63c143
+		/* Remove from primary record. */
Kmods SIG 63c143
+		WARN_ON(!mi_remove_attr(NULL, &ni->mi, b));
Kmods SIG 63c143
 
Kmods SIG 63c143
 		if (to_free <= asize)
Kmods SIG 63c143
 			break;
Kmods SIG 63c143
@@ -883,7 +885,8 @@ int ni_create_attr_list(struct ntfs_inode *ni)
Kmods SIG 63c143
 static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG 63c143
 			   enum ATTR_TYPE type, const __le16 *name, u8 name_len,
Kmods SIG 63c143
 			   u32 asize, CLST svcn, u16 name_off, bool force_ext,
Kmods SIG 63c143
-			   struct ATTRIB **ins_attr, struct mft_inode **ins_mi)
Kmods SIG 63c143
+			   struct ATTRIB **ins_attr, struct mft_inode **ins_mi,
Kmods SIG 63c143
+			   struct ATTR_LIST_ENTRY **ins_le)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	struct ATTRIB *attr;
Kmods SIG 63c143
 	struct mft_inode *mi;
Kmods SIG 63c143
@@ -956,12 +959,14 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG 63c143
 
Kmods SIG 63c143
 		/* Try to insert attribute into this subrecord. */
Kmods SIG 63c143
 		attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
Kmods SIG 63c143
-				       name_off, svcn);
Kmods SIG 63c143
+				       name_off, svcn, ins_le);
Kmods SIG 63c143
 		if (!attr)
Kmods SIG 63c143
 			continue;
Kmods SIG 63c143
 
Kmods SIG 63c143
 		if (ins_attr)
Kmods SIG 63c143
 			*ins_attr = attr;
Kmods SIG 63c143
+		if (ins_mi)
Kmods SIG 63c143
+			*ins_mi = mi;
Kmods SIG 63c143
 		return 0;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -977,7 +982,7 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 	attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
Kmods SIG 63c143
-			       name_off, svcn);
Kmods SIG 63c143
+			       name_off, svcn, ins_le);
Kmods SIG 63c143
 	if (!attr)
Kmods SIG 63c143
 		goto out2;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -1016,7 +1021,8 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG 63c143
 static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 			  const __le16 *name, u8 name_len, u32 asize,
Kmods SIG 63c143
 			  u16 name_off, CLST svcn, struct ATTRIB **ins_attr,
Kmods SIG 63c143
-			  struct mft_inode **ins_mi)
Kmods SIG 63c143
+			  struct mft_inode **ins_mi,
Kmods SIG 63c143
+			  struct ATTR_LIST_ENTRY **ins_le)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	struct ntfs_sb_info *sbi = ni->mi.sbi;
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
@@ -1045,7 +1051,7 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (asize <= free) {
Kmods SIG 63c143
 		attr = ni_ins_new_attr(ni, &ni->mi, NULL, type, name, name_len,
Kmods SIG 63c143
-				       asize, name_off, svcn);
Kmods SIG 63c143
+				       asize, name_off, svcn, ins_le);
Kmods SIG 63c143
 		if (attr) {
Kmods SIG 63c143
 			if (ins_attr)
Kmods SIG 63c143
 				*ins_attr = attr;
Kmods SIG 63c143
@@ -1059,7 +1065,8 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 	if (!is_mft || type != ATTR_DATA || svcn) {
Kmods SIG 63c143
 		/* This ATTRIB will be external. */
Kmods SIG 63c143
 		err = ni_ins_attr_ext(ni, NULL, type, name, name_len, asize,
Kmods SIG 63c143
-				      svcn, name_off, false, ins_attr, ins_mi);
Kmods SIG 63c143
+				      svcn, name_off, false, ins_attr, ins_mi,
Kmods SIG 63c143
+				      ins_le);
Kmods SIG 63c143
 		goto out;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -1117,7 +1124,7 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 		t16 = le16_to_cpu(attr->name_off);
Kmods SIG 63c143
 		err = ni_ins_attr_ext(ni, le, attr->type, Add2Ptr(attr, t16),
Kmods SIG 63c143
 				      attr->name_len, t32, attr_svcn(attr), t16,
Kmods SIG 63c143
-				      false, &eattr, NULL);
Kmods SIG 63c143
+				      false, &eattr, NULL, NULL);
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
 			return err;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -1125,8 +1132,8 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 		memcpy(eattr, attr, t32);
Kmods SIG 63c143
 		eattr->id = id;
Kmods SIG 63c143
 
Kmods SIG 63c143
-		/* Remove attrib from primary record. */
Kmods SIG 63c143
-		mi_remove_attr(&ni->mi, attr);
Kmods SIG 63c143
+		/* Remove from primary record. */
Kmods SIG 63c143
+		mi_remove_attr(NULL, &ni->mi, attr);
Kmods SIG 63c143
 
Kmods SIG 63c143
 		/* attr now points to next attribute. */
Kmods SIG 63c143
 		if (attr->type == ATTR_END)
Kmods SIG 63c143
@@ -1136,7 +1143,7 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 		;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	attr = ni_ins_new_attr(ni, &ni->mi, NULL, type, name, name_len, asize,
Kmods SIG 63c143
-			       name_off, svcn);
Kmods SIG 63c143
+			       name_off, svcn, ins_le);
Kmods SIG 63c143
 	if (!attr) {
Kmods SIG 63c143
 		err = -EINVAL;
Kmods SIG 63c143
 		goto out;
Kmods SIG 63c143
@@ -1251,7 +1258,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
Kmods SIG 63c143
 	 */
Kmods SIG 63c143
 	attr = ni_ins_new_attr(ni, mi_min, NULL, ATTR_DATA, NULL, 0,
Kmods SIG 63c143
 			       SIZEOF_NONRESIDENT + run_size,
Kmods SIG 63c143
-			       SIZEOF_NONRESIDENT, svcn);
Kmods SIG 63c143
+			       SIZEOF_NONRESIDENT, svcn, NULL);
Kmods SIG 63c143
 	if (!attr) {
Kmods SIG 63c143
 		err = -EINVAL;
Kmods SIG 63c143
 		goto out;
Kmods SIG 63c143
@@ -1315,14 +1322,15 @@ int ni_expand_list(struct ntfs_inode *ni)
Kmods SIG 63c143
 		err = ni_ins_attr_ext(ni, le, attr->type, attr_name(attr),
Kmods SIG 63c143
 				      attr->name_len, asize, attr_svcn(attr),
Kmods SIG 63c143
 				      le16_to_cpu(attr->name_off), true,
Kmods SIG 63c143
-				      &ins_attr, NULL);
Kmods SIG 63c143
+				      &ins_attr, NULL, NULL);
Kmods SIG 63c143
 
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
 			goto out;
Kmods SIG 63c143
 
Kmods SIG 63c143
 		memcpy(ins_attr, attr, asize);
Kmods SIG 63c143
 		ins_attr->id = le->id;
Kmods SIG 63c143
-		mi_remove_attr(&ni->mi, attr);
Kmods SIG 63c143
+		/* Remove from primary record. */
Kmods SIG 63c143
+		mi_remove_attr(NULL, &ni->mi, attr);
Kmods SIG 63c143
 
Kmods SIG 63c143
 		done += asize;
Kmods SIG 63c143
 		goto out;
Kmods SIG 63c143
@@ -1382,7 +1390,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 	err = ni_insert_attr(ni, type, name, name_len, asize, name_off, svcn,
Kmods SIG 63c143
-			     &attr, mi);
Kmods SIG 63c143
+			     &attr, mi, NULL);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (err)
Kmods SIG 63c143
 		goto out;
Kmods SIG 63c143
@@ -1422,7 +1430,8 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
  */
Kmods SIG 63c143
 int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG 63c143
 		       enum ATTR_TYPE type, const __le16 *name, u8 name_len,
Kmods SIG 63c143
-		       struct ATTRIB **new_attr, struct mft_inode **mi)
Kmods SIG 63c143
+		       struct ATTRIB **new_attr, struct mft_inode **mi,
Kmods SIG 63c143
+		       struct ATTR_LIST_ENTRY **le)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
 	u32 name_size = ALIGN(name_len * sizeof(short), 8);
Kmods SIG 63c143
@@ -1430,7 +1439,7 @@ int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG 63c143
 	struct ATTRIB *attr;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	err = ni_insert_attr(ni, type, name, name_len, asize, SIZEOF_RESIDENT,
Kmods SIG 63c143
-			     0, &attr, mi);
Kmods SIG 63c143
+			     0, &attr, mi, le);
Kmods SIG 63c143
 	if (err)
Kmods SIG 63c143
 		return err;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -1439,8 +1448,13 @@ int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	attr->res.data_size = cpu_to_le32(data_size);
Kmods SIG 63c143
 	attr->res.data_off = cpu_to_le16(SIZEOF_RESIDENT + name_size);
Kmods SIG 63c143
-	if (type == ATTR_NAME)
Kmods SIG 63c143
+	if (type == ATTR_NAME) {
Kmods SIG 63c143
 		attr->res.flags = RESIDENT_FLAG_INDEXED;
Kmods SIG 63c143
+
Kmods SIG 63c143
+		/* is_attr_indexed(attr)) == true */
Kmods SIG 63c143
+		le16_add_cpu(&ni->mi.mrec->hard_links, +1);
Kmods SIG 63c143
+		ni->mi.dirty = true;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
 	attr->res.res = 0;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (new_attr)
Kmods SIG 63c143
@@ -1452,22 +1466,13 @@ int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG 63c143
 /*
Kmods SIG 63c143
  * ni_remove_attr_le - Remove attribute from record.
Kmods SIG 63c143
  */
Kmods SIG 63c143
-int ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG 63c143
-		      struct ATTR_LIST_ENTRY *le)
Kmods SIG 63c143
+void ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG 63c143
+		       struct mft_inode *mi, struct ATTR_LIST_ENTRY *le)
Kmods SIG 63c143
 {
Kmods SIG 63c143
-	int err;
Kmods SIG 63c143
-	struct mft_inode *mi;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	err = ni_load_mi(ni, le, &mi);
Kmods SIG 63c143
-	if (err)
Kmods SIG 63c143
-		return err;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	mi_remove_attr(mi, attr);
Kmods SIG 63c143
+	mi_remove_attr(ni, mi, attr);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (le)
Kmods SIG 63c143
 		al_remove_le(ni, le);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	return 0;
Kmods SIG 63c143
 }
Kmods SIG 63c143
 
Kmods SIG 63c143
 /*
Kmods SIG 63c143
@@ -1549,10 +1554,12 @@ int ni_delete_all(struct ntfs_inode *ni)
Kmods SIG 63c143
 
Kmods SIG 63c143
 /* ni_fname_name
Kmods SIG 63c143
  *
Kmods SIG 63c143
- *Return: File name attribute by its value. */
Kmods SIG 63c143
+ * Return: File name attribute by its value.
Kmods SIG 63c143
+ */
Kmods SIG 63c143
 struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
Kmods SIG 63c143
 				     const struct cpu_str *uni,
Kmods SIG 63c143
 				     const struct MFT_REF *home_dir,
Kmods SIG 63c143
+				     struct mft_inode **mi,
Kmods SIG 63c143
 				     struct ATTR_LIST_ENTRY **le)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	struct ATTRIB *attr = NULL;
Kmods SIG 63c143
@@ -1562,7 +1569,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/* Enumerate all names. */
Kmods SIG 63c143
 next:
Kmods SIG 63c143
-	attr = ni_find_attr(ni, attr, le, ATTR_NAME, NULL, 0, NULL, NULL);
Kmods SIG 63c143
+	attr = ni_find_attr(ni, attr, le, ATTR_NAME, NULL, 0, NULL, mi);
Kmods SIG 63c143
 	if (!attr)
Kmods SIG 63c143
 		return NULL;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -1592,6 +1599,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
Kmods SIG 63c143
  * Return: File name attribute with given type.
Kmods SIG 63c143
  */
Kmods SIG 63c143
 struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
Kmods SIG 63c143
+				     struct mft_inode **mi,
Kmods SIG 63c143
 				     struct ATTR_LIST_ENTRY **le)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	struct ATTRIB *attr = NULL;
Kmods SIG 63c143
@@ -1599,10 +1607,12 @@ struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	*le = NULL;
Kmods SIG 63c143
 
Kmods SIG 63c143
+	if (FILE_NAME_POSIX == name_type)
Kmods SIG 63c143
+		return NULL;
Kmods SIG 63c143
+
Kmods SIG 63c143
 	/* Enumerate all names. */
Kmods SIG 63c143
 	for (;;) {
Kmods SIG 63c143
-		attr = ni_find_attr(ni, attr, le, ATTR_NAME, NULL, 0, NULL,
Kmods SIG 63c143
-				    NULL);
Kmods SIG 63c143
+		attr = ni_find_attr(ni, attr, le, ATTR_NAME, NULL, 0, NULL, mi);
Kmods SIG 63c143
 		if (!attr)
Kmods SIG 63c143
 			return NULL;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -2788,6 +2798,222 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages,
Kmods SIG 63c143
 	return err;
Kmods SIG 63c143
 }
Kmods SIG 63c143
 
Kmods SIG 63c143
+/*
Kmods SIG 63c143
+ * ni_remove_name - Removes name 'de' from MFT and from directory.
Kmods SIG 63c143
+ * 'de2' and 'undo_step' are used to restore MFT/dir, if error occurs.
Kmods SIG 63c143
+ */
Kmods SIG 63c143
+int ni_remove_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG 63c143
+		   struct NTFS_DE *de, struct NTFS_DE **de2, int *undo_step)
Kmods SIG 63c143
+{
Kmods SIG 63c143
+	int err;
Kmods SIG 63c143
+	struct ntfs_sb_info *sbi = ni->mi.sbi;
Kmods SIG 63c143
+	struct ATTR_FILE_NAME *de_name = (struct ATTR_FILE_NAME *)(de + 1);
Kmods SIG 63c143
+	struct ATTR_FILE_NAME *fname;
Kmods SIG 63c143
+	struct ATTR_LIST_ENTRY *le;
Kmods SIG 63c143
+	struct mft_inode *mi;
Kmods SIG 63c143
+	u16 de_key_size = le16_to_cpu(de->key_size);
Kmods SIG 63c143
+	u8 name_type;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	*undo_step = 0;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/* Find name in record. */
Kmods SIG 63c143
+	mi_get_ref(&dir_ni->mi, &de_name->home);
Kmods SIG 63c143
+
Kmods SIG 63c143
+	fname = ni_fname_name(ni, (struct cpu_str *)&de_name->name_len,
Kmods SIG 63c143
+			      &de_name->home, &mi, &le);
Kmods SIG 63c143
+	if (!fname)
Kmods SIG 63c143
+		return -ENOENT;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	memcpy(&de_name->dup, &fname->dup, sizeof(struct NTFS_DUP_INFO));
Kmods SIG 63c143
+	name_type = paired_name(fname->type);
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/* Mark ntfs as dirty. It will be cleared at umount. */
Kmods SIG 63c143
+	ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/* Step 1: Remove name from directory. */
Kmods SIG 63c143
+	err = indx_delete_entry(&dir_ni->dir, dir_ni, fname, de_key_size, sbi);
Kmods SIG 63c143
+	if (err)
Kmods SIG 63c143
+		return err;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/* Step 2: Remove name from MFT. */
Kmods SIG 63c143
+	ni_remove_attr_le(ni, attr_from_name(fname), mi, le);
Kmods SIG 63c143
+
Kmods SIG 63c143
+	*undo_step = 2;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/* Get paired name. */
Kmods SIG 63c143
+	fname = ni_fname_type(ni, name_type, &mi, &le);
Kmods SIG 63c143
+	if (fname) {
Kmods SIG 63c143
+		u16 de2_key_size = fname_full_size(fname);
Kmods SIG 63c143
+
Kmods SIG 63c143
+		*de2 = Add2Ptr(de, 1024);
Kmods SIG 63c143
+		(*de2)->key_size = cpu_to_le16(de2_key_size);
Kmods SIG 63c143
+
Kmods SIG 63c143
+		memcpy(*de2 + 1, fname, de2_key_size);
Kmods SIG 63c143
+
Kmods SIG 63c143
+		/* Step 3: Remove paired name from directory. */
Kmods SIG 63c143
+		err = indx_delete_entry(&dir_ni->dir, dir_ni, fname,
Kmods SIG 63c143
+					de2_key_size, sbi);
Kmods SIG 63c143
+		if (err)
Kmods SIG 63c143
+			return err;
Kmods SIG 63c143
+
Kmods SIG 63c143
+		/* Step 4: Remove paired name from MFT. */
Kmods SIG 63c143
+		ni_remove_attr_le(ni, attr_from_name(fname), mi, le);
Kmods SIG 63c143
+
Kmods SIG 63c143
+		*undo_step = 4;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
+	return 0;
Kmods SIG 63c143
+}
Kmods SIG 63c143
+
Kmods SIG 63c143
+/*
Kmods SIG 63c143
+ * ni_remove_name_undo - Paired function for ni_remove_name.
Kmods SIG 63c143
+ *
Kmods SIG 63c143
+ * Return: True if ok
Kmods SIG 63c143
+ */
Kmods SIG 63c143
+bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG 63c143
+			 struct NTFS_DE *de, struct NTFS_DE *de2, int undo_step)
Kmods SIG 63c143
+{
Kmods SIG 63c143
+	struct ntfs_sb_info *sbi = ni->mi.sbi;
Kmods SIG 63c143
+	struct ATTRIB *attr;
Kmods SIG 63c143
+	u16 de_key_size = de2 ? le16_to_cpu(de2->key_size) : 0;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	switch (undo_step) {
Kmods SIG 63c143
+	case 4:
Kmods SIG 63c143
+		if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0,
Kmods SIG 63c143
+				       &attr, NULL, NULL)) {
Kmods SIG 63c143
+			return false;
Kmods SIG 63c143
+		}
Kmods SIG 63c143
+		memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de2 + 1, de_key_size);
Kmods SIG 63c143
+
Kmods SIG 63c143
+		mi_get_ref(&ni->mi, &de2->ref);
Kmods SIG 63c143
+		de2->size = cpu_to_le16(ALIGN(de_key_size, 8) +
Kmods SIG 63c143
+					sizeof(struct NTFS_DE));
Kmods SIG 63c143
+		de2->flags = 0;
Kmods SIG 63c143
+		de2->res = 0;
Kmods SIG 63c143
+
Kmods SIG 63c143
+		if (indx_insert_entry(&dir_ni->dir, dir_ni, de2, sbi, NULL,
Kmods SIG 63c143
+				      1)) {
Kmods SIG 63c143
+			return false;
Kmods SIG 63c143
+		}
Kmods SIG 63c143
+		fallthrough;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	case 2:
Kmods SIG 63c143
+		de_key_size = le16_to_cpu(de->key_size);
Kmods SIG 63c143
+
Kmods SIG 63c143
+		if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0,
Kmods SIG 63c143
+				       &attr, NULL, NULL)) {
Kmods SIG 63c143
+			return false;
Kmods SIG 63c143
+		}
Kmods SIG 63c143
+
Kmods SIG 63c143
+		memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size);
Kmods SIG 63c143
+		mi_get_ref(&ni->mi, &de->ref);
Kmods SIG 63c143
+
Kmods SIG 63c143
+		if (indx_insert_entry(&dir_ni->dir, dir_ni, de, sbi, NULL, 1)) {
Kmods SIG 63c143
+			return false;
Kmods SIG 63c143
+		}
Kmods SIG 63c143
+	}
Kmods SIG 63c143
+
Kmods SIG 63c143
+	return true;
Kmods SIG 63c143
+}
Kmods SIG 63c143
+
Kmods SIG 63c143
+/*
Kmods SIG 63c143
+ * ni_add_name - Add new name in MFT and in directory.
Kmods SIG 63c143
+ */
Kmods SIG 63c143
+int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG 63c143
+		struct NTFS_DE *de)
Kmods SIG 63c143
+{
Kmods SIG 63c143
+	int err;
Kmods SIG 63c143
+	struct ATTRIB *attr;
Kmods SIG 63c143
+	struct ATTR_LIST_ENTRY *le;
Kmods SIG 63c143
+	struct mft_inode *mi;
Kmods SIG 63c143
+	struct ATTR_FILE_NAME *de_name = (struct ATTR_FILE_NAME *)(de + 1);
Kmods SIG 63c143
+	u16 de_key_size = le16_to_cpu(de->key_size);
Kmods SIG 63c143
+
Kmods SIG 63c143
+	mi_get_ref(&ni->mi, &de->ref);
Kmods SIG 63c143
+	mi_get_ref(&dir_ni->mi, &de_name->home);
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/* Insert new name in MFT. */
Kmods SIG 63c143
+	err = ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0, &attr,
Kmods SIG 63c143
+				 &mi, &le);
Kmods SIG 63c143
+	if (err)
Kmods SIG 63c143
+		return err;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de_name, de_key_size);
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/* Insert new name in directory. */
Kmods SIG 63c143
+	err = indx_insert_entry(&dir_ni->dir, dir_ni, de, ni->mi.sbi, NULL, 0);
Kmods SIG 63c143
+	if (err)
Kmods SIG 63c143
+		ni_remove_attr_le(ni, attr, mi, le);
Kmods SIG 63c143
+
Kmods SIG 63c143
+	return err;
Kmods SIG 63c143
+}
Kmods SIG 63c143
+
Kmods SIG 63c143
+/*
Kmods SIG 63c143
+ * ni_rename - Remove one name and insert new name.
Kmods SIG 63c143
+ */
Kmods SIG 63c143
+int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
Kmods SIG 63c143
+	      struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de,
Kmods SIG 63c143
+	      bool *is_bad)
Kmods SIG 63c143
+{
Kmods SIG 63c143
+	int err;
Kmods SIG 63c143
+	struct NTFS_DE *de2 = NULL;
Kmods SIG 63c143
+	int undo = 0;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/*
Kmods SIG 63c143
+	 * There are two possible ways to rename:
Kmods SIG 63c143
+	 * 1) Add new name and remove old name.
Kmods SIG 63c143
+	 * 2) Remove old name and add new name.
Kmods SIG 63c143
+	 *
Kmods SIG 63c143
+	 * In most cases (not all!) adding new name in MFT and in directory can
Kmods SIG 63c143
+	 * allocate additional cluster(s).
Kmods SIG 63c143
+	 * Second way may result to bad inode if we can't add new name
Kmods SIG 63c143
+	 * and then can't restore (add) old name.
Kmods SIG 63c143
+	 */
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/*
Kmods SIG 63c143
+	 * Way 1 - Add new + remove old.
Kmods SIG 63c143
+	 */
Kmods SIG 63c143
+	err = ni_add_name(new_dir_ni, ni, new_de);
Kmods SIG 63c143
+	if (!err) {
Kmods SIG 63c143
+		err = ni_remove_name(dir_ni, ni, de, &de2, &undo);
Kmods SIG 63c143
+		if (err && ni_remove_name(new_dir_ni, ni, new_de, &de2, &undo))
Kmods SIG 63c143
+			*is_bad = true;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
+
Kmods SIG 63c143
+	/*
Kmods SIG 63c143
+	 * Way 2 - Remove old + add new.
Kmods SIG 63c143
+	 */
Kmods SIG 63c143
+	/*
Kmods SIG 63c143
+	 *	err = ni_remove_name(dir_ni, ni, de, &de2, &undo);
Kmods SIG 63c143
+	 *	if (!err) {
Kmods SIG 63c143
+	 *		err = ni_add_name(new_dir_ni, ni, new_de);
Kmods SIG 63c143
+	 *		if (err && !ni_remove_name_undo(dir_ni, ni, de, de2, undo))
Kmods SIG 63c143
+	 *			*is_bad = true;
Kmods SIG 63c143
+	 *	}
Kmods SIG 63c143
+	 */
Kmods SIG 63c143
+
Kmods SIG 63c143
+	return err;
Kmods SIG 63c143
+}
Kmods SIG 63c143
+
Kmods SIG 63c143
+/*
Kmods SIG 63c143
+ * ni_is_dirty - Return: True if 'ni' requires ni_write_inode.
Kmods SIG 63c143
+ */
Kmods SIG 63c143
+bool ni_is_dirty(struct inode *inode)
Kmods SIG 63c143
+{
Kmods SIG 63c143
+	struct ntfs_inode *ni = ntfs_i(inode);
Kmods SIG 63c143
+	struct rb_node *node;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	if (ni->mi.dirty || ni->attr_list.dirty ||
Kmods SIG 63c143
+	    (ni->ni_flags & NI_FLAG_UPDATE_PARENT))
Kmods SIG 63c143
+		return true;
Kmods SIG 63c143
+
Kmods SIG 63c143
+	for (node = rb_first(&ni->mi_tree); node; node = rb_next(node)) {
Kmods SIG 63c143
+		if (rb_entry(node, struct mft_inode, node)->dirty)
Kmods SIG 63c143
+			return true;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
+
Kmods SIG 63c143
+	return false;
Kmods SIG 63c143
+}
Kmods SIG 63c143
+
Kmods SIG 63c143
 /*
Kmods SIG 63c143
  * ni_update_parent
Kmods SIG 63c143
  *
Kmods SIG 63c143
@@ -2802,8 +3028,6 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
Kmods SIG 63c143
 	struct ntfs_sb_info *sbi = ni->mi.sbi;
Kmods SIG 63c143
 	struct super_block *sb = sbi->sb;
Kmods SIG 63c143
 	bool re_dirty = false;
Kmods SIG 63c143
-	bool active = sb->s_flags & SB_ACTIVE;
Kmods SIG 63c143
-	bool upd_parent = ni->ni_flags & NI_FLAG_UPDATE_PARENT;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (ni->mi.mrec->flags & RECORD_FLAG_DIR) {
Kmods SIG 63c143
 		dup->fa |= FILE_ATTRIBUTE_DIRECTORY;
Kmods SIG 63c143
@@ -2867,19 +3091,9 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
Kmods SIG 63c143
 		struct ATTR_FILE_NAME *fname;
Kmods SIG 63c143
 
Kmods SIG 63c143
 		fname = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME);
Kmods SIG 63c143
-		if (!fname)
Kmods SIG 63c143
+		if (!fname || !memcmp(&fname->dup, dup, sizeof(fname->dup)))
Kmods SIG 63c143
 			continue;
Kmods SIG 63c143
 
Kmods SIG 63c143
-		if (memcmp(&fname->dup, dup, sizeof(fname->dup))) {
Kmods SIG 63c143
-			memcpy(&fname->dup, dup, sizeof(fname->dup));
Kmods SIG 63c143
-			mi->dirty = true;
Kmods SIG 63c143
-		} else if (!upd_parent) {
Kmods SIG 63c143
-			continue;
Kmods SIG 63c143
-		}
Kmods SIG 63c143
-
Kmods SIG 63c143
-		if (!active)
Kmods SIG 63c143
-			continue; /* Avoid __wait_on_freeing_inode(inode); */
Kmods SIG 63c143
-
Kmods SIG 63c143
 		/* ntfs_iget5 may sleep. */
Kmods SIG 63c143
 		dir = ntfs_iget5(sb, &fname->home, NULL);
Kmods SIG 63c143
 		if (IS_ERR(dir)) {
Kmods SIG 63c143
@@ -2898,6 +3112,8 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
Kmods SIG 63c143
 			} else {
Kmods SIG 63c143
 				indx_update_dup(dir_ni, sbi, fname, dup, sync);
Kmods SIG 63c143
 				ni_unlock(dir_ni);
Kmods SIG 63c143
+				memcpy(&fname->dup, dup, sizeof(fname->dup));
Kmods SIG 63c143
+				mi->dirty = true;
Kmods SIG 63c143
 			}
Kmods SIG 63c143
 		}
Kmods SIG 63c143
 		iput(dir);
Kmods SIG 63c143
@@ -2969,7 +3185,9 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
Kmods SIG 63c143
 			ni->mi.dirty = true;
Kmods SIG 63c143
 
Kmods SIG 63c143
 		if (!ntfs_is_meta_file(sbi, inode->i_ino) &&
Kmods SIG 63c143
-		    (modified || (ni->ni_flags & NI_FLAG_UPDATE_PARENT))) {
Kmods SIG 63c143
+		    (modified || (ni->ni_flags & NI_FLAG_UPDATE_PARENT))
Kmods SIG 63c143
+		    /* Avoid __wait_on_freeing_inode(inode). */
Kmods SIG 63c143
+		    && (sb->s_flags & SB_ACTIVE)) {
Kmods SIG 63c143
 			dup.cr_time = std->cr_time;
Kmods SIG 63c143
 			/* Not critical if this function fail. */
Kmods SIG 63c143
 			re_dirty = ni_update_parent(ni, &dup, sync);
Kmods SIG 63c143
@@ -3033,7 +3251,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
Kmods SIG 63c143
 		return err;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-	if (re_dirty && (sb->s_flags & SB_ACTIVE))
Kmods SIG 63c143
+	if (re_dirty)
Kmods SIG 63c143
 		mark_inode_dirty_sync(inode);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	return 0;
Kmods SIG 63c143
diff --git a/src/fsntfs.c b/src/fsntfs.c
Kmods SIG 63c143
index 0edb95ed9717f442f97b3ba3e85b4b6a361e0e27..66924943921771d3cf46f6a762b1ea81ae1e9ca2 100644
Kmods SIG 63c143
--- a/src/fsntfs.c
Kmods SIG 63c143
+++ b/src/fsntfs.c
Kmods SIG 63c143
@@ -358,29 +358,25 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
Kmods SIG 63c143
 			     enum ALLOCATE_OPT opt)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
+	CLST alen = 0;
Kmods SIG 63c143
 	struct super_block *sb = sbi->sb;
Kmods SIG 63c143
-	size_t a_lcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
Kmods SIG 63c143
+	size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
Kmods SIG 63c143
 	struct wnd_bitmap *wnd = &sbi->used.bitmap;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
Kmods SIG 63c143
 	if (opt & ALLOCATE_MFT) {
Kmods SIG 63c143
-		CLST alen;
Kmods SIG 63c143
-
Kmods SIG 63c143
 		zlen = wnd_zone_len(wnd);
Kmods SIG 63c143
 
Kmods SIG 63c143
 		if (!zlen) {
Kmods SIG 63c143
 			err = ntfs_refresh_zone(sbi);
Kmods SIG 63c143
 			if (err)
Kmods SIG 63c143
 				goto out;
Kmods SIG 63c143
-
Kmods SIG 63c143
 			zlen = wnd_zone_len(wnd);
Kmods SIG 63c143
+		}
Kmods SIG 63c143
 
Kmods SIG 63c143
-			if (!zlen) {
Kmods SIG 63c143
-				ntfs_err(sbi->sb,
Kmods SIG 63c143
-					 "no free space to extend mft");
Kmods SIG 63c143
-				err = -ENOSPC;
Kmods SIG 63c143
-				goto out;
Kmods SIG 63c143
-			}
Kmods SIG 63c143
+		if (!zlen) {
Kmods SIG 63c143
+			ntfs_err(sbi->sb, "no free space to extend mft");
Kmods SIG 63c143
+			goto out;
Kmods SIG 63c143
 		}
Kmods SIG 63c143
 
Kmods SIG 63c143
 		lcn = wnd_zone_bit(wnd);
Kmods SIG 63c143
@@ -389,14 +385,13 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
Kmods SIG 63c143
 		wnd_zone_set(wnd, lcn + alen, zlen - alen);
Kmods SIG 63c143
 
Kmods SIG 63c143
 		err = wnd_set_used(wnd, lcn, alen);
Kmods SIG 63c143
-		if (err)
Kmods SIG 63c143
-			goto out;
Kmods SIG 63c143
-
Kmods SIG 63c143
-		*new_lcn = lcn;
Kmods SIG 63c143
-		*new_len = alen;
Kmods SIG 63c143
-		goto ok;
Kmods SIG 63c143
+		if (err) {
Kmods SIG 63c143
+			up_write(&wnd->rw_lock);
Kmods SIG 63c143
+			return err;
Kmods SIG 63c143
+		}
Kmods SIG 63c143
+		alcn = lcn;
Kmods SIG 63c143
+		goto out;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
-
Kmods SIG 63c143
 	/*
Kmods SIG 63c143
 	 * 'Cause cluster 0 is always used this value means that we should use
Kmods SIG 63c143
 	 * cached value of 'next_free_lcn' to improve performance.
Kmods SIG 63c143
@@ -407,22 +402,17 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
Kmods SIG 63c143
 	if (lcn >= wnd->nbits)
Kmods SIG 63c143
 		lcn = 0;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	*new_len = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &a_lcn);
Kmods SIG 63c143
-	if (*new_len) {
Kmods SIG 63c143
-		*new_lcn = a_lcn;
Kmods SIG 63c143
-		goto ok;
Kmods SIG 63c143
-	}
Kmods SIG 63c143
+	alen = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &alcn);
Kmods SIG 63c143
+	if (alen)
Kmods SIG 63c143
+		goto out;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/* Try to use clusters from MftZone. */
Kmods SIG 63c143
 	zlen = wnd_zone_len(wnd);
Kmods SIG 63c143
 	zeroes = wnd_zeroes(wnd);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	/* Check too big request. */
Kmods SIG 63c143
-	if (len > zeroes + zlen)
Kmods SIG 63c143
-		goto no_space;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	if (zlen <= NTFS_MIN_MFT_ZONE)
Kmods SIG 63c143
-		goto no_space;
Kmods SIG 63c143
+	/* Check too big request */
Kmods SIG 63c143
+	if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE)
Kmods SIG 63c143
+		goto out;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/* How many clusters to cat from zone. */
Kmods SIG 63c143
 	zlcn = wnd_zone_bit(wnd);
Kmods SIG 63c143
@@ -439,31 +429,24 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
Kmods SIG 63c143
 	wnd_zone_set(wnd, zlcn, new_zlen);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/* Allocate continues clusters. */
Kmods SIG 63c143
-	*new_len =
Kmods SIG 63c143
-		wnd_find(wnd, len, 0,
Kmods SIG 63c143
-			 BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &a_lcn);
Kmods SIG 63c143
-	if (*new_len) {
Kmods SIG 63c143
-		*new_lcn = a_lcn;
Kmods SIG 63c143
-		goto ok;
Kmods SIG 63c143
-	}
Kmods SIG 63c143
-
Kmods SIG 63c143
-no_space:
Kmods SIG 63c143
-	up_write(&wnd->rw_lock);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	return -ENOSPC;
Kmods SIG 63c143
-
Kmods SIG 63c143
-ok:
Kmods SIG 63c143
-	err = 0;
Kmods SIG 63c143
+	alen = wnd_find(wnd, len, 0,
Kmods SIG 63c143
+			BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	ntfs_unmap_meta(sb, *new_lcn, *new_len);
Kmods SIG 63c143
+out:
Kmods SIG 63c143
+	if (alen) {
Kmods SIG 63c143
+		err = 0;
Kmods SIG 63c143
+		*new_len = alen;
Kmods SIG 63c143
+		*new_lcn = alcn;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	if (opt & ALLOCATE_MFT)
Kmods SIG 63c143
-		goto out;
Kmods SIG 63c143
+		ntfs_unmap_meta(sb, alcn, alen);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	/* Set hint for next requests. */
Kmods SIG 63c143
-	sbi->used.next_free_lcn = *new_lcn + *new_len;
Kmods SIG 63c143
+		/* Set hint for next requests. */
Kmods SIG 63c143
+		if (!(opt & ALLOCATE_MFT))
Kmods SIG 63c143
+			sbi->used.next_free_lcn = alcn + alen;
Kmods SIG 63c143
+	} else {
Kmods SIG 63c143
+		err = -ENOSPC;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-out:
Kmods SIG 63c143
 	up_write(&wnd->rw_lock);
Kmods SIG 63c143
 	return err;
Kmods SIG 63c143
 }
Kmods SIG 63c143
@@ -2226,7 +2209,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
Kmods SIG 63c143
 	sii_e.sec_id = d_security->key.sec_id;
Kmods SIG 63c143
 	memcpy(&sii_e.sec_hdr, d_security, SIZEOF_SECURITY_HDR);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL);
Kmods SIG 63c143
+	err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL, 0);
Kmods SIG 63c143
 	if (err)
Kmods SIG 63c143
 		goto out;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -2247,7 +2230,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	fnd_clear(fnd_sdh);
Kmods SIG 63c143
 	err = indx_insert_entry(indx_sdh, ni, &sdh_e.de, (void *)(size_t)1,
Kmods SIG 63c143
-				fnd_sdh);
Kmods SIG 63c143
+				fnd_sdh, 0);
Kmods SIG 63c143
 	if (err)
Kmods SIG 63c143
 		goto out;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -2385,7 +2368,7 @@ int ntfs_insert_reparse(struct ntfs_sb_info *sbi, __le32 rtag,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_REPARSE);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	err = indx_insert_entry(indx, ni, &re.de, NULL, NULL);
Kmods SIG 63c143
+	err = indx_insert_entry(indx, ni, &re.de, NULL, NULL, 0);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	mark_inode_dirty(&ni->vfs_inode);
Kmods SIG 63c143
 	ni_unlock(ni);
Kmods SIG 63c143
diff --git a/src/index.c b/src/index.c
Kmods SIG 63c143
index 70ef59455b72c927b40bbb76c5420b8dfc72e24a..1224b8e42b3e3d07938310739843f0ab7195f326 100644
Kmods SIG 63c143
--- a/src/index.c
Kmods SIG 63c143
+++ b/src/index.c
Kmods SIG 63c143
@@ -1427,7 +1427,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 	alloc->nres.valid_size = alloc->nres.data_size = cpu_to_le64(data_size);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	err = ni_insert_resident(ni, bitmap_size(1), ATTR_BITMAP, in->name,
Kmods SIG 63c143
-				 in->name_len, &bitmap, NULL);
Kmods SIG 63c143
+				 in->name_len, &bitmap, NULL, NULL);
Kmods SIG 63c143
 	if (err)
Kmods SIG 63c143
 		goto out2;
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -1443,7 +1443,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 	return 0;
Kmods SIG 63c143
 
Kmods SIG 63c143
 out2:
Kmods SIG 63c143
-	mi_remove_attr(&ni->mi, alloc);
Kmods SIG 63c143
+	mi_remove_attr(NULL, &ni->mi, alloc);
Kmods SIG 63c143
 
Kmods SIG 63c143
 out1:
Kmods SIG 63c143
 	run_deallocate(sbi, &run, false);
Kmods SIG 63c143
@@ -1529,24 +1529,24 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 /*
Kmods SIG 63c143
  * indx_insert_into_root - Attempt to insert an entry into the index root.
Kmods SIG 63c143
  *
Kmods SIG 63c143
+ * @undo - True if we undoing previous remove.
Kmods SIG 63c143
  * If necessary, it will twiddle the index b-tree.
Kmods SIG 63c143
  */
Kmods SIG 63c143
 static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 				 const struct NTFS_DE *new_de,
Kmods SIG 63c143
 				 struct NTFS_DE *root_de, const void *ctx,
Kmods SIG 63c143
-				 struct ntfs_fnd *fnd)
Kmods SIG 63c143
+				 struct ntfs_fnd *fnd, bool undo)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	int err = 0;
Kmods SIG 63c143
 	struct NTFS_DE *e, *e0, *re;
Kmods SIG 63c143
 	struct mft_inode *mi;
Kmods SIG 63c143
 	struct ATTRIB *attr;
Kmods SIG 63c143
-	struct MFT_REC *rec;
Kmods SIG 63c143
 	struct INDEX_HDR *hdr;
Kmods SIG 63c143
 	struct indx_node *n;
Kmods SIG 63c143
 	CLST new_vbn;
Kmods SIG 63c143
 	__le64 *sub_vbn, t_vbn;
Kmods SIG 63c143
 	u16 new_de_size;
Kmods SIG 63c143
-	u32 hdr_used, hdr_total, asize, used, to_move;
Kmods SIG 63c143
+	u32 hdr_used, hdr_total, asize, to_move;
Kmods SIG 63c143
 	u32 root_size, new_root_size;
Kmods SIG 63c143
 	struct ntfs_sb_info *sbi;
Kmods SIG 63c143
 	int ds_root;
Kmods SIG 63c143
@@ -1559,12 +1559,11 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/*
Kmods SIG 63c143
 	 * Try easy case:
Kmods SIG 63c143
-	 * hdr_insert_de will succeed if there's room the root for the new entry.
Kmods SIG 63c143
+	 * hdr_insert_de will succeed if there's
Kmods SIG 63c143
+	 * room the root for the new entry.
Kmods SIG 63c143
 	 */
Kmods SIG 63c143
 	hdr = &root->ihdr;
Kmods SIG 63c143
 	sbi = ni->mi.sbi;
Kmods SIG 63c143
-	rec = mi->mrec;
Kmods SIG 63c143
-	used = le32_to_cpu(rec->used);
Kmods SIG 63c143
 	new_de_size = le16_to_cpu(new_de->size);
Kmods SIG 63c143
 	hdr_used = le32_to_cpu(hdr->used);
Kmods SIG 63c143
 	hdr_total = le32_to_cpu(hdr->total);
Kmods SIG 63c143
@@ -1573,9 +1572,9 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	ds_root = new_de_size + hdr_used - hdr_total;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	if (used + ds_root < sbi->max_bytes_per_attr) {
Kmods SIG 63c143
-		/* Make a room for new elements. */
Kmods SIG 63c143
-		mi_resize_attr(mi, attr, ds_root);
Kmods SIG 63c143
+	/* If 'undo' is set then reduce requirements. */
Kmods SIG 63c143
+	if ((undo || asize + ds_root < sbi->max_bytes_per_attr) &&
Kmods SIG 63c143
+	    mi_resize_attr(mi, attr, ds_root)) {
Kmods SIG 63c143
 		hdr->total = cpu_to_le32(hdr_total + ds_root);
Kmods SIG 63c143
 		e = hdr_insert_de(indx, hdr, new_de, root_de, ctx);
Kmods SIG 63c143
 		WARN_ON(!e);
Kmods SIG 63c143
@@ -1629,7 +1628,7 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 			sizeof(u64);
Kmods SIG 63c143
 	ds_root = new_root_size - root_size;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	if (ds_root > 0 && used + ds_root > sbi->max_bytes_per_attr) {
Kmods SIG 63c143
+	if (ds_root > 0 && asize + ds_root > sbi->max_bytes_per_attr) {
Kmods SIG 63c143
 		/* Make root external. */
Kmods SIG 63c143
 		err = -EOPNOTSUPP;
Kmods SIG 63c143
 		goto out_free_re;
Kmods SIG 63c143
@@ -1710,7 +1709,7 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 
Kmods SIG 63c143
 		put_indx_node(n);
Kmods SIG 63c143
 		fnd_clear(fnd);
Kmods SIG 63c143
-		err = indx_insert_entry(indx, ni, new_de, ctx, fnd);
Kmods SIG 63c143
+		err = indx_insert_entry(indx, ni, new_de, ctx, fnd, undo);
Kmods SIG 63c143
 		goto out_free_root;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -1854,7 +1853,7 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 	 */
Kmods SIG 63c143
 	if (!level) {
Kmods SIG 63c143
 		/* Insert in root. */
Kmods SIG 63c143
-		err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd);
Kmods SIG 63c143
+		err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd, 0);
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
 			goto out;
Kmods SIG 63c143
 	} else {
Kmods SIG 63c143
@@ -1876,10 +1875,12 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 
Kmods SIG 63c143
 /*
Kmods SIG 63c143
  * indx_insert_entry - Insert new entry into index.
Kmods SIG 63c143
+ *
Kmods SIG 63c143
+ * @undo - True if we undoing previous remove.
Kmods SIG 63c143
  */
Kmods SIG 63c143
 int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 		      const struct NTFS_DE *new_de, const void *ctx,
Kmods SIG 63c143
-		      struct ntfs_fnd *fnd)
Kmods SIG 63c143
+		      struct ntfs_fnd *fnd, bool undo)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
 	int diff;
Kmods SIG 63c143
@@ -1925,7 +1926,7 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 		 * new entry into it.
Kmods SIG 63c143
 		 */
Kmods SIG 63c143
 		err = indx_insert_into_root(indx, ni, new_de, fnd->root_de, ctx,
Kmods SIG 63c143
-					    fnd);
Kmods SIG 63c143
+					    fnd, undo);
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
 			goto out;
Kmods SIG 63c143
 	} else {
Kmods SIG 63c143
@@ -2302,7 +2303,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 							      fnd->level - 1,
Kmods SIG 63c143
 							      fnd)
Kmods SIG 63c143
 				    : indx_insert_into_root(indx, ni, re, e,
Kmods SIG 63c143
-							    ctx, fnd);
Kmods SIG 63c143
+							    ctx, fnd, 0);
Kmods SIG 63c143
 			kfree(re);
Kmods SIG 63c143
 
Kmods SIG 63c143
 			if (err)
Kmods SIG 63c143
@@ -2507,7 +2508,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 		 * Re-insert the entry into the tree.
Kmods SIG 63c143
 		 * Find the spot the tree where we want to insert the new entry.
Kmods SIG 63c143
 		 */
Kmods SIG 63c143
-		err = indx_insert_entry(indx, ni, me, ctx, fnd);
Kmods SIG 63c143
+		err = indx_insert_entry(indx, ni, me, ctx, fnd, 0);
Kmods SIG 63c143
 		kfree(me);
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
 			goto out;
Kmods SIG 63c143
@@ -2595,10 +2596,8 @@ int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
Kmods SIG 63c143
 	struct ntfs_index *indx = &ni->dir;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	fnd = fnd_get();
Kmods SIG 63c143
-	if (!fnd) {
Kmods SIG 63c143
-		err = -ENOMEM;
Kmods SIG 63c143
-		goto out1;
Kmods SIG 63c143
-	}
Kmods SIG 63c143
+	if (!fnd)
Kmods SIG 63c143
+		return -ENOMEM;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	root = indx_get_root(indx, ni, NULL, &mi);
Kmods SIG 63c143
 	if (!root) {
Kmods SIG 63c143
@@ -2645,7 +2644,5 @@ int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
Kmods SIG 63c143
 
Kmods SIG 63c143
 out:
Kmods SIG 63c143
 	fnd_put(fnd);
Kmods SIG 63c143
-
Kmods SIG 63c143
-out1:
Kmods SIG 63c143
 	return err;
Kmods SIG 63c143
 }
Kmods SIG 63c143
diff --git a/src/inode.c b/src/inode.c
Kmods SIG 63c143
index b86ec7dd731cea9fd0b41abb40fe4d81ca965c13..8f72066b3229a3f87b7b0b0e770bce20a4b06edd 100644
Kmods SIG 63c143
--- a/src/inode.c
Kmods SIG 63c143
+++ b/src/inode.c
Kmods SIG 63c143
@@ -399,6 +399,12 @@ static struct inode *ntfs_read_mft(struct inode *inode,
Kmods SIG 63c143
 		goto out;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
+	if (names != le16_to_cpu(rec->hard_links)) {
Kmods SIG 63c143
+		/* Correct minor error on the fly. Do not mark inode as dirty. */
Kmods SIG 63c143
+		rec->hard_links = cpu_to_le16(names);
Kmods SIG 63c143
+		ni->mi.dirty = true;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
+
Kmods SIG 63c143
 	set_nlink(inode, names);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (S_ISDIR(mode)) {
Kmods SIG 63c143
@@ -1279,6 +1285,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 	inode = &ni->vfs_inode;
Kmods SIG 63c143
 	inode_init_owner(mnt_userns, inode, dir, mode);
Kmods SIG 63c143
+	mode = inode->i_mode;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	inode->i_atime = inode->i_mtime = inode->i_ctime = ni->i_crtime =
Kmods SIG 63c143
 		current_time(inode);
Kmods SIG 63c143
@@ -1371,6 +1378,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 		attr = Add2Ptr(attr, asize);
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
+	attr->id = cpu_to_le16(aid++);
Kmods SIG 63c143
 	if (fa & FILE_ATTRIBUTE_DIRECTORY) {
Kmods SIG 63c143
 		/*
Kmods SIG 63c143
 		 * Regular directory or symlink to directory.
Kmods SIG 63c143
@@ -1381,7 +1389,6 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 
Kmods SIG 63c143
 		attr->type = ATTR_ROOT;
Kmods SIG 63c143
 		attr->size = cpu_to_le32(asize);
Kmods SIG 63c143
-		attr->id = cpu_to_le16(aid++);
Kmods SIG 63c143
 
Kmods SIG 63c143
 		attr->name_len = ARRAY_SIZE(I30_NAME);
Kmods SIG 63c143
 		attr->name_off = SIZEOF_RESIDENT_LE;
Kmods SIG 63c143
@@ -1412,52 +1419,46 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 		/* Insert empty ATTR_DATA */
Kmods SIG 63c143
 		attr->type = ATTR_DATA;
Kmods SIG 63c143
 		attr->size = cpu_to_le32(SIZEOF_RESIDENT);
Kmods SIG 63c143
-		attr->id = cpu_to_le16(aid++);
Kmods SIG 63c143
 		attr->name_off = SIZEOF_RESIDENT_LE;
Kmods SIG 63c143
 		attr->res.data_off = SIZEOF_RESIDENT_LE;
Kmods SIG 63c143
-	} else {
Kmods SIG 63c143
+	} else if (S_ISREG(mode)) {
Kmods SIG 63c143
 		/*
Kmods SIG 63c143
-		 * Regular file or node.
Kmods SIG 63c143
+		 * Regular file. Create empty non resident data attribute.
Kmods SIG 63c143
 		 */
Kmods SIG 63c143
 		attr->type = ATTR_DATA;
Kmods SIG 63c143
-		attr->id = cpu_to_le16(aid++);
Kmods SIG 63c143
-
Kmods SIG 63c143
-		if (S_ISREG(mode)) {
Kmods SIG 63c143
-			/* Create empty non resident data attribute. */
Kmods SIG 63c143
-			attr->non_res = 1;
Kmods SIG 63c143
-			attr->nres.evcn = cpu_to_le64(-1ll);
Kmods SIG 63c143
-			if (fa & FILE_ATTRIBUTE_SPARSE_FILE) {
Kmods SIG 63c143
-				attr->size =
Kmods SIG 63c143
-					cpu_to_le32(SIZEOF_NONRESIDENT_EX + 8);
Kmods SIG 63c143
-				attr->name_off = SIZEOF_NONRESIDENT_EX_LE;
Kmods SIG 63c143
-				attr->flags = ATTR_FLAG_SPARSED;
Kmods SIG 63c143
-				asize = SIZEOF_NONRESIDENT_EX + 8;
Kmods SIG 63c143
-			} else if (fa & FILE_ATTRIBUTE_COMPRESSED) {
Kmods SIG 63c143
-				attr->size =
Kmods SIG 63c143
-					cpu_to_le32(SIZEOF_NONRESIDENT_EX + 8);
Kmods SIG 63c143
-				attr->name_off = SIZEOF_NONRESIDENT_EX_LE;
Kmods SIG 63c143
-				attr->flags = ATTR_FLAG_COMPRESSED;
Kmods SIG 63c143
-				attr->nres.c_unit = COMPRESSION_UNIT;
Kmods SIG 63c143
-				asize = SIZEOF_NONRESIDENT_EX + 8;
Kmods SIG 63c143
-			} else {
Kmods SIG 63c143
-				attr->size =
Kmods SIG 63c143
-					cpu_to_le32(SIZEOF_NONRESIDENT + 8);
Kmods SIG 63c143
-				attr->name_off = SIZEOF_NONRESIDENT_LE;
Kmods SIG 63c143
-				asize = SIZEOF_NONRESIDENT + 8;
Kmods SIG 63c143
-			}
Kmods SIG 63c143
-			attr->nres.run_off = attr->name_off;
Kmods SIG 63c143
+		attr->non_res = 1;
Kmods SIG 63c143
+		attr->nres.evcn = cpu_to_le64(-1ll);
Kmods SIG 63c143
+		if (fa & FILE_ATTRIBUTE_SPARSE_FILE) {
Kmods SIG 63c143
+			attr->size = cpu_to_le32(SIZEOF_NONRESIDENT_EX + 8);
Kmods SIG 63c143
+			attr->name_off = SIZEOF_NONRESIDENT_EX_LE;
Kmods SIG 63c143
+			attr->flags = ATTR_FLAG_SPARSED;
Kmods SIG 63c143
+			asize = SIZEOF_NONRESIDENT_EX + 8;
Kmods SIG 63c143
+		} else if (fa & FILE_ATTRIBUTE_COMPRESSED) {
Kmods SIG 63c143
+			attr->size = cpu_to_le32(SIZEOF_NONRESIDENT_EX + 8);
Kmods SIG 63c143
+			attr->name_off = SIZEOF_NONRESIDENT_EX_LE;
Kmods SIG 63c143
+			attr->flags = ATTR_FLAG_COMPRESSED;
Kmods SIG 63c143
+			attr->nres.c_unit = COMPRESSION_UNIT;
Kmods SIG 63c143
+			asize = SIZEOF_NONRESIDENT_EX + 8;
Kmods SIG 63c143
 		} else {
Kmods SIG 63c143
-			/* Create empty resident data attribute. */
Kmods SIG 63c143
-			attr->size = cpu_to_le32(SIZEOF_RESIDENT);
Kmods SIG 63c143
-			attr->name_off = SIZEOF_RESIDENT_LE;
Kmods SIG 63c143
-			if (fa & FILE_ATTRIBUTE_SPARSE_FILE)
Kmods SIG 63c143
-				attr->flags = ATTR_FLAG_SPARSED;
Kmods SIG 63c143
-			else if (fa & FILE_ATTRIBUTE_COMPRESSED)
Kmods SIG 63c143
-				attr->flags = ATTR_FLAG_COMPRESSED;
Kmods SIG 63c143
-			attr->res.data_off = SIZEOF_RESIDENT_LE;
Kmods SIG 63c143
-			asize = SIZEOF_RESIDENT;
Kmods SIG 63c143
-			ni->ni_flags |= NI_FLAG_RESIDENT;
Kmods SIG 63c143
+			attr->size = cpu_to_le32(SIZEOF_NONRESIDENT + 8);
Kmods SIG 63c143
+			attr->name_off = SIZEOF_NONRESIDENT_LE;
Kmods SIG 63c143
+			asize = SIZEOF_NONRESIDENT + 8;
Kmods SIG 63c143
 		}
Kmods SIG 63c143
+		attr->nres.run_off = attr->name_off;
Kmods SIG 63c143
+	} else {
Kmods SIG 63c143
+		/*
Kmods SIG 63c143
+		 * Node. Create empty resident data attribute.
Kmods SIG 63c143
+		 */
Kmods SIG 63c143
+		attr->type = ATTR_DATA;
Kmods SIG 63c143
+		attr->size = cpu_to_le32(SIZEOF_RESIDENT);
Kmods SIG 63c143
+		attr->name_off = SIZEOF_RESIDENT_LE;
Kmods SIG 63c143
+		if (fa & FILE_ATTRIBUTE_SPARSE_FILE)
Kmods SIG 63c143
+			attr->flags = ATTR_FLAG_SPARSED;
Kmods SIG 63c143
+		else if (fa & FILE_ATTRIBUTE_COMPRESSED)
Kmods SIG 63c143
+			attr->flags = ATTR_FLAG_COMPRESSED;
Kmods SIG 63c143
+		attr->res.data_off = SIZEOF_RESIDENT_LE;
Kmods SIG 63c143
+		asize = SIZEOF_RESIDENT;
Kmods SIG 63c143
+		ni->ni_flags |= NI_FLAG_RESIDENT;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (S_ISDIR(mode)) {
Kmods SIG 63c143
@@ -1485,7 +1486,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 		asize = ALIGN(SIZEOF_RESIDENT + nsize, 8);
Kmods SIG 63c143
 		t16 = PtrOffset(rec, attr);
Kmods SIG 63c143
 
Kmods SIG 63c143
-		if (asize + t16 + 8 > sbi->record_size) {
Kmods SIG 63c143
+		/* 0x78 - the size of EA + EAINFO to store WSL */
Kmods SIG 63c143
+		if (asize + t16 + 0x78 + 8 > sbi->record_size) {
Kmods SIG 63c143
 			CLST alen;
Kmods SIG 63c143
 			CLST clst = bytes_to_cluster(sbi, nsize);
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -1545,20 +1547,15 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 	rec->next_attr_id = cpu_to_le16(aid);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/* Step 2: Add new name in index. */
Kmods SIG 63c143
-	err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd);
Kmods SIG 63c143
+	err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd, 0);
Kmods SIG 63c143
 	if (err)
Kmods SIG 63c143
 		goto out6;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	/* Update current directory record. */
Kmods SIG 63c143
-	mark_inode_dirty(dir);
Kmods SIG 63c143
-
Kmods SIG 63c143
 	inode->i_generation = le16_to_cpu(rec->seq);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	dir->i_mtime = dir->i_ctime = inode->i_atime;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (S_ISDIR(mode)) {
Kmods SIG 63c143
-		if (dir->i_mode & S_ISGID)
Kmods SIG 63c143
-			mode |= S_ISGID;
Kmods SIG 63c143
 		inode->i_op = &ntfs_dir_inode_operations;
Kmods SIG 63c143
 		inode->i_fop = &ntfs_dir_operations;
Kmods SIG 63c143
 	} else if (S_ISLNK(mode)) {
Kmods SIG 63c143
@@ -1601,8 +1598,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 	d_instantiate(dentry, inode);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	ntfs_save_wsl_perm(inode);
Kmods SIG 63c143
-	mark_inode_dirty(inode);
Kmods SIG 63c143
 	mark_inode_dirty(dir);
Kmods SIG 63c143
+	mark_inode_dirty(inode);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/* Normal exit. */
Kmods SIG 63c143
 	goto out2;
Kmods SIG 63c143
@@ -1646,61 +1643,36 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
-	struct inode *dir = d_inode(dentry->d_parent);
Kmods SIG 63c143
-	struct ntfs_inode *dir_ni = ntfs_i(dir);
Kmods SIG 63c143
 	struct ntfs_inode *ni = ntfs_i(inode);
Kmods SIG 63c143
-	struct super_block *sb = inode->i_sb;
Kmods SIG 63c143
-	struct ntfs_sb_info *sbi = sb->s_fs_info;
Kmods SIG 63c143
-	const struct qstr *name = &dentry->d_name;
Kmods SIG 63c143
-	struct NTFS_DE *new_de = NULL;
Kmods SIG 63c143
-	struct ATTR_FILE_NAME *fname;
Kmods SIG 63c143
-	struct ATTRIB *attr;
Kmods SIG 63c143
-	u16 key_size;
Kmods SIG 63c143
-	struct INDEX_ROOT *dir_root;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	dir_root = indx_get_root(&dir_ni->dir, dir_ni, NULL, NULL);
Kmods SIG 63c143
-	if (!dir_root)
Kmods SIG 63c143
-		return -EINVAL;
Kmods SIG 63c143
+	struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
Kmods SIG 63c143
+	struct NTFS_DE *de;
Kmods SIG 63c143
+	struct ATTR_FILE_NAME *de_name;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/* Allocate PATH_MAX bytes. */
Kmods SIG 63c143
-	new_de = __getname();
Kmods SIG 63c143
-	if (!new_de)
Kmods SIG 63c143
+	de = __getname();
Kmods SIG 63c143
+	if (!de)
Kmods SIG 63c143
 		return -ENOMEM;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	/* Mark rw ntfs as dirty.  It will be cleared at umount. */
Kmods SIG 63c143
-	ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_DIRTY);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Insert file name. */
Kmods SIG 63c143
-	err = fill_name_de(sbi, new_de, name, NULL);
Kmods SIG 63c143
-	if (err)
Kmods SIG 63c143
-		goto out;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	key_size = le16_to_cpu(new_de->key_size);
Kmods SIG 63c143
-	err = ni_insert_resident(ni, key_size, ATTR_NAME, NULL, 0, &attr, NULL);
Kmods SIG 63c143
-	if (err)
Kmods SIG 63c143
-		goto out;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	mi_get_ref(&ni->mi, &new_de->ref);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	fname = (struct ATTR_FILE_NAME *)(new_de + 1);
Kmods SIG 63c143
-	mi_get_ref(&dir_ni->mi, &fname->home);
Kmods SIG 63c143
-	fname->dup.cr_time = fname->dup.m_time = fname->dup.c_time =
Kmods SIG 63c143
-		fname->dup.a_time = kernel2nt(&inode->i_ctime);
Kmods SIG 63c143
-	fname->dup.alloc_size = fname->dup.data_size = 0;
Kmods SIG 63c143
-	fname->dup.fa = ni->std_fa;
Kmods SIG 63c143
-	fname->dup.ea_size = fname->dup.reparse = 0;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), fname, key_size);
Kmods SIG 63c143
+	/* Mark rw ntfs as dirty. It will be cleared at umount. */
Kmods SIG 63c143
+	ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, NULL);
Kmods SIG 63c143
+	/* Construct 'de'. */
Kmods SIG 63c143
+	err = fill_name_de(sbi, de, &dentry->d_name, NULL);
Kmods SIG 63c143
 	if (err)
Kmods SIG 63c143
 		goto out;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	le16_add_cpu(&ni->mi.mrec->hard_links, 1);
Kmods SIG 63c143
-	ni->mi.dirty = true;
Kmods SIG 63c143
+	de_name = (struct ATTR_FILE_NAME *)(de + 1);
Kmods SIG 63c143
+	/* Fill duplicate info. */
Kmods SIG 63c143
+	de_name->dup.cr_time = de_name->dup.m_time = de_name->dup.c_time =
Kmods SIG 63c143
+		de_name->dup.a_time = kernel2nt(&inode->i_ctime);
Kmods SIG 63c143
+	de_name->dup.alloc_size = de_name->dup.data_size =
Kmods SIG 63c143
+		cpu_to_le64(inode->i_size);
Kmods SIG 63c143
+	de_name->dup.fa = ni->std_fa;
Kmods SIG 63c143
+	de_name->dup.ea_size = de_name->dup.reparse = 0;
Kmods SIG 63c143
 
Kmods SIG 63c143
+	err = ni_add_name(ntfs_i(d_inode(dentry->d_parent)), ni, de);
Kmods SIG 63c143
 out:
Kmods SIG 63c143
-	__putname(new_de);
Kmods SIG 63c143
+	__putname(de);
Kmods SIG 63c143
 	return err;
Kmods SIG 63c143
 }
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -1713,113 +1685,56 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
Kmods SIG 63c143
 int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
-	struct super_block *sb = dir->i_sb;
Kmods SIG 63c143
-	struct ntfs_sb_info *sbi = sb->s_fs_info;
Kmods SIG 63c143
+	struct ntfs_sb_info *sbi = dir->i_sb->s_fs_info;
Kmods SIG 63c143
 	struct inode *inode = d_inode(dentry);
Kmods SIG 63c143
 	struct ntfs_inode *ni = ntfs_i(inode);
Kmods SIG 63c143
-	const struct qstr *name = &dentry->d_name;
Kmods SIG 63c143
 	struct ntfs_inode *dir_ni = ntfs_i(dir);
Kmods SIG 63c143
-	struct ntfs_index *indx = &dir_ni->dir;
Kmods SIG 63c143
-	struct cpu_str *uni = NULL;
Kmods SIG 63c143
-	struct ATTR_FILE_NAME *fname;
Kmods SIG 63c143
-	u8 name_type;
Kmods SIG 63c143
-	struct ATTR_LIST_ENTRY *le;
Kmods SIG 63c143
-	struct MFT_REF ref;
Kmods SIG 63c143
-	bool is_dir = S_ISDIR(inode->i_mode);
Kmods SIG 63c143
-	struct INDEX_ROOT *dir_root;
Kmods SIG 63c143
+	struct NTFS_DE *de, *de2 = NULL;
Kmods SIG 63c143
+	int undo_remove;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	dir_root = indx_get_root(indx, dir_ni, NULL, NULL);
Kmods SIG 63c143
-	if (!dir_root)
Kmods SIG 63c143
+	if (ntfs_is_meta_file(sbi, ni->mi.rno))
Kmods SIG 63c143
 		return -EINVAL;
Kmods SIG 63c143
 
Kmods SIG 63c143
+	/* Allocate PATH_MAX bytes. */
Kmods SIG 63c143
+	de = __getname();
Kmods SIG 63c143
+	if (!de)
Kmods SIG 63c143
+		return -ENOMEM;
Kmods SIG 63c143
+
Kmods SIG 63c143
 	ni_lock(ni);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	if (is_dir && !dir_is_empty(inode)) {
Kmods SIG 63c143
+	if (S_ISDIR(inode->i_mode) && !dir_is_empty(inode)) {
Kmods SIG 63c143
 		err = -ENOTEMPTY;
Kmods SIG 63c143
-		goto out1;
Kmods SIG 63c143
-	}
Kmods SIG 63c143
-
Kmods SIG 63c143
-	if (ntfs_is_meta_file(sbi, inode->i_ino)) {
Kmods SIG 63c143
-		err = -EINVAL;
Kmods SIG 63c143
-		goto out1;
Kmods SIG 63c143
-	}
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Allocate PATH_MAX bytes. */
Kmods SIG 63c143
-	uni = __getname();
Kmods SIG 63c143
-	if (!uni) {
Kmods SIG 63c143
-		err = -ENOMEM;
Kmods SIG 63c143
-		goto out1;
Kmods SIG 63c143
+		goto out;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-	/* Convert input string to unicode. */
Kmods SIG 63c143
-	err = ntfs_nls_to_utf16(sbi, name->name, name->len, uni, NTFS_NAME_LEN,
Kmods SIG 63c143
-				UTF16_HOST_ENDIAN);
Kmods SIG 63c143
+	err = fill_name_de(sbi, de, &dentry->d_name, NULL);
Kmods SIG 63c143
 	if (err < 0)
Kmods SIG 63c143
-		goto out2;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Mark rw ntfs as dirty.  It will be cleared at umount. */
Kmods SIG 63c143
-	ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Find name in record. */
Kmods SIG 63c143
-	mi_get_ref(&dir_ni->mi, &ref;;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	le = NULL;
Kmods SIG 63c143
-	fname = ni_fname_name(ni, uni, &ref, &le);
Kmods SIG 63c143
-	if (!fname) {
Kmods SIG 63c143
-		err = -ENOENT;
Kmods SIG 63c143
-		goto out3;
Kmods SIG 63c143
-	}
Kmods SIG 63c143
-
Kmods SIG 63c143
-	name_type = paired_name(fname->type);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	err = indx_delete_entry(indx, dir_ni, fname, fname_full_size(fname),
Kmods SIG 63c143
-				sbi);
Kmods SIG 63c143
-	if (err)
Kmods SIG 63c143
-		goto out3;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Then remove name from MFT. */
Kmods SIG 63c143
-	ni_remove_attr_le(ni, attr_from_name(fname), le);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	le16_add_cpu(&ni->mi.mrec->hard_links, -1);
Kmods SIG 63c143
-	ni->mi.dirty = true;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	if (name_type != FILE_NAME_POSIX) {
Kmods SIG 63c143
-		/* Now we should delete name by type. */
Kmods SIG 63c143
-		fname = ni_fname_type(ni, name_type, &le);
Kmods SIG 63c143
-		if (fname) {
Kmods SIG 63c143
-			err = indx_delete_entry(indx, dir_ni, fname,
Kmods SIG 63c143
-						fname_full_size(fname), sbi);
Kmods SIG 63c143
-			if (err)
Kmods SIG 63c143
-				goto out3;
Kmods SIG 63c143
+		goto out;
Kmods SIG 63c143
 
Kmods SIG 63c143
-			ni_remove_attr_le(ni, attr_from_name(fname), le);
Kmods SIG 63c143
+	undo_remove = 0;
Kmods SIG 63c143
+	err = ni_remove_name(dir_ni, ni, de, &de2, &undo_remove);
Kmods SIG 63c143
 
Kmods SIG 63c143
-			le16_add_cpu(&ni->mi.mrec->hard_links, -1);
Kmods SIG 63c143
-		}
Kmods SIG 63c143
-	}
Kmods SIG 63c143
-out3:
Kmods SIG 63c143
-	switch (err) {
Kmods SIG 63c143
-	case 0:
Kmods SIG 63c143
+	if (!err) {
Kmods SIG 63c143
 		drop_nlink(inode);
Kmods SIG 63c143
-		break;
Kmods SIG 63c143
-	case -ENOTEMPTY:
Kmods SIG 63c143
-	case -ENOSPC:
Kmods SIG 63c143
-	case -EROFS:
Kmods SIG 63c143
-		break;
Kmods SIG 63c143
-	default:
Kmods SIG 63c143
+		dir->i_mtime = dir->i_ctime = current_time(dir);
Kmods SIG 63c143
+		mark_inode_dirty(dir);
Kmods SIG 63c143
+		inode->i_ctime = dir->i_ctime;
Kmods SIG 63c143
+		if (inode->i_nlink)
Kmods SIG 63c143
+			mark_inode_dirty(inode);
Kmods SIG 63c143
+	} else if (!ni_remove_name_undo(dir_ni, ni, de, de2, undo_remove)) {
Kmods SIG 63c143
 		make_bad_inode(inode);
Kmods SIG 63c143
+		ntfs_inode_err(inode, "failed to undo unlink");
Kmods SIG 63c143
+		ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
Kmods SIG 63c143
+	} else {
Kmods SIG 63c143
+		if (ni_is_dirty(dir))
Kmods SIG 63c143
+			mark_inode_dirty(dir);
Kmods SIG 63c143
+		if (ni_is_dirty(inode))
Kmods SIG 63c143
+			mark_inode_dirty(inode);
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-	dir->i_mtime = dir->i_ctime = current_time(dir);
Kmods SIG 63c143
-	mark_inode_dirty(dir);
Kmods SIG 63c143
-	inode->i_ctime = dir->i_ctime;
Kmods SIG 63c143
-	if (inode->i_nlink)
Kmods SIG 63c143
-		mark_inode_dirty(inode);
Kmods SIG 63c143
-
Kmods SIG 63c143
-out2:
Kmods SIG 63c143
-	__putname(uni);
Kmods SIG 63c143
-out1:
Kmods SIG 63c143
+out:
Kmods SIG 63c143
 	ni_unlock(ni);
Kmods SIG 63c143
+	__putname(de);
Kmods SIG 63c143
 	return err;
Kmods SIG 63c143
 }
Kmods SIG 63c143
 
Kmods SIG 63c143
diff --git a/src/namei.c b/src/namei.c
Kmods SIG 63c143
index f79a399bd015056f320714c91b935afac16eb488..e58415d0713280297df1b7bac30eb17642431fa0 100644
Kmods SIG 63c143
--- a/src/namei.c
Kmods SIG 63c143
+++ b/src/namei.c
Kmods SIG 63c143
@@ -152,12 +152,14 @@ static int ntfs_link(struct dentry *ode, struct inode *dir, struct dentry *de)
Kmods SIG 63c143
 	if (inode != dir)
Kmods SIG 63c143
 		ni_lock(ni);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	dir->i_ctime = dir->i_mtime = inode->i_ctime = current_time(inode);
Kmods SIG 63c143
 	inc_nlink(inode);
Kmods SIG 63c143
 	ihold(inode);
Kmods SIG 63c143
 
Kmods SIG 63c143
 	err = ntfs_link_inode(inode, de);
Kmods SIG 63c143
+
Kmods SIG 63c143
 	if (!err) {
Kmods SIG 63c143
+		dir->i_ctime = dir->i_mtime = inode->i_ctime =
Kmods SIG 63c143
+			current_time(dir);
Kmods SIG 63c143
 		mark_inode_dirty(inode);
Kmods SIG 63c143
 		mark_inode_dirty(dir);
Kmods SIG 63c143
 		d_instantiate(de, inode);
Kmods SIG 63c143
@@ -249,25 +251,26 @@ static int ntfs_rmdir(struct inode *dir, struct dentry *dentry)
Kmods SIG 63c143
 /*
Kmods SIG 63c143
  * ntfs_rename - inode_operations::rename
Kmods SIG 63c143
  */
Kmods SIG 63c143
-static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
Kmods SIG 63c143
-		       struct dentry *old_dentry, struct inode *new_dir,
Kmods SIG 63c143
+static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir,
Kmods SIG 63c143
+		       struct dentry *dentry, struct inode *new_dir,
Kmods SIG 63c143
 		       struct dentry *new_dentry, u32 flags)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
-	struct super_block *sb = old_dir->i_sb;
Kmods SIG 63c143
+	struct super_block *sb = dir->i_sb;
Kmods SIG 63c143
 	struct ntfs_sb_info *sbi = sb->s_fs_info;
Kmods SIG 63c143
-	struct ntfs_inode *old_dir_ni = ntfs_i(old_dir);
Kmods SIG 63c143
+	struct ntfs_inode *dir_ni = ntfs_i(dir);
Kmods SIG 63c143
 	struct ntfs_inode *new_dir_ni = ntfs_i(new_dir);
Kmods SIG 63c143
-	struct ntfs_inode *old_ni;
Kmods SIG 63c143
-	struct ATTR_FILE_NAME *old_name, *new_name, *fname;
Kmods SIG 63c143
-	u8 name_type;
Kmods SIG 63c143
-	bool is_same;
Kmods SIG 63c143
-	struct inode *old_inode, *new_inode;
Kmods SIG 63c143
-	struct NTFS_DE *old_de, *new_de;
Kmods SIG 63c143
-	struct ATTRIB *attr;
Kmods SIG 63c143
-	struct ATTR_LIST_ENTRY *le;
Kmods SIG 63c143
-	u16 new_de_key_size;
Kmods SIG 63c143
-
Kmods SIG 63c143
+	struct inode *inode = d_inode(dentry);
Kmods SIG 63c143
+	struct ntfs_inode *ni = ntfs_i(inode);
Kmods SIG 63c143
+	struct inode *new_inode = d_inode(new_dentry);
Kmods SIG 63c143
+	struct NTFS_DE *de, *new_de;
Kmods SIG 63c143
+	bool is_same, is_bad;
Kmods SIG 63c143
+	/*
Kmods SIG 63c143
+	 * de		- memory of PATH_MAX bytes:
Kmods SIG 63c143
+	 * [0-1024)	- original name (dentry->d_name)
Kmods SIG 63c143
+	 * [1024-2048)	- paired to original name, usually DOS variant of dentry->d_name
Kmods SIG 63c143
+	 * [2048-3072)	- new name (new_dentry->d_name)
Kmods SIG 63c143
+	 */
Kmods SIG 63c143
 	static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + SIZEOF_RESIDENT < 1024);
Kmods SIG 63c143
 	static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + sizeof(struct NTFS_DE) <
Kmods SIG 63c143
 		      1024);
Kmods SIG 63c143
@@ -276,24 +279,18 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
Kmods SIG 63c143
 	if (flags & ~RENAME_NOREPLACE)
Kmods SIG 63c143
 		return -EINVAL;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	old_inode = d_inode(old_dentry);
Kmods SIG 63c143
-	new_inode = d_inode(new_dentry);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	old_ni = ntfs_i(old_inode);
Kmods SIG 63c143
+	is_same = dentry->d_name.len == new_dentry->d_name.len &&
Kmods SIG 63c143
+		  !memcmp(dentry->d_name.name, new_dentry->d_name.name,
Kmods SIG 63c143
+			  dentry->d_name.len);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	is_same = old_dentry->d_name.len == new_dentry->d_name.len &&
Kmods SIG 63c143
-		  !memcmp(old_dentry->d_name.name, new_dentry->d_name.name,
Kmods SIG 63c143
-			  old_dentry->d_name.len);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	if (is_same && old_dir == new_dir) {
Kmods SIG 63c143
+	if (is_same && dir == new_dir) {
Kmods SIG 63c143
 		/* Nothing to do. */
Kmods SIG 63c143
-		err = 0;
Kmods SIG 63c143
-		goto out;
Kmods SIG 63c143
+		return 0;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-	if (ntfs_is_meta_file(sbi, old_inode->i_ino)) {
Kmods SIG 63c143
-		err = -EINVAL;
Kmods SIG 63c143
-		goto out;
Kmods SIG 63c143
+	if (ntfs_is_meta_file(sbi, inode->i_ino)) {
Kmods SIG 63c143
+		/* Should we print an error? */
Kmods SIG 63c143
+		return -EINVAL;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (new_inode) {
Kmods SIG 63c143
@@ -304,168 +301,61 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
Kmods SIG 63c143
 		ni_unlock(new_dir_ni);
Kmods SIG 63c143
 		dput(new_dentry);
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
-			goto out;
Kmods SIG 63c143
+			return err;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 	/* Allocate PATH_MAX bytes. */
Kmods SIG 63c143
-	old_de = __getname();
Kmods SIG 63c143
-	if (!old_de) {
Kmods SIG 63c143
-		err = -ENOMEM;
Kmods SIG 63c143
-		goto out;
Kmods SIG 63c143
-	}
Kmods SIG 63c143
+	de = __getname();
Kmods SIG 63c143
+	if (!de)
Kmods SIG 63c143
+		return -ENOMEM;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	err = fill_name_de(sbi, old_de, &old_dentry->d_name, NULL);
Kmods SIG 63c143
+	/* Translate dentry->d_name into unicode form. */
Kmods SIG 63c143
+	err = fill_name_de(sbi, de, &dentry->d_name, NULL);
Kmods SIG 63c143
 	if (err < 0)
Kmods SIG 63c143
-		goto out1;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	old_name = (struct ATTR_FILE_NAME *)(old_de + 1);
Kmods SIG 63c143
+		goto out;
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (is_same) {
Kmods SIG 63c143
-		new_de = old_de;
Kmods SIG 63c143
+		/* Reuse 'de'. */
Kmods SIG 63c143
+		new_de = de;
Kmods SIG 63c143
 	} else {
Kmods SIG 63c143
-		new_de = Add2Ptr(old_de, 1024);
Kmods SIG 63c143
+		/* Translate new_dentry->d_name into unicode form. */
Kmods SIG 63c143
+		new_de = Add2Ptr(de, 2048);
Kmods SIG 63c143
 		err = fill_name_de(sbi, new_de, &new_dentry->d_name, NULL);
Kmods SIG 63c143
 		if (err < 0)
Kmods SIG 63c143
-			goto out1;
Kmods SIG 63c143
-	}
Kmods SIG 63c143
-
Kmods SIG 63c143
-	ni_lock_dir(old_dir_ni);
Kmods SIG 63c143
-	ni_lock(old_ni);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	mi_get_ref(&old_dir_ni->mi, &old_name->home);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Get pointer to file_name in MFT. */
Kmods SIG 63c143
-	fname = ni_fname_name(old_ni, (struct cpu_str *)&old_name->name_len,
Kmods SIG 63c143
-			      &old_name->home, &le);
Kmods SIG 63c143
-	if (!fname) {
Kmods SIG 63c143
-		err = -EINVAL;
Kmods SIG 63c143
-		goto out2;
Kmods SIG 63c143
+			goto out;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-	/* Copy fname info from record into new fname. */
Kmods SIG 63c143
-	new_name = (struct ATTR_FILE_NAME *)(new_de + 1);
Kmods SIG 63c143
-	memcpy(&new_name->dup, &fname->dup, sizeof(fname->dup));
Kmods SIG 63c143
-
Kmods SIG 63c143
-	name_type = paired_name(fname->type);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Remove first name from directory. */
Kmods SIG 63c143
-	err = indx_delete_entry(&old_dir_ni->dir, old_dir_ni, old_de + 1,
Kmods SIG 63c143
-				le16_to_cpu(old_de->key_size), sbi);
Kmods SIG 63c143
-	if (err)
Kmods SIG 63c143
-		goto out3;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Remove first name from MFT. */
Kmods SIG 63c143
-	err = ni_remove_attr_le(old_ni, attr_from_name(fname), le);
Kmods SIG 63c143
-	if (err)
Kmods SIG 63c143
-		goto out4;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	le16_add_cpu(&old_ni->mi.mrec->hard_links, -1);
Kmods SIG 63c143
-	old_ni->mi.dirty = true;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	if (name_type != FILE_NAME_POSIX) {
Kmods SIG 63c143
-		/* Get paired name. */
Kmods SIG 63c143
-		fname = ni_fname_type(old_ni, name_type, &le);
Kmods SIG 63c143
-		if (fname) {
Kmods SIG 63c143
-			/* Remove second name from directory. */
Kmods SIG 63c143
-			err = indx_delete_entry(&old_dir_ni->dir, old_dir_ni,
Kmods SIG 63c143
-						fname, fname_full_size(fname),
Kmods SIG 63c143
-						sbi);
Kmods SIG 63c143
-			if (err)
Kmods SIG 63c143
-				goto out5;
Kmods SIG 63c143
-
Kmods SIG 63c143
-			/* Remove second name from MFT. */
Kmods SIG 63c143
-			err = ni_remove_attr_le(old_ni, attr_from_name(fname),
Kmods SIG 63c143
-						le);
Kmods SIG 63c143
-			if (err)
Kmods SIG 63c143
-				goto out6;
Kmods SIG 63c143
-
Kmods SIG 63c143
-			le16_add_cpu(&old_ni->mi.mrec->hard_links, -1);
Kmods SIG 63c143
-			old_ni->mi.dirty = true;
Kmods SIG 63c143
+	ni_lock_dir(dir_ni);
Kmods SIG 63c143
+	ni_lock(ni);
Kmods SIG 63c143
+
Kmods SIG 63c143
+	is_bad = false;
Kmods SIG 63c143
+	err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad);
Kmods SIG 63c143
+	if (is_bad) {
Kmods SIG 63c143
+		/* Restore after failed rename failed too. */
Kmods SIG 63c143
+		make_bad_inode(inode);
Kmods SIG 63c143
+		ntfs_inode_err(inode, "failed to undo rename");
Kmods SIG 63c143
+		ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
Kmods SIG 63c143
+	} else if (!err) {
Kmods SIG 63c143
+		inode->i_ctime = dir->i_ctime = dir->i_mtime =
Kmods SIG 63c143
+			current_time(dir);
Kmods SIG 63c143
+		mark_inode_dirty(inode);
Kmods SIG 63c143
+		mark_inode_dirty(dir);
Kmods SIG 63c143
+		if (dir != new_dir) {
Kmods SIG 63c143
+			new_dir->i_mtime = new_dir->i_ctime = dir->i_ctime;
Kmods SIG 63c143
+			mark_inode_dirty(new_dir);
Kmods SIG 63c143
 		}
Kmods SIG 63c143
-	}
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Add new name. */
Kmods SIG 63c143
-	mi_get_ref(&old_ni->mi, &new_de->ref);
Kmods SIG 63c143
-	mi_get_ref(&ntfs_i(new_dir)->mi, &new_name->home);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	new_de_key_size = le16_to_cpu(new_de->key_size);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Insert new name in MFT. */
Kmods SIG 63c143
-	err = ni_insert_resident(old_ni, new_de_key_size, ATTR_NAME, NULL, 0,
Kmods SIG 63c143
-				 &attr, NULL);
Kmods SIG 63c143
-	if (err)
Kmods SIG 63c143
-		goto out7;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	attr->res.flags = RESIDENT_FLAG_INDEXED;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), new_name, new_de_key_size);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	le16_add_cpu(&old_ni->mi.mrec->hard_links, 1);
Kmods SIG 63c143
-	old_ni->mi.dirty = true;
Kmods SIG 63c143
-
Kmods SIG 63c143
-	/* Insert new name in directory. */
Kmods SIG 63c143
-	err = indx_insert_entry(&new_dir_ni->dir, new_dir_ni, new_de, sbi,
Kmods SIG 63c143
-				NULL);
Kmods SIG 63c143
-	if (err)
Kmods SIG 63c143
-		goto out8;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	if (IS_DIRSYNC(new_dir))
Kmods SIG 63c143
-		err = ntfs_sync_inode(old_inode);
Kmods SIG 63c143
-	else
Kmods SIG 63c143
-		mark_inode_dirty(old_inode);
Kmods SIG 63c143
+		if (IS_DIRSYNC(dir))
Kmods SIG 63c143
+			ntfs_sync_inode(dir);
Kmods SIG 63c143
 
Kmods SIG 63c143
-	old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
Kmods SIG 63c143
-	if (IS_DIRSYNC(old_dir))
Kmods SIG 63c143
-		(void)ntfs_sync_inode(old_dir);
Kmods SIG 63c143
-	else
Kmods SIG 63c143
-		mark_inode_dirty(old_dir);
Kmods SIG 63c143
-
Kmods SIG 63c143
-	if (old_dir != new_dir) {
Kmods SIG 63c143
-		new_dir->i_mtime = new_dir->i_ctime = old_dir->i_ctime;
Kmods SIG 63c143
-		mark_inode_dirty(new_dir);
Kmods SIG 63c143
-	}
Kmods SIG 63c143
-
Kmods SIG 63c143
-	if (old_inode) {
Kmods SIG 63c143
-		old_inode->i_ctime = old_dir->i_ctime;
Kmods SIG 63c143
-		mark_inode_dirty(old_inode);
Kmods SIG 63c143
+		if (IS_DIRSYNC(new_dir))
Kmods SIG 63c143
+			ntfs_sync_inode(inode);
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-	err = 0;
Kmods SIG 63c143
-	/* Normal way* */
Kmods SIG 63c143
-	goto out2;
Kmods SIG 63c143
-
Kmods SIG 63c143
-out8:
Kmods SIG 63c143
-	/* undo
Kmods SIG 63c143
-	 * ni_insert_resident(old_ni, new_de_key_size, ATTR_NAME, NULL, 0,
Kmods SIG 63c143
-	 *			 &attr, NULL);
Kmods SIG 63c143
-	 */
Kmods SIG 63c143
-	mi_remove_attr(&old_ni->mi, attr);
Kmods SIG 63c143
-out7:
Kmods SIG 63c143
-	/* undo
Kmods SIG 63c143
-	 * ni_remove_attr_le(old_ni, attr_from_name(fname), le);
Kmods SIG 63c143
-	 */
Kmods SIG 63c143
-out6:
Kmods SIG 63c143
-	/* undo
Kmods SIG 63c143
-	 * indx_delete_entry(&old_dir_ni->dir, old_dir_ni,
Kmods SIG 63c143
-	 *					fname, fname_full_size(fname),
Kmods SIG 63c143
-	 *					sbi);
Kmods SIG 63c143
-	 */
Kmods SIG 63c143
-out5:
Kmods SIG 63c143
-	/* undo
Kmods SIG 63c143
-	 * ni_remove_attr_le(old_ni, attr_from_name(fname), le);
Kmods SIG 63c143
-	 */
Kmods SIG 63c143
-out4:
Kmods SIG 63c143
-	/* undo:
Kmods SIG 63c143
-	 * indx_delete_entry(&old_dir_ni->dir, old_dir_ni, old_de + 1,
Kmods SIG 63c143
-	 *			old_de->key_size, NULL);
Kmods SIG 63c143
-	 */
Kmods SIG 63c143
-out3:
Kmods SIG 63c143
-out2:
Kmods SIG 63c143
-	ni_unlock(old_ni);
Kmods SIG 63c143
-	ni_unlock(old_dir_ni);
Kmods SIG 63c143
-out1:
Kmods SIG 63c143
-	__putname(old_de);
Kmods SIG 63c143
+	ni_unlock(ni);
Kmods SIG 63c143
+	ni_unlock(dir_ni);
Kmods SIG 63c143
 out:
Kmods SIG 63c143
+	__putname(de);
Kmods SIG 63c143
 	return err;
Kmods SIG 63c143
 }
Kmods SIG 63c143
 
Kmods SIG 63c143
diff --git a/src/ntfs_fs.h b/src/ntfs_fs.h
Kmods SIG 63c143
index 64ef92e16363c4973be6438efdeea0663ce10e84..f9436cbbc347b617b458bb21d6c7229b467ca289 100644
Kmods SIG 63c143
--- a/src/ntfs_fs.h
Kmods SIG 63c143
+++ b/src/ntfs_fs.h
Kmods SIG 63c143
@@ -478,7 +478,7 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni);
Kmods SIG 63c143
 struct ATTR_STD_INFO5 *ni_std5(struct ntfs_inode *ni);
Kmods SIG 63c143
 void ni_clear(struct ntfs_inode *ni);
Kmods SIG 63c143
 int ni_load_mi_ex(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi);
Kmods SIG 63c143
-int ni_load_mi(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG 63c143
+int ni_load_mi(struct ntfs_inode *ni, const struct ATTR_LIST_ENTRY *le,
Kmods SIG 63c143
 	       struct mft_inode **mi);
Kmods SIG 63c143
 struct ATTRIB *ni_find_attr(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG 63c143
 			    struct ATTR_LIST_ENTRY **entry_o,
Kmods SIG 63c143
@@ -505,15 +505,18 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG 63c143
 			  struct mft_inode **mi);
Kmods SIG 63c143
 int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG 63c143
 		       enum ATTR_TYPE type, const __le16 *name, u8 name_len,
Kmods SIG 63c143
-		       struct ATTRIB **new_attr, struct mft_inode **mi);
Kmods SIG 63c143
-int ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG 63c143
-		      struct ATTR_LIST_ENTRY *le);
Kmods SIG 63c143
+		       struct ATTRIB **new_attr, struct mft_inode **mi,
Kmods SIG 63c143
+		       struct ATTR_LIST_ENTRY **le);
Kmods SIG 63c143
+void ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG 63c143
+		       struct mft_inode *mi, struct ATTR_LIST_ENTRY *le);
Kmods SIG 63c143
 int ni_delete_all(struct ntfs_inode *ni);
Kmods SIG 63c143
 struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
Kmods SIG 63c143
 				     const struct cpu_str *uni,
Kmods SIG 63c143
 				     const struct MFT_REF *home,
Kmods SIG 63c143
+				     struct mft_inode **mi,
Kmods SIG 63c143
 				     struct ATTR_LIST_ENTRY **entry);
Kmods SIG 63c143
 struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
Kmods SIG 63c143
+				     struct mft_inode **mi,
Kmods SIG 63c143
 				     struct ATTR_LIST_ENTRY **entry);
Kmods SIG 63c143
 int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa);
Kmods SIG 63c143
 enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG 63c143
@@ -528,6 +531,21 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
Kmods SIG 63c143
 		  u32 pages_per_frame);
Kmods SIG 63c143
 int ni_write_frame(struct ntfs_inode *ni, struct page **pages,
Kmods SIG 63c143
 		   u32 pages_per_frame);
Kmods SIG 63c143
+int ni_remove_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG 63c143
+		   struct NTFS_DE *de, struct NTFS_DE **de2, int *undo_step);
Kmods SIG 63c143
+
Kmods SIG 63c143
+bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG 63c143
+			 struct NTFS_DE *de, struct NTFS_DE *de2,
Kmods SIG 63c143
+			 int undo_step);
Kmods SIG 63c143
+
Kmods SIG 63c143
+int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG 63c143
+		struct NTFS_DE *de);
Kmods SIG 63c143
+
Kmods SIG 63c143
+int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
Kmods SIG 63c143
+	      struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de,
Kmods SIG 63c143
+	      bool *is_bad);
Kmods SIG 63c143
+
Kmods SIG 63c143
+bool ni_is_dirty(struct inode *inode);
Kmods SIG 63c143
 
Kmods SIG 63c143
 /* Globals from fslog.c */
Kmods SIG 63c143
 int log_replay(struct ntfs_inode *ni, bool *initialized);
Kmods SIG 63c143
@@ -631,7 +649,7 @@ int indx_find_raw(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 		  size_t *off, struct ntfs_fnd *fnd);
Kmods SIG 63c143
 int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 		      const struct NTFS_DE *new_de, const void *param,
Kmods SIG 63c143
-		      struct ntfs_fnd *fnd);
Kmods SIG 63c143
+		      struct ntfs_fnd *fnd, bool undo);
Kmods SIG 63c143
 int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG 63c143
 		      const void *key, u32 key_len, const void *param);
Kmods SIG 63c143
 int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
Kmods SIG 63c143
@@ -694,7 +712,8 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
Kmods SIG 63c143
 			      const __le16 *name, u8 name_len, u32 asize,
Kmods SIG 63c143
 			      u16 name_off);
Kmods SIG 63c143
 
Kmods SIG 63c143
-bool mi_remove_attr(struct mft_inode *mi, struct ATTRIB *attr);
Kmods SIG 63c143
+bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
Kmods SIG 63c143
+		    struct ATTRIB *attr);
Kmods SIG 63c143
 bool mi_resize_attr(struct mft_inode *mi, struct ATTRIB *attr, int bytes);
Kmods SIG 63c143
 int mi_pack_runs(struct mft_inode *mi, struct ATTRIB *attr,
Kmods SIG 63c143
 		 struct runs_tree *run, CLST len);
Kmods SIG 63c143
diff --git a/src/record.c b/src/record.c
Kmods SIG 63c143
index d48a5e6c5045c5f154f3c1aba4108f458e9676b0..61e3f2fb619f698ffdf5d81ca6f488008002de52 100644
Kmods SIG 63c143
--- a/src/record.c
Kmods SIG 63c143
+++ b/src/record.c
Kmods SIG 63c143
@@ -489,7 +489,8 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
Kmods SIG 63c143
  *
Kmods SIG 63c143
  * NOTE: The source attr will point to next attribute.
Kmods SIG 63c143
  */
Kmods SIG 63c143
-bool mi_remove_attr(struct mft_inode *mi, struct ATTRIB *attr)
Kmods SIG 63c143
+bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
Kmods SIG 63c143
+		    struct ATTRIB *attr)
Kmods SIG 63c143
 {
Kmods SIG 63c143
 	struct MFT_REC *rec = mi->mrec;
Kmods SIG 63c143
 	u32 aoff = PtrOffset(rec, attr);
Kmods SIG 63c143
@@ -499,6 +500,11 @@ bool mi_remove_attr(struct mft_inode *mi, struct ATTRIB *attr)
Kmods SIG 63c143
 	if (aoff + asize > used)
Kmods SIG 63c143
 		return false;
Kmods SIG 63c143
 
Kmods SIG 63c143
+	if (ni && is_attr_indexed(attr)) {
Kmods SIG 63c143
+		le16_add_cpu(&ni->mi.mrec->hard_links, -1);
Kmods SIG 63c143
+		ni->mi.dirty = true;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
+
Kmods SIG 63c143
 	used -= asize;
Kmods SIG 63c143
 	memmove(attr, Add2Ptr(attr, asize), used - aoff);
Kmods SIG 63c143
 	rec->used = cpu_to_le32(used);
Kmods SIG 63c143
diff --git a/src/xattr.c b/src/xattr.c
Kmods SIG 63c143
index b4c921e4bc1a1b4bbb1c51ef7cef6677967b8e13..22fd5eb32c5be7f53b3fd8076599f7dbaf84e2cf 100644
Kmods SIG 63c143
--- a/src/xattr.c
Kmods SIG 63c143
+++ b/src/xattr.c
Kmods SIG 63c143
@@ -395,11 +395,13 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
Kmods SIG 63c143
 		}
Kmods SIG 63c143
 
Kmods SIG 63c143
 		err = ni_insert_resident(ni, sizeof(struct EA_INFO),
Kmods SIG 63c143
-					 ATTR_EA_INFO, NULL, 0, NULL, NULL);
Kmods SIG 63c143
+					 ATTR_EA_INFO, NULL, 0, NULL, NULL,
Kmods SIG 63c143
+					 NULL);
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
 			goto out;
Kmods SIG 63c143
 
Kmods SIG 63c143
-		err = ni_insert_resident(ni, 0, ATTR_EA, NULL, 0, NULL, NULL);
Kmods SIG 63c143
+		err = ni_insert_resident(ni, 0, ATTR_EA, NULL, 0, NULL, NULL,
Kmods SIG 63c143
+					 NULL);
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
 			goto out;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
@@ -419,9 +421,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (!size) {
Kmods SIG 63c143
 		/* Delete xattr, ATTR_EA_INFO */
Kmods SIG 63c143
-		err = ni_remove_attr_le(ni, attr, le);
Kmods SIG 63c143
-		if (err)
Kmods SIG 63c143
-			goto out;
Kmods SIG 63c143
+		ni_remove_attr_le(ni, attr, mi, le);
Kmods SIG 63c143
 	} else {
Kmods SIG 63c143
 		p = resident_data_ex(attr, sizeof(struct EA_INFO));
Kmods SIG 63c143
 		if (!p) {
Kmods SIG 63c143
@@ -441,9 +441,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (!size) {
Kmods SIG 63c143
 		/* Delete xattr, ATTR_EA */
Kmods SIG 63c143
-		err = ni_remove_attr_le(ni, attr, le);
Kmods SIG 63c143
-		if (err)
Kmods SIG 63c143
-			goto out;
Kmods SIG 63c143
+		ni_remove_attr_le(ni, attr, mi, le);
Kmods SIG 63c143
 	} else if (attr->non_res) {
Kmods SIG 63c143
 		err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size);
Kmods SIG 63c143
 		if (err)
Kmods SIG 63c143
@@ -605,8 +603,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 			goto out;
Kmods SIG 63c143
 	}
Kmods SIG 63c143
 
Kmods SIG 63c143
-	err = ntfs_set_ea(inode, name, name_len, value, size,
Kmods SIG 63c143
-			  acl ? 0 : XATTR_REPLACE, locked);
Kmods SIG 63c143
+	err = ntfs_set_ea(inode, name, name_len, value, size, 0, locked);
Kmods SIG 63c143
 	if (!err)
Kmods SIG 63c143
 		set_cached_acl(inode, type, acl);
Kmods SIG 63c143
 
Kmods SIG 63c143
@@ -632,8 +629,10 @@ static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 	struct posix_acl *acl;
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	if (!(inode->i_sb->s_flags & SB_POSIXACL))
Kmods SIG 63c143
+	if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
Kmods SIG 63c143
+		ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
Kmods SIG 63c143
 		return -EOPNOTSUPP;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 	acl = ntfs_get_acl(inode, type);
Kmods SIG 63c143
 	if (IS_ERR(acl))
Kmods SIG 63c143
@@ -655,8 +654,10 @@ static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
Kmods SIG 63c143
 	struct posix_acl *acl;
Kmods SIG 63c143
 	int err;
Kmods SIG 63c143
 
Kmods SIG 63c143
-	if (!(inode->i_sb->s_flags & SB_POSIXACL))
Kmods SIG 63c143
+	if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
Kmods SIG 63c143
+		ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
Kmods SIG 63c143
 		return -EOPNOTSUPP;
Kmods SIG 63c143
+	}
Kmods SIG 63c143
 
Kmods SIG 63c143
 	if (!inode_owner_or_capable(mnt_userns, inode))
Kmods SIG 63c143
 		return -EPERM;
Kmods SIG 63c143
-- 
Kmods SIG 63c143
2.31.1
Kmods SIG 63c143