diff --git a/source/net/yacy/utils/tarTools.java b/source/net/yacy/utils/tarTools.java index 074440204..9af805e3b 100644 --- a/source/net/yacy/utils/tarTools.java +++ b/source/net/yacy/utils/tarTools.java @@ -35,8 +35,9 @@ import java.util.zip.GZIPInputStream; import net.yacy.cora.util.ConcurrentLog; -import org.apache.tools.tar.TarEntry; -import org.apache.tools.tar.TarInputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.io.IOUtils; public class tarTools { @@ -69,19 +70,19 @@ public class tarTools { public static void unTar(final InputStream in, final String untarDir) throws Exception{ ConcurrentLog.info("UNTAR", "starting"); if(new File(untarDir).exists()){ - final TarInputStream tin = new TarInputStream(in); - TarEntry tarEntry = tin.getNextEntry(); + final TarArchiveInputStream tin = new TarArchiveInputStream(in); + TarArchiveEntry tarEntry = tin.getNextTarEntry(); while(tarEntry != null){ final File destPath = new File(untarDir + File.separator + tarEntry.getName()); if (!tarEntry.isDirectory()) { new File(destPath.getParent()).mkdirs(); // create missing subdirectories final FileOutputStream fout = new FileOutputStream(destPath); - tin.copyEntryContents(fout); + IOUtils.copyLarge(tin,fout,0,tarEntry.getSize()); fout.close(); } else { destPath.mkdir(); } - tarEntry = tin.getNextEntry(); + tarEntry = tin.getNextTarEntry(); } tin.close(); } else { // untarDir doesn't exist @@ -89,8 +90,8 @@ public class tarTools { } ConcurrentLog.info("UNTAR", "finished"); } - - public static void main(final String args[]) { + + public static void main(final String args[]) { // @arg0 source // @arg1 destination if(args.length == 2){ @@ -103,4 +104,4 @@ public class tarTools { System.out.println("usage: "); } } -} +} diff --git a/source/org/apache/tools/tar/TarBuffer.java b/source/org/apache/tools/tar/TarBuffer.java deleted file mode 100644 index f33882bab..000000000 --- a/source/org/apache/tools/tar/TarBuffer.java +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/* - * This package is based on the work done by Timothy Gerard Endres - * (time@ice.com) to whom the Ant project is very grateful for his great code. - */ - -package org.apache.tools.tar; - -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; -import java.util.Arrays; - -/** - * The TarBuffer class implements the tar archive concept - * of a buffered input stream. This concept goes back to the - * days of blocked tape drives and special io devices. In the - * Java universe, the only real function that this class - * performs is to ensure that files have the correct "block" - * size, or other tars will complain. - *

- * You should never have a need to access this class directly. - * TarBuffers are created by Tar IO Streams. - * - */ - -public class TarBuffer { - - /** Default record size */ - public static final int DEFAULT_RCDSIZE = (512); - - /** Default block size */ - public static final int DEFAULT_BLKSIZE = (DEFAULT_RCDSIZE * 20); - - private InputStream inStream; - private OutputStream outStream; - private byte[] blockBuffer; - private int currBlkIdx; - private int currRecIdx; - private int blockSize; - private int recordSize; - private int recsPerBlock; - private boolean debug; - - /** - * Constructor for a TarBuffer on an input stream. - * @param inStream the input stream to use - */ - public TarBuffer(InputStream inStream) { - this(inStream, TarBuffer.DEFAULT_BLKSIZE); - } - - /** - * Constructor for a TarBuffer on an input stream. - * @param inStream the input stream to use - * @param blockSize the block size to use - */ - public TarBuffer(InputStream inStream, int blockSize) { - this(inStream, blockSize, TarBuffer.DEFAULT_RCDSIZE); - } - - /** - * Constructor for a TarBuffer on an input stream. - * @param inStream the input stream to use - * @param blockSize the block size to use - * @param recordSize the record size to use - */ - public TarBuffer(InputStream inStream, int blockSize, int recordSize) { - this.inStream = inStream; - this.outStream = null; - - this.initialize(blockSize, recordSize); - } - - /** - * Constructor for a TarBuffer on an output stream. - * @param outStream the output stream to use - */ - public TarBuffer(OutputStream outStream) { - this(outStream, TarBuffer.DEFAULT_BLKSIZE); - } - - /** - * Constructor for a TarBuffer on an output stream. - * @param outStream the output stream to use - * @param blockSize the block size to use - */ - public TarBuffer(OutputStream outStream, int blockSize) { - this(outStream, blockSize, TarBuffer.DEFAULT_RCDSIZE); - } - - /** - * Constructor for a TarBuffer on an output stream. - * @param outStream the output stream to use - * @param blockSize the block size to use - * @param recordSize the record size to use - */ - public TarBuffer(OutputStream outStream, int blockSize, int recordSize) { - this.inStream = null; - this.outStream = outStream; - - this.initialize(blockSize, recordSize); - } - - /** - * Initialization common to all constructors. - */ - private void initialize(int blockSize, int recordSize) { - this.debug = false; - this.blockSize = blockSize; - this.recordSize = recordSize; - this.recsPerBlock = (this.blockSize / this.recordSize); - this.blockBuffer = new byte[this.blockSize]; - - if (this.inStream != null) { - this.currBlkIdx = -1; - this.currRecIdx = this.recsPerBlock; - } else { - this.currBlkIdx = 0; - this.currRecIdx = 0; - } - } - - /** - * Get the TAR Buffer's block size. Blocks consist of multiple records. - * @return the block size - */ - public int getBlockSize() { - return this.blockSize; - } - - /** - * Get the TAR Buffer's record size. - * @return the record size - */ - public int getRecordSize() { - return this.recordSize; - } - - /** - * Set the debugging flag for the buffer. - * - * @param debug If true, print debugging output. - */ - public void setDebug(boolean debug) { - this.debug = debug; - } - - /** - * Determine if an archive record indicate End of Archive. End of - * archive is indicated by a record that consists entirely of null bytes. - * - * @param record The record data to check. - * @return true if the record data is an End of Archive - */ - public boolean isEOFRecord(byte[] record) { - for (int i = 0, sz = this.getRecordSize(); i < sz; ++i) { - if (record[i] != 0) { - return false; - } - } - - return true; - } - - /** - * Skip over a record on the input stream. - * @throws IOException on error - */ - public void skipRecord() throws IOException { - if (this.debug) { - System.err.println("SkipRecord: recIdx = " + this.currRecIdx - + " blkIdx = " + this.currBlkIdx); - } - - if (this.inStream == null) { - throw new IOException("reading (via skip) from an output buffer"); - } - - if (this.currRecIdx >= this.recsPerBlock) { - if (!this.readBlock()) { - return; // UNDONE - } - } - - this.currRecIdx++; - } - - /** - * Read a record from the input stream and return the data. - * - * @return The record data. - * @throws IOException on error - */ - public byte[] readRecord() throws IOException { - if (this.debug) { - System.err.println("ReadRecord: recIdx = " + this.currRecIdx - + " blkIdx = " + this.currBlkIdx); - } - - if (this.inStream == null) { - throw new IOException("reading from an output buffer"); - } - - if (this.currRecIdx >= this.recsPerBlock) { - if (!this.readBlock()) { - return null; - } - } - - byte[] result = new byte[this.recordSize]; - - System.arraycopy(this.blockBuffer, - (this.currRecIdx * this.recordSize), result, 0, - this.recordSize); - - this.currRecIdx++; - - return result; - } - - /** - * @return false if End-Of-File, else true - */ - private boolean readBlock() throws IOException { - if (this.debug) { - System.err.println("ReadBlock: blkIdx = " + this.currBlkIdx); - } - - if (this.inStream == null) { - throw new IOException("reading from an output buffer"); - } - - this.currRecIdx = 0; - - int offset = 0; - int bytesNeeded = this.blockSize; - - while (bytesNeeded > 0) { - long numBytes = this.inStream.read(this.blockBuffer, offset, - bytesNeeded); - - // - // NOTE - // We have fit EOF, and the block is not full! - // - // This is a broken archive. It does not follow the standard - // blocking algorithm. However, because we are generous, and - // it requires little effort, we will simply ignore the error - // and continue as if the entire block were read. This does - // not appear to break anything upstream. We used to return - // false in this case. - // - // Thanks to 'Yohann.Roussel@alcatel.fr' for this fix. - // - if (numBytes == -1) { - if (offset == 0) { - // Ensure that we do not read gigabytes of zeros - // for a corrupt tar file. - // See http://issues.apache.org/bugzilla/show_bug.cgi?id=39924 - return false; - } - // However, just leaving the unread portion of the buffer dirty does - // cause problems in some cases. This problem is described in - // http://issues.apache.org/bugzilla/show_bug.cgi?id=29877 - // - // The solution is to fill the unused portion of the buffer with zeros. - - Arrays.fill(blockBuffer, offset, offset + bytesNeeded, (byte) 0); - - break; - } - - offset += numBytes; - bytesNeeded -= numBytes; - - if (numBytes != this.blockSize) { - if (this.debug) { - System.err.println("ReadBlock: INCOMPLETE READ " - + numBytes + " of " + this.blockSize - + " bytes read."); - } - } - } - - this.currBlkIdx++; - - return true; - } - - /** - * Get the current block number, zero based. - * - * @return The current zero based block number. - */ - public int getCurrentBlockNum() { - return this.currBlkIdx; - } - - /** - * Get the current record number, within the current block, zero based. - * Thus, current offset = (currentBlockNum * recsPerBlk) + currentRecNum. - * - * @return The current zero based record number. - */ - public int getCurrentRecordNum() { - return this.currRecIdx - 1; - } - - /** - * Write an archive record to the archive. - * - * @param record The record data to write to the archive. - * @throws IOException on error - */ - public void writeRecord(byte[] record) throws IOException { - if (this.debug) { - System.err.println("WriteRecord: recIdx = " + this.currRecIdx - + " blkIdx = " + this.currBlkIdx); - } - - if (this.outStream == null) { - throw new IOException("writing to an input buffer"); - } - - if (record.length != this.recordSize) { - throw new IOException("record to write has length '" - + record.length - + "' which is not the record size of '" - + this.recordSize + "'"); - } - - if (this.currRecIdx >= this.recsPerBlock) { - this.writeBlock(); - } - - System.arraycopy(record, 0, this.blockBuffer, - (this.currRecIdx * this.recordSize), - this.recordSize); - - this.currRecIdx++; - } - - /** - * Write an archive record to the archive, where the record may be - * inside of a larger array buffer. The buffer must be "offset plus - * record size" long. - * - * @param buf The buffer containing the record data to write. - * @param offset The offset of the record data within buf. - * @throws IOException on error - */ - public void writeRecord(byte[] buf, int offset) throws IOException { - if (this.debug) { - System.err.println("WriteRecord: recIdx = " + this.currRecIdx - + " blkIdx = " + this.currBlkIdx); - } - - if (this.outStream == null) { - throw new IOException("writing to an input buffer"); - } - - if ((offset + this.recordSize) > buf.length) { - throw new IOException("record has length '" + buf.length - + "' with offset '" + offset - + "' which is less than the record size of '" - + this.recordSize + "'"); - } - - if (this.currRecIdx >= this.recsPerBlock) { - this.writeBlock(); - } - - System.arraycopy(buf, offset, this.blockBuffer, - (this.currRecIdx * this.recordSize), - this.recordSize); - - this.currRecIdx++; - } - - /** - * Write a TarBuffer block to the archive. - */ - private void writeBlock() throws IOException { - if (this.debug) { - System.err.println("WriteBlock: blkIdx = " + this.currBlkIdx); - } - - if (this.outStream == null) { - throw new IOException("writing to an input buffer"); - } - - this.outStream.write(this.blockBuffer, 0, this.blockSize); - this.outStream.flush(); - - this.currRecIdx = 0; - this.currBlkIdx++; - } - - /** - * Flush the current data block if it has any data in it. - */ - private void flushBlock() throws IOException { - if (this.debug) { - System.err.println("TarBuffer.flushBlock() called."); - } - - if (this.outStream == null) { - throw new IOException("writing to an input buffer"); - } - - if (this.currRecIdx > 0) { - this.writeBlock(); - } - } - - /** - * Close the TarBuffer. If this is an output buffer, also flush the - * current block before closing. - * @throws IOException on error - */ - public synchronized void close() throws IOException { - if (this.debug) { - System.err.println("TarBuffer.closeBuffer()."); - } - - if (this.outStream != null) { - this.flushBlock(); - - if (this.outStream != System.out - && this.outStream != System.err) { - this.outStream.close(); - - this.outStream = null; - } - } else if (this.inStream != null) { - if (this.inStream != System.in) { - this.inStream.close(); - - this.inStream = null; - } - } - } -} diff --git a/source/org/apache/tools/tar/TarConstants.java b/source/org/apache/tools/tar/TarConstants.java deleted file mode 100644 index 2ba5d6667..000000000 --- a/source/org/apache/tools/tar/TarConstants.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/* - * This package is based on the work done by Timothy Gerard Endres - * (time@ice.com) to whom the Ant project is very grateful for his great code. - */ - -package org.apache.tools.tar; - -/** - * This interface contains all the definitions used in the package. - * - */ -// CheckStyle:InterfaceIsTypeCheck OFF (bc) -public interface TarConstants { - - /** - * The length of the name field in a header buffer. - */ - int NAMELEN = 100; - - /** - * The length of the mode field in a header buffer. - */ - int MODELEN = 8; - - /** - * The length of the user id field in a header buffer. - */ - int UIDLEN = 8; - - /** - * The length of the group id field in a header buffer. - */ - int GIDLEN = 8; - - /** - * The length of the checksum field in a header buffer. - */ - int CHKSUMLEN = 8; - - /** - * The length of the size field in a header buffer. - */ - int SIZELEN = 12; - - /** - * The maximum size of a file in a tar archive (That's 11 sevens, octal). - */ - long MAXSIZE = 077777777777L; - - /** - * The length of the magic field in a header buffer. - */ - int MAGICLEN = 8; - - /** - * The length of the modification time field in a header buffer. - */ - int MODTIMELEN = 12; - - /** - * The length of the user name field in a header buffer. - */ - int UNAMELEN = 32; - - /** - * The length of the group name field in a header buffer. - */ - int GNAMELEN = 32; - - /** - * The length of the devices field in a header buffer. - */ - int DEVLEN = 8; - - /** - * LF_ constants represent the "link flag" of an entry, or more commonly, - * the "entry type". This is the "old way" of indicating a normal file. - */ - byte LF_OLDNORM = 0; - - /** - * Normal file type. - */ - byte LF_NORMAL = (byte) '0'; - - /** - * Link file type. - */ - byte LF_LINK = (byte) '1'; - - /** - * Symbolic link file type. - */ - byte LF_SYMLINK = (byte) '2'; - - /** - * Character device file type. - */ - byte LF_CHR = (byte) '3'; - - /** - * Block device file type. - */ - byte LF_BLK = (byte) '4'; - - /** - * Directory file type. - */ - byte LF_DIR = (byte) '5'; - - /** - * FIFO (pipe) file type. - */ - byte LF_FIFO = (byte) '6'; - - /** - * Contiguous file type. - */ - byte LF_CONTIG = (byte) '7'; - - /** - * The magic tag representing a POSIX tar archive. - */ - String TMAGIC = "ustar"; - - /** - * The magic tag representing a GNU tar archive. - */ - String GNU_TMAGIC = "ustar "; - - /** - * The namr of the GNU tar entry which contains a long name. - */ - String GNU_LONGLINK = "././@LongLink"; - - /** - * Identifies the *next* file on the tape as having a long name. - */ - byte LF_GNUTYPE_LONGNAME = (byte) 'L'; -} diff --git a/source/org/apache/tools/tar/TarEntry.java b/source/org/apache/tools/tar/TarEntry.java deleted file mode 100644 index 6f815c532..000000000 --- a/source/org/apache/tools/tar/TarEntry.java +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/* - * This package is based on the work done by Timothy Gerard Endres - * (time@ice.com) to whom the Ant project is very grateful for his great code. - */ -/* - * Modifications (Michael Christen) - * - replaced StringBuffer with StringBuilder - */ - -package org.apache.tools.tar; - -import java.io.File; -import java.util.Date; -import java.util.Locale; - - -/** - * This class represents an entry in a Tar archive. It consists - * of the entry's header, as well as the entry's File. Entries - * can be instantiated in one of three ways, depending on how - * they are to be used. - *

- * TarEntries that are created from the header bytes read from - * an archive are instantiated with the TarEntry( byte[] ) - * constructor. These entries will be used when extracting from - * or listing the contents of an archive. These entries have their - * header filled in using the header bytes. They also set the File - * to null, since they reference an archive entry not a file. - *

- * TarEntries that are created from Files that are to be written - * into an archive are instantiated with the TarEntry( File ) - * constructor. These entries have their header filled in using - * the File's information. They also keep a reference to the File - * for convenience when writing entries. - *

- * Finally, TarEntries can be constructed from nothing but a name. - * This allows the programmer to construct the entry by hand, for - * instance when only an InputStream is available for writing to - * the archive, and the header information is constructed from - * other information. In this case the header fields are set to - * defaults and the File is set to null. - * - *

- * The C structure for a Tar Entry's header is: - *

- * struct header {
- * char name[NAMSIZ];
- * char mode[8];
- * char uid[8];
- * char gid[8];
- * char size[12];
- * char mtime[12];
- * char chksum[8];
- * char linkflag;
- * char linkname[NAMSIZ];
- * char magic[8];
- * char uname[TUNMLEN];
- * char gname[TGNMLEN];
- * char devmajor[8];
- * char devminor[8];
- * } header;
- * 
- * - */ - -public class TarEntry implements TarConstants { - /** The entry's name. */ - private StringBuilder name; - - /** The entry's permission mode. */ - private int mode; - - /** The entry's user id. */ - private int userId; - - /** The entry's group id. */ - private int groupId; - - /** The entry's size. */ - private long size; - - /** The entry's modification time. */ - private long modTime; - - /** The entry's link flag. */ - private byte linkFlag; - - /** The entry's link name. */ - private StringBuilder linkName; - - /** The entry's magic tag. */ - private StringBuilder magic; - - /** The entry's user name. */ - private StringBuilder userName; - - /** The entry's group name. */ - private StringBuilder groupName; - - /** The entry's major device number. */ - private int devMajor; - - /** The entry's minor device number. */ - private int devMinor; - - /** The entry's file reference */ - private File file; - - /** Maximum length of a user's name in the tar file */ - public static final int MAX_NAMELEN = 31; - - /** Default permissions bits for directories */ - public static final int DEFAULT_DIR_MODE = 040755; - - /** Default permissions bits for files */ - public static final int DEFAULT_FILE_MODE = 0100644; - - /** Convert millis to seconds */ - public static final int MILLIS_PER_SECOND = 1000; - - /** - * Construct an empty entry and prepares the header values. - */ - private TarEntry () { - this.magic = new StringBuilder(TMAGIC); - this.name = new StringBuilder(); - this.linkName = new StringBuilder(); - - String user = System.getProperty("user.name", ""); - - if (user.length() > MAX_NAMELEN) { - user = user.substring(0, MAX_NAMELEN); - } - - this.userId = 0; - this.groupId = 0; - this.userName = new StringBuilder(user); - this.groupName = new StringBuilder(""); - this.file = null; - } - - /** - * Construct an entry with only a name. This allows the programmer - * to construct the entry's header "by hand". File is set to null. - * - * @param name the entry name - */ - public TarEntry(final String name) { - this(); - - final boolean isDir = name.endsWith("/"); - - this.devMajor = 0; - this.devMinor = 0; - this.name = new StringBuilder(name); - this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE; - this.linkFlag = isDir ? LF_DIR : LF_NORMAL; - this.userId = 0; - this.groupId = 0; - this.size = 0; - this.modTime = (new Date()).getTime() / MILLIS_PER_SECOND; - this.linkName = new StringBuilder(""); - this.userName = new StringBuilder(""); - this.groupName = new StringBuilder(""); - this.devMajor = 0; - this.devMinor = 0; - - } - - /** - * Construct an entry with a name an a link flag. - * - * @param name the entry name - * @param linkFlag the entry link flag. - */ - public TarEntry(final String name, final byte linkFlag) { - this(name); - this.linkFlag = linkFlag; - } - - /** - * Construct an entry for a file. File is set to file, and the - * header is constructed from information from the file. - * - * @param file The file that the entry represents. - */ - public TarEntry(final File file) { - this(); - - this.file = file; - - String fileName = file.getPath(); - final String osname = System.getProperty("os.name").toLowerCase(Locale.US); - - if (osname != null) { - - // Strip off drive letters! - // REVIEW Would a better check be "(File.separator == '\')"? - - if (osname.startsWith("windows")) { - if (fileName.length() > 2) { - final char ch1 = fileName.charAt(0); - final char ch2 = fileName.charAt(1); - - if (ch2 == ':' - && ((ch1 >= 'a' && ch1 <= 'z') - || (ch1 >= 'A' && ch1 <= 'Z'))) { - fileName = fileName.substring(2); - } - } - } else if (osname.indexOf("netware",0) > -1) { - final int colon = fileName.indexOf(':'); - if (colon != -1) { - fileName = fileName.substring(colon + 1); - } - } - } - - fileName = fileName.replace(File.separatorChar, '/'); - - // No absolute pathnames - // Windows (and Posix?) paths can start with "\\NetworkDrive\", - // so we loop on starting /'s. - while (fileName.length() > 0 && fileName.charAt(0) == '/') { - fileName = fileName.substring(1); - } - - this.linkName = new StringBuilder(""); - this.name = new StringBuilder(fileName); - - if (file.isDirectory()) { - this.mode = DEFAULT_DIR_MODE; - this.linkFlag = LF_DIR; - - if (this.name.charAt(this.name.length() - 1) != '/') { - this.name.append("/"); - } - } else { - this.mode = DEFAULT_FILE_MODE; - this.linkFlag = LF_NORMAL; - } - - this.size = file.length(); - this.modTime = file.lastModified() / MILLIS_PER_SECOND; - this.devMajor = 0; - this.devMinor = 0; - } - - /** - * Construct an entry from an archive's header bytes. File is set - * to null. - * - * @param headerBuf The header bytes from a tar archive entry. - */ - public TarEntry(final byte[] headerBuf) { - this(); - parseTarHeader(headerBuf); - } - - /** - * Determine if the two entries are equal. Equality is determined - * by the header names being equal. - * - * @param it Entry to be checked for equality. - * @return True if the entries are equal. - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (!(obj instanceof TarEntry)) return false; - final TarEntry other = (TarEntry) obj; - return getName().equals(other.getName()); - } - - /** - * Hashcodes are based on entry names. - * - * @return the entry hashcode - */ - @Override - public int hashCode() { - return getName().hashCode(); - } - - /** - * Determine if the given entry is a descendant of this entry. - * Descendancy is determined by the name of the descendant - * starting with this entry's name. - * - * @param desc Entry to be checked as a descendent of this. - * @return True if entry is a descendant of this. - */ - public boolean isDescendent(final TarEntry desc) { - return desc.getName().startsWith(getName()); - } - - /** - * Get this entry's name. - * - * @return This entry's name. - */ - public String getName() { - return this.name.toString(); - } - - /** - * Set this entry's name. - * - * @param name This entry's new name. - */ - public void setName(final String name) { - this.name = new StringBuilder(name); - } - - /** - * Set the mode for this entry - * - * @param mode the mode for this entry - */ - public void setMode(final int mode) { - this.mode = mode; - } - - /** - * Get this entry's link name. - * - * @return This entry's link name. - */ - public String getLinkName() { - return this.linkName.toString(); - } - - /** - * Get this entry's user id. - * - * @return This entry's user id. - */ - public int getUserId() { - return this.userId; - } - - /** - * Set this entry's user id. - * - * @param userId This entry's new user id. - */ - public void setUserId(final int userId) { - this.userId = userId; - } - - /** - * Get this entry's group id. - * - * @return This entry's group id. - */ - public int getGroupId() { - return this.groupId; - } - - /** - * Set this entry's group id. - * - * @param groupId This entry's new group id. - */ - public void setGroupId(final int groupId) { - this.groupId = groupId; - } - - /** - * Get this entry's user name. - * - * @return This entry's user name. - */ - public String getUserName() { - return this.userName.toString(); - } - - /** - * Set this entry's user name. - * - * @param userName This entry's new user name. - */ - public void setUserName(final String userName) { - this.userName = new StringBuilder(userName); - } - - /** - * Get this entry's group name. - * - * @return This entry's group name. - */ - public String getGroupName() { - return this.groupName.toString(); - } - - /** - * Set this entry's group name. - * - * @param groupName This entry's new group name. - */ - public void setGroupName(final String groupName) { - this.groupName = new StringBuilder(groupName); - } - - /** - * Convenience method to set this entry's group and user ids. - * - * @param userId This entry's new user id. - * @param groupId This entry's new group id. - */ - public void setIds(final int userId, final int groupId) { - setUserId(userId); - setGroupId(groupId); - } - - /** - * Convenience method to set this entry's group and user names. - * - * @param userName This entry's new user name. - * @param groupName This entry's new group name. - */ - public void setNames(final String userName, final String groupName) { - setUserName(userName); - setGroupName(groupName); - } - - /** - * Set this entry's modification time. The parameter passed - * to this method is in "Java time". - * - * @param time This entry's new modification time. - */ - public void setModTime(final long time) { - this.modTime = time / MILLIS_PER_SECOND; - } - - /** - * Set this entry's modification time. - * - * @param time This entry's new modification time. - */ - public void setModTime(final Date time) { - this.modTime = time.getTime() / MILLIS_PER_SECOND; - } - - /** - * Set this entry's modification time. - * - * @return time This entry's new modification time. - */ - public Date getModTime() { - return new Date(this.modTime * MILLIS_PER_SECOND); - } - - /** - * Get this entry's file. - * - * @return This entry's file. - */ - public File getFile() { - return this.file; - } - - /** - * Get this entry's mode. - * - * @return This entry's mode. - */ - public int getMode() { - return this.mode; - } - - /** - * Get this entry's file size. - * - * @return This entry's file size. - */ - public long getSize() { - return this.size; - } - - /** - * Set this entry's file size. - * - * @param size This entry's new file size. - */ - public void setSize(final long size) { - this.size = size; - } - - - /** - * Indicate if this entry is a GNU long name block - * - * @return true if this is a long name extension provided by GNU tar - */ - public boolean isGNULongNameEntry() { - return this.linkFlag == LF_GNUTYPE_LONGNAME - && this.name.toString().equals(GNU_LONGLINK); - } - - /** - * Return whether or not this entry represents a directory. - * - * @return True if this entry is a directory. - */ - public boolean isDirectory() { - if (this.file != null) { - return this.file.isDirectory(); - } - - if (this.linkFlag == LF_DIR) { - return true; - } - - if (getName().endsWith("/")) { - return true; - } - - return false; - } - - /** - * If this entry represents a file, and the file is a directory, return - * an array of TarEntries for this entry's children. - * - * @return An array of TarEntry's for this entry's children. - */ - public TarEntry[] getDirectoryEntries() { - if (this.file == null || !this.file.isDirectory()) { - return new TarEntry[0]; - } - - final String[] list = this.file.list(); - final TarEntry[] result = new TarEntry[list.length]; - - for (int i = 0; i < list.length; ++i) { - result[i] = new TarEntry(new File(this.file, list[i])); - } - - return result; - } - - /** - * Write an entry's header information to a header buffer. - * - * @param outbuf The tar entry header buffer to fill in. - */ - public void writeEntryHeader(final byte[] outbuf) { - int offset = 0; - - offset = TarUtils.getNameBytes(this.name, outbuf, offset, NAMELEN); - offset = TarUtils.getOctalBytes(this.mode, outbuf, offset, MODELEN); - offset = TarUtils.getOctalBytes(this.userId, outbuf, offset, UIDLEN); - offset = TarUtils.getOctalBytes(this.groupId, outbuf, offset, GIDLEN); - offset = TarUtils.getLongOctalBytes(this.size, outbuf, offset, SIZELEN); - offset = TarUtils.getLongOctalBytes(this.modTime, outbuf, offset, MODTIMELEN); - - final int csOffset = offset; - - for (int c = 0; c < CHKSUMLEN; ++c) { - outbuf[offset++] = (byte) ' '; - } - - outbuf[offset++] = this.linkFlag; - offset = TarUtils.getNameBytes(this.linkName, outbuf, offset, NAMELEN); - offset = TarUtils.getNameBytes(this.magic, outbuf, offset, MAGICLEN); - offset = TarUtils.getNameBytes(this.userName, outbuf, offset, UNAMELEN); - offset = TarUtils.getNameBytes(this.groupName, outbuf, offset, GNAMELEN); - offset = TarUtils.getOctalBytes(this.devMajor, outbuf, offset, DEVLEN); - offset = TarUtils.getOctalBytes(this.devMinor, outbuf, offset, DEVLEN); - - while (offset < outbuf.length) { - outbuf[offset++] = 0; - } - - final long chk = TarUtils.computeCheckSum(outbuf); - - TarUtils.getCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN); - } - - /** - * Parse an entry's header information from a header buffer. - * - * @param header The tar entry header buffer to get information from. - */ - public void parseTarHeader(final byte[] header) { - int offset = 0; - - this.name = TarUtils.parseName(header, offset, NAMELEN); - offset += NAMELEN; - this.mode = (int) TarUtils.parseOctal(header, offset, MODELEN); - offset += MODELEN; - this.userId = (int) TarUtils.parseOctal(header, offset, UIDLEN); - offset += UIDLEN; - this.groupId = (int) TarUtils.parseOctal(header, offset, GIDLEN); - offset += GIDLEN; - this.size = TarUtils.parseOctal(header, offset, SIZELEN); - offset += SIZELEN; - this.modTime = TarUtils.parseOctal(header, offset, MODTIMELEN); - offset += MODTIMELEN; - offset += CHKSUMLEN; - this.linkFlag = header[offset++]; - this.linkName = TarUtils.parseName(header, offset, NAMELEN); - offset += NAMELEN; - this.magic = TarUtils.parseName(header, offset, MAGICLEN); - offset += MAGICLEN; - this.userName = TarUtils.parseName(header, offset, UNAMELEN); - offset += UNAMELEN; - this.groupName = TarUtils.parseName(header, offset, GNAMELEN); - offset += GNAMELEN; - this.devMajor = (int) TarUtils.parseOctal(header, offset, DEVLEN); - offset += DEVLEN; - this.devMinor = (int) TarUtils.parseOctal(header, offset, DEVLEN); - } -} diff --git a/source/org/apache/tools/tar/TarInputStream.java b/source/org/apache/tools/tar/TarInputStream.java deleted file mode 100644 index 30365bbbe..000000000 --- a/source/org/apache/tools/tar/TarInputStream.java +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/* - * This package is based on the work done by Timothy Gerard Endres - * (time@ice.com) to whom the Ant project is very grateful for his great code. - */ -/* - * Modifications (Michael Christen) - * - replaced StringBuffer with StringBuilder - */ - -package org.apache.tools.tar; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * The TarInputStream reads a UNIX tar archive as an InputStream. - * methods are provided to position at each successive entry in - * the archive, and the read each entry as a normal input stream - * using read(). - * - */ -public class TarInputStream extends FilterInputStream { - private static final int SMALL_BUFFER_SIZE = 256; - private static final int BUFFER_SIZE = 8 * 1024; - private static final int LARGE_BUFFER_SIZE = 32 * 1024; - private static final int BYTE_MASK = 0xFF; - - // CheckStyle:VisibilityModifier OFF - bc - protected boolean debug; - protected boolean hasHitEOF; - protected long entrySize; - protected long entryOffset; - protected byte[] readBuf; - protected TarBuffer buffer; - protected TarEntry currEntry; - - /** - * This contents of this array is not used at all in this class, - * it is only here to avoid repreated object creation during calls - * to the no-arg read method. - */ - protected byte[] oneBuf; - - // CheckStyle:VisibilityModifier ON - - /** - * Constructor for TarInputStream. - * @param is the input stream to use - */ - public TarInputStream(InputStream is) { - this(is, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE); - } - - /** - * Constructor for TarInputStream. - * @param is the input stream to use - * @param blockSize the block size to use - */ - public TarInputStream(InputStream is, int blockSize) { - this(is, blockSize, TarBuffer.DEFAULT_RCDSIZE); - } - - /** - * Constructor for TarInputStream. - * @param is the input stream to use - * @param blockSize the block size to use - * @param recordSize the record size to use - */ - public TarInputStream(InputStream is, int blockSize, int recordSize) { - super(is); - - this.buffer = new TarBuffer(is, blockSize, recordSize); - this.readBuf = null; - this.oneBuf = new byte[1]; - this.debug = false; - this.hasHitEOF = false; - } - - /** - * Sets the debugging flag. - * - * @param debug True to turn on debugging. - */ - public void setDebug(boolean debug) { - this.debug = debug; - this.buffer.setDebug(debug); - } - - /** - * Closes this stream. Calls the TarBuffer's close() method. - * @throws IOException on error - */ - @Override - public synchronized void close() throws IOException { - this.buffer.close(); - } - - /** - * Get the record size being used by this stream's TarBuffer. - * - * @return The TarBuffer record size. - */ - public int getRecordSize() { - return this.buffer.getRecordSize(); - } - - /** - * Get the available data that can be read from the current - * entry in the archive. This does not indicate how much data - * is left in the entire archive, only in the current entry. - * This value is determined from the entry's size header field - * and the amount of data already read from the current entry. - * Integer.MAX_VALUE is returen in case more than Integer.MAX_VALUE - * bytes are left in the current entry in the archive. - * - * @return The number of available bytes for the current entry. - * @throws IOException for signature - */ - @Override - public int available() throws IOException { - if (this.entrySize - this.entryOffset > Integer.MAX_VALUE) { - return Integer.MAX_VALUE; - } - return (int) (this.entrySize - this.entryOffset); - } - - /** - * Skip bytes in the input buffer. This skips bytes in the - * current entry's data, not the entire archive, and will - * stop at the end of the current entry's data if the number - * to skip extends beyond that point. - * - * @param numToSkip The number of bytes to skip. - * @return the number actually skipped - * @throws IOException on error - */ - @Override - public long skip(long numToSkip) throws IOException { - // REVIEW - // This is horribly inefficient, but it ensures that we - // properly skip over bytes via the TarBuffer... - // - byte[] skipBuf = new byte[BUFFER_SIZE]; - long skip = numToSkip; - while (skip > 0) { - int realSkip = (int) (skip > skipBuf.length ? skipBuf.length : skip); - int numRead = this.read(skipBuf, 0, realSkip); - if (numRead == -1) { - break; - } - skip -= numRead; - } - return (numToSkip - skip); - } - - /** - * Since we do not support marking just yet, we return false. - * - * @return False. - */ - @Override - public boolean markSupported() { - return false; - } - - /** - * Since we do not support marking just yet, we do nothing. - * - * @param markLimit The limit to mark. - */ - @Override - public synchronized void mark(int markLimit) { - } - - /** - * Since we do not support marking just yet, we do nothing. - */ - @Override - public synchronized void reset() { - } - - /** - * Get the next entry in this tar archive. This will skip - * over any remaining data in the current entry, if there - * is one, and place the input stream at the header of the - * next entry, and read the header and instantiate a new - * TarEntry from the header bytes and return that entry. - * If there are no more entries in the archive, null will - * be returned to indicate that the end of the archive has - * been reached. - * - * @return The next TarEntry in the archive, or null. - * @throws IOException on error - */ - public TarEntry getNextEntry() throws IOException { - if (this.hasHitEOF) { - return null; - } - - if (this.currEntry != null) { - long numToSkip = this.entrySize - this.entryOffset; - - if (this.debug) { - System.err.println("TarInputStream: SKIP currENTRY '" - + this.currEntry.getName() + "' SZ " - + this.entrySize + " OFF " - + this.entryOffset + " skipping " - + numToSkip + " bytes"); - } - - if (numToSkip > 0) { - this.skip(numToSkip); - } - - this.readBuf = null; - } - - byte[] headerBuf = this.buffer.readRecord(); - - if (headerBuf == null) { - if (this.debug) { - System.err.println("READ NULL RECORD"); - } - this.hasHitEOF = true; - } else if (this.buffer.isEOFRecord(headerBuf)) { - if (this.debug) { - System.err.println("READ EOF RECORD"); - } - this.hasHitEOF = true; - } - - if (this.hasHitEOF) { - this.currEntry = null; - } else { - this.currEntry = new TarEntry(headerBuf); - - if (this.debug) { - System.err.println("TarInputStream: SET CURRENTRY '" - + this.currEntry.getName() - + "' size = " - + this.currEntry.getSize()); - } - - this.entryOffset = 0; - - this.entrySize = this.currEntry.getSize(); - } - - if (this.currEntry != null && this.currEntry.isGNULongNameEntry()) { - // read in the name - StringBuilder longName = new StringBuilder(); - byte[] buf = new byte[SMALL_BUFFER_SIZE]; - int length = 0; - while ((length = read(buf)) >= 0) { - longName.append(new String(buf, 0, length)); - } - getNextEntry(); - if (this.currEntry == null) { - // Bugzilla: 40334 - // Malformed tar file - long entry name not followed by entry - return null; - } - // remove trailing null terminator - if (longName.length() > 0 - && longName.charAt(longName.length() - 1) == 0) { - longName.deleteCharAt(longName.length() - 1); - } - this.currEntry.setName(longName.toString()); - } - - return this.currEntry; - } - - /** - * Reads a byte from the current tar archive entry. - * - * This method simply calls read( byte[], int, int ). - * - * @return The byte read, or -1 at EOF. - * @throws IOException on error - */ - @Override - public int read() throws IOException { - int num = this.read(this.oneBuf, 0, 1); - return num == -1 ? -1 : (this.oneBuf[0]) & BYTE_MASK; - } - - /** - * Reads bytes from the current tar archive entry. - * - * This method is aware of the boundaries of the current - * entry in the archive and will deal with them as if they - * were this stream's start and EOF. - * - * @param buf The buffer into which to place bytes read. - * @param offset The offset at which to place bytes read. - * @param numToRead The number of bytes to read. - * @return The number of bytes read, or -1 at EOF. - * @throws IOException on error - */ - @Override - public int read(byte[] buf, int offset, int numToRead) throws IOException { - int totalRead = 0; - - if (this.entryOffset >= this.entrySize) { - return -1; - } - - if ((numToRead + this.entryOffset) > this.entrySize) { - numToRead = (int) (this.entrySize - this.entryOffset); - } - - if (this.readBuf != null) { - int sz = (numToRead > this.readBuf.length) ? this.readBuf.length - : numToRead; - - System.arraycopy(this.readBuf, 0, buf, offset, sz); - - if (sz >= this.readBuf.length) { - this.readBuf = null; - } else { - int newLen = this.readBuf.length - sz; - byte[] newBuf = new byte[newLen]; - - System.arraycopy(this.readBuf, sz, newBuf, 0, newLen); - - this.readBuf = newBuf; - } - - totalRead += sz; - numToRead -= sz; - offset += sz; - } - - while (numToRead > 0) { - byte[] rec = this.buffer.readRecord(); - - if (rec == null) { - // Unexpected EOF! - throw new IOException("unexpected EOF with " + numToRead - + " bytes unread"); - } - - int sz = numToRead; - int recLen = rec.length; - - if (recLen > sz) { - System.arraycopy(rec, 0, buf, offset, sz); - - this.readBuf = new byte[recLen - sz]; - - System.arraycopy(rec, sz, this.readBuf, 0, recLen - sz); - } else { - sz = recLen; - - System.arraycopy(rec, 0, buf, offset, recLen); - } - - totalRead += sz; - numToRead -= sz; - offset += sz; - } - - this.entryOffset += totalRead; - - return totalRead; - } - - /** - * Copies the contents of the current tar archive entry directly into - * an output stream. - * - * @param out The OutputStream into which to write the entry's data. - * @throws IOException on error - */ - public void copyEntryContents(OutputStream out) throws IOException { - byte[] buf = new byte[LARGE_BUFFER_SIZE]; - - while (true) { - int numRead = this.read(buf, 0, buf.length); - - if (numRead == -1) { - break; - } - - out.write(buf, 0, numRead); - } - } -} diff --git a/source/org/apache/tools/tar/TarOutputStream.java b/source/org/apache/tools/tar/TarOutputStream.java deleted file mode 100644 index c7afda383..000000000 --- a/source/org/apache/tools/tar/TarOutputStream.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/* - * This package is based on the work done by Timothy Gerard Endres - * (time@ice.com) to whom the Ant project is very grateful for his great code. - */ - -package org.apache.tools.tar; - -import java.io.FilterOutputStream; -import java.io.OutputStream; -import java.io.IOException; - -/** - * The TarOutputStream writes a UNIX tar archive as an OutputStream. - * Methods are provided to put entries, and then write their contents - * by writing to this stream using write(). - * - */ -public class TarOutputStream extends FilterOutputStream { - /** Fail if a long file name is required in the archive. */ - public static final int LONGFILE_ERROR = 0; - - /** Long paths will be truncated in the archive. */ - public static final int LONGFILE_TRUNCATE = 1; - - /** GNU tar extensions are used to store long file names in the archive. */ - public static final int LONGFILE_GNU = 2; - - // CheckStyle:VisibilityModifier OFF - bc - protected boolean debug; - protected long currSize; - protected String currName; - protected long currBytes; - protected byte[] oneBuf; - protected byte[] recordBuf; - protected int assemLen; - protected byte[] assemBuf; - protected TarBuffer buffer; - protected int longFileMode = LONGFILE_ERROR; - // CheckStyle:VisibilityModifier ON - - private boolean closed = false; - - /** - * Constructor for TarInputStream. - * @param os the output stream to use - */ - public TarOutputStream(OutputStream os) { - this(os, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE); - } - - /** - * Constructor for TarInputStream. - * @param os the output stream to use - * @param blockSize the block size to use - */ - public TarOutputStream(OutputStream os, int blockSize) { - this(os, blockSize, TarBuffer.DEFAULT_RCDSIZE); - } - - /** - * Constructor for TarInputStream. - * @param os the output stream to use - * @param blockSize the block size to use - * @param recordSize the record size to use - */ - public TarOutputStream(OutputStream os, int blockSize, int recordSize) { - super(os); - - this.buffer = new TarBuffer(os, blockSize, recordSize); - this.debug = false; - this.assemLen = 0; - this.assemBuf = new byte[recordSize]; - this.recordBuf = new byte[recordSize]; - this.oneBuf = new byte[1]; - } - - /** - * Set the long file mode. - * This can be LONGFILE_ERROR(0), LONGFILE_TRUNCATE(1) or LONGFILE_GNU(2). - * This specifies the treatment of long file names (names >= TarConstants.NAMELEN). - * Default is LONGFILE_ERROR. - * @param longFileMode the mode to use - */ - public void setLongFileMode(int longFileMode) { - this.longFileMode = longFileMode; - } - - - /** - * Sets the debugging flag. - * - * @param debugF True to turn on debugging. - */ - public void setDebug(boolean debugF) { - this.debug = debugF; - } - - /** - * Sets the debugging flag in this stream's TarBuffer. - * - * @param debug True to turn on debugging. - */ - public void setBufferDebug(boolean debug) { - this.buffer.setDebug(debug); - } - - /** - * Ends the TAR archive without closing the underlying OutputStream. - * The result is that the two EOF records of nulls are written. - * @throws IOException on error - */ - public void finish() throws IOException { - // See Bugzilla 28776 for a discussion on this - // http://issues.apache.org/bugzilla/show_bug.cgi?id=28776 - this.writeEOFRecord(); - this.writeEOFRecord(); - } - - /** - * Ends the TAR archive and closes the underlying OutputStream. - * This means that finish() is called followed by calling the - * TarBuffer's close(). - * @throws IOException on error - */ - @Override - public synchronized void close() throws IOException { - if (!closed) { - this.finish(); - this.buffer.close(); - out.close(); - closed = true; - } - } - - /** - * Get the record size being used by this stream's TarBuffer. - * - * @return The TarBuffer record size. - */ - public int getRecordSize() { - return this.buffer.getRecordSize(); - } - - /** - * Put an entry on the output stream. This writes the entry's - * header record and positions the output stream for writing - * the contents of the entry. Once this method is called, the - * stream is ready for calls to write() to write the entry's - * contents. Once the contents are written, closeEntry() - * MUST be called to ensure that all buffered data - * is completely written to the output stream. - * - * @param entry The TarEntry to be written to the archive. - * @throws IOException on error - */ - public void putNextEntry(TarEntry entry) throws IOException { - if (entry.getName().length() >= TarConstants.NAMELEN) { - - if (longFileMode == LONGFILE_GNU) { - // create a TarEntry for the LongLink, the contents - // of which are the entry's name - TarEntry longLinkEntry = new TarEntry(TarConstants.GNU_LONGLINK, - TarConstants.LF_GNUTYPE_LONGNAME); - - longLinkEntry.setSize(entry.getName().length() + 1); - putNextEntry(longLinkEntry); - write(entry.getName().getBytes()); - write(0); - closeEntry(); - } else if (longFileMode != LONGFILE_TRUNCATE) { - throw new RuntimeException("file name '" + entry.getName() - + "' is too long ( > " - + TarConstants.NAMELEN + " bytes)"); - } - } - - entry.writeEntryHeader(this.recordBuf); - this.buffer.writeRecord(this.recordBuf); - - this.currBytes = 0; - - if (entry.isDirectory()) { - this.currSize = 0; - } else { - this.currSize = entry.getSize(); - } - currName = entry.getName(); - } - - /** - * Close an entry. This method MUST be called for all file - * entries that contain data. The reason is that we must - * buffer data written to the stream in order to satisfy - * the buffer's record based writes. Thus, there may be - * data fragments still being assembled that must be written - * to the output stream before this entry is closed and the - * next entry written. - * @throws IOException on error - */ - public void closeEntry() throws IOException { - if (this.assemLen > 0) { - for (int i = this.assemLen; i < this.assemBuf.length; ++i) { - this.assemBuf[i] = 0; - } - - this.buffer.writeRecord(this.assemBuf); - - this.currBytes += this.assemLen; - this.assemLen = 0; - } - - if (this.currBytes < this.currSize) { - throw new IOException("entry '" + currName + "' closed at '" - + this.currBytes - + "' before the '" + this.currSize - + "' bytes specified in the header were written"); - } - } - - /** - * Writes a byte to the current tar archive entry. - * - * This method simply calls read( byte[], int, int ). - * - * @param b The byte written. - * @throws IOException on error - */ - @Override - public void write(int b) throws IOException { - this.oneBuf[0] = (byte) b; - - this.write(this.oneBuf, 0, 1); - } - - /** - * Writes bytes to the current tar archive entry. - * - * This method simply calls write( byte[], int, int ). - * - * @param wBuf The buffer to write to the archive. - * @throws IOException on error - */ - @Override - public void write(byte[] wBuf) throws IOException { - this.write(wBuf, 0, wBuf.length); - } - - /** - * Writes bytes to the current tar archive entry. This method - * is aware of the current entry and will throw an exception if - * you attempt to write bytes past the length specified for the - * current entry. The method is also (painfully) aware of the - * record buffering required by TarBuffer, and manages buffers - * that are not a multiple of recordsize in length, including - * assembling records from small buffers. - * - * @param wBuf The buffer to write to the archive. - * @param wOffset The offset in the buffer from which to get bytes. - * @param numToWrite The number of bytes to write. - * @throws IOException on error - */ - @Override - public void write(byte[] wBuf, int wOffset, int numToWrite) throws IOException { - if ((this.currBytes + numToWrite) > this.currSize) { - throw new IOException("request to write '" + numToWrite - + "' bytes exceeds size in header of '" - + this.currSize + "' bytes for entry '" - + currName + "'"); - - // - // We have to deal with assembly!!! - // The programmer can be writing little 32 byte chunks for all - // we know, and we must assemble complete records for writing. - // REVIEW Maybe this should be in TarBuffer? Could that help to - // eliminate some of the buffer copying. - // - } - - if (this.assemLen > 0) { - if ((this.assemLen + numToWrite) >= this.recordBuf.length) { - int aLen = this.recordBuf.length - this.assemLen; - - System.arraycopy(this.assemBuf, 0, this.recordBuf, 0, - this.assemLen); - System.arraycopy(wBuf, wOffset, this.recordBuf, - this.assemLen, aLen); - this.buffer.writeRecord(this.recordBuf); - - this.currBytes += this.recordBuf.length; - wOffset += aLen; - numToWrite -= aLen; - this.assemLen = 0; - } else { - System.arraycopy(wBuf, wOffset, this.assemBuf, this.assemLen, - numToWrite); - - wOffset += numToWrite; - this.assemLen += numToWrite; - numToWrite -= numToWrite; - } - } - - // - // When we get here we have EITHER: - // o An empty "assemble" buffer. - // o No bytes to write (numToWrite == 0) - // - while (numToWrite > 0) { - if (numToWrite < this.recordBuf.length) { - System.arraycopy(wBuf, wOffset, this.assemBuf, this.assemLen, - numToWrite); - - this.assemLen += numToWrite; - - break; - } - - this.buffer.writeRecord(wBuf, wOffset); - - int num = this.recordBuf.length; - - this.currBytes += num; - numToWrite -= num; - wOffset += num; - } - } - - /** - * Write an EOF (end of archive) record to the tar archive. - * An EOF record consists of a record of all zeros. - */ - private void writeEOFRecord() throws IOException { - for (int i = 0; i < this.recordBuf.length; ++i) { - this.recordBuf[i] = 0; - } - - this.buffer.writeRecord(this.recordBuf); - } -} - - diff --git a/source/org/apache/tools/tar/TarUtils.java b/source/org/apache/tools/tar/TarUtils.java deleted file mode 100644 index 68636e6a8..000000000 --- a/source/org/apache/tools/tar/TarUtils.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/* - * This package is based on the work done by Timothy Gerard Endres - * (time@ice.com) to whom the Ant project is very grateful for his great code. - */ -/* - * Modifications (Michael Christen) - * - replaced StringBuffer with StringBuilder - */ - -package org.apache.tools.tar; - -/** - * This class provides static utility methods to work with byte streams. - * - */ -// CheckStyle:HideUtilityClassConstructorCheck OFF (bc) -public class TarUtils { - - private static final int BYTE_MASK = 255; - - /** - * Parse an octal string from a header buffer. This is used for the - * file permission mode value. - * - * @param header The header buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The number of header bytes to parse. - * @return The long value of the octal string. - */ - public static long parseOctal(byte[] header, int offset, int length) { - long result = 0; - boolean stillPadding = true; - int end = offset + length; - - for (int i = offset; i < end; ++i) { - if (header[i] == 0) { - break; - } - - if (header[i] == (byte) ' ' || header[i] == '0') { - if (stillPadding) { - continue; - } - - if (header[i] == (byte) ' ') { - break; - } - } - - stillPadding = false; - // CheckStyle:MagicNumber OFF - result = (result << 3) + (header[i] - '0'); - // CheckStyle:MagicNumber ON - } - - return result; - } - - /** - * Parse an entry name from a header buffer. - * - * @param header The header buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The number of header bytes to parse. - * @return The header's entry name. - */ - public static StringBuilder parseName(byte[] header, int offset, int length) { - StringBuilder result = new StringBuilder(length); - int end = offset + length; - - for (int i = offset; i < end; ++i) { - if (header[i] == 0) { - break; - } - - result.append((char) header[i]); - } - - return result; - } - - /** - * Determine the number of bytes in an entry name. - * - * @param name The header name from which to parse. - * @param buf The buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The number of header bytes to parse. - * @return The number of bytes in a header's entry name. - */ - public static int getNameBytes(StringBuilder name, byte[] buf, int offset, int length) { - int i; - - for (i = 0; i < length && i < name.length(); ++i) { - buf[offset + i] = (byte) name.charAt(i); - } - - for (; i < length; ++i) { - buf[offset + i] = 0; - } - - return offset + length; - } - - /** - * Parse an octal integer from a header buffer. - * - * @param value The header value - * @param buf The buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The number of header bytes to parse. - * @return The integer value of the octal bytes. - */ - public static int getOctalBytes(long value, byte[] buf, int offset, int length) { - int idx = length - 1; - - buf[offset + idx] = 0; - --idx; - buf[offset + idx] = (byte) ' '; - --idx; - - if (value == 0) { - buf[offset + idx] = (byte) '0'; - --idx; - } else { - for (long val = value; idx >= 0 && val > 0; --idx) { - // CheckStyle:MagicNumber OFF - buf[offset + idx] = (byte) ((byte) '0' + (byte) (val & 7)); - val = val >> 3; - // CheckStyle:MagicNumber ON - } - } - - for (; idx >= 0; --idx) { - buf[offset + idx] = (byte) ' '; - } - - return offset + length; - } - - /** - * Parse an octal long integer from a header buffer. - * - * @param value The header value - * @param buf The buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The number of header bytes to parse. - * @return The long value of the octal bytes. - */ - public static int getLongOctalBytes(long value, byte[] buf, int offset, int length) { - byte[] temp = new byte[length + 1]; - - getOctalBytes(value, temp, 0, length + 1); - System.arraycopy(temp, 0, buf, offset, length); - - return offset + length; - } - - /** - * Parse the checksum octal integer from a header buffer. - * - * @param value The header value - * @param buf The buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The number of header bytes to parse. - * @return The integer value of the entry's checksum. - */ - public static int getCheckSumOctalBytes(long value, byte[] buf, int offset, int length) { - getOctalBytes(value, buf, offset, length); - - buf[offset + length - 1] = (byte) ' '; - buf[offset + length - 2] = 0; - - return offset + length; - } - - /** - * Compute the checksum of a tar entry header. - * - * @param buf The tar entry's header buffer. - * @return The computed checksum. - */ - public static long computeCheckSum(byte[] buf) { - long sum = 0; - - for (int i = 0; i < buf.length; ++i) { - sum += BYTE_MASK & buf[i]; - } - - return sum; - } -}