KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > filesystem > local > LocalFile


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.filesystem.local;
12
13 import java.io.*;
14 import java.net.URI JavaDoc;
15 import org.eclipse.core.filesystem.*;
16 import org.eclipse.core.filesystem.provider.FileInfo;
17 import org.eclipse.core.filesystem.provider.FileStore;
18 import org.eclipse.core.internal.filesystem.Messages;
19 import org.eclipse.core.internal.filesystem.Policy;
20 import org.eclipse.core.runtime.*;
21 import org.eclipse.osgi.util.NLS;
22
23 /**
24  * File system implementation based on storage of files in the local
25  * operating system's file system.
26  */

27 public class LocalFile extends FileStore {
28     /**
29      * The java.io.File that this store represents.
30      */

31     protected final File file;
32     /**
33      * The absolute file system path of the file represented by this store.
34      */

35     protected final String JavaDoc filePath;
36
37     private static int attributes(File aFile) {
38         if (!aFile.exists() || aFile.canWrite())
39             return EFS.NONE;
40         return EFS.ATTRIBUTE_READ_ONLY;
41     }
42
43     /**
44      * Creates a new local file.
45      *
46      * @param file The file this local file represents
47      */

48     public LocalFile(File file) {
49         this.file = file;
50         this.filePath = file.getAbsolutePath();
51     }
52
53     /**
54      * This method is called after a failure to modify a file or directory.
55      * Check to see if the parent is read-only and if so then
56      * throw an exception with a more specific message and error code.
57      *
58      * @param target The file that we failed to modify
59      * @param exception The low level exception that occurred, or <code>null</code>
60      * @throws CoreException A more specific exception if the parent is read-only
61      */

62     private void checkReadOnlyParent(File target, Throwable JavaDoc exception) throws CoreException {
63         File parent = target.getParentFile();
64         if (parent != null && (attributes(parent) & EFS.ATTRIBUTE_READ_ONLY) != 0) {
65             String JavaDoc message = NLS.bind(Messages.readOnlyParent, target.getAbsolutePath());
66             Policy.error(EFS.ERROR_PARENT_READ_ONLY, message, exception);
67         }
68     }
69
70     public String JavaDoc[] childNames(int options, IProgressMonitor monitor) {
71         String JavaDoc[] names = file.list();
72         return (names == null ? EMPTY_STRING_ARRAY : names);
73     }
74
75     public void copy(IFileStore destFile, int options, IProgressMonitor monitor) throws CoreException {
76         if (destFile instanceof LocalFile) {
77             File source = file;
78             File destination = ((LocalFile) destFile).file;
79             //handle case variants on a case-insensitive OS, or copying between
80
//two equivalent files in an environment that supports symbolic links.
81
//in these nothing needs to be copied (and doing so would likely lose data)
82
try {
83                 if (source.getCanonicalFile().equals(destination.getCanonicalFile())) {
84                     //nothing to do
85
return;
86                 }
87             } catch (IOException e) {
88                 String JavaDoc message = NLS.bind(Messages.couldNotRead, source.getAbsolutePath());
89                 Policy.error(EFS.ERROR_READ, message, e);
90             }
91         }
92         //fall through to super implementation
93
super.copy(destFile, options, monitor);
94     }
95
96     public void delete(int options, IProgressMonitor monitor) throws CoreException {
97         if (monitor == null)
98             monitor = new NullProgressMonitor();
99         else
100             monitor = new InfiniteProgress(monitor);
101         try {
102             monitor.beginTask(NLS.bind(Messages.deleting, this), 200);
103             String JavaDoc message = Messages.deleteProblem;
104             MultiStatus result = new MultiStatus(Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, null);
105             internalDelete(file, filePath, result, monitor);
106             if (!result.isOK())
107                 throw new CoreException(result);
108         } finally {
109             monitor.done();
110         }
111     }
112
113     public boolean equals(Object JavaDoc obj) {
114         if (!(obj instanceof LocalFile))
115             return false;
116         //Mac oddity: file.equals returns false when case is different even when
117
//file system is not case sensitive (Radar bug 3190672)
118
LocalFile otherFile = (LocalFile) obj;
119         if (LocalFileSystem.MACOSX)
120             return filePath.toLowerCase().equals(otherFile.filePath.toLowerCase());
121         return file.equals(otherFile.file);
122     }
123
124     public IFileInfo fetchInfo(int options, IProgressMonitor monitor) {
125         if (LocalFileNatives.usingNatives()) {
126             FileInfo info = LocalFileNatives.fetchFileInfo(filePath);
127             //natives don't set the file name on all platforms
128
if (info.getName().length() == 0)
129                 info.setName(file.getName());
130             return info;
131         }
132         //in-lined non-native implementation
133
FileInfo info = new FileInfo(file.getName());
134         final long lastModified = file.lastModified();
135         if (lastModified <= 0) {
136             //if the file doesn't exist, all other attributes should be default values
137
info.setExists(false);
138             return info;
139         }
140         info.setLastModified(lastModified);
141         info.setExists(true);
142         info.setLength(file.length());
143         info.setDirectory(file.isDirectory());
144         info.setAttribute(EFS.ATTRIBUTE_READ_ONLY, file.exists() && !file.canWrite());
145         info.setAttribute(EFS.ATTRIBUTE_HIDDEN, file.isHidden());
146         return info;
147     }
148
149     public IFileStore getChild(IPath path) {
150         return new LocalFile(new File(file, path.toOSString()));
151     }
152
153     public IFileStore getChild(String JavaDoc name) {
154         return new LocalFile(new File(file, name));
155     }
156
157     /*
158      * (non-Javadoc)
159      * @see org.eclipse.core.filesystem.IFileStore#getFileSystem()
160      */

161     public IFileSystem getFileSystem() {
162         return LocalFileSystem.getInstance();
163     }
164
165     public String JavaDoc getName() {
166         return file.getName();
167     }
168
169     public IFileStore getParent() {
170         File parent = file.getParentFile();
171         return parent == null ? null : new LocalFile(parent);
172     }
173
174     public int hashCode() {
175         return file.hashCode();
176     }
177
178     /**
179      * Deletes the given file recursively, adding failure info to
180      * the provided status object. The filePath is passed as a parameter
181      * to optimize java.io.File object creation.
182      */

183     private boolean internalDelete(File target, String JavaDoc pathToDelete, MultiStatus status, IProgressMonitor monitor) {
184         //first try to delete - this should succeed for files and symbolic links to directories
185
if (target.delete() || !target.exists())
186             return true;
187         if (target.isDirectory()) {
188             monitor.subTask(NLS.bind(Messages.deleting, target));
189             String JavaDoc[] list = target.list();
190             if (list == null)
191                 list = EMPTY_STRING_ARRAY;
192             int parentLength = pathToDelete.length();
193             boolean failedRecursive = false;
194             for (int i = 0, imax = list.length; i < imax; i++) {
195                 //optimized creation of child path object
196
StringBuffer JavaDoc childBuffer = new StringBuffer JavaDoc(parentLength + list[i].length() + 1);
197                 childBuffer.append(pathToDelete);
198                 childBuffer.append(File.separatorChar);
199                 childBuffer.append(list[i]);
200                 String JavaDoc childName = childBuffer.toString();
201                 // try best effort on all children so put logical OR at end
202
failedRecursive = !internalDelete(new java.io.File JavaDoc(childName), childName, status, monitor) || failedRecursive;
203                 monitor.worked(1);
204             }
205             try {
206                 // don't try to delete the root if one of the children failed
207
if (!failedRecursive && target.delete())
208                     return true;
209             } catch (Exception JavaDoc e) {
210                 // we caught a runtime exception so log it
211
String JavaDoc message = NLS.bind(Messages.couldnotDelete, target.getAbsolutePath());
212                 status.add(new Status(IStatus.ERROR, Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, e));
213                 return false;
214             }
215         }
216         //if we got this far, we failed
217
String JavaDoc message = null;
218         if (fetchInfo().getAttribute(EFS.ATTRIBUTE_READ_ONLY))
219             message = NLS.bind(Messages.couldnotDeleteReadOnly, target.getAbsolutePath());
220         else
221             message = NLS.bind(Messages.couldnotDelete, target.getAbsolutePath());
222         status.add(new Status(IStatus.ERROR, Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, null));
223         return false;
224     }
225
226     public boolean isParentOf(IFileStore other) {
227         if (!(other instanceof LocalFile))
228             return false;
229         String JavaDoc thisPath = filePath;
230         String JavaDoc thatPath = ((LocalFile) other).filePath;
231         int thisLength = thisPath.length();
232         int thatLength = thatPath.length();
233         //if equal then not a parent
234
if (thisLength >= thatLength)
235             return false;
236         if (getFileSystem().isCaseSensitive()) {
237             if (thatPath.indexOf(thisPath) != 0)
238                 return false;
239         } else {
240             if (thatPath.toLowerCase().indexOf(thisPath.toLowerCase()) != 0)
241                 return false;
242         }
243         //The common portion must end with a separator character for this to be a parent of that
244
return thisPath.charAt(thisLength - 1) == File.separatorChar || thatPath.charAt(thisLength) == File.separatorChar;
245     }
246
247     public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException {
248         boolean shallow = (options & EFS.SHALLOW) != 0;
249         //must be a directory
250
if (shallow)
251             file.mkdir();
252         else
253             file.mkdirs();
254         if (!file.isDirectory()) {
255             checkReadOnlyParent(file, null);
256             String JavaDoc message = NLS.bind(Messages.failedCreateWrongType, filePath);
257             Policy.error(EFS.ERROR_WRONG_TYPE, message);
258         }
259         return this;
260     }
261
262     public void move(IFileStore destFile, int options, IProgressMonitor monitor) throws CoreException {
263         if (!(destFile instanceof LocalFile)) {
264             super.move(destFile, options, monitor);
265             return;
266         }
267         File source = file;
268         File destination = ((LocalFile) destFile).file;
269         boolean overwrite = (options & EFS.OVERWRITE) != 0;
270         monitor = Policy.monitorFor(monitor);
271         try {
272             monitor.beginTask(NLS.bind(Messages.moving, source.getAbsolutePath()), 10);
273             //this flag captures case renaming on a case-insensitive OS, or moving
274
//two equivalent files in an environment that supports symbolic links.
275
//in these cases we NEVER want to delete anything
276
boolean sourceEqualsDest = false;
277             try {
278                 sourceEqualsDest = source.getCanonicalFile().equals(destination.getCanonicalFile());
279             } catch (IOException e) {
280                 String JavaDoc message = NLS.bind(Messages.couldNotMove, source.getAbsolutePath());
281                 Policy.error(EFS.ERROR_WRITE, message, e);
282             }
283             if (!sourceEqualsDest && !overwrite && destination.exists()) {
284                 String JavaDoc message = NLS.bind(Messages.fileExists, destination.getAbsolutePath());
285                 Policy.error(EFS.ERROR_EXISTS, message);
286             }
287             if (source.renameTo(destination)) {
288                 // double-check to ensure we really did move
289
// since java.io.File#renameTo sometimes lies
290
if (!sourceEqualsDest && source.exists()) {
291                     // XXX: document when this occurs
292
if (destination.exists()) {
293                         // couldn't delete the source so remove the destination and throw an error
294
// XXX: if we fail deleting the destination, the destination (root) may still exist
295
new LocalFile(destination).delete(EFS.NONE, null);
296                         String JavaDoc message = NLS.bind(Messages.couldnotDelete, source.getAbsolutePath());
297                         Policy.error(EFS.ERROR_DELETE, message);
298                     }
299                     // source exists but destination doesn't so try to copy below
300
} else {
301                     if (!destination.exists()) {
302                         // neither the source nor the destination exist. this is REALLY bad
303
String JavaDoc message = NLS.bind(Messages.failedMove, source.getAbsolutePath(), destination.getAbsolutePath());
304                         Policy.error(EFS.ERROR_WRITE, message);
305                     }
306                     //the move was successful
307
monitor.worked(10);
308                     return;
309                 }
310             }
311             // for some reason renameTo didn't work
312
if (sourceEqualsDest) {
313                 String JavaDoc message = NLS.bind(Messages.couldNotMove, source.getAbsolutePath());
314                 Policy.error(EFS.ERROR_WRITE, message, null);
315             }
316             // fall back to default implementation
317
super.move(destFile, options, Policy.subMonitorFor(monitor, 10));
318         } finally {
319             monitor.done();
320         }
321     }
322
323     public InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException {
324         monitor = Policy.monitorFor(monitor);
325         try {
326             monitor.beginTask("", 1); //$NON-NLS-1$
327
return new FileInputStream(file);
328         } catch (FileNotFoundException e) {
329             String JavaDoc message;
330             if (!file.exists())
331                 message = NLS.bind(Messages.fileNotFound, filePath);
332             else if (file.isDirectory())
333                 message = NLS.bind(Messages.notAFile, filePath);
334             else
335                 message = NLS.bind(Messages.couldNotRead, filePath);
336             Policy.error(EFS.ERROR_READ, message, e);
337             return null;
338         } finally {
339             monitor.done();
340         }
341     }
342
343     public OutputStream openOutputStream(int options, IProgressMonitor monitor) throws CoreException {
344         monitor = Policy.monitorFor(monitor);
345         try {
346             monitor.beginTask("", 1); //$NON-NLS-1$
347
return new FileOutputStream(file, (options & EFS.APPEND) != 0);
348         } catch (FileNotFoundException e) {
349             checkReadOnlyParent(file, e);
350             String JavaDoc message;
351             String JavaDoc path = filePath;
352             if (file.isDirectory())
353                 message = NLS.bind(Messages.notAFile, path);
354             else
355                 message = NLS.bind(Messages.couldNotWrite, path);
356             Policy.error(EFS.ERROR_WRITE, message, e);
357             return null;
358         } finally {
359             monitor.done();
360         }
361     }
362
363     public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) throws CoreException {
364         boolean success = true;
365         if ((options & EFS.SET_ATTRIBUTES) != 0) {
366             if (LocalFileNatives.usingNatives())
367                 success &= LocalFileNatives.setFileInfo(filePath, info, options);
368         }
369         //native does not currently set last modified
370
if ((options & EFS.SET_LAST_MODIFIED) != 0)
371             success &= file.setLastModified(info.getLastModified());
372         if (!success && !file.exists())
373             Policy.error(EFS.ERROR_NOT_EXISTS, NLS.bind(Messages.fileNotFound, filePath));
374     }
375
376     /* (non-Javadoc)
377      * @see org.eclipse.core.filesystem.provider.FileStore#toLocalFile(int, org.eclipse.core.runtime.IProgressMonitor)
378      */

379     public File toLocalFile(int options, IProgressMonitor monitor) throws CoreException {
380         if (options == EFS.CACHE)
381             return super.toLocalFile(options, monitor);
382         return file;
383     }
384
385     /* (non-Javadoc)
386      * @see org.eclipse.core.filesystem.IFileStore#toString()
387      */

388     public String JavaDoc toString() {
389         return file.toString();
390     }
391
392     /* (non-Javadoc)
393      * @see org.eclipse.core.filesystem.IFileStore#toURI()
394      */

395     public URI JavaDoc toURI() {
396         return URIUtil.toURI(filePath);
397     }
398 }
399
Popular Tags