diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarEntry.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarEntry.java index c19baf947e2..3f03b6cc390 100644 --- a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarEntry.java +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarEntry.java @@ -7,10 +7,10 @@ * * Initial Contributors: * The following IBM employees contributed to the Remote System Explorer - * component that contains this file: David McKnight, Kushal Munir, - * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. - * + * * Contributors: * Martin Oberhuber (Wind River) - [219975] Fix implementations of clone() * Xuan Chen (IBM) - [api] SystemTarHandler has inconsistent API @@ -27,12 +27,13 @@ import org.eclipse.rse.internal.services.clientserver.archiveutils.ITarConstants /** * This class represents a tar file entry. + * @since 3.0 */ public class TarEntry implements Cloneable { - + // NOTE: Read the GNU tar specification to understand what each of the fields mean. // http://www.gnu.org/software/tar/manual/html_mono/tar.html#SEC118 - + // TODO (KM): Do we need to worry about ASCII? I think we do. We are constantly // switching between bytes and String assuming local encoding. However, the tar specification states // local ASCII variant must always be used. I think our code will probably fail on non-ASCII machines @@ -41,7 +42,7 @@ public class TarEntry implements Cloneable { // local variant of ASCII? Can we just use US-ASCII everywhere and get away with it. I think // that should work. Local variant of ASCII possibly means slightly different versions of ASCII used // on different machines, but not between locales. - + // block header fields public byte[] name = new byte[ITarConstants.NAME_LENGTH]; public byte[] mode = new byte[ITarConstants.MODE_LENGTH]; @@ -70,7 +71,7 @@ public class TarEntry implements Cloneable { public TarEntry(String name) { setName(name); } - + /** * Creates a new tar entry from the given block data. Fills in all the fields from the * block data. @@ -81,26 +82,26 @@ public class TarEntry implements Cloneable { */ TarEntry(byte[] blockData) throws IOException { checkNull(blockData); - + if (blockData.length != ITarConstants.BLOCK_SIZE) { throw new IllegalArgumentException(); } - + populateFields(blockData); } - + /** * Fills in the fields of the entry from block data. * @param blockData data in a header block. * @throws IOException if an I/O error occurs. */ private void populateFields(byte[] blockData) throws IOException { - + InputStream byteStream = new ByteArrayInputStream(blockData); // read the name byteStream.read(name); - + // if the name is an empty string, then don't fill in other fields, // since this indicates that we have reached end of file if (getName().equals("")) { //$NON-NLS-1$ @@ -123,7 +124,7 @@ public class TarEntry implements Cloneable { byteStream.read(devminor); byteStream.read(prefix); } - + /** * Checks whether the given object is null, and throws a NullPointerException if the * obect is null. @@ -131,12 +132,12 @@ public class TarEntry implements Cloneable { * @throws NullPointerException if the given object is null. */ private void checkNull(Object o) { - + if (o == null) { throw new NullPointerException(); } } - + /** * Sets the name of the tar entry. * @param fileName the name for the tar entry. @@ -144,17 +145,17 @@ public class TarEntry implements Cloneable { */ public void setName(String fileName) { checkNull(fileName); - + int length = ITarConstants.NAME_LENGTH - fileName.length(); - + // append null characters to the name for (int i = 0; i < length; i++) { fileName = fileName + "\0"; //$NON-NLS-1$ } - + name = fileName.getBytes(); } - + /** * Gets the name. * @return the name. @@ -162,7 +163,7 @@ public class TarEntry implements Cloneable { public String getName() { return (new String(name)).trim(); } - + /** * Sets the user mod. * @param canRead true if the user has read permission, false otherwise. @@ -170,27 +171,27 @@ public class TarEntry implements Cloneable { * @param canExecute true if the user has execute permission, false otherwise. */ public void setUserMode(boolean canRead, boolean canWrite, boolean canExecute) { - + int mod = 00; - + if (canRead) { mod += 04; } - + if (canWrite) { mod += 02; } - + if (canExecute) { mod += 01; } - + String modString = "0100" + Integer.toString(mod, 8) + "44"; //$NON-NLS-1$ //$NON-NLS-2$ modString = modString + "\0"; //$NON-NLS-1$ - + mode = modString.getBytes(); } - + /** * Gets the mode in octal. * @return the mode. @@ -198,7 +199,7 @@ public class TarEntry implements Cloneable { public String getMode() { return (new String(mode)).trim(); } - + /** * Gets the uid in octal. * @return the uid. @@ -206,7 +207,7 @@ public class TarEntry implements Cloneable { public String getUID() { return (new String(uid)).trim(); } - + /** * Gets the gid in octal. * @return the gid. @@ -214,32 +215,32 @@ public class TarEntry implements Cloneable { public String getGID() { return (new String(gid)).trim(); } - + /** * Sets the file size in bytes. * @param fileSize the file size. */ public void setSize(long fileSize) { - + // get the octal representation of the file size as a string String sizeString = Long.toString(fileSize, 8).trim(); - + // get the length of the string int length = sizeString.length(); - + int diff = ITarConstants.SIZE_LENGTH - length - 1; - + // prepend the string with 0s for (int i = 0; i < diff; i++) { sizeString = "0" + sizeString; //$NON-NLS-1$ } - + // append a space at the end sizeString = sizeString + " "; //$NON-NLS-1$ - + size = sizeString.getBytes(); } - + /** * Gets the size in bytes. * @return the size. @@ -247,32 +248,32 @@ public class TarEntry implements Cloneable { public long getSize() { return Long.parseLong((new String(size)).trim(), 8); } - + /** * Sets the modification time. * @param modTime the modification time, in milliseconds since 00:00:00 GMT, January 1, 1970. */ public void setModificationTime(long modTime) { - + // get the octal representation of the modification time as a string String mtimeString = Long.toString(modTime/1000, 8).trim(); - + // get the length of the string int length = mtimeString.length(); - + int diff = ITarConstants.MTIME_LENGTH - length - 1; - + // prepend the string with 0s for (int i = 0; i < diff; i++) { mtimeString = "0" + mtimeString; //$NON-NLS-1$ } - + // append a space at the end mtimeString = mtimeString + " "; //$NON-NLS-1$ - + mtime = mtimeString.getBytes(); } - + /** * Gets the modification time, in milliseconds since 00:00:00 GMT, January 1, 1970. * @return the modification time. @@ -280,7 +281,7 @@ public class TarEntry implements Cloneable { public long getModificationTime() { return Long.parseLong((new String(mtime)).trim(), 8) * 1000; } - + /** * Gets the checksum. * @return the checksum. @@ -307,13 +308,13 @@ public class TarEntry implements Cloneable { /** * Returns whether the archive was output in the P1003 archive format. - * This is not used. + * This is not used. * @return the magic field. */ public String getMagic() { return (new String(magic)).trim(); } - + /** * Gets the version in octal. * @return the version. @@ -321,7 +322,7 @@ public class TarEntry implements Cloneable { public String getVersion() { return (new String(version)).trim(); } - + /** * Sets the user name of the tar entry. * @param userName the user name for the tar entry. @@ -329,14 +330,14 @@ public class TarEntry implements Cloneable { */ public void setUserName(String userName) { checkNull(userName); - + int length = ITarConstants.UNAME_LENGTH - userName.length(); - + // append null characters to the user name for (int i = 0; i < length; i++) { userName = userName + "\0"; //$NON-NLS-1$ } - + uname = userName.getBytes(); } @@ -371,7 +372,7 @@ public class TarEntry implements Cloneable { public String getDevMinor() { return (new String(devminor)).trim(); } - + /** * Gets the prefix in octal. * @return the prefix. @@ -379,15 +380,15 @@ public class TarEntry implements Cloneable { public String getPrefix() { return (new String(prefix)).trim(); } - + /** * Returns whether the entry represents a directory. * @return true if the entry represents a directory, false otherwise. */ public boolean isDirectory() { - + String entryName = getName(); - + if (entryName.endsWith("/")) { //$NON-NLS-1$ return true; } @@ -395,7 +396,7 @@ public class TarEntry implements Cloneable { return false; } } - + /** * Write the fields to the given output stream. * @param outStream the output stream to write to. @@ -418,113 +419,113 @@ public class TarEntry implements Cloneable { outStream.write(devminor); outStream.write(prefix); } - + /** * Calculates the checksum of the entry. */ public void calculateChecksum() { int sum = 0; - + // add name bytes for (int i = 0; i < name.length; i++) { sum += name[i]; } - + // add mode bytes for (int i = 0; i < mode.length; i++) { sum += mode[i]; } - + // add uid bytes for (int i = 0; i < uid.length; i++) { sum += uid[i]; } - + // add gid bytes for (int i = 0; i < gid.length; i++) { sum += gid[i]; } - + // add size bytes for (int i = 0; i < size.length; i++) { sum += size[i]; } - + // add mtime bytes for (int i = 0; i < mtime.length; i++) { sum += mtime[i]; } - + // add checksum bytes assuming check sum is blank spaces char space = ' '; byte spaceByte = (byte)space; - + for (int i = 0; i < chksum.length; i++) { sum += spaceByte; } - + // add typeflag byte sum += typeflag; - + // add linkname bytes for (int i = 0; i < linkname.length; i++) { sum += linkname[i]; } - + // add magic bytes for (int i = 0; i < magic.length; i++) { sum += magic[i]; } - + // add version bytes for (int i = 0; i < version.length; i++) { sum += version[i]; } - + // add uname bytes for (int i = 0; i < uname.length; i++) { sum += uname[i]; } - + // add gname bytes for (int i = 0; i < gname.length; i++) { sum += gname[i]; } - + // add devmajor bytes for (int i = 0; i < devmajor.length; i++) { sum += devmajor[i]; } - + // add devminor bytes for (int i = 0; i < devminor.length; i++) { sum += devminor[i]; } - + // add prefix bytes for (int i = 0; i < prefix.length; i++) { sum += prefix[i]; } - + // get the octal representation of the sum as a string String sumString = Long.toString(sum, 8).trim(); - + // get the length of the string int length = sumString.length(); - + int diff = ITarConstants.CHKSUM_LENGTH - length - 2; - + // prepend the string with 0s for (int i = 0; i < diff; i++) { sumString = "0" + sumString; //$NON-NLS-1$ } - + // append a null character sumString = sumString + "\0"; //$NON-NLS-1$ - + // append a space sumString = sumString + " "; //$NON-NLS-1$ - + // set the checksum chksum = sumString.getBytes(); } diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarFile.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarFile.java index 2f0fd5fcd34..b11035335eb 100644 --- a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarFile.java +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarFile.java @@ -7,10 +7,10 @@ * * Initial Contributors: * The following IBM employees contributed to the Remote System Explorer - * component that contains this file: David McKnight, Kushal Munir, - * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. - * + * * Contributors: * Xuan Chen (IBM) - [api] SystemTarHandler has inconsistent API * Johnson Ma (Wind River) - [195402] Add tar.gz archive support @@ -30,18 +30,19 @@ import org.eclipse.rse.internal.services.clientserver.archiveutils.ITarConstants /** * This class is used to read entries from a tar file. + * @since 3.0 */ public class TarFile { - + private File file; private Vector blockHeaders; - + private class TarEntryInputStream extends InputStream { - + private long size; private InputStream stream; private long numRead; - + /** * Creates a tar entry input stream. * @param size the size of the data in the tar entry. @@ -52,12 +53,12 @@ public class TarFile { this.stream = stream; numRead = 0; } - + /** * @see java.io.InputStream#read() */ public int read() throws IOException { - + if (numRead >= size) { return -1; } @@ -66,18 +67,18 @@ public class TarFile { return stream.read(); } } - + /** * @see java.io.InputStream#available() */ public int available() throws IOException { - + // get difference between file size and how much we have already read long diff = size - numRead; - + // get how much we can read from underlying stream. int av = stream.available(); - + // return the smaller of the two // note although diff is a long, if it's smaller than av, we know it must fit // in an integer. @@ -124,7 +125,7 @@ public class TarFile { this.file = file; loadTarEntries(); } - + /** * Opens a tar file for reading given the file name. * @param name the name of the tar file to be opened for reading. @@ -134,7 +135,7 @@ public class TarFile { public TarFile(String name) throws FileNotFoundException, IOException { this(new File(name)); } - + /** * Loads tar entries. * @throws FileNotFoundException if the file does not exist. @@ -143,13 +144,13 @@ public class TarFile { private void loadTarEntries() throws FileNotFoundException, IOException { InputStream stream = getInputStream(); blockHeaders = new Vector(); - + // now read all the block headers byte[] blockData = readBlock(stream); // while end of stream is not reached, extract block headers while (blockData.length != 0) { - + // extract the header from the block TarEntry header = extractBlockHeader(blockData); @@ -158,7 +159,7 @@ public class TarFile { // determine how many blocks make up the contents of the file long fileSize = 0; - + // Bug 139207: Browsing into some tar archives failed // The reason was that the last entry in the file did not necessarily have an empty string as the name // of the entry and so the header is not null. The tar format does not guarantee an empty name. @@ -170,10 +171,10 @@ public class TarFile { catch (NumberFormatException e) { break; } - + // add header only if the size is valid blockHeaders.add(header); - + int numFileBlocks = (int)(fileSize / ITarConstants.BLOCK_SIZE); numFileBlocks += (fileSize % ITarConstants.BLOCK_SIZE) > 0 ? 1 : 0; @@ -192,7 +193,7 @@ public class TarFile { stream.close(); } - + /** * Gets the input stream for the tar file. * @return the input stream for the tar file. @@ -203,7 +204,7 @@ public class TarFile { FileInputStream stream = new FileInputStream(file); return stream; } - + /** * Reads the next block. * @param stream the input stream of the tar file. @@ -218,7 +219,7 @@ public class TarFile { for (int i = 0; i < ITarConstants.BLOCK_SIZE; i++) { byteRead = stream.read(); - + if (byteRead != -1) { blockData[i] = (byte)byteRead; } @@ -234,16 +235,16 @@ public class TarFile { return blockData; } - + /** * Extracts the header of a block given the block data. * @param blockData the block data. * @return the header of the block, or null if the block indicates end of file. */ private TarEntry extractBlockHeader(byte[] blockData) throws IOException { - + TarEntry entry = new TarEntry(blockData); - + // if the name of the entry is an empty string, it means we have reached end of file // so just return null if (entry.getName().equals("")) { //$NON-NLS-1$ @@ -253,7 +254,7 @@ public class TarFile { return entry; } } - + /** * Returns an enumeration of the tar file entries. * @return an enumeration of the tar file entries. @@ -261,7 +262,7 @@ public class TarFile { public Enumeration entries() { return blockHeaders.elements(); } - + /** * Returns the number of entries in the tar file. * @return the number of entries in the tar file. @@ -269,33 +270,33 @@ public class TarFile { public int size() { return blockHeaders.size(); } - + /** * Returns the tar file entry with that name, or null if not found. * @param name the name of the entry. * @return the tar file entry, or null if not found. */ public TarEntry getEntry(String name) { - + // TODO: could we maybe keep a hash instead to make it faster? // The hash could be keyed by names. But tars do allow headers with the same name. // Research this. Enumeration headers = entries(); - - // go through all block headers + + // go through all block headers while (headers.hasMoreElements()) { TarEntry entry = (TarEntry)(headers.nextElement()); String entryName = entry.getName(); - + // if name of entry matches the given name, then that is the entry we are looking for if (entryName.equals(name) || entryName.equals(name + "/")) { //$NON-NLS-1$ return entry; } } - + return null; } - + /** * Returns the input stream of the data in the given entry. * @param entry the entry. @@ -304,21 +305,21 @@ public class TarFile { */ public InputStream getInputStream(TarEntry entry) throws IOException { InputStream stream = getInputStream(); - + // now read all the block headers byte[] blockData = readBlock(stream); // while end of stream is not reached, extract block headers while (blockData.length != 0) { - + // extract the header from the block TarEntry header = extractBlockHeader(blockData); // if header is not null, we add it to our list of headers if (header != null) { - + long fileSize = 0; - + // Bug 139207: Browsing into some tar archives failed // The reason was that the last entry in the file did not necessarily have an empty string as the name // of the entry and so the header is not null. The tar format does not guarantee an empty name. @@ -333,7 +334,7 @@ public class TarFile { // if the header name does not match the entry name if (!header.getName().equals(entry.getName())) { - + // determine how many blocks make up the contents of the file int numFileBlocks = (int)(fileSize / ITarConstants.BLOCK_SIZE); numFileBlocks += (fileSize % ITarConstants.BLOCK_SIZE) > 0 ? 1 : 0; @@ -356,7 +357,7 @@ public class TarFile { // now read the next block blockData = readBlock(stream); } - + return null; } } diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarOutputStream.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarOutputStream.java index e1d21f2ac37..6539f925b80 100644 --- a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarOutputStream.java +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/TarOutputStream.java @@ -10,7 +10,7 @@ * component that contains this file: David McKnight, Kushal Munir, * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. - * + * * Contributors: * Xuan Chen (IBM) - [api] SystemTarHandler has inconsistent API * Martin Oberhuber (Wind River) - [cleanup] Move from internal to fix API leakage @@ -24,8 +24,9 @@ import java.io.OutputStream; import org.eclipse.rse.internal.services.clientserver.archiveutils.ITarConstants; /** - * This class implements an output stream filter for writing files in the - * tar file format. + * This class implements an output stream filter for writing files in the tar + * file format. + * @since 3.0 */ public class TarOutputStream extends OutputStream {