diff options
Diffstat (limited to 'plugins/org.yocto.bc.ui/src/org/yocto/bc/ui/filesystem/OEFile.java')
-rw-r--r-- | plugins/org.yocto.bc.ui/src/org/yocto/bc/ui/filesystem/OEFile.java | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/plugins/org.yocto.bc.ui/src/org/yocto/bc/ui/filesystem/OEFile.java b/plugins/org.yocto.bc.ui/src/org/yocto/bc/ui/filesystem/OEFile.java new file mode 100644 index 0000000..85794f1 --- /dev/null +++ b/plugins/org.yocto.bc.ui/src/org/yocto/bc/ui/filesystem/OEFile.java | |||
@@ -0,0 +1,515 @@ | |||
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 | * Ken Gilmer - adaptation from internal class. | ||
11 | *******************************************************************************/ | ||
12 | package org.yocto.bc.ui.filesystem; | ||
13 | |||
14 | import java.io.File; | ||
15 | import java.io.FileInputStream; | ||
16 | import java.io.FileNotFoundException; | ||
17 | import java.io.FileOutputStream; | ||
18 | import java.io.IOException; | ||
19 | import java.io.InputStream; | ||
20 | import java.io.OutputStream; | ||
21 | import java.net.URI; | ||
22 | import java.util.List; | ||
23 | |||
24 | import org.eclipse.core.filesystem.EFS; | ||
25 | import org.eclipse.core.filesystem.IFileInfo; | ||
26 | import org.eclipse.core.filesystem.IFileStore; | ||
27 | import org.eclipse.core.filesystem.IFileSystem; | ||
28 | import org.eclipse.core.filesystem.URIUtil; | ||
29 | import org.eclipse.core.filesystem.provider.FileInfo; | ||
30 | import org.eclipse.core.filesystem.provider.FileStore; | ||
31 | import org.eclipse.core.runtime.CoreException; | ||
32 | import org.eclipse.core.runtime.IPath; | ||
33 | import org.eclipse.core.runtime.IProgressMonitor; | ||
34 | import org.eclipse.core.runtime.IStatus; | ||
35 | import org.eclipse.core.runtime.MultiStatus; | ||
36 | import org.eclipse.core.runtime.NullProgressMonitor; | ||
37 | import org.eclipse.core.runtime.Status; | ||
38 | import org.eclipse.osgi.util.NLS; | ||
39 | import org.yocto.bc.bitbake.BBSession; | ||
40 | import org.yocto.bc.bitbake.ProjectInfoHelper; | ||
41 | import org.yocto.bc.bitbake.ShellSession; | ||
42 | |||
43 | /** | ||
44 | * File system implementation based on storage of files in the local | ||
45 | * operating system's file system. | ||
46 | */ | ||
47 | public class OEFile extends FileStore { | ||
48 | private static int attributes(File aFile) { | ||
49 | if (!aFile.exists() || aFile.canWrite()) | ||
50 | return EFS.NONE; | ||
51 | return EFS.ATTRIBUTE_READ_ONLY; | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * The java.io.File that this store represents. | ||
56 | */ | ||
57 | protected final File file; | ||
58 | private List ignorePaths; | ||
59 | |||
60 | /** | ||
61 | * The absolute file system path of the file represented by this store. | ||
62 | */ | ||
63 | protected final String filePath; | ||
64 | |||
65 | private final String root; | ||
66 | |||
67 | /** | ||
68 | * Creates a new local file. | ||
69 | * | ||
70 | * @param file The file this local file represents | ||
71 | * @param root | ||
72 | */ | ||
73 | public OEFile(File file, List ignorePaths, String root) { | ||
74 | this.file = file; | ||
75 | this.ignorePaths = ignorePaths; | ||
76 | this.root = root; | ||
77 | this.filePath = file.getAbsolutePath(); | ||
78 | } | ||
79 | |||
80 | /** | ||
81 | * This method is called after a failure to modify a file or directory. | ||
82 | * Check to see if the parent is read-only and if so then | ||
83 | * throw an exception with a more specific message and error code. | ||
84 | * | ||
85 | * @param target The file that we failed to modify | ||
86 | * @param exception The low level exception that occurred, or <code>null</code> | ||
87 | * @throws CoreException A more specific exception if the parent is read-only | ||
88 | */ | ||
89 | private void checkReadOnlyParent(File target, Throwable exception) throws CoreException { | ||
90 | File parent = target.getParentFile(); | ||
91 | if (parent != null && (attributes(parent) & EFS.ATTRIBUTE_READ_ONLY) != 0) { | ||
92 | String message = NLS.bind(Messages.readOnlyParent, target.getAbsolutePath()); | ||
93 | Policy.error(EFS.ERROR_PARENT_READ_ONLY, message, exception); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | @Override | ||
98 | public String[] childNames(int options, IProgressMonitor monitor) { | ||
99 | String[] names = file.list(); | ||
100 | return (names == null ? EMPTY_STRING_ARRAY : names); | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * detect if the path is potential builddir | ||
105 | */ | ||
106 | private boolean isPotentialBuildDir(String path) { | ||
107 | boolean ret = true; | ||
108 | for (int i=0; i < BBSession.BUILDDIR_INDICATORS.length && ret == true; i++) { | ||
109 | if((new File(path + BBSession.BUILDDIR_INDICATORS[i])).exists() == false) { | ||
110 | ret=false; | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * try to find items for ignoreList | ||
119 | */ | ||
120 | private void updateIgnorePaths(String path, List list) { | ||
121 | if(isPotentialBuildDir(path)) { | ||
122 | BBSession config = null; | ||
123 | try { | ||
124 | ShellSession shell = new ShellSession(ShellSession.SHELL_TYPE_BASH, new File(root), | ||
125 | ProjectInfoHelper.getInitScriptPath(root) + " " + path, null); | ||
126 | config = new BBSession(shell, root, true); | ||
127 | config.initialize(); | ||
128 | } catch(Exception e) { | ||
129 | e.printStackTrace(); | ||
130 | return; | ||
131 | } | ||
132 | if (config.get("TMPDIR") == null || config.get("DL_DIR") == null || config.get("SSTATE_DIR") == null) { | ||
133 | //wrong guess about the buildDir | ||
134 | return; | ||
135 | }else { | ||
136 | if(!list.contains(config.get("TMPDIR"))) { | ||
137 | list.add(config.get("TMPDIR")); | ||
138 | } | ||
139 | if(!list.contains(config.get("DL_DIR"))) { | ||
140 | list.add(config.get("DL_DIR")); | ||
141 | } | ||
142 | if(!list.contains(config.get("SSTATE_DIR"))) { | ||
143 | list.add(config.get("SSTATE_DIR")); | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | @Override | ||
150 | public IFileStore[] childStores(int options, IProgressMonitor monitor) throws CoreException { | ||
151 | String[] children = childNames(options, monitor); | ||
152 | IFileStore[] wrapped = new IFileStore[children.length]; | ||
153 | |||
154 | for (int i = 0; i < wrapped.length; i++) { | ||
155 | String fullPath = file.toString() +File.separatorChar + children[i]; | ||
156 | |||
157 | updateIgnorePaths(fullPath, ignorePaths); | ||
158 | if (ignorePaths.contains(fullPath)) { | ||
159 | wrapped[i] = getDeadChild(children[i]); | ||
160 | } else { | ||
161 | wrapped[i] = getChild(children[i]); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | return wrapped; | ||
166 | } | ||
167 | |||
168 | @Override | ||
169 | public void copy(IFileStore destFile, int options, IProgressMonitor monitor) throws CoreException { | ||
170 | if (destFile instanceof OEFile) { | ||
171 | File source = file; | ||
172 | File destination = ((OEFile) destFile).file; | ||
173 | //handle case variants on a case-insensitive OS, or copying between | ||
174 | //two equivalent files in an environment that supports symbolic links. | ||
175 | //in these nothing needs to be copied (and doing so would likely lose data) | ||
176 | try { | ||
177 | if (source.getCanonicalFile().equals(destination.getCanonicalFile())) { | ||
178 | //nothing to do | ||
179 | return; | ||
180 | } | ||
181 | } catch (IOException e) { | ||
182 | String message = NLS.bind(Messages.couldNotRead, source.getAbsolutePath()); | ||
183 | Policy.error(EFS.ERROR_READ, message, e); | ||
184 | } | ||
185 | } | ||
186 | //fall through to super implementation | ||
187 | super.copy(destFile, options, monitor); | ||
188 | } | ||
189 | |||
190 | @Override | ||
191 | public void delete(int options, IProgressMonitor monitor) throws CoreException { | ||
192 | if (monitor == null) | ||
193 | monitor = new NullProgressMonitor(); | ||
194 | else | ||
195 | monitor = new NullProgressMonitor(); | ||
196 | try { | ||
197 | monitor.beginTask(NLS.bind(Messages.deleting, this), 200); | ||
198 | String message = Messages.deleteProblem; | ||
199 | MultiStatus result = new MultiStatus(Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, null); | ||
200 | |||
201 | //don't allow Eclipse to delete entire OE directory | ||
202 | |||
203 | if (!isProject()) { | ||
204 | internalDelete(file, filePath, result, monitor); | ||
205 | } | ||
206 | |||
207 | if (!result.isOK()) | ||
208 | throw new CoreException(result); | ||
209 | } finally { | ||
210 | monitor.done(); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | @Override | ||
215 | public boolean equals(Object obj) { | ||
216 | if (!(obj instanceof OEFile)) | ||
217 | return false; | ||
218 | |||
219 | OEFile otherFile = (OEFile) obj; | ||
220 | |||
221 | return file.equals(otherFile.file); | ||
222 | } | ||
223 | |||
224 | @Override | ||
225 | public IFileInfo fetchInfo(int options, IProgressMonitor monitor) { | ||
226 | //in-lined non-native implementation | ||
227 | FileInfo info = new FileInfo(file.getName()); | ||
228 | final long lastModified = file.lastModified(); | ||
229 | if (lastModified <= 0) { | ||
230 | //if the file doesn't exist, all other attributes should be default values | ||
231 | info.setExists(false); | ||
232 | return info; | ||
233 | } | ||
234 | info.setLastModified(lastModified); | ||
235 | info.setExists(true); | ||
236 | info.setLength(file.length()); | ||
237 | info.setDirectory(file.isDirectory()); | ||
238 | info.setAttribute(EFS.ATTRIBUTE_READ_ONLY, file.exists() && !file.canWrite()); | ||
239 | info.setAttribute(EFS.ATTRIBUTE_HIDDEN, file.isHidden()); | ||
240 | return info; | ||
241 | } | ||
242 | |||
243 | @Override | ||
244 | public IFileStore getChild(IPath path) { | ||
245 | return new OEFile(new File(file, path.toOSString()), ignorePaths, root); | ||
246 | } | ||
247 | |||
248 | @Override | ||
249 | public IFileStore getChild(String name) { | ||
250 | return new OEFile(new File(file, name), ignorePaths, root); | ||
251 | } | ||
252 | |||
253 | private IFileStore getDeadChild(String name) { | ||
254 | return new OEIgnoreFile(new File(file, name)); | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * (non-Javadoc) | ||
259 | * @see org.eclipse.core.filesystem.IFileStore#getFileSystem() | ||
260 | */ | ||
261 | @Override | ||
262 | public IFileSystem getFileSystem() { | ||
263 | return OEFileSystem.getInstance(); | ||
264 | } | ||
265 | |||
266 | @Override | ||
267 | public String getName() { | ||
268 | return file.getName(); | ||
269 | } | ||
270 | |||
271 | @Override | ||
272 | public IFileStore getParent() { | ||
273 | File parent = file.getParentFile(); | ||
274 | return parent == null ? null : new OEFile(parent, ignorePaths, root); | ||
275 | } | ||
276 | |||
277 | @Override | ||
278 | public int hashCode() { | ||
279 | return file.hashCode(); | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * Deletes the given file recursively, adding failure info to | ||
284 | * the provided status object. The filePath is passed as a parameter | ||
285 | * to optimize java.io.File object creation. | ||
286 | */ | ||
287 | private boolean internalDelete(File target, String pathToDelete, MultiStatus status, IProgressMonitor monitor) { | ||
288 | //first try to delete - this should succeed for files and symbolic links to directories | ||
289 | if (target.delete() || !target.exists()) | ||
290 | return true; | ||
291 | if (target.isDirectory()) { | ||
292 | monitor.subTask(NLS.bind(Messages.deleting, target)); | ||
293 | String[] list = target.list(); | ||
294 | if (list == null) | ||
295 | list = EMPTY_STRING_ARRAY; | ||
296 | int parentLength = pathToDelete.length(); | ||
297 | boolean failedRecursive = false; | ||
298 | for (int i = 0, imax = list.length; i < imax; i++) { | ||
299 | //optimized creation of child path object | ||
300 | StringBuffer childBuffer = new StringBuffer(parentLength + list[i].length() + 1); | ||
301 | childBuffer.append(pathToDelete); | ||
302 | childBuffer.append(File.separatorChar); | ||
303 | childBuffer.append(list[i]); | ||
304 | String childName = childBuffer.toString(); | ||
305 | // try best effort on all children so put logical OR at end | ||
306 | failedRecursive = !internalDelete(new java.io.File(childName), childName, status, monitor) || failedRecursive; | ||
307 | monitor.worked(1); | ||
308 | } | ||
309 | try { | ||
310 | // don't try to delete the root if one of the children failed | ||
311 | if (!failedRecursive && target.delete()) | ||
312 | return true; | ||
313 | } catch (Exception e) { | ||
314 | // we caught a runtime exception so log it | ||
315 | String message = NLS.bind(Messages.couldnotDelete, target.getAbsolutePath()); | ||
316 | status.add(new Status(IStatus.ERROR, Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, e)); | ||
317 | return false; | ||
318 | } | ||
319 | } | ||
320 | //if we got this far, we failed | ||
321 | String message = null; | ||
322 | if (fetchInfo().getAttribute(EFS.ATTRIBUTE_READ_ONLY)) | ||
323 | message = NLS.bind(Messages.couldnotDeleteReadOnly, target.getAbsolutePath()); | ||
324 | else | ||
325 | message = NLS.bind(Messages.couldnotDelete, target.getAbsolutePath()); | ||
326 | status.add(new Status(IStatus.ERROR, Policy.PI_FILE_SYSTEM, EFS.ERROR_DELETE, message, null)); | ||
327 | return false; | ||
328 | } | ||
329 | |||
330 | @Override | ||
331 | public boolean isParentOf(IFileStore other) { | ||
332 | if (!(other instanceof OEFile)) | ||
333 | return false; | ||
334 | String thisPath = filePath; | ||
335 | String thatPath = ((OEFile) other).filePath; | ||
336 | int thisLength = thisPath.length(); | ||
337 | int thatLength = thatPath.length(); | ||
338 | //if equal then not a parent | ||
339 | if (thisLength >= thatLength) | ||
340 | return false; | ||
341 | if (getFileSystem().isCaseSensitive()) { | ||
342 | if (thatPath.indexOf(thisPath) != 0) | ||
343 | return false; | ||
344 | } else { | ||
345 | if (thatPath.toLowerCase().indexOf(thisPath.toLowerCase()) != 0) | ||
346 | return false; | ||
347 | } | ||
348 | //The common portion must end with a separator character for this to be a parent of that | ||
349 | return thisPath.charAt(thisLength - 1) == File.separatorChar || thatPath.charAt(thisLength) == File.separatorChar; | ||
350 | } | ||
351 | |||
352 | /** | ||
353 | * @return | ||
354 | */ | ||
355 | private boolean isProject() { | ||
356 | return this.file.toString().equals(root); | ||
357 | } | ||
358 | |||
359 | @Override | ||
360 | public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException { | ||
361 | boolean shallow = (options & EFS.SHALLOW) != 0; | ||
362 | //must be a directory | ||
363 | if (shallow) | ||
364 | file.mkdir(); | ||
365 | else | ||
366 | file.mkdirs(); | ||
367 | if (!file.isDirectory()) { | ||
368 | checkReadOnlyParent(file, null); | ||
369 | String message = NLS.bind(Messages.failedCreateWrongType, filePath); | ||
370 | Policy.error(EFS.ERROR_WRONG_TYPE, message); | ||
371 | } | ||
372 | return this; | ||
373 | } | ||
374 | |||
375 | @Override | ||
376 | public void move(IFileStore destFile, int options, IProgressMonitor monitor) throws CoreException { | ||
377 | if (!(destFile instanceof OEFile)) { | ||
378 | super.move(destFile, options, monitor); | ||
379 | return; | ||
380 | } | ||
381 | File source = file; | ||
382 | File destination = ((OEFile) destFile).file; | ||
383 | boolean overwrite = (options & EFS.OVERWRITE) != 0; | ||
384 | monitor = Policy.monitorFor(monitor); | ||
385 | try { | ||
386 | monitor.beginTask(NLS.bind(Messages.moving, source.getAbsolutePath()), 10); | ||
387 | //this flag captures case renaming on a case-insensitive OS, or moving | ||
388 | //two equivalent files in an environment that supports symbolic links. | ||
389 | //in these cases we NEVER want to delete anything | ||
390 | boolean sourceEqualsDest = false; | ||
391 | try { | ||
392 | sourceEqualsDest = source.getCanonicalFile().equals(destination.getCanonicalFile()); | ||
393 | } catch (IOException e) { | ||
394 | String message = NLS.bind(Messages.couldNotMove, source.getAbsolutePath()); | ||
395 | Policy.error(EFS.ERROR_WRITE, message, e); | ||
396 | } | ||
397 | if (!sourceEqualsDest && !overwrite && destination.exists()) { | ||
398 | String message = NLS.bind(Messages.fileExists, destination.getAbsolutePath()); | ||
399 | Policy.error(EFS.ERROR_EXISTS, message); | ||
400 | } | ||
401 | if (source.renameTo(destination)) { | ||
402 | // double-check to ensure we really did move | ||
403 | // since java.io.File#renameTo sometimes lies | ||
404 | if (!sourceEqualsDest && source.exists()) { | ||
405 | // XXX: document when this occurs | ||
406 | if (destination.exists()) { | ||
407 | // couldn't delete the source so remove the destination and throw an error | ||
408 | // XXX: if we fail deleting the destination, the destination (root) may still exist | ||
409 | new OEFile(destination, ignorePaths, root).delete(EFS.NONE, null); | ||
410 | String message = NLS.bind(Messages.couldnotDelete, source.getAbsolutePath()); | ||
411 | Policy.error(EFS.ERROR_DELETE, message); | ||
412 | } | ||
413 | // source exists but destination doesn't so try to copy below | ||
414 | } else { | ||
415 | if (!destination.exists()) { | ||
416 | // neither the source nor the destination exist. this is REALLY bad | ||
417 | String message = NLS.bind(Messages.failedMove, source.getAbsolutePath(), destination.getAbsolutePath()); | ||
418 | Policy.error(EFS.ERROR_WRITE, message); | ||
419 | } | ||
420 | //the move was successful | ||
421 | monitor.worked(10); | ||
422 | return; | ||
423 | } | ||
424 | } | ||
425 | // for some reason renameTo didn't work | ||
426 | if (sourceEqualsDest) { | ||
427 | String message = NLS.bind(Messages.couldNotMove, source.getAbsolutePath()); | ||
428 | Policy.error(EFS.ERROR_WRITE, message, null); | ||
429 | } | ||
430 | // fall back to default implementation | ||
431 | super.move(destFile, options, Policy.subMonitorFor(monitor, 10)); | ||
432 | } finally { | ||
433 | monitor.done(); | ||
434 | } | ||
435 | } | ||
436 | |||
437 | @Override | ||
438 | public InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException { | ||
439 | monitor = Policy.monitorFor(monitor); | ||
440 | try { | ||
441 | monitor.beginTask("", 1); //$NON-NLS-1$ | ||
442 | return new FileInputStream(file); | ||
443 | } catch (FileNotFoundException e) { | ||
444 | String message; | ||
445 | if (!file.exists()) | ||
446 | message = NLS.bind(Messages.fileNotFound, filePath); | ||
447 | else if (file.isDirectory()) | ||
448 | message = NLS.bind(Messages.notAFile, filePath); | ||
449 | else | ||
450 | message = NLS.bind(Messages.couldNotRead, filePath); | ||
451 | Policy.error(EFS.ERROR_READ, message, e); | ||
452 | return null; | ||
453 | } finally { | ||
454 | monitor.done(); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | @Override | ||
459 | public OutputStream openOutputStream(int options, IProgressMonitor monitor) throws CoreException { | ||
460 | monitor = Policy.monitorFor(monitor); | ||
461 | try { | ||
462 | monitor.beginTask("", 1); //$NON-NLS-1$ | ||
463 | return new FileOutputStream(file, (options & EFS.APPEND) != 0); | ||
464 | } catch (FileNotFoundException e) { | ||
465 | checkReadOnlyParent(file, e); | ||
466 | String message; | ||
467 | String path = filePath; | ||
468 | if (file.isDirectory()) | ||
469 | message = NLS.bind(Messages.notAFile, path); | ||
470 | else | ||
471 | message = NLS.bind(Messages.couldNotWrite, path); | ||
472 | Policy.error(EFS.ERROR_WRITE, message, e); | ||
473 | return null; | ||
474 | } finally { | ||
475 | monitor.done(); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | @Override | ||
480 | public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) throws CoreException { | ||
481 | boolean success = true; | ||
482 | |||
483 | //native does not currently set last modified | ||
484 | if ((options & EFS.SET_LAST_MODIFIED) != 0) | ||
485 | success &= file.setLastModified(info.getLastModified()); | ||
486 | if (!success && !file.exists()) | ||
487 | Policy.error(EFS.ERROR_NOT_EXISTS, NLS.bind(Messages.fileNotFound, filePath)); | ||
488 | } | ||
489 | |||
490 | /* (non-Javadoc) | ||
491 | * @see org.eclipse.core.filesystem.provider.FileStore#toLocalFile(int, org.eclipse.core.runtime.IProgressMonitor) | ||
492 | */ | ||
493 | @Override | ||
494 | public File toLocalFile(int options, IProgressMonitor monitor) throws CoreException { | ||
495 | if (options == EFS.CACHE) | ||
496 | return super.toLocalFile(options, monitor); | ||
497 | return file; | ||
498 | } | ||
499 | |||
500 | /* (non-Javadoc) | ||
501 | * @see org.eclipse.core.filesystem.IFileStore#toString() | ||
502 | */ | ||
503 | @Override | ||
504 | public String toString() { | ||
505 | return file.toString(); | ||
506 | } | ||
507 | |||
508 | /* (non-Javadoc) | ||
509 | * @see org.eclipse.core.filesystem.IFileStore#toURI() | ||
510 | */ | ||
511 | @Override | ||
512 | public URI toURI() { | ||
513 | return URIUtil.toURI(filePath); | ||
514 | } | ||
515 | } | ||