Tape Archive Lister: Tar file : Zip Tar File « File Input Output « Java






Tape Archive Lister: Tar file

         

/*
 * Copyright (c) Ian F. Darwin, http://www.darwinsys.com/, 1996-2002.
 * All rights reserved. Software written by Ian F. Darwin and others.
 * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Java, the Duke mascot, and all variants of Sun's Java "steaming coffee
 * cup" logo are trademarks of Sun Microsystems. Sun's, and James Gosling's,
 * pioneering role in inventing and promulgating (and standardizing) the Java 
 * language and environment is gratefully acknowledged.
 * 
 * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
 * inventing predecessor languages C and C++ is also gratefully acknowledged.
 */

/*
Error handling throughout. In particular, the reading code needs to checksum!

Write getInputStream(). Here's how: seek on the file, malloc a buffer
big enough to hold the file, read it into memory, return a
ByteArrayInputStream.

Handle LF_LINK linked files: getEntry(name).getOffset().

Think about writing Tar files?
*/

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

/**
 * Demonstrate the Tar archive lister.
 * 
 * @author Ian F. Darwin, http://www.darwinsys.com/
 * @version $Id: TarList.java,v 1.7 2004/03/07 17:47:35 ian Exp $
 */
public class TarList {
  public static void main(String[] argv) throws IOException, TarException {
    if (argv.length == 0) {
      System.err.println("Usage: TarList archive");
      System.exit(1);
    }
    new TarList(argv[0]).list();
  }

  /** The TarFile we are reading */
  TarFile tf;

  /** Constructor */
  public TarList(String fileName) {
    tf = new TarFile(fileName);
  }

  /** Generate and print the listing */
  public void list() throws IOException, TarException {
    Enumeration list = tf.entries();
    while (list.hasMoreElements()) {
      TarEntry e = (TarEntry) list.nextElement();
      System.out.println(toListFormat(e));
    }
  }

  protected StringBuffer sb;

  /** Shift used in formatting permissions */
  protected static int[] shft = { 6, 3, 0 };

  /** Format strings used in permissions */
  protected static String rwx[] = { "---", "--x", "-w-", "-wx", "r--", "r-x",
      "rw-", "rwx" };

  /** NumberFormat used in formatting List form string */
  NumberFormat sizeForm = new DecimalFormat("00000000");

  /** Date used in printing mtime */
  Date date = new Date();

  SimpleDateFormat dateForm = new SimpleDateFormat("yyyy-MM-dd HH:mm");

  /** Format a TarEntry the same way that UNIX tar does */
  public String toListFormat(TarEntry e) {
    sb = new StringBuffer();
    switch (e.type) {
    case TarEntry.LF_OLDNORMAL:
    case TarEntry.LF_NORMAL:
    case TarEntry.LF_CONTIG:
    case TarEntry.LF_LINK: // hard link: same as file
      sb.append('-'); // 'f' would be sensible
      break;
    case TarEntry.LF_DIR:
      sb.append('d');
      break;
    case TarEntry.LF_SYMLINK:
      sb.append('l');
      break;
    case TarEntry.LF_CHR: // UNIX character device file
      sb.append('c');
      break;
    case TarEntry.LF_BLK: // UNIX block device file
      sb.append('b');
      break;
    case TarEntry.LF_FIFO: // UNIX named pipe
      sb.append('p');
      break;
    default: // Can't happen?
      sb.append('?');
      break;
    }

    // Convert e.g., 754 to rwxrw-r--
    int mode = e.getMode();
    for (int i = 0; i < 3; i++) {
      sb.append(rwx[mode >> shft[i] & 007]);
    }
    sb.append(' ');

    // owner and group
    sb.append(e.getUname()).append('/').append(e.getGname()).append(' ');

    // size
    // DecimalFormat can't do "%-9d", so we do part of it ourselves
    sb.append(' ');
    String t = sizeForm.format(e.getSize());
    boolean digit = false;
    char c;
    for (int i = 0; i < 8; i++) {
      c = t.charAt(i);
      if (!digit && i < (8 - 1) && c == '0')
        sb.append(' '); // leading space
      else {
        digit = true;
        sb.append(c);
      }
    }
    sb.append(' ');

    // mtime
    // copy file's mtime into Data object (after scaling
    // from "sec since 1970" to "msec since 1970"), and format it.
    date.setTime(1000 * e.getTime());
    sb.append(dateForm.format(date)).append(' ');

    sb.append(e.getName());
    if (e.isLink())
      sb.append(" link to ").append(e.getLinkName());
    if (e.isSymLink())
      sb.append(" -> ").append(e.getLinkName());

    return sb.toString();
  }
}

