You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Emmanuel Bourg (Jira)" <ji...@apache.org> on 2020/12/06 23:27:00 UTC

[jira] [Resolved] (IO-692) PathUtils delete throws an exception when deleting a symlink that points to a file that does not exist

     [ https://issues.apache.org/jira/browse/IO-692?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Emmanuel Bourg resolved IO-692.
-------------------------------
    Resolution: Fixed

Thank you for the report, the suggested fix has been applied.

> PathUtils delete throws an exception when deleting a symlink that points to a file that does not exist
> ------------------------------------------------------------------------------------------------------
>
>                 Key: IO-692
>                 URL: https://issues.apache.org/jira/browse/IO-692
>             Project: Commons IO
>          Issue Type: Bug
>    Affects Versions: 2.8.0
>         Environment: {noformat}
> java version "1.8.0_202" Java(TM) SE Runtime Environment (build 1.8.0_202-b08) Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)
> {noformat}
>            Reporter: Matthew Rooney
>            Priority: Major
>             Fix For: 2.9.0
>
>
> *PathUtils.delete* throws an Exception when deleting a symlink to a file that doesn't exist, in our case this was when the files were deleted out of sequence.
> Minimal reproducing code running as a unit test (scala). This creates a symlink to a fail that does not exist at all.
> {code:java}
> val file = Files.createSymbolicLink(
>   Paths.get("target", "x.txt"),
>   Paths.get("target",  "y.txt").toAbsolutePath,
> )
> PathUtils.delete(file)
> {code}
> This throws the following exception
> {noformat}
> [error]    java.nio.file.NoSuchFileException: target/x.txt (UnixException.java:86)
> [error] sun.nio.fs.UnixException.translateToIOException(UnixException.java:86)
> [error] sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
> [error] sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
> [error] sun.nio.fs.UnixFileAttributeViews$Basic.readAttributes(UnixFileAttributeViews.java:55)
> [error] sun.nio.fs.UnixFileSystemProvider.readAttributes(UnixFileSystemProvider.java:144)
> [error] org.apache.commons.io.file.PathUtils.deleteFile(PathUtils.java:361)
> [error] org.apache.commons.io.file.PathUtils.delete(PathUtils.java:304)
> [error] org.apache.commons.io.file.PathUtils.delete(PathUtils.java:280){noformat}
> The offending code is this in *PathUtils*
> {code:java}
> public static PathCounters deleteFile(final Path file, final DeleteOption... options) throws IOException {
>     // Files.deleteIfExists() never follows links, so use LinkOption.NOFOLLOW_LINKS in other calls to Files.
>     if (Files.isDirectory(file, LinkOption.NOFOLLOW_LINKS)) {
>         throw new NoSuchFileException(file.toString());
>     }
>     final PathCounters pathCounts = Counters.longPathCounters();
>     final boolean exists = Files.exists(file, LinkOption.NOFOLLOW_LINKS);
>     final long size = exists ? Files.size(file) : 0;
>     if (overrideReadOnly(options) && exists) {
>         setReadOnly(file, false, LinkOption.NOFOLLOW_LINKS);
>     }
>     if (Files.deleteIfExists(file)) {
>         pathCounts.getFileCounter().increment();
>         pathCounts.getByteCounter().add(size);
>     }
>     return pathCounts;
> }
> {code}
> This manifests because 
> {code:java}
> Files.exists(file, LinkOption.NOFOLLOW_LINKS); // this always returns true if the symlink exists
> Files.size(file) // this throws an exception because there is no file to check the size of{code}
> A guess at the solution would be to only check the size if the file exists and is not a symlink
> {code:java}
> final long size = exists && !Files.isSymbolicLink() ? Files.size(file) : 0;{code}
> This was discovered when using *FileUtils.deleteDirectory* where we have a structure like the following. We clean up these directories when the process finishes, since upgrading to 2.8.0 this fails if the parent directory is deleted before the child.
> {code:java}
>  work_dir/
>    parent_dir/
>      big_file.txt
>    child_dir/
>      symlink_to_big_file.txt{code}
> As a work around using *PathUtils.deleteDirectory* seems to work regardless of the deletion order
>  



--
This message was sent by Atlassian Jira
(v8.3.4#803005)