I have created the following function which now gives me the required feedback
independently of Commons IO, so I will now be able to migrate to 2.18.0
The function below is actually giving me more feedback about various scenarios
which can go wrong so maybe this was a blessing in disguise.
Dave
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.DosFileAttributes;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
public class RemoteShareChecker
{
private String errorMessage = "";
private void setErrorMessage(String message)
{
this.errorMessage = message;
}
public String getErrorMessage()
{
return this.errorMessage;
}
public boolean isValidPath(String path)
{
boolean result = true;
Path remotePath = Paths.get(path);
try
{
Files.readAttributes(remotePath,
BasicFileAttributes.class);
setErrorMessage("File is accessible: " + remotePath);
if (Files.isRegularFile(remotePath))
{
if (canDelete(remotePath))
{
setErrorMessage("The file can be
deleted.");
}
else
{
setErrorMessage("The file cannot be
deleted due to permission or other restrictions.");
result = false;
}
}
if (Files.isRegularFile(remotePath))
{
if (isFileLocked(remotePath))
{
setErrorMessage("The file is locked by
another process.");
result = false;
}
else
{
setErrorMessage("The file is not
locked.");
}
}
}
catch (NoSuchFileException e)
{
setErrorMessage("The file or directory does not exist:
" + e.getFile());
result = false;
}
catch (AccessDeniedException e)
{
setErrorMessage("Access denied to the path: " +
e.getFile());
result = false;
}
catch (FileSystemException e)
{
setErrorMessage("File system error: " + e.getMessage());
result = false;
}
catch (IOException e)
{
setErrorMessage("An I/O error occurred: " +
e.getMessage());
result = false;
}
return result;
}
private boolean canDelete(Path path)
{
try
{
Path parentDir = path.getParent();
// Check if the parent directory is writable
if (!Files.isWritable(parentDir))
{
setErrorMessage("Parent directory is not
writable: " + parentDir);
return false;
}
// Platform-specific writable check
if
(!System.getProperty("os.name").toLowerCase().contains("win"))
{
PosixFileAttributes posixAttributes =
Files.readAttributes(path, PosixFileAttributes.class);
Set<PosixFilePermission> permissions =
posixAttributes.permissions();
if
(!permissions.contains(PosixFilePermission.OWNER_WRITE))
{
setErrorMessage("File is not writable
according to POSIX permissions: " + path);
return false;
}
}
else
{
DosFileAttributes dosAttributes =
Files.readAttributes(path, DosFileAttributes.class);
if (dosAttributes.isReadOnly())
{
setErrorMessage("File is read-only: " +
path);
return false;
}
}
return true;
}
catch (IOException e)
{
setErrorMessage("Error checking delete permissions: " +
e.getMessage());
return false;
}
}
private boolean isFileLocked(Path path)
{
// Attempt to open the file with exclusive access
try (FileChannel channel = FileChannel.open(path,
StandardOpenOption.WRITE))
{
// File is not locked if we successfully open it
return false;
}
catch (IOException e)
{
setErrorMessage("Error: Unable to open the file for
write access. It may be locked.");
return true;
}
}
}
> On 30 Dec 2024, at 22:43, Gary Gregory <[email protected]> wrote:
>
> We had a unit test missing for this specific use case it seems. Maybe check
> your test coverage (JaCoCo for example).
>
> Gary
>
> On Mon, Dec 30, 2024, 5:22 PM Dave Garratt <[email protected]>
> wrote:
>
>> Well yes I suppose that would suffice - I’m just a little worried about
>> how much code might be broken in my dependencies as well as my own code.
>>
>> Dave
>>
>>> On 30 Dec 2024, at 21:28, Ruby Paasche <[email protected]> wrote:
>>>
>>> How about `dir.exists()` maybe in combination with `dir.isDirectory()`?
>>>
>>> Dave Garratt <[email protected] <mailto:
>> [email protected]>> schrieb am Mo., 30. Dez. 2024, 22:21:
>>>> I’m not sure if I understand if the usefulness of the behaviour in all
>> versions up to and including 2.17.0 is a bug unless something else is
>> happening which I’m unaware of.
>>>>
>>>> Assuming the ability to detect a path / network url is no longer valid
>> has gone it begs the question- is there some other mechanism within commons
>> io which can be used to detect the same issue.
>>>>
>>>> The application which I develop runs as a middleware solution and as a
>> service. When a network url is no longer available I generate an alert via
>> an email.
>>>>
>>>> My code simply loops around check for the presence of files in a folder
>> constantly.
>>>>
>>>> With the new behaviour I won’t be able to detect and report on a
>> failure of this kind.
>>>>
>>>> Thanks
>>>>
>>>> Dave
>>>>
>>>>
>>>> ‑‑
>>>> Ruby Paasche
>>>> Senior Entwicklerin
>>>> <image493809.png> <https://www.linkedin.com/company/pripares-gmbh>
>>>> PRIPARES Software Solutions GmbH
>>>> Ridlerstraße 57
>>>> 80339 München
>>>> Tel:
>>>> +49 (0)89 45 22 808 ‑ 30
>>>> Email:
>>>> [email protected]
>>>> Web:
>>>> https://pripares.com <https://pripares.com/>
>>>> Handelsregister: Registergericht München HRB 138701
>>>> Sitz der Gesellschaft: München
>>>> Geschäftsführer: Aßmann Christoph, Ertl Andreas
>>>>
>>>> Diese E‑Mail enthält vertrauliche und/oder rechtlich geschützte
>> Informationen. Wenn Sie nicht der richtige Adressat sind oder diese E‑Mail
>> irrtümlich erhalten haben, informieren Sie bitte sofort den Absender und
>> löschen Sie diese Mail. Das unerlaubte Kopieren sowie die unbefugte
>> Weitergabe dieser Mail und der darin enthaltenen Informationen sind nicht
>> gestattet.
>>>>
>>>> This e‑mail may contain confidential and/or privileged information. If
>> you are not the intended recipient (or have received this e‑mail in error)
>>>> please notify the sender immediately and delete this e‑mail. Any
>> unauthorized copying, disclosure or distribution of the material in this
>> e‑mail is strictly forbidden.
>>>>> On 30 Dec 2024, at 19:49, Gary D. Gregory <[email protected]
>> <mailto:[email protected]>> wrote:
>>>>>
>>>>> It looks like this change with by design for
>> https://issues.apache.org/jira/browse/IO-856
>>>>>
>>>>> Gary
>>>>>
>>>>>> On 2024/12/30 17:54:17 "Gary D. Gregory" wrote:
>>>>>> Hm, we'll have to look into that one. In the meantime, I added
>>>>>>
>>>>>> org.apache.commons.io <http://org.apache.commons.io/
>>> .FileUtilsListFilesTest.testListFilesMissing()
>>>>>>
>>>>>> which asserts the current behavior in git master.
>>>>>>
>>>>>> TY,
>>>>>> Gary
>>>>>>
>>>>>>> On 2024/12/30 17:00:17 Dave Garratt wrote:
>>>>>>>
>>>>>>> I have recently tried updating from Commons IO 2.16.1 to Commons IO
>> 2.18.0
>>>>>>>
>>>>>>> My java program constantly polls a folder for the presence of
>> files. Normally this will be a remote folder on a windows share.
>>>>>>>
>>>>>>> In Commons IO 2.16.1 when I use FileUtils.listFiles it would
>> trigger an exception if the folder being polled became unavailable and I
>> would use this to trigger an action.
>>>>>>>
>>>>>>> In Commons IO 2.18.0 the error does not occur.
>>>>>>>
>>>>>>> I have created a very simple test program to illustrate this.
>>>>>>>
>>>>>>> Running this code with Commons IO 2.16.1 and passing an invalid
>> (non existent) path to it gives me the following exception (which in my
>> case is desirable):
>>>>>>>
>>>>>>> import java.io.File;
>>>>>>>
>>>>>>> import org.apache.commons.io <http://org.apache.commons.io/
>>> .FileUtils;
>>>>>>>
>>>>>>> public class Test2161
>>>>>>> {
>>>>>>>
>>>>>>> public static void main(String[] args)
>>>>>>> {
>>>>>>> File dir = new File("/Users/dave/Downloads/nonexistent");
>>>>>>>
>>>>>>> try
>>>>>>> {
>>>>>>> FileUtils.listFiles(dir, args, false);
>>>>>>> }
>>>>>>> catch (Exception ex)
>>>>>>> {
>>>>>>> System.out.println(ex.getMessage());
>>>>>>> ex.printStackTrace();
>>>>>>> }
>>>>>>> }
>>>>>>> }
>>>>>>>
>>>>>>> java.nio.file.NoSuchFileException: /Users/dave/Downloads/nonexistent
>>>>>>> java.io.UncheckedIOException: java.nio.file.NoSuchFileException:
>> /Users/dave/Downloads/nonexistent
>>>>>>> at org.apache.commons.io <http://org.apache.commons.io/
>>> .function.Uncheck.wrap(Uncheck.java:339)
>>>>>>> at org.apache.commons.io <http://org.apache.commons.io/
>>> .function.Uncheck.get(Uncheck.java:199)
>>>>>>> at org.apache.commons.io <http://org.apache.commons.io/
>>> .FileUtils.listFiles(FileUtils.java:2313)
>>>>>>> at Test2161.main(Test2161.java:14)
>>>>>>> Caused by: java.nio.file.NoSuchFileException:
>> /Users/dave/Downloads/nonexistent
>>>>>>> at
>> java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
>>>>>>> at
>> java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
>>>>>>> at
>> java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
>>>>>>> at
>> java.base/sun.nio.fs.UnixFileAttributeViews$Basic.readAttributes(UnixFileAttributeViews.java:55)
>>>>>>> at
>> java.base/sun.nio.fs.UnixFileSystemProvider.readAttributes(UnixFileSystemProvider.java:148)
>>>>>>> at java.base/java.nio.file.Files.readAttributes(Files.java:1851)
>>>>>>> at
>> java.base/java.nio.file.FileTreeWalker.getAttributes(FileTreeWalker.java:226)
>>>>>>> at
>> java.base/java.nio.file.FileTreeWalker.visit(FileTreeWalker.java:277)
>>>>>>> at
>> java.base/java.nio.file.FileTreeWalker.walk(FileTreeWalker.java:323)
>>>>>>> at
>> java.base/java.nio.file.FileTreeIterator.<init>(FileTreeIterator.java:71)
>>>>>>> at java.base/java.nio.file.Files.walk(Files.java:3918)
>>>>>>> at org.apache.commons.io.file.PathUtils.walk(PathUtils.java:1847)
>>>>>>> at org.apache.commons.io <http://org.apache.commons.io/
>>> .FileUtils.streamFiles(FileUtils.java:2952)
>>>>>>> at org.apache.commons.io <http://org.apache.commons.io/
>>> .FileUtils.lambda$listFiles$10(FileUtils.java:2313)
>>>>>>> at org.apache.commons.io <http://org.apache.commons.io/
>>> .function.Uncheck.get(Uncheck.java:197)
>>>>>>> ... 2 more
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> If however I run the same code with Commons IO 2.18.0 I get
>> nothing, no indication that the path is not valid which make it difficult
>> to determine if the folder is empty or the remote file server is shutdown.
>>>>>>>
>>>>>>> Am I supposed to use a different way to accomplish the same error
>> condition now ?
>>>>>>>
>>>>>>> Thanks
>>>>>>>
>>>>>>> Dave
>>>>>>>
>>>>>>>
>>>>>>>
>> ---------------------------------------------------------------------
>>>>>>> To unsubscribe, e-mail: [email protected]
>> <mailto:[email protected]>
>>>>>>> For additional commands, e-mail: [email protected]
>> <mailto:[email protected]>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: [email protected] <mailto:
>> [email protected]>
>>>>>> For additional commands, e-mail: [email protected]
>> <mailto:[email protected]>
>>>>>>
>>>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: [email protected] <mailto:
>> [email protected]>
>>>>> For additional commands, e-mail: [email protected]
>> <mailto:[email protected]>
>>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: [email protected] <mailto:
>> [email protected]>
>>>> For additional commands, e-mail: [email protected] <mailto:
>> [email protected]>
>>>>
>>
>>