Paul Taylor
Paul Taylor

Reputation: 13130

How can you work out why FIles.isWritable() returns false on Windows

In my application that allows users to modify their music files occasionally I have a problem when application does not have permissions to modify a file but the user is convinced they have given it full permissions

I've discovered the Java 7 improvements and wrote this method to output the permissions

public static String displayPermissions(Path path)
{
    StringBuilder sb = new StringBuilder();
    sb.append("File "+path + " permissions\n");
    try
    {
        {
            AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class);
            if (view != null)
            {
                for (AclEntry acl : view.getAcl())
                {
                    sb.append(acl+"\n");
                }
            }
        }

        {
            PosixFileAttributeView view = Files.getFileAttributeView(path, PosixFileAttributeView.class);
            if (view != null)
            {
                PosixFileAttributes pfa = view.readAttributes();
                sb.append(":owner:"+pfa.owner().getName()+":group:"+pfa.group().getName()+":"+PosixFilePermissions.toString(pfa.permissions())+"\n");
            }
        }
    }
    catch(IOException ioe)
    {
        logger.severe("Unable to read permissions for:"+path.toString());
    }
    return sb.toString();
}

but for Windows systems it can still be rather difficult/impossible to work out why they don't have permissions

WARNING: File testdata\test157.dsf permissions
NT AUTHORITY\SYSTEM:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:DENY
BUILTIN\Administrators:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:DENY
BUILTIN\Administrators:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:ALLOW
NT AUTHORITY\SYSTEM:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:ALLOW
BUILTIN\Users:READ_DATA/READ_NAMED_ATTRS/EXECUTE/READ_ATTRIBUTES/READ_ACL/SYNCHRONIZE:ALLOW
NT AUTHORITY\Authenticated Users:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/SYNCHRONIZE:ALLOW

, any suggestions on how I can programmatically work out the reason for isWritable() (or isReadable()) failing.

Upvotes: 3

Views: 2623

Answers (2)

SubOptimal
SubOptimal

Reputation: 22983

I believe the confusion comes from the fact that the effective permission depends on the directory permissions and the file permissions.

If the user has e.g. the Write permission for a file but not the Modify permission for the containing directory he has effectively not write permission to that file. See the full matix of File and folder permissions.

To do the check in Java you can use the FileSystemProvider.checkAccess method to check the permission of

Assume following files and permissions (all permissions out of scope are removed to make it more clear). The permissions were retrieved with the icacls tool.

c:\ BUILTIN\Users:(OI)(CI)(RX) - read + execute permission

c:\bar BUILTIN\Users:(RX) - read + execute permission

c:\foo BUILTIN\Users:(F) - full permission

Sample snippet for demonstration.

public class AccessCheckDemo {
    public static void main(String[] args) throws IOException {
        String[] files = {"c:/foo", "c:/bar"};
        for (String file : files) {
            Path path = Paths.get(file);
            System.out.println("check " + path);
            System.out.println("file      Files.isWritable: "
                    + Files.isWritable(path));
            System.out.println("directory Files.isWritable: "
                    + Files.isWritable(path.getParent()));
            System.out.println();
        }
    }
}

output

check c:\foo
file      Files.isWritable: true
directory Files.isWritable: false

check c:\bar
file      Files.isWritable: true
directory Files.isWritable: false

Even BUILTIN\Users have full permissions on file c:\foo they cannot write to this file, as the permission of the directory c:\ does not permit it (only read + execute permission for this group on c:\).

As already mentioned by badsamaritan (JDK-7190897) this doesn't work properly in Java 7.

Upvotes: 3

badsamaritan
badsamaritan

Reputation: 447

any suggestions on how I can programmatically work out the reason for isWritable() (or isReadable()) failing

Maybe it is real bug, not your fault:

https://bugs.openjdk.java.net/browse/JDK-8034863

or

http://bugs.java.com/view_bug.do?bug_id=7190897


When talking about Windows permissions it is worth mentioning that they are indeed a bit strange (even Microsoft admits it): DENY has stronger priority than ALLOW, so if you allow some users to read particular file and also deny everyone every permission this deny 'overrides' everything and no one (including owner) can't read this file. That's why you don't see DENY permission selected in ACLs very often.

Upvotes: 1

Related Questions