blob: 322c13c5e6e852b494bf3243aefa326debb8d424 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util.resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.security.Permission;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/** File Resource.
*
* Handle resources of implied or explicit file type.
* This class can check for aliasing in the filesystem (eg case
* insensitivity). By default this is turned on, or it can be controlled
* by calling the static method @see FileResource#setCheckAliases(boolean)
*
*/
public class FileResource extends URLResource
{
private static final Logger LOG = Log.getLogger(FileResource.class);
private static boolean __checkAliases = true;
/* ------------------------------------------------------------ */
private File _file;
private transient URL _alias=null;
private transient boolean _aliasChecked=false;
/* ------------------------------------------------------------------------------- */
/** setCheckAliases.
* @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
*/
public static void setCheckAliases(boolean checkAliases)
{
__checkAliases=checkAliases;
}
/* ------------------------------------------------------------------------------- */
/** getCheckAliases.
* @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
*/
public static boolean getCheckAliases()
{
return __checkAliases;
}
/* -------------------------------------------------------- */
public FileResource(URL url)
throws IOException, URISyntaxException
{
super(url,null);
try
{
// Try standard API to convert URL to file.
_file =new File(new URI(url.toString()));
}
catch (URISyntaxException e)
{
throw e;
}
catch (Exception e)
{
LOG.ignore(e);
try
{
// Assume that File.toURL produced unencoded chars. So try
// encoding them.
String file_url="file:"+URIUtil.encodePath(url.toString().substring(5));
URI uri = new URI(file_url);
if (uri.getAuthority()==null)
_file = new File(uri);
else
_file = new File("//"+uri.getAuthority()+URIUtil.decodePath(url.getFile()));
}
catch (Exception e2)
{
LOG.ignore(e2);
// Still can't get the file. Doh! try good old hack!
checkConnection();
Permission perm = _connection.getPermission();
_file = new File(perm==null?url.getFile():perm.getName());
}
}
if (_file.isDirectory())
{
if (!_urlString.endsWith("/"))
_urlString=_urlString+"/";
}
else
{
if (_urlString.endsWith("/"))
_urlString=_urlString.substring(0,_urlString.length()-1);
}
}
/* -------------------------------------------------------- */
FileResource(URL url, URLConnection connection, File file)
{
super(url,connection);
_file=file;
if (_file.isDirectory() && !_urlString.endsWith("/"))
_urlString=_urlString+"/";
}
/* -------------------------------------------------------- */
@Override
public Resource addPath(String path)
throws IOException,MalformedURLException
{
URLResource r=null;
String url=null;
path = org.eclipse.jetty.util.URIUtil.canonicalPath(path);
if ("/".equals(path))
return this;
else if (!isDirectory())
{
r=(FileResource)super.addPath(path);
url=r._urlString;
}
else
{
if (path==null)
throw new MalformedURLException();
// treat all paths being added as relative
String rel=path;
if (path.startsWith("/"))
rel = path.substring(1);
url=URIUtil.addPaths(_urlString,URIUtil.encodePath(rel));
r=(URLResource)Resource.newResource(url);
}
// Check for encoding aliases
// The encoded path should be a suffix of the resource (give or take a directory / )
String encoded=URIUtil.encodePath(path);
int expected=r.toString().length()-encoded.length();
int index = r._urlString.lastIndexOf(encoded, expected);
if (expected!=index && ((expected-1)!=index || path.endsWith("/") || !r.isDirectory()))
{
if (r instanceof FileResource)
{
((FileResource)r)._alias=((FileResource)r)._file.getCanonicalFile().toURI().toURL();
((FileResource)r)._aliasChecked=true;
}
}
return r;
}
/* ------------------------------------------------------------ */
@Override
public URL getAlias()
{
if (__checkAliases && !_aliasChecked)
{
try
{
String abs=_file.getAbsolutePath();
String can=_file.getCanonicalPath();
if (abs.length()!=can.length() || !abs.equals(can))
_alias=Resource.toURL(new File(can));
_aliasChecked=true;
if (_alias!=null && LOG.isDebugEnabled())
{
LOG.debug("ALIAS abs="+abs);
LOG.debug("ALIAS can="+can);
}
}
catch(Exception e)
{
LOG.warn(Log.EXCEPTION,e);
return getURL();
}
}
return _alias;
}
/* -------------------------------------------------------- */
/**
* Returns true if the resource exists.
*/
@Override
public boolean exists()
{
return _file.exists();
}
/* -------------------------------------------------------- */
/**
* Returns the last modified time
*/
@Override
public long lastModified()
{
return _file.lastModified();
}
/* -------------------------------------------------------- */
/**
* Returns true if the respresenetd resource is a container/directory.
*/
@Override
public boolean isDirectory()
{
return _file.isDirectory();
}
/* --------------------------------------------------------- */
/**
* Return the length of the resource
*/
@Override
public long length()
{
return _file.length();
}
/* --------------------------------------------------------- */
/**
* Returns the name of the resource
*/
@Override
public String getName()
{
return _file.getAbsolutePath();
}
/* ------------------------------------------------------------ */
/**
* Returns an File representing the given resource or NULL if this
* is not possible.
*/
@Override
public File getFile()
{
return _file;
}
/* --------------------------------------------------------- */
/**
* Returns an input stream to the resource
*/
@Override
public InputStream getInputStream() throws IOException
{
return new FileInputStream(_file);
}
/* --------------------------------------------------------- */
/**
* Returns an output stream to the resource
*/
@Override
public OutputStream getOutputStream()
throws java.io.IOException, SecurityException
{
return new FileOutputStream(_file);
}
/* --------------------------------------------------------- */
/**
* Deletes the given resource
*/
@Override
public boolean delete()
throws SecurityException
{
return _file.delete();
}
/* --------------------------------------------------------- */
/**
* Rename the given resource
*/
@Override
public boolean renameTo( Resource dest)
throws SecurityException
{
if( dest instanceof FileResource)
return _file.renameTo( ((FileResource)dest)._file);
else
return false;
}
/* --------------------------------------------------------- */
/**
* Returns a list of resources contained in the given resource
*/
@Override
public String[] list()
{
String[] list =_file.list();
if (list==null)
return null;
for (int i=list.length;i-->0;)
{
if (new File(_file,list[i]).isDirectory() &&
!list[i].endsWith("/"))
list[i]+="/";
}
return list;
}
/* ------------------------------------------------------------ */
/** Encode according to this resource type.
* File URIs are encoded.
* @param uri URI to encode.
* @return The uri unchanged.
*/
@Override
public String encode(String uri)
{
return uri;
}
/* ------------------------------------------------------------ */
/**
* @param o
* @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource.
*/
@Override
public boolean equals( Object o)
{
if (this == o)
return true;
if (null == o || ! (o instanceof FileResource))
return false;
FileResource f=(FileResource)o;
return f._file == _file || (null != _file && _file.equals(f._file));
}
/* ------------------------------------------------------------ */
/**
* @return the hashcode.
*/
@Override
public int hashCode()
{
return null == _file ? super.hashCode() : _file.hashCode();
}
/* ------------------------------------------------------------ */
@Override
public void copyTo(File destination)
throws IOException
{
if (isDirectory())
{
IO.copyDir(getFile(),destination);
}
else
{
if (destination.exists())
throw new IllegalArgumentException(destination+" exists");
IO.copy(getFile(),destination);
}
}
}