/**
 * One entry in an archive file.
 * 
 * @author Ian Darwin
 * @version $Id: TarEntry.java,v 1.7 2004/03/06 21:16:19 ian Exp $
 * @note Tar format info taken from John Gilmore's public domain tar program,
 * @(#)tar.h 1.21 87/05/01 Public Domain, which said: "Created 25 August 1985 by
 *           John Gilmore, ihnp4!hoptoad!gnu." John is now gnu@toad.com, and by
 *           another path tar.h is GPL'd in GNU Tar.
 */

class TarEntry {
  /** Where in the tar archive this entry's HEADER is found. */
  public long fileOffset = 0;

  /** The maximum size of a name */
  public static final int NAMSIZ = 100;

  public static final int TUNMLEN = 32;

  public static final int TGNMLEN = 32;

  // Next fourteen fields constitute one physical record.
  // Padded to TarFile.RECORDSIZE bytes on tape/disk.
  // Lazy Evaluation: just read fields in raw form, only format when asked.

  /** File name */
  byte[] name = new byte[NAMSIZ];

  /** permissions, e.g., rwxr-xr-x? */
  byte[] mode = new byte[8];

  /* user */
  byte[] uid = new byte[8];

  /* group */
  byte[] gid = new byte[8];

  /* size */
  byte[] size = new byte[12];

  /* UNIX modification time */
  byte[] mtime = new byte[12];

  /* checksum field */
  byte[] chksum = new byte[8];

  byte type;

  byte[] linkName = new byte[NAMSIZ];

  byte[] magic = new byte[8];

  byte[] uname = new byte[TUNMLEN];

  byte[] gname = new byte[TGNMLEN];

  byte[] devmajor = new byte[8];

  byte[] devminor = new byte[8];

  // End of the physical data fields.

  /* The magic field is filled with this if uname and gname are valid. */
  public static final byte TMAGIC[] = {
  // 'u', 's', 't', 'a', 'r', ' ', ' ', '\0'
      0, 0, 0, 0, 0, 0, 0x20, 0x20, 0 }; /* 7 chars and a null */

  /* Type value for Normal file, Unix compatibility */
  public static final int LF_OLDNORMAL = '\0';

  /* Type value for Normal file */
  public static final int LF_NORMAL = '0';

  /* Type value for Link to previously dumped file */
  public static final int LF_LINK = '1';

  /* Type value for Symbolic link */
  public static final int LF_SYMLINK = '2';

  /* Type value for Character special file */
  public static final int LF_CHR = '3';

  /* Type value for Block special file */
  public static final int LF_BLK = '4';

  /* Type value for Directory */
  public static final int LF_DIR = '5';

  /* Type value for FIFO special file */
  public static final int LF_FIFO = '6';

  /* Type value for Contiguous file */
  public static final int LF_CONTIG = '7';

  /* Constructor that reads the entry's header. */
  public TarEntry(RandomAccessFile is) throws IOException, TarException {

    fileOffset = is.getFilePointer();

    // read() returns -1 at EOF
    if (is.read(name) < 0)
      throw new EOFException();
    // Tar pads to block boundary with nulls.
    if (name[0] == '\0')
      throw new EOFException();
    // OK, read remaining fields.
    is.read(mode);
    is.read(uid);
    is.read(gid);
    is.read(size);
    is.read(mtime);
    is.read(chksum);
    type = is.readByte();
    is.read(linkName);
    is.read(magic);
    is.read(uname);
    is.read(gname);
    is.read(devmajor);
    is.read(devminor);

    // Since the tar header is < 512, we need to skip it.
    is
        .skipBytes((int) (TarFile.RECORDSIZE - (is.getFilePointer() % TarFile.RECORDSIZE)));

    // TODO if checksum() fails,
    //  throw new TarException("Failed to find next header");

  }

  /** Returns the name of the file this entry represents. */
  public String getName() {
    return new String(name).trim();
  }

  public String getTypeName() {
    switch (type) {
    case LF_OLDNORMAL:
    case LF_NORMAL:
      return "file";
    case LF_LINK:
      return "link w/in archive";
    case LF_SYMLINK:
      return "symlink";
    case LF_CHR:
    case LF_BLK:
    case LF_FIFO:
      return "special file";
    case LF_DIR:
      return "directory";
    case LF_CONTIG:
      return "contig";
    default:
      throw new IllegalStateException("TarEntry.getTypeName: type "
          + type + " invalid");
    }
  }

