KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > localstore > FileSystemStore


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 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.localstore;
12
13 import java.io.*;
14 import java.io.File JavaDoc;
15 import org.eclipse.core.internal.resources.*;
16 import org.eclipse.core.internal.utils.Messages;
17 import org.eclipse.core.internal.utils.Policy;
18 import org.eclipse.core.resources.*;
19 import org.eclipse.core.runtime.*;
20 import org.eclipse.osgi.util.NLS;
21
22 public class FileSystemStore implements ILocalStoreConstants {
23     /**
24      * Singleton buffer created to prevent buffer creations in the
25      * transferStreams method. Used as an optimization, based on the assumption
26      * that multiple writes won't happen in a given instance of FileSystemStore.
27      */

28     private final byte[] buffer = new byte[8192];
29
30     public FileSystemStore() {
31         super();
32     }
33
34     public void copy(File JavaDoc source, File JavaDoc destination, int depth, IProgressMonitor monitor) throws CoreException {
35         monitor = Policy.monitorFor(monitor);
36         try {
37             monitor.beginTask(NLS.bind(Messages.localstore_copying, source.getAbsolutePath()), 1);
38             Policy.checkCanceled(monitor);
39             if (source.isDirectory())
40                 copyDirectory(source, destination, depth, Policy.subMonitorFor(monitor, 1));
41             else
42                 copyFile(source, destination, Policy.subMonitorFor(monitor, 1));
43         } finally {
44             monitor.done();
45         }
46     }
47
48     protected void copyDirectory(File JavaDoc source, File JavaDoc destination, int depth, IProgressMonitor monitor) throws CoreException {
49         monitor = Policy.monitorFor(monitor);
50         try {
51             String JavaDoc[] children = source.list();
52             if (children == null) {
53                 children = new String JavaDoc[0];
54             }
55
56             monitor.beginTask(NLS.bind(Messages.localstore_copying, source.getAbsolutePath()), children.length);
57             // create directory
58
writeFolder(destination);
59
60             // depth
61
if (depth == IResource.DEPTH_ZERO)
62                 return;
63             if (depth == IResource.DEPTH_ONE)
64                 depth = IResource.DEPTH_ZERO;
65
66             // copy children
67
for (int i = 0; i < children.length; i++)
68                 copy(new File JavaDoc(source, children[i]), new File JavaDoc(destination, children[i]), depth, Policy.subMonitorFor(monitor, 1));
69         } finally {
70             monitor.done();
71         }
72     }
73
74     protected void copyFile(File JavaDoc target, File JavaDoc destination, IProgressMonitor monitor) throws CoreException {
75         monitor = Policy.monitorFor(monitor);
76         try {
77             int totalWork = 1 + ((int) target.length() / 8192);
78             monitor.beginTask(NLS.bind(Messages.localstore_copying, target.getAbsolutePath()), totalWork);
79             try {
80                 write(destination, read(target), false, monitor);
81             } catch (CoreException e) {
82                 //if we failed to write, try to cleanup the half written file
83
if (!destination.isDirectory())
84                     destination.delete();
85                 throw e;
86             }
87             // update the destination timestamp on disk
88
long stat = CoreFileSystemLibrary.getStat(target.getAbsolutePath());
89             long lastModified = CoreFileSystemLibrary.getLastModified(stat);
90             destination.setLastModified(lastModified);
91             // update file attributes
92
CoreFileSystemLibrary.copyAttributes(target.getAbsolutePath(), destination.getAbsolutePath(), false);
93         } finally {
94             monitor.done();
95         }
96     }
97
98     /**
99      * Returns an output stream on the given file. The user of the
100      * returned stream is responsible for closing the stream when finished.
101      */

102     protected OutputStream createStream(File JavaDoc target, boolean append) throws CoreException {
103         String JavaDoc path = target.getAbsolutePath();
104         try {
105             return new FileOutputStream(path, append);
106         } catch (FileNotFoundException e) {
107             String JavaDoc message;
108             int code = IResourceStatus.FAILED_WRITE_LOCAL;
109             // Check to see if the parent is a read-only folder and if so then
110
// throw an exception with a more specific message and error code.
111
String JavaDoc parent = target.getParent();
112             if (parent != null && CoreFileSystemLibrary.isReadOnly(parent)) {
113                 message = NLS.bind(Messages.localstore_readOnlyParent, path);
114                 code = IResourceStatus.PARENT_READ_ONLY;
115             } else if (target.isDirectory())
116                 message = NLS.bind(Messages.localstore_notAFile, path);
117             else
118                 message = NLS.bind(Messages.localstore_couldNotWrite, path);
119             throw new ResourceException(code, new Path(path), message, e);
120         }
121     }
122
123     public void delete(File JavaDoc target) throws CoreException {
124         if (!Workspace.clear(target)) {
125             String JavaDoc message = NLS.bind(Messages.localstore_couldnotDelete, target.getAbsolutePath());
126             throw new ResourceException(IResourceStatus.FAILED_DELETE_LOCAL, new Path(target.getAbsolutePath()), message, null);
127         }
128     }
129
130     /**
131      * Deletes the given file recursively, adding failure info to
132      * the provided status object.
133      */

134     public boolean delete(File JavaDoc root, MultiStatus status) {
135         return delete(root, root.getAbsolutePath(), status);
136     }
137
138     /**
139      * Deletes the given file recursively, adding failure info to
140      * the provided status object. The filePath is passed as a parameter
141      * to optimize java.io.File object creation.
142      */

143     protected boolean delete(File JavaDoc root, String JavaDoc filePath, MultiStatus status) {
144         boolean failedRecursive = false;
145         if (root.isDirectory()) {
146             String JavaDoc[] list = root.list();
147             if (list != null) {
148                 int parentLength = filePath.length();
149                 for (int i = 0, imax = list.length; i < imax; i++) {
150                     //optimized creation of child path object
151
StringBuffer JavaDoc childBuffer = new StringBuffer JavaDoc(parentLength + list[i].length() + 1);
152                     childBuffer.append(filePath);
153                     childBuffer.append(File.separatorChar);
154                     childBuffer.append(list[i]);
155                     String JavaDoc childName = childBuffer.toString();
156                     // try best effort on all children so put logical OR at end
157
failedRecursive = !delete(new java.io.File JavaDoc(childName), childName, status) || failedRecursive;
158                 }
159             }
160         }
161         boolean failedThis = false;
162         try {
163             // don't try to delete the root if one of the children failed
164
if (!failedRecursive && root.exists())
165                 failedThis = !root.delete();
166         } catch (Exception JavaDoc e) {
167             // we caught a runtime exception so log it
168
String JavaDoc message = NLS.bind(Messages.localstore_couldnotDelete, root.getAbsolutePath());
169             status.add(new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, new Path(root.getAbsolutePath()), message, e));
170             return false;
171         }
172         if (failedThis) {
173             String JavaDoc message = null;
174             if (CoreFileSystemLibrary.isReadOnly(root.getAbsolutePath()))
175                 message = NLS.bind(Messages.localstore_couldnotDeleteReadOnly, root.getAbsolutePath());
176             else
177                 message = NLS.bind(Messages.localstore_couldnotDelete, root.getAbsolutePath());
178             status.add(new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, new Path(root.getAbsolutePath()), message, null));
179         }
180         return !(failedRecursive || failedThis);
181     }
182
183     /**
184      * @deprecated
185      */

