git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267567 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -1,43 +0,0 @@ | |||||
| /* | |||||
| ** Copyright (c) 1998 by Timothy Gerard Endres | |||||
| ** <mailto:time@ice.com> <http://www.ice.com> | |||||
| ** | |||||
| ** This package is free software. | |||||
| ** | |||||
| ** You may redistribute it and/or modify it under the terms of the GNU | |||||
| ** General Public License as published by the Free Software Foundation. | |||||
| ** Version 2 of the license should be included with this distribution in | |||||
| ** the file LICENSE, as well as License.html. If the license is not | |||||
| ** included with this distribution, you may find a copy at the FSF web | |||||
| ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the | |||||
| ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA. | |||||
| ** | |||||
| ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, | |||||
| ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR | |||||
| ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY | |||||
| ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR | |||||
| ** REDISTRIBUTION OF THIS SOFTWARE. | |||||
| ** | |||||
| */ | |||||
| package com.ice.tar; | |||||
| public class | |||||
| InvalidHeaderException extends Exception | |||||
| { | |||||
| public | |||||
| InvalidHeaderException() | |||||
| { | |||||
| super(); | |||||
| } | |||||
| public | |||||
| InvalidHeaderException( String msg ) | |||||
| { | |||||
| super( msg ); | |||||
| } | |||||
| } | |||||
| @@ -1,472 +0,0 @@ | |||||
| /* | |||||
| ** Copyright (c) 1998 by Timothy Gerard Endres | |||||
| ** <mailto:time@ice.com> <http://www.ice.com> | |||||
| ** | |||||
| ** This package is free software. | |||||
| ** | |||||
| ** You may redistribute it and/or modify it under the terms of the GNU | |||||
| ** General Public License as published by the Free Software Foundation. | |||||
| ** Version 2 of the license should be included with this distribution in | |||||
| ** the file LICENSE, as well as License.html. If the license is not | |||||
| ** included with this distribution, you may find a copy at the FSF web | |||||
| ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the | |||||
| ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA. | |||||
| ** | |||||
| ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, | |||||
| ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR | |||||
| ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY | |||||
| ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR | |||||
| ** REDISTRIBUTION OF THIS SOFTWARE. | |||||
| ** | |||||
| */ | |||||
| package com.ice.tar; | |||||
| import java.io.*; | |||||
| /** | |||||
| * The TarArchive class implements the concept of a | |||||
| * tar archive. A tar archive is a series of entries, each of | |||||
| * which represents a file system object. Each entry in | |||||
| * the archive consists of a header record. Directory entries | |||||
| * consist only of the header record, and are followed by entries | |||||
| * for the directory's contents. File entries consist of a | |||||
| * header record followed by the number of records needed to | |||||
| * contain the file's contents. All entries are written on | |||||
| * record boundaries. Records are 512 bytes long. | |||||
| * | |||||
| * TarArchives are instantiated in either read or write mode, | |||||
| * based upon whether they are instantiated with an InputStream | |||||
| * or an OutputStream. Once instantiated TarArchives read/write | |||||
| * mode can not be changed. | |||||
| * | |||||
| * There is currently no support for random access to tar archives. | |||||
| * However, it seems that subclassing TarArchive, and using the | |||||
| * TarBuffer.getCurrentRecordNum() and TarBuffer.getCurrentBlockNum() | |||||
| * methods, this would be rather trvial. | |||||
| * | |||||
| * @version $Revision$ | |||||
| * @author Timothy Gerard Endres, | |||||
| * <a href="mailto:time@ice.com">time@ice.com</a>. | |||||
| * @see TarBuffer | |||||
| * @see TarHeader | |||||
| * @see TarEntry | |||||
| */ | |||||
| public class | |||||
| TarArchive extends Object | |||||
| { | |||||
| public static final int RECORDSIZE = 512; | |||||
| protected boolean verbose; | |||||
| protected boolean debug; | |||||
| protected boolean keepOldFiles; | |||||
| protected int userId; | |||||
| protected String userName; | |||||
| protected int groupId; | |||||
| protected String groupName; | |||||
| protected String pathPrefix; | |||||
| protected int recordSize; | |||||
| protected byte[] recordBuf; | |||||
| protected TarBuffer buffer; | |||||
| protected TarProgressDisplay progressDisplay; | |||||
| public | |||||
| TarArchive( InputStream inStream ) | |||||
| { | |||||
| this( inStream, TarBuffer.DEFAULT_BLKSIZE ); | |||||
| } | |||||
| public | |||||
| TarArchive( InputStream inStream, int blockSize ) | |||||
| { | |||||
| this( inStream, blockSize, TarArchive.RECORDSIZE ); | |||||
| } | |||||
| public | |||||
| TarArchive( InputStream inStream, int blockSize, int recordSize ) | |||||
| { | |||||
| this.initialize( recordSize ); | |||||
| this.buffer = new TarBuffer( this, inStream, blockSize ); | |||||
| } | |||||
| public | |||||
| TarArchive( OutputStream outStream ) | |||||
| { | |||||
| this( outStream, TarBuffer.DEFAULT_BLKSIZE ); | |||||
| } | |||||
| public | |||||
| TarArchive( OutputStream outStream, int blockSize ) | |||||
| { | |||||
| this( outStream, blockSize, TarArchive.RECORDSIZE ); | |||||
| } | |||||
| public | |||||
| TarArchive( OutputStream outStream, int blockSize, int recordSize ) | |||||
| { | |||||
| this.initialize( recordSize ); | |||||
| this.buffer = new TarBuffer( this, outStream, blockSize ); | |||||
| } | |||||
| public void | |||||
| initialize( int recordSize ) | |||||
| { | |||||
| this.pathPrefix = null; | |||||
| this.recordSize = recordSize; | |||||
| this.recordBuf = new byte[ recordSize ]; | |||||
| this.userId = 0; | |||||
| this.userName = ""; | |||||
| this.groupId = 0; | |||||
| this.groupName = ""; | |||||
| this.debug = false; | |||||
| this.verbose = false; | |||||
| this.keepOldFiles = false; | |||||
| this.progressDisplay = null; | |||||
| } | |||||
| public void | |||||
| setDebug( boolean debugF ) | |||||
| { | |||||
| this.debug = debugF; | |||||
| } | |||||
| public void | |||||
| setBufferDebug( boolean debug ) | |||||
| { | |||||
| this.buffer.setDebug( debug ); | |||||
| } | |||||
| public boolean | |||||
| isVerbose() | |||||
| { | |||||
| return this.verbose; | |||||
| } | |||||
| public void | |||||
| setVerbose( boolean verbose ) | |||||
| { | |||||
| this.verbose = verbose; | |||||
| } | |||||
| public void | |||||
| setTarProgressDisplay( TarProgressDisplay display ) | |||||
| { | |||||
| this.progressDisplay = display; | |||||
| } | |||||
| public void | |||||
| setKeepOldFiles( boolean keepOldFiles ) | |||||
| { | |||||
| this.keepOldFiles = keepOldFiles; | |||||
| } | |||||
| public void | |||||
| setUserInfo( | |||||
| int userId, String userName, | |||||
| int groupId, String groupName ) | |||||
| { | |||||
| this.userId = userId; | |||||
| this.userName = userName; | |||||
| this.groupId = groupId; | |||||
| this.groupName = groupName; | |||||
| } | |||||
| public int | |||||
| getUserId() | |||||
| { | |||||
| return this.userId; | |||||
| } | |||||
| public String | |||||
| getUserName() | |||||
| { | |||||
| return this.userName; | |||||
| } | |||||
| public int | |||||
| getGroupId() | |||||
| { | |||||
| return this.groupId; | |||||
| } | |||||
| public String | |||||
| getGroupName() | |||||
| { | |||||
| return this.groupName; | |||||
| } | |||||
| public void | |||||
| closeArchive() | |||||
| throws IOException | |||||
| { | |||||
| this.buffer.flushBlock(); | |||||
| this.buffer.closeBuffer(); | |||||
| } | |||||
| public int | |||||
| getRecordSize() | |||||
| { | |||||
| return this.recordSize; | |||||
| } | |||||
| public TarEntry | |||||
| parseArchive() | |||||
| { | |||||
| return null; | |||||
| } | |||||
| public TarEntry | |||||
| parseEntry() | |||||
| { | |||||
| return null; | |||||
| } | |||||
| public void | |||||
| extractArchive() | |||||
| { | |||||
| } | |||||
| public void | |||||
| listContents() | |||||
| throws IOException, InvalidHeaderException | |||||
| { | |||||
| TarEntry entry; | |||||
| byte[] headerBuf; | |||||
| for ( ; ; ) | |||||
| { | |||||
| headerBuf = this.buffer.readRecord(); | |||||
| if ( headerBuf == null ) | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println( "READ NULL RECORD" ); | |||||
| } | |||||
| break; | |||||
| } | |||||
| if ( this.isEOFRecord( headerBuf ) ) | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println( "READ EOF RECORD" ); | |||||
| } | |||||
| break; | |||||
| } | |||||
| try { | |||||
| entry = new TarEntry( this, headerBuf ); | |||||
| } | |||||
| catch ( InvalidHeaderException ex ) | |||||
| { | |||||
| throw new InvalidHeaderException | |||||
| ( "bad header in block " | |||||
| + this.buffer.getCurrentBlockNum() | |||||
| + " record " | |||||
| + this.buffer.getCurrentRecordNum() ); | |||||
| } | |||||
| if ( this.progressDisplay != null ) | |||||
| this.progressDisplay.showTarProgressMessage | |||||
| ( entry.getName() ); | |||||
| this.buffer.skipBytes( (int)entry.getSize() ); | |||||
| } | |||||
| } | |||||
| public void | |||||
| extractContents( File destDir ) | |||||
| throws IOException, InvalidHeaderException | |||||
| { | |||||
| TarEntry entry; | |||||
| byte[] headerBuf; | |||||
| for ( ; ; ) | |||||
| { | |||||
| headerBuf = this.buffer.readRecord(); | |||||
| if ( headerBuf == null ) | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println( "READ NULL RECORD" ); | |||||
| } | |||||
| break; | |||||
| } | |||||
| if ( this.isEOFRecord( headerBuf ) ) | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println( "READ EOF RECORD" ); | |||||
| } | |||||
| break; | |||||
| } | |||||
| try { | |||||
| entry = new TarEntry( this, headerBuf ); | |||||
| } | |||||
| catch ( InvalidHeaderException ex ) | |||||
| { | |||||
| throw new InvalidHeaderException | |||||
| ( "bad header in block " | |||||
| + this.buffer.getCurrentBlockNum() | |||||
| + " record " | |||||
| + this.buffer.getCurrentRecordNum() ); | |||||
| } | |||||
| this.extractEntry( destDir, entry ); | |||||
| } | |||||
| } | |||||
| public void | |||||
| extractEntry( File destDir, TarEntry entry ) | |||||
| throws IOException | |||||
| { | |||||
| if ( this.verbose ) | |||||
| { | |||||
| if ( this.progressDisplay != null ) | |||||
| this.progressDisplay.showTarProgressMessage | |||||
| ( entry.getName() ); | |||||
| } | |||||
| File subDir = | |||||
| new File( destDir, entry.getName() ); | |||||
| if ( entry.isDirectory() ) | |||||
| { | |||||
| if ( ! subDir.exists() ) | |||||
| { | |||||
| if ( ! subDir.mkdirs() ) | |||||
| { | |||||
| throw new IOException | |||||
| ( "error making directory path '" | |||||
| + subDir.getPath() + "'" ); | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| String name = entry.getName().toString(); | |||||
| name = name.replace( '/', File.separatorChar ); | |||||
| File destFile = new File( destDir, name ); | |||||
| if ( this.keepOldFiles && destFile.exists() ) | |||||
| { | |||||
| if ( this.verbose ) | |||||
| { | |||||
| if ( this.progressDisplay != null ) | |||||
| this.progressDisplay.showTarProgressMessage | |||||
| ( "not overwriting " + entry.getName() ); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| FileOutputStream out = | |||||
| new FileOutputStream( destFile ); | |||||
| for ( int num = (int)entry.getSize() ; num > 0 ; ) | |||||
| { | |||||
| byte[] record = this.buffer.readRecord(); | |||||
| int wNum = | |||||
| ( num < record.length ) | |||||
| ? num : record.length; | |||||
| out.write( record, 0, wNum ); | |||||
| num -= wNum; | |||||
| } | |||||
| out.close(); | |||||
| } | |||||
| } | |||||
| } | |||||
| public boolean | |||||
| isEOFRecord( byte[] record ) | |||||
| { | |||||
| for ( int i = 0 ; i < this.recordSize ; ++i ) | |||||
| if ( record[i] != 0 ) | |||||
| return false; | |||||
| return true; | |||||
| } | |||||
| public void | |||||
| writeEOFRecord() | |||||
| throws IOException | |||||
| { | |||||
| for ( int i = 0 ; i < this.recordSize ; ++i ) | |||||
| this.recordBuf[i] = 0; | |||||
| this.buffer.writeRecord( this.recordBuf ); | |||||
| } | |||||
| public void | |||||
| writeEntry( TarEntry entry, boolean recurse ) | |||||
| throws IOException | |||||
| { | |||||
| if ( this.verbose ) | |||||
| { | |||||
| if ( this.progressDisplay != null ) | |||||
| this.progressDisplay.showTarProgressMessage | |||||
| ( entry.getName() ); | |||||
| } | |||||
| entry.writeEntryHeader( this.recordBuf ); | |||||
| this.buffer.writeRecord( this.recordBuf ); | |||||
| if ( entry.isDirectory() ) | |||||
| { | |||||
| TarEntry[] list = entry.getDirectoryEntries(); | |||||
| for ( int i = 0 ; i < list.length ; ++i ) | |||||
| { | |||||
| this.writeEntry( list[i], recurse ); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| entry.writeEntryContents( this.buffer ); | |||||
| } | |||||
| } | |||||
| public TarEntry | |||||
| readEntry() | |||||
| throws IOException, InvalidHeaderException | |||||
| { | |||||
| TarEntry result = null; | |||||
| byte[] header = this.readRecord(); | |||||
| TarEntry entry = new TarEntry( this, header ); | |||||
| return entry; | |||||
| } | |||||
| public byte[] | |||||
| readRecord() | |||||
| throws IOException | |||||
| { | |||||
| return this.buffer.readRecord(); | |||||
| } | |||||
| public void | |||||
| writeRecord( byte[] record ) | |||||
| throws IOException | |||||
| { | |||||
| this.buffer.writeRecord( record ); | |||||
| } | |||||
| } | |||||
| @@ -1,331 +0,0 @@ | |||||
| /* | |||||
| ** Copyright (c) 1998 by Timothy Gerard Endres | |||||
| ** <mailto:time@ice.com> <http://www.ice.com> | |||||
| ** | |||||
| ** This package is free software. | |||||
| ** | |||||
| ** You may redistribute it and/or modify it under the terms of the GNU | |||||
| ** General Public License as published by the Free Software Foundation. | |||||
| ** Version 2 of the license should be included with this distribution in | |||||
| ** the file LICENSE, as well as License.html. If the license is not | |||||
| ** included with this distribution, you may find a copy at the FSF web | |||||
| ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the | |||||
| ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA. | |||||
| ** | |||||
| ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, | |||||
| ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR | |||||
| ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY | |||||
| ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR | |||||
| ** REDISTRIBUTION OF THIS SOFTWARE. | |||||
| ** | |||||
| */ | |||||
| package com.ice.tar; | |||||
| import java.io.*; | |||||
| /** | |||||
| * 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. | |||||
| * <p> | |||||
| * You should never have a need to access this class directly. | |||||
| * TarBuffers are created by TarArchives, which in turn provide | |||||
| * several methods to allow you access to the buffer. | |||||
| * | |||||
| * @version $Revision$ | |||||
| * @author Timothy Gerard Endres, | |||||
| * <a href="mailto:time@ice.com">time@ice.com</a>. | |||||
| * @see TarArchive | |||||
| */ | |||||
| public class | |||||
| TarBuffer extends Object | |||||
| { | |||||
| public static final int DEFAULT_BLKSIZE = ( 512 * 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; | |||||
| public | |||||
| TarBuffer( TarArchive archive, InputStream inStream ) | |||||
| { | |||||
| this( archive, inStream, TarBuffer.DEFAULT_BLKSIZE ); | |||||
| } | |||||
| public | |||||
| TarBuffer( TarArchive archive, InputStream inStream, int blockSize ) | |||||
| { | |||||
| this.inStream = inStream; | |||||
| this.outStream = null; | |||||
| this.initialize( archive, blockSize ); | |||||
| } | |||||
| public | |||||
| TarBuffer( TarArchive archive, OutputStream outStream ) | |||||
| { | |||||
| this( archive, outStream, TarBuffer.DEFAULT_BLKSIZE ); | |||||
| } | |||||
| public | |||||
| TarBuffer( TarArchive archive, OutputStream outStream, int blockSize ) | |||||
| { | |||||
| this.inStream = null; | |||||
| this.outStream = outStream; | |||||
| this.initialize( archive, blockSize ); | |||||
| } | |||||
| public void | |||||
| initialize( TarArchive archive, int blockSize ) | |||||
| { | |||||
| this.debug = false; | |||||
| this.blockSize = blockSize; | |||||
| this.recordSize = archive.getRecordSize(); | |||||
| this.recsPerBlock = ( this.blockSize / this.recordSize ); | |||||
| this.blockBuffer = new byte[ this.blockSize ]; | |||||
| if ( inStream != null ) | |||||
| { | |||||
| this.currBlkIdx = -1; | |||||
| this.currRecIdx = this.recsPerBlock; | |||||
| } | |||||
| else | |||||
| { | |||||
| this.currBlkIdx = 0; | |||||
| this.currRecIdx = 0; | |||||
| } | |||||
| } | |||||
| public void | |||||
| setDebug( boolean debug ) | |||||
| { | |||||
| this.debug = debug; | |||||
| } | |||||
| public void | |||||
| skipBytes( int bytes ) | |||||
| { | |||||
| for ( int num = bytes ; num > 0 ; ) | |||||
| { | |||||
| try { this.skipRecord(); } | |||||
| catch ( IOException ex ) | |||||
| { | |||||
| break; | |||||
| } | |||||
| num -= this.recordSize; | |||||
| } | |||||
| } | |||||
| public void | |||||
| skipRecord() | |||||
| throws IOException | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println | |||||
| ( "SkipRecord: recIdx = " + this.currRecIdx | |||||
| + " blkIdx = " + this.currBlkIdx ); | |||||
| } | |||||
| if ( this.currRecIdx >= this.recsPerBlock ) | |||||
| { | |||||
| if ( ! this.readBlock() ) | |||||
| return; // UNDONE | |||||
| } | |||||
| this.currRecIdx++; | |||||
| } | |||||
| public byte[] | |||||
| readRecord() | |||||
| throws IOException | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println | |||||
| ( "ReadRecord: recIdx = " + this.currRecIdx | |||||
| + " blkIdx = " + this.currBlkIdx ); | |||||
| } | |||||
| 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 | |||||
| */ | |||||
| public boolean | |||||
| readBlock() | |||||
| throws IOException | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println | |||||
| ( "ReadBlock: blkIdx = " + this.currBlkIdx ); | |||||
| } | |||||
| if ( this.inStream == null ) | |||||
| throw new IOException( "input stream is null" ); | |||||
| this.currRecIdx = 0; | |||||
| int offset = 0; | |||||
| int bytesNeeded = this.blockSize; | |||||
| for ( ; bytesNeeded > 0 ; ) | |||||
| { | |||||
| long numBytes = | |||||
| this.inStream.read | |||||
| ( this.blockBuffer, offset, bytesNeeded ); | |||||
| if ( numBytes == -1 ) | |||||
| return false; | |||||
| 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; | |||||
| } | |||||
| public int | |||||
| getCurrentBlockNum() | |||||
| { | |||||
| return this.currBlkIdx; | |||||
| } | |||||
| public int | |||||
| getCurrentRecordNum() | |||||
| { | |||||
| return this.currRecIdx - 1; | |||||
| } | |||||
| public void | |||||
| writeRecord( byte[] record ) | |||||
| throws IOException | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println | |||||
| ( "WriteRecord: recIdx = " + this.currRecIdx | |||||
| + " blkIdx = " + this.currBlkIdx ); | |||||
| } | |||||
| if ( this.currRecIdx >= this.recsPerBlock ) | |||||
| { | |||||
| this.writeBlock(); | |||||
| } | |||||
| System.arraycopy( | |||||
| record, 0, | |||||
| this.blockBuffer, (this.currRecIdx * this.recordSize), | |||||
| this.recordSize ); | |||||
| this.currRecIdx++; | |||||
| } | |||||
| public void | |||||
| writeBlock() | |||||
| throws IOException | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println | |||||
| ( "WriteBlock: blkIdx = " + this.currBlkIdx ); | |||||
| } | |||||
| if ( this.outStream == null ) | |||||
| throw new IOException( "output stream is null" ); | |||||
| this.outStream.write( this.blockBuffer, 0, this.blockSize ); | |||||
| this.currRecIdx = 0; | |||||
| this.currBlkIdx++; | |||||
| } | |||||
| public void | |||||
| flushBlock() | |||||
| throws IOException | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println( "TarBuffer.flushBlock() called." ); | |||||
| } | |||||
| if ( this.outStream != null ) | |||||
| { | |||||
| if ( this.currRecIdx > 0 ) | |||||
| { | |||||
| this.writeBlock(); | |||||
| } | |||||
| } | |||||
| } | |||||
| public void | |||||
| closeBuffer() | |||||
| throws IOException | |||||
| { | |||||
| if ( this.debug ) | |||||
| { | |||||
| System.err.println( "TarBuffer.closeBuffer()." ); | |||||
| } | |||||
| if ( this.outStream != null ) | |||||
| { | |||||
| 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; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,411 +0,0 @@ | |||||
| /* | |||||
| ** Copyright (c) 1998 by Timothy Gerard Endres | |||||
| ** <mailto:time@ice.com> <http://www.ice.com> | |||||
| ** | |||||
| ** This package is free software. | |||||
| ** | |||||
| ** You may redistribute it and/or modify it under the terms of the GNU | |||||
| ** General Public License as published by the Free Software Foundation. | |||||
| ** Version 2 of the license should be included with this distribution in | |||||
| ** the file LICENSE, as well as License.html. If the license is not | |||||
| ** included with this distribution, you may find a copy at the FSF web | |||||
| ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the | |||||
| ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA. | |||||
| ** | |||||
| ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, | |||||
| ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR | |||||
| ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY | |||||
| ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR | |||||
| ** REDISTRIBUTION OF THIS SOFTWARE. | |||||
| ** | |||||
| */ | |||||
| package com.ice.tar; | |||||
| import java.io.*; | |||||
| /** | |||||
| * | |||||
| * | |||||
| * 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 extends Object | |||||
| { | |||||
| protected TarArchive archive; | |||||
| protected TarHeader header; | |||||
| protected File file; | |||||
| public | |||||
| TarEntry( TarArchive archive, File file ) | |||||
| { | |||||
| this.archive = archive; | |||||
| this.file = file; | |||||
| this.header = this.getFileTarHeader( file ); | |||||
| } | |||||
| public | |||||
| TarEntry( TarArchive archive, byte[] headerBuf ) | |||||
| throws InvalidHeaderException | |||||
| { | |||||
| this.archive = archive; | |||||
| this.file = null; | |||||
| this.header = this.parseTarHeader( headerBuf ); | |||||
| } | |||||
| public TarArchive | |||||
| getArchive() | |||||
| { | |||||
| return this.archive; | |||||
| } | |||||
| public File | |||||
| getFile() | |||||
| { | |||||
| return this.file; | |||||
| } | |||||
| public TarHeader | |||||
| getHeader() | |||||
| { | |||||
| return this.header; | |||||
| } | |||||
| public String | |||||
| getName() | |||||
| { | |||||
| return this.header.name.toString(); | |||||
| } | |||||
| public long | |||||
| getSize() | |||||
| { | |||||
| return this.header.size; | |||||
| } | |||||
| public TarHeader | |||||
| getFileTarHeader( File file ) | |||||
| { | |||||
| TarHeader hdr = new TarHeader(); | |||||
| String name = file.getPath(); | |||||
| String osname = System.getProperty( "os.name" ); | |||||
| if ( osname != null ) | |||||
| { | |||||
| if ( osname.startsWith( "macos" ) ) | |||||
| { | |||||
| // UNDONE | |||||
| } | |||||
| else if ( osname.startsWith( "Windows" ) ) | |||||
| { | |||||
| if ( name.length() > 2 ) | |||||
| { | |||||
| char ch1 = name.charAt(0); | |||||
| char ch2 = name.charAt(1); | |||||
| if ( ch2 == File.separatorChar | |||||
| && ( (ch1 >= 'a' && ch1 <= 'z') | |||||
| || (ch1 >= 'a' && ch1 <= 'z') ) ) | |||||
| { | |||||
| name = name.substring( 2 ); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| hdr.name = | |||||
| new StringBuffer | |||||
| ( name.replace( File.separatorChar, '/' ) ); | |||||
| if ( file.isDirectory() ) | |||||
| { | |||||
| hdr.mode = 040755; | |||||
| hdr.linkFlag = TarHeader.LF_DIR; | |||||
| hdr.name.append( "/" ); | |||||
| } | |||||
| else | |||||
| { | |||||
| hdr.mode = 0100644; | |||||
| hdr.linkFlag = TarHeader.LF_NORMAL; | |||||
| } | |||||
| hdr.userId = this.archive.getUserId(); | |||||
| hdr.groupId = this.archive.getGroupId(); | |||||
| hdr.size = file.length(); | |||||
| hdr.modTime = file.lastModified() / 1000; | |||||
| hdr.checkSum = 0; | |||||
| hdr.linkName = new StringBuffer( "" ); | |||||
| hdr.magic = new StringBuffer( TarHeader.TMAGIC ); | |||||
| String userName = this.archive.getUserName(); | |||||
| if ( userName == null ) | |||||
| userName = System.getProperty( "user.name", "" ); | |||||
| if ( userName.length() > 31 ) | |||||
| userName = userName.substring( 0, 32 ); | |||||
| hdr.userName = new StringBuffer( userName ); | |||||
| String grpName = this.archive.getGroupName(); | |||||
| if ( grpName == null ) | |||||
| grpName = ""; | |||||
| if ( grpName.length() > 31 ) | |||||
| grpName = grpName.substring( 0, 32 ); | |||||
| hdr.groupName = new StringBuffer( grpName ); | |||||
| hdr.devMajor = 0; | |||||
| hdr.devMinor = 0; | |||||
| return hdr; | |||||
| } | |||||
| public boolean | |||||
| isDirectory() | |||||
| { | |||||
| if ( this.file != null ) | |||||
| return this.file.isDirectory(); | |||||
| if ( this.header != null ) | |||||
| { | |||||
| if ( this.header.linkFlag == TarHeader.LF_DIR ) | |||||
| return true; | |||||
| if ( this.header.name.toString().endsWith( "/" ) ) | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| public TarEntry[] | |||||
| getDirectoryEntries() | |||||
| { | |||||
| if ( this.file == null | |||||
| || ! this.file.isDirectory() ) | |||||
| { | |||||
| return new TarEntry[0]; | |||||
| } | |||||
| String[] list = this.file.list(); | |||||
| TarEntry[] result = new TarEntry[ list.length ]; | |||||
| for ( int i = 0 ; i < list.length ; ++i ) | |||||
| { | |||||
| result[i] = | |||||
| new TarEntry | |||||
| ( this.archive, | |||||
| new File( this.file, list[i] ) ); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| public long | |||||
| computeCheckSum( byte[] buf ) | |||||
| { | |||||
| long sum = 0; | |||||
| for ( int i = 0 ; i < buf.length ; ++i ) | |||||
| { | |||||
| sum += 255 & buf[ i ]; | |||||
| } | |||||
| return sum; | |||||
| } | |||||
| public void | |||||
| writeEntryHeader( byte[] outbuf ) | |||||
| { | |||||
| int offset = 0; | |||||
| offset = TarHeader.getNameBytes | |||||
| ( this.header.name, outbuf, offset, TarHeader.NAMELEN ); | |||||
| offset = TarHeader.getOctalBytes | |||||
| ( this.header.mode, outbuf, offset, TarHeader.MODELEN ); | |||||
| offset = TarHeader.getOctalBytes | |||||
| ( this.header.userId, outbuf, offset, TarHeader.UIDLEN ); | |||||
| offset = TarHeader.getOctalBytes | |||||
| ( this.header.groupId, outbuf, offset, TarHeader.GIDLEN ); | |||||
| offset = TarHeader.getLongOctalBytes | |||||
| ( this.header.size, outbuf, offset, TarHeader.SIZELEN ); | |||||
| offset = TarHeader.getLongOctalBytes | |||||
| ( this.header.modTime, outbuf, offset, TarHeader.MODTIMELEN ); | |||||
| int csOffset = offset; | |||||
| for ( int c = 0 ; c < TarHeader.CHKSUMLEN ; ++c ) | |||||
| outbuf[ offset++ ] = new Byte(" ").byteValue(); | |||||
| outbuf[ offset++ ] = this.header.linkFlag; | |||||
| offset = TarHeader.getNameBytes | |||||
| ( this.header.linkName, outbuf, offset, TarHeader.NAMELEN ); | |||||
| offset = TarHeader.getNameBytes | |||||
| ( this.header.magic, outbuf, offset, TarHeader.MAGICLEN ); | |||||
| offset = TarHeader.getNameBytes | |||||
| ( this.header.userName, outbuf, offset, TarHeader.UNAMELEN ); | |||||
| offset = TarHeader.getNameBytes | |||||
| ( this.header.groupName, outbuf, offset, TarHeader.GNAMELEN ); | |||||
| offset = TarHeader.getOctalBytes | |||||
| ( this.header.devMajor, outbuf, offset, TarHeader.DEVLEN ); | |||||
| offset = TarHeader.getOctalBytes | |||||
| ( this.header.devMinor, outbuf, offset, TarHeader.DEVLEN ); | |||||
| long checkSum = this.computeCheckSum( outbuf ); | |||||
| TarHeader.getCheckSumOctalBytes | |||||
| ( checkSum, outbuf, csOffset, TarHeader.CHKSUMLEN ); | |||||
| } | |||||
| public void | |||||
| writeEntryContents( TarBuffer buffer ) | |||||
| throws IOException | |||||
| { | |||||
| if ( this.file == null ) | |||||
| throw new IOException( "file is null" ); | |||||
| if ( ! this.file.exists() ) | |||||
| throw new IOException | |||||
| ( "file '" + this.file.getPath() | |||||
| + "' does not exist" ); | |||||
| // UNDONE - handle ASCII line termination translation!!!! | |||||
| FileInputStream in = | |||||
| new FileInputStream( this.file ); | |||||
| int recSize = this.archive.getRecordSize(); | |||||
| byte[] recbuf = new byte[ recSize ]; | |||||
| for ( ; ; ) | |||||
| { | |||||
| int num = in.read( recbuf, 0, recSize ); | |||||
| if ( num == -1 ) | |||||
| break; | |||||
| if ( num < recSize ) | |||||
| { | |||||
| for ( int j = num ; j < recSize ; ++j ) | |||||
| recbuf[j] = 0; | |||||
| } | |||||
| buffer.writeRecord( recbuf ); | |||||
| } | |||||
| in.close(); | |||||
| } | |||||
| public TarHeader | |||||
| parseTarHeader( byte[] header ) | |||||
| throws InvalidHeaderException | |||||
| { | |||||
| TarHeader hdr = new TarHeader(); | |||||
| int offset = 0; | |||||
| hdr.name = | |||||
| TarHeader.parseName( header, offset, TarHeader.NAMELEN ); | |||||
| offset += TarHeader.NAMELEN; | |||||
| hdr.mode = (int) | |||||
| TarHeader.parseOctal( header, offset, TarHeader.MODELEN ); | |||||
| offset += TarHeader.MODELEN; | |||||
| hdr.userId = (int) | |||||
| TarHeader.parseOctal( header, offset, TarHeader.UIDLEN ); | |||||
| offset += TarHeader.UIDLEN; | |||||
| hdr.groupId = (int) | |||||
| TarHeader.parseOctal( header, offset, TarHeader.GIDLEN ); | |||||
| offset += TarHeader.GIDLEN; | |||||
| hdr.size = | |||||
| TarHeader.parseOctal( header, offset, TarHeader.SIZELEN ); | |||||
| offset += TarHeader.SIZELEN; | |||||
| hdr.modTime = | |||||
| TarHeader.parseOctal( header, offset, TarHeader.MODTIMELEN ); | |||||
| offset += TarHeader.MODTIMELEN; | |||||
| hdr.checkSum = (int) | |||||
| TarHeader.parseOctal( header, offset, TarHeader.CHKSUMLEN ); | |||||
| offset += TarHeader.CHKSUMLEN; | |||||
| hdr.linkFlag = header[ offset++ ]; | |||||
| hdr.linkName = | |||||
| TarHeader.parseName( header, offset, TarHeader.NAMELEN ); | |||||
| offset += TarHeader.NAMELEN; | |||||
| hdr.magic = | |||||
| TarHeader.parseName( header, offset, TarHeader.MAGICLEN ); | |||||
| offset += TarHeader.MAGICLEN; | |||||
| hdr.userName = | |||||
| TarHeader.parseName( header, offset, TarHeader.UNAMELEN ); | |||||
| offset += TarHeader.UNAMELEN; | |||||
| hdr.groupName = | |||||
| TarHeader.parseName( header, offset, TarHeader.GNAMELEN ); | |||||
| offset += TarHeader.GNAMELEN; | |||||
| hdr.devMajor = (int) | |||||
| TarHeader.parseOctal( header, offset, TarHeader.DEVLEN ); | |||||
| offset += TarHeader.DEVLEN; | |||||
| hdr.devMinor = (int) | |||||
| TarHeader.parseOctal( header, offset, TarHeader.DEVLEN ); | |||||
| return hdr; | |||||
| } | |||||
| } | |||||
| @@ -1,200 +0,0 @@ | |||||
| /* | |||||
| ** Copyright (c) 1998 by Timothy Gerard Endres | |||||
| ** <mailto:time@ice.com> <http://www.ice.com> | |||||
| ** | |||||
| ** This package is free software. | |||||
| ** | |||||
| ** You may redistribute it and/or modify it under the terms of the GNU | |||||
| ** General Public License as published by the Free Software Foundation. | |||||
| ** Version 2 of the license should be included with this distribution in | |||||
| ** the file LICENSE, as well as License.html. If the license is not | |||||
| ** included with this distribution, you may find a copy at the FSF web | |||||
| ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the | |||||
| ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA. | |||||
| ** | |||||
| ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, | |||||
| ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR | |||||
| ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY | |||||
| ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR | |||||
| ** REDISTRIBUTION OF THIS SOFTWARE. | |||||
| ** | |||||
| */ | |||||
| package com.ice.tar; | |||||
| public class | |||||
| TarHeader extends Object | |||||
| { | |||||
| public static final int NAMELEN = 100; | |||||
| public static final int MODELEN = 8; | |||||
| public static final int UIDLEN = 8; | |||||
| public static final int GIDLEN = 8; | |||||
| public static final int CHKSUMLEN = 8; | |||||
| public static final int SIZELEN = 12; | |||||
| public static final int MAGICLEN = 8; | |||||
| public static final int MODTIMELEN = 12; | |||||
| public static final int UNAMELEN = 32; | |||||
| public static final int GNAMELEN = 32; | |||||
| public static final int DEVLEN = 8; | |||||
| public static final byte LF_OLDNORM = 0; | |||||
| public static final byte LF_NORMAL = new Byte("0").byteValue(); | |||||
| public static final byte LF_LINK = new Byte("1").byteValue(); | |||||
| public static final byte LF_SYMLINK = new Byte("2").byteValue(); | |||||
| public static final byte LF_CHR = new Byte("3").byteValue(); | |||||
| public static final byte LF_BLK = new Byte("4").byteValue(); | |||||
| public static final byte LF_DIR = new Byte("5").byteValue(); | |||||
| public static final byte LF_FIFO = new Byte("6").byteValue(); | |||||
| public static final byte LF_CONTIG = new Byte("7").byteValue(); | |||||
| public static final String TMAGIC = "ustar "; | |||||
| public StringBuffer name; | |||||
| public int mode; | |||||
| public int userId; | |||||
| public int groupId; | |||||
| public long size; | |||||
| public long modTime; | |||||
| public int checkSum; | |||||
| public byte linkFlag; | |||||
| public StringBuffer linkName; | |||||
| public StringBuffer magic; | |||||
| public StringBuffer userName; | |||||
| public StringBuffer groupName; | |||||
| public int devMajor; | |||||
| public int devMinor; | |||||
| public | |||||
| TarHeader() | |||||
| { | |||||
| } | |||||
| public static long | |||||
| parseOctal( byte[] header, int offset, int length ) | |||||
| throws InvalidHeaderException | |||||
| { | |||||
| 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] == ' ' || header[i] == '0' ) | |||||
| { | |||||
| if ( stillPadding ) | |||||
| continue; | |||||
| if ( header[i] == ' ' ) | |||||
| break; | |||||
| } | |||||
| stillPadding = false; | |||||
| result = | |||||
| (result << 3) | |||||
| + (header[i] - '0'); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| public static StringBuffer | |||||
| parseName( byte[] header, int offset, int length ) | |||||
| throws InvalidHeaderException | |||||
| { | |||||
| StringBuffer result = new StringBuffer( length ); | |||||
| int end = offset + length; | |||||
| for ( int i = offset ; i < end ; ++i ) | |||||
| { | |||||
| if ( header[i] == 0 ) | |||||
| break; | |||||
| result.append( (char)header[i] ); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| public static int | |||||
| getNameBytes( StringBuffer 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; | |||||
| } | |||||
| public static int | |||||
| getOctalBytes( long value, byte[] buf, int offset, int length ) | |||||
| { | |||||
| byte[] result = new byte[ length ]; | |||||
| int idx = length - 1; | |||||
| buf[ offset + idx ] = 0; | |||||
| --idx; | |||||
| buf[ offset + idx ] = new Byte(" ").byteValue(); | |||||
| --idx; | |||||
| if ( value == 0 ) | |||||
| { | |||||
| buf[ offset + idx ] = new Byte("0").byteValue(); | |||||
| --idx; | |||||
| } | |||||
| else | |||||
| { | |||||
| for ( long val = value ; idx >= 0 && val > 0 ; --idx ) | |||||
| { | |||||
| buf[ offset + idx ] = | |||||
| (byte) ( '0' + (val & 7) ); | |||||
| val = val >> 3; | |||||
| } | |||||
| } | |||||
| for ( ; idx >= 0 ; --idx ) | |||||
| { | |||||
| buf[ offset + idx ] = new Byte(" ").byteValue(); | |||||
| } | |||||
| return offset + length; | |||||
| } | |||||
| public static int | |||||
| getLongOctalBytes( long value, byte[] buf, int offset, int length ) | |||||
| { | |||||
| byte[] temp = new byte[ length + 1 ]; | |||||
| TarHeader.getOctalBytes( value, temp, 0, length + 1 ); | |||||
| System.arraycopy( temp, 0, buf, offset, length ); | |||||
| return offset + length; | |||||
| } | |||||
| public static int | |||||
| getCheckSumOctalBytes( long value, byte[] buf, int offset, int length ) | |||||
| { | |||||
| TarHeader.getOctalBytes( value, buf, offset, length ); | |||||
| buf[ offset + length - 1 ] = new Byte(" ").byteValue(); | |||||
| buf[ offset + length - 2 ] = 0; | |||||
| return offset + length; | |||||
| } | |||||
| public String | |||||
| getName() | |||||
| { | |||||
| return this.name.toString(); | |||||
| } | |||||
| } | |||||
| @@ -1,32 +0,0 @@ | |||||
| /* | |||||
| ** Copyright (c) 1998 by Timothy Gerard Endres | |||||
| ** <mailto:time@ice.com> <http://www.ice.com> | |||||
| ** | |||||
| ** This package is free software. | |||||
| ** | |||||
| ** You may redistribute it and/or modify it under the terms of the GNU | |||||
| ** General Public License as published by the Free Software Foundation. | |||||
| ** Version 2 of the license should be included with this distribution in | |||||
| ** the file LICENSE, as well as License.html. If the license is not | |||||
| ** included with this distribution, you may find a copy at the FSF web | |||||
| ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the | |||||
| ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA. | |||||
| ** | |||||
| ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, | |||||
| ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR | |||||
| ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY | |||||
| ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR | |||||
| ** REDISTRIBUTION OF THIS SOFTWARE. | |||||
| ** | |||||
| */ | |||||
| package com.ice.tar; | |||||
| public interface | |||||
| TarProgressDisplay | |||||
| { | |||||
| public void | |||||
| showTarProgressMessage( String msg ); | |||||
| } | |||||