  /** Returns the UNIX-specific "mode" (type+permissions) of the entry */
  public int getMode() {
    try {
      return Integer.parseInt(new String(mode).trim(), 8) & 0777;
    } catch (IllegalArgumentException e) {
      return 0;
    }
  }

  /** Returns the size of the entry */
  public int getSize() {
    try {
      return Integer.parseInt(new String(size).trim(), 8);
    } catch (IllegalArgumentException e) {
      return 0;
    }
  }

  /**
   * Returns the name of the file this entry is a link to, or null if this
   * entry is not a link.
   */
  public String getLinkName() {
    // if (isLink())
    //   return null;
    return new String(linkName).trim();
  }

  /** Returns the modification time of the entry */
  public long getTime() {
    try {
      return Long.parseLong(new String(mtime).trim(), 8);
    } catch (IllegalArgumentException e) {
      return 0;
    }
  }

  /** Returns the string name of the userid */
  public String getUname() {
    return new String(uname).trim();
  }

  /** Returns the string name of the group id */
  public String getGname() {
    return new String(gname).trim();
  }

  /** Returns the numeric userid of the entry */
  public int getuid() {
    try {
      return Integer.parseInt(new String(uid).trim());
    } catch (IllegalArgumentException e) {
      return -1;
    }
  }

  /** Returns the numeric gid of the entry */
  public int getgid() {
    try {
      return Integer.parseInt(new String(gid).trim());
    } catch (IllegalArgumentException e) {
      return -1;
    }
  }

  /** Returns true if this entry represents a file */
  boolean isFile() {
    return type == LF_NORMAL || type == LF_OLDNORMAL;
  }

  /** Returns true if this entry represents a directory */
  boolean isDirectory() {
    return type == LF_DIR;
  }

  /** Returns true if this a hard link (to a file in the archive) */
  boolean isLink() {
    return type == LF_LINK;
  }

  /** Returns true if this a symbolic link */
  boolean isSymLink() {
    return type == LF_SYMLINK;
  }

  /** Returns true if this entry represents some type of UNIX special file */
  boolean isSpecial() {
    return type == LF_CHR || type == LF_BLK || type == LF_FIFO;
  }

  public String toString() {
    return "TarEntry[" + getName() + ']';
  }
}
/*
 * Exception for TarFile and TarEntry. $Id: TarException.java,v 1.3 1999/10/06
 * 15:13:53 ian Exp $
 */

class TarException extends java.io.IOException {
  public TarException() {
    super();
  }

  public TarException(String msg) {
    super(msg);
  }
}

/**
 * Tape Archive Lister, patterned loosely after java.util.ZipFile. Since, unlike
 * Zip files, there is no central directory, you have to read the entire file
 * either to be sure of having a particular file's entry, or to know how many
 * entries there are in the archive.
 * 
 * @author Ian Darwin, http://www.darwinsys.com/
 * @version $Id: TarFile.java,v 1.12 2004/03/07 17:53:15 ian Exp $
 */

class TarFile {
  /** True after we've done the expensive read. */
  protected boolean read = false;

  /** The list of entries found in the archive */
  protected Vector list;

  /** Size of header block. */
  public static final int RECORDSIZE = 512;

  /* Size of each block, in records */
  protected int blocking;

  /* Size of each block, in bytes */
  protected int blocksize;

  /** File containing archive */
  protected String fileName;

  /** Construct (open) a Tar file by name */
  public TarFile(String name) {
    fileName = name;
    list = new Vector();
  }

  /** Construct (open) a Tar file by File */
  public TarFile(java.io.File name) throws IOException {
    this(name.getCanonicalPath());
  }

  /** The main datastream. */
  protected RandomAccessFile is;

  /**
   * Read the Tar archive in its entirety. This is semi-lazy evaluation, in
   * that we don't read the file until we need to. A future revision may use
   * even lazier evaluation: in getEntry, scan the list and, if not found,
   * continue reading! For now, just read the whole file.
   */
  protected void readFile() throws IOException, TarException {
    is = new RandomAccessFile(fileName, "r");
    TarEntry hdr;
    try {
      do {
        hdr = new TarEntry(is);
        if (hdr.getSize() < 0) {
          System.out.println("Size < 0");
          break;
        }
        // System.out.println(hdr.toString());
        list.addElement(hdr);
        // Get the size of the entry
        int nbytes = hdr.getSize(), diff;
        // Round it up to blocksize.
        if ((diff = (nbytes % RECORDSIZE)) != 0) {
          nbytes += RECORDSIZE - diff;
        }
        // And skip over the data portion.
        // System.out.println("Skipping " + nbytes + " bytes");
        is.skipBytes(nbytes);
      } while (true);
    } catch (EOFException e) {
      // OK, just stop reading.
    }
    // All done, say we've read the contents.
    read = true;
  }

