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 ); | |||
| } | |||