/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ package lucee.runtime.tag; import static lucee.runtime.tag.util.FileUtil.NAMECONFLICT_ERROR; import static lucee.runtime.tag.util.FileUtil.NAMECONFLICT_OVERWRITE; import static lucee.runtime.tag.util.FileUtil.NAMECONFLICT_SKIP; import static lucee.runtime.tag.util.FileUtil.NAMECONFLICT_UNDEFINED; import java.io.File; import java.io.IOException; import java.util.Date; import lucee.commons.io.ModeUtil; import lucee.commons.io.res.Resource; import lucee.commons.io.res.ResourceMetaData; import lucee.commons.io.res.filter.AndResourceFilter; import lucee.commons.io.res.filter.DirectoryResourceFilter; import lucee.commons.io.res.filter.FileResourceFilter; import lucee.commons.io.res.filter.NotResourceFilter; import lucee.commons.io.res.filter.OrResourceFilter; import lucee.commons.io.res.filter.ResourceFilter; import lucee.commons.io.res.filter.ResourceNameFilter; import lucee.commons.io.res.type.file.FileResource; import lucee.commons.io.res.util.ModeObjectWrap; import lucee.commons.io.res.util.ResourceUtil; import lucee.commons.io.res.util.UDFFilter; import lucee.commons.io.res.util.WildcardPatternFilter; import lucee.commons.lang.ExceptionUtil; import lucee.commons.lang.StringUtil; import lucee.loader.engine.CFMLEngineFactory; import lucee.runtime.PageContext; import lucee.runtime.exp.ApplicationException; import lucee.runtime.exp.PageException; import lucee.runtime.ext.function.BIF; import lucee.runtime.ext.tag.TagImpl; import lucee.runtime.op.Caster; import lucee.runtime.op.Decision; import lucee.runtime.reflection.Reflector; import lucee.runtime.security.SecurityManager; import lucee.runtime.tag.util.FileUtil; import lucee.runtime.type.Array; import lucee.runtime.type.ArrayImpl; import lucee.runtime.type.Collection.Key; import lucee.runtime.type.Query; import lucee.runtime.type.QueryImpl; import lucee.runtime.type.UDF; import lucee.runtime.type.util.KeyConstants; /** * Handles interactions with directories. * * * **/ public final class Directory extends TagImpl { public static final int TYPE_ALL = 0; public static final int TYPE_FILE = 1; public static final int TYPE_DIR = 2; public static final ResourceFilter DIRECTORY_FILTER = new DirectoryResourceFilter(); public static final ResourceFilter FILE_FILTER = new FileResourceFilter(); private static final Key MODE = KeyConstants._mode; private static final Key META = KeyConstants._meta; private static final Key DATE_LAST_MODIFIED = KeyConstants._dateLastModified; private static final Key ATTRIBUTES = KeyConstants._attributes; private static final Key DIRECTORY = KeyConstants._directory; public static final int LIST_INFO_QUERY_ALL = 1; public static final int LIST_INFO_QUERY_NAME = 2; public static final int LIST_INFO_ARRAY_NAME = 4; public static final int LIST_INFO_ARRAY_PATH = 8; public static final int NAMECONFLICT_DEFAULT = NAMECONFLICT_OVERWRITE; // default /** Optional for action = "list". Ignored by all other actions. File extension filter applied to ** returned names. For example: *m. Only one mask filter can be applied at a time. */ //private final ResourceFilter filter=null; //private ResourceAndResourceNameFilter nameFilter=null; private ResourceFilter filter=null; private String pattern; private String patternDelimiters; /** The name of the directory to perform the action against. */ private Resource directory; /** Defines the action to be taken with directory(ies) specified in directory. */ private String action="list"; /** Optional for action = "list". Ignored by all other actions. The query columns by which to sort ** the directory listing. Any combination of columns from query output can be specified in comma-separated list. ** You can specify ASC (ascending) or DESC (descending) as qualifiers for column names. ASC is the default */ private String sort; /** Used with action = "Create" to define the permissions for a directory on UNIX and Linux ** platforms. Ignored on Windows. Options correspond to the octal values of the UNIX chmod command. From ** left to right, permissions are assigned for owner, group, and other. */ private int mode=-1; /** Required for action = "rename". Ignored by all other actions. The new name of the directory ** specified in the directory attribute. */ private String strNewdirectory; /** Required for action = "list". Ignored by all other actions. Name of output query for directory ** listing. */ private String name=null; private boolean recurse=false; private String serverPassword; private int type=TYPE_ALL; //private boolean listOnlyNames; private int listInfo=LIST_INFO_QUERY_ALL; //private int acl=S3Constants.ACL_UNKNOW; private Object acl=null; private String storage=null; private String destination; private int nameconflict = NAMECONFLICT_DEFAULT; private boolean createPath=true; @Override public void release() { super.release(); acl=null; storage=null; type=TYPE_ALL; //filter=null; filter=null; destination=null; directory=null; action="list"; sort=null; mode=-1; strNewdirectory=null; name=null; recurse=false; serverPassword=null; listInfo=LIST_INFO_QUERY_ALL; nameconflict = NAMECONFLICT_DEFAULT; createPath=true; pattern = null; patternDelimiters = null; } public void setCreatepath(boolean createPath) { this.createPath=createPath; } /** * sets a filter * @param filter * @throws PageException **/ public void setFilter(Object filter) throws PageException { if (filter instanceof UDF) this.setFilter((UDF)filter); else if (filter instanceof String) this.setFilter((String)filter); } public void setFilter(UDF filter) throws PageException { this.filter=UDFFilter.createResourceAndResourceNameFilter(filter); } public void setFilter(String pattern) { this.pattern = pattern; } public void setFilterdelimiters(String patternDelimiters) { this.patternDelimiters = patternDelimiters; } /** set the value acl * used only for s3 resources, for all others ignored * @param acl value to set * @throws ApplicationException * @Deprecated only exists for backward compatibility to old ra files. **/ public void setAcl(String acl) throws ApplicationException { this.acl=acl; } public void setAcl(Object acl) { this.acl=acl; } public void setStoreacl(Object acl) { this.acl=acl; } /** set the value storage * used only for s3 resources, for all others ignored * @param storage value to set * @throws PageException **/ public void setStorage(String storage) throws PageException { this.storage=improveStorage(storage); } public void setStorelocation(String storage) throws PageException { setStorage(storage); } public static String improveStorage(String storage) throws ApplicationException { storage=improveStorage(storage, null); if(storage!=null) return storage; throw new ApplicationException("invalid storage value, valid values are [eu,us,us-west]"); } public static String improveStorage(String storage, String defaultValue) { storage=storage.toLowerCase().trim(); if("us".equals(storage)) return "us"; if("usa".equals(storage)) return "us"; if("u.s.".equals(storage)) return "us"; if("u.s.a.".equals(storage)) return "us"; if("united states of america".equals(storage)) return "us"; if("eu".equals(storage)) return "eu"; if("europe.".equals(storage)) return "eu"; if("european union.".equals(storage)) return "eu"; if("euro.".equals(storage)) return "eu"; if("e.u.".equals(storage)) return "eu"; if("us-west".equals(storage)) return "us-west"; if("usa-west".equals(storage)) return "us-west"; return defaultValue; } public void setServerpassword(String serverPassword) { this.serverPassword=serverPassword; } public void setListinfo(String strListinfo) { strListinfo=strListinfo.trim().toLowerCase(); this.listInfo="name".equals(strListinfo)?LIST_INFO_QUERY_NAME:LIST_INFO_QUERY_ALL; } /** set the value directory * The name of the directory to perform the action against. * @param directory value to set **/ public void setDirectory(String directory) { this.directory=ResourceUtil.toResourceNotExisting(pageContext, directory); //print.ln(this.directory); } /** set the value action * Defines the action to be taken with directory(ies) specified in directory. * @param action value to set **/ public void setAction(String action) { this.action=action.toLowerCase(); } /** set the value sort * Optional for action = "list". Ignored by all other actions. The query columns by which to sort * the directory listing. Any combination of columns from query output can be specified in comma-separated list. * You can specify ASC (ascending) or DESC (descending) as qualifiers for column names. ASC is the default * @param sort value to set **/ public void setSort(String sort) { if(sort.trim().length()>0) this.sort=sort; } /** set the value mode * Used with action = "Create" to define the permissions for a directory on UNIX and Linux * platforms. Ignored on Windows. Options correspond to the octal values of the UNIX chmod command. From * left to right, permissions are assigned for owner, group, and other. * @param mode value to set * @throws PageException **/ public void setMode(String mode) throws PageException { try { this.mode=ModeUtil.toOctalMode(mode); } catch (IOException e) { throw Caster.toPageException(e); } } /** set the value newdirectory * Required for action = "rename". Ignored by all other actions. The new name of the directory * specified in the directory attribute. * @param newdirectory value to set **/ public void setNewdirectory(String newdirectory) { //this.newdirectory=ResourceUtil.toResourceNotExisting(pageContext ,newdirectory); this.strNewdirectory=newdirectory; } public void setDestination(String destination) { this.destination=destination; } /** set the value name * Required for action = "list". Ignored by all other actions. Name of output query for directory * listing. * @param name value to set **/ public void setName(String name) { this.name=name; } /** * @param recurse The recurse to set. */ public void setRecurse(boolean recurse) { this.recurse = recurse; } /** set the value nameconflict * Action to take if destination directory is the same as that of a file in the directory. * @param nameconflict value to set * @throws ApplicationException **/ public void setNameconflict(String nameconflict) throws ApplicationException { this.nameconflict = FileUtil.toNameConflict( nameconflict, NAMECONFLICT_UNDEFINED | NAMECONFLICT_ERROR | NAMECONFLICT_OVERWRITE, NAMECONFLICT_DEFAULT ); } @Override public int doStartTag() throws PageException { if (this.filter == null && !StringUtil.isEmpty(this.pattern)) this.filter = new WildcardPatternFilter(pattern, patternDelimiters); //securityManager = pageContext.getConfig().getSecurityManager(); if(action.equals("list")) { Object res=actionList(pageContext,directory,serverPassword,type,filter,listInfo,recurse,sort); if(!StringUtil.isEmpty(name) && res!=null)pageContext.setVariable(name,res); } else if(action.equals("create")) actionCreate(pageContext,directory,serverPassword,createPath,mode,acl,storage, nameconflict); else if(action.equals("delete")) actionDelete(pageContext,directory,recurse,serverPassword); else if(action.equals("forcedelete")) actionDelete(pageContext,directory,true,serverPassword); else if(action.equals("rename")) actionRename(pageContext,directory,strNewdirectory,serverPassword,createPath,acl,storage); else if(action.equals("copy")) { if(StringUtil.isEmpty(destination,true) && !StringUtil.isEmpty(strNewdirectory,true)) { destination=strNewdirectory.trim(); } actionCopy(pageContext,directory,destination,serverPassword,createPath,acl,storage,filter,recurse, nameconflict); } else throw new ApplicationException("invalid action ["+action+"] for the tag directory"); return SKIP_BODY; } @Override public int doEndTag() { return EVAL_PAGE; } /** * list all files and directories inside a directory * @throws PageException */ public static Object actionList(PageContext pageContext,Resource directory, String serverPassword, int type, ResourceFilter filter, int listInfo,boolean recurse,String sort) throws PageException { // check directory SecurityManager securityManager = pageContext.getConfig().getSecurityManager(); securityManager.checkFileLocation(pageContext.getConfig(),directory,serverPassword); if(type!=TYPE_ALL) { ResourceFilter typeFilter = (type==TYPE_DIR)?DIRECTORY_FILTER:FILE_FILTER; if(filter==null) filter=typeFilter; else filter=new AndResourceFilter(new ResourceFilter[]{typeFilter,filter}); } // create query Object String[] names = new String[]{"name","size","type","dateLastModified","attributes","mode","directory"}; String[] types=new String[]{"VARCHAR","DOUBLE","VARCHAR","DATE","VARCHAR","VARCHAR","VARCHAR"}; boolean hasMeta=directory instanceof ResourceMetaData; if(hasMeta){ names = new String[]{"name","size","type","dateLastModified","attributes","mode","directory","meta"}; types=new String[]{"VARCHAR","DOUBLE","VARCHAR","DATE","VARCHAR","VARCHAR","VARCHAR","OBJECT"}; } Array array=null; Query query=null; Object rtn; if(listInfo==LIST_INFO_QUERY_ALL || listInfo==LIST_INFO_QUERY_NAME){ boolean listOnlyNames=listInfo==LIST_INFO_QUERY_NAME; rtn=query=new QueryImpl( listOnlyNames?new String[]{"name"}:names, listOnlyNames?new String[]{"VARCHAR"}:types, 0,"query"); } else rtn=array=new ArrayImpl(); if(!directory.exists()){ if(directory instanceof FileResource) return rtn; throw new ApplicationException("directory ["+directory.toString()+"] doesn't exist"); } if(!directory.isDirectory()){ if(directory instanceof FileResource) return rtn; throw new ApplicationException("file ["+directory.toString()+"] exists, but isn't a directory"); } if(!directory.isReadable()){ if(directory instanceof FileResource) return rtn; throw new ApplicationException("no access to read directory ["+directory.toString()+"]"); } long startNS=System.nanoTime(); try { // Query All if(listInfo==LIST_INFO_QUERY_ALL) _fillQueryAll(query,directory,filter,0,hasMeta,recurse); // Query Name else if(listInfo==LIST_INFO_QUERY_NAME) { if(recurse || type!=TYPE_ALL)_fillQueryNamesRec("",query, directory, filter, 0,recurse); else _fillQueryNames(query, directory, filter, 0); } //Array Name/Path else if(listInfo==LIST_INFO_ARRAY_NAME || listInfo==LIST_INFO_ARRAY_PATH) { boolean onlyName=listInfo==LIST_INFO_ARRAY_NAME; if(!onlyName || recurse || type!=TYPE_ALL)_fillArrayPathOrName(array, directory, filter, 0, recurse, onlyName);//QueryNamesRec("",query, directory, filter, 0,recurse); else _fillArrayName(array, directory, filter, 0); } } catch (IOException e) { throw Caster.toPageException(e); } // sort if(sort!=null && query!=null) { String[] arr=sort.toLowerCase().split(","); for(int i=arr.length-1;i>=0;i--) { try { String[] col=arr[i].trim().split("\\s+"); if(col.length==1)query.sort(col[0].trim()); else if(col.length==2) { String order=col[1].toLowerCase().trim(); if(order.equals("asc")) query.sort(col[0],lucee.runtime.type.Query.ORDER_ASC); else if(order.equals("desc")) query.sort(col[0],lucee.runtime.type.Query.ORDER_DESC); else throw new ApplicationException("invalid order type ["+col[1]+"]"); } } catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);} } } if(query!=null)query.setExecutionTime(System.nanoTime()-startNS); return rtn; } private static int _fillQueryAll(Query query, Resource directory, ResourceFilter filter, int count, boolean hasMeta, boolean recurse) throws PageException, IOException { Resource[] list=directory.listResources(); if(list==null || list.length==0) return count; String dir=directory.getCanonicalPath(); // fill data to query //query.addRow(list.length); boolean isDir; for(int i=0;i<list.length;i++) { if(filter==null || filter.accept(list[i])) { query.addRow(1); count++; query.setAt(KeyConstants._name,count,list[i].getName()); isDir=list[i].isDirectory(); query.setAt(KeyConstants._size,count,new Double(isDir?0:list[i].length())); query.setAt(KeyConstants._type,count,isDir?"Dir":"File"); if(directory.getResourceProvider().isModeSupported()){ query.setAt(MODE,count,new ModeObjectWrap(list[i])); } query.setAt(DATE_LAST_MODIFIED,count,new Date(list[i].lastModified())); query.setAt(ATTRIBUTES,count,getFileAttribute(list[i],true)); if(hasMeta){ query.setAt(META,count,((ResourceMetaData)list[i]).getMetaData()); } query.setAt(DIRECTORY,count,dir); } if(recurse && list[i].isDirectory()) count=_fillQueryAll(query,list[i],filter,count,hasMeta,recurse); } return count; } // this method only exists for performance reasion private static int _fillQueryNames(Query query, Resource directory, ResourceFilter filter, int count) throws PageException { if(filter==null || filter instanceof ResourceNameFilter) { ResourceNameFilter rnf=filter==null?null:(ResourceNameFilter)filter; String[] list=directory.list(); if(list==null || list.length==0) return count; for(int i=0;i<list.length;i++) { if(rnf==null || rnf.accept(directory,list[i])) { query.addRow(1); count++; query.setAt(KeyConstants._name,count,list[i]); } } } else { Resource[] list = directory.listResources(); if(list==null || list.length==0) return count; for(int i=0;i<list.length;i++) { if(filter==null || filter.accept(list[i])) { query.addRow(1); count++; query.setAt(KeyConstants._name,count,list[i].getName()); } } } return count; } private static int _fillQueryNamesRec(String parent, Query query, Resource directory, ResourceFilter filter, int count, boolean recurse) throws PageException { Resource[] list=directory.listResources(); if(list==null || list.length==0) return count; for(int i=0;i<list.length;i++) { if(filter==null || filter.accept(list[i])) { query.addRow(1); count++; query.setAt(KeyConstants._name,count,parent.concat(list[i].getName())); } if(recurse && list[i].isDirectory()) count=_fillQueryNamesRec(parent + list[i].getName() + "/", query, list[i], filter, count, recurse); } return count; } private static int _fillArrayPathOrName(Array arr, Resource directory, ResourceFilter filter, int count, boolean recurse,boolean onlyName) throws PageException { Resource[] list=directory.listResources(); if(list==null || list.length==0) return count; for(int i=0;i<list.length;i++) { if(filter==null || filter.accept(list[i])) { arr.appendEL(onlyName?list[i].getName():list[i].getAbsolutePath()); count++; } if(recurse && list[i].isDirectory()) count=_fillArrayPathOrName(arr,list[i],filter,count,recurse,onlyName); } return count; } // this method only exists for performance reasion private static int _fillArrayName(Array arr, Resource directory, ResourceFilter filter, int count) { if(filter==null || filter instanceof ResourceNameFilter) { ResourceNameFilter rnf=filter==null?null:(ResourceNameFilter)filter; String[] list=directory.list(); if(list==null || list.length==0) return count; for(int i=0;i<list.length;i++) { if(rnf==null || rnf.accept(directory,list[i])) { arr.appendEL(list[i]); } } } else { Resource[] list = directory.listResources(); if(list==null || list.length==0) return count; for(int i=0;i<list.length;i++) { if(filter.accept(list[i])) { arr.appendEL(list[i].getName()); } } } return count; } /** * create a directory * @throws PageException */ public static void actionCreate(PageContext pc,Resource directory,String serverPassword, boolean createPath, int mode, Object acl, String storage, int nameConflict) throws PageException { SecurityManager securityManager = pc.getConfig().getSecurityManager(); securityManager.checkFileLocation(pc.getConfig(),directory,serverPassword); if(directory.exists()) { if(directory.isDirectory()) { if ( nameConflict == NAMECONFLICT_SKIP ) return; throw new ApplicationException("directory ["+directory.toString()+"] already exist"); } else if(directory.isFile()) throw new ApplicationException("can't create directory ["+directory.toString()+"], it exist a file with same name"); } //if(!directory.mkdirs()) throw new ApplicationException("can't create directory ["+directory.toString()+"]"); try { directory.createDirectory(createPath); } catch (IOException ioe) { throw Caster.toPageException(ioe); } // set S3 stuff setS3Attrs(pc,directory,acl,storage); // Set Mode if(mode!=-1) { try { directory.setMode(mode); //FileUtil.setMode(directory,mode); } catch (IOException e) { throw Caster.toPageException(e); } } } public static void setS3Attrs(PageContext pc, Resource res,Object acl,String storage) throws PageException { String scheme = res.getResourceProvider().getScheme(); if("s3".equalsIgnoreCase(scheme)){ // ACL if(acl!=null) { try { // old way if(Decision.isString(acl)) { Reflector.callMethod(res, "setACL", new Object[]{improveACL(Caster.toString(acl))}); } // new way else { BIF bif = CFMLEngineFactory.getInstance().getClassUtil().loadBIF(pc, "StoreSetACL"); bif.invoke(pc, new Object[]{res.getAbsolutePath(),acl}); } } catch (Exception e) { throw Caster.toPageException(e); } } // STORAGE if(storage!=null) { Reflector.callMethod(res, "setStorage", new Object[]{storage}); } } } public static String improveACL(String acl) throws ApplicationException { acl=acl.toLowerCase().trim(); if("public-read".equals(acl)) return "public-read"; if("publicread".equals(acl)) return "public-read"; if("public_read".equals(acl)) return "public-read"; if("public-read-write".equals(acl)) return "public-read-write"; if("publicreadwrite".equals(acl)) return "public-read-write"; if("public_read_write".equals(acl)) return "public-read-write"; if("private".equals(acl)) return "private"; if("authenticated-read".equals(acl)) return "authenticated-read"; if("authenticated_read".equals(acl)) return "authenticated-read"; if("authenticatedread".equals(acl)) return "authenticated-read"; throw new ApplicationException("invalid acl value, valid values are [public-read, private, public-read-write, authenticated-read]"); } /** * delete directory * @param dir * @param forceDelete * @throws PageException */ public static void actionDelete(PageContext pc,Resource dir, boolean forceDelete,String serverPassword) throws PageException { SecurityManager securityManager = pc.getConfig().getSecurityManager(); securityManager.checkFileLocation(pc.getConfig(),dir,serverPassword); // directory doesn't exist if(!dir.exists()) { if(dir.isDirectory()) throw new ApplicationException("directory ["+dir.toString()+"] doesn't exist"); else if(dir.isFile()) throw new ApplicationException("file ["+dir.toString()+"] doesn't exist and isn't a directory"); } // check if file if(dir.isFile()) throw new ApplicationException("can't delete ["+dir.toString()+"], it isn't a directory it is a file"); // delete directory try { dir.remove(forceDelete); } catch (IOException e) { throw Caster.toPageException(e); } } /** * rename a directory to a new Name * @throws PageException */ public static void actionRename(PageContext pc,Resource directory,String strNewdirectory,String serverPassword, boolean createPath, Object acl,String storage) throws PageException { // check directory SecurityManager securityManager = pc.getConfig().getSecurityManager(); securityManager.checkFileLocation(pc.getConfig(),directory,serverPassword); if(!directory.exists()) throw new ApplicationException("the directory ["+directory.toString()+"] doesn't exist"); if(!directory.isDirectory()) throw new ApplicationException("the file ["+directory.toString()+"] exists, but it isn't a directory"); if(!directory.canRead()) throw new ApplicationException("no access to read directory ["+directory.toString()+"]"); if(strNewdirectory==null) throw new ApplicationException("the attribute [newDirectory] is not defined"); // real to source Resource newdirectory=toDestination(pc,strNewdirectory,directory); securityManager.checkFileLocation(pc.getConfig(),newdirectory,serverPassword); if(newdirectory.exists()) throw new ApplicationException("new directory ["+newdirectory.toString()+"] already exists"); if(createPath) { newdirectory.getParentResource().mkdirs(); } try { directory.moveTo(newdirectory); } catch(Throwable t) { ExceptionUtil.rethrowIfNecessary(t); throw Caster.toPageException(t); } // set S3 stuff setS3Attrs(pc,directory,acl,storage); } public static void actionCopy(PageContext pc,Resource directory,String strDestination,String serverPassword,boolean createPath, Object acl,String storage, final ResourceFilter filter, boolean recurse, int nameconflict) throws PageException { // check directory SecurityManager securityManager = pc.getConfig().getSecurityManager(); securityManager.checkFileLocation(pc.getConfig(),directory,serverPassword); if(!directory.exists()) throw new ApplicationException("directory ["+directory.toString()+"] doesn't exist"); if(!directory.isDirectory()) throw new ApplicationException("file ["+directory.toString()+"] exists, but isn't a directory"); if(!directory.canRead()) throw new ApplicationException("no access to read directory ["+directory.toString()+"]"); if(StringUtil.isEmpty(strDestination)) throw new ApplicationException("attribute destination is not defined"); // real to source Resource newdirectory=toDestination(pc,strDestination,directory); if ( nameconflict == NAMECONFLICT_ERROR && newdirectory.exists() ) throw new ApplicationException("new directory ["+newdirectory.toString()+"] already exist"); securityManager.checkFileLocation(pc.getConfig(),newdirectory,serverPassword); try { boolean clearEmpty=false; // has already a filter ResourceFilter f=null; if(filter!=null) { if(!recurse) { f=new AndResourceFilter( new ResourceFilter[]{ filter, new NotResourceFilter(DirectoryResourceFilter.FILTER) } ); } else { clearEmpty=true; f=new OrResourceFilter( new ResourceFilter[]{ filter, DirectoryResourceFilter.FILTER } ); } } else { if(!recurse)f=new NotResourceFilter(DirectoryResourceFilter.FILTER); } if(!createPath) { Resource p = newdirectory.getParentResource(); if(p!=null && !p.exists()) throw new ApplicationException("parent directory for ["+newdirectory+"] doesn't exist"); } ResourceUtil.copyRecursive(directory, newdirectory,f); if(clearEmpty)ResourceUtil.removeEmptyFolders(newdirectory,f==null?null:new NotResourceFilter(filter)); } catch(Throwable t) { ExceptionUtil.rethrowIfNecessary(t); throw new ApplicationException(t.getMessage()); } // set S3 stuff setS3Attrs(pc,directory,acl,storage); } private static Resource toDestination(PageContext pageContext,String path, Resource source) { if(source!=null && path.indexOf(File.separatorChar)==-1 && path.indexOf('/')==-1 && path.indexOf('\\')==-1) { Resource p = source.getParentResource(); if(p!=null)return p.getRealResource(path); } return ResourceUtil.toResourceNotExisting(pageContext ,path); } private static String getFileAttribute(Resource file, boolean exists){ return exists && !file.isWriteable() ? "R".concat(file.isHidden() ? "H" : "") : file.isHidden() ? "H" : ""; } /** * @param strType the type to set */ public void setType(String strType) throws ApplicationException { if(StringUtil.isEmpty(strType)) return; type=toType(strType); } public static int toType(String strType) throws ApplicationException { strType=strType.trim().toLowerCase(); if("all".equals(strType)) return TYPE_ALL; else if("dir".equals(strType)) return TYPE_DIR; else if("directory".equals(strType)) return TYPE_DIR; else if("file".equals(strType)) return TYPE_FILE; else throw new ApplicationException("invalid type ["+strType+"], valid types are [all,directory,file]"); } }