Merge "Added StructStat nanosecond precision fields."
diff --git a/luni/src/main/java/android/system/StructStat.java b/luni/src/main/java/android/system/StructStat.java
index ce3548f6..a1e8729 100644
--- a/luni/src/main/java/android/system/StructStat.java
+++ b/luni/src/main/java/android/system/StructStat.java
@@ -53,15 +53,24 @@
*/
public final long st_size; /*off_t*/
- /** Time of last access. */
+ /** Seconds part of time of last access. */
public final long st_atime; /*time_t*/
- /** Time of last data modification. */
+ /** StructTimespec with time of last access. */
+ public final StructTimespec st_atim;
+
+ /** Seconds part of time of last data modification. */
public final long st_mtime; /*time_t*/
- /** Time of last status change. */
+ /** StructTimespec with time of last modification. */
+ public final StructTimespec st_mtim;
+
+ /** Seconds part of time of last status change */
public final long st_ctime; /*time_t*/
+ /** StructTimespec with time of last status change. */
+ public final StructTimespec st_ctim;
+
/**
* A file system-specific preferred I/O block size for this object.
* For some file system types, this may vary from file to file.
@@ -77,6 +86,17 @@
public StructStat(long st_dev, long st_ino, int st_mode, long st_nlink, int st_uid, int st_gid,
long st_rdev, long st_size, long st_atime, long st_mtime, long st_ctime,
long st_blksize, long st_blocks) {
+ this(st_dev, st_ino, st_mode, st_nlink, st_uid, st_gid,
+ st_rdev, st_size, new StructTimespec(st_atime, 0L), new StructTimespec(st_mtime, 0L),
+ new StructTimespec(st_ctime, 0L), st_blksize, st_blocks);
+ }
+
+ /**
+ * Constructs an instance with the given field values.
+ */
+ public StructStat(long st_dev, long st_ino, int st_mode, long st_nlink, int st_uid, int st_gid,
+ long st_rdev, long st_size, StructTimespec st_atim, StructTimespec st_mtim,
+ StructTimespec st_ctim, long st_blksize, long st_blocks) {
this.st_dev = st_dev;
this.st_ino = st_ino;
this.st_mode = st_mode;
@@ -85,9 +105,12 @@
this.st_gid = st_gid;
this.st_rdev = st_rdev;
this.st_size = st_size;
- this.st_atime = st_atime;
- this.st_mtime = st_mtime;
- this.st_ctime = st_ctime;
+ this.st_atime = st_atim.tv_sec;
+ this.st_mtime = st_mtim.tv_sec;
+ this.st_ctime = st_ctim.tv_sec;
+ this.st_atim = st_atim;
+ this.st_mtim = st_mtim;
+ this.st_ctim = st_ctim;
this.st_blksize = st_blksize;
this.st_blocks = st_blocks;
}
diff --git a/luni/src/main/java/android/system/StructTimespec.java b/luni/src/main/java/android/system/StructTimespec.java
new file mode 100644
index 0000000..e999249
--- /dev/null
+++ b/luni/src/main/java/android/system/StructTimespec.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.system;
+
+import libcore.util.Objects;;
+
+/**
+ * Corresponds to C's {@code struct timespec} from {@code <time.h>}.
+ */
+public final class StructTimespec implements Comparable<StructTimespec> {
+ /** Seconds part of time of last data modification. */
+ public final long tv_sec; /*time_t*/
+
+ /** Nanoseconds (values are [0, 999999999]). */
+ public final long tv_nsec;
+
+ public StructTimespec(long tv_sec, long tv_nsec) {
+ this.tv_sec = tv_sec;
+ this.tv_nsec = tv_nsec;
+ if (tv_nsec < 0 || tv_nsec > 999_999_999) {
+ throw new IllegalArgumentException(
+ "tv_nsec value " + tv_nsec + " is not in [0, 999999999]");
+ }
+ }
+
+ @Override
+ public int compareTo(StructTimespec other) {
+ if (tv_sec > other.tv_sec) {
+ return 1;
+ }
+ if (tv_sec < other.tv_sec) {
+ return -1;
+ }
+ if (tv_nsec > other.tv_nsec) {
+ return 1;
+ }
+ if (tv_nsec < other.tv_nsec) {
+ return -1;
+ }
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toString(this);
+ }
+}
diff --git a/luni/src/main/native/libcore_io_Linux.cpp b/luni/src/main/native/libcore_io_Linux.cpp
index 1e2f3a5..176300e 100644
--- a/luni/src/main/native/libcore_io_Linux.cpp
+++ b/luni/src/main/native/libcore_io_Linux.cpp
@@ -423,16 +423,23 @@
pw_name, static_cast<jint>(pw.pw_uid), static_cast<jint>(pw.pw_gid), pw_dir, pw_shell);
}
+static jobject makeStructTimespec(JNIEnv* env, const struct timespec& ts) {
+ static jmethodID ctor = env->GetMethodID(JniConstants::structTimespecClass, "<init>",
+ "(JJ)V");
+ return env->NewObject(JniConstants::structTimespecClass, ctor,
+ static_cast<jlong>(ts.tv_sec), static_cast<jlong>(ts.tv_nsec));
+}
+
static jobject makeStructStat(JNIEnv* env, const struct stat64& sb) {
static jmethodID ctor = env->GetMethodID(JniConstants::structStatClass, "<init>",
- "(JJIJIIJJJJJJJ)V");
+ "(JJIJIIJJLandroid/system/StructTimespec;Landroid/system/StructTimespec;Landroid/system/StructTimespec;JJ)V");
return env->NewObject(JniConstants::structStatClass, ctor,
static_cast<jlong>(sb.st_dev), static_cast<jlong>(sb.st_ino),
static_cast<jint>(sb.st_mode), static_cast<jlong>(sb.st_nlink),
static_cast<jint>(sb.st_uid), static_cast<jint>(sb.st_gid),
static_cast<jlong>(sb.st_rdev), static_cast<jlong>(sb.st_size),
- static_cast<jlong>(sb.st_atime), static_cast<jlong>(sb.st_mtime),
- static_cast<jlong>(sb.st_ctime), static_cast<jlong>(sb.st_blksize),
+ makeStructTimespec(env, sb.st_atim), makeStructTimespec(env, sb.st_mtim),
+ makeStructTimespec(env, sb.st_ctim), static_cast<jlong>(sb.st_blksize),
static_cast<jlong>(sb.st_blocks));
}
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index 07ce7d2..0f47d87 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -20,6 +20,7 @@
import android.system.NetlinkSocketAddress;
import android.system.OsConstants;
import android.system.PacketSocketAddress;
+import android.system.StructStat;
import android.system.StructTimeval;
import android.system.StructUcred;
import android.system.UnixSocketAddress;
@@ -783,4 +784,23 @@
assertEquals(srcSock.getLocalPort(), address.getPort());
}
}
+
+ public void test_fstat_times() throws Exception {
+ File file = File.createTempFile("OsTest", "fstattest");
+ FileOutputStream fos = new FileOutputStream(file);
+ StructStat structStat1 = Libcore.os.fstat(fos.getFD());
+ assertEquals(structStat1.st_mtim.tv_sec, structStat1.st_mtime);
+ assertEquals(structStat1.st_ctim.tv_sec, structStat1.st_ctime);
+ assertEquals(structStat1.st_atim.tv_sec, structStat1.st_atime);
+ Thread.sleep(100);
+ fos.write(new byte[]{1,2,3});
+ fos.flush();
+ StructStat structStat2 = Libcore.os.fstat(fos.getFD());
+ fos.close();
+
+ assertEquals(-1, structStat1.st_mtim.compareTo(structStat2.st_mtim));
+ assertEquals(-1, structStat1.st_ctim.compareTo(structStat2.st_ctim));
+ assertEquals(0, structStat1.st_atim.compareTo(structStat2.st_atim));
+ }
+
}
diff --git a/non_openjdk_java_files.mk b/non_openjdk_java_files.mk
index ecd0ffa..29f8d0c 100644
--- a/non_openjdk_java_files.mk
+++ b/non_openjdk_java_files.mk
@@ -19,6 +19,7 @@
luni/src/main/java/android/system/StructStat.java \
luni/src/main/java/android/system/StructStatVfs.java \
luni/src/main/java/android/system/StructTimeval.java \
+ luni/src/main/java/android/system/StructTimespec.java \
luni/src/main/java/android/system/StructUcred.java \
luni/src/main/java/android/system/StructUtsname.java \
luni/src/main/java/android/util/MutableBoolean.java \