001 package railo.commons.io.res.util; 002 003 import java.io.File; 004 import java.io.FileNotFoundException; 005 import java.io.IOException; 006 import java.io.InputStream; 007 import java.io.PrintStream; 008 import java.util.ArrayList; 009 import java.util.HashMap; 010 011 import net.sf.jmimemagic.Magic; 012 import net.sf.jmimemagic.MagicMatch; 013 import railo.commons.io.DevNullOutputStream; 014 import railo.commons.io.IOUtil; 015 import railo.commons.io.SystemUtil; 016 import railo.commons.io.res.ContentType; 017 import railo.commons.io.res.ContentTypeImpl; 018 import railo.commons.io.res.Resource; 019 import railo.commons.io.res.ResourcesImpl; 020 import railo.commons.io.res.filter.ExtensionResourceFilter; 021 import railo.commons.io.res.filter.ResourceFilter; 022 import railo.commons.io.res.filter.ResourceNameFilter; 023 import railo.commons.io.res.type.http.HTTPResource; 024 import railo.commons.lang.StringUtil; 025 import railo.runtime.PageContext; 026 import railo.runtime.PageContextImpl; 027 import railo.runtime.PageSource; 028 import railo.runtime.config.Config; 029 import railo.runtime.config.ConfigWebImpl; 030 import railo.runtime.exp.ExpressionException; 031 import railo.runtime.exp.PageException; 032 import railo.runtime.type.List; 033 import railo.runtime.type.util.ArrayUtil; 034 035 public final class ResourceUtil { 036 037 /** 038 * Field <code>FILE_SEPERATOR</code> 039 */ 040 public static final char FILE_SEPERATOR=File.separatorChar; 041 /** 042 * Field <code>FILE_ANTI_SEPERATOR</code> 043 */ 044 public static final char FILE_ANTI_SEPERATOR=(FILE_SEPERATOR=='/')?'\\':'/'; 045 046 /** 047 * Field <code>TYPE_DIR</code> 048 */ 049 public static final short TYPE_DIR=0; 050 051 /** 052 * Field <code>TYPE_FILE</code> 053 */ 054 public static final short TYPE_FILE=1; 055 056 /** 057 * Field <code>LEVEL_FILE</code> 058 */ 059 public static final short LEVEL_FILE=0; 060 /** 061 * Field <code>LEVEL_PARENT_FILE</code> 062 */ 063 public static final short LEVEL_PARENT_FILE=1; 064 /** 065 * Field <code>LEVEL_GRAND_PARENT_FILE</code> 066 */ 067 public static final short LEVEL_GRAND_PARENT_FILE=2; 068 069 070 private static boolean isUnix=SystemUtil.isUnix(); 071 072 private static final HashMap<String, String> EXT_MT=new HashMap<String, String>(); 073 static { 074 EXT_MT.put("ai","application/postscript"); 075 EXT_MT.put("aif","audio/x-aiff"); 076 EXT_MT.put("aifc","audio/x-aiff"); 077 EXT_MT.put("aiff","audio/x-aiff"); 078 EXT_MT.put("au","audio/basic"); 079 EXT_MT.put("avi","video/x-msvideo"); 080 EXT_MT.put("bin","application/octet-stream"); 081 EXT_MT.put("bmp","image/x-ms-bmp"); 082 EXT_MT.put("cgm","image/cgm"); 083 EXT_MT.put("cmx","image/x-cmx"); 084 EXT_MT.put("csh","application/x-csh"); 085 EXT_MT.put("css ","text/css"); 086 EXT_MT.put("doc","application/msword"); 087 EXT_MT.put("docx","application/msword"); 088 EXT_MT.put("eps","application/postscript"); 089 EXT_MT.put("exe","application/octet-stream"); 090 EXT_MT.put("gif","image/gif"); 091 EXT_MT.put("gtar","application/x-gtar"); 092 EXT_MT.put("hqx","application/mac-binhex40"); 093 EXT_MT.put("htm","text/html"); 094 EXT_MT.put("html","text/html"); 095 EXT_MT.put("jpe","image/jpeg"); 096 EXT_MT.put("jpeg","image/jpeg"); 097 EXT_MT.put("jpg","image/jpeg"); 098 EXT_MT.put("js","text/javascript"); 099 EXT_MT.put("mmid","x-music/x-midi"); 100 EXT_MT.put("mov","video/quicktime"); 101 EXT_MT.put("mp2a","audio/x-mpeg-2"); 102 EXT_MT.put("mp2v","video/mpeg-2"); 103 EXT_MT.put("mp3","audio/mpeg"); 104 EXT_MT.put("mp4","video/mp4"); 105 EXT_MT.put("mpa","audio/x-mpeg"); 106 EXT_MT.put("mpa2","audio/x-mpeg-2"); 107 EXT_MT.put("mpeg","video/mpeg"); 108 EXT_MT.put("mpega","audio/x-mpeg"); 109 EXT_MT.put("mpg","video/mpeg"); 110 EXT_MT.put("mpv2","video/mpeg-2"); 111 EXT_MT.put("pbm","image/x-portable-bitmap"); 112 EXT_MT.put("pcd","image/x-photo-cd"); 113 EXT_MT.put("pdf","application/pdf"); 114 EXT_MT.put("pgm","image/x-portable-graymap"); 115 EXT_MT.put("pict","image/x-pict"); 116 EXT_MT.put("pl","application/x-perl"); 117 EXT_MT.put("png","image/png"); 118 EXT_MT.put("pnm","image/x-portable-anymap"); 119 EXT_MT.put("ppm","image/x-portable-pixmap"); 120 EXT_MT.put("ppt","application/vnd.ms-powerpoint"); 121 EXT_MT.put("pptx","application/vnd.ms-powerpoint"); 122 EXT_MT.put("ps","application/postscript"); 123 EXT_MT.put("qt","video/quicktime"); 124 EXT_MT.put("rgb","image/rgb"); 125 EXT_MT.put("rtf","application/rtf"); 126 EXT_MT.put("sh","application/x-sh"); 127 EXT_MT.put("sit","application/x-stuffit"); 128 EXT_MT.put("swf","application/x-shockwave-flash"); 129 EXT_MT.put("tar","application/x-tar"); 130 EXT_MT.put("tcl","application/x-tcl"); 131 EXT_MT.put("tif","image/tiff"); 132 EXT_MT.put("tiff","image/tiff"); 133 EXT_MT.put("txt","text/plain"); 134 EXT_MT.put("wav","audio/x-wav"); 135 EXT_MT.put("wma","audio/x-ms-wma"); 136 EXT_MT.put("wmv","video/x-ms-wmv"); 137 EXT_MT.put("xbm","image/x-xbitmap"); 138 EXT_MT.put("xhtml","application/xhtml+xml"); 139 EXT_MT.put("xls","application/vnd.ms-excel"); 140 EXT_MT.put("xlsx","application/vnd.ms-excel"); 141 EXT_MT.put("xpm","image/x-xpixmap"); 142 EXT_MT.put("zip","application/zip"); 143 144 } 145 146 147 //private static Magic mimeTypeParser; 148 149 /** 150 * cast a String (argumet destination) to a File Object, 151 * if destination is not a absolute, file object will be relative to current position (get from PageContext) 152 * file must exist otherwise throw exception 153 * @param pc Page Context to et actuell position in filesystem 154 * @param path relative or absolute path for file object 155 * @return file object from destination 156 * @throws ExpressionException 157 */ 158 public static Resource toResourceExisting(PageContext pc ,String path) throws ExpressionException { 159 return toResourceExisting(pc, path,pc.getConfig().allowRealPath()); 160 } 161 public static Resource toResourceExisting(PageContext pc ,String path,boolean allowRealpath) throws ExpressionException { 162 path=path.replace('\\','/'); 163 Resource res = pc.getConfig().getResource(path); 164 165 // not allow realpath 166 if(!allowRealpath){ 167 if(res.exists()) return res; 168 throw new ExpressionException("file or directory "+path+" not exist"); 169 } 170 171 if(res.isAbsolute() && res.exists()) { 172 return res; 173 } 174 175 //if(allowRealpath){ 176 if(StringUtil.startsWith(path,'/')) { 177 PageContextImpl pci=(PageContextImpl) pc; 178 ConfigWebImpl cwi=(ConfigWebImpl) pc.getConfig(); 179 Resource[] reses = cwi.getPhysicalResources(pc,pc.getApplicationContext().getMappings(),path,false,pci.useSpecialMappings(),true); 180 if(!ArrayUtil.isEmpty(reses)) { 181 for(int i=0;i<reses.length;i++){ 182 res=reses[i]; 183 if(res.exists()) return res; 184 } 185 } 186 //res = pc.getPhysical(path,true); 187 //if(res!=null && res.exists()) return res; 188 } 189 res=ResourceUtil.getCanonicalResourceEL(pc.getCurrentPageSource().getPhyscalFile().getParentResource().getRealResource(path)); 190 if(res.exists()) return res; 191 //} 192 193 throw new ExpressionException("file or directory "+path+" not exist"); 194 } 195 196 public static Resource toResourceExisting(Config config ,String path) throws ExpressionException { 197 path=path.replace('\\','/'); 198 Resource res = config.getResource(path); 199 200 if(res.exists()) return res; 201 throw new ExpressionException("file or directory "+path+" not exist"); 202 } 203 204 public static Resource toResourceNotExisting(Config config ,String path) { 205 Resource res; 206 path=path.replace('\\','/'); 207 res=config.getResource(path); 208 return res; 209 } 210 211 212 213 /** 214 * cast a String (argumet destination) to a File Object, 215 * if destination is not a absolute, file object will be relative to current position (get from PageContext) 216 * at least parent must exist 217 * @param pc Page Context to et actuell position in filesystem 218 * @param destination relative or absolute path for file object 219 * @return file object from destination 220 * @throws ExpressionException 221 */ 222 223 public static Resource toResourceExistingParent(PageContext pc ,String destination) throws ExpressionException { 224 return toResourceExistingParent(pc, destination, pc.getConfig().allowRealPath()); 225 } 226 227 public static Resource toResourceExistingParent(PageContext pc ,String destination, boolean allowRealpath) throws ExpressionException { 228 destination=destination.replace('\\','/'); 229 Resource res=pc.getConfig().getResource(destination); 230 231 // not allow realpath 232 if(!allowRealpath){ 233 if(res.exists() || parentExists(res)) 234 return res; 235 throw new ExpressionException("parent directory "+res.getParent()+" for file "+destination+" doesn't exist"); 236 237 } 238 239 // allow realpath 240 if(res.isAbsolute() && (res.exists() || parentExists(res))) { 241 return res; 242 } 243 //if(allowRealpath){ 244 if(StringUtil.startsWith(destination,'/')) { 245 PageContextImpl pci=(PageContextImpl) pc; 246 ConfigWebImpl cwi=(ConfigWebImpl) pc.getConfig(); 247 Resource[] reses = cwi.getPhysicalResources(pc,pc.getApplicationContext().getMappings(),destination,false,pci.useSpecialMappings(),true); 248 if(!ArrayUtil.isEmpty(reses)) { 249 for(int i=0;i<reses.length;i++){ 250 res=reses[i]; 251 if(res.exists() || parentExists(res)) return res; 252 } 253 } 254 //res = pc.getPhysical(destination,true); 255 //if(res!=null && (res.exists() || parentExists(res))) return res; 256 } 257 res=ResourceUtil.getCanonicalResourceEL(pc.getCurrentPageSource().getPhyscalFile().getParentResource().getRealResource(destination)); 258 if(res!=null && (res.exists() || parentExists(res))) return res; 259 //} 260 261 throw new ExpressionException("parent directory "+res.getParent()+" for file "+destination+" doesn't exist"); 262 263 } 264 265 /** 266 * cast a String (argument destination) to a File Object, 267 * if destination is not a absolute, file object will be relative to current position (get from PageContext) 268 * existing file is prefered but dont must exist 269 * @param pc Page Context to et actuell position in filesystem 270 * @param destination relative or absolute path for file object 271 * @return file object from destination 272 */ 273 274 public static Resource toResourceNotExisting(PageContext pc ,String destination) { 275 return toResourceNotExisting(pc ,destination,pc.getConfig().allowRealPath()); 276 } 277 278 public static Resource toResourceNotExisting(PageContext pc ,String destination,boolean allowRealpath) { 279 Resource res; 280 destination=destination.replace('\\','/'); 281 282 if(!allowRealpath){ 283 res=pc.getConfig().getResource(destination); 284 return res; 285 } 286 287 boolean isUNC; 288 if(!(isUNC=isUNCPath(destination)) && StringUtil.startsWith(destination,'/')) { 289 PageContextImpl pci=(PageContextImpl) pc; 290 ConfigWebImpl cwi=(ConfigWebImpl) pc.getConfig(); 291 Resource[] arr = cwi.getPhysicalResources(pc,pc.getApplicationContext().getMappings(),destination,false,pci.useSpecialMappings(),SystemUtil.isWindows()); 292 if(!ArrayUtil.isEmpty(arr)) return arr[0]; 293 //Resource res2 = pc.getPhysical(destination,SystemUtil.isWindows()); 294 //if(res2!=null) return res2; 295 } 296 if(isUNC) { 297 res=pc.getConfig().getResource(destination.replace('/','\\')); 298 } 299 else res=pc.getConfig().getResource(destination); 300 if(res.isAbsolute()) return res; 301 302 303 try { 304 return pc.getCurrentPageSource().getPhyscalFile().getParentResource().getRealResource(destination).getCanonicalResource(); 305 } 306 catch (IOException e) {} 307 return res; 308 } 309 310 311 312 private static boolean isUNCPath(String path) { 313 return SystemUtil.isWindows() && path.startsWith("//") ; 314 } 315 316 /** 317 * transalte the path of the file to a existing file path by changing case of letters 318 * Works only on Linux, becasue 319 * 320 * Example Unix: 321 * we have a existing file with path "/usr/virtual/myFile.txt" 322 * now you call this method with path "/Usr/Virtual/myfile.txt" 323 * the result of the method will be "/usr/virtual/myFile.txt" 324 * 325 * if there are more file with rhe same name but different cases 326 * Example: 327 * /usr/virtual/myFile.txt 328 * /usr/virtual/myfile.txt 329 * /Usr/Virtual/myFile.txt 330 * the nearest case wil returned 331 * 332 * @param res 333 * @return file 334 */ 335 public static Resource toExactResource(Resource res) { 336 res=getCanonicalResourceEL(res); 337 if(isUnix) { 338 if(res.exists()) return res; 339 return _check(res); 340 341 } 342 return res; 343 } 344 private static Resource _check(Resource file) { 345 // todo cascade durch while ersetzten 346 Resource parent=file.getParentResource(); 347 if(parent==null) return file; 348 349 if(!parent.exists()) { 350 Resource op=parent; 351 parent=_check(parent); 352 if(op==parent) return file; 353 if((file = parent.getRealResource(file.getName())).exists()) return file; 354 } 355 356 String[] files = parent.list(); 357 if(files==null) return file; 358 String name=file.getName(); 359 for(int i=0;i<files.length;i++) { 360 if(name.equalsIgnoreCase(files[i])) 361 return parent.getRealResource(files[i]); 362 } 363 return file; 364 } 365 366 /** 367 * create a file if possible, return file if ok, otherwise return null 368 * @param res file to touch 369 * @param level touch also parent and grand parent 370 * @param type is file or directory 371 * @return file if exists, otherwise null 372 */ 373 public static Resource createResource(Resource res, short level, short type) { 374 375 boolean asDir=type==TYPE_DIR; 376 // File 377 if(level>=LEVEL_FILE && res.exists() && ((res.isDirectory() && asDir)||(res.isFile() && !asDir))) { 378 return getCanonicalResourceEL(res); 379 } 380 381 // Parent 382 Resource parent=res.getParentResource(); 383 if(level>=LEVEL_PARENT_FILE && parent!=null && parent.exists() && canRW(parent)) { 384 if(asDir) { 385 if(res.mkdirs()) return getCanonicalResourceEL(res); 386 } 387 else { 388 if(createNewResourceEL(res))return getCanonicalResourceEL(res); 389 } 390 return getCanonicalResourceEL(res); 391 } 392 393 // Grand Parent 394 if(level>=LEVEL_GRAND_PARENT_FILE && parent!=null) { 395 Resource gparent=parent.getParentResource(); 396 if(gparent!=null && gparent.exists() && canRW(gparent)) { 397 if(asDir) { 398 if(res.mkdirs())return getCanonicalResourceEL(res); 399 } 400 else { 401 if(parent.mkdirs() && createNewResourceEL(res)) 402 return getCanonicalResourceEL(res); 403 } 404 } 405 } 406 return null; 407 } 408 409 public static void setAttribute(Resource res,String attributes) throws IOException { 410 /*if(res instanceof File && SystemUtil.isWindows()) { 411 if(attributes.length()>0) { 412 attributes=ResourceUtil.translateAttribute(attributes); 413 Runtime.getRuntime().exec("attrib "+attributes+" " + res.getAbsolutePath()); 414 } 415 } 416 else {*/ 417 short[] flags = strAttrToBooleanFlags(attributes); 418 419 if(flags[READ_ONLY]==YES)res.setWritable(false); 420 else if(flags[READ_ONLY]==NO)res.setWritable(true); 421 422 if(flags[HIDDEN]==YES) res.setAttribute(Resource.ATTRIBUTE_HIDDEN, true);//setHidden(true); 423 else if(flags[HIDDEN]==NO) res.setAttribute(Resource.ATTRIBUTE_HIDDEN, false);//res.setHidden(false); 424 425 if(flags[ARCHIVE]==YES) res.setAttribute(Resource.ATTRIBUTE_ARCHIVE, true);//res.setArchive(true); 426 else if(flags[ARCHIVE]==NO) res.setAttribute(Resource.ATTRIBUTE_ARCHIVE, false);//res.setArchive(false); 427 428 if(flags[SYSTEM]==YES) res.setAttribute(Resource.ATTRIBUTE_SYSTEM, true);//res.setSystem(true); 429 else if(flags[SYSTEM]==NO) res.setAttribute(Resource.ATTRIBUTE_SYSTEM, false);//res.setSystem(false); 430 431 //} 432 } 433 434 //private static final int NORMAL=0; 435 private static final int READ_ONLY=0; 436 private static final int HIDDEN=1; 437 private static final int ARCHIVE=2; 438 private static final int SYSTEM=3; 439 440 //private static final int IGNORE=0; 441 private static final int NO=1; 442 private static final int YES=2; 443 444 445 446 private static short[] strAttrToBooleanFlags(String attributes) throws IOException { 447 448 String[] arr; 449 try { 450 arr = List.toStringArray(List.listToArrayRemoveEmpty(attributes.toLowerCase(),',')); 451 } 452 catch (PageException e) { 453 arr=new String[0]; 454 } 455 456 boolean hasNormal=false; 457 boolean hasReadOnly=false; 458 boolean hasHidden=false; 459 boolean hasArchive=false; 460 boolean hasSystem=false; 461 462 for(int i=0;i<arr.length;i++) { 463 String str=arr[i].trim().toLowerCase(); 464 if(str.equals("readonly") || str.equals("read-only") || str.equals("+r")) hasReadOnly=true; 465 else if(str.equals("normal") || str.equals("temporary")) hasNormal=true; 466 else if(str.equals("hidden") || str.equals("+h")) hasHidden=true; 467 else if(str.equals("system") || str.equals("+s")) hasSystem=true; 468 else if(str.equals("archive") || str.equals("+a")) hasArchive=true; 469 else throw new IOException("invalid attribute definition ["+str+"]"); 470 } 471 472 short[] flags=new short[4]; 473 474 if(hasReadOnly)flags[READ_ONLY]=YES; 475 else if(hasNormal)flags[READ_ONLY]=NO; 476 477 if(hasHidden)flags[HIDDEN]=YES; 478 else if(hasNormal)flags[HIDDEN]=NO; 479 480 if(hasSystem)flags[SYSTEM]=YES; 481 else if(hasNormal)flags[SYSTEM]=NO; 482 483 if(hasArchive)flags[ARCHIVE]=YES; 484 else if(hasNormal)flags[ARCHIVE]=NO; 485 486 return flags; 487 } 488 489 490 /** 491 * sets attributes of a file on Windows system 492 * @param res 493 * @param attributes 494 * @throws PageException 495 * @throws IOException 496 */ 497 public static String translateAttribute(String attributes) throws IOException { 498 short[] flags = strAttrToBooleanFlags(attributes); 499 500 StringBuilder sb=new StringBuilder(); 501 if(flags[READ_ONLY]==YES)sb.append(" +R"); 502 else if(flags[READ_ONLY]==NO)sb.append(" -R"); 503 504 if(flags[HIDDEN]==YES)sb.append(" +H"); 505 else if(flags[HIDDEN]==NO)sb.append(" -H"); 506 507 if(flags[SYSTEM]==YES)sb.append(" +S"); 508 else if(flags[SYSTEM]==NO)sb.append(" -S"); 509 510 if(flags[ARCHIVE]==YES)sb.append(" +A"); 511 else if(flags[ARCHIVE]==NO)sb.append(" -A"); 512 513 return sb.toString(); 514 } 515 516 /* * 517 * transalte a path in a proper form 518 * example susi\petere -> /susi/peter 519 * @param path 520 * @return path 521 * / 522 public static String translatePath(String path) { 523 /*path=prettifyPath(path); 524 if(path.indexOf('/')!=0)path='/'+path; 525 int index=path.lastIndexOf('/'); 526 // remove slash at the end 527 if(index==path.length()-1) path=path.substring(0,path.length()-1); 528 return path;* / 529 return translatePath(path, true, false); 530 }*/ 531 532 /* * 533 * transalte a path in a proper form 534 * example susi\petere -> susi/peter/ 535 * @param path 536 * @return path 537 * / 538 public static String translatePath2x(String path) { 539 /*path=prettifyPath(path); 540 if(path.indexOf('/')==0)path=path.substring(1); 541 int index=path.lastIndexOf('/'); 542 // remove slash at the end 543 if(index!=path.length()-1) path=path+'/';* / 544 return translatePath(path, false, true); 545 }*/ 546 547 548 public static String translatePath(String path, boolean slashAdBegin, boolean slashAddEnd) { 549 path=prettifyPath(path); 550 551 // begin 552 if(slashAdBegin) { 553 if(path.indexOf('/')!=0)path='/'+path; 554 } 555 else { 556 if(path.indexOf('/')==0)path=path.substring(1); 557 } 558 559 // end 560 int index=path.lastIndexOf('/'); 561 if(slashAddEnd) { 562 if(index!=path.length()-1) path=path+'/'; 563 } 564 else { 565 if(index==path.length()-1 && index>-1) path=path.substring(0,path.length()-1); 566 } 567 return path; 568 } 569 570 571 572 573 /** 574 * transalte a path in a proper form and cut name away 575 * example susi\petere -> /susi/ and peter 576 * @param path 577 * @return 578 */ 579 public static String[] translatePathName(String path) { 580 path=prettifyPath(path); 581 if(path.indexOf('/')!=0)path='/'+path; 582 int index=path.lastIndexOf('/'); 583 // remove slash at the end 584 if(index==path.length()-1) path=path.substring(0,path.length()-1); 585 586 index=path.lastIndexOf('/'); 587 String name; 588 if(index==-1) { 589 name=path; 590 path = "/"; 591 } 592 else { 593 name = path.substring(index+1); 594 path = path.substring(0,index+1); 595 } 596 return new String[] {path,name}; 597 } 598 599 public static String prettifyPath(String path) { 600 path=path.replace('\\','/'); 601 return StringUtil.replace(path, "//", "/", false); 602 // TODO /aaa/../bbb/ 603 } 604 605 public static String removeScheme(String scheme, String path) { 606 if(path.indexOf("://")==scheme.length() && StringUtil.startsWithIgnoreCase(path,scheme)) path=path.substring(3+scheme.length()); 607 return path; 608 } 609 610 /** 611 * merge to path parts to one 612 * @param parent 613 * @param child 614 * @return 615 */ 616 public static String merge(String parent, String child) { 617 if(child.length()<=2) { 618 if(child.length()==0) return parent; 619 if(child.equals(".")) return parent; 620 if(child.equals("..")) child="../"; 621 } 622 623 624 625 parent=translatePath(parent, true, false); 626 child=prettifyPath(child);//child.replace('\\', '/'); 627 628 if(child.startsWith("./"))child=child.substring(2); 629 if(StringUtil.startsWith(child, '/'))return parent.concat(child); 630 if(!StringUtil.startsWith(child, '.'))return parent.concat("/").concat(child); 631 632 633 while(child.startsWith("../")) { 634 parent=pathRemoveLast(parent); 635 child=child.substring(3); 636 } 637 if(StringUtil.startsWith(child, '/'))return parent.concat(child); 638 return parent.concat("/").concat(child); 639 } 640 641 private static String pathRemoveLast(String path) { 642 if(path.length()==0) return ".."; 643 644 else if(path.endsWith("..")){ 645 return path.concat("/.."); 646 } 647 return path.substring(0,path.lastIndexOf('/')); 648 } 649 650 /** 651 * Returns the canonical form of this abstract pathname. 652 * @param res file to get canoncial form from it 653 * 654 * @return The canonical pathname string denoting the same file or 655 * directory as this abstract pathname 656 * 657 * @throws SecurityException 658 * If a required system property value cannot be accessed. 659 */ 660 public static String getCanonicalPathEL(Resource res) { 661 try { 662 return res.getCanonicalPath(); 663 } catch (IOException e) { 664 return res.toString(); 665 } 666 } 667 668 669 /** 670 * Returns the canonical form of this abstract pathname. 671 * @param res file to get canoncial form from it 672 * 673 * @return The canonical pathname string denoting the same file or 674 * directory as this abstract pathname 675 * 676 * @throws SecurityException 677 * If a required system property value cannot be accessed. 678 */ 679 public static Resource getCanonicalResourceEL(Resource res) { 680 if(res==null) return res; 681 try { 682 return res.getCanonicalResource(); 683 } catch (IOException e) { 684 return res; 685 } 686 } 687 688 /** 689 * creates a new File 690 * @param res 691 * @return was successfull 692 */ 693 public static boolean createNewResourceEL(Resource res) { 694 try { 695 res.createFile(false); 696 return true; 697 } catch (IOException e) { 698 return false; 699 } 700 } 701 702 public static boolean exists(Resource res) { 703 return res!=null && res.exists(); 704 } 705 706 707 /** 708 * check if file is read and writable 709 * @param res 710 * @return is or not 711 */ 712 public static boolean canRW(Resource res) { 713 return res.isReadable() && res.isWriteable(); 714 } 715 716 717 /** 718 * similat to linux bash fuction toch, create file if not exists oherwise change last modified date 719 * @param res 720 * @throws IOException 721 */ 722 public static void touch(Resource res) throws IOException { 723 if(res.exists()) { 724 res.setLastModified(System.currentTimeMillis()); 725 } 726 else { 727 res.createFile(true); 728 } 729 } 730 731 public static void clear(Resource res) throws IOException { 732 if(res.exists()) { 733 IOUtil.write(res, new byte[0]); 734 } 735 else { 736 res.createFile(true); 737 } 738 } 739 740 741 742 /** 743 * return the mime type of a file, dont check extension 744 * @param res 745 * @param defaultValue 746 * @return mime type of the file 747 */ 748 public static String getMymeType(Resource res, String defaultValue) { 749 return getMymeType(res, false,defaultValue); 750 } 751 752 public static String getMymeType(Resource res, boolean alsoCheckExtension, String defaultValue) { 753 if(alsoCheckExtension) { 754 String ext = getExtension(res, null); 755 if(!StringUtil.isEmpty(ext)){ 756 String mt=EXT_MT.get(ext.trim().toLowerCase()); 757 if(mt!=null) return mt; 758 } 759 } 760 PrintStream out = System.out; 761 try { 762 System.setOut(new PrintStream(DevNullOutputStream.DEV_NULL_OUTPUT_STREAM)); 763 MagicMatch match = Magic.getMagicMatch(IOUtil.toBytes(res)); 764 return match.getMimeType(); 765 } 766 catch (Exception e) { 767 return defaultValue; 768 } 769 finally { 770 System.setOut(out); 771 } 772 } 773 774 /** 775 * return the mime type of a file, dont check extension 776 * @param barr 777 * @return mime type of the file 778 * @throws IOException 779 */ 780 public static String getMymeType(byte[] barr) throws IOException { 781 //if(mimeTypeParser==null)mimeTypeParser=new Magic(); 782 PrintStream out = System.out; 783 try { 784 System.setOut(new PrintStream(DevNullOutputStream.DEV_NULL_OUTPUT_STREAM)); 785 MagicMatch match = Magic.getMagicMatch(barr); 786 return match.getMimeType(); 787 } 788 catch (Exception e) { 789 throw new IOException(e.getMessage()); 790 } 791 finally { 792 System.setOut(out); 793 } 794 } 795 796 /** 797 * return the mime type of a file, dont check extension 798 * @param barr 799 * @param defaultValue 800 * @return mime type of the file 801 */ 802 public static String getMymeType(byte[] barr, String defaultValue) { 803 PrintStream out = System.out; 804 try { 805 System.setOut(new PrintStream(DevNullOutputStream.DEV_NULL_OUTPUT_STREAM)); 806 MagicMatch match = Magic.getMagicMatch(barr); 807 return match.getMimeType(); 808 } 809 catch (Exception e) { 810 return defaultValue; 811 } 812 finally { 813 System.setOut(out); 814 } 815 } 816 817 /** 818 * check if file is a child of given directory 819 * @param file file to search 820 * @param dir directory to search 821 * @return is inside or not 822 */ 823 public static boolean isChildOf(Resource file, Resource dir) { 824 if(file==null) return false; 825 if(file.equals(dir)) return true; 826 return isChildOf(file.getParentResource(),dir); 827 } 828 /** 829 * return diffrents of one file to a other if first is child of second otherwise return null 830 * @param file file to search 831 * @param dir directory to search 832 */ 833 public static String getPathToChild(Resource file, Resource dir) { 834 boolean isFile=file.isFile(); 835 String str="/"; 836 while(file!=null) { 837 //print.out("- "+file+".equals("+dir+"):"+file.equals(dir)); 838 if(file.equals(dir)) { 839 if(isFile) 840 return str.substring(0,str.length()-1); 841 return str; 842 } 843 str="/"+file.getName()+str; 844 file=file.getParentResource(); 845 } 846 return null; 847 } 848 849 /** 850 * get the Extension of a file 851 * @param res 852 * @return extension of file 853 */ 854 public static String getExtension(Resource res, String defaultValue) { 855 return getExtension(res.getName(),defaultValue); 856 } 857 858 /** 859 * get the Extension of a file 860 * @param strFile 861 * @return extension of file 862 */ 863 public static String getExtension(String strFile, String defaultValue) { 864 int pos=strFile.lastIndexOf('.'); 865 if(pos==-1)return defaultValue; 866 return strFile.substring(pos+1); 867 } 868 869 public static String getName(String strFileName) { 870 int pos=strFileName.lastIndexOf('.'); 871 if(pos==-1)return strFileName; 872 return strFileName.substring(0,pos); 873 } 874 875 /** 876 * split a FileName in Parts 877 * @param fileName 878 * @return new String[]{name[,extension]} 879 */ 880 public static String[] splitFileName(String fileName) { 881 int pos=fileName.lastIndexOf('.'); 882 if(pos==-1) { 883 return new String[]{fileName}; 884 } 885 return new String[]{fileName.substring(0,pos),fileName.substring(pos+1)}; 886 } 887 888 /** 889 * change extesnion of file and return new file 890 * @param file 891 * @param newExtension 892 * @return file with new Extension 893 */ 894 public static Resource changeExtension(Resource file, String newExtension) { 895 String ext=getExtension(file,null); 896 if(ext==null) return file.getParentResource().getRealResource(file.getName()+'.'+newExtension); 897 //new File(file.getParentFile(),file.getName()+'.'+newExtension); 898 String name=file.getName(); 899 return file.getParentResource().getRealResource(name.substring(0,name.length()-ext.length())+newExtension); 900 //new File(file.getParentFile(),name.substring(0,name.length()-ext.length())+newExtension); 901 } 902 903 /** 904 * @param res delete the content of a directory 905 */ 906 907 public static void deleteContent(Resource src,ResourceFilter filter) { 908 _deleteContent(src, filter,false); 909 } 910 public static void _deleteContent(Resource src,ResourceFilter filter,boolean deleteDirectories) { 911 if(src.isDirectory()) { 912 Resource[] files=filter==null?src.listResources():src.listResources(filter); 913 for(int i=0;i<files.length;i++) { 914 _deleteContent(files[i],filter,true); 915 if(deleteDirectories){ 916 try { 917 src.remove(false); 918 } catch (IOException e) {} 919 } 920 } 921 922 } 923 else if(src.isFile()) { 924 src.delete(); 925 } 926 } 927 928 929 /** 930 * copy a file or directory recursive (with his content) 931 * @param res file or directory to delete 932 * @throws IOException 933 * @throws FileNotFoundException 934 */ 935 public static void copyRecursive(Resource src,Resource trg) throws IOException { 936 copyRecursive(src, trg,null); 937 } 938 939 940 /** 941 * copy a file or directory recursive (with his content) 942 * @param src 943 * @param trg 944 * @param filter 945 * @throws IOException 946 * @throws FileNotFoundException 947 */ 948 public static void copyRecursive(Resource src,Resource trg,ResourceFilter filter) throws IOException { 949 //print.out(src); 950 //print.out(trg); 951 if(!src.exists()) return ; 952 if(src.isDirectory()) { 953 if(!trg.exists())trg.createDirectory(true); 954 Resource[] files=filter==null?src.listResources():src.listResources(filter); 955 for(int i=0;i<files.length;i++) { 956 copyRecursive(files[i],trg.getRealResource(files[i].getName()),filter); 957 } 958 } 959 else if(src.isFile()) { 960 touch(trg); 961 IOUtil.copy(src,trg); 962 } 963 } 964 965 public static void copy(Resource src, Resource trg) throws IOException { 966 if(src.equals(trg)) return; 967 ResourceUtil.checkCopyToOK(src,trg); 968 IOUtil.copy(src,trg); 969 } 970 971 972 /** 973 * return if parent file exists 974 * @param res file to check 975 * @return parent exists? 976 */ 977 private static boolean parentExists(Resource res) { 978 res=res.getParentResource(); 979 return res!=null && res.exists(); 980 } 981 982 public static void removeChildren(Resource res) throws IOException { 983 removeChildren(res, (ResourceFilter)null); 984 } 985 986 public static void removeChildren(Resource res,ResourceNameFilter filter) throws IOException { 987 Resource[] children = filter==null?res.listResources():res.listResources(filter); 988 if(children==null) return; 989 990 for(int i=0;i<children.length;i++) { 991 children[i].remove(true); 992 } 993 } 994 995 public static void removeChildren(Resource res,ResourceFilter filter) throws IOException { 996 Resource[] children = filter==null?res.listResources():res.listResources(filter); 997 if(children==null) return; 998 999 for(int i=0;i<children.length;i++) { 1000 children[i].remove(true); 1001 } 1002 } 1003 1004 public static void removeChildrenEL(Resource res,ResourceNameFilter filter) { 1005 try { 1006 removeChildren(res,filter); 1007 } 1008 catch(Throwable e) {} 1009 } 1010 1011 public static void removeChildrenEL(Resource res,ResourceFilter filter) { 1012 try { 1013 removeChildren(res,filter); 1014 } 1015 catch(Throwable e) {} 1016 } 1017 1018 public static void removeChildrenEL(Resource res) { 1019 try { 1020 removeChildren(res); 1021 } 1022 catch(Throwable e) {} 1023 } 1024 1025 public static void removeEL(Resource res, boolean force) { 1026 try { 1027 res.remove(force); 1028 } 1029 catch (Throwable t) {} 1030 } 1031 1032 public static void createFileEL(Resource res, boolean force) { 1033 try { 1034 res.createFile(force); 1035 } 1036 catch (IOException e) {} 1037 } 1038 1039 public static void createDirectoryEL(Resource res, boolean force) { 1040 try { 1041 res.createDirectory(force); 1042 } 1043 catch (IOException e) {} 1044 } 1045 1046 public static ContentType getContentType(Resource resource) { 1047 // TODO make this part of a interface 1048 if(resource instanceof HTTPResource) { 1049 try { 1050 return ((HTTPResource)resource).getContentType(); 1051 } catch (IOException e) {} 1052 } 1053 InputStream is=null; 1054 try { 1055 is = resource.getInputStream(); 1056 return new ContentTypeImpl(is); 1057 } 1058 catch(IOException e) { 1059 return ContentTypeImpl.APPLICATION_UNKNOW; 1060 } 1061 finally { 1062 IOUtil.closeEL(is); 1063 } 1064 } 1065 1066 public static void moveTo(Resource src, Resource dest) throws IOException { 1067 ResourceUtil.checkMoveToOK(src, dest); 1068 1069 if(src.isFile()){ 1070 if(!dest.exists()) dest.createFile(false); 1071 IOUtil.copy(src,dest); 1072 src.remove(false); 1073 } 1074 else { 1075 if(!dest.exists()) dest.createDirectory(false); 1076 Resource[] children = src.listResources(); 1077 for(int i=0;i<children.length;i++){ 1078 moveTo(children[i],dest.getRealResource(children[i].getName())); 1079 } 1080 src.remove(false); 1081 } 1082 dest.setLastModified(System.currentTimeMillis()); 1083 } 1084 1085 /** 1086 * return the size of the Resource, other than method length of Resource this mthod return the size of all files in a directory 1087 * @param collectionDir 1088 * @return 1089 */ 1090 public static long getRealSize(Resource res) { 1091 return getRealSize(res,null); 1092 } 1093 1094 /** 1095 * return the size of the Resource, other than method length of Resource this mthod return the size of all files in a directory 1096 * @param collectionDir 1097 * @return 1098 */ 1099 public static long getRealSize(Resource res, ResourceFilter filter) { 1100 if(res.isFile()) { 1101 return res.length(); 1102 } 1103 else if(res.isDirectory()) { 1104 long size=0; 1105 Resource[] children = filter==null?res.listResources():res.listResources(filter); 1106 for(int i=0;i<children.length;i++) { 1107 size+=getRealSize(children[i]); 1108 } 1109 return size; 1110 } 1111 1112 return 0; 1113 } 1114 1115 1116 /** 1117 * return if Resource is empty, means is directory and has no children or a empty file, 1118 * if not exists return false. 1119 * @param res 1120 * @return 1121 */ 1122 public static boolean isEmpty(Resource res) { 1123 return isEmptyDirectory(res) || isEmptyFile(res); 1124 } 1125 1126 public static boolean isEmptyDirectory(Resource res) { 1127 if(res.isDirectory()) { 1128 String[] children = res.list(); 1129 return children==null || children.length==0; 1130 } 1131 return false; 1132 } 1133 1134 public static boolean isEmptyFile(Resource res) { 1135 if(res.isFile()) { 1136 return res.length()==0; 1137 } 1138 return false; 1139 } 1140 1141 public static Resource toResource(File file) { 1142 return ResourcesImpl.getFileResourceProvider().getResource(file.getPath()); 1143 } 1144 1145 1146 /** 1147 * list childrn of all given resources 1148 * @param resources 1149 * @return 1150 */ 1151 public static Resource[] listResources(Resource[] resources,ResourceFilter filter) { 1152 int count=0; 1153 Resource[] children; 1154 ArrayList list=new ArrayList(); 1155 for(int i=0;i<resources.length;i++) { 1156 children=filter==null?resources[i].listResources():resources[i].listResources(filter); 1157 if(children!=null){ 1158 count+=children.length; 1159 list.add(children); 1160 } 1161 else list.add(new Resource[0]); 1162 } 1163 Resource[] rtn=new Resource[count]; 1164 int index=0; 1165 for(int i=0;i<resources.length;i++) { 1166 children=(Resource[]) list.get(i); 1167 for(int y=0;y<children.length;y++) { 1168 rtn[index++]=children[y]; 1169 } 1170 } 1171 //print.out(rtn); 1172 return rtn; 1173 } 1174 1175 1176 public static Resource[] listResources(Resource res,ResourceFilter filter) { 1177 return filter==null?res.listResources():res.listResources(filter); 1178 } 1179 1180 1181 public static void deleteFileOlderThan(Resource res, long date, ExtensionResourceFilter filter) { 1182 if(res.isFile()) { 1183 if(res.lastModified()<=date) res.delete(); 1184 } 1185 else if(res.isDirectory()) { 1186 Resource[] children = filter==null?res.listResources():res.listResources(filter); 1187 for(int i=0;i<children.length;i++) { 1188 deleteFileOlderThan(children[i],date,filter); 1189 } 1190 } 1191 } 1192 1193 /** 1194 * check if directory creation is ok with the rules for the Resource interface, to not change this rules. 1195 * @param resource 1196 * @param createParentWhenNotExists 1197 * @throws IOException 1198 */ 1199 public static void checkCreateDirectoryOK(Resource resource, boolean createParentWhenNotExists) throws IOException { 1200 if(resource.exists()) { 1201 if(resource.isFile()) 1202 throw new IOException("can't create directory ["+resource.getPath()+"], resource already exists as a file"); 1203 if(resource.isDirectory()) 1204 throw new IOException("can't create directory ["+resource.getPath()+"], directory already exists"); 1205 } 1206 1207 Resource parent = resource.getParentResource(); 1208 // when there is a parent but the parent does not exists 1209 if(parent!=null) { 1210 if(!parent.exists()) { 1211 if(createParentWhenNotExists)parent.createDirectory(true); 1212 else throw new IOException("can't create file ["+resource.getPath()+"], missng parent directory"); 1213 } 1214 else if(parent.isFile()) { 1215 throw new IOException("can't create directory ["+resource.getPath()+"], parent is a file"); 1216 } 1217 } 1218 } 1219 1220 1221 /** 1222 * check if file creating is ok with the rules for the Resource interface, to not change this rules. 1223 * @param resource 1224 * @param createParentWhenNotExists 1225 * @throws IOException 1226 */ 1227 public static void checkCreateFileOK(Resource resource, boolean createParentWhenNotExists) throws IOException { 1228 if(resource.exists()) { 1229 if(resource.isDirectory()) 1230 throw new IOException("can't create file ["+resource.getPath()+"], resource already exists as a directory"); 1231 if(resource.isFile()) 1232 throw new IOException("can't create file ["+resource.getPath()+"], file already exists"); 1233 } 1234 1235 Resource parent = resource.getParentResource(); 1236 // when there is a parent but the parent does not exists 1237 if(parent!=null) { 1238 if(!parent.exists()) { 1239 if(createParentWhenNotExists)parent.createDirectory(true); 1240 else throw new IOException("can't create file ["+resource.getPath()+"], missng parent directory"); 1241 } 1242 else if(parent.isFile()) { 1243 throw new IOException("can't create file ["+resource.getPath()+"], parent is a file"); 1244 } 1245 } 1246 } 1247 1248 /** 1249 * check if copying a file is ok with the rules for the Resource interface, to not change this rules. 1250 * @param source 1251 * @param target 1252 * @throws IOException 1253 */ 1254 public static void checkCopyToOK(Resource source, Resource target) throws IOException { 1255 if(!source.isFile()) { 1256 if(source.isDirectory()) 1257 throw new IOException("can't copy ["+source.getPath()+"] to ["+target.getPath()+"], source is a directory"); 1258 throw new IOException("can't copy ["+source.getPath()+"] to ["+target.getPath()+"], source file does not exists"); 1259 } 1260 else if(target.isDirectory()) { 1261 throw new IOException("can't copy ["+source.getPath()+"] to ["+target.getPath()+"], target is a directory"); 1262 } 1263 } 1264 1265 /** 1266 * check if moveing a file is ok with the rules for the Resource interface, to not change this rules. 1267 * @param source 1268 * @param target 1269 * @throws IOException 1270 */ 1271 public static void checkMoveToOK(Resource source, Resource target) throws IOException { 1272 if(!source.exists()) { 1273 throw new IOException("can't move ["+source.getPath()+"] to ["+target.getPath()+"], source file does not exists"); 1274 } 1275 if(source.isDirectory() && target.isFile()) 1276 throw new IOException("can't move ["+source.getPath()+"] directory to ["+target.getPath()+"], target is a file"); 1277 if(source.isFile() && target.isDirectory()) 1278 throw new IOException("can't move ["+source.getPath()+"] file to ["+target.getPath()+"], target is a directory"); 1279 } 1280 1281 /** 1282 * check if getting a inputstream of the file is ok with the rules for the Resource interface, to not change this rules. 1283 * @param resource 1284 * @throws IOException 1285 */ 1286 public static void checkGetInputStreamOK(Resource resource) throws IOException { 1287 if(!resource.exists()) 1288 throw new IOException("file ["+resource.getPath()+"] does not exists"); 1289 1290 if(resource.isDirectory()) 1291 throw new IOException("can't read directory ["+resource.getPath()+"] as a file"); 1292 1293 } 1294 1295 /** 1296 * check if getting a outputstream of the file is ok with the rules for the Resource interface, to not change this rules. 1297 * @param resource 1298 * @throws IOException 1299 */ 1300 public static void checkGetOutputStreamOK(Resource resource) throws IOException { 1301 if(resource.exists() && !resource.isWriteable()) { 1302 throw new IOException("can't write to file ["+resource.getPath()+"],file is readonly"); 1303 } 1304 if(resource.isDirectory()) 1305 throw new IOException("can't write directory ["+resource.getPath()+"] as a file"); 1306 if(!resource.getParentResource().exists()) 1307 throw new IOException("can't write file ["+resource.getPath()+"] as a file, missing parent directory ["+resource.getParent()+"]"); 1308 } 1309 1310 /** 1311 * check if removing the file is ok with the rules for the Resource interface, to not change this rules. 1312 * @param resource 1313 * @throws IOException 1314 */ 1315 public static void checkRemoveOK(Resource resource) throws IOException { 1316 if(!resource.exists())throw new IOException("can't delete resource "+resource+", resource does not exists"); 1317 if(!resource.canWrite())throw new IOException("can't delete resource "+resource+", no access"); 1318 1319 } 1320 1321 public static void deleteEmptyFolders(Resource res) throws IOException { 1322 if(res.isDirectory()){ 1323 Resource[] children = res.listResources(); 1324 for(int i=0;i<children.length;i++){ 1325 deleteEmptyFolders(children[i]); 1326 } 1327 if(res.listResources().length==0){ 1328 res.remove(false); 1329 } 1330 } 1331 } 1332 1333 // FUTURE this method should be part of pagesource in a more proper way, there should be a method getResource() inside PageSource 1334 public static Resource getResource(PageContext pc,PageSource ps) throws ExpressionException { 1335 Resource res = ps.getPhyscalFile(); 1336 1337 // there is no physical resource 1338 if(res==null){ 1339 String path=ps.getDisplayPath(); 1340 if(path.startsWith("ra://")) 1341 path="zip://"+path.substring(5); 1342 res=ResourceUtil.toResourceExisting(pc, path,false); 1343 } 1344 return res; 1345 } 1346 1347 public static Resource getResource(PageContext pc,PageSource ps, Resource defaultValue) { 1348 try { 1349 return getResource(pc, ps); 1350 } 1351 catch (Throwable t) { 1352 return defaultValue; 1353 } 1354 } 1355 1356 public static int directrySize(Resource dir,ResourceFilter filter) { 1357 if(dir==null || !dir.isDirectory()) return 0; 1358 if(filter==null) return dir.list().length; 1359 return dir.list(filter).length; 1360 } 1361 1362 public static int directrySize(Resource dir,ResourceNameFilter filter) { 1363 if(dir==null || !dir.isDirectory()) return 0; 1364 if(filter==null) return dir.list().length; 1365 return dir.list(filter).length; 1366 } 1367 1368 public static String[] names(Resource[] resources) { 1369 String[] names=new String[resources.length]; 1370 for(int i=0;i<names.length;i++){ 1371 names[i]=resources[i].getName(); 1372 } 1373 return names; 1374 } 1375 1376 }