  /* Close the Tar file. */
  public void close() {
    try {
      is.close();
    } catch (IOException e) {
      // nothing to do
    }
  }

  /* Returns an enumeration of the Tar file entries. */
  public Enumeration entries() throws IOException, TarException {
    if (!read) {
      readFile();
    }
    return list.elements();
  }

  /** Returns the Tar entry for the specified name, or null if not found. */
  public TarEntry getEntry(String name) {
    for (int i = 0; i < list.size(); i++) {
      TarEntry e = (TarEntry) list.elementAt(i);
      if (name.equals(e.getName()))
        return e;
    }
    return null;
  }

  /**
   * Returns an InputStream for reading the contents of the specified entry
   * from the archive. May cause the entire file to be read.
   */
  public InputStream getInputStream(TarEntry entry) {
    return null;
  }

  /** Returns the path name of the Tar file. */
  public String getName() {
    return fileName;
  }

  /**
   * Returns the number of entries in the Tar archive. May cause the entire
   * file to be read. XXX Obviously not written yet, sorry.
   */
  public int size() {
    return 0;
  }
}

           
         
    
    
    
    
    
    
    
    
  








Related examples in the same category

1.Extract contents of a zip file
2.List the contents of a zip file
3.Read entries in a zip / compressed file
4.Decompress a zip file using ZipInputStream
5.Decompress a zip file using ZipFile
6.Create checksum for a zip file
7.Read a zip file checksum value
8.Create a zip file with java.util.zip package
9.Extract file/files from a zip file
10.Read files within a zip file
11.Retrieve a compressed file from a ZIP file
12.Retrieve the contents of a ZIP file
13.Making a zip file of directory including its subdirectories recursively
14.Displaying contents of a compressed zip file
15.Compress a Byte Array
16.Decompress a Byte Array
17.Read zip file
18.Write Zip file
19.The java.util.zip package can be used to create a checksum.
20.Read the content of a zip file ZipFile
21.List the entries of a zip file
22.Compressing Streams: Zipper, Java example
23.Compressing Streams: Parity Checksum
24.Compressing Streams: File Summer
25.Create a simple ZIP File: not retain any directory path information about the files.
26.Decompress a ZIP file.
27.Decompressing a Byte Array
28.Zip unzip byte array
29.Creating a ZIP File
30.Listing the Contents of a ZIP File
31.Retrieving a Compressed File from a ZIP File
32.Calculating the Checksum of a Byte Array (Compute Adler-32 checksum)
33.Compute CRC-32 checksum
34.Calculating the Checksum of a File
35.Compress string(byte array) by Deflater
36.Use Java code to zip a folder
37.Uses Zip compression to compress any number of files given on the command line
38.Load zip file and scan zip file
39.Reading the Contents of a ZIP File
40.UnZip -- print or unzip a JAR or PKZIP file using java.util.zip
41.Compressing a Byte Array
42.Tar file stream
43.Tar file and untar file
44.bzip source code
45.Unpack an archive from a URL
46.Compare two zip files
47.Determine whether a file is a ZIP File.
48.Zip up a directory
49.Check sum for a path
50.Check sum for an InputStream
51.Extract zip file to destination folder
52.Return the first directory of this archive. This is needed to determine the plugin directory
53.Makes a zip file named xmlFileName from xmlURL at path
54.Unzipps a zip file placed at zipURL to path
55.A single checksum calculation for multiple files
56.Put file To Zip File
57.Provides both writing and reading from a file which is transparently compressed in Zip
58.TarInputStream reads a UNIX tar archive as an InputStream
59.TarOutputStream writes a UNIX tar archive as an OutputStream
60.Package files utility
61.Zip Compare
62.Unpack a segment from a zip
63.Unpack a zip file
64.Unzip file to a directory
65.Zip a list of file into one zip file.
66.Validate that an archive contains a named entry
67.A frame with a text area to show the contents of a file inside a ZIP archive
68.Compress object and decompress
69.Util for extracting *.jar, *.war and *.zip archives.