| /******************************************************************************* |
| * Copyright (c) 2005, 2016 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.osgi.storage.bundlefile; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.*; |
| import org.eclipse.osgi.internal.messages.Msg; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * A BundleFile that uses a directory as its base file. |
| */ |
| public class DirBundleFile extends BundleFile { |
| |
| private static final String POINTER_SAME_DIRECTORY_1 = "/.";//$NON-NLS-1$ |
| private static final String POINTER_SAME_DIRECTORY_2 = "//";//$NON-NLS-1$ |
| private static final String POINTER_UPPER_DIRECTORY = "..";//$NON-NLS-1$ |
| |
| private final boolean enableStrictBundleEntryPath; |
| |
| /** |
| * Constructs a DirBundleFile |
| * @param basefile the base file |
| * @throws IOException |
| */ |
| public DirBundleFile(File basefile, boolean enableStrictBundleEntryPath) throws IOException { |
| super(getBaseFile(basefile, enableStrictBundleEntryPath)); |
| if (!BundleFile.secureAction.exists(basefile) || !BundleFile.secureAction.isDirectory(basefile)) { |
| throw new IOException(NLS.bind(Msg.ADAPTOR_DIRECTORY_EXCEPTION, basefile)); |
| } |
| this.enableStrictBundleEntryPath = enableStrictBundleEntryPath; |
| } |
| |
| private static File getBaseFile(File basefile, boolean enableStrictBundleEntryPath) throws IOException { |
| return enableStrictBundleEntryPath ? secureAction.getCanonicalFile(basefile) : basefile; |
| } |
| |
| public File getFile(String path, boolean nativeCode) { |
| final boolean checkInBundle = path != null && path.indexOf(POINTER_UPPER_DIRECTORY) >= 0; |
| File file = new File(this.basefile, path); |
| if (!BundleFile.secureAction.exists(file)) { |
| return null; |
| } |
| |
| if (!enableStrictBundleEntryPath) { |
| // must do an extra check to make sure file is within the bundle (bug 320546) |
| if (checkInBundle) { |
| try { |
| if (!BundleFile.secureAction.getCanonicalPath(file).startsWith(BundleFile.secureAction.getCanonicalPath(basefile))) |
| return null; |
| } catch (IOException e) { |
| return null; |
| } |
| } |
| return file; |
| } |
| boolean normalize = false; |
| boolean isBundleRoot = false; |
| if (path != null) { |
| isBundleRoot = path.equals("/");//$NON-NLS-1$ |
| if (!isBundleRoot) { |
| normalize = checkInBundle || path.indexOf(POINTER_SAME_DIRECTORY_1) >= 0 || path.indexOf(POINTER_SAME_DIRECTORY_2) >= 0; |
| } |
| } |
| File canonicalFile; |
| try { |
| canonicalFile = BundleFile.secureAction.getCanonicalFile(file); |
| if (!isBundleRoot) { |
| File absoluteFile = BundleFile.secureAction.getAbsoluteFile(file); |
| String canonicalPath; |
| String absolutePath; |
| if (normalize) { |
| canonicalPath = canonicalFile.toURI().getPath(); |
| absolutePath = absoluteFile.toURI().normalize().getPath(); |
| } else { |
| canonicalPath = canonicalFile.getPath(); |
| absolutePath = absoluteFile.getPath(); |
| } |
| if (!canonicalPath.equals(absolutePath)) { |
| return null; |
| } |
| } |
| // must do an extra check to make sure file is within the bundle (bug 320546) |
| if (checkInBundle) { |
| if (!canonicalFile.getPath().startsWith(basefile.getPath())) |
| return null; |
| } |
| } catch (IOException e) { |
| return null; |
| } |
| |
| return file; |
| } |
| |
| public BundleEntry getEntry(String path) { |
| File filePath = getFile(path, false); |
| if (filePath == null) |
| return null; |
| return new FileBundleEntry(filePath, path); |
| } |
| |
| public boolean containsDir(String dir) { |
| File dirPath = getFile(dir, false); |
| return dirPath != null && BundleFile.secureAction.isDirectory(dirPath); |
| } |
| |
| public Enumeration<String> getEntryPaths(String path, boolean recurse) { |
| if (path.length() > 0 && path.charAt(0) == '/') |
| path = path.substring(1); |
| File pathFile = getFile(path, false); |
| if (pathFile == null || !BundleFile.secureAction.isDirectory(pathFile)) |
| return null; |
| String[] fileList = BundleFile.secureAction.list(pathFile); |
| if (fileList == null || fileList.length == 0) |
| return null; |
| String dirPath = path.length() == 0 || path.charAt(path.length() - 1) == '/' ? path : path + '/'; |
| |
| LinkedHashSet<String> entries = new LinkedHashSet<>(); |
| for (String s : fileList) { |
| java.io.File childFile = new java.io.File(pathFile, s); |
| StringBuilder sb = new StringBuilder(dirPath).append(s); |
| if (BundleFile.secureAction.isDirectory(childFile)) { |
| sb.append("/"); //$NON-NLS-1$ |
| if (recurse) { |
| Enumeration<String> e = getEntryPaths(sb.toString(), true); |
| if (e != null) |
| entries.addAll(Collections.list(e)); |
| } |
| } |
| entries.add(sb.toString()); |
| } |
| return Collections.enumeration(entries); |
| } |
| |
| public void close() { |
| // nothing to do. |
| } |
| |
| public void open() { |
| // nothing to do. |
| } |
| } |