提交 53e20158 编写于 作者: A alanb

8011536: (fs) BasicFileAttributes.creationTime() should return birth time (mac)

Reviewed-by: chegar
上级 d497139d
...@@ -147,11 +147,11 @@ public interface BasicFileAttributeView ...@@ -147,11 +147,11 @@ public interface BasicFileAttributeView
* this method has no effect. * this method has no effect.
* *
* <p> <b>Usage Example:</b> * <p> <b>Usage Example:</b>
* Suppose we want to change a file's creation time. * Suppose we want to change a file's last access time.
* <pre> * <pre>
* Path path = ... * Path path = ...
* FileTime time = ... * FileTime time = ...
* Files.getFileAttributeView(path, BasicFileAttributeView.class).setTimes(null, null, time); * Files.getFileAttributeView(path, BasicFileAttributeView.class).setTimes(null, time, null);
* </pre> * </pre>
* *
* @param lastModifiedTime * @param lastModifiedTime
......
...@@ -84,7 +84,7 @@ class UnixChannelFactory { ...@@ -84,7 +84,7 @@ class UnixChannelFactory {
} }
continue; continue;
} }
if (option == LinkOption.NOFOLLOW_LINKS && supportsNoFollowLinks()) { if (option == LinkOption.NOFOLLOW_LINKS && O_NOFOLLOW != 0) {
flags.noFollowLinks = true; flags.noFollowLinks = true;
continue; continue;
} }
...@@ -218,7 +218,7 @@ class UnixChannelFactory { ...@@ -218,7 +218,7 @@ class UnixChannelFactory {
// follow links by default // follow links by default
boolean followLinks = true; boolean followLinks = true;
if (!flags.createNew && (flags.noFollowLinks || flags.deleteOnClose)) { if (!flags.createNew && (flags.noFollowLinks || flags.deleteOnClose)) {
if (flags.deleteOnClose && !supportsNoFollowLinks()) { if (flags.deleteOnClose && O_NOFOLLOW == 0) {
try { try {
if (UnixFileAttributes.get(path, false).isSymbolicLink()) if (UnixFileAttributes.get(path, false).isSymbolicLink())
throw new UnixException("DELETE_ON_CLOSE specified and file is a symbolic link"); throw new UnixException("DELETE_ON_CLOSE specified and file is a symbolic link");
......
...@@ -189,7 +189,7 @@ class UnixCopyFile { ...@@ -189,7 +189,7 @@ class UnixCopyFile {
// copy time stamps last // copy time stamps last
if (flags.copyBasicAttributes) { if (flags.copyBasicAttributes) {
try { try {
if (dfd >= 0) { if (dfd >= 0 && futimesSupported()) {
futimes(dfd, futimes(dfd,
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS), attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS)); attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
...@@ -269,9 +269,15 @@ class UnixCopyFile { ...@@ -269,9 +269,15 @@ class UnixCopyFile {
// copy time attributes // copy time attributes
if (flags.copyBasicAttributes) { if (flags.copyBasicAttributes) {
try { try {
futimes(fo, if (futimesSupported()) {
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS), futimes(fo,
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS)); attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
} else {
utimes(target,
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
}
} catch (UnixException x) { } catch (UnixException x) {
if (flags.failIfUnableToCopyBasic) if (flags.failIfUnableToCopyBasic)
x.rethrowAsIOException(target); x.rethrowAsIOException(target);
......
...@@ -73,6 +73,8 @@ class UnixFileAttributeViews { ...@@ -73,6 +73,8 @@ class UnixFileAttributeViews {
int fd = file.openForAttributeAccess(followLinks); int fd = file.openForAttributeAccess(followLinks);
try { try {
// assert followLinks || !UnixFileAttributes.get(fd).isSymbolicLink();
// if not changing both attributes then need existing attributes // if not changing both attributes then need existing attributes
if (lastModifiedTime == null || lastAccessTime == null) { if (lastModifiedTime == null || lastAccessTime == null) {
try { try {
...@@ -92,9 +94,13 @@ class UnixFileAttributeViews { ...@@ -92,9 +94,13 @@ class UnixFileAttributeViews {
boolean retry = false; boolean retry = false;
try { try {
futimes(fd, accessValue, modValue); if (futimesSupported()) {
futimes(fd, accessValue, modValue);
} else {
utimes(file, accessValue, modValue);
}
} catch (UnixException x) { } catch (UnixException x) {
// if futimes fails with EINVAL and one/both of the times is // if futimes/utimes fails with EINVAL and one/both of the times is
// negative then we adjust the value to the epoch and retry. // negative then we adjust the value to the epoch and retry.
if (x.errno() == UnixConstants.EINVAL && if (x.errno() == UnixConstants.EINVAL &&
(modValue < 0L || accessValue < 0L)) { (modValue < 0L || accessValue < 0L)) {
...@@ -107,7 +113,11 @@ class UnixFileAttributeViews { ...@@ -107,7 +113,11 @@ class UnixFileAttributeViews {
if (modValue < 0L) modValue = 0L; if (modValue < 0L) modValue = 0L;
if (accessValue < 0L) accessValue= 0L; if (accessValue < 0L) accessValue= 0L;
try { try {
futimes(fd, accessValue, modValue); if (futimesSupported()) {
futimes(fd, accessValue, modValue);
} else {
utimes(file, accessValue, modValue);
}
} catch (UnixException x) { } catch (UnixException x) {
x.rethrowAsIOException(file); x.rethrowAsIOException(file);
} }
......
...@@ -51,6 +51,7 @@ class UnixFileAttributes ...@@ -51,6 +51,7 @@ class UnixFileAttributes
private long st_mtime_nsec; private long st_mtime_nsec;
private long st_ctime_sec; private long st_ctime_sec;
private long st_ctime_nsec; private long st_ctime_nsec;
private long st_birthtime_sec;
// created lazily // created lazily
private volatile UserPrincipal owner; private volatile UserPrincipal owner;
...@@ -139,7 +140,12 @@ class UnixFileAttributes ...@@ -139,7 +140,12 @@ class UnixFileAttributes
@Override @Override
public FileTime creationTime() { public FileTime creationTime() {
return lastModifiedTime(); if (UnixNativeDispatcher.birthtimeSupported()) {
return FileTime.from(st_birthtime_sec, TimeUnit.SECONDS);
} else {
// return last modified when birth time not supported
return lastModifiedTime();
}
} }
@Override @Override
......
...@@ -394,9 +394,9 @@ public abstract class UnixFileSystemProvider ...@@ -394,9 +394,9 @@ public abstract class UnixFileSystemProvider
if (filter == null) if (filter == null)
throw new NullPointerException(); throw new NullPointerException();
// can't return SecureDirectoryStream on kernels that don't support // can't return SecureDirectoryStream on kernels that don't support openat
// openat, etc. // or O_NOFOLLOW
if (!supportsAtSysCalls() || !supportsNoFollowLinks()) { if (!openatSupported() || O_NOFOLLOW == 0) {
try { try {
long ptr = opendir(dir); long ptr = opendir(dir);
return new UnixDirectoryStream(dir, ptr, filter); return new UnixDirectoryStream(dir, ptr, filter);
......
...@@ -537,30 +537,42 @@ class UnixNativeDispatcher { ...@@ -537,30 +537,42 @@ class UnixNativeDispatcher {
*/ */
static native byte[] strerror(int errnum); static native byte[] strerror(int errnum);
// indicates if openat, unlinkat, etc. is supported /**
private static final boolean hasAtSysCalls; * Capabilities
static boolean supportsAtSysCalls() { */
return hasAtSysCalls; private static final int SUPPORTS_OPENAT = 1 << 1; // syscalls
} private static final int SUPPORTS_FUTIMES = 1 << 2;
private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features
private static final int capabilities;
static boolean supportsNoFollowLinks() { /**
return UnixConstants.O_NOFOLLOW != 0; * Supports openat and other *at calls.
*/
static boolean openatSupported() {
return (capabilities & SUPPORTS_OPENAT) != 0;
} }
// initialize syscalls and fieldIDs /**
private static native int init(); * Supports futimes or futimesat
*/
static boolean futimesSupported() {
return (capabilities & SUPPORTS_FUTIMES) != 0;
}
// flags returned by init to indicate capabilities /**
private static final int HAS_AT_SYSCALLS = 0x1; * Supports file birth (creation) time attribute
*/
static boolean birthtimeSupported() {
return (capabilities & SUPPORTS_BIRTHTIME) != 0;
}
private static native int init();
static { static {
AccessController.doPrivileged(new PrivilegedAction<Void>() { AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() { public Void run() {
System.loadLibrary("nio"); System.loadLibrary("nio");
return null; return null;
}}); }});
int flags = init(); capabilities = init();
hasAtSysCalls = (flags & HAS_AT_SYSCALLS) > 0;
} }
} }
...@@ -769,7 +769,7 @@ class UnixPath ...@@ -769,7 +769,7 @@ class UnixPath
int openForAttributeAccess(boolean followLinks) throws IOException { int openForAttributeAccess(boolean followLinks) throws IOException {
int flags = O_RDONLY; int flags = O_RDONLY;
if (!followLinks) { if (!followLinks) {
if (!supportsNoFollowLinks()) if (O_NOFOLLOW == 0)
throw new IOException("NOFOLLOW_LINKS is not supported on this platform"); throw new IOException("NOFOLLOW_LINKS is not supported on this platform");
flags |= O_NOFOLLOW; flags |= O_NOFOLLOW;
} }
......
...@@ -97,6 +97,10 @@ static jfieldID attrs_st_mtime_nsec; ...@@ -97,6 +97,10 @@ static jfieldID attrs_st_mtime_nsec;
static jfieldID attrs_st_ctime_sec; static jfieldID attrs_st_ctime_sec;
static jfieldID attrs_st_ctime_nsec; static jfieldID attrs_st_ctime_nsec;
#ifdef _DARWIN_FEATURE_64_BIT_INODE
static jfieldID attrs_st_birthtime_sec;
#endif
static jfieldID attrs_f_frsize; static jfieldID attrs_f_frsize;
static jfieldID attrs_f_blocks; static jfieldID attrs_f_blocks;
static jfieldID attrs_f_bfree; static jfieldID attrs_f_bfree;
...@@ -171,7 +175,7 @@ static void throwUnixException(JNIEnv* env, int errnum) { ...@@ -171,7 +175,7 @@ static void throwUnixException(JNIEnv* env, int errnum) {
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
{ {
jint flags = 0; jint capabilities = 0;
jclass clazz; jclass clazz;
clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes"); clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes");
...@@ -193,6 +197,10 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) ...@@ -193,6 +197,10 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
attrs_st_ctime_sec = (*env)->GetFieldID(env, clazz, "st_ctime_sec", "J"); attrs_st_ctime_sec = (*env)->GetFieldID(env, clazz, "st_ctime_sec", "J");
attrs_st_ctime_nsec = (*env)->GetFieldID(env, clazz, "st_ctime_nsec", "J"); attrs_st_ctime_nsec = (*env)->GetFieldID(env, clazz, "st_ctime_nsec", "J");
#ifdef _DARWIN_FEATURE_64_BIT_INODE
attrs_st_birthtime_sec = (*env)->GetFieldID(env, clazz, "st_birthtime_sec", "J");
#endif
clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes"); clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes");
if (clazz == NULL) { if (clazz == NULL) {
return 0; return 0;
...@@ -233,14 +241,31 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) ...@@ -233,14 +241,31 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper; my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper;
#endif #endif
/* supports futimes or futimesat */
#ifdef _ALLBSD_SOURCE
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;
#else
if (my_futimesat_func != NULL)
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;
#endif
/* supports openat, etc. */
if (my_openat64_func != NULL && my_fstatat64_func != NULL && if (my_openat64_func != NULL && my_fstatat64_func != NULL &&
my_unlinkat_func != NULL && my_renameat_func != NULL && my_unlinkat_func != NULL && my_renameat_func != NULL &&
my_futimesat_func != NULL && my_fdopendir_func != NULL) my_futimesat_func != NULL && my_fdopendir_func != NULL)
{ {
flags |= sun_nio_fs_UnixNativeDispatcher_HAS_AT_SYSCALLS; capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_OPENAT;
} }
return flags; /* supports file birthtime */
#ifdef _DARWIN_FEATURE_64_BIT_INODE
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME;
#endif
return capabilities;
} }
JNIEXPORT jbyteArray JNICALL JNIEXPORT jbyteArray JNICALL
...@@ -405,6 +430,10 @@ static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { ...@@ -405,6 +430,10 @@ static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) {
(*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime); (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime);
(*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime); (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime);
#ifdef _DARWIN_FEATURE_64_BIT_INODE
(*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime);
#endif
#if (_POSIX_C_SOURCE >= 200809L) || defined(__solaris__) #if (_POSIX_C_SOURCE >= 200809L) || defined(__solaris__)
(*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec); (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec);
(*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec); (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec);
......
...@@ -70,22 +70,16 @@ public class Basic { ...@@ -70,22 +70,16 @@ public class Basic {
check(f.lastModified()/1000 == attrs.lastModifiedTime().to(TimeUnit.SECONDS), check(f.lastModified()/1000 == attrs.lastModifiedTime().to(TimeUnit.SECONDS),
"last-modified time should be the same"); "last-modified time should be the same");
// copy last-modified time and file create time from directory to file, // copy last-modified time from directory to file,
// re-read attribtues, and check they match // re-read attribtues, and check they match
BasicFileAttributeView view = BasicFileAttributeView view =
Files.getFileAttributeView(file, BasicFileAttributeView.class); Files.getFileAttributeView(file, BasicFileAttributeView.class);
BasicFileAttributes dirAttrs = Files.readAttributes(dir, BasicFileAttributes.class); BasicFileAttributes dirAttrs = Files.readAttributes(dir, BasicFileAttributes.class);
view.setTimes(dirAttrs.lastModifiedTime(), null, null); view.setTimes(dirAttrs.lastModifiedTime(), null, null);
if (dirAttrs.creationTime() != null) {
view.setTimes(null, null, dirAttrs.creationTime());
}
attrs = view.readAttributes(); attrs = view.readAttributes();
check(attrs.lastModifiedTime().equals(dirAttrs.lastModifiedTime()), check(attrs.lastModifiedTime().equals(dirAttrs.lastModifiedTime()),
"last-modified time should be equal"); "last-modified time should be equal");
if (dirAttrs.creationTime() != null) {
check(attrs.creationTime().equals(dirAttrs.creationTime()),
"create time should be the same");
}
// security tests // security tests
check (!(attrs instanceof PosixFileAttributes), check (!(attrs instanceof PosixFileAttributes),
......
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 8011536
* @summary Basic test for creationTime attribute on platforms/file systems
* that support it.
* @library ../..
*/
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.attribute.*;
import java.time.Instant;
import java.io.IOException;
public class CreationTime {
private static final java.io.PrintStream err = System.err;
/**
* Reads the creationTime attribute
*/
private static FileTime creationTime(Path file) throws IOException {
return Files.readAttributes(file, BasicFileAttributes.class).creationTime();
}
/**
* Sets the creationTime attribute
*/
private static void setCreationTime(Path file, FileTime time) throws IOException {
BasicFileAttributeView view =
Files.getFileAttributeView(file, BasicFileAttributeView.class);
view.setTimes(null, null, time);
}
static void test(Path top) throws IOException {
Path file = Files.createFile(top.resolve("foo"));
/**
* Check that creationTime reported
*/
FileTime creationTime = creationTime(file);
Instant now = Instant.now();
if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) {
err.println("File creation time reported as: " + creationTime);
throw new RuntimeException("Expected to be close to: " + now);
}
/**
* Is the creationTime attribute supported here?
*/
boolean supportsCreationTimeRead = false;
boolean supportsCreationTimeWrite = false;
String os = System.getProperty("os.name");
if (os.contains("OS X") && Files.getFileStore(file).type().equals("hfs")) {
supportsCreationTimeRead = true;
} else if (os.startsWith("Windows")) {
String type = Files.getFileStore(file).type();
if (type.equals("NTFS") || type.equals("FAT")) {
supportsCreationTimeRead = true;
supportsCreationTimeWrite = true;
}
}
/**
* If the creation-time attribute is supported then change the file's
* last modified and check that it doesn't change the creation-time.
*/
if (supportsCreationTimeRead) {
// change modified time by +1 hour
Instant plusHour = Instant.now().plusSeconds(60L * 60L);
Files.setLastModifiedTime(file, FileTime.from(plusHour));
FileTime current = creationTime(file);
if (!current.equals(creationTime))
throw new RuntimeException("Creation time should not have changed");
}
/**
* If the creation-time attribute is supported and can be changed then
* check that the change is effective.
*/
if (supportsCreationTimeWrite) {
// change creation time by -1 hour
Instant minusHour = Instant.now().minusSeconds(60L * 60L);
creationTime = FileTime.from(minusHour);
setCreationTime(file, creationTime);
FileTime current = creationTime(file);
if (Math.abs(creationTime.toMillis()-current.toMillis()) > 1000L)
throw new RuntimeException("Creation time not changed");
}
}
public static void main(String[] args) throws IOException {
// create temporary directory to run tests
Path dir = TestUtil.createTemporaryDirectory();
try {
test(dir);
} finally {
TestUtil.removeAll(dir);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册