Use Files.isSameFile to check Resource equality (#6093)

Use Files.isSameFile to check Resource equality
Avoid using canonical and instead use Files.isSameFile

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2021-03-24 22:54:21 +11:00 committed by GitHub
parent 63810134c7
commit ebe8311333
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 115 additions and 75 deletions

View File

@ -20,7 +20,6 @@ package org.eclipse.jetty.deploy.providers;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -50,12 +49,11 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
{
private static final Logger LOG = Log.getLogger(ScanningAppProvider.class);
private Map<String, App> _appMap = new HashMap<String, App>();
private final Map<String, App> _appMap = new HashMap<>();
private DeploymentManager _deploymentManager;
protected FilenameFilter _filenameFilter;
private final List<Resource> _monitored = new CopyOnWriteArrayList<>();
private final List<Resource> _canonicalMonitored = new CopyOnWriteArrayList<>();
private boolean _recursive = false;
private int _scanInterval = 10;
private Scanner _scanner;
@ -249,34 +247,12 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
{
_monitored.clear();
_monitored.addAll(resources);
_canonicalMonitored.clear();
for (Resource r : resources)
{
Resource canonical = r; //assume original is canonical
try
{
File f = r.getFile(); //if it has a file, ensure it is canonical
if (f != null)
canonical = Resource.newResource(f.getCanonicalFile());
}
catch (IOException e)
{
//use the original resource
LOG.ignore(e);
}
_canonicalMonitored.add(canonical);
}
}
public List<Resource> getMonitoredResources()
{
return Collections.unmodifiableList(_monitored);
}
List<Resource> getCanonicalMonitoredResources()
{
return Collections.unmodifiableList(_canonicalMonitored);
}
public void setMonitoredDirResource(Resource resource)
{

View File

@ -20,7 +20,6 @@ package org.eclipse.jetty.deploy.providers;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Locale;
import org.eclipse.jetty.deploy.App;
@ -79,62 +78,48 @@ public class WebAppProvider extends ScanningAppProvider
@Override
public boolean accept(File dir, String name)
{
if (dir == null)
if (dir == null || !dir.exists())
return false;
try
{
//Always work on canonical files because we need to
//check if the file passed in is one of the
//monitored resources
if (!dir.getCanonicalFile().exists())
return false;
String lowerName = name.toLowerCase(Locale.ENGLISH);
String lowerName = name.toLowerCase(Locale.ENGLISH);
File canonical = new File(dir, name).getCanonicalFile();
Resource r = Resource.newResource(canonical);
if (getCanonicalMonitoredResources().contains(r) && r.isDirectory())
Resource resource = Resource.newResource(new File(dir, name));
for (Resource m : getMonitoredResources())
if (resource.isSame(m))
return false;
// ignore hidden files
if (lowerName.startsWith("."))
return false;
// Ignore some directories
if (canonical.isDirectory())
{
// is it a nominated config directory
if (lowerName.endsWith(".d"))
return false;
// is it an unpacked directory for an existing war file?
if (exists(name + ".war") || exists(name + ".WAR"))
return false;
// is it a directory for an existing xml file?
if (exists(name + ".xml") || exists(name + ".XML"))
return false;
//is it a sccs dir?
return !"cvs".equals(lowerName) && !"cvsroot".equals(lowerName); // OK to deploy it then
}
// else is it a war file
if (lowerName.endsWith(".war"))
{
//defer deployment decision to fileChanged()
return true;
}
// else is it a context XML file
return lowerName.endsWith(".xml");
}
catch (IOException e)
{
LOG.warn(e);
// ignore hidden files
if (lowerName.startsWith("."))
return false;
// Ignore some directories
if (resource.isDirectory())
{
// is it a nominated config directory
if (lowerName.endsWith(".d"))
return false;
// is it an unpacked directory for an existing war file?
if (exists(name + ".war") || exists(name + ".WAR"))
return false;
// is it a directory for an existing xml file?
if (exists(name + ".xml") || exists(name + ".XML"))
return false;
//is it a sccs dir?
return !"cvs".equals(lowerName) && !"cvsroot".equals(lowerName); // OK to deploy it then
}
// else is it a war file
if (lowerName.endsWith(".war"))
{
//defer deployment decision to fileChanged()
return true;
}
// else is it a context XML file
return lowerName.endsWith(".xml");
}
}

View File

@ -29,7 +29,9 @@ import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.security.Permission;
@ -184,6 +186,30 @@ public class FileResource extends Resource
_alias = checkFileAlias(_uri, _file);
}
@Override
public boolean isSame(Resource resource)
{
try
{
if (resource instanceof PathResource)
{
Path path = ((PathResource)resource).getPath();
return Files.isSameFile(getFile().toPath(), path);
}
if (resource instanceof FileResource)
{
Path path = ((FileResource)resource).getFile().toPath();
return Files.isSameFile(getFile().toPath(), path);
}
}
catch (IOException e)
{
if (LOG.isDebugEnabled())
LOG.debug("ignored", e);
}
return false;
}
private static URI normalizeURI(File file, URI uri) throws URISyntaxException
{
String u = uri.toASCIIString();

View File

@ -336,6 +336,30 @@ public class PathResource extends Resource
this(url.toURI());
}
@Override
public boolean isSame(Resource resource)
{
try
{
if (resource instanceof PathResource)
{
Path path = ((PathResource)resource).getPath();
return Files.isSameFile(getPath(), path);
}
if (resource instanceof FileResource)
{
Path path = ((FileResource)resource).getFile().toPath();
return Files.isSameFile(getPath(), path);
}
}
catch (IOException e)
{
if (LOG.isDebugEnabled())
LOG.debug("ignored", e);
}
return false;
}
@Override
public Resource addPath(final String subpath) throws IOException
{

View File

@ -311,6 +311,18 @@ public abstract class Resource implements ResourceFactory, Closeable
public abstract boolean isContainedIn(Resource r) throws MalformedURLException;
/**
* Return true if the passed Resource represents the same resource as the Resource.
* For many resource types, this is equivalent to {@link #equals(Object)}, however
* for resources types that support aliasing, this maybe some other check (e.g. {@link java.nio.file.Files#isSameFile(Path, Path)}).
* @param resource The resource to check
* @return true if the passed resource represents the same resource.
*/
public boolean isSame(Resource resource)
{
return equals(resource);
}
/**
* Release any temporary resources held by the resource.
*

View File

@ -32,6 +32,7 @@ import java.util.HashMap;
import java.util.Map;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -146,4 +147,20 @@ public class PathResourceTest
File file = resource.getFile();
assertThat("File for default FileSystem", file, is(exampleJar.toFile()));
}
@Test
public void testSame() throws Exception
{
Path rpath = MavenTestingUtils.getTestResourcePathFile("resource.txt");
Path epath = MavenTestingUtils.getTestResourcePathFile("example.jar");
PathResource rPathResource = new PathResource(rpath);
FileResource rFileResource = new FileResource(rpath.toFile());
PathResource ePathResource = new PathResource(epath);
FileResource eFileResource = new FileResource(epath.toFile());
assertThat(rPathResource.isSame(rPathResource), Matchers.is(true));
assertThat(rPathResource.isSame(rFileResource), Matchers.is(true));
assertThat(rPathResource.isSame(ePathResource), Matchers.is(false));
assertThat(rPathResource.isSame(eFileResource), Matchers.is(false));
}
}