KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > io > FileVFS


1 /*
2  * FileVFS.java - Local filesystem VFS
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 1998, 2005 Slava Pestov
7  * Portions copyright (C) 1998, 1999, 2000 Peter Graves
8  * Portions copyright (C) 2007 Matthieu Casanova
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  */

24
25 package org.gjt.sp.jedit.io;
26
27 //{{{ Imports
28
import javax.swing.filechooser.FileSystemView JavaDoc;
29 import javax.swing.*;
30 import java.awt.Component JavaDoc;
31 import java.io.*;
32 import java.text.*;
33 import java.util.Date JavaDoc;
34 import org.gjt.sp.jedit.*;
35 import org.gjt.sp.util.Log;
36 //}}}
37

38 /**
39  * Local filesystem VFS.
40  * @author Slava Pestov
41  * @version $Id: FileVFS.java 8590 2007-01-15 18:39:41Z kpouer $
42  */

43 public class FileVFS extends VFS
44 {
45     public static final String JavaDoc PERMISSIONS_PROPERTY = "FileVFS__perms";
46
47     //{{{ FileVFS method
48
public FileVFS()
49     {
50         super("file",READ_CAP | WRITE_CAP | DELETE_CAP
51             | RENAME_CAP | MKDIR_CAP | LOW_LATENCY_CAP
52             | ((OperatingSystem.isCaseInsensitiveFS())
53             ? CASE_INSENSITIVE_CAP : 0),
54             new String JavaDoc[] { EA_TYPE, EA_SIZE, EA_STATUS,
55             EA_MODIFIED });
56     } //}}}
57

58     //{{{ getParentOfPath() method
59
public String JavaDoc getParentOfPath(String JavaDoc path)
60     {
61         if(OperatingSystem.isDOSDerived())
62         {
63             if(path.length() == 2 && path.charAt(1) == ':')
64                 return FileRootsVFS.PROTOCOL + ':';
65             else if(path.length() == 3 && path.endsWith(":\\"))
66                 return FileRootsVFS.PROTOCOL + ':';
67             else if(path.startsWith("\\\\") && path.indexOf('\\',2) == -1)
68                 return path;
69         }
70
71         return super.getParentOfPath(path);
72     } //}}}
73

74     //{{{ constructPath() method
75
public String JavaDoc constructPath(String JavaDoc parent, String JavaDoc path)
76     {
77         if(parent.endsWith(File.separator)
78             || parent.endsWith("/"))
79             return parent + path;
80         else
81             return parent + File.separator + path;
82     } //}}}
83

84     //{{{ getFileSeparator() method
85
public char getFileSeparator()
86     {
87         return File.separatorChar;
88     } //}}}
89

90     //{{{ getTwoStageSaveName() method
91
/**
92      * Returns a temporary file name based on the given path.
93      *
94      * <p>If the directory where the file would be created cannot be
95      * written (i.e., no new files can be created in that directory),
96      * this method returns <code>null</code>.</p>
97      *
98      * @param path The path name
99      */

100     public String JavaDoc getTwoStageSaveName(String JavaDoc path)
101     {
102         File parent = new File(getParentOfPath(path));
103         return (parent.canWrite())
104             ? super.getTwoStageSaveName(path)
105             : null;
106     } //}}}
107

108     //{{{ save() method
109
public boolean save(View JavaDoc view, Buffer buffer, String JavaDoc path)
110     {
111         if(OperatingSystem.isUnix())
112         {
113             int permissions = getPermissions(buffer.getPath());
114             Log.log(Log.DEBUG,this,buffer.getPath() + " has permissions 0"
115                 + Integer.toString(permissions,8));
116             buffer.setIntegerProperty(PERMISSIONS_PROPERTY,permissions);
117         }
118
119         return super.save(view,buffer,path);
120     } //}}}
121

122     //{{{ insert() method
123
public boolean insert(View JavaDoc view, Buffer buffer, String JavaDoc path)
124     {
125         File file = new File(path);
126
127         //{{{ Check if file is valid
128
if(!file.exists())
129             return false;
130
131         if(file.isDirectory())
132         {
133             VFSManager.error(view,file.getPath(),
134                 "ioerror.open-directory",null);
135             return false;
136         }
137
138         if(!file.canRead())
139         {
140             VFSManager.error(view,file.getPath(),
141                 "ioerror.no-read",null);
142             return false;
143         } //}}}
144

145         return super.insert(view,buffer,path);
146     } //}}}
147

148     //{{{ recursiveDelete() method
149
/**
150      * #
151      * @param path the directory path to recursive delete
152      * @return true if successful, else false
153      */

154     public boolean recursiveDelete(File path) {
155         if( path.exists() ) {
156           File[] files = path.listFiles();
157           for(int i=0; i<files.length; i++) {
158              if(files[i].isDirectory()) {
159                recursiveDelete(files[i]);
160              }
161              else {
162                files[i].delete();
163              }
164           }
165         }
166         return path.delete();
167       } //}}}
168

169     //{{{ _canonPath() method
170
/**
171      * Returns the canonical form if the specified path name. For example,
172      * <code>~</code> might be expanded to the user's home directory.
173      * @param session The session
174      * @param path The path
175      * @param comp The component that will parent error dialog boxes
176      * @exception IOException if an I/O error occurred
177      * @since jEdit 4.0pre2
178      */

179     public String JavaDoc _canonPath(Object JavaDoc session, String JavaDoc path, Component JavaDoc comp)
180         throws IOException
181     {
182         return MiscUtilities.canonPath(path);
183     } //}}}
184

185     //{{{ LocalFile class
186
public static class LocalFile extends VFSFile
187     {
188         private File file;
189
190         // use system default short format
191
public static DateFormat DATE_FORMAT
192             = DateFormat.getInstance();
193
194         /**
195          * @deprecated Call getModified() instead.
196          */

197         public long modified;
198
199         public LocalFile(File file)
200         {
201             this.file = file;
202
203             /* These attributes are fetched relatively
204             quickly. The rest are lazily filled in. */

205             setName(file.getName());
206             String JavaDoc path = file.getPath();
207             setPath(path);
208             setDeletePath(path);
209             setHidden(file.isHidden());
210             setType(file.isDirectory()
211                 ? VFSFile.DIRECTORY
212                 : VFSFile.FILE);
213         }
214
215         public String JavaDoc getExtendedAttribute(String JavaDoc name)
216         {
217             if(name.equals(EA_MODIFIED))
218                 return DATE_FORMAT.format(new Date JavaDoc(modified));
219             else
220                 return super.getExtendedAttribute(name);
221         }
222         
223         protected void fetchAttrs()
224         {
225             if(fetchedAttrs())
226                 return;
227
228             super.fetchAttrs();
229
230             setSymlinkPath(MiscUtilities.resolveSymlinks(
231                 file.getPath()));
232             setReadable(file.canRead());
233             setWriteable(file.canWrite());
234             setLength(file.length());
235             setModified(file.lastModified());
236         }
237
238         /**
239          * Returns the file system icon for the file.
240          *
241          * @param expanded not used here
242          * @param openBuffer not used here
243          * @return the file system icon
244          * @since 4.3pre9
245          */

246         public Icon getIcon(boolean expanded, boolean openBuffer)
247         {
248             if (icon == null)
249             {
250                 if (fsView == null)
251                     fsView = FileSystemView.getFileSystemView();
252
253                 icon = fsView.getSystemIcon(file);
254             }
255             return icon;
256         }
257
258         public String JavaDoc getSymlinkPath()
259         {
260             fetchAttrs();
261             return super.getSymlinkPath();
262         }
263         
264         public long getLength()
265         {
266             fetchAttrs();
267             return super.getLength();
268         }
269         
270         public boolean isReadable()
271         {
272             fetchAttrs();
273             return super.isReadable();
274         }
275         
276         public boolean isWriteable()
277         {
278             fetchAttrs();
279             return super.isWriteable();
280         }
281
282         public long getModified()
283         {
284             fetchAttrs();
285             return modified;
286         }
287
288         public void setModified(long modified)
289         {
290             this.modified = modified;
291         }
292
293         private transient FileSystemView JavaDoc fsView;
294         private transient Icon icon;
295     } //}}}
296

297     //{{{ _listFiles() method
298
public VFSFile[] _listFiles(Object JavaDoc session, String JavaDoc path,
299         Component JavaDoc comp)
300     {
301         //{{{ Windows work around
302
/* On Windows, paths of the form X: list the last *working
303          * directory* on that drive. To list the root of the drive,
304          * you must use X:\.
305          *
306          * However, the VFS browser and friends strip off trailing
307          * path separators, for various reasons. So to work around
308          * that, we add a '\' to drive letter paths on Windows.
309          */

310         if(OperatingSystem.isWindows())
311         {
312             if(path.length() == 2 && path.charAt(1) == ':')
313                 path = path.concat(File.separator);
314         } //}}}
315

316         File directory = new File(path);
317         File[] list = null;
318         if(directory.exists())
319             list = fsView.getFiles(directory,false);
320
321         if(list == null)
322         {
323             VFSManager.error(comp,path,"ioerror.directory-error-nomsg",null);
324             return null;
325         }
326
327         VFSFile[] list2 = new VFSFile[list.length];
328         for(int i = 0; i < list.length; i++)
329             list2[i] = new LocalFile(list[i]);
330
331         return list2;
332     } //}}}
333

334     //{{{ _getFile() method
335
public VFSFile _getFile(Object JavaDoc session, String JavaDoc path,
336         Component JavaDoc comp)
337     {
338         if(path.equals("/") && OperatingSystem.isUnix())
339         {
340             return new VFS.DirectoryEntry(path,path,path,
341                 VFSFile.DIRECTORY,0L,false);
342         }
343
344         File file = new File(path);
345         if(!file.exists())
346             return null;
347
348         return new LocalFile(file);
349     } //}}}
350

351     //{{{ _delete() method
352
public boolean _delete(Object JavaDoc session, String JavaDoc path, Component JavaDoc comp)
353     {
354         File file = new File(path);
355         // do some platforms throw exceptions if the file does not exist
356
// when we ask for the canonical path?
357
String JavaDoc canonPath;
358         try
359         {
360             canonPath = file.getCanonicalPath();
361         }
362         catch(IOException io)
363         {
364             canonPath = path;
365         }
366         // if directory, do recursive delete
367
boolean retVal;
368         if (!file.isDirectory()) {
369             retVal = file.delete();
370         }
371         else
372         {
373             retVal = recursiveDelete(file);
374         }
375         if(retVal)
376             VFSManager.sendVFSUpdate(this,canonPath,true);
377         return retVal;
378     } //}}}
379

380     //{{{ _rename() method
381
public boolean _rename(Object JavaDoc session, String JavaDoc from, String JavaDoc to,
382         Component JavaDoc comp)
383     {
384         File _to = new File(to);
385
386         String JavaDoc toCanonPath;
387         try
388         {
389             toCanonPath = _to.getCanonicalPath();
390         }
391         catch(IOException io)
392         {
393             toCanonPath = to;
394         }
395
396         // this is needed because on OS X renaming to a non-existent
397
// directory causes problems
398
File parent = new File(_to.getParent());
399         if(parent.exists())
400         {
401             if(!parent.isDirectory())
402                 return false;
403         }
404         else
405         {
406             parent.mkdirs();
407             if(!parent.exists())
408                 return false;
409         }
410
411         File _from = new File(from);
412
413         String JavaDoc fromCanonPath;
414         try
415         {
416             fromCanonPath = _from.getCanonicalPath();
417         }
418         catch(IOException io)
419         {
420             fromCanonPath = from;
421         }
422
423         // Case-insensitive fs workaround
424
if(!fromCanonPath.equalsIgnoreCase(toCanonPath))
425             _to.delete();
426
427         boolean retVal = _from.renameTo(_to);
428         VFSManager.sendVFSUpdate(this,fromCanonPath,true);
429         VFSManager.sendVFSUpdate(this,toCanonPath,true);
430         return retVal;
431     } //}}}
432

433     //{{{ _mkdir() method
434
public boolean _mkdir(Object JavaDoc session, String JavaDoc directory, Component JavaDoc comp)
435     {
436         String JavaDoc parent = getParentOfPath(directory);
437         if(!new File(parent).exists())
438         {
439             if(!_mkdir(session,parent,comp))
440                 return false;
441         }
442
443         File file = new File(directory);
444
445         boolean retVal = file.mkdir();
446         String JavaDoc canonPath;
447         try
448         {
449             canonPath = file.getCanonicalPath();
450         }
451         catch(IOException io)
452         {
453             canonPath = directory;
454         }
455         VFSManager.sendVFSUpdate(this,canonPath,true);
456         return retVal;
457     } //}}}
458

459     //{{{ _backup() method
460
public void _backup(Object JavaDoc session, String JavaDoc path, Component JavaDoc comp)
461         throws IOException
462     {
463         // Fetch properties
464
int backups = jEdit.getIntegerProperty("backups",1);
465
466         if(backups == 0)
467             return;
468
469         String JavaDoc backupPrefix = jEdit.getProperty("backup.prefix");
470         String JavaDoc backupSuffix = jEdit.getProperty("backup.suffix");
471
472         String JavaDoc backupDirectory = jEdit.getProperty("backup.directory");
473
474         int backupTimeDistance = jEdit.getIntegerProperty("backup.minTime",0);
475         File file = new File(path);
476
477         if (!file.exists())
478             return;
479
480         // Check for backup.directory, and create that
481
// directory if it doesn't exist
482
if(backupDirectory == null || backupDirectory.length() == 0)
483             backupDirectory = file.getParent();
484         else
485         {
486             backupDirectory = MiscUtilities.constructPath(
487                 System.getProperty("user.home"),backupDirectory);
488
489             // Perhaps here we would want to guard with
490
// a property for parallel backups or not.
491
backupDirectory = MiscUtilities.concatPath(
492                 backupDirectory,file.getParent());
493
494             File dir = new File(backupDirectory);
495
496             if (!dir.exists())
497                 dir.mkdirs();
498         }
499
500         MiscUtilities.saveBackup(file,backups,backupPrefix,
501             backupSuffix,backupDirectory,backupTimeDistance);
502     } //}}}
503

504     //{{{ _createInputStream() method
505
public InputStream _createInputStream(Object JavaDoc session, String JavaDoc path,
506         boolean ignoreErrors, Component JavaDoc comp) throws IOException
507     {
508         try
509         {
510             return new FileInputStream(path);
511         }
512         catch(IOException io)
513         {
514             if(ignoreErrors)
515                 return null;
516             else
517                 throw io;
518         }
519     } //}}}
520

521     //{{{ _createOutputStream() method
522
public OutputStream _createOutputStream(Object JavaDoc session, String JavaDoc path,
523         Component JavaDoc comp) throws IOException
524     {
525         return new FileOutputStream(path);
526     } //}}}
527

528     //{{{ _saveComplete() method
529
public void _saveComplete(Object JavaDoc session, Buffer buffer, String JavaDoc path,
530         Component JavaDoc comp)
531     {
532         int permissions = buffer.getIntegerProperty(PERMISSIONS_PROPERTY,0);
533         setPermissions(path,permissions);
534     } //}}}
535

536     //{{{ Permission preservation code
537

538     /** Code borrowed from j text editor (http://www.armedbear.org) */
539     /** I made some changes to make it support suid, sgid and sticky files */
540
541     //{{{ getPermissions() method
542
/**
543      * Returns numeric permissions of a file. On non-Unix systems, always
544      * returns zero.
545      * @since jEdit 3.2pre9
546      */

547     public static int getPermissions(String JavaDoc path)
548     {
549         int permissions = 0;
550
551         if(jEdit.getBooleanProperty("chmodDisabled"))
552             return permissions;
553
554         if(OperatingSystem.isUnix())
555         {
556             String JavaDoc[] cmdarray = { "ls", "-ld", path };
557
558             try
559             {
560                 Process JavaDoc process = Runtime.getRuntime().exec(cmdarray);
561
562                 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
563
564                 String JavaDoc output = reader.readLine();
565
566                 if(output != null)
567                 {
568                     String JavaDoc s = output.substring(1, 10);
569
570                     permissions = MiscUtilities
571                         .parsePermissions(s);
572                 }
573             }
574
575             // Feb 4 2000 5:30 PM
576
// Catch Throwable here rather than Exception.
577
// Kaffe's implementation of Runtime.exec throws java.lang.InternalError.
578
catch (Throwable JavaDoc t)
579             {
580             }
581         }
582
583         return permissions;
584     } //}}}
585

586     //{{{ setPermissions() method
587
/**
588      * Sets numeric permissions of a file. On non-Unix platforms,
589      * does nothing.
590      * @since jEdit 3.2pre9
591      */

592     public static void setPermissions(String JavaDoc path, int permissions)
593     {
594         if(jEdit.getBooleanProperty("chmodDisabled"))
595             return;
596
597         if(permissions != 0)
598         {
599             if(OperatingSystem.isUnix())
600             {
601                 String JavaDoc[] cmdarray = { "chmod", Integer.toString(permissions, 8), path };
602
603                 try
604                 {
605                     Process JavaDoc process = Runtime.getRuntime().exec(cmdarray);
606                     process.getInputStream().close();
607                     process.getOutputStream().close();
608                     process.getErrorStream().close();
609                     // Jun 9 2004 12:40 PM
610
// waitFor() hangs on some Java
611
// implementations.
612
/* int exitCode = process.waitFor();
613                     if(exitCode != 0)
614                         Log.log(Log.NOTICE,FileVFS.class,"chmod exited with code " + exitCode); */

615                 }
616
617                 // Feb 4 2000 5:30 PM
618
// Catch Throwable here rather than Exception.
619
// Kaffe's implementation of Runtime.exec throws java.lang.InternalError.
620
catch (Throwable JavaDoc t)
621                 {
622                 }
623             }
624         }
625     } //}}}
626

627     //}}}
628

629     //{{{ Private members
630
private static FileSystemView JavaDoc fsView = FileSystemView.getFileSystemView();
631     //}}}
632
}
633
Popular Tags