What is the best way to check file creation permissions in java - java

I need to check for file creation permissions for specific directory.
I've tried:
try {
AccessController.checkPermission(new FilePermission("directory_path", "write"));
// Have permission
} catch (SecurityException e) {
// Doesn't have permission
}
... but this always throws SecurityException (as far as I've understood this checks not underlying fs permissions but some JVM settings that should be configured explicitly).
Another possible way was to use something like this:
File f = new File("directory_path");
if(f.canWrite()) {
// Have permission
} else {
// Doesn't have permission
}
... but this returns true even if I cannot create file in specified directory (For example I cannot create file in "c:\" when I run my app under user without admin privileges, but f.canWrite() returns true).
In the end I've done hack similar to this:
File f = new File("directory_path");
try {
File.createTempFile("check", null, f).delete();
// Have permission
} catch (IOException e) {
// Doesn't have permission
}
... but this may serve only as a temporary solution since I need to get such permissions for almost all folders on client's fs.
Does anybody know how to get REAL file creation permissions nicely, without causing performance issues and hacks described above?

The best way to test the availability/usability of any resource is to try to use it. In this case, new FileOutputStream(new File(dir, name)). It will throw an IOException if the directory isn't writable, or the file already exists and isn't writable, etc etc etc. The operating system already has to do all those checks when you execute that code: there is no point in trying to duplicate it all, and even if you get it 100% right, which is unlikely, you are still introducing a timing window in which the previously 'true' condition can become 'false' due to asynchronous activity. You have to catch exceptions from the file creation anyway, and write code in the catch block to handle them: why write all that twice?

Related

In Java on WIndows how do I detect if file has 'Read Only' attribute

In Windows a file may not be writable because the user simply doesn't have permission to modify the file due to Access Control Lists permissions, or just because the read only attribute is set for the file.
My application is written in Java and either of these conditions could cause Files.isWritable(file) to fail, but how can I determine which condition caused the failure, specifically I just want to know if the read only attribute is set.
I note that there is a File.setReadOnly() method (as well as File.setWritable()), and I assume on Windows this would just set the attribute, but there doesn;t seem to be a File.isReadOnly() method.
I used this method to check if read only, (it uses custom method Platform .ifWindows() to only run on Windows, but you could use alternatives).
private boolean isReadOnlyFile(Path file)
{
if(Platform.isWindows())
{
if (!file.toFile().canWrite())
{
DosFileAttributes dosAttr;
try
{
dosAttr = Files.readAttributes(file, DosFileAttributes.class);
if(dosAttr.isReadOnly())
{
return true;
}
}
catch (IOException e)
{
}
}
}
return false;
}
Use the canWrite() method:
if(file.canWrite()) {
System.out.println("you can write");
} else {
System.out.println("you cannot write");
}
Useful info:
Returns:
true if and only if the file system actually contains a file denoted by this abstract pathname and the application is allowed to
write to the file; false otherwise.
Throws:
SecurityException - If a security manager exists and its SecurityManager.checkWrite(java.lang.String) method denies write
access to the file
Don't. Just try to open the file for output. If it isn't writable, it will fail. Catch the exception and deal with it then. Don't try to predict the future. You could test it wrong, or it could change between test and use, both ways.

Why do I get a FolderNotFoundException after successfully creating a folder?

I am trying to create a folder if it does not exist and then copy a message from another folder to the destination folder. I am finding some strange behaviour that I can not understand. Given the following excerpt:
// messages is an array of Message instances.
// Source is the source folder
// destination is a string of the destination folder.
Folder dest = null;
try {
dest = store.getFolder(destination);
if (!dest.exists()) {
dest.create(Folder.HOLDS_MESSAGES | Folder.HOLDS_FOLDERS);
// Since folder's are not meant to cache I thought I'd get it again
// though this does not work either.
//dest.close(false);
//dest = store.getFolder(destination);
}
dest.open(Folder.READ_WRITE);
// Fails here
source.copyMessages(messages, dest);
source.setFlags(messages, new Flags(Flags.Flag.DELETED), true);
} catch (MessagingException ex) {
throw new MailProcessorException(ex.getMessage(), ex);
} finally {
if (dest != null) {
try {
dest.close(false);
} catch (MessagingException ex) {
System.err.println("Couldn't close destination folder.");
}
}
}
The following behaviour is examined:
If the folder does not exist:
The folder gets created
An exception is thrown at source.copyMessages.
If the folder does exist:
The messages are copied as expected.
Messages are marked for deletion.
I am using JavaMail 1.4.6, also tried with 1.6.5.
This is really strange. Looking at your code and reading the docs, there should be no way that this is happening...
Could it be some problem with the mail server? Some databases use consistency models (see http://en.wikipedia.org/wiki/Eventual_consistency for example) that don't always act the way you'd naively expect. Is there a chance you can try your code on a different mail server? Or, try to put a really long (30 seconds?) Thread.sleep(...) before your copyMessages(...) call and see if that fixes it.
If it does, what is happening is that your server creates the folder in one request, but this creation takes a while to reach the part of the server code that is handling the message copying. Then, unfortunately, I'm not sure if there is much you can do other than a retry if the copying fails or the artificial delay (which sucks).
Aside: The docs seem to say, that you can skip the dest.open(Folder.READ_WRITE); if you like.

How to check write permissions of a directory in java? Can we change it?

I am using the code below, but it’s not working. The method canWrite() is not working, even if changing the rights for writing for a directory.
File file = new File(fc.getSelectedFile().getAbsolutePath());
// fc is a FileChooser object
if(f.canWrite())
{
// write access
}
else
{
// no write access
}
I have also tried:
try
{
AccessController.checkPermission(new FilePermission("/tmp/*", "read,write"));
System.out.println("Good");
// Has permission
}
catch (SecurityException e)
{
// Does not have permission
System.out.println("Bad");
}
The File.canWrite() method is behaving as its specification says it should:
Returns: true if and only if the file system actually contains a file denoted by this abstract pathname and the application is allowed to write to the file; false otherwise.
(Emphasis added).
It is returning false because the object is not a file.
If you are using Java 7 (or later), one solution would be to use Files.getAttribute to retrieve the relevant attribute(s) to determine the access. Note that the attribute you use may be operating system specific. (I'm sure Google could find examples for you.)

Major java libraries doesn't predict the case of “cyclic copy” of a file onto a destination differently mapped

In my experience and after repeated tests I've done and deep web researches, I've found that major java libraries (either "Apache Commons" or Google.coomons or Jcifs) doesn't predict the case of “cyclic copy” of a file onto a destination differently mapped (denoted with different RootPath according with newer java.nio package Path Class) that,at last end of mapping cycle,resolves into the itself origin file.
That's a situation of data losing, because Outputsream method nor jnio's GetChannel method prevents itself this case:the origin file and the destination file are in reality "the same file" and the result of these methods is that the file become lost, better said the size o file become 0 length.
How can one avoid this without get off at a lower filesystem level or even surrender to a more safe Runtime.exec, delegating the stuff at the underlying S.O.
Should I have to lock the destination file (the above methods not allowing this), perhaps with the aid of the oldest RandomAccessFile Class ?
You can test using those cited major libraries with a common "CopyFile(File origin,File dest)" method after having done:
1) the origin folder of file c:\tmp\test.txt mapped to to x: virtual drive via a cmd's [SUBST x: c:\tmp] thus trying to copy onto x:\test.txt
2) Similar case if the local folder c:\tmp has been shared via Windows share mechanism and the destination is represented as a UNC path ending with the same file name
3) Other similar network situations ...
I think there must be another better solution, but my experience of java is fairly few and so I ask for this to you all. Thanks in advance if interested in this “real world” discussion.
Your question is interesting, never thought about that. Look at this question: Determine Symbolic Links. You should detect the cycle before copying.
Perhaps you can try to approach this problem slightly differently and try to detect that source and destination files are the same by comparing file's metadata (name, size, date, etc) and perhaps even calculate hash of the files content as well. This would of course slow processing down.
If you have enough permissions you could also write 'marker' file with random name in destination and try to read it at the source to detect that they're pointing to the same place. Or try to check that file already exist at destination before copying.
I agree that it is unusual situations, but you will agree that files are a critical base of every IT system. I disagree that manipulating files in java is unusual: in my case I have to attach image files of products through FileChooser and copy them in ordered way to a repository ... but real world users (call them customers who buy your product) may fall in such situations and if it happens, one can not 'blame the devil of bad luck if your product does something "less" than expected.
It is a good practice learning from experience and try to avoid what one of Murphy's Laws says, more' or less: "if something CAN go wrong, it WILL go wrong sooner or later.
Is perhaps also for one of those a reason I believe the Java team at Sun and Oracle has enhanced the old java.io package for to the newest java.nio. I'm analyzing a the new java.nio.Files Class which I had escaped to attention, and soon I believe I've found the solution I wanted and expected. See you later.
Thank for the address from other experienced members of the community,and thanks also to a young member of my team, Tindaro, who helped me in the research, I've found the real solution in Jdk 1.7, which is made by reliable, fast, simple and almost definitively will spawn a pity veil on older java.io solutions. Despite the web is still plenty full of examples of copying files in java using In/out Streams I'll warmely suggest everyone to use a simple method : java.nio.Files.copy(Path origin, Path destination) with optional parameters for replacing destination,migrate metadata file attributes and even try a transactional move of files (if permitted by the underlying O.S.).
That's a really good Job, waited for so long!
You can easily convert code from copy(File file1, File file2) by appending a ".toPath()" to the File instance (e.g. file1.toPath(), file2.toPath().
Note also that the boolean method "isSameFile(file1.toPath(), file2.toPath())", is already used inside the above copy method but easily usable in every case you want.
For every case you can't upgrade to 1.7 using community libraries from Apache or Google is still suggested, but for reliable purpose, permit me to suggest the temporary workaround I've found before:
public static boolean isTheSameFile(File f1, File f2) {//throws Exception{
// minimum prerequisites !
if(f1.length()!=f2.length()) return false;
if (!file1.exists() || !file2.exists()) { return false; }
if (file1.isDirectory() || file2.isDirectory()){ return false; }
//if (file1.getCanonicalFile().equals(file2.getCanonicalFile())); //don't rely in this ! can even still fail
//new FileInputStream(f2).getChannel().lock();//exception, can lock only on OutputStream
RandomAccessFile rf1=null,rf2=null; //the only practicable solution on my own ... better than parse entire files
try {
rf1 = new RandomAccessFile(f1, "r");
rf2=new RandomAccessFile(f2, "rw");
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
}
try {
rf2.getChannel().lock();
} catch (IOException e) {
return false;
}
try {
rf1.getChannel().read(ByteBuffer.allocate(1));//reads 1 only byte
} catch (IOException e) {
//e.printStackTrace(); // if and if only the same file, the O.S. will throw an IOException with reason "file already in use"
try {rf2.close();} catch (IOException e1) {}
return true;
}
//close the still opened resources ...
if (rf1.getChannel().isOpen())
try {rf1.getChannel().close();} catch (IOException e) {}
try {
rf2.close();
} catch (IOException e) {
return false;
}
// done, files differs
return false;
}

How to delete files from a USB Stick ? Using File.delete() doesn't work

after creating a file and populating it with that with a thread if the file is in a USB java can't delete it, when I try on disk it deletes the file ok !
Here is the part of the code that create and after an exception when try to delete the file.
if(canExport && fileCreated)
{
//Create the file
this.file.createNewFile();
//Export the data
this.run();
if(possible == false){ // in case writing fails delete the file created.
file.delete();
Export novaTentativa = new Export(plan);
novaTentativa.fileCreator(plan);
}
}
The file is created when the this.file.createNewFile() acts.
When this.run() runs, there is a lot of methods to populate the data and handle exceptions, if one exception is caught it sets the global variable possible to false so I know the file is created but empty in the USB, after that I try to delete it with file.delete();
You mention that you're trying to delete the file "after an exception" - consequently, your approach is on the wrong track and isn't going to work as-is.
If an exception is thrown by earlier methods (e.g. the createNewFile() call), then that exception will immediately propagate upwards, so your file.delete() call won't get a chance to execute. You'd need to wrap the earlier statements in a try block, and put the delete call in the corresponding catch or finally block in order for it to execute when an exception was thrown.
Here's an example of what you might try to do:
if(canExport && fileCreated)
{
//Create the file
this.file.createNewFile();
try
{
this.run();
}
catch (IOException e)
{
try
{
file.delete();
}
catch (IOException ignore) {} // don't want to mask the real exception
// Rethrow the actual exception from run() so callers can handle it
throw e;
}
}
An alternative approach rather than catching IOExceptions would be to have a finally block (which is always run) and then check a condition there, such as your possible flag.
Note as well that I start the try block after the call to createNewFile() - if an exception is thrown in the create file call then the file won't exist to delete at all!
As a file note, adding "a lot of code that asks for the thread to start over" in your error-handling block is probably not the best design. It would be more appropriate to simply consider recovering from IO situations here, and let the exception bubble up to the top and cause the thread/runnable to die. The logic around restarting tasks and/or resurrecting threads would be better positioned with the class that started the threads in the first place (e.g. a thread pool/task executor/etc.). Scattering the logic throughout the code will make it harder to see what any individual class is doing (not to mention that having a class marshall resources to resurrect itself just seems wrong from an OO standpoint).
Try explicitly stating the drive letter, path and folder to access the USB device to create write and read or delete the file. If that does not work then it is possible only a specific operating system utility or proprietory utility can delete the file.
How certain are you that you closed the file when the write failed? I'll bet money that you are missing a finally block somewhere in this.run(). That would result in exactly the behavior you describe - delete() will fail if the file is open (you should check it's return code - File.delete() doesn't throw exceptions if it is unable to delete the file).
If you want to test this, replace this.run() with a super, crazy simple implementation that writes 100 bytes to the file, sets 'possible' to false, then returns. If the file still won't delete, post the code you are using for this simplified version of run() and maybe someone can spot what's going on.

Categories