@Override public List<AclEntry> getAcl() throws IOException { // permission check checkAccess(file, true, false); // open file (will fail if file is a link and not following links) int fd = file.openForAttributeAccess(followLinks); try { long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES); try { // read ACL and decode it int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address); assert n >= 0; return decode(address, n); } catch (UnixException x) { if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) { throw new FileSystemException( file.getPathForExceptionMessage(), null, x.getMessage() + " (file system does not support NFSv4 ACLs)"); } x.rethrowAsIOException(file); return null; // keep compiler happy } finally { unsafe.freeMemory(address); } } finally { close(fd); } }
@Override public void setAcl(List<AclEntry> acl) throws IOException { // permission check checkAccess(file, false, true); // open file (will fail if file is a link and not following links) int fd = file.openForAttributeAccess(followLinks); try { // SECURITY: need to copy list as can change during processing acl = new ArrayList<AclEntry>(acl); int n = acl.size(); long address = unsafe.allocateMemory(SIZEOF_ACE_T * n); try { encode(acl, address); facl(fd, ACE_SETACL, n, address); } catch (UnixException x) { if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) { throw new FileSystemException( file.getPathForExceptionMessage(), null, x.getMessage() + " (file system does not support NFSv4 ACLs)"); } if (x.errno() == EINVAL && (n < 3)) throw new IOException("ACL must contain at least 3 entries"); x.rethrowAsIOException(file); } finally { unsafe.freeMemory(address); } } finally { close(fd); } }
@Override public UnixFileAttributes readAttributes() throws IOException { checkReadExtended(); try { return UnixFileAttributes.get(file, followLinks); } catch (UnixException x) { x.rethrowAsIOException(file); return null; // keep compiler happy } }
@Override public BasicFileAttributes readAttributes() throws IOException { file.checkRead(); try { UnixFileAttributes attrs = UnixFileAttributes.get(file, followLinks); return attrs.asBasicFileAttributes(); } catch (UnixException x) { x.rethrowAsIOException(file); return null; // keep compiler happy } }
@Override public UserPrincipal getOwner() throws IOException { checkAccess(file, true, false); try { UnixFileAttributes attrs = UnixFileAttributes.get(file, followLinks); return UnixUserPrincipals.fromUid(attrs.uid()); } catch (UnixException x) { x.rethrowAsIOException(file); return null; // keep compile happy } }
// chown final void setOwners(int uid, int gid) throws IOException { checkWriteExtended(); try { if (followLinks) { chown(file, uid, gid); } else { lchown(file, uid, gid); } } catch (UnixException x) { x.rethrowAsIOException(file); } }
// chmod final void setMode(int mode) throws IOException { checkWriteExtended(); try { if (followLinks) { chmod(file, mode); } else { int fd = file.openForAttributeAccess(false); try { fchmod(fd, mode); } finally { close(fd); } } } catch (UnixException x) { x.rethrowAsIOException(file); } }
@Override public void setOwner(UserPrincipal owner) throws IOException { checkAccess(file, true, false); if (!(owner instanceof UnixUserPrincipals.User)) throw new ProviderMismatchException(); if (owner instanceof UnixUserPrincipals.Group) throw new IOException("'owner' parameter is a group"); int uid = ((UnixUserPrincipals.User) owner).uid(); try { if (followLinks) { lchown(file, uid, -1); } else { chown(file, uid, -1); } } catch (UnixException x) { x.rethrowAsIOException(file); } }
@Override public void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, FileTime createTime) throws IOException { // null => don't change if (lastModifiedTime == null && lastAccessTime == null) { // no effect return; } // permission check file.checkWrite(); int fd = file.openForAttributeAccess(followLinks); try { // 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(file); } } // uptime times long modValue = lastModifiedTime.to(TimeUnit.MICROSECONDS); long accessValue = lastAccessTime.to(TimeUnit.MICROSECONDS); boolean retry = false; try { futimes(fd, accessValue, modValue); } catch (UnixException x) { // if futimes 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(file); } } if (retry) { if (modValue < 0L) modValue = 0L; if (accessValue < 0L) accessValue = 0L; try { futimes(fd, accessValue, modValue); } catch (UnixException x) { x.rethrowAsIOException(file); } } } finally { close(fd); } }