git: 3d945604ef8e - main - cd9660: Add support for birth times

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Tue, 23 Jun 2026 15:51:53 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=3d945604ef8e1aaa49e153d82821fb4c6c1e67f2

commit 3d945604ef8e1aaa49e153d82821fb4c6c1e67f2
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2026-06-23 15:51:43 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2026-06-23 15:51:43 +0000

    cd9660: Add support for birth times
    
    Both the Extended Attribute Record in the base ISO-9660 standard and
    the RockRidge timestamp extension support a file creation timestamp.
    Use this to populate the birthtime if present.
    
    Reviewed by:    markj (earlier version)
    Differential Revision:  https://reviews.freebsd.org/D57526
---
 sys/fs/cd9660/cd9660_node.c  | 12 +++++++-----
 sys/fs/cd9660/cd9660_node.h  |  1 +
 sys/fs/cd9660/cd9660_rrip.c  | 16 ++++++++++++++--
 sys/fs/cd9660/cd9660_vnops.c |  1 +
 4 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/sys/fs/cd9660/cd9660_node.c b/sys/fs/cd9660/cd9660_node.c
index 747536042ccc..a8b0df832aa4 100644
--- a/sys/fs/cd9660/cd9660_node.c
+++ b/sys/fs/cd9660/cd9660_node.c
@@ -184,13 +184,14 @@ cd9660_deftstamp(struct iso_directory_record *isodir, struct iso_node *inop,
 			 * Only the first two are meaningful for struct
 			 * stat.
 			 */
-			struct timespec birthtime;
-
-			if (!cd9660_tstamp_conv17(ap->ctime, &birthtime))
-				memset(&birthtime, 0, sizeof(birthtime));
+			if (!cd9660_tstamp_conv17(ap->ctime,
+			    &inop->inode.iso_birthtime))
+				memset(&inop->inode.iso_birthtime, 0,
+				    sizeof(inop->inode.iso_birthtime));
 			if (!cd9660_tstamp_conv17(ap->mtime,
 			    &inop->inode.iso_mtime))
-				inop->inode.iso_mtime = birthtime;
+				inop->inode.iso_mtime =
+				    inop->inode.iso_birthtime;
 			inop->inode.iso_ctime = inop->inode.iso_mtime;
 			inop->inode.iso_atime = inop->inode.iso_mtime;
 		} else
@@ -200,6 +201,7 @@ cd9660_deftstamp(struct iso_directory_record *isodir, struct iso_node *inop,
 		cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime,ftype);
 		inop->inode.iso_atime = inop->inode.iso_ctime;
 		inop->inode.iso_mtime = inop->inode.iso_ctime;
+		inop->inode.iso_birthtime = inop->inode.iso_ctime;
 	}
 	if (bp2)
 		brelse(bp2);
diff --git a/sys/fs/cd9660/cd9660_node.h b/sys/fs/cd9660/cd9660_node.h
index 6021c1681c5d..27e4de2f5594 100644
--- a/sys/fs/cd9660/cd9660_node.h
+++ b/sys/fs/cd9660/cd9660_node.h
@@ -47,6 +47,7 @@ typedef	struct	{
 	struct timespec	iso_atime;	/* time of last access */
 	struct timespec	iso_mtime;	/* time of last modification */
 	struct timespec	iso_ctime;	/* time file changed */
+	struct timespec	iso_birthtime;	/* time file created */
 	u_short		iso_mode;	/* files access mode and type */
 	uid_t		iso_uid;	/* owner user id */
 	gid_t		iso_gid;	/* owner group id */
diff --git a/sys/fs/cd9660/cd9660_rrip.c b/sys/fs/cd9660/cd9660_rrip.c
index e3aab4fa6115..1f956434c642 100644
--- a/sys/fs/cd9660/cd9660_rrip.c
+++ b/sys/fs/cd9660/cd9660_rrip.c
@@ -376,14 +376,20 @@ cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, size_t len, ISO_RRIP_ANALYZE *ana)
 	/* Check a format of time stamp (7bytes/17bytes) */
 	if (!(*p->flags & ISO_SUSP_TSTAMP_FORM17)) {
 		if (*p->flags & ISO_SUSP_TSTAMP_CREAT) {
+			cd9660_tstamp_conv7(ptime,
+			    &ana->inop->inode.iso_birthtime, ISO_FTYPE_RRIP);
 			ptime += 7;
+		} else {
+			memset(&ana->inop->inode.iso_birthtime, 0,
+			    sizeof(struct timespec));
 		}
 		if (*p->flags & ISO_SUSP_TSTAMP_MODIFY) {
 			cd9660_tstamp_conv7(ptime, &ana->inop->inode.iso_mtime,
 			    ISO_FTYPE_RRIP);
 			ptime += 7;
 		} else {
-			memset(&ana->inop->inode.iso_mtime, 0, sizeof(struct timespec));
+			ana->inop->inode.iso_mtime =
+			    ana->inop->inode.iso_birthtime;
 		}
 		if (*p->flags & ISO_SUSP_TSTAMP_ACCESS) {
 			cd9660_tstamp_conv7(ptime, &ana->inop->inode.iso_atime,
@@ -400,13 +406,19 @@ cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, size_t len, ISO_RRIP_ANALYZE *ana)
 		}
 	} else {
 		if (*p->flags & ISO_SUSP_TSTAMP_CREAT) {
+			cd9660_tstamp_conv17(ptime,
+			    &ana->inop->inode.iso_birthtime);
 			ptime += 17;
+		} else {
+			memset(&ana->inop->inode.iso_birthtime, 0,
+			    sizeof(struct timespec));
 		}
 		if (*p->flags & ISO_SUSP_TSTAMP_MODIFY) {
 			cd9660_tstamp_conv17(ptime, &ana->inop->inode.iso_mtime);
 			ptime += 17;
 		} else {
-			memset(&ana->inop->inode.iso_mtime, 0, sizeof(struct timespec));
+			ana->inop->inode.iso_mtime =
+			    ana->inop->inode.iso_birthtime;
 		}
 		if (*p->flags & ISO_SUSP_TSTAMP_ACCESS) {
 			cd9660_tstamp_conv17(ptime, &ana->inop->inode.iso_atime);
diff --git a/sys/fs/cd9660/cd9660_vnops.c b/sys/fs/cd9660/cd9660_vnops.c
index 92ea6d2b4501..579844e941aa 100644
--- a/sys/fs/cd9660/cd9660_vnops.c
+++ b/sys/fs/cd9660/cd9660_vnops.c
@@ -191,6 +191,7 @@ cd9660_getattr(struct vop_getattr_args *ap)
 	vap->va_atime	= ip->inode.iso_atime;
 	vap->va_mtime	= ip->inode.iso_mtime;
 	vap->va_ctime	= ip->inode.iso_ctime;
+	vap->va_birthtime = ip->inode.iso_birthtime;
 	vap->va_rdev	= VN_ISDEV(vp) ? ip->inode.iso_rdev : NODEV;
 
 	vap->va_size	= ip->i_size;