001 package railo.runtime.tag; 002 003 import java.awt.image.BufferedImage; 004 import java.io.ByteArrayInputStream; 005 import java.io.File; 006 import java.io.IOException; 007 import java.io.InputStream; 008 import java.io.UnsupportedEncodingException; 009 010 import railo.commons.io.IOUtil; 011 import railo.commons.io.ModeUtil; 012 import railo.commons.io.SystemUtil; 013 import railo.commons.io.res.Resource; 014 import railo.commons.io.res.type.s3.S3; 015 import railo.commons.io.res.type.s3.S3Resource; 016 import railo.commons.io.res.util.ModeObjectWrap; 017 import railo.commons.io.res.util.ResourceUtil; 018 import railo.commons.lang.StringUtil; 019 import railo.runtime.PageContext; 020 import railo.runtime.exp.ApplicationException; 021 import railo.runtime.exp.PageException; 022 import railo.runtime.ext.tag.TagImpl; 023 import railo.runtime.functions.list.ListFirst; 024 import railo.runtime.functions.list.ListLast; 025 import railo.runtime.functions.s3.StoreSetACL; 026 import railo.runtime.img.ImageUtil; 027 import railo.runtime.op.Caster; 028 import railo.runtime.op.Decision; 029 import railo.runtime.type.Array; 030 import railo.runtime.type.ArrayImpl; 031 import railo.runtime.type.Collection.Key; 032 import railo.runtime.type.KeyImpl; 033 import railo.runtime.type.List; 034 import railo.runtime.type.Struct; 035 import railo.runtime.type.StructImpl; 036 import railo.runtime.type.dt.DateImpl; 037 import railo.runtime.type.dt.DateTimeImpl; 038 import railo.runtime.type.scope.FormImpl; 039 import railo.runtime.type.scope.FormImpl.Item; 040 import railo.runtime.type.scope.FormUpload; 041 import railo.runtime.type.util.ArrayUtil; 042 043 /** 044 * Handles all interactions with files. The attributes you use with cffile depend on the value of the action attribute. 045 * For example, if the action = "write", use the attributes associated with writing a text file. 046 * 047 * 048 * 049 **/ 050 public final class FileTag extends TagImpl { 051 052 public static final int NAMECONFLICT_UNDEFINED=0; 053 public static final int NAMECONFLICT_ERROR=1; 054 public static final int NAMECONFLICT_SKIP=2; 055 public static final int NAMECONFLICT_OVERWRITE=3; 056 public static final int NAMECONFLICT_MAKEUNIQUE=4; 057 private static final Key SET_ACL = KeyImpl.intern("setACL"); 058 059 //private static final String DEFAULT_ENCODING=Charset.getDefault(); 060 061 /** Type of file manipulation that the tag performs. */ 062 private String action; 063 064 /** Absolute pathname of directory or file on web server. */ 065 private String strDestination; 066 067 /** Content of the file to be created. */ 068 private Object output; 069 070 /** Absolute pathname of file on web server. */ 071 private Resource file; 072 073 /** Applies only to Solaris and HP-UX. Permissions. Octal values of UNIX chmod command. Assigned to owner, group, and other, respectively. */ 074 private int mode=-1; 075 076 /** Name of variable to contain contents of text file. */ 077 private String variable; 078 079 /** Name of form field used to select the file. */ 080 private String filefield; 081 082 /** Character set name for the file contents. */ 083 private String charset=null; 084 085 /** Yes: appends newline character to text written to file */ 086 private boolean addnewline=true; 087 private boolean fixnewline=true; 088 /** One attribute (Windows) or a comma-delimited list of attributes (other platforms) to set on the file. 089 ** If omitted, the file's attributes are maintained. */ 090 private String attributes; 091 092 /** Absolute pathname of file on web server. 093 ** On Windows, use backward slashes; on UNIX, use forward slashes. */ 094 private Resource source; 095 096 /** Action to take if filename is the same as that of a file in the directory. */ 097 private int nameconflict=NAMECONFLICT_UNDEFINED; 098 099 /** Limits the MIME types to accept. Comma-delimited list. For example, to permit JPG and Microsoft Word file uploads: 100 ** accept = "image/jpg, application/msword" 101 ** The browser uses file extension to determine file type. */ 102 private String accept; 103 104 private String result=null; 105 106 private railo.runtime.security.SecurityManager securityManager; 107 108 private String serverPassword=null; 109 private Object acl=null; 110 111 /** 112 * @see javax.servlet.jsp.tagext.Tag#release() 113 */ 114 public void release() { 115 super.release(); 116 acl=null; 117 action=null; 118 strDestination=null; 119 output=null; 120 file=null; 121 mode=-1; 122 variable=null; 123 filefield=null; 124 charset=null; 125 addnewline=true; 126 fixnewline=true; 127 attributes=null; 128 source=null; 129 nameconflict=NAMECONFLICT_UNDEFINED; 130 accept=null; 131 securityManager=null; 132 result=null; 133 serverPassword=null; 134 } 135 136 /** set the value action 137 * Type of file manipulation that the tag performs. 138 * @param action value to set 139 **/ 140 public void setAction(String action) { 141 this.action=action.toLowerCase(); 142 } 143 144 /** set the value destination 145 * Absolute pathname of directory or file on web server. 146 * @param destination value to set 147 **/ 148 public void setDestination(String destination) { 149 this.strDestination=destination;//ResourceUtil.toResourceNotExisting(pageContext ,destination); 150 } 151 152 /** set the value output 153 * Content of the file to be created. 154 * @param output value to set 155 **/ 156 public void setOutput(Object output) { 157 if(output==null)this.output=""; 158 else this.output=output; 159 } 160 161 /** set the value file 162 * Absolute pathname of file on web server. 163 * @param file value to set 164 **/ 165 public void setFile(String file) { 166 this.file=ResourceUtil.toResourceNotExisting(pageContext ,file); 167 168 } 169 170 /** set the value mode 171 * Applies only to Solaris and HP-UX. Permissions. Octal values of UNIX chmod command. Assigned to owner, group, and other, respectively. 172 * @param mode value to set 173 * @throws PageException 174 **/ 175 public void setMode(String mode) throws PageException { 176 this.mode=toMode(mode); 177 } 178 179 180 public static int toMode(String mode) throws PageException { 181 if(StringUtil.isEmpty(mode,true)) return -1; 182 try { 183 return ModeUtil.toOctalMode(mode); 184 } 185 catch (IOException e) { 186 throw Caster.toPageException(e); 187 } 188 } 189 190 191 /** set the value variable 192 * Name of variable to contain contents of text file. 193 * @param variable value to set 194 **/ 195 public void setVariable(String variable) { 196 this.variable=variable; 197 } 198 199 /** set the value filefield 200 * Name of form field used to select the file. 201 * @param filefield value to set 202 **/ 203 public void setFilefield(String filefield) { 204 this.filefield=filefield; 205 } 206 207 /** set the value charset 208 * Character set name for the file contents. 209 * @param charset value to set 210 **/ 211 public void setCharset(String charset) { 212 this.charset=charset.trim(); 213 } 214 215 /** set the value acl 216 * used only for s3 resources, for all others ignored 217 * @param charset value to set 218 * @throws ApplicationException 219 * @Deprecated only exists for backward compatibility to old ra files. 220 **/ 221 public void setAcl(String acl) throws ApplicationException { 222 this.acl=acl; 223 } 224 public void setAcl(Object acl) throws ApplicationException { 225 this.acl=acl; 226 } 227 public void setStoreacl(Object acl) throws ApplicationException { 228 this.acl=acl; 229 } 230 231 232 233 public void setServerpassword(String serverPassword) { 234 this.serverPassword=serverPassword; 235 } 236 237 /** set the value addnewline 238 * Yes: appends newline character to text written to file 239 * @param addnewline value to set 240 **/ 241 public void setAddnewline(boolean addnewline) { 242 this.addnewline=addnewline; 243 } 244 245 /** set the value attributes 246 * One attribute (Windows) or a comma-delimited list of attributes (other platforms) to set on the file. 247 * If omitted, the file's attributes are maintained. 248 * @param attributes value to set 249 **/ 250 public void setAttributes(String attributes) { 251 this.attributes=attributes; 252 } 253 254 /** set the value source 255 * Absolute pathname of file on web server. 256 * On Windows, use backward slashes; on UNIX, use forward slashes. 257 * @param source value to set 258 **/ 259 public void setSource(String source) { 260 this.source=ResourceUtil.toResourceNotExisting(pageContext ,source); 261 } 262 263 /** set the value nameconflict 264 * Action to take if filename is the same as that of a file in the directory. 265 * @param nameconflict value to set 266 * @throws ApplicationException 267 **/ 268 public void setNameconflict(String nameconflict) throws ApplicationException { 269 this.nameconflict=toNameconflict(nameconflict); 270 } 271 272 public static int toNameconflict(String nameconflict) throws ApplicationException { 273 if(StringUtil.isEmpty(nameconflict,true)) return NAMECONFLICT_UNDEFINED; 274 275 nameconflict=nameconflict.toLowerCase().trim(); 276 if("error".equals(nameconflict)) return NAMECONFLICT_ERROR; 277 else if("skip".equals(nameconflict)) return NAMECONFLICT_SKIP; 278 else if("overwrite".equals(nameconflict)) return NAMECONFLICT_OVERWRITE; 279 else if("makeunique".equals(nameconflict)) return NAMECONFLICT_MAKEUNIQUE; 280 else throw new ApplicationException("invalid value for attribute/argument nameconflict ["+nameconflict+"]", 281 "valid values are [error,skip,overwrite,makeunique]"); 282 } 283 284 285 286 /** set the value accept 287 * Limits the MIME types to accept. Comma-delimited list. For example, to permit JPG and Microsoft Word file uploads: 288 * accept = "image/jpg, application/msword" 289 * The browser uses file extension to determine file type. 290 * @param accept value to set 291 **/ 292 public void setAccept(String accept) { 293 this.accept=accept; 294 } 295 296 /** 297 * @param result The result to set. 298 */ 299 public void setResult(String result) { 300 this.result = result; 301 } 302 303 304 /** 305 * @see javax.servlet.jsp.tagext.Tag#doStartTag() 306 */ 307 public int doStartTag() throws PageException { 308 309 if(StringUtil.isEmpty(charset)) charset=pageContext.getConfig().getResourceCharset(); 310 311 securityManager = pageContext.getConfig().getSecurityManager(); 312 if(action.equals("move")) actionMove(pageContext, securityManager,source, strDestination, nameconflict,serverPassword,acl, mode, attributes); 313 else if(action.equals("rename")) actionMove(pageContext, securityManager,source, strDestination, nameconflict,serverPassword,acl, mode, attributes); 314 else if(action.equals("copy")) actionCopy(pageContext, securityManager,source, strDestination, nameconflict,serverPassword,acl, mode, attributes); 315 else if(action.equals("delete")) actionDelete(); 316 else if(action.equals("read")) actionRead(); 317 else if(action.equals("readbinary")) actionReadBinary(); 318 else if(action.equals("write")) actionWrite(); 319 else if(action.equals("append")) actionAppend(); 320 else if(action.equals("upload")) actionUpload(); 321 else if(action.equals("uploadall")) actionUploadAll(); 322 else if(action.equals("info")) actionInfo(); 323 else if(action.equals("touch")) actionTouch(); 324 else 325 throw new ApplicationException("invalid value ["+action+"] for attribute action","values for attribute action are:info,move,rename,copy,delete,read,readbinary,write,append,upload,uploadall"); 326 327 return SKIP_BODY; 328 } 329 330 /** 331 * @see javax.servlet.jsp.tagext.Tag#doEndTag() 332 */ 333 public int doEndTag() { 334 return EVAL_PAGE; 335 } 336 337 /** 338 * move source file to destination path or file 339 * @throws PageException 340 */ 341 public static void actionMove(PageContext pageContext, railo.runtime.security.SecurityManager securityManager, 342 Resource source, String strDestination, int nameconflict,String serverPassword, 343 Object acl, int mode, String attributes) throws PageException { 344 if(nameconflict==NAMECONFLICT_UNDEFINED) nameconflict=NAMECONFLICT_OVERWRITE; 345 346 if(source==null) 347 throw new ApplicationException("attribute source is not defined for tag file"); 348 if(StringUtil.isEmpty(strDestination)) 349 throw new ApplicationException("attribute destination is not defined for tag file"); 350 351 Resource destination=toDestination(pageContext,strDestination,source); 352 353 securityManager.checkFileLocation(pageContext.getConfig(),source,serverPassword); 354 securityManager.checkFileLocation(pageContext.getConfig(),destination,serverPassword); 355 if(source.equals(destination)) return ; 356 357 // source 358 if(!source.exists()) 359 throw new ApplicationException("source file ["+source.toString()+"] doesn't exist"); 360 else if(!source.isFile()) 361 throw new ApplicationException("source file ["+source.toString()+"] is not a file"); 362 else if(!source.isReadable() || !source.isWriteable()) 363 throw new ApplicationException("no access to source file ["+source.toString()+"]"); 364 365 // destination 366 if(destination.isDirectory()) destination=destination.getRealResource(source.getName()); 367 if(destination.exists()) { 368 // SKIP 369 if(nameconflict==NAMECONFLICT_SKIP) return; 370 // OVERWRITE 371 else if(nameconflict==NAMECONFLICT_OVERWRITE) destination.delete(); 372 // MAKEUNIQUE 373 else if(nameconflict==NAMECONFLICT_MAKEUNIQUE) destination=makeUnique(destination); 374 // ERROR 375 else throw new ApplicationException("destiniation file ["+destination.toString()+"] already exist"); 376 } 377 378 379 try { 380 source.moveTo(destination); 381 382 } 383 catch(Throwable t) {t.printStackTrace(); 384 throw new ApplicationException(t.getMessage()); 385 } 386 setACL(destination,acl); 387 setMode(destination,mode); 388 setAttributes(destination,attributes); 389 } 390 391 private static Resource toDestination(PageContext pageContext,String path, Resource source) { 392 if(source!=null && path.indexOf(File.separatorChar)==-1 && path.indexOf('/')==-1 && path.indexOf('\\')==-1) { 393 Resource p = source.getParentResource(); 394 if(p!=null)return p.getRealResource(path); 395 } 396 return ResourceUtil.toResourceNotExisting(pageContext ,path); 397 } 398 399 /** 400 * copy source file to destination file or path 401 * @throws PageException 402 */ 403 public static void actionCopy(PageContext pageContext, railo.runtime.security.SecurityManager securityManager, 404 Resource source, String strDestination, int nameconflict,String serverPassword, 405 Object acl, int mode, String attributes) throws PageException { 406 if(nameconflict==NAMECONFLICT_UNDEFINED) nameconflict=NAMECONFLICT_OVERWRITE; 407 408 if(source==null) 409 throw new ApplicationException("attribute source is not defined for tag file"); 410 if(StringUtil.isEmpty(strDestination)) 411 throw new ApplicationException("attribute destination is not defined for tag file"); 412 413 Resource destination=toDestination(pageContext,strDestination,source); 414 415 416 securityManager.checkFileLocation(pageContext.getConfig(),source,serverPassword); 417 securityManager.checkFileLocation(pageContext.getConfig(),destination,serverPassword); 418 419 // source 420 if(!source.exists()) 421 throw new ApplicationException("source file ["+source.toString()+"] doesn't exist"); 422 else if(!source.isFile()) 423 throw new ApplicationException("source file ["+source.toString()+"] is not a file"); 424 else if(!source.canRead()) 425 throw new ApplicationException("no access to source file ["+source.toString()+"]"); 426 427 // destination 428 if(destination.isDirectory()) destination=destination.getRealResource(source.getName()); 429 if(destination.exists()) { 430 // SKIP 431 if(nameconflict==NAMECONFLICT_SKIP) return; 432 // SKIP 433 else if(nameconflict==NAMECONFLICT_OVERWRITE) destination.delete(); 434 // MAKEUNIQUE 435 else if(nameconflict==NAMECONFLICT_MAKEUNIQUE) destination=makeUnique(destination); 436 // ERROR 437 else throw new ApplicationException("destiniation file ["+destination.toString()+"] already exist"); 438 } 439 440 try { 441 IOUtil.copy(source,destination); 442 } 443 catch(IOException e) { 444 445 ApplicationException ae = new ApplicationException("can't copy file ["+source+"] to ["+destination+"]",e.getMessage()); 446 ae.setStackTrace(e.getStackTrace()); 447 throw ae; 448 } 449 setACL(destination,acl); 450 setMode(destination,mode); 451 setAttributes(destination,attributes); 452 } 453 454 private static void setACL(Resource res,Object acl) throws PageException { 455 String scheme = res.getResourceProvider().getScheme(); 456 457 if("s3".equalsIgnoreCase(scheme)){ 458 S3Resource s3r=(S3Resource) res; 459 460 if(acl!=null){ 461 try { 462 // old way 463 if(Decision.isString(acl)) { 464 s3r.setACL(S3.toIntACL(Caster.toString(acl))); 465 } 466 // new way 467 else { 468 StoreSetACL.invoke(s3r, acl); 469 } 470 } catch (IOException e) { 471 throw Caster.toPageException(e); 472 } 473 } 474 475 } 476 // set acl for s3 resource 477 /*if(res instanceof S3Resource) { 478 ((S3Resource)res).setACL(acl); 479 }*/ 480 } 481 482 private static Resource makeUnique(Resource res) { 483 484 String ext=getFileExtension(res); 485 String name=getFileName(res); 486 ext=(ext==null)?"":"."+ext; 487 int count=0; 488 while(res.exists()) { 489 res=res.getParentResource().getRealResource(name+(++count)+ext); 490 } 491 492 return res; 493 } 494 495 /** 496 * copy source file to destination file or path 497 * @throws PageException 498 */ 499 private void actionDelete() throws PageException { 500 checkFile(false,false,false); 501 setACL(file,acl); 502 try { 503 if(!file.delete()) throw new ApplicationException("can't delete file ["+file+"]"); 504 } 505 catch(Throwable t) { 506 throw new ApplicationException(t.getMessage()); 507 } 508 } 509 510 /** 511 * read source file 512 * @throws PageException 513 */ 514 private void actionRead() throws PageException { 515 if(variable==null) 516 throw new ApplicationException("attribute variable is not defined for tag file"); 517 checkFile(false,true,false); 518 //print.ln(charset); 519 //TextFile tf=new TextFile(file.getAbsolutePath()); 520 521 try { 522 pageContext.setVariable(variable,IOUtil.toString(file,charset)); 523 } 524 catch (IOException e) { 525 526 throw new ApplicationException("can't read file ["+file+"]",e.getMessage()); 527 } 528 529 } 530 531 /** 532 * read source file 533 * @throws PageException 534 */ 535 private void actionReadBinary() throws PageException { 536 if(variable==null) 537 throw new ApplicationException("attribute variable is not defined for tag file"); 538 checkFile(false,true,false); 539 540 //TextFile tf=new TextFile(file.getAbsolutePath()); 541 542 try { 543 pageContext.setVariable(variable,IOUtil.toBytes(file)); 544 }catch (IOException e) { 545 throw new ApplicationException("can't read binary file ["+source.toString()+"]",e.getMessage()); 546 } 547 } 548 549 /** 550 * write to the source file 551 * @throws PageException 552 */ 553 private void actionWrite() throws PageException { 554 if(output==null) 555 throw new ApplicationException("attribute output is not defined for tag file"); 556 checkFile(true,false,true); 557 558 try { 559 if(output instanceof InputStream) { 560 IOUtil.copy( 561 (InputStream)output, 562 file, 563 false); 564 } 565 else if(Decision.isCastableToBinary(output,false)) { 566 IOUtil.copy( 567 new ByteArrayInputStream(Caster.toBinary(output)), 568 file, 569 true); 570 } 571 else { 572 String content=Caster.toString(output); 573 if(fixnewline)content=doFixNewLine(content); 574 if(addnewline) content+=SystemUtil.getOSSpecificLineSeparator(); 575 576 if(content.length()==0)ResourceUtil.touch(file); 577 else IOUtil.write(file,content,charset,false); 578 579 } 580 } 581 catch (UnsupportedEncodingException e) { 582 throw new ApplicationException("Unsupported Charset Definition ["+charset+"]",e.getMessage()); 583 } 584 catch (IOException e) { 585 586 throw new ApplicationException("can't write file "+file.getAbsolutePath(),e.getMessage()); 587 } 588 setACL(file,acl); 589 setMode(file,mode); 590 setAttributes(file,attributes); 591 } 592 593 /** 594 * write to the source file 595 * @throws PageException 596 */ 597 private void actionTouch() throws PageException { 598 checkFile(true,true,true); 599 600 try { 601 ResourceUtil.touch(file); 602 } 603 catch (IOException e) { 604 605 throw new ApplicationException("can't touch file "+file.getAbsolutePath(),e.getMessage()); 606 } 607 608 setACL(file,acl); 609 setMode(file,mode); 610 setAttributes(file,attributes); 611 } 612 613 614 615 /** 616 * append data to source file 617 * @throws PageException 618 */ 619 private void actionAppend() throws PageException { 620 if(output==null) 621 throw new ApplicationException("attribute output is not defined for tag file"); 622 checkFile(true,false,true); 623 624 try { 625 626 if(!file.exists()) file.createNewFile(); 627 String content=Caster.toString(output); 628 if(fixnewline)content=doFixNewLine(content); 629 if(addnewline) content+=SystemUtil.getOSSpecificLineSeparator(); 630 IOUtil.write(file,content,charset,true); 631 632 } 633 catch (UnsupportedEncodingException e) { 634 throw new ApplicationException("Unsupported Charset Definition ["+charset+"]",e.getMessage()); 635 } 636 catch (IOException e) { 637 throw new ApplicationException("can't write file",e.getMessage()); 638 } 639 setACL(file,acl); 640 setMode(file,mode); 641 setAttributes(file,attributes); 642 } 643 644 private String doFixNewLine(String content) { 645 // TODO replace new line with system new line 646 return content; 647 } 648 649 /** 650 * list all files and directories inside a directory 651 * @throws PageException 652 */ 653 private void actionInfo() throws PageException { 654 655 if(variable==null) 656 throw new ApplicationException("attribute variable is not defined for tag file"); 657 checkFile(false,false,false); 658 659 Struct sct =new StructImpl(); 660 pageContext.setVariable(variable,sct); 661 662 // fill data to query 663 sct.setEL(KeyImpl.NAME,file.getName()); 664 sct.setEL(KeyImpl.SIZE,Long.valueOf(file.length())); 665 sct.setEL(KeyImpl.TYPE,file.isDirectory()?"Dir":"File"); 666 sct.setEL("dateLastModified",new DateTimeImpl(pageContext,file.lastModified(),false)); 667 sct.setEL("attributes",getFileAttribute(file)); 668 if(SystemUtil.isUnix())sct.setEL("mode",new ModeObjectWrap(file)); 669 670 try { 671 BufferedImage bi = ImageUtil.toBufferedImage(file, null); 672 if(bi!=null) { 673 Struct img =new StructImpl(); 674 img.setEL("width",new Double(bi.getWidth())); 675 img.setEL("height",new Double(bi.getHeight())); 676 sct.setEL("img",img); 677 } 678 } 679 catch (Throwable t) {} 680 } 681 682 private static String getFileAttribute(Resource file){ 683 return file.exists() && !file.canWrite() ? "R".concat(file.isHidden() ? "H" : "") : file.isHidden() ? "H" : ""; 684 } 685 686 /** 687 * read source file 688 * @throws PageException 689 */ 690 691 public void actionUpload() throws PageException { 692 FormImpl.Item item=getFormItem(pageContext,filefield); 693 Struct cffile = _actionUpload(pageContext,securityManager,item,strDestination,nameconflict,accept,mode,attributes,acl,serverPassword); 694 if(StringUtil.isEmpty(result)) { 695 pageContext.undefinedScope().set("file",cffile); 696 pageContext.undefinedScope().set("cffile",cffile); 697 } 698 else { 699 pageContext.setVariable(result,cffile); 700 } 701 } 702 703 704 public static Struct actionUpload(PageContext pageContext,railo.runtime.security.SecurityManager securityManager,String filefield, 705 String strDestination,int nameconflict,String accept,int mode,String attributes,Object acl,String serverPassword) throws PageException { 706 FormImpl.Item item=getFormItem(pageContext,filefield); 707 return _actionUpload(pageContext,securityManager,item,strDestination,nameconflict,accept,mode,attributes,acl,serverPassword); 708 } 709 710 public void actionUploadAll() throws PageException { 711 Array arr=actionUploadAll(pageContext,securityManager,strDestination,nameconflict,accept,mode,attributes,acl,serverPassword); 712 if(StringUtil.isEmpty(result)) { 713 Struct sct; 714 if(arr!=null && arr.size()>0) sct=(Struct) arr.getE(1); 715 else sct=new StructImpl(); 716 717 pageContext.undefinedScope().set("file",sct); 718 pageContext.undefinedScope().set("cffile",sct); 719 } 720 else { 721 pageContext.setVariable(result,arr); 722 } 723 } 724 725 726 public static Array actionUploadAll(PageContext pageContext,railo.runtime.security.SecurityManager securityManager, 727 String strDestination,int nameconflict,String accept,int mode,String attributes,Object acl,String serverPassword) throws PageException { 728 Item[] items=getFormItems(pageContext); 729 Struct sct=null; 730 Array arr=new ArrayImpl(); 731 for(int i=0;i<items.length;i++){ 732 sct = _actionUpload(pageContext,securityManager,items[i],strDestination,nameconflict,accept,mode,attributes,acl,serverPassword); 733 arr.appendEL(sct); 734 } 735 return arr; 736 } 737 738 private static synchronized Struct _actionUpload(PageContext pageContext, railo.runtime.security.SecurityManager securityManager, 739 Item formItem,String strDestination,int nameconflict,String accept,int mode,String attributes,Object acl,String serverPassword) throws PageException { 740 if(nameconflict==NAMECONFLICT_UNDEFINED) nameconflict=NAMECONFLICT_ERROR; 741 742 boolean fileWasRenamed=false; 743 boolean fileWasAppended=false; 744 boolean fileExisted=false; 745 boolean fileWasOverwritten=false; 746 747 748 String contentType=formItem.getContentType(); 749 750 // check file type 751 checkContentType(pageContext,contentType,accept); 752 753 // set cffile struct 754 Struct cffile=new StructImpl(); 755 756 long length = formItem.getResource().length(); 757 cffile.set("timecreated",new DateTimeImpl(pageContext.getConfig())); 758 cffile.set("timelastmodified",new DateTimeImpl(pageContext.getConfig())); 759 cffile.set("datelastaccessed",new DateImpl(pageContext)); 760 cffile.set("oldfilesize",Long.valueOf(length)); 761 cffile.set("filesize",Long.valueOf(length)); 762 cffile.set("contenttype",ListFirst.call(pageContext,contentType,"/")); 763 cffile.set("contentsubtype",ListLast.call(pageContext,contentType,"/")); 764 765 // client file 766 String strClientFile=formItem.getName(); 767 while(strClientFile.indexOf('\\')!=-1) 768 strClientFile=strClientFile.replace('\\','/'); 769 Resource clientFile=pageContext.getConfig().getResource(strClientFile); 770 String clientFileName=clientFile.getName(); 771 772 //String dir=clientFile.getParent(); 773 //dir=correctDirectory(dir); 774 775 cffile.set("clientdirectory",getParent(clientFile)); 776 cffile.set("clientfile",clientFile.getName()); 777 cffile.set("clientfileext",getFileExtension(clientFile)); 778 cffile.set("clientfilename",getFileName(clientFile)); 779 780 // check destination 781 if(StringUtil.isEmpty(strDestination)) 782 throw new ApplicationException("attribute destination is not defined in tag file"); 783 784 785 Resource destination=toDestination(pageContext,strDestination,null); 786 787 788 securityManager.checkFileLocation(pageContext.getConfig(),destination,serverPassword); 789 790 // destination.getCanonicalPath() 791 if(destination.isDirectory()) 792 destination=destination.getRealResource(clientFileName); 793 else if(!clientFileName.equalsIgnoreCase(destination.getName())) 794 fileWasRenamed=true; 795 796 // check parent destination -> directory of the desinatrion 797 Resource parentDestination=destination.getParentResource(); 798 799 if(!parentDestination.exists()) 800 throw new ApplicationException("attribute destination has a invalid value ["+destination+"], directory ["+parentDestination+"] doesn't exist"); 801 else if(!parentDestination.canWrite()) 802 throw new ApplicationException("can't write to destination directory ["+parentDestination+"], no access to write"); 803 804 // set server variables 805 cffile.set("serverdirectory",getParent(destination)); 806 cffile.set("serverfile",destination.getName()); 807 cffile.set("serverfileext",getFileExtension(destination)); 808 cffile.set("serverfilename",getFileName(destination)); 809 cffile.set("attemptedserverfile",destination.getName()); 810 811 812 // check nameconflict 813 if(destination.exists()) { 814 fileExisted=true; 815 if(nameconflict==NAMECONFLICT_ERROR) { 816 throw new ApplicationException("destination file ["+destination+"] already exist"); 817 } 818 else if(nameconflict==NAMECONFLICT_SKIP) { 819 cffile.set("fileexisted",Caster.toBoolean(fileExisted)); 820 cffile.set("filewasappended",Boolean.FALSE); 821 cffile.set("filewasoverwritten",Boolean.FALSE); 822 cffile.set("filewasrenamed",Boolean.FALSE); 823 cffile.set("filewassaved",Boolean.FALSE); 824 return cffile; 825 } 826 else if(nameconflict==NAMECONFLICT_MAKEUNIQUE) { 827 destination=makeUnique(destination); 828 fileWasRenamed=true; 829 830 //if(fileWasRenamed) { 831 cffile.set("serverdirectory",getParent(destination)); 832 cffile.set("serverfile",destination.getName()); 833 cffile.set("serverfileext",getFileExtension(destination)); 834 cffile.set("serverfilename",getFileName(destination)); 835 cffile.set("attemptedserverfile",destination.getName()); 836 //} 837 } 838 else if(nameconflict==NAMECONFLICT_OVERWRITE) { 839 //fileWasAppended=true; 840 fileWasOverwritten=true; 841 if(!destination.delete()) 842 if(destination.exists()) // hier hatte ich concurrent problem das damit ausgeraeumt ist 843 throw new ApplicationException("can't delete destination file ["+destination+"]"); 844 } 845 // for "overwrite" no action is neded 846 847 } 848 849 try { 850 destination.createNewFile(); 851 IOUtil.copy(formItem.getResource(),destination); 852 } 853 catch(Throwable t) { 854 throw new ApplicationException(t.getMessage()); 855 } 856 857 // Set cffile/file struct 858 859 cffile.set("fileexisted",Caster.toBoolean(fileExisted)); 860 cffile.set("filewasappended",Caster.toBoolean(fileWasAppended)); 861 cffile.set("filewasoverwritten",Caster.toBoolean(fileWasOverwritten)); 862 cffile.set("filewasrenamed",Caster.toBoolean(fileWasRenamed)); 863 cffile.set("filewassaved",Boolean.TRUE); 864 865 866 setACL(destination,acl); 867 setMode(destination,mode); 868 setAttributes(destination, attributes); 869 return cffile; 870 } 871 872 /** 873 * check if the content ii ok 874 * @param contentType 875 * @throws PageException 876 */ 877 private static void checkContentType(PageContext pageContext,String contentType,String accept) throws PageException { 878 String type=ListFirst.call(pageContext,contentType,"/").trim().toLowerCase(); 879 String subType=ListLast.call(pageContext,contentType,"/").trim().toLowerCase(); 880 881 if(accept==null || accept.trim().length()==0) return; 882 883 Array whishedTypes=List.listToArrayRemoveEmpty(accept,','); 884 int len=whishedTypes.size(); 885 for(int i=1;i<=len;i++) { 886 String whishedType=Caster.toString(whishedTypes.getE(i)).trim(); 887 String wType=ListFirst.call(pageContext,whishedType,"/").trim().toLowerCase(); 888 String wSubType=ListLast.call(pageContext,whishedType,"/").trim().toLowerCase(); 889 if((wType.equals("*") || wType.equals(type)) && (wSubType.equals("*") || wSubType.equals(subType)))return; 890 891 } 892 throw new ApplicationException("The MIME type of the uploaded file ["+contentType+"] was not accepted by the server.","only this ["+accept+"] mime type are accepted"); 893 } 894 895 /** 896 * rreturn fileItem matching to filefiled definition or throw a exception 897 * @return FileItem 898 * @throws ApplicationException 899 */ 900 private static Item getFormItem(PageContext pageContext, String filefield) throws PageException { 901 // check filefield 902 if(StringUtil.isEmpty(filefield)){ 903 Item[] items = getFormItems(pageContext); 904 if(ArrayUtil.isEmpty(items)) 905 throw new ApplicationException("no file send with this form"); 906 return items[0]; 907 } 908 909 PageException pe = pageContext.formScope().getInitException(); 910 if(pe!=null) throw pe; 911 FormUpload upload = (FormUpload)pageContext.formScope(); 912 FormImpl.Item fileItem = upload.getUploadResource(filefield); 913 if(fileItem==null) { 914 Item[] items = upload.getFileItems(); 915 StringBuilder sb=new StringBuilder(); 916 for(int i=0;i<items.length;i++){ 917 if(i!=0) sb.append(", "); 918 sb.append(items[i].getFieldName()); 919 } 920 String add="."; 921 if(sb.length()>0) add=", valid field names are ["+sb+"]."; 922 923 924 if(pageContext.formScope().get(filefield,null)==null) 925 throw new ApplicationException("form field ["+filefield+"] is not a file field"+add); 926 throw new ApplicationException("form field ["+filefield+"] doesn't exist or has no content"+add); 927 } 928 929 return fileItem; 930 } 931 932 private static Item[] getFormItems(PageContext pageContext) throws PageException { 933 PageException pe = pageContext.formScope().getInitException(); 934 if(pe!=null) throw pe; 935 936 FormUpload scope = (FormUpload) pageContext.formScope(); 937 return scope.getFileItems(); 938 } 939 940 941 /** 942 * get file extension of a file object 943 * @param file file object 944 * @return extnesion 945 */ 946 private static String getFileExtension(Resource file) { 947 String name=file.getName(); 948 String[] arr; 949 try { 950 arr = List.toStringArray(List.listToArrayRemoveEmpty(name, '.')); 951 } catch (PageException e) { 952 arr=null; 953 } 954 if(arr.length<2) return ""; 955 956 return arr[arr.length-1]; 957 } 958 959 /** 960 * get file name of a file object without extension 961 * @param file file object 962 * @return name of the file 963 */ 964 private static String getFileName(Resource file) { 965 String name=file.getName(); 966 int pos=name.lastIndexOf("."); 967 968 if(pos==-1)return name; 969 return name.substring(0,pos); 970 } 971 972 /*private String correctDirectory(Resource resource) { 973 if(StringUtil.isEmpty(resource,true)) return ""; 974 resource=resource.trim(); 975 if((StringUtil.endsWith(resource, '/') || StringUtil.endsWith(resource, '\\')) && resource.length()>1) { 976 return resource.substring(0,resource.length()-1); 977 } 978 return resource; 979 }*/ 980 981 private static String getParent(Resource res) { 982 Resource parent = res.getParentResource(); 983 //print.out("res:"+res); 984 //print.out("parent:"+parent); 985 if(parent==null) return ""; 986 return ResourceUtil.getCanonicalPathEL(parent); 987 } 988 989 990 private void checkFile(boolean create, boolean canRead, boolean canWrite) throws PageException { 991 if(file==null) 992 throw new ApplicationException("attribute file is not defined for tag file"); 993 994 securityManager.checkFileLocation(pageContext.getConfig(),file,serverPassword); 995 if(!file.exists()) { 996 if(create) { 997 Resource parent=file.getParentResource(); 998 if(parent!=null && !parent.exists()) 999 throw new ApplicationException("parent directory for ["+file+"] doesn't exists"); 1000 try { 1001 file.createFile(false); 1002 } catch (IOException e) { 1003 throw new ApplicationException("invalid file ["+file+"]",e.getMessage()); 1004 } 1005 } 1006 else if(!file.isFile()) 1007 throw new ApplicationException("source file ["+file.toString()+"] is not a file"); 1008 else 1009 throw new ApplicationException("source file ["+file.toString()+"] doesn't exist"); 1010 } 1011 else if(!file.isFile()) 1012 throw new ApplicationException("source file ["+file.toString()+"] is not a file"); 1013 else if(canRead &&!file.canRead()) 1014 throw new ApplicationException("no read access to source file ["+file.toString()+"]"); 1015 else if(canWrite && !file.canWrite()) 1016 throw new ApplicationException("no write access to source file ["+file.toString()+"]"); 1017 1018 } 1019 1020 /** 1021 * set attributes on file 1022 * @param file 1023 * @throws PageException 1024 */ 1025 private static void setAttributes(Resource file,String attributes) throws PageException { 1026 if(!SystemUtil.isWindows() || StringUtil.isEmpty(attributes)) return; 1027 try { 1028 ResourceUtil.setAttribute(file, attributes); 1029 } 1030 catch (IOException e) { 1031 throw new ApplicationException("can't change attributes of file "+file,e.getMessage()); 1032 } 1033 } 1034 1035 /** 1036 * change mode of given file 1037 * @param file 1038 * @throws ApplicationException 1039 */ 1040 private static void setMode(Resource file,int mode) throws ApplicationException { 1041 if(mode==-1 || SystemUtil.isWindows()) return; 1042 try { 1043 file.setMode(mode); 1044 //FileUtil.setMode(file,mode); 1045 } catch (IOException e) { 1046 throw new ApplicationException("can't change mode of file "+file,e.getMessage()); 1047 } 1048 } 1049 1050 /** 1051 * @param fixnewline the fixnewline to set 1052 */ 1053 public void setFixnewline(boolean fixnewline) { 1054 this.fixnewline = fixnewline; 1055 } 1056 }