001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.tag; 020 021import static lucee.runtime.tag.util.FileUtil.NAMECONFLICT_ERROR; 022import static lucee.runtime.tag.util.FileUtil.NAMECONFLICT_OVERWRITE; 023import static lucee.runtime.tag.util.FileUtil.NAMECONFLICT_SKIP; 024import static lucee.runtime.tag.util.FileUtil.NAMECONFLICT_UNDEFINED; 025 026import java.io.File; 027import java.io.IOException; 028import java.util.Date; 029 030import lucee.commons.io.ModeUtil; 031import lucee.commons.io.res.Resource; 032import lucee.commons.io.res.ResourceMetaData; 033import lucee.commons.io.res.filter.AndResourceFilter; 034import lucee.commons.io.res.filter.DirectoryResourceFilter; 035import lucee.commons.io.res.filter.FileResourceFilter; 036import lucee.commons.io.res.filter.NotResourceFilter; 037import lucee.commons.io.res.filter.OrResourceFilter; 038import lucee.commons.io.res.filter.ResourceFilter; 039import lucee.commons.io.res.filter.ResourceNameFilter; 040import lucee.commons.io.res.type.file.FileResource; 041import lucee.commons.io.res.type.s3.S3; 042import lucee.commons.io.res.type.s3.S3Constants; 043import lucee.commons.io.res.type.s3.S3Exception; 044import lucee.commons.io.res.type.s3.S3Resource; 045import lucee.commons.io.res.util.ModeObjectWrap; 046import lucee.commons.io.res.util.ResourceAndResourceNameFilter; 047import lucee.commons.io.res.util.ResourceUtil; 048import lucee.commons.io.res.util.UDFFilter; 049import lucee.commons.io.res.util.WildcardPatternFilter; 050import lucee.commons.lang.ExceptionUtil; 051import lucee.commons.lang.StringUtil; 052import lucee.runtime.PageContext; 053import lucee.runtime.exp.ApplicationException; 054import lucee.runtime.exp.PageException; 055import lucee.runtime.ext.tag.TagImpl; 056import lucee.runtime.functions.s3.StoreSetACL; 057import lucee.runtime.op.Caster; 058import lucee.runtime.op.Decision; 059import lucee.runtime.security.SecurityManager; 060import lucee.runtime.tag.util.FileUtil; 061import lucee.runtime.type.Array; 062import lucee.runtime.type.ArrayImpl; 063import lucee.runtime.type.Collection.Key; 064import lucee.runtime.type.Query; 065import lucee.runtime.type.QueryImpl; 066import lucee.runtime.type.UDF; 067import lucee.runtime.type.util.KeyConstants; 068 069/** 070* Handles interactions with directories. 071* 072* 073* 074**/ 075public final class Directory extends TagImpl { 076 077 public static final int TYPE_ALL = 0; 078 public static final int TYPE_FILE = 1; 079 public static final int TYPE_DIR = 2; 080 081 public static final ResourceFilter DIRECTORY_FILTER = new DirectoryResourceFilter(); 082 public static final ResourceFilter FILE_FILTER = new FileResourceFilter(); 083 084 private static final Key MODE = KeyConstants._mode; 085 private static final Key META = KeyConstants._meta; 086 private static final Key DATE_LAST_MODIFIED = KeyConstants._dateLastModified; 087 private static final Key ATTRIBUTES = KeyConstants._attributes; 088 private static final Key DIRECTORY = KeyConstants._directory; 089 090 public static final int LIST_INFO_QUERY_ALL = 1; 091 public static final int LIST_INFO_QUERY_NAME = 2; 092 public static final int LIST_INFO_ARRAY_NAME = 4; 093 public static final int LIST_INFO_ARRAY_PATH = 8; 094 095 public static final int NAMECONFLICT_DEFAULT = NAMECONFLICT_OVERWRITE; // default 096 097 /** Optional for action = "list". Ignored by all other actions. File extension filter applied to 098 ** returned names. For example: *m. Only one mask filter can be applied at a time. */ 099 private ResourceFilter filter; 100 private ResourceAndResourceNameFilter nameFilter; 101 102 private String pattern; 103 private String patternDelimiters; 104 105 /** The name of the directory to perform the action against. */ 106 private Resource directory; 107 108 /** Defines the action to be taken with directory(ies) specified in directory. */ 109 private String action="list"; 110 111 /** Optional for action = "list". Ignored by all other actions. The query columns by which to sort 112 ** the directory listing. Any combination of columns from query output can be specified in comma-separated list. 113 ** You can specify ASC (ascending) or DESC (descending) as qualifiers for column names. ASC is the default */ 114 private String sort; 115 116 /** Used with action = "Create" to define the permissions for a directory on UNIX and Linux 117 ** platforms. Ignored on Windows. Options correspond to the octal values of the UNIX chmod command. From 118 ** left to right, permissions are assigned for owner, group, and other. */ 119 private int mode=-1; 120 121 /** Required for action = "rename". Ignored by all other actions. The new name of the directory 122 ** specified in the directory attribute. */ 123 private String strNewdirectory; 124 125 /** Required for action = "list". Ignored by all other actions. Name of output query for directory 126 ** listing. */ 127 private String name=null; 128 129 130 private boolean recurse=false; 131 132 private String serverPassword; 133 134 private int type=TYPE_ALL; 135 //private boolean listOnlyNames; 136 private int listInfo=LIST_INFO_QUERY_ALL; 137 //private int acl=S3Constants.ACL_UNKNOW; 138 private Object acl=null; 139 private int storage=S3Constants.STORAGE_UNKNOW; 140 private String destination; 141 142 private int nameconflict = NAMECONFLICT_DEFAULT; 143 144 private boolean createPath=true; 145 146 147 @Override 148 public void release() { 149 super.release(); 150 acl=null; 151 storage=S3Constants.STORAGE_UNKNOW; 152 153 154 type=TYPE_ALL; 155 filter=null; 156 nameFilter=null; 157 destination=null; 158 directory=null; 159 action="list"; 160 sort=null; 161 mode=-1; 162 strNewdirectory=null; 163 name=null; 164 recurse=false; 165 serverPassword=null; 166 listInfo=LIST_INFO_QUERY_ALL; 167 168 nameconflict = NAMECONFLICT_DEFAULT; 169 createPath=true; 170 171 pattern = null; 172 patternDelimiters = null; 173 } 174 175 176 public void setCreatepath(boolean createPath) { 177 this.createPath=createPath; 178 } 179 180 181 /** 182 * sets a filter 183 * @param filter 184 * @throws PageException 185 **/ 186 public void setFilter(Object filter) throws PageException { 187 188 if (filter instanceof UDF) 189 this.setFilter((UDF)filter); 190 else if (filter instanceof String) 191 this.setFilter((String)filter); 192 } 193 194 public void setFilter(UDF filter) throws PageException { 195 this.filter=nameFilter=UDFFilter.createResourceAndResourceNameFilter(filter); 196 } 197 198 public void setFilter(String pattern) { 199 this.pattern = pattern; 200 } 201 202 public void setFilterdelimiters(String patternDelimiters) { 203 this.patternDelimiters = patternDelimiters; 204 } 205 206 /** set the value acl 207 * used only for s3 resources, for all others ignored 208 * @param acl value to set 209 * @throws ApplicationException 210 * @Deprecated only exists for backward compatibility to old ra files. 211 **/ 212 public void setAcl(String acl) throws ApplicationException { 213 this.acl=acl; 214 /*acl=acl.trim().toLowerCase(); 215 216 if("private".equals(acl)) this.acl=S3Constants.ACL_PRIVATE; 217 else if("public-read".equals(acl)) this.acl=S3Constants.ACL_PRIVATE; 218 else if("public-read-write".equals(acl)) this.acl=S3Constants.ACL_PUBLIC_READ_WRITE; 219 else if("authenticated-read".equals(acl)) this.acl=S3Constants.ACL_AUTH_READ; 220 221 else throw new ApplicationException("invalid value for attribute acl ["+acl+"]", 222 "valid values are [private,public-read,public-read-write,authenticated-read]");*/ 223 } 224 225 public void setAcl(Object acl) { 226 this.acl=acl; 227 } 228 229 public void setStoreacl(Object acl) { 230 this.acl=acl; 231 } 232 233 /** set the value storage 234 * used only for s3 resources, for all others ignored 235 * @param storage value to set 236 * @throws PageException 237 **/ 238 public void setStorage(String storage) throws PageException { 239 try { 240 this.storage=S3.toIntStorage(storage); 241 } catch (S3Exception e) { 242 throw Caster.toPageException(e); 243 } 244 } 245 public void setStorelocation(String storage) throws PageException { 246 setStorage(storage); 247 } 248 249 250 251 public void setServerpassword(String serverPassword) { 252 this.serverPassword=serverPassword; 253 } 254 255 256 public void setListinfo(String strListinfo) { 257 strListinfo=strListinfo.trim().toLowerCase(); 258 this.listInfo="name".equals(strListinfo)?LIST_INFO_QUERY_NAME:LIST_INFO_QUERY_ALL; 259 } 260 261 262 263 /** set the value directory 264 * The name of the directory to perform the action against. 265 * @param directory value to set 266 **/ 267 public void setDirectory(String directory) { 268 269 this.directory=ResourceUtil.toResourceNotExisting(pageContext, directory); 270 //print.ln(this.directory); 271 } 272 273 /** set the value action 274 * Defines the action to be taken with directory(ies) specified in directory. 275 * @param action value to set 276 **/ 277 public void setAction(String action) { 278 this.action=action.toLowerCase(); 279 } 280 281 /** set the value sort 282 * Optional for action = "list". Ignored by all other actions. The query columns by which to sort 283 * the directory listing. Any combination of columns from query output can be specified in comma-separated list. 284 * You can specify ASC (ascending) or DESC (descending) as qualifiers for column names. ASC is the default 285 * @param sort value to set 286 **/ 287 public void setSort(String sort) { 288 if(sort.trim().length()>0) 289 this.sort=sort; 290 } 291 292 /** set the value mode 293 * Used with action = "Create" to define the permissions for a directory on UNIX and Linux 294 * platforms. Ignored on Windows. Options correspond to the octal values of the UNIX chmod command. From 295 * left to right, permissions are assigned for owner, group, and other. 296 * @param mode value to set 297 * @throws PageException 298 **/ 299 public void setMode(String mode) throws PageException { 300 try { 301 this.mode=ModeUtil.toOctalMode(mode); 302 } 303 catch (IOException e) { 304 throw Caster.toPageException(e); 305 } 306 } 307 308 /** set the value newdirectory 309 * Required for action = "rename". Ignored by all other actions. The new name of the directory 310 * specified in the directory attribute. 311 * @param newdirectory value to set 312 **/ 313 public void setNewdirectory(String newdirectory) { 314 //this.newdirectory=ResourceUtil.toResourceNotExisting(pageContext ,newdirectory); 315 this.strNewdirectory=newdirectory; 316 } 317 public void setDestination(String destination) { 318 this.destination=destination; 319 } 320 321 /** set the value name 322 * Required for action = "list". Ignored by all other actions. Name of output query for directory 323 * listing. 324 * @param name value to set 325 **/ 326 public void setName(String name) { 327 this.name=name; 328 } 329 330 /** 331 * @param recurse The recurse to set. 332 */ 333 public void setRecurse(boolean recurse) { 334 this.recurse = recurse; 335 } 336 337 /** set the value nameconflict 338 * Action to take if destination directory is the same as that of a file in the directory. 339 * @param nameconflict value to set 340 * @throws ApplicationException 341 **/ 342 public void setNameconflict(String nameconflict) throws ApplicationException { 343 344 this.nameconflict = FileUtil.toNameConflict( nameconflict, NAMECONFLICT_UNDEFINED | NAMECONFLICT_ERROR | NAMECONFLICT_OVERWRITE, NAMECONFLICT_DEFAULT ); 345 } 346 347 348 @Override 349 public int doStartTag() throws PageException { 350 351 if (this.filter == null && !StringUtil.isEmpty(this.pattern)) 352 this.filter = nameFilter = new WildcardPatternFilter(pattern, patternDelimiters); 353 354 //securityManager = pageContext.getConfig().getSecurityManager(); 355 if(action.equals("list")) { 356 Object res=actionList(pageContext,directory,serverPassword,type,filter,nameFilter,listInfo,recurse,sort); 357 if(!StringUtil.isEmpty(name) && res!=null)pageContext.setVariable(name,res); 358 } 359 else if(action.equals("create")) actionCreate(pageContext,directory,serverPassword,createPath,mode,acl,storage, nameconflict); 360 else if(action.equals("delete")) actionDelete(pageContext,directory,recurse,serverPassword); 361 else if(action.equals("forcedelete")) actionDelete(pageContext,directory,true,serverPassword); 362 else if(action.equals("rename")) actionRename(pageContext,directory,strNewdirectory,serverPassword,createPath,acl,storage); 363 else if(action.equals("copy")) { 364 if(StringUtil.isEmpty(destination,true) && !StringUtil.isEmpty(strNewdirectory,true)) { 365 destination=strNewdirectory.trim(); 366 } 367 actionCopy(pageContext,directory,destination,serverPassword,createPath,acl,storage,filter,recurse, nameconflict); 368 } 369 else throw new ApplicationException("invalid action ["+action+"] for the tag directory"); 370 371 return SKIP_BODY; 372 } 373 374 375 @Override 376 public int doEndTag() { 377 return EVAL_PAGE; 378 } 379 380 /** 381 * list all files and directories inside a directory 382 * @throws PageException 383 */ 384 public static Object actionList(PageContext pageContext,Resource directory, String serverPassword, int type,ResourceFilter filter,ResourceAndResourceNameFilter nameFilter, 385 int listInfo,boolean recurse,String sort) throws PageException { 386 // check directory 387 SecurityManager securityManager = pageContext.getConfig().getSecurityManager(); 388 securityManager.checkFileLocation(pageContext.getConfig(),directory,serverPassword); 389 390 if(type!=TYPE_ALL) { 391 ResourceFilter typeFilter = (type==TYPE_DIR)?DIRECTORY_FILTER:FILE_FILTER; 392 if(filter==null) filter=typeFilter; 393 else filter=new AndResourceFilter(new ResourceFilter[]{typeFilter,filter}); 394 } 395 396 397 // create query Object 398 String[] names = new String[]{"name","size","type","dateLastModified","attributes","mode","directory"}; 399 String[] types=new String[]{"VARCHAR","DOUBLE","VARCHAR","DATE","VARCHAR","VARCHAR","VARCHAR"}; 400 401 boolean hasMeta=directory instanceof ResourceMetaData; 402 if(hasMeta){ 403 names = new String[]{"name","size","type","dateLastModified","attributes","mode","directory","meta"}; 404 types=new String[]{"VARCHAR","DOUBLE","VARCHAR","DATE","VARCHAR","VARCHAR","VARCHAR","OBJECT"}; 405 } 406 Array array=null; 407 Query query=null; 408 Object rtn; 409 if(listInfo==LIST_INFO_QUERY_ALL || listInfo==LIST_INFO_QUERY_NAME){ 410 boolean listOnlyNames=listInfo==LIST_INFO_QUERY_NAME; 411 rtn=query=new QueryImpl( 412 listOnlyNames?new String[]{"name"}:names, 413 listOnlyNames?new String[]{"VARCHAR"}:types, 414 0,"query"); 415 } 416 else 417 rtn=array=new ArrayImpl(); 418 419 if(!directory.exists()){ 420 if(directory instanceof FileResource) return rtn; 421 throw new ApplicationException("directory ["+directory.toString()+"] doesn't exist"); 422 } 423 if(!directory.isDirectory()){ 424 if(directory instanceof FileResource) return rtn; 425 throw new ApplicationException("file ["+directory.toString()+"] exists, but isn't a directory"); 426 } 427 if(!directory.isReadable()){ 428 if(directory instanceof FileResource) return rtn; 429 throw new ApplicationException("no access to read directory ["+directory.toString()+"]"); 430 } 431 432 long startNS=System.nanoTime(); 433 434 try { 435 // Query All 436 if(listInfo==LIST_INFO_QUERY_ALL) 437 _fillQueryAll(query,directory,filter,0,hasMeta,recurse); 438 439 // Query Name 440 else if(listInfo==LIST_INFO_QUERY_NAME) { 441 if(recurse || type!=TYPE_ALL)_fillQueryNamesRec("",query, directory, filter, 0,recurse); 442 else _fillQueryNames(query, directory, nameFilter, 0); 443 } 444 445 //Array Name/Path 446 else if(listInfo==LIST_INFO_ARRAY_NAME || listInfo==LIST_INFO_ARRAY_PATH) { 447 boolean onlyName=listInfo==LIST_INFO_ARRAY_NAME; 448 if(!onlyName || recurse || type!=TYPE_ALL)_fillArrayPathOrName(array, directory, nameFilter, 0, recurse, onlyName);//QueryNamesRec("",query, directory, filter, 0,recurse); 449 else _fillArrayName(array, directory, nameFilter, 0); 450 } 451 452 453 } catch (IOException e) { 454 throw Caster.toPageException(e); 455 } 456 457 // sort 458 if(sort!=null && query!=null) { 459 String[] arr=sort.toLowerCase().split(","); 460 for(int i=arr.length-1;i>=0;i--) { 461 try { 462 String[] col=arr[i].trim().split("\\s+"); 463 if(col.length==1)query.sort(col[0].trim()); 464 else if(col.length==2) { 465 String order=col[1].toLowerCase().trim(); 466 if(order.equals("asc")) 467 query.sort(col[0],lucee.runtime.type.Query.ORDER_ASC); 468 else if(order.equals("desc")) 469 query.sort(col[0],lucee.runtime.type.Query.ORDER_DESC); 470 else 471 throw new ApplicationException("invalid order type ["+col[1]+"]"); 472 } 473 } 474 catch(Throwable t) { 475 ExceptionUtil.rethrowIfNecessary(t); 476 } 477 } 478 } 479 if(query!=null)query.setExecutionTime(System.nanoTime()-startNS); 480 return rtn; 481 } 482 483 484 485 486 private static int _fillQueryAll(Query query, Resource directory, ResourceFilter filter, int count, boolean hasMeta, boolean recurse) throws PageException, IOException { 487 //long start=System.currentTimeMillis(); 488 Resource[] list=directory.listResources(); 489 490 if(list==null || list.length==0) return count; 491 String dir=directory.getCanonicalPath(); 492 // fill data to query 493 //query.addRow(list.length); 494 boolean isDir; 495 for(int i=0;i<list.length;i++) { 496 if(filter==null || filter.accept(list[i])) { 497 query.addRow(1); 498 count++; 499 query.setAt(KeyConstants._name,count,list[i].getName()); 500 isDir=list[i].isDirectory(); 501 query.setAt(KeyConstants._size,count,new Double(isDir?0:list[i].length())); 502 query.setAt(KeyConstants._type,count,isDir?"Dir":"File"); 503 if(directory.getResourceProvider().isModeSupported()){ 504 505 query.setAt(MODE,count,new ModeObjectWrap(list[i])); 506 } 507 query.setAt(DATE_LAST_MODIFIED,count,new Date(list[i].lastModified())); 508 query.setAt(ATTRIBUTES,count,getFileAttribute(list[i],true)); 509 510 if(hasMeta){ 511 query.setAt(META,count,((ResourceMetaData)list[i]).getMetaData()); 512 } 513 514 query.setAt(DIRECTORY,count,dir); 515 } 516 if(recurse && list[i].isDirectory()) 517 count=_fillQueryAll(query,list[i],filter,count,hasMeta,recurse); 518 } 519 return count; 520 } 521 // this method only exists for performance reasion 522 private static int _fillQueryNames(Query query, Resource directory, ResourceNameFilter filter, int count) throws PageException { 523 String[] list=directory.list(); 524 if(list==null || list.length==0) return count; 525 for(int i=0;i<list.length;i++) { 526 if(filter==null || filter.accept(directory,list[i])) { 527 query.addRow(1); 528 count++; 529 query.setAt(KeyConstants._name,count,list[i]); 530 } 531 } 532 return count; 533 } 534 535 private static int _fillQueryNamesRec(String parent, Query query, Resource directory, ResourceFilter filter, int count, boolean recurse) throws PageException { 536 Resource[] list=directory.listResources(); 537 if(list==null || list.length==0) return count; 538 for(int i=0;i<list.length;i++) { 539 if(filter==null || filter.accept(list[i])) { 540 query.addRow(1); 541 count++; 542 query.setAt(KeyConstants._name,count,parent.concat(list[i].getName())); 543 544 } 545 if(recurse && list[i].isDirectory()) 546 count=_fillQueryNamesRec(parent + list[i].getName() + "/", query, list[i], filter, count, recurse); 547 } 548 return count; 549 } 550 551 private static int _fillArrayPathOrName(Array arr, Resource directory, ResourceFilter filter, int count, boolean recurse,boolean onlyName) throws PageException { 552 Resource[] list=directory.listResources(); 553 if(list==null || list.length==0) return count; 554 for(int i=0;i<list.length;i++) { 555 if(filter==null || filter.accept(list[i])) { 556 arr.appendEL(onlyName?list[i].getName():list[i].getAbsolutePath()); 557 count++; 558 559 } 560 if(recurse && list[i].isDirectory()) 561 count=_fillArrayPathOrName(arr,list[i],filter,count,recurse,onlyName); 562 } 563 return count; 564 } 565 566 // this method only exists for performance reasion 567 private static int _fillArrayName(Array arr, Resource directory, ResourceNameFilter filter, int count) { 568 String[] list=directory.list(); 569 if(list==null || list.length==0) return count; 570 for(int i=0;i<list.length;i++) { 571 if(filter==null || filter.accept(directory,list[i])) { 572 arr.appendEL(list[i]); 573 } 574 } 575 return count; 576 } 577 578 579 580 /** 581 * create a directory 582 * @throws PageException 583 */ 584 public static void actionCreate(PageContext pc,Resource directory,String serverPassword, boolean createPath, int mode, Object acl, int storage, int nameConflict) throws PageException { 585 586 SecurityManager securityManager = pc.getConfig().getSecurityManager(); 587 securityManager.checkFileLocation(pc.getConfig(),directory,serverPassword); 588 589 if(directory.exists()) { 590 if(directory.isDirectory()) { 591 if ( nameConflict == NAMECONFLICT_SKIP ) 592 return; 593 594 throw new ApplicationException("directory ["+directory.toString()+"] already exist"); 595 } 596 else if(directory.isFile()) 597 throw new ApplicationException("can't create directory ["+directory.toString()+"], it exist a file with same name"); 598 } 599 //if(!directory.mkdirs()) throw new ApplicationException("can't create directory ["+directory.toString()+"]"); 600 try { 601 directory.createDirectory(createPath); 602 } catch (IOException ioe) { 603 throw Caster.toPageException(ioe); 604 } 605 606 // set S3 stuff 607 setS3Attrs(directory,acl,storage); 608 609 // Set Mode 610 if(mode!=-1) { 611 try { 612 directory.setMode(mode); 613 //FileUtil.setMode(directory,mode); 614 } catch (IOException e) { 615 throw Caster.toPageException(e); 616 } 617 } 618 } 619 620 private static void setS3Attrs(Resource res,Object acl,int storage) throws PageException { 621 String scheme = res.getResourceProvider().getScheme(); 622 623 if("s3".equalsIgnoreCase(scheme)){ 624 S3Resource s3r=(S3Resource) res; 625 if(acl!=null){ 626 try { 627 // old way 628 if(Decision.isString(acl)) { 629 if(Decision.isInteger(acl)) s3r.setACL(Caster.toIntValue(acl)); 630 else s3r.setACL(S3.toIntACL(Caster.toString(acl))); 631 } 632 // new way 633 else { 634 StoreSetACL.invoke(s3r, acl); 635 } 636 } catch (IOException e) { 637 throw Caster.toPageException(e); 638 } 639 } 640 641 if(storage!=S3Constants.STORAGE_UNKNOW) s3r.setStorage(storage); 642 } 643 } 644 645 646 647 /** 648 * delete directory 649 * @param dir 650 * @param forceDelete 651 * @throws PageException 652 */ 653 public static void actionDelete(PageContext pc,Resource dir, boolean forceDelete,String serverPassword) throws PageException { 654 SecurityManager securityManager = pc.getConfig().getSecurityManager(); 655 securityManager.checkFileLocation(pc.getConfig(),dir,serverPassword); 656 657 // directory doesn't exist 658 if(!dir.exists()) { 659 if(dir.isDirectory()) 660 throw new ApplicationException("directory ["+dir.toString()+"] doesn't exist"); 661 else if(dir.isFile()) 662 throw new ApplicationException("file ["+dir.toString()+"] doesn't exist and isn't a directory"); 663 } 664 665 // check if file 666 if(dir.isFile()) 667 throw new ApplicationException("can't delete ["+dir.toString()+"], it isn't a directory it is a file"); 668 669 // delete directory 670 try { 671 dir.remove(forceDelete); 672 } catch (IOException e) { 673 throw Caster.toPageException(e); 674 } 675 } 676 677 /** 678 * rename a directory to a new Name 679 * @throws PageException 680 */ 681 public static void actionRename(PageContext pc,Resource directory,String strNewdirectory,String serverPassword, boolean createPath, Object acl,int storage) throws PageException { 682 // check directory 683 SecurityManager securityManager = pc.getConfig().getSecurityManager(); 684 securityManager.checkFileLocation(pc.getConfig(),directory,serverPassword); 685 686 687 if(!directory.exists()) 688 throw new ApplicationException("the directory ["+directory.toString()+"] doesn't exist"); 689 if(!directory.isDirectory()) 690 throw new ApplicationException("the file ["+directory.toString()+"] exists, but it isn't a directory"); 691 if(!directory.canRead()) 692 throw new ApplicationException("no access to read directory ["+directory.toString()+"]"); 693 694 if(strNewdirectory==null) 695 throw new ApplicationException("the attribute [newDirectory] is not defined"); 696 697 // real to source 698 Resource newdirectory=toDestination(pc,strNewdirectory,directory); 699 700 securityManager.checkFileLocation(pc.getConfig(),newdirectory,serverPassword); 701 if(newdirectory.exists()) 702 throw new ApplicationException("new directory ["+newdirectory.toString()+"] already exists"); 703 if(createPath) { 704 newdirectory.getParentResource().mkdirs(); 705 706 } 707 try { 708 directory.moveTo(newdirectory); 709 } 710 catch(Throwable t) { 711 throw Caster.toPageException(t); 712 } 713 714 // set S3 stuff 715 setS3Attrs(directory,acl,storage); 716 717 } 718 719 720 public static void actionCopy(PageContext pc,Resource directory,String strDestination,String serverPassword,boolean createPath, Object acl,int storage, final ResourceFilter filter, boolean recurse, int nameconflict) throws PageException { 721 // check directory 722 SecurityManager securityManager = pc.getConfig().getSecurityManager(); 723 securityManager.checkFileLocation(pc.getConfig(),directory,serverPassword); 724 725 726 if(!directory.exists()) 727 throw new ApplicationException("directory ["+directory.toString()+"] doesn't exist"); 728 if(!directory.isDirectory()) 729 throw new ApplicationException("file ["+directory.toString()+"] exists, but isn't a directory"); 730 if(!directory.canRead()) 731 throw new ApplicationException("no access to read directory ["+directory.toString()+"]"); 732 733 if(StringUtil.isEmpty(strDestination)) 734 throw new ApplicationException("attribute destination is not defined"); 735 736 // real to source 737 Resource newdirectory=toDestination(pc,strDestination,directory); 738 739 if ( nameconflict == NAMECONFLICT_ERROR && newdirectory.exists() ) 740 throw new ApplicationException("new directory ["+newdirectory.toString()+"] already exist"); 741 742 securityManager.checkFileLocation(pc.getConfig(),newdirectory,serverPassword); 743 744 try { 745 boolean clearEmpty=false; 746 // has already a filter 747 ResourceFilter f=null; 748 if(filter!=null) { 749 if(!recurse) { 750 f=new AndResourceFilter( 751 new ResourceFilter[]{ 752 filter, 753 new NotResourceFilter(DirectoryResourceFilter.FILTER) 754 } 755 ); 756 } 757 else { 758 clearEmpty=true; 759 f=new OrResourceFilter( 760 new ResourceFilter[]{ 761 filter, 762 DirectoryResourceFilter.FILTER 763 } 764 ); 765 } 766 } 767 else { 768 if(!recurse)f=new NotResourceFilter(DirectoryResourceFilter.FILTER); 769 } 770 if(!createPath) { 771 Resource p = newdirectory.getParentResource(); 772 if(p!=null && !p.exists()) 773 throw new ApplicationException("parent directory for ["+newdirectory+"] doesn't exist"); 774 } 775 ResourceUtil.copyRecursive(directory, newdirectory,f); 776 if(clearEmpty)ResourceUtil.removeEmptyFolders(newdirectory,f==null?null:new NotResourceFilter(filter)); 777 778 } 779 catch(Throwable t) { 780 ExceptionUtil.rethrowIfNecessary(t); 781 throw new ApplicationException(t.getMessage()); 782 } 783 784 // set S3 stuff 785 setS3Attrs(directory,acl,storage); 786 787 } 788 789 790 private static Resource toDestination(PageContext pageContext,String path, Resource source) { 791 if(source!=null && path.indexOf(File.separatorChar)==-1 && path.indexOf('/')==-1 && path.indexOf('\\')==-1) { 792 Resource p = source.getParentResource(); 793 if(p!=null)return p.getRealResource(path); 794 } 795 return ResourceUtil.toResourceNotExisting(pageContext ,path); 796 } 797 798 799 private static String getFileAttribute(Resource file, boolean exists){ 800 return exists && !file.isWriteable() ? "R".concat(file.isHidden() ? "H" : "") : file.isHidden() ? "H" : ""; 801 } 802 803 804 /** 805 * @param strType the type to set 806 */ 807 public void setType(String strType) throws ApplicationException { 808 strType=strType.trim().toLowerCase(); 809 810 if("all".equals(strType)) type=TYPE_ALL; 811 else if("dir".equals(strType)) type=TYPE_DIR; 812 else if("directory".equals(strType)) type=TYPE_DIR; 813 else if("file".equals(strType)) type=TYPE_FILE; 814 else throw new ApplicationException("invalid type ["+strType+"] for the tag directory"); 815 816 } 817 818}