8298187: (fs) BsdFileAttributeViews::setTimes does not support lastAccessTime on HFS+

Reviewed-by: alanb
This commit is contained in:
Brian Burkhalter 2022-12-15 22:47:29 +00:00
parent 3cdbd878e6
commit 5412439445
5 changed files with 153 additions and 36 deletions

View file

@ -28,7 +28,8 @@ package sun.nio.fs;
import java.io.IOException;
import java.nio.file.attribute.FileTime;
import java.util.concurrent.TimeUnit;
import static sun.nio.fs.BsdNativeDispatcher.setattrlist;
import static sun.nio.fs.BsdNativeDispatcher.*;
import static sun.nio.fs.UnixNativeDispatcher.lutimes;
class BsdFileAttributeViews {
//
@ -49,28 +50,94 @@ class BsdFileAttributeViews {
// permission check
path.checkWrite();
int commonattr = 0;
long modValue = 0L;
if (lastModifiedTime != null) {
modValue = lastModifiedTime.to(TimeUnit.NANOSECONDS);
commonattr |= UnixConstants.ATTR_CMN_MODTIME;
boolean useLutimes = false;
try {
useLutimes = !followLinks &&
UnixFileAttributes.get(path, false).isSymbolicLink();
} catch (UnixException x) {
x.rethrowAsIOException(path);
}
long accValue = 0L;
if (lastAccessTime != null) {
accValue = lastAccessTime.to(TimeUnit.NANOSECONDS);
commonattr |= UnixConstants.ATTR_CMN_ACCTIME;
}
long createValue = 0L;
if (createTime != null) {
createValue = createTime.to(TimeUnit.NANOSECONDS);
commonattr |= UnixConstants.ATTR_CMN_CRTIME;
int fd = -1;
if (!useLutimes) {
try {
fd = path.openForAttributeAccess(followLinks);
} catch (UnixException x) {
x.rethrowAsIOException(path);
}
}
try {
setattrlist(path, commonattr, modValue, accValue, createValue,
followLinks ? 0 : UnixConstants.FSOPT_NOFOLLOW);
} catch (UnixException x) {
x.rethrowAsIOException(path);
// not all volumes support setattrlist(2), so set the last
// modified and last access times using futimens(2)/lutimes(3)
if (lastModifiedTime != null || lastAccessTime != null) {
// if not changing both attributes then need existing attributes
if (lastModifiedTime == null || lastAccessTime == null) {
try {
UnixFileAttributes attrs = UnixFileAttributes.get(fd);
if (lastModifiedTime == null)
lastModifiedTime = attrs.lastModifiedTime();
if (lastAccessTime == null)
lastAccessTime = attrs.lastAccessTime();
} catch (UnixException x) {
x.rethrowAsIOException(path);
}
}
// update times
TimeUnit timeUnit = useLutimes ?
TimeUnit.MICROSECONDS : TimeUnit.NANOSECONDS;
long modValue = lastModifiedTime.to(timeUnit);
long accessValue= lastAccessTime.to(timeUnit);
boolean retry = false;
try {
if (useLutimes)
lutimes(path, accessValue, modValue);
else
futimens(fd, accessValue, modValue);
} catch (UnixException x) {
// if futimens 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)) {
retry = true;
} else {
x.rethrowAsIOException(path);
}
}
if (retry) {
if (modValue < 0L) modValue = 0L;
if (accessValue < 0L) accessValue= 0L;
try {
if (useLutimes)
lutimes(path, accessValue, modValue);
else
futimens(fd, accessValue, modValue);
} catch (UnixException x) {
x.rethrowAsIOException(path);
}
}
}
// set the creation time using setattrlist
if (createTime != null) {
long createValue = createTime.to(TimeUnit.NANOSECONDS);
int commonattr = UnixConstants.ATTR_CMN_CRTIME;
try {
if (useLutimes)
setattrlist(path, commonattr, 0L, 0L, createValue,
followLinks ? 0 : UnixConstants.FSOPT_NOFOLLOW);
else
fsetattrlist(fd, commonattr, 0L, 0L, createValue,
followLinks ? 0 : UnixConstants.FSOPT_NOFOLLOW);
} catch (UnixException x) {
x.rethrowAsIOException(path);
}
}
} finally {
if (!useLutimes)
close(fd, e -> null);
}
}

View file

@ -104,6 +104,27 @@ class BsdNativeDispatcher extends UnixNativeDispatcher {
long createTime, long options)
throws UnixException;
/**
* fsetattrlist(int fd, struct attrlist* attrList, void* attrBuf,
* size_t attrBufSize, unsigned long options)
*/
static void fsetattrlist(int fd, int commonattr, long modTime,
long accTime, long createTime, long options)
throws UnixException
{
long comp = Blocker.begin();
try {
fsetattrlist0(fd, commonattr, modTime, accTime,
createTime, options);
} finally {
Blocker.end(comp);
}
}
private static native void fsetattrlist0(int fd, int commonattr,
long modTime, long accTime,
long createTime, long options)
throws UnixException;
// initialize field IDs
private static native void initIDs();

View file

@ -39,6 +39,7 @@
#define ISREADONLY MNT_RDONLY
#endif
#include <sys/attr.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
@ -243,17 +244,11 @@ Java_sun_nio_fs_BsdNativeDispatcher_clonefile0(JNIEnv* env, jclass this,
return 0;
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_BsdNativeDispatcher_setattrlist0(JNIEnv* env, jclass this,
jlong pathAddress, int commonattr, jlong modTime, jlong accTime,
jlong createTime, jlong options)
size_t initattrlist(jint commonattr, jlong modTime, jlong accTime,
jlong createTime, const int attrsize, char* buf, struct attrlist *attrList)
{
const char* path = (const char*)jlong_to_ptr(pathAddress);
// attributes must align on 4-byte boundaries per the getattrlist(2) spec
const int attrsize = ((sizeof(struct timespec) + 3)/4)*4;
char buf[3*attrsize];
int count = 0;
// attributes are ordered per the getattrlist(2) spec
if ((commonattr & ATTR_CMN_CRTIME) != 0) {
struct timespec* t = (struct timespec*)buf;
@ -274,12 +269,46 @@ Java_sun_nio_fs_BsdNativeDispatcher_setattrlist0(JNIEnv* env, jclass this,
count++;
}
struct attrlist attrList;
memset(&attrList, 0, sizeof(struct attrlist));
attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
attrList.commonattr = commonattr;
memset(attrList, 0, sizeof(struct attrlist));
attrList->bitmapcount = ATTR_BIT_MAP_COUNT;
attrList->commonattr = commonattr;
if (setattrlist(path, &attrList, (void*)buf, count*attrsize, options) != 0) {
return count*attrsize;
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_BsdNativeDispatcher_setattrlist0(JNIEnv* env, jclass this,
jlong pathAddress, int commonattr, jlong modTime, jlong accTime,
jlong createTime, jlong options)
{
const char* path = (const char*)jlong_to_ptr(pathAddress);
// attributes must align on 4-byte boundaries per the getattrlist(2) spec
const int attrsize = ((sizeof(struct timespec) + 3)/4)*4;
char buf[3*attrsize];
struct attrlist attrList;
size_t attrBufSize = initattrlist(commonattr, modTime, accTime, createTime,
attrsize, buf, &attrList);
if (setattrlist(path, &attrList, (void*)buf, attrBufSize, options) != 0) {
throwUnixException(env, errno);
}
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_BsdNativeDispatcher_fsetattrlist0(JNIEnv* env, jclass this,
jint fd, int commonattr, jlong modTime, jlong accTime,
jlong createTime, jlong options)
{
// attributes must align on 4-byte boundaries per the getattrlist(2) spec
const int attrsize = ((sizeof(struct timespec) + 3)/4)*4;
char buf[3*attrsize];
struct attrlist attrList;
size_t attrBufSize = initattrlist(commonattr, modTime, accTime, createTime,
attrsize, buf, &attrList);
if (fsetattrlist(fd, &attrList, (void*)buf, attrBufSize, options) != 0) {
throwUnixException(env, errno);
}
}