186     public int getEncoding(File JavaDoc target) throws CoreException {
187         InputStream input = null;
188         try {
189             input = read(target);
190             int first = input.read();
191             int second = input.read();
192             if (first == -1 || second == -1)
193                 return IFile.ENCODING_UNKNOWN;
194             first &= 0xFF;//converts unsigned byte to int
195
second &= 0xFF;
196             //look for the UTF-16 Byte Order Mark (BOM)
197
if (first == 0xFE && second == 0xFF)
198                 return IFile.ENCODING_UTF_16BE;
199             if (first == 0xFF && second == 0xFE)
200                 return IFile.ENCODING_UTF_16LE;
201             int third = (input.read() & 0xFF);
202             if (third == -1)
203                 return IFile.ENCODING_UNKNOWN;
204             //look for the UTF-8 BOM
205
if (first == 0xEF && second == 0xBB && third == 0xBF)
206                 return IFile.ENCODING_UTF_8;
207             return IFile.ENCODING_UNKNOWN;
208         } catch (IOException e) {
209             String JavaDoc message = NLS.bind(Messages.localstore_couldNotRead, target.getAbsolutePath());
210             throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, new Path(target.getAbsolutePath()), message, e);
211         } finally {
212             if (input != null) {
213                 try {
214                     input.close();
215                 } catch (IOException e) {
216                     //ignore exceptions on close
217
}
218             }
219         }
220     }
221
222     public void move(File JavaDoc source, File JavaDoc destination, boolean force, IProgressMonitor monitor) throws CoreException {
223         monitor = Policy.monitorFor(monitor);
224         try {
225             monitor.beginTask(NLS.bind(Messages.localstore_moving, source.getAbsolutePath()), 2);
226             //this flag captures case renaming on a case-insensitive OS, or moving
227
//two equivalent files in an environment that supports symbolic links.
228
//in these cases we NEVER want to delete anything
229
boolean sourceEqualsDest = false;
230             try {
231                 sourceEqualsDest = source.getCanonicalFile().equals(destination.getCanonicalFile());
232             } catch (IOException e) {
233                 String JavaDoc message = NLS.bind(Messages.localstore_couldNotMove, source.getAbsolutePath());
234                 throw new ResourceException(new ResourceStatus(IResourceStatus.FAILED_WRITE_LOCAL, new Path(source.getAbsolutePath()), message, e));
235             }
236             if (!sourceEqualsDest && !force && destination.exists()) {
237                 String JavaDoc message = NLS.bind(Messages.localstore_resourceExists, destination.getAbsolutePath());
238                 throw new ResourceException(IResourceStatus.EXISTS_LOCAL, new Path(destination.getAbsolutePath()), message, null);
239             }
240             if (source.renameTo(destination)) {
241                 // double-check to ensure we really did move
242
// since java.io.File#renameTo sometimes lies
243
if (!sourceEqualsDest && source.exists()) {
244                     // XXX: document when this occurs
245
if (destination.exists()) {
246                         // couldn't delete the source so remove the destination
247
// and throw an error
248
// XXX: if we fail deleting the destination, the destination (root) may still exist
249
Workspace.clear(destination);
250                         String JavaDoc message = NLS.bind(Messages.localstore_couldnotDelete, source.getAbsolutePath());
251                         throw new ResourceException(new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, new Path(source.getAbsolutePath()), message, null));
252                     } else {
253                         // source exists but destination doesn't so try to copy below
254
}
255                 } else {
256                     if (destination.exists()) {
257                         // success case
258
return;
259                     } else {
260                         // neither the source nor the destination exist. this is REALLY bad
261
String JavaDoc message = NLS.bind(Messages.localstore_failedMove, source.getAbsolutePath(), destination.getAbsolutePath());
262                         throw new ResourceException(new ResourceStatus(IResourceStatus.FAILED_WRITE_LOCAL, new Path(source.getAbsolutePath()), message, null));
263                     }
264                 }
265             }
266             // for some reason we couldn't move - workaround: copy and delete the source
267
// but if just case-renaming on a case-insensitive FS, there is no workaround
268
if (sourceEqualsDest) {
269                 String JavaDoc message = NLS.bind(Messages.localstore_couldNotMove, source.getAbsolutePath());
270                 throw new ResourceException(new ResourceStatus(IResourceStatus.FAILED_WRITE_LOCAL, new Path(source.getAbsolutePath()), message, null));
271             }
272             boolean success = false;
273             boolean canceled = false;
274             try {
275                 copy(source, destination, IResource.DEPTH_INFINITE, Policy.subMonitorFor(monitor, 1));
276                 success = true;
277             } catch (OperationCanceledException e) {
278                 canceled = true;
279                 throw e;
280             } finally {
281                 if (success) {
282                     // fail if source cannot be successfully deleted
283
String JavaDoc message = Messages.localstore_deleteProblemDuringMove;
284                     MultiStatus result = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.FAILED_DELETE_LOCAL, message, null);
285                     if (!delete(source, result))
286                         throw new ResourceException(result);
287                 } else {
288                     if (!canceled) {
289                         // We do not want to delete the destination in case of failure. It might
290
// the case where we already had contents in the destination, so we would
291
// be deleting resources we don't know about and the user might lose data.
292
String JavaDoc message = NLS.bind(Messages.localstore_couldNotMove, source.getAbsolutePath());
293                         throw new ResourceException(new ResourceStatus(IResourceStatus.FAILED_WRITE_LOCAL, new Path(source.getAbsolutePath()), message, null));
294                     }
295                 }
296             }
297             monitor.worked(1);
298         } finally {
299             monitor.done();
300         }
301     }
302
303     /**
304      * Returns an input stream containing the contents of the given
305      * file as maintained by this store. The user of the returned
306      * stream is responsible for closing the stream when finished.
307      *
308      * @exception CoreException if the content of
309      * the resource cannot be accessed.
310      */

