Module Name:    src
Committed By:   jdolecek
Date:           Wed Aug  3 23:29:05 UTC 2016

Modified Files:
        src/sys/ufs/ext2fs: ext2fs_dinode.h ext2fs_subr.c ext2fs_vnops.c

Log Message:
get and set expanded timestamp if the inode contains the extra information, add 
support for create time


To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/sys/ufs/ext2fs/ext2fs_dinode.h
cvs rdiff -u -r1.31 -r1.32 src/sys/ufs/ext2fs/ext2fs_subr.c
cvs rdiff -u -r1.118 -r1.119 src/sys/ufs/ext2fs/ext2fs_vnops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/ufs/ext2fs/ext2fs_dinode.h
diff -u src/sys/ufs/ext2fs/ext2fs_dinode.h:1.28 src/sys/ufs/ext2fs/ext2fs_dinode.h:1.29
--- src/sys/ufs/ext2fs/ext2fs_dinode.h:1.28	Wed Aug  3 21:53:02 2016
+++ src/sys/ufs/ext2fs/ext2fs_dinode.h	Wed Aug  3 23:29:05 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ext2fs_dinode.h,v 1.28 2016/08/03 21:53:02 jdolecek Exp $	*/
+/*	$NetBSD: ext2fs_dinode.h,v 1.29 2016/08/03 23:29:05 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1982, 1989, 1993
@@ -189,6 +189,52 @@ struct ext2fs_dinode {
 	)
 
 /*
+ * Time encoding
+ * Lower two bits of extra field are extra high bits for epoch; unfortunately still, Linux kernels treat 11 there as 00 for compatibility
+ * Rest of extra fields are nanoseconds
+ */
+static __inline void
+ext2fs_dinode_time_get(struct timespec *ts, uint32_t epoch, uint32_t extra)
+{
+	ts->tv_sec = (signed) epoch;
+
+	if (extra) {
+		uint64_t epoch_bits = extra & 0x3;
+		/* XXX compatibility with linux kernel < 4.20 */
+		if (epoch_bits == 3 && ts->tv_sec < 0)
+			epoch_bits = 0;
+
+		ts->tv_sec |= epoch_bits << 32;
+
+		ts->tv_nsec = extra >> 2;
+	} else {
+		ts->tv_nsec = 0;
+	}
+}
+#define EXT2_DINODE_TIME_GET(ts, dinode, field, isize) \
+	ext2fs_dinode_time_get(ts, (dinode)->field, \
+		EXT2_DINODE_FITS(dinode, field ## _extra, isize) \
+			? (dinode)->field ## _extra : 0 \
+	)
+
+static __inline void
+ext2fs_dinode_time_set(const struct timespec *ts, uint32_t *epoch, uint32_t *extra)
+{
+	*epoch = (int32_t) ts->tv_sec;
+
+	if (extra) {
+		uint32_t epoch_bits = (ts->tv_sec >> 32) & 0x3;
+
+		*extra = (ts->tv_nsec << 2) | epoch_bits;
+	}
+}
+#define EXT2_DINODE_TIME_SET(ts, dinode, field, isize) \
+	ext2fs_dinode_time_set(ts, &(dinode)->field, \
+		EXT2_DINODE_FITS(dinode, field ## _extra, isize) \
+			? &(dinode)->field ## _extra : NULL \
+	)
+
+/*
  * The e2di_blocks fields may be overlaid with other information for
  * file types that do not have associated disk storage. Block
  * and character devices overlay the first data block with their

Index: src/sys/ufs/ext2fs/ext2fs_subr.c
diff -u src/sys/ufs/ext2fs/ext2fs_subr.c:1.31 src/sys/ufs/ext2fs/ext2fs_subr.c:1.32
--- src/sys/ufs/ext2fs/ext2fs_subr.c:1.31	Sat Mar 28 19:24:04 2015
+++ src/sys/ufs/ext2fs/ext2fs_subr.c	Wed Aug  3 23:29:05 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ext2fs_subr.c,v 1.31 2015/03/28 19:24:04 maxv Exp $	*/
+/*	$NetBSD: ext2fs_subr.c,v 1.32 2016/08/03 23:29:05 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -60,7 +60,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_subr.c,v 1.31 2015/03/28 19:24:04 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_subr.c,v 1.32 2016/08/03 23:29:05 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -115,18 +115,18 @@ ext2fs_itimes(struct inode *ip, const st
 	if (ip->i_flag & IN_ACCESS) {
 		if (acc == NULL)
 			acc = &now;
-		ip->i_e2fs_atime = acc->tv_sec;
+		EXT2_DINODE_TIME_SET(acc, ip->i_din.e2fs_din, e2di_atime, EXT2_DINODE_SIZE(ip->i_e2fs));
 	}
 	if (ip->i_flag & (IN_UPDATE | IN_MODIFY)) {
 		if (mod == NULL)
 			mod = &now;
-		ip->i_e2fs_mtime = mod->tv_sec;
+		EXT2_DINODE_TIME_SET(mod, ip->i_din.e2fs_din, e2di_mtime, EXT2_DINODE_SIZE(ip->i_e2fs));
 		ip->i_modrev++;
 	}
 	if (ip->i_flag & (IN_CHANGE | IN_MODIFY)) {
 		if (cre == NULL)
 			cre = &now;
-		ip->i_e2fs_ctime = cre->tv_sec;
+		EXT2_DINODE_TIME_SET(cre, ip->i_din.e2fs_din, e2di_ctime, EXT2_DINODE_SIZE(ip->i_e2fs));
 	}
 	if (ip->i_flag & (IN_ACCESS | IN_MODIFY))
 		ip->i_flag |= IN_ACCESSED;

Index: src/sys/ufs/ext2fs/ext2fs_vnops.c
diff -u src/sys/ufs/ext2fs/ext2fs_vnops.c:1.118 src/sys/ufs/ext2fs/ext2fs_vnops.c:1.119
--- src/sys/ufs/ext2fs/ext2fs_vnops.c:1.118	Wed Aug  3 21:53:03 2016
+++ src/sys/ufs/ext2fs/ext2fs_vnops.c	Wed Aug  3 23:29:05 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ext2fs_vnops.c,v 1.118 2016/08/03 21:53:03 jdolecek Exp $	*/
+/*	$NetBSD: ext2fs_vnops.c,v 1.119 2016/08/03 23:29:05 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -65,7 +65,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.118 2016/08/03 21:53:03 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.119 2016/08/03 23:29:05 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -305,12 +305,12 @@ ext2fs_getattr(void *v)
 	vap->va_gid = ip->i_gid;
 	vap->va_rdev = (dev_t)fs2h32(ip->i_din.e2fs_din->e2di_rdev);
 	vap->va_size = vp->v_size;
-	vap->va_atime.tv_sec = ip->i_e2fs_atime;
-	vap->va_atime.tv_nsec = 0;
-	vap->va_mtime.tv_sec = ip->i_e2fs_mtime;
-	vap->va_mtime.tv_nsec = 0;
-	vap->va_ctime.tv_sec = ip->i_e2fs_ctime;
-	vap->va_ctime.tv_nsec = 0;
+	EXT2_DINODE_TIME_GET(&vap->va_atime, ip->i_din.e2fs_din, e2di_atime, EXT2_DINODE_SIZE(ip->i_e2fs));
+	EXT2_DINODE_TIME_GET(&vap->va_mtime, ip->i_din.e2fs_din, e2di_mtime, EXT2_DINODE_SIZE(ip->i_e2fs));
+	EXT2_DINODE_TIME_GET(&vap->va_ctime, ip->i_din.e2fs_din, e2di_ctime, EXT2_DINODE_SIZE(ip->i_e2fs));
+	if (EXT2_DINODE_FITS(ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs))) {
+		EXT2_DINODE_TIME_GET(&vap->va_birthtime, ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs));
+	}
 #ifdef EXT2FS_SYSTEM_FLAGS
 	vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
 	vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
@@ -439,7 +439,7 @@ ext2fs_setattr(void *v)
 			return (error);
 	}
 	ip = VTOI(vp);
-	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_birthtime.tv_sec != VNOVAL) {
 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
 			return (EROFS);
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
@@ -455,6 +455,11 @@ ext2fs_setattr(void *v)
 			if (vp->v_mount->mnt_flag & MNT_RELATIME)
 				ip->i_flag |= IN_ACCESS;
 		}
+		if (vap->va_birthtime.tv_sec != VNOVAL &&
+		    EXT2_DINODE_FITS(ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs))) {
+
+			EXT2_DINODE_TIME_SET(&vap->va_birthtime, ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs));
+		}
 		error = ext2fs_update(vp, &vap->va_atime, &vap->va_mtime,
 			UPDATE_WAIT);
 		if (error)

Reply via email to