| /******************************************************************************* |
| * Copyright (c) 2005, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.core.internal.filesystem; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import org.eclipse.core.filesystem.*; |
| import org.eclipse.core.filesystem.provider.FileStore; |
| import org.eclipse.core.internal.filesystem.local.LocalFile; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.service.environment.Constants; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * An instance of this class represents a directory on disk where cached |
| * files can be stored. Files in the cache expire on VM exit. |
| */ |
| public class FileCache { |
| private static final String CACHE_DIR_NAME = "filecache";//$NON-NLS-1$ |
| |
| /** |
| * Thread safety for lazy instantiation of the cache |
| */ |
| private static final Object creationLock = new Object(); |
| |
| /** |
| * Cached constant indicating if the current OS is Mac OSX |
| */ |
| static final boolean MACOSX = FileCache.getOS().equals(Constants.OS_MACOSX); |
| |
| /** |
| * The singleton file cache instance. |
| */ |
| private static FileCache instance = null; |
| |
| private File cacheDir; |
| |
| /** |
| * Public accessor to obtain the singleton file cache instance, |
| * creating the cache lazily if necessary. |
| * @return The file cache instance |
| * @throws CoreException If the file cache could not be created |
| */ |
| public static FileCache getCache() throws CoreException { |
| synchronized (creationLock) { |
| if (instance == null) |
| instance = new FileCache(); |
| return instance; |
| } |
| } |
| |
| /** |
| * Creates a new file cache. |
| * |
| * @throws CoreException If the file cache could not be created |
| */ |
| private FileCache() throws CoreException { |
| IPath location = FileSystemAccess.getCacheLocation(); |
| File cacheParent = new File(location.toFile(), CACHE_DIR_NAME); |
| cleanOldCache(cacheParent); |
| cacheParent.mkdirs(); |
| //make sure we have a unique non-existing cache directory |
| cacheDir = getUniqueDirectory(cacheParent, true); |
| } |
| |
| /** |
| * Implements {@link FileStore#toLocalFile(int, IProgressMonitor)} |
| * @param source source data to cache on disk |
| * @param monitor |
| * monitor to indicate progress and receive cancellation |
| * @return The cached file |
| * @throws CoreException on errors using the source filestore or writing the cache file |
| */ |
| public java.io.File cache(IFileStore source, IProgressMonitor monitor) throws CoreException { |
| try { |
| SubMonitor subMonitor = SubMonitor.convert(monitor, NLS.bind(Messages.copying, toString()), 3); |
| IFileInfo myInfo = source.fetchInfo(EFS.NONE, subMonitor.newChild(1)); |
| if (!myInfo.exists()) |
| return new File(cacheDir, "Non-Existent-" + System.currentTimeMillis()); //$NON-NLS-1$ |
| File result; |
| if (myInfo.isDirectory()) { |
| result = getUniqueDirectory(cacheDir, false); |
| } else { |
| result = File.createTempFile(source.getFileSystem().getScheme(), "efs", cacheDir); //$NON-NLS-1$ |
| } |
| subMonitor.worked(1); |
| IFileStore resultStore = new LocalFile(result); |
| source.copy(resultStore, EFS.OVERWRITE, subMonitor.newChild(1)); |
| result.deleteOnExit(); |
| return result; |
| } catch (IOException e) { |
| Policy.error(EFS.ERROR_WRITE, NLS.bind(Messages.couldNotWrite, toString())); |
| return null; // Can't get here |
| } |
| } |
| |
| /** |
| * Performs initial cleanup of any old cached state left over from previous |
| * sessions. |
| */ |
| private void cleanOldCache(File cacheParent) throws CoreException { |
| //clear any old cache - this could be moved to a background thread |
| if (MACOSX) { |
| // fix for bug 323833: clear the immutable flag before old cache deletion on MacOS |
| clearImmutableFlag(cacheParent); |
| } |
| new LocalFile(cacheParent).delete(EFS.NONE, null); |
| } |
| |
| private void clearImmutableFlag(File target) { |
| if (!target.exists()) { |
| return; |
| } |
| if (target.isDirectory()) { |
| File[] children = target.listFiles(); |
| if (children != null) { |
| for (File element : children) { |
| clearImmutableFlag(element); |
| } |
| } |
| } else { |
| LocalFile lfile = new LocalFile(target); |
| try { |
| IFileInfo info = lfile.fetchInfo(EFS.NONE, null); |
| if (info.getAttribute(EFS.ATTRIBUTE_IMMUTABLE)) { |
| info.setAttribute(EFS.ATTRIBUTE_IMMUTABLE, false); |
| lfile.putInfo(info, EFS.SET_ATTRIBUTES, null); |
| } |
| } catch (CoreException e) { |
| // ignore and continue since failed deletions will be reported by LocalFile.delete() |
| } |
| } |
| } |
| |
| /** |
| * Returns the current OS. This is equivalent to Platform.getOS(), but |
| * is tolerant of the platform runtime not being present. |
| */ |
| static String getOS() { |
| return System.getProperty("osgi.os", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * Returns a new unique directory in the given parent directory. |
| * |
| * @param parent |
| * @param create <code>true</code> if the directory should |
| * be created, and false otherwise. |
| * @return The unique directory |
| */ |
| private File getUniqueDirectory(File parent, boolean create) { |
| File dir; |
| long i = 0; |
| //find an unused directory name |
| do { |
| dir = new File(parent, Long.toString(System.currentTimeMillis() + i++)); |
| } while (dir.exists()); |
| if (create) |
| dir.mkdir(); |
| return dir; |
| } |
| } |