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

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

Reviewed-by: chegar
上级 d497139d
......@@ -147,11 +147,11 @@ public interface BasicFileAttributeView
* this method has no effect.
*
* <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>
* Path path = ...
* FileTime time = ...
* Files.getFileAttributeView(path, BasicFileAttributeView.class).setTimes(null, null, time);
* Files.getFileAttributeView(path, BasicFileAttributeView.class).setTimes(null, time, null);
* </pre>
*
* @param lastModifiedTime
......
......@@ -84,7 +84,7 @@ class UnixChannelFactory {
}
continue;
}
if (option == LinkOption.NOFOLLOW_LINKS && supportsNoFollowLinks()) {
if (option == LinkOption.NOFOLLOW_LINKS && O_NOFOLLOW != 0) {
flags.noFollowLinks = true;
continue;
}
......@@ -218,7 +218,7 @@ class UnixChannelFactory {
// follow links by default
boolean followLinks = true;
if (!flags.createNew && (flags.noFollowLinks || flags.deleteOnClose)) {
if (flags.deleteOnClose && !supportsNoFollowLinks()) {
if (flags.deleteOnClose && O_NOFOLLOW == 0) {
try {
if (UnixFileAttributes.get(path, false).isSymbolicLink())
throw new UnixException("DELETE_ON_CLOSE specified and file is a symbolic link");
......
......@@ -189,7 +189,7 @@ class UnixCopyFile {
// copy time stamps last
if (flags.copyBasicAttributes) {
try {
if (dfd >= 0) {
if (dfd >= 0 && futimesSupported()) {
futimes(dfd,
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
......@@ -269,9 +269,15 @@ class UnixCopyFile {
// copy time attributes
if (flags.copyBasicAttributes) {
try {
futimes(fo,
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
if (futimesSupported()) {
futimes(fo,
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) {
if (flags.failIfUnableToCopyBasic)
x.rethrowAsIOException(target);
......
......@@ -73,6 +73,8 @@ class UnixFileAttributeViews {
int fd = file.openForAttributeAccess(followLinks);
try {
// assert followLinks || !UnixFileAttributes.get(fd).isSymbolicLink();
// if not changing both attributes then need existing attributes
if (lastModifiedTime == null || lastAccessTime == null) {
try {
......@@ -92,9 +94,13 @@ class UnixFileAttributeViews {
boolean retry = false;
try {
futimes(fd, accessValue, modValue);
if (futimesSupported()) {
futimes(fd, accessValue, modValue);
} else {
utimes(file, accessValue, modValue);
}
} 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.
if (x.errno() == UnixConstants.EINVAL &&
(modValue < 0L || accessValue < 0L)) {
......@@ -107,7 +113,11 @@ class UnixFileAttributeViews {
if (modValue < 0L) modValue = 0L;
if (accessValue < 0L) accessValue= 0L;
try {
futimes(fd, accessValue, modValue);
if (futimesSupported()) {
futimes(fd, accessValue, modValue);
} else {
utimes(file, accessValue, modValue);
}
} catch (UnixException x) {
x.rethrowAsIOException(file);
}
......
......@@ -51,6 +51,7 @@ class UnixFileAttributes
private long st_mtime_nsec;
private long st_ctime_sec;
private long st_ctime_nsec;
private long st_birthtime_sec;
// created lazily
private volatile UserPrincipal owner;
......@@ -139,7 +140,12 @@ class UnixFileAttributes
@Override
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
......
......@@ -394,9 +394,9 @@ public abstract class UnixFileSystemProvider
if (filter == null)
throw new NullPointerException();
// can't return SecureDirectoryStream on kernels that don't support
// openat, etc.
if (!supportsAtSysCalls() || !supportsNoFollowLinks()) {
// can't return SecureDirectoryStream on kernels that don't support openat
// or O_NOFOLLOW
if (!openatSupported() || O_NOFOLLOW == 0) {
try {
long ptr = opendir(dir);
return new UnixDirectoryStream(dir, ptr, filter);
......
......@@ -537,30 +537,42 @@ class UnixNativeDispatcher {
*/
static native byte[] strerror(int errnum);
// indicates if openat, unlinkat, etc. is supported
private static final boolean hasAtSysCalls;
static boolean supportsAtSysCalls() {
return hasAtSysCalls;
}
/**
* Capabilities
*/
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 {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("nio");
return null;
}});
int flags = init();
hasAtSysCalls = (flags & HAS_AT_SYSCALLS) > 0;
capabilities = init();
}
}
......@@ -769,7 +769,7 @@ class UnixPath
int openForAttributeAccess(boolean followLinks) throws IOException {
int flags = O_RDONLY;
if (!followLinks) {
if (!supportsNoFollowLinks())
if (O_NOFOLLOW == 0)
throw new IOException("NOFOLLOW_LINKS is not supported on this platform");
flags |= O_NOFOLLOW;
}
......
......@@ -97,6 +97,10 @@ static jfieldID attrs_st_mtime_nsec;
static jfieldID attrs_st_ctime_sec;
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_blocks;
static jfieldID attrs_f_bfree;
......@@ -171,7 +175,7 @@ static void throwUnixException(JNIEnv* env, int errnum) {
JNIEXPORT jint JNICALL
Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
{
jint flags = 0;
jint capabilities = 0;
jclass clazz;
clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes");
......@@ -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_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");
if (clazz == NULL) {
return 0;
......@@ -233,14 +241,31 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper;
#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 &&
my_unlinkat_func != NULL && my_renameat_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
......@@ -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_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__)
(*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);
......
......@@ -70,22 +70,16 @@ public class Basic {
check(f.lastModified()/1000 == attrs.lastModifiedTime().to(TimeUnit.SECONDS),
"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
BasicFileAttributeView view =
Files.getFileAttributeView(file, BasicFileAttributeView.class);
BasicFileAttributes dirAttrs = Files.readAttributes(dir, BasicFileAttributes.class);
view.setTimes(dirAttrs.lastModifiedTime(), null, null);
if (dirAttrs.creationTime() != null) {
view.setTimes(null, null, dirAttrs.creationTime());
}
attrs = view.readAttributes();
check(attrs.lastModifiedTime().equals(dirAttrs.lastModifiedTime()),
"last-modified time should be equal");
if (dirAttrs.creationTime() != null) {
check(attrs.creationTime().equals(dirAttrs.creationTime()),
"create time should be the same");
}
// security tests
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.
先完成此消息的编辑!
想要评论请 注册