shashi
shashi

Reputation: 1049

File.canWrite and Files.isWritable not giving correct value on Linux

I have this test java program

import java.io.File;
import java.nio.file.FileSystems;
import java.nio.file.Files;

public class TestFileReadOnly
{    
    public static void main(String[] args)
    {
        String filePath = args[0];
        File f = new File(filePath);

        System.out.println("File.canWrite() for file: " + filePath + ", is: " + f.canWrite());
        System.out.println("Files.isWritable() for file: " + filePath + ", is: " + Files.isWritable(FileSystems.getDefault().getPath(f.getParent(), f.getName())));
    }
}  

I login on Linux using root and create two files.

echo "test file" > /root/ro.txt
echo "test file" > /root/rw.txt
chmod 444 /root/ro.txt
chmod 777 /root/rw.txt

When I execute the test program this way, the output is always incorrect

[root@xxx ~]# /jdk1.8.0_31/bin/java TestFileReadOnly /root/ro.txt
File.canWrite() for file: /root/ro.txt, is: true
Files.isWritable() for file: /root/ro.txt, is: true
[root@xxx ~]# /jdk1.8.0_31/bin/java TestFileReadOnly /root/rw.txt
File.canWrite() for file: /root/rw.txt, is: true
Files.isWritable() for file: /root/rw.txt, is: true

I am basically looking for java code to verify if the file is read only, but am not able to acheive it using above. However, this works well on Windows. I tried compiling and executing using jdk1.7.0_07, jdk1.7.0_75 and jdk1.8.0_31 but the result is same. Any help to address this is highly appreciated.

Solution: Used @Matteo 's suggestion to use PosixFileAttributes for UNIX-like platforms. The working code is given below:

private boolean isFileReadOnly(File file)
{
    boolean isReadOnly = false;
    if (System.getProperty("os.name").startsWith("Windows"))
    {
        // All Windows versions
        isReadOnly = !file.canWrite();
    }
    else
    {
        // All Unix-like OSes.
        Path path = Paths.get(file.getParent(), file.getName());
        PosixFileAttributes attributes = null;
        try
        {
            attributes = Files.getFileAttributeView(path, PosixFileAttributeView.class).readAttributes();
        }
        catch (java.io.IOException e)
        {
            // File presence is guaranteed. Ignore
            e.printStackTrace();
        }

        if (attributes != null)
        {
            // A file is read-only in Linux only when it has 0444 permissions.
            Set<PosixFilePermission> permissions = attributes.permissions();

            if (!permissions.contains(PosixFilePermission.OWNER_WRITE)
                && !permissions.contains(PosixFilePermission.OWNER_EXECUTE)
                && !permissions.contains(PosixFilePermission.GROUP_WRITE)
                && !permissions.contains(PosixFilePermission.GROUP_EXECUTE)
                && !permissions.contains(PosixFilePermission.OTHERS_WRITE)
                && !permissions.contains(PosixFilePermission.OTHERS_EXECUTE))
            {
                isReadOnly = true;
            }
        }
    }
    return isReadOnly;
}

Upvotes: 5

Views: 2181

Answers (1)

Matteo
Matteo

Reputation: 14940

Executing your program as a normal user you will get false in both cases as you are not able the /root directory.

Executing your program as root you will get true in both cases as root can write a file even without the write permission:

$ echo uuu > ro.txt 
$ echo > ro.txt 
$ ls -l ro.txt 
-r--r--r-- 1 root root 1 Feb  6 15:03 ro.txt
$ cat ro.txt 

$ echo Test > ro.txt 
$ cat ro.txt 
Test

Upvotes: 3

Related Questions