PageRenderTime 93ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/io/FileVFS.java

#
Java | 487 lines | 320 code | 69 blank | 98 comment | 55 complexity | ac935b1130321eaeb58599a9a1cf2ddb MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * FileVFS.java - Local filesystem VFS
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1998, 1999, 2000, 2001, 2002 Slava Pestov
  7. * Portions copyright (C) 1998, 1999, 2000 Peter Graves
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. package org.gjt.sp.jedit.io;
  24. //{{{ Imports
  25. import java.awt.Component;
  26. import java.io.*;
  27. import java.text.*;
  28. import java.util.Date;
  29. import org.gjt.sp.jedit.*;
  30. import org.gjt.sp.util.Log;
  31. //}}}
  32. /**
  33. * Local filesystem VFS.
  34. * @author Slava Pestov
  35. * @version $Id: FileVFS.java 4986 2004-03-06 22:56:08Z spestov $
  36. */
  37. public class FileVFS extends VFS
  38. {
  39. public static final String PERMISSIONS_PROPERTY = "FileVFS__perms";
  40. //{{{ FileVFS method
  41. public FileVFS()
  42. {
  43. super("file",READ_CAP | WRITE_CAP | DELETE_CAP
  44. | RENAME_CAP | MKDIR_CAP | LOW_LATENCY_CAP
  45. | ((OperatingSystem.isMacOS()
  46. || OperatingSystem.isDOSDerived())
  47. ? CASE_INSENSITIVE_CAP : 0),
  48. new String[] { EA_TYPE, EA_SIZE, EA_STATUS,
  49. EA_MODIFIED });
  50. } //}}}
  51. //{{{ getParentOfPath() method
  52. public String getParentOfPath(String path)
  53. {
  54. if(OperatingSystem.isDOSDerived())
  55. {
  56. if(path.length() == 2 && path.charAt(1) == ':')
  57. return FileRootsVFS.PROTOCOL + ":";
  58. else if(path.length() == 3 && path.endsWith(":\\"))
  59. return FileRootsVFS.PROTOCOL + ":";
  60. else if(path.startsWith("\\\\") && path.indexOf('\\',2) == -1)
  61. return path;
  62. }
  63. return super.getParentOfPath(path);
  64. } //}}}
  65. //{{{ constructPath() method
  66. public String constructPath(String parent, String path)
  67. {
  68. if(parent.endsWith(File.separator)
  69. || parent.endsWith("/"))
  70. return parent + path;
  71. else
  72. return parent + File.separator + path;
  73. } //}}}
  74. //{{{ getFileSeparator() method
  75. public char getFileSeparator()
  76. {
  77. return File.separatorChar;
  78. } //}}}
  79. //{{{ save() method
  80. public boolean save(View view, Buffer buffer, String path)
  81. {
  82. if(OperatingSystem.isUnix())
  83. {
  84. int permissions = getPermissions(buffer.getPath());
  85. Log.log(Log.DEBUG,this,buffer.getPath() + " has permissions 0"
  86. + Integer.toString(permissions,8));
  87. buffer.setIntegerProperty(PERMISSIONS_PROPERTY,permissions);
  88. }
  89. return super.save(view,buffer,path);
  90. } //}}}
  91. //{{{ insert() method
  92. public boolean insert(View view, Buffer buffer, String path)
  93. {
  94. File file = new File(path);
  95. //{{{ Check if file is valid
  96. if(!file.exists())
  97. return false;
  98. if(file.isDirectory())
  99. {
  100. VFSManager.error(view,file.getPath(),
  101. "ioerror.open-directory",null);
  102. return false;
  103. }
  104. if(!file.canRead())
  105. {
  106. VFSManager.error(view,file.getPath(),
  107. "ioerror.no-read",null);
  108. return false;
  109. } //}}}
  110. return super.insert(view,buffer,path);
  111. } //}}}
  112. //{{{ _canonPath() method
  113. /**
  114. * Returns the canonical form if the specified path name. For example,
  115. * <code>~</code> might be expanded to the user's home directory.
  116. * @param session The session
  117. * @param path The path
  118. * @param comp The component that will parent error dialog boxes
  119. * @exception IOException if an I/O error occurred
  120. * @since jEdit 4.0pre2
  121. */
  122. public String _canonPath(Object session, String path, Component comp)
  123. throws IOException
  124. {
  125. return MiscUtilities.canonPath(path);
  126. } //}}}
  127. //{{{ LocalDirectoryEntry class
  128. public static class LocalDirectoryEntry extends VFS.DirectoryEntry
  129. {
  130. // use system default short format
  131. public static DateFormat DATE_FORMAT
  132. = DateFormat.getInstance();
  133. public long modified;
  134. public LocalDirectoryEntry(File file)
  135. {
  136. super(file.getName(),file.getPath(),
  137. file.getPath(),file.isDirectory() ? DIRECTORY : FILE,file.length(),file.isHidden());
  138. this.modified = file.lastModified();
  139. this.canRead = file.canRead();
  140. this.canWrite = file.canWrite();
  141. this.symlinkPath = MiscUtilities.resolveSymlinks(path);
  142. }
  143. public String getExtendedAttribute(String name)
  144. {
  145. if(name.equals(EA_MODIFIED))
  146. return DATE_FORMAT.format(new Date(modified));
  147. else
  148. return super.getExtendedAttribute(name);
  149. }
  150. } //}}}
  151. //{{{ _listDirectory() method
  152. public VFS.DirectoryEntry[] _listDirectory(Object session, String path,
  153. Component comp)
  154. {
  155. //{{{ Windows work around
  156. /* On Windows, paths of the form X: list the last *working
  157. * directory* on that drive. To list the root of the drive,
  158. * you must use X:\.
  159. *
  160. * However, the VFS browser and friends strip off trailing
  161. * path separators, for various reasons. So to work around
  162. * that, we add a '\' to drive letter paths on Windows.
  163. */
  164. if(OperatingSystem.isWindows())
  165. {
  166. if(path.length() == 2 && path.charAt(1) == ':')
  167. path = path.concat(File.separator);
  168. } //}}}
  169. File directory = new File(path);
  170. File[] list = directory.listFiles();
  171. if(list == null)
  172. {
  173. VFSManager.error(comp,path,"ioerror.directory-error-nomsg",null);
  174. return null;
  175. }
  176. VFS.DirectoryEntry[] list2 = new VFS.DirectoryEntry[list.length];
  177. for(int i = 0; i < list.length; i++)
  178. list2[i] = new LocalDirectoryEntry(list[i]);
  179. return list2;
  180. } //}}}
  181. //{{{ _getDirectoryEntry() method
  182. public DirectoryEntry _getDirectoryEntry(Object session, String path,
  183. Component comp)
  184. {
  185. if(path.equals("/") && OperatingSystem.isUnix())
  186. {
  187. return new VFS.DirectoryEntry(path,path,path,
  188. VFS.DirectoryEntry.DIRECTORY,0L,false);
  189. }
  190. File file = new File(path);
  191. if(!file.exists())
  192. return null;
  193. return new LocalDirectoryEntry(file);
  194. } //}}}
  195. //{{{ _delete() method
  196. public boolean _delete(Object session, String path, Component comp)
  197. {
  198. File file = new File(path);
  199. // do some platforms throw exceptions if the file does not exist
  200. // when we ask for the canonical path?
  201. String canonPath;
  202. try
  203. {
  204. canonPath = file.getCanonicalPath();
  205. }
  206. catch(IOException io)
  207. {
  208. canonPath = path;
  209. }
  210. boolean retVal = file.delete();
  211. if(retVal)
  212. VFSManager.sendVFSUpdate(this,canonPath,true);
  213. return retVal;
  214. } //}}}
  215. //{{{ _rename() method
  216. public boolean _rename(Object session, String from, String to,
  217. Component comp)
  218. {
  219. File _to = new File(to);
  220. String toCanonPath;
  221. try
  222. {
  223. toCanonPath = _to.getCanonicalPath();
  224. }
  225. catch(IOException io)
  226. {
  227. toCanonPath = to;
  228. }
  229. // this is needed because on OS X renaming to a non-existent
  230. // directory causes problems
  231. File parent = new File(_to.getParent());
  232. if(parent.exists())
  233. {
  234. if(!parent.isDirectory())
  235. return false;
  236. }
  237. else
  238. {
  239. parent.mkdirs();
  240. if(!parent.exists())
  241. return false;
  242. }
  243. File _from = new File(from);
  244. String fromCanonPath;
  245. try
  246. {
  247. fromCanonPath = _from.getCanonicalPath();
  248. }
  249. catch(IOException io)
  250. {
  251. fromCanonPath = from;
  252. }
  253. // Case-insensitive fs workaround
  254. if(!fromCanonPath.equalsIgnoreCase(toCanonPath))
  255. _to.delete();
  256. boolean retVal = _from.renameTo(_to);
  257. VFSManager.sendVFSUpdate(this,fromCanonPath,true);
  258. VFSManager.sendVFSUpdate(this,toCanonPath,true);
  259. return retVal;
  260. } //}}}
  261. //{{{ _mkdir() method
  262. public boolean _mkdir(Object session, String directory, Component comp)
  263. {
  264. String parent = getParentOfPath(directory);
  265. if(!new File(parent).exists())
  266. {
  267. if(!_mkdir(session,parent,comp))
  268. return false;
  269. }
  270. File file = new File(directory);
  271. boolean retVal = file.mkdir();
  272. String canonPath;
  273. try
  274. {
  275. canonPath = file.getCanonicalPath();
  276. }
  277. catch(IOException io)
  278. {
  279. canonPath = directory;
  280. }
  281. VFSManager.sendVFSUpdate(this,canonPath,true);
  282. return retVal;
  283. } //}}}
  284. //{{{ _backup() method
  285. public void _backup(Object session, String path, Component comp)
  286. throws IOException
  287. {
  288. // Fetch properties
  289. int backups = jEdit.getIntegerProperty("backups",1);
  290. if(backups == 0)
  291. return;
  292. String backupPrefix = jEdit.getProperty("backup.prefix");
  293. String backupSuffix = jEdit.getProperty("backup.suffix");
  294. String backupDirectory = jEdit.getProperty("backup.directory");
  295. int backupTimeDistance = jEdit.getIntegerProperty("backup.minTime",0);
  296. File file = new File(path);
  297. // Check for backup.directory, and create that
  298. // directory if it doesn't exist
  299. if(backupDirectory == null || backupDirectory.length() == 0)
  300. backupDirectory = file.getParent();
  301. else
  302. {
  303. backupDirectory = MiscUtilities.constructPath(
  304. System.getProperty("user.home"),backupDirectory);
  305. // Perhaps here we would want to guard with
  306. // a property for parallel backups or not.
  307. backupDirectory = MiscUtilities.concatPath(
  308. backupDirectory,file.getParent());
  309. File dir = new File(backupDirectory);
  310. if (!dir.exists())
  311. dir.mkdirs();
  312. }
  313. MiscUtilities.saveBackup(file,backups,backupPrefix,
  314. backupSuffix,backupDirectory,backupTimeDistance);
  315. } //}}}
  316. //{{{ _createInputStream() method
  317. public InputStream _createInputStream(Object session, String path,
  318. boolean ignoreErrors, Component comp) throws IOException
  319. {
  320. try
  321. {
  322. return new FileInputStream(path);
  323. }
  324. catch(IOException io)
  325. {
  326. if(ignoreErrors)
  327. return null;
  328. else
  329. throw io;
  330. }
  331. } //}}}
  332. //{{{ _createOutputStream() method
  333. public OutputStream _createOutputStream(Object session, String path,
  334. Component comp) throws IOException
  335. {
  336. return new FileOutputStream(path);
  337. } //}}}
  338. //{{{ _saveComplete() method
  339. public void _saveComplete(Object session, Buffer buffer, String path,
  340. Component comp)
  341. {
  342. int permissions = buffer.getIntegerProperty(PERMISSIONS_PROPERTY,0);
  343. setPermissions(path,permissions);
  344. } //}}}
  345. //{{{ Permission preservation code
  346. /** Code borrowed from j text editor (http://www.armedbear.org) */
  347. /** I made some changes to make it support suid, sgid and sticky files */
  348. //{{{ getPermissions() method
  349. /**
  350. * Returns numeric permissions of a file. On non-Unix systems, always
  351. * returns zero.
  352. * @since jEdit 3.2pre9
  353. */
  354. public static int getPermissions(String path)
  355. {
  356. int permissions = 0;
  357. if(jEdit.getBooleanProperty("chmodDisabled"))
  358. return permissions;
  359. if(OperatingSystem.isUnix())
  360. {
  361. String[] cmdarray = { "ls", "-ld", path };
  362. try
  363. {
  364. Process process = Runtime.getRuntime().exec(cmdarray);
  365. BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
  366. String output = reader.readLine();
  367. if(output != null)
  368. {
  369. String s = output.substring(1, 10);
  370. permissions = MiscUtilities
  371. .parsePermissions(s);
  372. }
  373. }
  374. // Feb 4 2000 5:30 PM
  375. // Catch Throwable here rather than Exception.
  376. // Kaffe's implementation of Runtime.exec throws java.lang.InternalError.
  377. catch (Throwable t)
  378. {
  379. }
  380. }
  381. return permissions;
  382. } //}}}
  383. //{{{ setPermissions() method
  384. /**
  385. * Sets numeric permissions of a file. On non-Unix platforms,
  386. * does nothing.
  387. * @since jEdit 3.2pre9
  388. */
  389. public static void setPermissions(String path, int permissions)
  390. {
  391. if(jEdit.getBooleanProperty("chmodDisabled"))
  392. return;
  393. if(permissions != 0)
  394. {
  395. if(OperatingSystem.isUnix())
  396. {
  397. String[] cmdarray = { "chmod", Integer.toString(permissions, 8), path };
  398. try
  399. {
  400. Process process = Runtime.getRuntime().exec(cmdarray);
  401. process.getInputStream().close();
  402. process.getOutputStream().close();
  403. process.getErrorStream().close();
  404. int exitCode = process.waitFor();
  405. if(exitCode != 0)
  406. Log.log(Log.NOTICE,FileVFS.class,"chmod exited with code " + exitCode);
  407. }
  408. // Feb 4 2000 5:30 PM
  409. // Catch Throwable here rather than Exception.
  410. // Kaffe's implementation of Runtime.exec throws java.lang.InternalError.
  411. catch (Throwable t)
  412. {
  413. }
  414. }
  415. }
  416. } //}}}
  417. //}}}
  418. }