All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Smith <defendthedisabled@gmail.com>
To: linux-fsdevel@vger.kernel.org
Cc: linux-ext4@vger.kernel.org, linux-btrfs@vger.kernel.org,
	tytso@mit.edu, dsterba@suse.com, david@fromorbit.com,
	brauner@kernel.org, osandov@osandov.com, almaz@kernel.org,
	hirofumi@mail.parknet.co.jp, linkinjeon@kernel.org,
	Sean Smith <DefendTheDisabled@gmail.com>
Subject: [PATCH 3/6] ntfs3: map ptime to NTFS creation time with rename-over
Date: Sun,  5 Apr 2026 14:49:59 -0500	[thread overview]
Message-ID: <20260405195007.1306-4-DefendTheDisabled@gmail.com> (raw)
In-Reply-To: <20260405195007.1306-1-DefendTheDisabled@gmail.com>

Map ptime to the NTFS Date Created field in $STANDARD_INFORMATION.
This is a mapped-ptime implementation: setting ptime overwrites the
creation time. Justified because Windows treats NTFS creation time
as mutable via SetFileTime() - it was never truly immutable.

Getattr: report NTFS creation time as ptime.
Setattr: write ptime to NTFS creation time via frecord cr_time path.
Rename-over: save target creation time before unlink, restore to
  source after rename. Replicates Windows behavior where creation
  time survives application atomic saves.

Round-trip: NTFS Date Created -> Btrfs ptime -> NTFS Date Created
preserves the original creation date through cross-FS copies.

Signed-off-by: Sean Smith <DefendTheDisabled@gmail.com>
---
 fs/ntfs3/file.c    | 13 +++++++++++++
 fs/ntfs3/frecord.c |  8 ++++++++
 fs/ntfs3/namei.c   | 14 ++++++++++++++
 3 files changed, 35 insertions(+)

diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 13d014b87..8688a48b1 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -161,6 +161,13 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
 
 	stat->result_mask |= STATX_BTIME;
 	stat->btime = ni->i_crtime;
+
+	/* Map NTFS creation time to ptime (provenance time) */
+	if (request_mask & STATX_PTIME) {
+		stat->ptime = ni->i_crtime;
+		stat->result_mask |= STATX_PTIME;
+	}
+
 	stat->blksize = ni->mi.sbi->cluster_size; /* 512, 1K, ..., 2M */
 
 	if (inode->i_flags & S_IMMUTABLE)
@@ -857,6 +864,12 @@ int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
 		i_size_write(inode, newsize);
 	}
 
+	/* Accept ptime and store as NTFS creation time */
+	if (ia_valid & ATTR_PTIME) {
+		ni->i_crtime = attr->ia_ptime;
+		ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
+	}
+
 	setattr_copy(idmap, inode, attr);
 
 	if (mode != inode->i_mode) {
diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c
index d5bbd47e1..b164b2f50 100644
--- a/fs/ntfs3/frecord.c
+++ b/fs/ntfs3/frecord.c
@@ -3197,6 +3197,14 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
 			modified = true;
 		}
 
+		/* Write creation time (ptime maps to NTFS cr_time) */
+		ts = ni->i_crtime;
+		dup.cr_time = kernel2nt(&ts);
+		if (std->cr_time != dup.cr_time) {
+			std->cr_time = dup.cr_time;
+			modified = true;
+		}
+
 		dup.fa = ni->std_fa;
 		if (std->fa != dup.fa) {
 			std->fa = dup.fa;
diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c
index b2af8f695..40d06884f 100644
--- a/fs/ntfs3/namei.c
+++ b/fs/ntfs3/namei.c
@@ -292,6 +292,16 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
 		return -EINVAL;
 	}
 
+	/* ptime rename-over: save target creation time before unlink */
+	struct timespec64 saved_crtime = {};
+	bool inherit_crtime = false;
+
+	if (new_inode && S_ISREG(inode->i_mode) &&
+	    S_ISREG(new_inode->i_mode) && inode->i_nlink == 1) {
+		saved_crtime = ntfs_i(new_inode)->i_crtime;
+		inherit_crtime = true;
+	}
+
 	if (new_inode) {
 		/* Target name exists. Unlink it. */
 		dget(new_dentry);
@@ -330,6 +340,10 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
 
 	err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de);
 	if (!err) {
+		/* ptime rename-over: inherit target creation time */
+		if (inherit_crtime)
+			ni->i_crtime = saved_crtime;
+
 		simple_rename_timestamp(dir, dentry, new_dir, new_dentry);
 		mark_inode_dirty(inode);
 		mark_inode_dirty(dir);
-- 
2.53.0


  parent reply	other threads:[~2026-04-05 19:50 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-05 19:49 [RFC PATCH v1 0/6] provenance_time (ptime): a new settable timestamp for cross-filesystem provenance Sean Smith
2026-04-05 19:49 ` [PATCH 1/6] vfs: add provenance_time (ptime) infrastructure Sean Smith
2026-04-05 19:49 ` [PATCH 2/6] btrfs: add provenance time (ptime) support Sean Smith
2026-04-05 19:49 ` Sean Smith [this message]
2026-04-05 19:50 ` [PATCH 4/6] ext4: add dedicated ptime field alongside i_crtime Sean Smith
2026-04-05 19:50 ` [PATCH 5/6] fat: map ptime to FAT creation time with rename-over Sean Smith
2026-04-05 19:50 ` [PATCH 6/6] exfat: map ptime to exFAT " Sean Smith
2026-04-05 22:54 ` [RFC PATCH v1 0/6] provenance_time (ptime): a new settable timestamp for cross-filesystem provenance Theodore Tso
2026-04-07  0:05   ` Sean Smith
2026-04-07  1:42     ` Darrick J. Wong
2026-04-07  6:06       ` Sean Smith
2026-04-07 15:17         ` Darrick J. Wong
2026-04-07 23:36     ` Theodore Tso
2026-04-08  2:54       ` Sean Smith
2026-04-08 13:33         ` Theodore Tso
2026-04-09  0:15           ` Sean Smith
2026-04-09 13:38       ` Christian Brauner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260405195007.1306-4-DefendTheDisabled@gmail.com \
    --to=defendthedisabled@gmail.com \
    --cc=almaz@kernel.org \
    --cc=brauner@kernel.org \
    --cc=david@fromorbit.com \
    --cc=dsterba@suse.com \
    --cc=hirofumi@mail.parknet.co.jp \
    --cc=linkinjeon@kernel.org \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=osandov@osandov.com \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.