Working on a Java 8 project where I copy files from external sources. In one of these sources a file is set with the immutable bit flag.
In OSX this is set like so
sudo chflags schg /path/to/file
In Linux
chattr +i /path/to/file
I now need to delete the files that I have copied. I had been using Apache Commons IO to delete the directory like so,
FileUtils.deleteDirectory(new File("/path/here"));
However this crashes out with a java.io.IOException exception
.
Is there any Cross Platform way to delete these files? The process running is the owner of the file.
To force delete file using Java, we can use the FileUtils or FileDeleteStrategy class available in Apache Commons Io. We can also use FileDeleteStrategy class of apache commons io to force delete file, even if the file represents a non-enpty directory . the delete() method deletes the file object.
files. deleteifexists(Path p) method defined in Files package: This method deletes a file if it exists. It also deletes a directory mentioned in the path only if the directory is not empty. Returns: It returns true if the file was deleted by this method; false if it could not be deleted because it did not exist.
In Java, we can delete a file by using the File. delete() method of File class. The delete() method deletes the file or directory denoted by the abstract pathname. If the pathname is a directory, that directory must be empty to delete.
In Java, we can use the NIO Files. delete(Path) and Files. deleteIfExists(Path) to delete a file.
Problem : Since, we know that the file with immutable attribute set, cannot be deleted by any user. Even The root user cannot delete the following file.
Now, to be able to delete the file you have to remove the immutable attribute and then delete the file.
Now, what you have to do is to apply the shell command through the code and remove the immutable attribute on the file.
As you have mentioned the cross platform issue
So the basic algo would be
private static String OS = System.getProperty("os.name").toLowerCase();
if(OS.indexOf("win") >= 0)
//your code for windows OS.
else if(OS.indexOf("mac") >= 0)
//your code for MAC OS.
else if(OS.indexOf("sunos") >= 0)
//your code for Solaris OS
Note: I haven't added code for checking all OS's. So have a look at them by yourself.
Step 2: This step helps you solve the Cross platform issue
Issue the appropriate shell command through java.lang.Runtime.exec
to remove the immutable attribute of the file.
Look at the java.lang.Runtime.exec.
java.lang.Runtime.exec : Through this, you supply the appropriate shell command for any underlying Environment, whether be MAC, Windows, Linux etc.
sample code would be
//if the OS detected is Linux then
Process p = Runtime.getRuntime().exec("chattr -i /path/to/file");
//Play with the process as you would like to, using the documentation.
//else if the OS detected is OSX then : example to unlock in OSX
Process p = Runtime.getRuntime().exec("chflags nouchg /path/to/file");
//Play with the process as you would like to, using the documentation.
//else if the OS detected is say Windows then : example to unlock in Windows
Process p = Runtime.getRuntime().exec("ATTRIB -s -h /path/to/file");
//-s -h are used to unlock and unhide (i dont the Antonym of hide :p ) the file in windows
//Play with the process as you would like to, using the documentation.
Note: To run other shell commands which include pipes you can use this kind of sample code:
Process p = Runtime.getRuntime().exec(new String[]{"csh","-c","cat /home/narek/pk.txt"});
Step 3: Use the same Runtime.exec() to check whether the immutable attribute has been removed or not, like this:
Process p = Runtime.getRuntime().exec("lsattr /whateverPath");
//Play with the process to check whether the attribute is set or not, using the documentation.
Step 4: If Step3 is true|false, whatever the logic you apply, then Delete the file using your respective command again using the Runtime.exec().
Thing is to have a look at the above linked documentation of java.lang.Runtime.exec and work with it.
please, let me know whether it helped to some extent or not.
Is there any Cross Platform way to delete these files?
Not that I was able to find. I had to adopt the obvious solution you already considered, the long way round:
Actually a simpler, and lazier, shortcut would be:
/usr/bin/chattr
, etc.), with full path to avoid possible security problems. They will all quickly fail except one; on e.g. Linux any call to ATTRIB.EXE
or chflags
will fail. If they all fail, the system is not supported.lsattr
for chattr
), to verify flag removal.java.io.IOException
.I started looking into what it was that chattr
did, but it was immediately clear that there were several specialized, OS-specific system calls I would have needed to issue: so there was no real advantage over calling an external binary, except perhaps performance, but that wasn't an issue in my case.
Once one goes on the OS-specific (native) road, through either JNI or JNA, on a Linux system it is a "simple" matter of invoking the appropriate IOCTL function.
Note that it is not enough to identify the OS, you also need to identify the filesystem, because on e.g. FAT32 filesystems or NTFS-3G FSs, the IOCTL will return an error (the flag is either not available at low level, or not (yet) supported by the IOSS intermediate driver).
The same problem exists in Python 2.7, where at high level a OS independent call is supplied... but it does not work everywhere.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With