@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);
      }
    }
 @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
    }
  }
 @Override
 public Map<String, Object> readAttributes(String[] requested) throws IOException {
   AttributesBuilder builder = AttributesBuilder.create(unixAttributeNames, requested);
   UnixFileAttributes attrs = readAttributes();
   addRequestedPosixAttributes(attrs, builder);
   if (builder.match(MODE_NAME)) builder.add(MODE_NAME, attrs.mode());
   if (builder.match(INO_NAME)) builder.add(INO_NAME, attrs.ino());
   if (builder.match(DEV_NAME)) builder.add(DEV_NAME, attrs.dev());
   if (builder.match(RDEV_NAME)) builder.add(RDEV_NAME, attrs.rdev());
   if (builder.match(NLINK_NAME)) builder.add(NLINK_NAME, attrs.nlink());
   if (builder.match(UID_NAME)) builder.add(UID_NAME, attrs.uid());
   if (builder.match(GID_NAME)) builder.add(GID_NAME, attrs.gid());
   if (builder.match(CTIME_NAME)) builder.add(CTIME_NAME, attrs.ctime());
   return builder.unmodifiableMap();
 }
 @Override
 public UnixFileAttributes readAttributes() throws IOException {
   checkReadExtended();
   try {
     return UnixFileAttributes.get(file, followLinks);
   } catch (UnixException x) {
     x.rethrowAsIOException(file);
     return null; // keep compiler happy
   }
 }