311     public InputStream read(File JavaDoc target) throws CoreException {
312         try {
313             return new FileInputStream(target);
314         } catch (FileNotFoundException e) {
315             String JavaDoc message;
316             if (!target.exists())
317                 message = NLS.bind(Messages.localstore_fileNotFound, target.getAbsolutePath());
318             else if (target.isDirectory())
319                 message = NLS.bind(Messages.localstore_notAFile, target.getAbsolutePath());
320             else
321                 message = NLS.bind(Messages.localstore_couldNotRead, target.getAbsolutePath());
322             throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, new Path(target.getAbsolutePath()), message, e);
323         }
324     }
325
326     /**
327      * Transfers all available bytes from the given input stream to the given output stream.
328      * Regardless of failure, this method closes both streams.
329      * @param path The path of the object being copied, may be null
330      */

331     public void transferStreams(InputStream source, OutputStream destination, String JavaDoc path, IProgressMonitor monitor) throws CoreException {
332         monitor = Policy.monitorFor(monitor);
333         try {
334             /*
335              * Note: although synchronizing on the buffer is thread-safe,
336              * it may result in slower performance in the future if we want
337              * to allow concurrent writes.
338              */

339             synchronized (buffer) {
340                 while (true) {
341                     int bytesRead = -1;
342                     try {
343                         bytesRead = source.read(buffer);
344                     } catch (IOException e) {
345                         String JavaDoc msg = NLS.bind(Messages.localstore_failedReadDuringWrite, path);
346                         IPath p = path == null ? null : new Path(path);
347                         throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, p, msg, e);
348                     }
349                     if (bytesRead == -1)
350                         break;
351                     try {
352                         destination.write(buffer, 0, bytesRead);
353                     } catch (IOException e) {
354                         String JavaDoc msg = NLS.bind(Messages.localstore_couldNotWrite, path);
355                         IPath p = path == null ? null : new Path(path);
356                         throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, p, msg, e);
357                     }
358                     monitor.worked(1);
359                 }
360             }
361         } finally {
362             try {
363                 source.close();
364             } catch (IOException e) {
365                 // ignore
366
} finally {
367                 //close destination in finally in case source.close fails
368
try {
369                     destination.close();
370                 } catch (IOException e) {
371                     // ignore
372
}
373             }
374         }
375     }
376
377     /**
378      * Content cannot be null and it is closed even if the operation is not
379      * completed successfully. It is assumed that the caller has ensured
380      * the destination is not read-only.
381      */

