From 330b50d73484fe5d548929089e73863742a1c2e5 Mon Sep 17 00:00:00 2001
From: Henri Hannetel <henri.hannetel@pm.me>
Date: Thu, 19 Oct 2023 14:57:58 +0000
Subject: [PATCH] Add UTIME_OMIT and UTIME_NOW

---
 src/header/sys_stat/mod.rs |  3 +++
 tests/futimens.c           | 54 +++++++++++++++++++++++++++++---------
 2 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/src/header/sys_stat/mod.rs b/src/header/sys_stat/mod.rs
index 5a047a075..7d258fefb 100644
--- a/src/header/sys_stat/mod.rs
+++ b/src/header/sys_stat/mod.rs
@@ -37,6 +37,9 @@ pub const S_ISUID: c_int = 0o4_000;
 pub const S_ISGID: c_int = 0o2_000;
 pub const S_ISVTX: c_int = 0o1_000;
 
+pub const UTIME_NOW: useconds_t = (1 << 30) - 1;
+pub const UTIME_OMIT: useconds_t = (1 << 30) - 2;
+
 #[repr(C)]
 #[derive(Default)]
 pub struct stat {
diff --git a/tests/futimens.c b/tests/futimens.c
index 820e936a4..4d2594443 100644
--- a/tests/futimens.c
+++ b/tests/futimens.c
@@ -6,8 +6,31 @@
 #include <string.h>
 #include <errno.h>
 #include <stdio.h>
+#include <time.h>
 #include <unistd.h>
 
+int check_mtime(char *path, int expected_sec, int expected_nsec, int err_gap) {
+  // Checks whether the moditication time of the file located at *path* match the provided times.
+  // When err_gap is set, only checks for a match on sec with a margin of error of +/- err_gap.
+  struct stat sb;
+  if (stat(path, &sb) != 0) {
+    fprintf(stderr, "stat: %s\n", strerror(errno));
+    return -1;
+  }
+  if (err_gap > 0) {
+    if (sb.st_mtim.tv_sec < expected_sec + err_gap && sb.st_mtim.tv_sec > expected_sec - err_gap) {
+      return 0;
+    }
+  } else {
+    if (sb.st_mtim.tv_sec == expected_sec && sb.st_mtim.tv_nsec == expected_nsec) {
+      return 0;
+    }
+  }
+  fprintf(stderr, "Wrong modified time: %d.%d\n", sb.st_mtim.tv_sec, sb.st_mtim.tv_nsec);
+  return -1;
+}
+
+
 int main(int argc, char** argv) {
   char temp[] = "/tmp/stattest-XXXXXX";
   const char file[] = "/mkfifo_fifo";
@@ -47,21 +70,28 @@ int main(int argc, char** argv) {
     fprintf(stderr, "futimens: %s\n", strerror(errno));
     exit(1);
   }
+  if (check_mtime(path, 20, 0, 0) != 0) {
+    exit(1);
+  }
+  // Access times are not flushed to disk, so atime checks can't be (currently) performed
 
-  struct stat sb;
-  if (stat(path, &sb) != 0) {
-    fprintf(stderr, "stat: %s\n", strerror(errno));
+  const struct timespec omit_times[] = { { 25, UTIME_OMIT }, { 12, UTIME_OMIT } };
+  if (futimens(fd, omit_times) == -1) {
+    fprintf(stderr, "futimens: %s\n", strerror(errno));
+    exit(1);
+  }
+  if (check_mtime(path, 20, 0, 0) != 0) {
     exit(1);
   }
-  if (sb.st_mtim.tv_sec != 20 || sb.st_mtim.tv_nsec != 0) {
-    fprintf(stderr, "Wrong modified time: %d.%d\n", sb.st_mtim.tv_sec, sb.st_mtim.tv_nsec);
+
+  const struct timespec now_times[] = { { 25, UTIME_NOW }, { 12, UTIME_NOW } };
+  if (futimens(fd, now_times) == -1) {
+    fprintf(stderr, "futimens: %s\n", strerror(errno));
+    exit(1);
+  }
+  int now_ts = time(NULL);
+  if (check_mtime(path, now_ts, 0, 1) != 0) {
     exit(1);
   }
-  // Access times are not flushed to disk, so this check can't be (currently) performed
-  /*
-   * if (sb.st_atim.tv_sec != 10 || sb.st_atim.tv_nsec != 0) {
-   *  fprintf(stderr, "Wrong accessed time: %d.%d\n", sb.st_atim.tv_sec, sb.st_atim.tv_nsec);
-   *  exit(1);
-   * }
-   */
 }
+
-- 
GitLab