summaryrefslogtreecommitdiffstats
path: root/plugins/org.yocto.bc.ui/src/org/yocto/bc/ui/filesystem/OEFile.java
diff options
context:
space:
mode:
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.java515
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 *******************************************************************************/
12package org.yocto.bc.ui.filesystem;
13
14import java.io.File;
15import java.io.FileInputStream;
16import java.io.FileNotFoundException;
17import java.io.FileOutputStream;
18import java.io.IOException;
19import java.io.InputStream;
20import java.io.OutputStream;
21import java.net.URI;
22import java.util.List;
23
24import org.eclipse.core.filesystem.EFS;
25import org.eclipse.core.filesystem.IFileInfo;
26import org.eclipse.core.filesystem.IFileStore;
27import org.eclipse.core.filesystem.IFileSystem;
28import org.eclipse.core.filesystem.URIUtil;
29import org.eclipse.core.filesystem.provider.FileInfo;
30import org.eclipse.core.filesystem.provider.FileStore;
31import org.eclipse.core.runtime.CoreException;
32import org.eclipse.core.runtime.IPath;
33import org.eclipse.core.runtime.IProgressMonitor;
34import org.eclipse.core.runtime.IStatus;
35import org.eclipse.core.runtime.MultiStatus;
36import org.eclipse.core.runtime.NullProgressMonitor;
37import org.eclipse.core.runtime.Status;
38import org.eclipse.osgi.util.NLS;
39import org.yocto.bc.bitbake.BBSession;
40import org.yocto.bc.bitbake.ProjectInfoHelper;
41import 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 */
47public 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}