import org.eclipse.swt.widgets.Shell;
import org.eclipse.tracecompass.tmf.core.util.Pair;
import org.eclipse.ui.internal.wizards.datatransfer.ArchiveFileManipulations;
-import org.eclipse.ui.internal.wizards.datatransfer.TarException;
-import org.eclipse.ui.internal.wizards.datatransfer.TarFile;
-import org.eclipse.ui.internal.wizards.datatransfer.TarLeveledStructureProvider;
import org.eclipse.ui.internal.wizards.datatransfer.ZipLeveledStructureProvider;
import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider;
return ArchiveFileManipulations.closeZipFile(specifiedFile, shell);
}
- static boolean ensureTarSourceIsValid(String archivePath, Shell shell) {
+ static boolean ensureTarSourceIsValid(String archivePath) {
TarFile specifiedFile = getSpecifiedTarSourceFile(archivePath);
if (specifiedFile == null) {
return false;
}
- return ArchiveFileManipulations.closeTarFile(specifiedFile, shell);
+ return closeTarFile(specifiedFile);
}
static boolean ensureGzipSourceIsValid(String archivePath) {
return isGzipFile(archivePath);
}
+ static boolean closeTarFile(TarFile file) {
+ try {
+ file.close();
+ } catch (IOException e) {
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Get the root file system object and it's associated import provider for
* the specified source file. A shell is used to display messages in case of
FileSystemObjectLeveledImportStructureProvider leveledImportStructureProvider = null;
String archivePath = sourceFile.getAbsolutePath();
if (isTarFile(archivePath)) {
- if (ensureTarSourceIsValid(archivePath, shell)) {
+ if (ensureTarSourceIsValid(archivePath)) {
// We close the file when we dispose the import provider,
// see disposeSelectionGroupRoot
TarFile tarFile = getSpecifiedTarSourceFile(archivePath);
import java.util.List;
import java.util.zip.ZipEntry;
-import org.eclipse.ui.internal.wizards.datatransfer.TarEntry;
import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider;
/**
* An import provider that makes use of the IFileSystemObject abstraction
* instead of using plain file system objects (File, TarEntry, ZipEntry, etc)
*/
-@SuppressWarnings("restriction")
public class FileSystemObjectImportStructureProvider implements IImportStructureProvider {
private IImportStructureProvider fImportProvider;
return false;
}
- if (!isImportFromDirectory() && !ArchiveUtil.ensureTarSourceIsValid(source.getAbsolutePath(), getContainer().getShell()) && !ArchiveUtil.ensureZipSourceIsValid(source.getAbsolutePath(), getContainer().getShell())
+ if (!isImportFromDirectory() && !ArchiveUtil.ensureTarSourceIsValid(source.getAbsolutePath()) && !ArchiveUtil.ensureZipSourceIsValid(source.getAbsolutePath(), getContainer().getShell())
&& !ArchiveUtil.ensureGzipSourceIsValid(source.getAbsolutePath())) {
setMessage(null);
setErrorMessage(Messages.ImportTraceWizard_BadArchiveFormat);
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Marc-Andre Laperle <marc-andre.laperle@ericsson.com> - Copied to Trace Compass to work around bug 501379
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
+
+/**
+ * Representation of a file in a tar archive.
+ */
+public class TarEntry implements Cloneable
+{
+ private String name;
+ private long mode, time, size;
+ private int type;
+ int filepos;
+
+ /**
+ * Entry type for normal files.
+ */
+ public static final int FILE = '0';
+
+ /**
+ * Entry type for directories.
+ */
+ public static final int DIRECTORY = '5';
+
+ /**
+ * Create a new TarEntry for a file of the given name at the
+ * given position in the file.
+ *
+ * @param name filename
+ * @param pos position in the file in bytes
+ */
+ TarEntry(String name, int pos) {
+ this.name = name;
+ mode = 0644;
+ type = FILE;
+ filepos = pos;
+ time = System.currentTimeMillis() / 1000;
+ }
+
+ /**
+ * Create a new TarEntry for a file of the given name.
+ *
+ * @param name filename
+ */
+ public TarEntry(String name) {
+ this(name, -1);
+ }
+
+ /**
+ * Returns the type of this file, one of FILE, LINK, SYM_LINK,
+ * CHAR_DEVICE, BLOCK_DEVICE, DIRECTORY or FIFO.
+ *
+ * @return file type
+ */
+ public int getFileType() {
+ return type;
+ }
+
+ /**
+ * Returns the mode of the file in UNIX permissions format.
+ *
+ * @return file mode
+ */
+ public long getMode() {
+ return mode;
+ }
+
+ /**
+ * Returns the name of the file.
+ *
+ * @return filename
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the size of the file in bytes.
+ *
+ * @return filesize
+ */
+ public long getSize() {
+ return size;
+ }
+
+ /**
+ * Returns the modification time of the file in seconds since January
+ * 1st 1970.
+ *
+ * @return time
+ */
+ public long getTime() {
+ return time;
+ }
+
+ /**
+ * Sets the type of the file, one of FILE, LINK, SYMLINK, CHAR_DEVICE,
+ * BLOCK_DEVICE, or DIRECTORY.
+ *
+ * @param type the file type
+ */
+ public void setFileType(int type) {
+ this.type = type;
+ }
+
+ /**
+ * Sets the mode of the file in UNIX permissions format.
+ *
+ * @param mode the mode
+ */
+ public void setMode(long mode) {
+ this.mode = mode;
+ }
+
+ /**
+ * Sets the size of the file in bytes.
+ *
+ * @param size the file size
+ */
+ public void setSize(long size) {
+ this.size = size;
+ }
+
+ /**
+ * Sets the modification time of the file in seconds since January
+ * 1st 1970.
+ *
+ * @param time the modification time
+ */
+ public void setTime(long time) {
+ this.time = time;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Marc-Andre Laperle <marc-andre.laperle@ericsson.com> - Copied to Trace Compass to work around bug 501379
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
+
+/**
+ * Exception generated upon encountering corrupted tar files.
+ */
+public class TarException extends Exception {
+ /**
+ * Generated serial version UID for this class.
+ */
+ private static final long serialVersionUID = 2886671254518853528L;
+
+ /**
+ * Constructs a TarException without a detail string.
+ */
+ public TarException() {
+ super();
+ }
+
+ /**
+ * Constructs a TarException with the specified detail string.
+ *
+ * @param s the detail string
+ */
+ public TarException(String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs a TarException with the specified detail string.
+ *
+ * @param s the detail string
+ * @param cause the cause
+ */
+ public TarException(String s, Throwable cause) {
+ super(s, cause);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 243347 TarFile should not throw NPE in finalize()
+ * Marc-Andre Laperle <marc-andre.laperle@ericsson.com> - Bug 463633
+ * Marc-Andre Laperle <marc-andre.laperle@ericsson.com> - Copied to Trace Compass to work around bug 501379
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.zip.GZIPInputStream;
+
+
+/**
+ * Reads a .tar or .tar.gz archive file, providing an index enumeration
+ * and allows for accessing an InputStream for arbitrary files in the
+ * archive.
+ */
+public class TarFile {
+ private File file;
+ private TarInputStream entryEnumerationStream;
+ private TarEntry curEntry;
+ private TarInputStream entryStream;
+
+ private InputStream internalEntryStream;
+ // This field is just to prevent try with resources error and keep the code
+ // similar to the original
+ private InputStream fInputStream;
+
+ /**
+ * Create a new TarFile for the given file.
+ *
+ * @param file the file
+ * @throws TarException on Tar error (bad format, etc)
+ * @throws IOException on i/o error
+ */
+ public TarFile(File file) throws TarException, IOException {
+ this.file = file;
+
+ fInputStream = new FileInputStream(file);
+ // First, check if it's a GZIPInputStream.
+ try {
+ fInputStream = new GZIPInputStream(fInputStream);
+ } catch(IOException e) {
+ //If it is not compressed we close
+ //the old one and recreate
+ fInputStream.close();
+ fInputStream = new FileInputStream(file);
+ }
+ try {
+ entryEnumerationStream = new TarInputStream(fInputStream);
+ } catch (TarException | IOException ex) {
+ fInputStream.close();
+ throw ex;
+ }
+ curEntry = entryEnumerationStream.getNextEntry();
+ }
+
+ /**
+ * Close the tar file input stream.
+ *
+ * @throws IOException if the file cannot be successfully closed
+ */
+ public void close() throws IOException {
+ if (entryEnumerationStream != null) {
+ entryEnumerationStream.close();
+ }
+ if (internalEntryStream != null) {
+ internalEntryStream.close();
+ }
+ }
+
+ /**
+ * Create a new TarFile for the given path name.
+ *
+ * @param filename the file name to create the TarFile from
+ * @throws TarException on Tar error (bad format, etc)
+ * @throws IOException on i/o error
+ */
+ public TarFile(String filename) throws TarException, IOException {
+ this(new File(filename));
+ }
+
+ /**
+ * Returns an enumeration cataloguing the tar archive.
+ *
+ * @return enumeration of all files in the archive
+ */
+ public Enumeration<TarEntry> entries() {
+ return new Enumeration<TarEntry>() {
+ @Override
+ public boolean hasMoreElements() {
+ return (curEntry != null);
+ }
+
+ @Override
+ public TarEntry nextElement() {
+ TarEntry oldEntry = curEntry;
+ try {
+ curEntry = entryEnumerationStream.getNextEntry();
+ } catch(TarException e) {
+ curEntry = null;
+ } catch(IOException e) {
+ curEntry = null;
+ }
+ return oldEntry;
+ }
+ };
+ }
+
+ /**
+ * Returns a new InputStream for the given file in the tar archive.
+ *
+ * @param entry the entry to get the InputStream from
+ * @return an input stream for the given file
+ * @throws TarException on Tar error (bad format, etc)
+ * @throws IOException on i/o error
+ */
+ public InputStream getInputStream(TarEntry entry) throws TarException, IOException {
+ if(entryStream == null || !entryStream.skipToEntry(entry)) {
+ if (internalEntryStream != null) {
+ internalEntryStream.close();
+ }
+ internalEntryStream = new FileInputStream(file);
+ // First, check if it's a GZIPInputStream.
+ try {
+ internalEntryStream = new GZIPInputStream(internalEntryStream);
+ } catch(IOException e) {
+ //If it is not compressed we close
+ //the old one and recreate
+ internalEntryStream.close();
+ internalEntryStream = new FileInputStream(file);
+ }
+ entryStream = new TarInputStream(internalEntryStream, entry) {
+ @Override
+ public void close() {
+ // Ignore close() since we want to reuse the stream.
+ }
+ };
+ }
+ return entryStream;
+ }
+
+ /**
+ * Returns the path name of the file this archive represents.
+ *
+ * @return path
+ */
+ public String getName() {
+ return file.getPath();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ close();
+ }
+}
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.URIUtil;
-import org.eclipse.ui.internal.wizards.datatransfer.TarEntry;
/**
* The "Tar" implementation of an IFileSystemObject, entries can also be Gzipped
* and are uncompressed transparently.
*/
-@SuppressWarnings("restriction")
class TarFileSystemObject implements IFileSystemObject {
private TarEntry fFileSystemObject;
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Marc-Andre Laperle <marc-andre.laperle@ericsson.com> - Copied to Trace Compass to work around bug 501379
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.ui.internal.wizards.datatransfer.DataTransferMessages;
+
+/**
+ * Input stream for reading files in ustar format (tar) compatible
+ * with the specification in IEEE Std 1003.1-2001. Also supports
+ * long filenames encoded using the GNU @LongLink extension.
+ */
+@SuppressWarnings("restriction")
+public class TarInputStream extends FilterInputStream
+{
+ private int nextEntry = 0;
+ private int nextEOF = 0;
+ private int filepos = 0;
+ private long bytesread = 0;
+ private TarEntry firstEntry = null;
+ private String longLinkName = null;
+
+ /**
+ * Creates a new tar input stream on the given input stream.
+ *
+ * @param in input stream
+ * @throws TarException on Tar error (bad format, etc)
+ * @throws IOException on i/o error
+ */
+ public TarInputStream(InputStream in) throws TarException, IOException {
+ super(in);
+
+ // Read in the first TarEntry to make sure
+ // the input is a valid tar file stream.
+ firstEntry = getNextEntry();
+ }
+
+ /**
+ * Create a new tar input stream, skipping ahead to the given entry
+ * in the file.
+ *
+ * @param in input stream
+ * @param entry skips to this entry in the file
+ * @throws TarException
+ * @throws IOException
+ */
+ TarInputStream(InputStream in, TarEntry entry) throws TarException, IOException {
+ super(in);
+ skipToEntry(entry);
+ }
+
+ /**
+ * The checksum of a tar file header is simply the sum of the bytes in
+ * the header.
+ *
+ * @param header
+ * @return checksum
+ */
+ private static long headerChecksum(byte[] header) {
+ long sum = 0;
+ for(int i = 0; i < 512; i++) {
+ sum += header[i] & 0xff;
+ }
+ return sum;
+ }
+
+ /**
+ * Skips ahead to the position of the given entry in the file.
+ *
+ * @param entry
+ * @returns false if the entry has already been passed
+ * @throws TarException
+ * @throws IOException
+ */
+ boolean skipToEntry(TarEntry entry) throws TarException, IOException {
+ long bytestoskip = entry.filepos - bytesread;
+ if(bytestoskip < 0) {
+ return false;
+ }
+ while(bytestoskip > 0) {
+ long ret = in.skip(bytestoskip);
+ if(ret < 0) {
+ throw new IOException("early end of stream"); //$NON-NLS-1$
+ }
+ bytestoskip -= ret;
+ bytesread += ret;
+ }
+ filepos = entry.filepos;
+ nextEntry = 0;
+ nextEOF = 0;
+ // Read next header to seek to file data.
+ getNextEntry();
+ return true;
+ }
+
+ /**
+ * Returns true if the header checksum is correct.
+ *
+ * @param header
+ * @return true if this header has a valid checksum
+ */
+ private static boolean isValidTarHeader(byte[] header) {
+ long fileChecksum, calculatedChecksum;
+ int pos, i;
+
+ pos = 148;
+ StringBuffer checksumString = new StringBuffer();
+ for(i = 0; i < 8; i++) {
+ if(header[pos + i] == ' ') {
+ continue;
+ }
+ if(header[pos + i] == 0 || !Character.isDigit((char) header[pos + i])) {
+ break;
+ }
+ checksumString.append((char) header[pos + i]);
+ }
+ if(checksumString.length() == 0) {
+ return false;
+ }
+ if(checksumString.charAt(0) != '0') {
+ checksumString.insert(0, '0');
+ }
+ try {
+ fileChecksum = Long.decode(checksumString.toString()).longValue();
+ } catch(NumberFormatException exception) {
+ //This is not valid if it cannot be parsed
+ return false;
+ }
+
+ // Blank out the checksum.
+ for(i = 0; i < 8; i++) {
+ header[pos + i] = ' ';
+ }
+ calculatedChecksum = headerChecksum(header);
+
+ return (fileChecksum == calculatedChecksum);
+ }
+
+ /**
+ * Returns the next entry in the tar file. Does not handle
+ * GNU @LongLink extensions.
+ *
+ * @return the next entry in the tar file
+ * @throws TarException
+ * @throws IOException
+ */
+ TarEntry getNextEntryInternal() throws TarException, IOException {
+ byte[] header = new byte[512];
+ int pos = 0;
+ int i;
+
+ if(firstEntry != null) {
+ TarEntry entryReturn = firstEntry;
+ firstEntry = null;
+ return entryReturn;
+ }
+
+ while(nextEntry > 0) {
+ long ret = in.skip(nextEntry);
+ if(ret < 0) {
+ throw new IOException("early end of stream"); //$NON-NLS-1$
+ }
+ nextEntry -= ret;
+ bytesread += ret;
+ }
+
+ int bytestoread = 512;
+ while(bytestoread > 0) {
+ int ret = super.read(header, 512 - bytestoread, bytestoread);
+ if( ret < 0 ) {
+ throw new IOException("early end of stream"); //$NON-NLS-1$
+ }
+ bytestoread -= ret;
+ bytesread += ret;
+ }
+
+ // If we have a header of all zeros, this marks the end of the file.
+ if(headerChecksum(header) == 0) {
+ // We are at the end of the file.
+ if(filepos > 0) {
+ return null;
+ }
+
+ // Invalid stream.
+ throw new TarException("not in tar format"); //$NON-NLS-1$
+ }
+
+ // Validate checksum.
+ if(!isValidTarHeader(header)) {
+ throw new TarException("not in tar format"); //$NON-NLS-1$
+ }
+
+ while (pos < 100 && header[pos] != 0) {
+ pos++;
+ }
+ String name = new String(header, 0, pos, "UTF8"); //$NON-NLS-1$
+ // Prepend the prefix here.
+ pos = 345;
+ if(header[pos] != 0) {
+ while (pos < 500 && header[pos] != 0) {
+ pos++;
+ }
+ String prefix = new String(header, 345, pos - 345, "UTF8"); //$NON-NLS-1$
+ name = prefix + "/" + name; //$NON-NLS-1$
+ }
+
+ TarEntry entry;
+ if(longLinkName != null) {
+ entry = new TarEntry(longLinkName, filepos);
+ longLinkName = null;
+ } else {
+ entry = new TarEntry(name, filepos);
+ }
+ if(header[156] != 0) {
+ entry.setFileType(header[156]);
+ }
+
+ pos = 100;
+ StringBuffer mode = new StringBuffer();
+ for(i = 0; i < 8; i++) {
+ if(header[pos + i] == 0) {
+ break;
+ }
+ if(header[pos + i] == ' ') {
+ continue;
+ }
+ mode.append((char) header[pos + i]);
+ }
+ if(mode.length() > 0 && mode.charAt(0) != '0') {
+ mode.insert(0, '0');
+ }
+ try {
+ long fileMode = Long.decode(mode.toString()).longValue();
+ entry.setMode(fileMode);
+ } catch(NumberFormatException nfe) {
+ throw new TarException(DataTransferMessages.TarImport_invalid_tar_format, nfe);
+ }
+
+ pos = 100 + 24;
+ StringBuffer size = new StringBuffer();
+ for(i = 0; i < 12; i++) {
+ if(header[pos + i] == 0) {
+ break;
+ }
+ if(header[pos + i] == ' ') {
+ continue;
+ }
+ size.append((char) header[pos + i]);
+ }
+ if(size.charAt(0) != '0') {
+ size.insert(0, '0');
+ }
+ int fileSize;
+ try {
+ fileSize = Integer.decode(size.toString()).intValue();
+ } catch(NumberFormatException nfe) {
+ throw new TarException(DataTransferMessages.TarImport_invalid_tar_format, nfe);
+ }
+
+ entry.setSize(fileSize);
+ nextEOF = fileSize;
+ if(fileSize % 512 > 0) {
+ nextEntry = fileSize + (512 - (fileSize % 512));
+ } else {
+ nextEntry = fileSize;
+ }
+ filepos += (nextEntry + 512);
+ return entry;
+ }
+
+ /**
+ * Moves ahead to the next file in the tar archive and returns
+ * a TarEntry object describing it.
+ *
+ * @return the next entry in the tar file
+ * @throws TarException on Tar error (bad format, etc)
+ * @throws IOException on i/o errors
+ */
+ public TarEntry getNextEntry() throws TarException, IOException {
+ TarEntry entry = getNextEntryInternal();
+
+ if(entry != null && entry.getName().equals("././@LongLink")) { //$NON-NLS-1$
+ // This is a GNU extension for doing long filenames.
+ // We get a file called ././@LongLink which just contains
+ // the real pathname.
+ byte[] longNameData = new byte[(int) entry.getSize()];
+ int nbytesread = 0;
+ while (nbytesread < longNameData.length) {
+ int cur = read(longNameData, nbytesread, longNameData.length - nbytesread);
+ if (cur < 0) {
+ throw new IOException("early end of stream"); //$NON-NLS-1$
+ }
+ nbytesread += cur;
+ }
+
+ int pos = 0;
+ while (pos < longNameData.length && longNameData[pos] != 0) {
+ pos++;
+ }
+ longLinkName = new String(longNameData, 0, pos, "UTF8"); //$NON-NLS-1$
+ return getNextEntryInternal();
+ }
+ return entry;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int lenToRead = len;
+ if(nextEOF == 0) {
+ return -1;
+ }
+ if(lenToRead > nextEOF) {
+ lenToRead = nextEOF;
+ }
+ int size = super.read(b, off, lenToRead);
+ nextEntry -= size;
+ nextEOF -= size;
+ bytesread += size;
+ return size;
+ }
+
+ @Override
+ public int read() throws IOException {
+ byte[] data = new byte[1];
+ int size = read(data, 0, 1);
+ if (size < 0) {
+ return size;
+ }
+ return data[0];
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Red Hat, Inc - Was TarFileStructureProvider, performed changes from
+ * IImportStructureProvider to ILeveledImportStructureProvider
+ * Mickael Istria (Red Hat Inc.) - Bug 486901
+ * Marc-Andre Laperle <marc-andre.laperle@ericsson.com> - Copied to Trace Compass to work around bug 501379
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.ResourceAttributes;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
+import org.eclipse.ui.internal.wizards.datatransfer.DataTransferMessages;
+import org.eclipse.ui.internal.wizards.datatransfer.ILeveledImportStructureProvider;
+
+/**
+ * This class provides information regarding the context structure and content
+ * of specified tar file entry objects.
+ */
+@SuppressWarnings("restriction")
+public class TarLeveledStructureProvider implements
+ ILeveledImportStructureProvider {
+ private TarFile tarFile;
+
+ private TarEntry root = new TarEntry("/");//$NON-NLS-1$
+
+ private Map<TarEntry, List<TarEntry>> children;
+
+ private Map<IPath, TarEntry> directoryEntryCache = new HashMap<>();
+
+ private int stripLevel;
+
+ /**
+ * Creates a <code>TarFileStructureProvider</code>, which will operate on
+ * the passed tar file.
+ *
+ * @param sourceFile
+ * the source TarFile
+ */
+ public TarLeveledStructureProvider(TarFile sourceFile) {
+ super();
+ tarFile = sourceFile;
+ root.setFileType(TarEntry.DIRECTORY);
+ }
+
+ /**
+ * Creates a new container tar entry with the specified name, iff it has
+ * not already been created. If the parent of the given element does not
+ * already exist it will be recursively created as well.
+ * @param pathname The path representing the container
+ * @return The element represented by this pathname (it may have already existed)
+ */
+ protected TarEntry createContainer(IPath pathname) {
+ TarEntry existingEntry = directoryEntryCache.get(pathname);
+ if (existingEntry != null) {
+ return existingEntry;
+ }
+
+ TarEntry parent;
+ if (pathname.segmentCount() == 1) {
+ parent = root;
+ } else {
+ parent = createContainer(pathname.removeLastSegments(1));
+ }
+ TarEntry newEntry = new TarEntry(pathname.toString());
+ newEntry.setFileType(TarEntry.DIRECTORY);
+ directoryEntryCache.put(pathname, newEntry);
+ List<TarEntry> childList = new ArrayList<>();
+ children.put(newEntry, childList);
+
+ List<TarEntry> parentChildList = children.get(parent);
+ NonNullUtils.checkNotNull(parentChildList).add(newEntry);
+ return newEntry;
+ }
+
+ /**
+ * Creates a new tar file entry with the specified name.
+ * @param entry the entry to create the file for
+ */
+ protected void createFile(TarEntry entry) {
+ IPath pathname = new Path(entry.getName());
+ TarEntry parent;
+ if (pathname.segmentCount() == 1) {
+ parent = root;
+ } else {
+ parent = directoryEntryCache.get(pathname
+ .removeLastSegments(1));
+ }
+
+ List<TarEntry> childList = children.get(parent);
+ NonNullUtils.checkNotNull(childList).add(entry);
+ }
+
+ @Override
+ public List getChildren(Object element) {
+ if (children == null) {
+ initialize();
+ }
+
+ return (children.get(element));
+ }
+
+ @Override
+ public InputStream getContents(Object element) {
+ try {
+ return tarFile.getInputStream((TarEntry) element);
+ } catch (TarException e) {
+ IDEWorkbenchPlugin.log(e.getLocalizedMessage(), e);
+ return null;
+ } catch (IOException e) {
+ IDEWorkbenchPlugin.log(e.getLocalizedMessage(), e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the resource attributes for this file.
+ *
+ * @param element the element to get the attributes from
+ * @return the attributes of the file
+ */
+ public ResourceAttributes getResourceAttributes(Object element) {
+ ResourceAttributes attributes = new ResourceAttributes();
+ TarEntry entry = (TarEntry) element;
+ attributes.setExecutable((entry.getMode() & 0100) != 0);
+ attributes.setReadOnly((entry.getMode() & 0200) == 0);
+ return attributes;
+ }
+
+ @Override
+ public String getFullPath(Object element) {
+ return stripPath(((TarEntry) element).getName());
+ }
+
+ @Override
+ public String getLabel(Object element) {
+ if (element.equals(root)) {
+ return ((TarEntry) element).getName();
+ }
+
+ return stripPath(new Path(((TarEntry) element).getName()).lastSegment());
+ }
+
+ /**
+ * Returns the entry that this importer uses as the root sentinel.
+ *
+ * @return TarEntry entry
+ */
+ @Override
+ public Object getRoot() {
+ return root;
+ }
+
+ /**
+ * Returns the tar file that this provider provides structure for.
+ *
+ * @return TarFile file
+ */
+ public TarFile getTarFile() {
+ return tarFile;
+ }
+
+ @Override
+ public boolean closeArchive(){
+ try {
+ getTarFile().close();
+ } catch (IOException e) {
+ IDEWorkbenchPlugin.log(DataTransferMessages.ZipImport_couldNotClose
+ + getTarFile().getName(), e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Initializes this object's children table based on the contents of the
+ * specified source file.
+ */
+ protected void initialize() {
+ children = new HashMap<>(1000);
+
+ children.put(root, new ArrayList<>());
+ Enumeration<TarEntry> entries = tarFile.entries();
+ while (entries.hasMoreElements()) {
+ TarEntry entry = entries.nextElement();
+ IPath path = new Path(entry.getName()).addTrailingSeparator();
+
+ if (entry.getFileType() == TarEntry.DIRECTORY) {
+ createContainer(path);
+ } else
+ {
+ // Ensure the container structure for all levels above this is initialized
+ // Once we hit a higher-level container that's already added we need go no further
+ int pathSegmentCount = path.segmentCount();
+ if (pathSegmentCount > 1) {
+ createContainer(path.uptoSegment(pathSegmentCount - 1));
+ }
+ createFile(entry);
+ }
+ }
+ }
+
+ @Override
+ public boolean isFolder(Object element) {
+ return (((TarEntry) element).getFileType() == TarEntry.DIRECTORY);
+ }
+
+ /*
+ * Strip the leading directories from the path
+ */
+ private String stripPath(String path) {
+ String strippedPath = path;
+ String pathOrig = strippedPath;
+ for (int i = 0; i < stripLevel; i++) {
+ int firstSep = strippedPath.indexOf('/');
+ // If the first character was a seperator we must strip to the next
+ // seperator as well
+ if (firstSep == 0) {
+ strippedPath = strippedPath.substring(1);
+ firstSep = strippedPath.indexOf('/');
+ }
+ // No seperator wasw present so we're in a higher directory right
+ // now
+ if (firstSep == -1) {
+ return pathOrig;
+ }
+ strippedPath = strippedPath.substring(firstSep);
+ }
+ return strippedPath;
+ }
+
+ @Override
+ public void setStrip(int level) {
+ stripLevel = level;
+ }
+
+ @Override
+ public int getStrip() {
+ return stripLevel;
+ }
+}
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.ui.internal.wizards.datatransfer.TarEntry;
-import org.eclipse.ui.internal.wizards.datatransfer.TarException;
-import org.eclipse.ui.internal.wizards.datatransfer.TarFile;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TarEntry;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TarException;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TarFile;
/**
* An abstract operation containing common code useful for other trace package
*
* @author Marc-Andre Laperle
*/
-@SuppressWarnings("restriction")
public abstract class AbstractTracePackageOperation {
private IStatus fStatus;
// Result of this operation, if any
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jface.operation.ModalContext;
import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TarException;
import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.AbstractTracePackageOperation;
import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageBookmarkElement;
import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils;
import org.eclipse.ui.dialogs.IOverwriteQuery;
import org.eclipse.ui.ide.IDE;
-import org.eclipse.ui.internal.wizards.datatransfer.TarException;
import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider;
import org.eclipse.ui.wizards.datatransfer.ImportOperation;
*
* @author Marc-Andre Laperle
*/
-@SuppressWarnings("restriction")
public class TracePackageImportOperation extends AbstractTracePackageOperation implements IOverwriteQuery {
private final TracePackageElement[] fImportTraceElements;