382     public void write(File JavaDoc target, InputStream content, boolean append, IProgressMonitor monitor) throws CoreException {
383         try {
384             String JavaDoc path = target.getAbsolutePath();
385             writeFolder(target.getParentFile());
386             transferStreams(content, createStream(target, append), path, monitor);
387         } finally {
388             try {
389                 content.close();
390             } catch (IOException e) {
391                 // ignore
392
}
393         }
394     }
395
396     public void writeFolder(File JavaDoc target) throws CoreException {
397         if (!target.exists())
398             target.mkdirs();
399         if (!target.isDirectory()) {
400             String JavaDoc path = target.getAbsolutePath();
401             int code = IResourceStatus.FAILED_WRITE_LOCAL;
402             String JavaDoc message = NLS.bind(Messages.localstore_couldNotCreateFolder, path);
403             // Check to see if the parent is a read-only folder and if so then
404
// throw an exception with a more specific message and error code.
405
String JavaDoc parent = target.getParent();
406             if (parent != null && CoreFileSystemLibrary.isReadOnly(parent)) {
407                 message = NLS.bind(Messages.localstore_readOnlyParent, path);
408                 code = IResourceStatus.PARENT_READ_ONLY;
409             }
410             throw new ResourceException(code, new Path(path), message, null);
411         }
412     }
413
414 }
415
Popular Tags