001 package railo.commons.io.res.type.file; 002 import java.io.BufferedInputStream; 003 import java.io.BufferedOutputStream; 004 import java.io.File; 005 import java.io.FileInputStream; 006 import java.io.FileOutputStream; 007 import java.io.IOException; 008 import java.io.InputStream; 009 import java.io.OutputStream; 010 import java.util.ArrayList; 011 import java.util.List; 012 013 import railo.commons.cli.Command; 014 import railo.commons.io.IOUtil; 015 import railo.commons.io.ModeUtil; 016 import railo.commons.io.SystemUtil; 017 import railo.commons.io.res.ContentType; 018 import railo.commons.io.res.Resource; 019 import railo.commons.io.res.ResourceProvider; 020 import railo.commons.io.res.filter.ResourceFilter; 021 import railo.commons.io.res.filter.ResourceNameFilter; 022 import railo.commons.io.res.util.ResourceOutputStream; 023 import railo.commons.io.res.util.ResourceUtil; 024 025 /** 026 * Implementation og Resource for the local filesystem (java.io.File) 027 */ 028 public final class FileResource extends File implements Resource { 029 030 private final FileResourceProvider provider; 031 032 /** 033 * Constructor for the factory 034 * @param pathname 035 */ 036 FileResource(FileResourceProvider provider,String pathname) { 037 super(pathname); 038 this.provider=provider; 039 } 040 041 /** 042 * Inner Constr constructor to create parent/child 043 * @param parent 044 * @param child 045 */ 046 private FileResource(FileResourceProvider provider,File parent, String child) { 047 super(parent, child); 048 this.provider=provider; 049 } 050 051 052 @Override 053 public void copyFrom(Resource res,boolean append) throws IOException { 054 IOUtil.copy(res, this.getOutputStream(append),true); 055 } 056 057 @Override 058 public void copyTo(Resource res,boolean append) throws IOException { 059 IOUtil.copy(this, res.getOutputStream(append),true); 060 } 061 062 @Override 063 public Resource getAbsoluteResource() { 064 return new FileResource(provider,getAbsolutePath()); 065 } 066 067 @Override 068 public Resource getCanonicalResource() throws IOException { 069 return new FileResource(provider,getCanonicalPath()); 070 } 071 072 @Override 073 public Resource getParentResource() { 074 String p = getParent(); 075 if(p==null) return null; 076 return new FileResource(provider,p); 077 } 078 079 @Override 080 public Resource[] listResources() { 081 String[] files = list(); 082 if(files==null) return null; 083 084 Resource[] resources=new Resource[files.length]; 085 for(int i=0;i<files.length;i++) { 086 resources[i]=getRealResource(files[i]); 087 } 088 return resources; 089 } 090 091 @Override 092 public String[] list(ResourceFilter filter) { 093 String[] files = list(); 094 if(files==null) return null; 095 096 List list=new ArrayList(); 097 FileResource res; 098 for(int i=0;i<files.length;i++) { 099 res=new FileResource(provider,this,files[i]); 100 if(filter.accept(res))list.add(files[i]); 101 } 102 return (String[]) list.toArray(new String[list.size()]); 103 } 104 105 @Override 106 public Resource[] listResources(ResourceFilter filter) { 107 String[] files = list(); 108 if(files==null) return null; 109 110 List list=new ArrayList(); 111 Resource res; 112 for(int i=0;i<files.length;i++) { 113 res=getRealResource(files[i]); 114 if(filter.accept(res))list.add(res); 115 } 116 return (Resource[]) list.toArray(new FileResource[list.size()]); 117 } 118 119 120 @Override 121 public String[] list(ResourceNameFilter filter) { 122 String[] files = list(); 123 if(files==null) return null; 124 List list=new ArrayList(); 125 for(int i=0;i<files.length;i++) { 126 if(filter.accept(this,files[i]))list.add(files[i]); 127 } 128 return (String[]) list.toArray(new String[list.size()]); 129 } 130 131 @Override 132 public Resource[] listResources(ResourceNameFilter filter) { 133 String[] files = list(); 134 if(files==null) return null; 135 136 List list=new ArrayList(); 137 for(int i=0;i<files.length;i++) { 138 if(filter.accept(this,files[i]))list.add(getRealResource(files[i])); 139 } 140 return (Resource[]) list.toArray(new Resource[list.size()]); 141 } 142 143 @Override 144 public void moveTo(Resource dest) throws IOException { 145 if(this.equals(dest)) return; 146 if(dest instanceof File) { 147 provider.lock(this); 148 try { 149 if(dest.exists() && !dest.delete()) 150 throw new IOException("can't move file "+this.getAbsolutePath()+" cannot remove existing file "+dest.getAbsolutePath()); 151 152 if(!super.renameTo((File)dest)) { 153 throw new IOException("can't move file "+this.getAbsolutePath()+" to destination resource "+dest.getAbsolutePath()); 154 } 155 } 156 finally { 157 provider.unlock(this); 158 } 159 } 160 else { 161 ResourceUtil.checkMoveToOK(this, dest); 162 IOUtil.copy(getInputStream(),dest,true); 163 if(!this.delete()) { 164 throw new IOException("can't delete resource "+this.getAbsolutePath()); 165 } 166 } 167 } 168 169 @Override 170 public InputStream getInputStream() throws IOException { 171 //provider.lock(this); 172 provider.read(this); 173 try { 174 //return new BufferedInputStream(new ResourceInputStream(this,new FileInputStream(this))); 175 return new BufferedInputStream(new FileInputStream(this)); 176 } 177 catch(IOException ioe) { 178 //provider.unlock(this); 179 throw ioe; 180 } 181 } 182 183 @Override 184 public OutputStream getOutputStream() throws IOException { 185 return getOutputStream(false); 186 } 187 188 @Override 189 public OutputStream getOutputStream(boolean append) throws IOException { 190 provider.lock(this); 191 try { 192 if(!super.exists() && !super.createNewFile()) { 193 throw new IOException("can't create file "+this); 194 } 195 return new BufferedOutputStream(new ResourceOutputStream(this,new FileOutputStream(this,append))); 196 } 197 catch(IOException ioe) { 198 provider.unlock(this); 199 throw ioe; 200 } 201 } 202 203 @Override 204 public void createFile(boolean createParentWhenNotExists) throws IOException { 205 provider.lock(this); 206 try { 207 if(createParentWhenNotExists) { 208 File p = super.getParentFile(); 209 if(!p.exists()) p.mkdirs(); 210 } 211 if(!super.createNewFile()) { 212 if(super.isFile()) throw new IOException("can't create file "+this+", file already exists"); 213 throw new IOException("can't create file "+this); 214 } 215 } 216 finally { 217 provider.unlock(this); 218 } 219 } 220 221 @Override 222 public void remove(boolean alsoRemoveChildren) throws IOException { 223 if(alsoRemoveChildren && isDirectory()) { 224 Resource[] children = listResources(); 225 for(int i=0;i<children.length;i++) { 226 children[i].remove(alsoRemoveChildren); 227 } 228 } 229 provider.lock(this); 230 try { 231 if(!super.delete()) { 232 if(!super.exists())throw new IOException("can't delete file "+this+", file does not exist"); 233 if(!super.canWrite())throw new IOException("can't delete file "+this+", no access"); 234 throw new IOException("can't delete file "+this); 235 } 236 } 237 finally { 238 provider.unlock(this); 239 } 240 } 241 242 @Override 243 public String getReal(String realpath) { 244 if(realpath.length()<=2) { 245 if(realpath.length()==0) return getPath(); 246 if(realpath.equals(".")) return getPath(); 247 if(realpath.equals("..")) return getParent(); 248 } 249 return new FileResource(provider,this,realpath).getPath(); 250 } 251 252 @Override 253 public Resource getRealResource(String realpath) { 254 if(realpath.length()<=2) { 255 if(realpath.length()==0) return this; 256 if(realpath.equals(".")) return this; 257 if(realpath.equals("..")) return getParentResource(); 258 } 259 return new FileResource(provider,this,realpath); 260 } 261 262 public ContentType getContentType() { 263 return ResourceUtil.getContentType(this); 264 } 265 266 @Override 267 public void createDirectory(boolean createParentWhenNotExists) throws IOException { 268 provider.lock(this); 269 try { 270 if(createParentWhenNotExists?!_mkdirs():!super.mkdir()) { 271 if(super.isDirectory()) throw new IOException("can't create directory "+this+", directory already exists"); 272 throw new IOException("can't create directory "+this); 273 } 274 } 275 finally { 276 provider.unlock(this); 277 } 278 } 279 280 @Override 281 public ResourceProvider getResourceProvider() { 282 return provider; 283 } 284 285 @Override 286 public boolean isReadable() { 287 return canRead(); 288 } 289 290 @Override 291 public boolean isWriteable() { 292 return canWrite(); 293 } 294 295 @Override 296 public boolean renameTo(Resource dest) { 297 try { 298 moveTo(dest); 299 return true; 300 } 301 catch (IOException e) {} 302 return false; 303 } 304 305 @Override 306 public boolean isArchive() { 307 return getAttribute(ATTRIBUTE_ARCHIVE); 308 } 309 310 @Override 311 public boolean isSystem() { 312 return getAttribute(ATTRIBUTE_SYSTEM); 313 } 314 315 @Override 316 public int getMode() { 317 if(!exists()) return 0; 318 if(SystemUtil.isUnix()) { 319 try { 320 // TODO geht nur fuer file 321 String line = Command.execute("ls -ld "+getPath(),false); 322 323 line=line.trim(); 324 line=line.substring(0,line.indexOf(' ')); 325 //print.ln(getPath()); 326 return ModeUtil.toOctalMode(line); 327 328 } catch (Exception e) {} 329 330 } 331 int mode=SystemUtil.isWindows() && exists() ?0111:0; 332 if(super.canRead())mode+=0444; 333 if(super.canWrite())mode+=0222; 334 return mode; 335 } 336 337 public void setMode(int mode) throws IOException { 338 // TODO unter windows mit setReadable usw. 339 if(!SystemUtil.isUnix()) return; 340 provider.lock(this); 341 try { 342 //print.ln(ModeUtil.toStringMode(mode)); 343 if (Runtime.getRuntime().exec( 344 new String[] { "chmod", ModeUtil.toStringMode(mode), getPath() } ).waitFor() != 0) 345 throw new IOException("chmod "+ModeUtil.toStringMode(mode)+" " + toString() + " failed"); 346 } 347 catch (InterruptedException e) { 348 throw new IOException("Interrupted waiting for chmod " + toString()); 349 } 350 finally { 351 provider.unlock(this); 352 } 353 } 354 355 @Override 356 public void setArchive(boolean value) throws IOException { 357 setAttribute(ATTRIBUTE_ARCHIVE, value); 358 } 359 360 @Override 361 public void setHidden(boolean value) throws IOException { 362 setAttribute(ATTRIBUTE_HIDDEN, value); 363 } 364 365 @Override 366 public void setSystem(boolean value) throws IOException { 367 setAttribute(ATTRIBUTE_SYSTEM, value); 368 } 369 370 @Override 371 372 public boolean setReadable(boolean value) { 373 if(!SystemUtil.isUnix()) return false; 374 try { 375 setMode(ModeUtil.setReadable(getMode(), value)); 376 return true; 377 } 378 catch (IOException e) { 379 return false; 380 } 381 } 382 383 public boolean setWritable(boolean value) { 384 // setReadonly 385 if(!value){ 386 try { 387 provider.lock(this); 388 if(!super.setReadOnly()) 389 throw new IOException("can't set resource read-only"); 390 } 391 catch(IOException ioe){ 392 return false; 393 } 394 finally { 395 provider.unlock(this); 396 } 397 return true; 398 } 399 400 if(SystemUtil.isUnix()) { 401 // need no lock because get/setmode has one 402 try { 403 setMode(ModeUtil.setWritable(getMode(), value)); 404 } 405 catch (IOException e) { 406 return false; 407 } 408 return true; 409 } 410 411 try { 412 provider.lock(this); 413 Runtime.getRuntime().exec("attrib -R " + getAbsolutePath()); 414 } 415 catch(IOException ioe){ 416 return false; 417 } 418 finally { 419 provider.unlock(this); 420 } 421 return true; 422 } 423 424 425 426 427 428 429 @Override 430 public boolean createNewFile() { 431 try { 432 provider.lock(this); 433 return super.createNewFile(); 434 } 435 catch (IOException e) { 436 return false; 437 } 438 finally { 439 provider.unlock(this); 440 } 441 } 442 443 @Override 444 public boolean canRead() { 445 try { 446 provider.read(this); 447 } catch (IOException e) { 448 return false; 449 } 450 return super.canRead(); 451 } 452 453 @Override 454 public boolean canWrite() { 455 try { 456 provider.read(this); 457 } catch (IOException e) { 458 return false; 459 } 460 return super.canWrite(); 461 } 462 463 @Override 464 public boolean delete() { 465 try { 466 provider.lock(this); 467 return super.delete(); 468 } 469 catch (IOException e) { 470 return false; 471 } 472 finally { 473 provider.unlock(this); 474 } 475 } 476 477 @Override 478 public boolean exists() { 479 try { 480 provider.read(this); 481 } catch (IOException e) {} 482 483 return super.exists(); 484 } 485 486 487 488 @Override 489 public boolean isAbsolute() { 490 try { 491 provider.read(this); 492 } 493 catch (IOException e) { 494 return false; 495 } 496 return super.isAbsolute(); 497 } 498 499 @Override 500 public boolean isDirectory() { 501 try { 502 provider.read(this); 503 } catch (IOException e) { 504 return false; 505 } 506 return super.isDirectory(); 507 } 508 509 @Override 510 public boolean isFile() { 511 try { 512 provider.read(this); 513 } catch (IOException e) { 514 return false; 515 } 516 return super.isFile(); 517 } 518 519 @Override 520 public boolean isHidden() { 521 try { 522 provider.read(this); 523 } catch (IOException e) { 524 return false; 525 } 526 return super.isHidden(); 527 } 528 529 @Override 530 public long lastModified() { 531 try { 532 provider.read(this); 533 } catch (IOException e) { 534 return 0; 535 } 536 return super.lastModified(); 537 } 538 539 @Override 540 public long length() { 541 try { 542 provider.read(this); 543 } catch (IOException e) { 544 return 0; 545 } 546 return super.length(); 547 } 548 549 @Override 550 public String[] list() { 551 try { 552 provider.read(this); 553 } catch (IOException e) { 554 return null; 555 } 556 return super.list(); 557 } 558 559 @Override 560 public boolean mkdir() { 561 try { 562 provider.lock(this); 563 return super.mkdir(); 564 } 565 catch (IOException e) { 566 return false; 567 } 568 finally { 569 provider.unlock(this); 570 } 571 } 572 573 @Override 574 public boolean mkdirs() { 575 try { 576 provider.lock(this); 577 return _mkdirs(); 578 579 } 580 catch (IOException e) { 581 return false; 582 } 583 finally { 584 provider.unlock(this); 585 } 586 } 587 588 private boolean _mkdirs() { 589 if (super.exists()) return false; 590 if (super.mkdir()) return true; 591 592 File parent = super.getParentFile(); 593 return (parent != null) && (parent.mkdirs() && super.mkdir()); 594 } 595 596 @Override 597 public boolean setLastModified(long time) { 598 try { 599 provider.lock(this); 600 return super.setLastModified(time); 601 } 602 catch (Throwable t) {// IllegalArgumentException or IOException 603 return false; 604 } 605 finally { 606 provider.unlock(this); 607 } 608 609 } 610 611 @Override 612 public boolean setReadOnly() { 613 try { 614 provider.lock(this); 615 return super.setReadOnly(); 616 } 617 catch (IOException e) { 618 return false; 619 } 620 finally { 621 provider.unlock(this); 622 } 623 } 624 625 public boolean getAttribute(short attribute) { 626 if(!SystemUtil.isWindows()) return false; 627 if(attribute==ATTRIBUTE_HIDDEN) return isHidden(); 628 629 String attr=null; 630 if(attribute==ATTRIBUTE_ARCHIVE) attr="A"; 631 else if(attribute==ATTRIBUTE_SYSTEM) attr="S"; 632 633 try { 634 provider.lock(this); 635 String result = Command.execute("attrib " + getAbsolutePath(),false); 636 String[] arr = railo.runtime.type.util.ListUtil.listToStringArray(result, ' '); 637 for(int i=0;i>arr.length-1;i++) { 638 if(attr.equals(arr[i].toUpperCase())) return true; 639 } 640 } 641 catch (Exception e) {} 642 finally { 643 provider.unlock(this); 644 } 645 return false; 646 } 647 648 public void setAttribute(short attribute, boolean value) throws IOException { 649 String attr=null; 650 if(attribute==ATTRIBUTE_ARCHIVE) attr="A"; 651 else if(attribute==ATTRIBUTE_HIDDEN) attr="H"; 652 else if(attribute==ATTRIBUTE_SYSTEM) attr="S"; 653 654 if(!SystemUtil.isWindows()) return ; 655 provider.lock(this); 656 try { 657 Runtime.getRuntime().exec("attrib "+attr+(value?"+":"-")+" " + getAbsolutePath()); 658 } 659 finally { 660 provider.unlock(this); 661 } 662 } 663 664 public boolean equals(Object other){ 665 if(provider.isCaseSensitive()) return super.equals(other); 666 if(!(other instanceof File)) return false; 667 return getAbsolutePath().equalsIgnoreCase(((File)other).getAbsolutePath()); 668 } 669 }