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    }