activemq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hadr...@apache.org
Subject [13/14] Use autocrlf consistently for line endings
Date Tue, 29 Apr 2014 18:34:25 GMT
http://git-wip-us.apache.org/repos/asf/activemq/blob/3f32507f/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarEntry.java
----------------------------------------------------------------------
diff --git a/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarEntry.java b/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarEntry.java
index 5c7afa9..c388707 100644
--- a/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarEntry.java
+++ b/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarEntry.java
@@ -1,664 +1,664 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- */
-
-/*
- * This package is based on the work done by Timothy Gerard Endres
- * (time@ice.com) to whom the Ant project is very grateful for his great code.
- */
-
-package org.apache.activemq.console.command.store.tar;
-
-import java.io.File;
-import java.util.Date;
-import java.util.Locale;
-
-/**
- * This class represents an entry in a Tar archive. It consists
- * of the entry's header, as well as the entry's File. Entries
- * can be instantiated in one of three ways, depending on how
- * they are to be used.
- * <p>
- * TarEntries that are created from the header bytes read from
- * an archive are instantiated with the TarEntry( byte[] )
- * constructor. These entries will be used when extracting from
- * or listing the contents of an archive. These entries have their
- * header filled in using the header bytes. They also set the File
- * to null, since they reference an archive entry not a file.
- * <p>
- * TarEntries that are created from Files that are to be written
- * into an archive are instantiated with the TarEntry( File )
- * constructor. These entries have their header filled in using
- * the File's information. They also keep a reference to the File
- * for convenience when writing entries.
- * <p>
- * Finally, TarEntries can be constructed from nothing but a name.
- * This allows the programmer to construct the entry by hand, for
- * instance when only an InputStream is available for writing to
- * the archive, and the header information is constructed from
- * other information. In this case the header fields are set to
- * defaults and the File is set to null.
- *
- * <p>
- * The C structure for a Tar Entry's header is:
- * <pre>
- * 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;
- * </pre>
- *
- */
-
-public class TarEntry implements TarConstants {
-    /** The entry's name. */
-    private StringBuffer name;
-
-    /** The entry's permission mode. */
-    private int mode;
-
-    /** The entry's user id. */
-    private int userId;
-
-    /** The entry's group id. */
-    private int groupId;
-
-    /** The entry's size. */
-    private long size;
-
-    /** The entry's modification time. */
-    private long modTime;
-
-    /** The entry's link flag. */
-    private byte linkFlag;
-
-    /** The entry's link name. */
-    private StringBuffer linkName;
-
-    /** The entry's magic tag. */
-    private StringBuffer magic;
-
-    /** The entry's user name. */
-    private StringBuffer userName;
-
-    /** The entry's group name. */
-    private StringBuffer groupName;
-
-    /** The entry's major device number. */
-    private int devMajor;
-
-    /** The entry's minor device number. */
-    private int devMinor;
-
-    /** The entry's file reference */
-    private File file;
-
-    /** Maximum length of a user's name in the tar file */
-    public static final int MAX_NAMELEN = 31;
-
-    /** Default permissions bits for directories */
-    public static final int DEFAULT_DIR_MODE = 040755;
-
-    /** Default permissions bits for files */
-    public static final int DEFAULT_FILE_MODE = 0100644;
-
-    /** Convert millis to seconds */
-    public static final int MILLIS_PER_SECOND = 1000;
-
-    /**
-     * Construct an empty entry and prepares the header values.
-     */
-    private TarEntry () {
-        this.magic = new StringBuffer(TMAGIC);
-        this.name = new StringBuffer();
-        this.linkName = new StringBuffer();
-
-        String user = System.getProperty("user.name", "");
-
-        if (user.length() > MAX_NAMELEN) {
-            user = user.substring(0, MAX_NAMELEN);
-        }
-
-        this.userId = 0;
-        this.groupId = 0;
-        this.userName = new StringBuffer(user);
-        this.groupName = new StringBuffer("");
-        this.file = null;
-    }
-
-    /**
-     * Construct an entry with only a name. This allows the programmer
-     * to construct the entry's header "by hand". File is set to null.
-     *
-     * @param name the entry name
-     */
-    public TarEntry(String name) {
-        this(name, false);
-    }
-
-    /**
-     * Construct an entry with only a name. This allows the programmer
-     * to construct the entry's header "by hand". File is set to null.
-     *
-     * @param name the entry name
-     * @param preserveLeadingSlashes whether to allow leading slashes
-     * in the name.
-     */
-    public TarEntry(String name, boolean preserveLeadingSlashes) {
-        this();
-
-        name = normalizeFileName(name, preserveLeadingSlashes);
-        boolean isDir = name.endsWith("/");
-
-        this.devMajor = 0;
-        this.devMinor = 0;
-        this.name = new StringBuffer(name);
-        this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE;
-        this.linkFlag = isDir ? LF_DIR : LF_NORMAL;
-        this.userId = 0;
-        this.groupId = 0;
-        this.size = 0;
-        this.modTime = (new Date()).getTime() / MILLIS_PER_SECOND;
-        this.linkName = new StringBuffer("");
-        this.userName = new StringBuffer("");
-        this.groupName = new StringBuffer("");
-        this.devMajor = 0;
-        this.devMinor = 0;
-
-    }
-
-    /**
-     * Construct an entry with a name and a link flag.
-     *
-     * @param name the entry name
-     * @param linkFlag the entry link flag.
-     */
-    public TarEntry(String name, byte linkFlag) {
-        this(name);
-        this.linkFlag = linkFlag;
-        if (linkFlag == LF_GNUTYPE_LONGNAME) {
-            magic = new StringBuffer(GNU_TMAGIC);
-        }
-    }
-
-    /**
-     * Construct an entry for a file. File is set to file, and the
-     * header is constructed from information from the file.
-     *
-     * @param file The file that the entry represents.
-     */
-    public TarEntry(File file) {
-        this();
-
-        this.file = file;
-
-        String fileName = normalizeFileName(file.getPath(), false);
-        this.linkName = new StringBuffer("");
-        this.name = new StringBuffer(fileName);
-
-        if (file.isDirectory()) {
-            this.mode = DEFAULT_DIR_MODE;
-            this.linkFlag = LF_DIR;
-
-            int nameLength = name.length();
-            if (nameLength == 0 || name.charAt(nameLength - 1) != '/') {
-                this.name.append("/");
-            }
-            this.size = 0;
-        } else {
-            this.mode = DEFAULT_FILE_MODE;
-            this.linkFlag = LF_NORMAL;
-            this.size = file.length();
-        }
-
-        this.modTime = file.lastModified() / MILLIS_PER_SECOND;
-        this.devMajor = 0;
-        this.devMinor = 0;
-    }
-
-    /**
-     * Construct an entry from an archive's header bytes. File is set
-     * to null.
-     *
-     * @param headerBuf The header bytes from a tar archive entry.
-     */
-    public TarEntry(byte[] headerBuf) {
-        this();
-        parseTarHeader(headerBuf);
-    }
-
-    /**
-     * Determine if the two entries are equal. Equality is determined
-     * by the header names being equal.
-     *
-     * @param it Entry to be checked for equality.
-     * @return True if the entries are equal.
-     */
-    public boolean equals(TarEntry it) {
-        return getName().equals(it.getName());
-    }
-
-    /**
-     * Determine if the two entries are equal. Equality is determined
-     * by the header names being equal.
-     *
-     * @param it Entry to be checked for equality.
-     * @return True if the entries are equal.
-     */
-    public boolean equals(Object it) {
-        if (it == null || getClass() != it.getClass()) {
-            return false;
-        }
-        return equals((TarEntry) it);
-    }
-
-    /**
-     * Hashcodes are based on entry names.
-     *
-     * @return the entry hashcode
-     */
-    public int hashCode() {
-        return getName().hashCode();
-    }
-
-    /**
-     * Determine if the given entry is a descendant of this entry.
-     * Descendancy is determined by the name of the descendant
-     * starting with this entry's name.
-     *
-     * @param desc Entry to be checked as a descendent of this.
-     * @return True if entry is a descendant of this.
-     */
-    public boolean isDescendent(TarEntry desc) {
-        return desc.getName().startsWith(getName());
-    }
-
-    /**
-     * Get this entry's name.
-     *
-     * @return This entry's name.
-     */
-    public String getName() {
-        return name.toString();
-    }
-
-    /**
-     * Set this entry's name.
-     *
-     * @param name This entry's new name.
-     */
-    public void setName(String name) {
-        this.name = new StringBuffer(normalizeFileName(name, false));
-    }
-
-    /**
-     * Set the mode for this entry
-     *
-     * @param mode the mode for this entry
-     */
-    public void setMode(int mode) {
-        this.mode = mode;
-    }
-
-    /**
-     * Get this entry's link name.
-     *
-     * @return This entry's link name.
-     */
-    public String getLinkName() {
-        return linkName.toString();
-    }
-
-    /**
-     * Get this entry's user id.
-     *
-     * @return This entry's user id.
-     */
-    public int getUserId() {
-        return userId;
-    }
-
-    /**
-     * Set this entry's user id.
-     *
-     * @param userId This entry's new user id.
-     */
-    public void setUserId(int userId) {
-        this.userId = userId;
-    }
-
-    /**
-     * Get this entry's group id.
-     *
-     * @return This entry's group id.
-     */
-    public int getGroupId() {
-        return groupId;
-    }
-
-    /**
-     * Set this entry's group id.
-     *
-     * @param groupId This entry's new group id.
-     */
-    public void setGroupId(int groupId) {
-        this.groupId = groupId;
-    }
-
-    /**
-     * Get this entry's user name.
-     *
-     * @return This entry's user name.
-     */
-    public String getUserName() {
-        return userName.toString();
-    }
-
-    /**
-     * Set this entry's user name.
-     *
-     * @param userName This entry's new user name.
-     */
-    public void setUserName(String userName) {
-        this.userName = new StringBuffer(userName);
-    }
-
-    /**
-     * Get this entry's group name.
-     *
-     * @return This entry's group name.
-     */
-    public String getGroupName() {
-        return groupName.toString();
-    }
-
-    /**
-     * Set this entry's group name.
-     *
-     * @param groupName This entry's new group name.
-     */
-    public void setGroupName(String groupName) {
-        this.groupName = new StringBuffer(groupName);
-    }
-
-    /**
-     * Convenience method to set this entry's group and user ids.
-     *
-     * @param userId This entry's new user id.
-     * @param groupId This entry's new group id.
-     */
-    public void setIds(int userId, int groupId) {
-        setUserId(userId);
-        setGroupId(groupId);
-    }
-
-    /**
-     * Convenience method to set this entry's group and user names.
-     *
-     * @param userName This entry's new user name.
-     * @param groupName This entry's new group name.
-     */
-    public void setNames(String userName, String groupName) {
-        setUserName(userName);
-        setGroupName(groupName);
-    }
-
-    /**
-     * Set this entry's modification time. The parameter passed
-     * to this method is in "Java time".
-     *
-     * @param time This entry's new modification time.
-     */
-    public void setModTime(long time) {
-        modTime = time / MILLIS_PER_SECOND;
-    }
-
-    /**
-     * Set this entry's modification time.
-     *
-     * @param time This entry's new modification time.
-     */
-    public void setModTime(Date time) {
-        modTime = time.getTime() / MILLIS_PER_SECOND;
-    }
-
-    /**
-     * Set this entry's modification time.
-     *
-     * @return time This entry's new modification time.
-     */
-    public Date getModTime() {
-        return new Date(modTime * MILLIS_PER_SECOND);
-    }
-
-    /**
-     * Get this entry's file.
-     *
-     * @return This entry's file.
-     */
-    public File getFile() {
-        return file;
-    }
-
-    /**
-     * Get this entry's mode.
-     *
-     * @return This entry's mode.
-     */
-    public int getMode() {
-        return mode;
-    }
-
-    /**
-     * Get this entry's file size.
-     *
-     * @return This entry's file size.
-     */
-    public long getSize() {
-        return size;
-    }
-
-    /**
-     * Set this entry's file size.
-     *
-     * @param size This entry's new file size.
-     */
-    public void setSize(long size) {
-        this.size = size;
-    }
-
-
-    /**
-     * Indicate if this entry is a GNU long name block
-     *
-     * @return true if this is a long name extension provided by GNU tar
-     */
-    public boolean isGNULongNameEntry() {
-        return linkFlag == LF_GNUTYPE_LONGNAME
-                           && name.toString().equals(GNU_LONGLINK);
-    }
-
-    /**
-     * Return whether or not this entry represents a directory.
-     *
-     * @return True if this entry is a directory.
-     */
-    public boolean isDirectory() {
-        if (file != null) {
-            return file.isDirectory();
-        }
-
-        if (linkFlag == LF_DIR) {
-            return true;
-        }
-
-        if (getName().endsWith("/")) {
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * If this entry represents a file, and the file is a directory, return
-     * an array of TarEntries for this entry's children.
-     *
-     * @return An array of TarEntry's for this entry's children.
-     */
-    public TarEntry[] getDirectoryEntries() {
-        if (file == null || !file.isDirectory()) {
-            return new TarEntry[0];
-        }
-
-        String[]   list = file.list();
-        TarEntry[] result = new TarEntry[list.length];
-
-        for (int i = 0; i < list.length; ++i) {
-            result[i] = new TarEntry(new File(file, list[i]));
-        }
-
-        return result;
-    }
-
-    /**
-     * Write an entry's header information to a header buffer.
-     *
-     * @param outbuf The tar entry header buffer to fill in.
-     */
-    public void writeEntryHeader(byte[] outbuf) {
-        int offset = 0;
-
-        offset = TarUtils.getNameBytes(name, outbuf, offset, NAMELEN);
-        offset = TarUtils.getOctalBytes(mode, outbuf, offset, MODELEN);
-        offset = TarUtils.getOctalBytes(userId, outbuf, offset, UIDLEN);
-        offset = TarUtils.getOctalBytes(groupId, outbuf, offset, GIDLEN);
-        offset = TarUtils.getLongOctalBytes(size, outbuf, offset, SIZELEN);
-        offset = TarUtils.getLongOctalBytes(modTime, outbuf, offset, MODTIMELEN);
-
-        int csOffset = offset;
-
-        for (int c = 0; c < CHKSUMLEN; ++c) {
-            outbuf[offset++] = (byte) ' ';
-        }
-
-        outbuf[offset++] = linkFlag;
-        offset = TarUtils.getNameBytes(linkName, outbuf, offset, NAMELEN);
-        offset = TarUtils.getNameBytes(magic, outbuf, offset, MAGICLEN);
-        offset = TarUtils.getNameBytes(userName, outbuf, offset, UNAMELEN);
-        offset = TarUtils.getNameBytes(groupName, outbuf, offset, GNAMELEN);
-        offset = TarUtils.getOctalBytes(devMajor, outbuf, offset, DEVLEN);
-        offset = TarUtils.getOctalBytes(devMinor, outbuf, offset, DEVLEN);
-
-        while (offset < outbuf.length) {
-            outbuf[offset++] = 0;
-        }
-
-        long chk = TarUtils.computeCheckSum(outbuf);
-
-        TarUtils.getCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN);
-    }
-
-    /**
-     * Parse an entry's header information from a header buffer.
-     *
-     * @param header The tar entry header buffer to get information from.
-     */
-    public void parseTarHeader(byte[] header) {
-        int offset = 0;
-
-        name = TarUtils.parseName(header, offset, NAMELEN);
-        offset += NAMELEN;
-        mode = (int) TarUtils.parseOctal(header, offset, MODELEN);
-        offset += MODELEN;
-        userId = (int) TarUtils.parseOctal(header, offset, UIDLEN);
-        offset += UIDLEN;
-        groupId = (int) TarUtils.parseOctal(header, offset, GIDLEN);
-        offset += GIDLEN;
-        size = TarUtils.parseOctal(header, offset, SIZELEN);
-        offset += SIZELEN;
-        modTime = TarUtils.parseOctal(header, offset, MODTIMELEN);
-        offset += MODTIMELEN;
-        offset += CHKSUMLEN;
-        linkFlag = header[offset++];
-        linkName = TarUtils.parseName(header, offset, NAMELEN);
-        offset += NAMELEN;
-        magic = TarUtils.parseName(header, offset, MAGICLEN);
-        offset += MAGICLEN;
-        userName = TarUtils.parseName(header, offset, UNAMELEN);
-        offset += UNAMELEN;
-        groupName = TarUtils.parseName(header, offset, GNAMELEN);
-        offset += GNAMELEN;
-        devMajor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
-        offset += DEVLEN;
-        devMinor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
-    }
-
-    /**
-     * Strips Windows' drive letter as well as any leading slashes,
-     * turns path separators into forward slahes.
-     */
-    private static String normalizeFileName(String fileName,
-                                            boolean preserveLeadingSlashes) {
-        String osname = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
-
-        if (osname != null) {
-
-            // Strip off drive letters!
-            // REVIEW Would a better check be "(File.separator == '\')"?
-
-            if (osname.startsWith("windows")) {
-                if (fileName.length() > 2) {
-                    char ch1 = fileName.charAt(0);
-                    char ch2 = fileName.charAt(1);
-
-                    if (ch2 == ':'
-                        && ((ch1 >= 'a' && ch1 <= 'z')
-                            || (ch1 >= 'A' && ch1 <= 'Z'))) {
-                        fileName = fileName.substring(2);
-                    }
-                }
-            } else if (osname.indexOf("netware") > -1) {
-                int colon = fileName.indexOf(':');
-                if (colon != -1) {
-                    fileName = fileName.substring(colon + 1);
-                }
-            }
-        }
-
-        fileName = fileName.replace(File.separatorChar, '/');
-
-        // No absolute pathnames
-        // Windows (and Posix?) paths can start with "\\NetworkDrive\",
-        // so we loop on starting /'s.
-        while (!preserveLeadingSlashes && fileName.startsWith("/")) {
-            fileName = fileName.substring(1);
-        }
-        return fileName;
-    }
-}
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Timothy Gerard Endres
+ * (time@ice.com) to whom the Ant project is very grateful for his great code.
+ */
+
+package org.apache.activemq.console.command.store.tar;
+
+import java.io.File;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * This class represents an entry in a Tar archive. It consists
+ * of the entry's header, as well as the entry's File. Entries
+ * can be instantiated in one of three ways, depending on how
+ * they are to be used.
+ * <p>
+ * TarEntries that are created from the header bytes read from
+ * an archive are instantiated with the TarEntry( byte[] )
+ * constructor. These entries will be used when extracting from
+ * or listing the contents of an archive. These entries have their
+ * header filled in using the header bytes. They also set the File
+ * to null, since they reference an archive entry not a file.
+ * <p>
+ * TarEntries that are created from Files that are to be written
+ * into an archive are instantiated with the TarEntry( File )
+ * constructor. These entries have their header filled in using
+ * the File's information. They also keep a reference to the File
+ * for convenience when writing entries.
+ * <p>
+ * Finally, TarEntries can be constructed from nothing but a name.
+ * This allows the programmer to construct the entry by hand, for
+ * instance when only an InputStream is available for writing to
+ * the archive, and the header information is constructed from
+ * other information. In this case the header fields are set to
+ * defaults and the File is set to null.
+ *
+ * <p>
+ * The C structure for a Tar Entry's header is:
+ * <pre>
+ * 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;
+ * </pre>
+ *
+ */
+
+public class TarEntry implements TarConstants {
+    /** The entry's name. */
+    private StringBuffer name;
+
+    /** The entry's permission mode. */
+    private int mode;
+
+    /** The entry's user id. */
+    private int userId;
+
+    /** The entry's group id. */
+    private int groupId;
+
+    /** The entry's size. */
+    private long size;
+
+    /** The entry's modification time. */
+    private long modTime;
+
+    /** The entry's link flag. */
+    private byte linkFlag;
+
+    /** The entry's link name. */
+    private StringBuffer linkName;
+
+    /** The entry's magic tag. */
+    private StringBuffer magic;
+
+    /** The entry's user name. */
+    private StringBuffer userName;
+
+    /** The entry's group name. */
+    private StringBuffer groupName;
+
+    /** The entry's major device number. */
+    private int devMajor;
+
+    /** The entry's minor device number. */
+    private int devMinor;
+
+    /** The entry's file reference */
+    private File file;
+
+    /** Maximum length of a user's name in the tar file */
+    public static final int MAX_NAMELEN = 31;
+
+    /** Default permissions bits for directories */
+    public static final int DEFAULT_DIR_MODE = 040755;
+
+    /** Default permissions bits for files */
+    public static final int DEFAULT_FILE_MODE = 0100644;
+
+    /** Convert millis to seconds */
+    public static final int MILLIS_PER_SECOND = 1000;
+
+    /**
+     * Construct an empty entry and prepares the header values.
+     */
+    private TarEntry () {
+        this.magic = new StringBuffer(TMAGIC);
+        this.name = new StringBuffer();
+        this.linkName = new StringBuffer();
+
+        String user = System.getProperty("user.name", "");
+
+        if (user.length() > MAX_NAMELEN) {
+            user = user.substring(0, MAX_NAMELEN);
+        }
+
+        this.userId = 0;
+        this.groupId = 0;
+        this.userName = new StringBuffer(user);
+        this.groupName = new StringBuffer("");
+        this.file = null;
+    }
+
+    /**
+     * Construct an entry with only a name. This allows the programmer
+     * to construct the entry's header "by hand". File is set to null.
+     *
+     * @param name the entry name
+     */
+    public TarEntry(String name) {
+        this(name, false);
+    }
+
+    /**
+     * Construct an entry with only a name. This allows the programmer
+     * to construct the entry's header "by hand". File is set to null.
+     *
+     * @param name the entry name
+     * @param preserveLeadingSlashes whether to allow leading slashes
+     * in the name.
+     */
+    public TarEntry(String name, boolean preserveLeadingSlashes) {
+        this();
+
+        name = normalizeFileName(name, preserveLeadingSlashes);
+        boolean isDir = name.endsWith("/");
+
+        this.devMajor = 0;
+        this.devMinor = 0;
+        this.name = new StringBuffer(name);
+        this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE;
+        this.linkFlag = isDir ? LF_DIR : LF_NORMAL;
+        this.userId = 0;
+        this.groupId = 0;
+        this.size = 0;
+        this.modTime = (new Date()).getTime() / MILLIS_PER_SECOND;
+        this.linkName = new StringBuffer("");
+        this.userName = new StringBuffer("");
+        this.groupName = new StringBuffer("");
+        this.devMajor = 0;
+        this.devMinor = 0;
+
+    }
+
+    /**
+     * Construct an entry with a name and a link flag.
+     *
+     * @param name the entry name
+     * @param linkFlag the entry link flag.
+     */
+    public TarEntry(String name, byte linkFlag) {
+        this(name);
+        this.linkFlag = linkFlag;
+        if (linkFlag == LF_GNUTYPE_LONGNAME) {
+            magic = new StringBuffer(GNU_TMAGIC);
+        }
+    }
+
+    /**
+     * Construct an entry for a file. File is set to file, and the
+     * header is constructed from information from the file.
+     *
+     * @param file The file that the entry represents.
+     */
+    public TarEntry(File file) {
+        this();
+
+        this.file = file;
+
+        String fileName = normalizeFileName(file.getPath(), false);
+        this.linkName = new StringBuffer("");
+        this.name = new StringBuffer(fileName);
+
+        if (file.isDirectory()) {
+            this.mode = DEFAULT_DIR_MODE;
+            this.linkFlag = LF_DIR;
+
+            int nameLength = name.length();
+            if (nameLength == 0 || name.charAt(nameLength - 1) != '/') {
+                this.name.append("/");
+            }
+            this.size = 0;
+        } else {
+            this.mode = DEFAULT_FILE_MODE;
+            this.linkFlag = LF_NORMAL;
+            this.size = file.length();
+        }
+
+        this.modTime = file.lastModified() / MILLIS_PER_SECOND;
+        this.devMajor = 0;
+        this.devMinor = 0;
+    }
+
+    /**
+     * Construct an entry from an archive's header bytes. File is set
+     * to null.
+     *
+     * @param headerBuf The header bytes from a tar archive entry.
+     */
+    public TarEntry(byte[] headerBuf) {
+        this();
+        parseTarHeader(headerBuf);
+    }
+
+    /**
+     * Determine if the two entries are equal. Equality is determined
+     * by the header names being equal.
+     *
+     * @param it Entry to be checked for equality.
+     * @return True if the entries are equal.
+     */
+    public boolean equals(TarEntry it) {
+        return getName().equals(it.getName());
+    }
+
+    /**
+     * Determine if the two entries are equal. Equality is determined
+     * by the header names being equal.
+     *
+     * @param it Entry to be checked for equality.
+     * @return True if the entries are equal.
+     */
+    public boolean equals(Object it) {
+        if (it == null || getClass() != it.getClass()) {
+            return false;
+        }
+        return equals((TarEntry) it);
+    }
+
+    /**
+     * Hashcodes are based on entry names.
+     *
+     * @return the entry hashcode
+     */
+    public int hashCode() {
+        return getName().hashCode();
+    }
+
+    /**
+     * Determine if the given entry is a descendant of this entry.
+     * Descendancy is determined by the name of the descendant
+     * starting with this entry's name.
+     *
+     * @param desc Entry to be checked as a descendent of this.
+     * @return True if entry is a descendant of this.
+     */
+    public boolean isDescendent(TarEntry desc) {
+        return desc.getName().startsWith(getName());
+    }
+
+    /**
+     * Get this entry's name.
+     *
+     * @return This entry's name.
+     */
+    public String getName() {
+        return name.toString();
+    }
+
+    /**
+     * Set this entry's name.
+     *
+     * @param name This entry's new name.
+     */
+    public void setName(String name) {
+        this.name = new StringBuffer(normalizeFileName(name, false));
+    }
+
+    /**
+     * Set the mode for this entry
+     *
+     * @param mode the mode for this entry
+     */
+    public void setMode(int mode) {
+        this.mode = mode;
+    }
+
+    /**
+     * Get this entry's link name.
+     *
+     * @return This entry's link name.
+     */
+    public String getLinkName() {
+        return linkName.toString();
+    }
+
+    /**
+     * Get this entry's user id.
+     *
+     * @return This entry's user id.
+     */
+    public int getUserId() {
+        return userId;
+    }
+
+    /**
+     * Set this entry's user id.
+     *
+     * @param userId This entry's new user id.
+     */
+    public void setUserId(int userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * Get this entry's group id.
+     *
+     * @return This entry's group id.
+     */
+    public int getGroupId() {
+        return groupId;
+    }
+
+    /**
+     * Set this entry's group id.
+     *
+     * @param groupId This entry's new group id.
+     */
+    public void setGroupId(int groupId) {
+        this.groupId = groupId;
+    }
+
+    /**
+     * Get this entry's user name.
+     *
+     * @return This entry's user name.
+     */
+    public String getUserName() {
+        return userName.toString();
+    }
+
+    /**
+     * Set this entry's user name.
+     *
+     * @param userName This entry's new user name.
+     */
+    public void setUserName(String userName) {
+        this.userName = new StringBuffer(userName);
+    }
+
+    /**
+     * Get this entry's group name.
+     *
+     * @return This entry's group name.
+     */
+    public String getGroupName() {
+        return groupName.toString();
+    }
+
+    /**
+     * Set this entry's group name.
+     *
+     * @param groupName This entry's new group name.
+     */
+    public void setGroupName(String groupName) {
+        this.groupName = new StringBuffer(groupName);
+    }
+
+    /**
+     * Convenience method to set this entry's group and user ids.
+     *
+     * @param userId This entry's new user id.
+     * @param groupId This entry's new group id.
+     */
+    public void setIds(int userId, int groupId) {
+        setUserId(userId);
+        setGroupId(groupId);
+    }
+
+    /**
+     * Convenience method to set this entry's group and user names.
+     *
+     * @param userName This entry's new user name.
+     * @param groupName This entry's new group name.
+     */
+    public void setNames(String userName, String groupName) {
+        setUserName(userName);
+        setGroupName(groupName);
+    }
+
+    /**
+     * Set this entry's modification time. The parameter passed
+     * to this method is in "Java time".
+     *
+     * @param time This entry's new modification time.
+     */
+    public void setModTime(long time) {
+        modTime = time / MILLIS_PER_SECOND;
+    }
+
+    /**
+     * Set this entry's modification time.
+     *
+     * @param time This entry's new modification time.
+     */
+    public void setModTime(Date time) {
+        modTime = time.getTime() / MILLIS_PER_SECOND;
+    }
+
+    /**
+     * Set this entry's modification time.
+     *
+     * @return time This entry's new modification time.
+     */
+    public Date getModTime() {
+        return new Date(modTime * MILLIS_PER_SECOND);
+    }
+
+    /**
+     * Get this entry's file.
+     *
+     * @return This entry's file.
+     */
+    public File getFile() {
+        return file;
+    }
+
+    /**
+     * Get this entry's mode.
+     *
+     * @return This entry's mode.
+     */
+    public int getMode() {
+        return mode;
+    }
+
+    /**
+     * Get this entry's file size.
+     *
+     * @return This entry's file size.
+     */
+    public long getSize() {
+        return size;
+    }
+
+    /**
+     * Set this entry's file size.
+     *
+     * @param size This entry's new file size.
+     */
+    public void setSize(long size) {
+        this.size = size;
+    }
+
+
+    /**
+     * Indicate if this entry is a GNU long name block
+     *
+     * @return true if this is a long name extension provided by GNU tar
+     */
+    public boolean isGNULongNameEntry() {
+        return linkFlag == LF_GNUTYPE_LONGNAME
+                           && name.toString().equals(GNU_LONGLINK);
+    }
+
+    /**
+     * Return whether or not this entry represents a directory.
+     *
+     * @return True if this entry is a directory.
+     */
+    public boolean isDirectory() {
+        if (file != null) {
+            return file.isDirectory();
+        }
+
+        if (linkFlag == LF_DIR) {
+            return true;
+        }
+
+        if (getName().endsWith("/")) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * If this entry represents a file, and the file is a directory, return
+     * an array of TarEntries for this entry's children.
+     *
+     * @return An array of TarEntry's for this entry's children.
+     */
+    public TarEntry[] getDirectoryEntries() {
+        if (file == null || !file.isDirectory()) {
+            return new TarEntry[0];
+        }
+
+        String[]   list = file.list();
+        TarEntry[] result = new TarEntry[list.length];
+
+        for (int i = 0; i < list.length; ++i) {
+            result[i] = new TarEntry(new File(file, list[i]));
+        }
+
+        return result;
+    }
+
+    /**
+     * Write an entry's header information to a header buffer.
+     *
+     * @param outbuf The tar entry header buffer to fill in.
+     */
+    public void writeEntryHeader(byte[] outbuf) {
+        int offset = 0;
+
+        offset = TarUtils.getNameBytes(name, outbuf, offset, NAMELEN);
+        offset = TarUtils.getOctalBytes(mode, outbuf, offset, MODELEN);
+        offset = TarUtils.getOctalBytes(userId, outbuf, offset, UIDLEN);
+        offset = TarUtils.getOctalBytes(groupId, outbuf, offset, GIDLEN);
+        offset = TarUtils.getLongOctalBytes(size, outbuf, offset, SIZELEN);
+        offset = TarUtils.getLongOctalBytes(modTime, outbuf, offset, MODTIMELEN);
+
+        int csOffset = offset;
+
+        for (int c = 0; c < CHKSUMLEN; ++c) {
+            outbuf[offset++] = (byte) ' ';
+        }
+
+        outbuf[offset++] = linkFlag;
+        offset = TarUtils.getNameBytes(linkName, outbuf, offset, NAMELEN);
+        offset = TarUtils.getNameBytes(magic, outbuf, offset, MAGICLEN);
+        offset = TarUtils.getNameBytes(userName, outbuf, offset, UNAMELEN);
+        offset = TarUtils.getNameBytes(groupName, outbuf, offset, GNAMELEN);
+        offset = TarUtils.getOctalBytes(devMajor, outbuf, offset, DEVLEN);
+        offset = TarUtils.getOctalBytes(devMinor, outbuf, offset, DEVLEN);
+
+        while (offset < outbuf.length) {
+            outbuf[offset++] = 0;
+        }
+
+        long chk = TarUtils.computeCheckSum(outbuf);
+
+        TarUtils.getCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN);
+    }
+
+    /**
+     * Parse an entry's header information from a header buffer.
+     *
+     * @param header The tar entry header buffer to get information from.
+     */
+    public void parseTarHeader(byte[] header) {
+        int offset = 0;
+
+        name = TarUtils.parseName(header, offset, NAMELEN);
+        offset += NAMELEN;
+        mode = (int) TarUtils.parseOctal(header, offset, MODELEN);
+        offset += MODELEN;
+        userId = (int) TarUtils.parseOctal(header, offset, UIDLEN);
+        offset += UIDLEN;
+        groupId = (int) TarUtils.parseOctal(header, offset, GIDLEN);
+        offset += GIDLEN;
+        size = TarUtils.parseOctal(header, offset, SIZELEN);
+        offset += SIZELEN;
+        modTime = TarUtils.parseOctal(header, offset, MODTIMELEN);
+        offset += MODTIMELEN;
+        offset += CHKSUMLEN;
+        linkFlag = header[offset++];
+        linkName = TarUtils.parseName(header, offset, NAMELEN);
+        offset += NAMELEN;
+        magic = TarUtils.parseName(header, offset, MAGICLEN);
+        offset += MAGICLEN;
+        userName = TarUtils.parseName(header, offset, UNAMELEN);
+        offset += UNAMELEN;
+        groupName = TarUtils.parseName(header, offset, GNAMELEN);
+        offset += GNAMELEN;
+        devMajor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
+        offset += DEVLEN;
+        devMinor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
+    }
+
+    /**
+     * Strips Windows' drive letter as well as any leading slashes,
+     * turns path separators into forward slahes.
+     */
+    private static String normalizeFileName(String fileName,
+                                            boolean preserveLeadingSlashes) {
+        String osname = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
+
+        if (osname != null) {
+
+            // Strip off drive letters!
+            // REVIEW Would a better check be "(File.separator == '\')"?
+
+            if (osname.startsWith("windows")) {
+                if (fileName.length() > 2) {
+                    char ch1 = fileName.charAt(0);
+                    char ch2 = fileName.charAt(1);
+
+                    if (ch2 == ':'
+                        && ((ch1 >= 'a' && ch1 <= 'z')
+                            || (ch1 >= 'A' && ch1 <= 'Z'))) {
+                        fileName = fileName.substring(2);
+                    }
+                }
+            } else if (osname.indexOf("netware") > -1) {
+                int colon = fileName.indexOf(':');
+                if (colon != -1) {
+                    fileName = fileName.substring(colon + 1);
+                }
+            }
+        }
+
+        fileName = fileName.replace(File.separatorChar, '/');
+
+        // No absolute pathnames
+        // Windows (and Posix?) paths can start with "\\NetworkDrive\",
+        // so we loop on starting /'s.
+        while (!preserveLeadingSlashes && fileName.startsWith("/")) {
+            fileName = fileName.substring(1);
+        }
+        return fileName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/3f32507f/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarInputStream.java
----------------------------------------------------------------------
diff --git a/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarInputStream.java b/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarInputStream.java
index 53c114d..f0a75a9 100644
--- a/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarInputStream.java
+++ b/activemq-console/src/main/java/org/apache/activemq/console/command/store/tar/TarInputStream.java
@@ -1,402 +1,402 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- */
-
-/*
- * This package is based on the work done by Timothy Gerard Endres
- * (time@ice.com) to whom the Ant project is very grateful for his great code.
- */
-
-package org.apache.activemq.console.command.store.tar;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * The TarInputStream reads a UNIX tar archive as an InputStream.
- * methods are provided to position at each successive entry in
- * the archive, and the read each entry as a normal input stream
- * using read().
- *
- */
-public class TarInputStream extends FilterInputStream {
-    private static final int SMALL_BUFFER_SIZE = 256;
-    private static final int BUFFER_SIZE = 8 * 1024;
-    private static final int LARGE_BUFFER_SIZE = 32 * 1024;
-    private static final int BYTE_MASK = 0xFF;
-
-    // CheckStyle:VisibilityModifier OFF - bc
-    protected boolean debug;
-    protected boolean hasHitEOF;
-    protected long entrySize;
-    protected long entryOffset;
-    protected byte[] readBuf;
-    protected TarBuffer buffer;
-    protected TarEntry currEntry;
-
-    /**
-     * This contents of this array is not used at all in this class,
-     * it is only here to avoid repreated object creation during calls
-     * to the no-arg read method.
-     */
-    protected byte[] oneBuf;
-
-    // CheckStyle:VisibilityModifier ON
-
-    /**
-     * Constructor for TarInputStream.
-     * @param is the input stream to use
-     */
-    public TarInputStream(InputStream is) {
-        this(is, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE);
-    }
-
-    /**
-     * Constructor for TarInputStream.
-     * @param is the input stream to use
-     * @param blockSize the block size to use
-     */
-    public TarInputStream(InputStream is, int blockSize) {
-        this(is, blockSize, TarBuffer.DEFAULT_RCDSIZE);
-    }
-
-    /**
-     * Constructor for TarInputStream.
-     * @param is the input stream to use
-     * @param blockSize the block size to use
-     * @param recordSize the record size to use
-     */
-    public TarInputStream(InputStream is, int blockSize, int recordSize) {
-        super(is);
-
-        this.buffer = new TarBuffer(is, blockSize, recordSize);
-        this.readBuf = null;
-        this.oneBuf = new byte[1];
-        this.debug = false;
-        this.hasHitEOF = false;
-    }
-
-    /**
-     * Sets the debugging flag.
-     *
-     * @param debug True to turn on debugging.
-     */
-    public void setDebug(boolean debug) {
-        this.debug = debug;
-        buffer.setDebug(debug);
-    }
-
-    /**
-     * Closes this stream. Calls the TarBuffer's close() method.
-     * @throws IOException on error
-     */
-    public void close() throws IOException {
-        buffer.close();
-    }
-
-    /**
-     * Get the record size being used by this stream's TarBuffer.
-     *
-     * @return The TarBuffer record size.
-     */
-    public int getRecordSize() {
-        return buffer.getRecordSize();
-    }
-
-    /**
-     * Get the available data that can be read from the current
-     * entry in the archive. This does not indicate how much data
-     * is left in the entire archive, only in the current entry.
-     * This value is determined from the entry's size header field
-     * and the amount of data already read from the current entry.
-     * Integer.MAX_VALUE is returen in case more than Integer.MAX_VALUE
-     * bytes are left in the current entry in the archive.
-     *
-     * @return The number of available bytes for the current entry.
-     * @throws IOException for signature
-     */
-    public int available() throws IOException {
-        if (entrySize - entryOffset > Integer.MAX_VALUE) {
-            return Integer.MAX_VALUE;
-        }
-        return (int) (entrySize - entryOffset);
-    }
-
-    /**
-     * Skip bytes in the input buffer. This skips bytes in the
-     * current entry's data, not the entire archive, and will
-     * stop at the end of the current entry's data if the number
-     * to skip extends beyond that point.
-     *
-     * @param numToSkip The number of bytes to skip.
-     * @return the number actually skipped
-     * @throws IOException on error
-     */
-    public long skip(long numToSkip) throws IOException {
-        // REVIEW
-        // This is horribly inefficient, but it ensures that we
-        // properly skip over bytes via the TarBuffer...
-        //
-        byte[] skipBuf = new byte[BUFFER_SIZE];
-        long skip = numToSkip;
-        while (skip > 0) {
-            int realSkip = (int) (skip > skipBuf.length ? skipBuf.length : skip);
-            int numRead = read(skipBuf, 0, realSkip);
-            if (numRead == -1) {
-                break;
-            }
-            skip -= numRead;
-        }
-        return (numToSkip - skip);
-    }
-
-    /**
-     * Since we do not support marking just yet, we return false.
-     *
-     * @return False.
-     */
-    public boolean markSupported() {
-        return false;
-    }
-
-    /**
-     * Since we do not support marking just yet, we do nothing.
-     *
-     * @param markLimit The limit to mark.
-     */
-    public void mark(int markLimit) {
-    }
-
-    /**
-     * Since we do not support marking just yet, we do nothing.
-     */
-    public void reset() {
-    }
-
-    /**
-     * Get the next entry in this tar archive. This will skip
-     * over any remaining data in the current entry, if there
-     * is one, and place the input stream at the header of the
-     * next entry, and read the header and instantiate a new
-     * TarEntry from the header bytes and return that entry.
-     * If there are no more entries in the archive, null will
-     * be returned to indicate that the end of the archive has
-     * been reached.
-     *
-     * @return The next TarEntry in the archive, or null.
-     * @throws IOException on error
-     */
-    public TarEntry getNextEntry() throws IOException {
-        if (hasHitEOF) {
-            return null;
-        }
-
-        if (currEntry != null) {
-            long numToSkip = entrySize - entryOffset;
-
-            if (debug) {
-                System.err.println("TarInputStream: SKIP currENTRY '"
-                        + currEntry.getName() + "' SZ "
-                        + entrySize + " OFF "
-                        + entryOffset + "  skipping "
-                        + numToSkip + " bytes");
-            }
-
-            while (numToSkip > 0) {
-                long skipped = skip(numToSkip);
-                if (skipped <= 0) {
-                    throw new RuntimeException("failed to skip current tar"
-                                               + " entry");
-                }
-                numToSkip -= skipped;
-            }
-
-            readBuf = null;
-        }
-
-        byte[] headerBuf = buffer.readRecord();
-
-        if (headerBuf == null) {
-            if (debug) {
-                System.err.println("READ NULL RECORD");
-            }
-            hasHitEOF = true;
-        } else if (buffer.isEOFRecord(headerBuf)) {
-            if (debug) {
-                System.err.println("READ EOF RECORD");
-            }
-            hasHitEOF = true;
-        }
-
-        if (hasHitEOF) {
-            currEntry = null;
-        } else {
-            currEntry = new TarEntry(headerBuf);
-
-            if (debug) {
-                System.err.println("TarInputStream: SET CURRENTRY '"
-                        + currEntry.getName()
-                        + "' size = "
-                        + currEntry.getSize());
-            }
-
-            entryOffset = 0;
-
-            entrySize = currEntry.getSize();
-        }
-
-        if (currEntry != null && currEntry.isGNULongNameEntry()) {
-            // read in the name
-            StringBuffer longName = new StringBuffer();
-            byte[] buf = new byte[SMALL_BUFFER_SIZE];
-            int length = 0;
-            while ((length = read(buf)) >= 0) {
-                longName.append(new String(buf, 0, length));
-            }
-            getNextEntry();
-            if (currEntry == null) {
-                // Bugzilla: 40334
-                // Malformed tar file - long entry name not followed by entry
-                return null;
-            }
-            // remove trailing null terminator
-            if (longName.length() > 0
-                && longName.charAt(longName.length() - 1) == 0) {
-                longName.deleteCharAt(longName.length() - 1);
-            }
-            currEntry.setName(longName.toString());
-        }
-
-        return currEntry;
-    }
-
-    /**
-     * Reads a byte from the current tar archive entry.
-     *
-     * This method simply calls read( byte[], int, int ).
-     *
-     * @return The byte read, or -1 at EOF.
-     * @throws IOException on error
-     */
-    public int read() throws IOException {
-        int num = read(oneBuf, 0, 1);
-        return num == -1 ? -1 : ((int) oneBuf[0]) & BYTE_MASK;
-    }
-
-    /**
-     * Reads bytes from the current tar archive entry.
-     *
-     * This method is aware of the boundaries of the current
-     * entry in the archive and will deal with them as if they
-     * were this stream's start and EOF.
-     *
-     * @param buf The buffer into which to place bytes read.
-     * @param offset The offset at which to place bytes read.
-     * @param numToRead The number of bytes to read.
-     * @return The number of bytes read, or -1 at EOF.
-     * @throws IOException on error
-     */
-    public int read(byte[] buf, int offset, int numToRead) throws IOException {
-        int totalRead = 0;
-
-        if (entryOffset >= entrySize) {
-            return -1;
-        }
-
-        if ((numToRead + entryOffset) > entrySize) {
-            numToRead = (int) (entrySize - entryOffset);
-        }
-
-        if (readBuf != null) {
-            int sz = (numToRead > readBuf.length) ? readBuf.length
-                    : numToRead;
-
-            System.arraycopy(readBuf, 0, buf, offset, sz);
-
-            if (sz >= readBuf.length) {
-                readBuf = null;
-            } else {
-                int newLen = readBuf.length - sz;
-                byte[] newBuf = new byte[newLen];
-
-                System.arraycopy(readBuf, sz, newBuf, 0, newLen);
-
-                readBuf = newBuf;
-            }
-
-            totalRead += sz;
-            numToRead -= sz;
-            offset += sz;
-        }
-
-        while (numToRead > 0) {
-            byte[] rec = buffer.readRecord();
-
-            if (rec == null) {
-                // Unexpected EOF!
-                throw new IOException("unexpected EOF with " + numToRead
-                        + " bytes unread");
-            }
-
-            int sz = numToRead;
-            int recLen = rec.length;
-
-            if (recLen > sz) {
-                System.arraycopy(rec, 0, buf, offset, sz);
-
-                readBuf = new byte[recLen - sz];
-
-                System.arraycopy(rec, sz, readBuf, 0, recLen - sz);
-            } else {
-                sz = recLen;
-
-                System.arraycopy(rec, 0, buf, offset, recLen);
-            }
-
-            totalRead += sz;
-            numToRead -= sz;
-            offset += sz;
-        }
-
-        entryOffset += totalRead;
-
-        return totalRead;
-    }
-
-    /**
-     * Copies the contents of the current tar archive entry directly into
-     * an output stream.
-     *
-     * @param out The OutputStream into which to write the entry's data.
-     * @throws IOException on error
-     */
-    public void copyEntryContents(OutputStream out) throws IOException {
-        byte[] buf = new byte[LARGE_BUFFER_SIZE];
-
-        while (true) {
-            int numRead = read(buf, 0, buf.length);
-
-            if (numRead == -1) {
-                break;
-            }
-
-            out.write(buf, 0, numRead);
-        }
-    }
-}
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Timothy Gerard Endres
+ * (time@ice.com) to whom the Ant project is very grateful for his great code.
+ */
+
+package org.apache.activemq.console.command.store.tar;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * The TarInputStream reads a UNIX tar archive as an InputStream.
+ * methods are provided to position at each successive entry in
+ * the archive, and the read each entry as a normal input stream
+ * using read().
+ *
+ */
+public class TarInputStream extends FilterInputStream {
+    private static final int SMALL_BUFFER_SIZE = 256;
+    private static final int BUFFER_SIZE = 8 * 1024;
+    private static final int LARGE_BUFFER_SIZE = 32 * 1024;
+    private static final int BYTE_MASK = 0xFF;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean debug;
+    protected boolean hasHitEOF;
+    protected long entrySize;
+    protected long entryOffset;
+    protected byte[] readBuf;
+    protected TarBuffer buffer;
+    protected TarEntry currEntry;
+
+    /**
+     * This contents of this array is not used at all in this class,
+     * it is only here to avoid repreated object creation during calls
+     * to the no-arg read method.
+     */
+    protected byte[] oneBuf;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Constructor for TarInputStream.
+     * @param is the input stream to use
+     */
+    public TarInputStream(InputStream is) {
+        this(is, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param is the input stream to use
+     * @param blockSize the block size to use
+     */
+    public TarInputStream(InputStream is, int blockSize) {
+        this(is, blockSize, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param is the input stream to use
+     * @param blockSize the block size to use
+     * @param recordSize the record size to use
+     */
+    public TarInputStream(InputStream is, int blockSize, int recordSize) {
+        super(is);
+
+        this.buffer = new TarBuffer(is, blockSize, recordSize);
+        this.readBuf = null;
+        this.oneBuf = new byte[1];
+        this.debug = false;
+        this.hasHitEOF = false;
+    }
+
+    /**
+     * Sets the debugging flag.
+     *
+     * @param debug True to turn on debugging.
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+        buffer.setDebug(debug);
+    }
+
+    /**
+     * Closes this stream. Calls the TarBuffer's close() method.
+     * @throws IOException on error
+     */
+    public void close() throws IOException {
+        buffer.close();
+    }
+
+    /**
+     * Get the record size being used by this stream's TarBuffer.
+     *
+     * @return The TarBuffer record size.
+     */
+    public int getRecordSize() {
+        return buffer.getRecordSize();
+    }
+
+    /**
+     * Get the available data that can be read from the current
+     * entry in the archive. This does not indicate how much data
+     * is left in the entire archive, only in the current entry.
+     * This value is determined from the entry's size header field
+     * and the amount of data already read from the current entry.
+     * Integer.MAX_VALUE is returen in case more than Integer.MAX_VALUE
+     * bytes are left in the current entry in the archive.
+     *
+     * @return The number of available bytes for the current entry.
+     * @throws IOException for signature
+     */
+    public int available() throws IOException {
+        if (entrySize - entryOffset > Integer.MAX_VALUE) {
+            return Integer.MAX_VALUE;
+        }
+        return (int) (entrySize - entryOffset);
+    }
+
+    /**
+     * Skip bytes in the input buffer. This skips bytes in the
+     * current entry's data, not the entire archive, and will
+     * stop at the end of the current entry's data if the number
+     * to skip extends beyond that point.
+     *
+     * @param numToSkip The number of bytes to skip.
+     * @return the number actually skipped
+     * @throws IOException on error
+     */
+    public long skip(long numToSkip) throws IOException {
+        // REVIEW
+        // This is horribly inefficient, but it ensures that we
+        // properly skip over bytes via the TarBuffer...
+        //
+        byte[] skipBuf = new byte[BUFFER_SIZE];
+        long skip = numToSkip;
+        while (skip > 0) {
+            int realSkip = (int) (skip > skipBuf.length ? skipBuf.length : skip);
+            int numRead = read(skipBuf, 0, realSkip);
+            if (numRead == -1) {
+                break;
+            }
+            skip -= numRead;
+        }
+        return (numToSkip - skip);
+    }
+
+    /**
+     * Since we do not support marking just yet, we return false.
+     *
+     * @return False.
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * Since we do not support marking just yet, we do nothing.
+     *
+     * @param markLimit The limit to mark.
+     */
+    public void mark(int markLimit) {
+    }
+
+    /**
+     * Since we do not support marking just yet, we do nothing.
+     */
+    public void reset() {
+    }
+
+    /**
+     * Get the next entry in this tar archive. This will skip
+     * over any remaining data in the current entry, if there
+     * is one, and place the input stream at the header of the
+     * next entry, and read the header and instantiate a new
+     * TarEntry from the header bytes and return that entry.
+     * If there are no more entries in the archive, null will
+     * be returned to indicate that the end of the archive has
+     * been reached.
+     *
+     * @return The next TarEntry in the archive, or null.
+     * @throws IOException on error
+     */
+    public TarEntry getNextEntry() throws IOException {
+        if (hasHitEOF) {
+            return null;
+        }
+
+        if (currEntry != null) {
+            long numToSkip = entrySize - entryOffset;
+
+            if (debug) {
+                System.err.println("TarInputStream: SKIP currENTRY '"
+                        + currEntry.getName() + "' SZ "
+                        + entrySize + " OFF "
+                        + entryOffset + "  skipping "
+                        + numToSkip + " bytes");
+            }
+
+            while (numToSkip > 0) {
+                long skipped = skip(numToSkip);
+                if (skipped <= 0) {
+                    throw new RuntimeException("failed to skip current tar"
+                                               + " entry");
+                }
+                numToSkip -= skipped;
+            }
+
+            readBuf = null;
+        }
+
+        byte[] headerBuf = buffer.readRecord();
+
+        if (headerBuf == null) {
+            if (debug) {
+                System.err.println("READ NULL RECORD");
+            }
+            hasHitEOF = true;
+        } else if (buffer.isEOFRecord(headerBuf)) {
+            if (debug) {
+                System.err.println("READ EOF RECORD");
+            }
+            hasHitEOF = true;
+        }
+
+        if (hasHitEOF) {
+            currEntry = null;
+        } else {
+            currEntry = new TarEntry(headerBuf);
+
+            if (debug) {
+                System.err.println("TarInputStream: SET CURRENTRY '"
+                        + currEntry.getName()
+                        + "' size = "
+                        + currEntry.getSize());
+            }
+
+            entryOffset = 0;
+
+            entrySize = currEntry.getSize();
+        }
+
+        if (currEntry != null && currEntry.isGNULongNameEntry()) {
+            // read in the name
+            StringBuffer longName = new StringBuffer();
+            byte[] buf = new byte[SMALL_BUFFER_SIZE];
+            int length = 0;
+            while ((length = read(buf)) >= 0) {
+                longName.append(new String(buf, 0, length));
+            }
+            getNextEntry();
+            if (currEntry == null) {
+                // Bugzilla: 40334
+                // Malformed tar file - long entry name not followed by entry
+                return null;
+            }
+            // remove trailing null terminator
+            if (longName.length() > 0
+                && longName.charAt(longName.length() - 1) == 0) {
+                longName.deleteCharAt(longName.length() - 1);
+            }
+            currEntry.setName(longName.toString());
+        }
+
+        return currEntry;
+    }
+
+    /**
+     * Reads a byte from the current tar archive entry.
+     *
+     * This method simply calls read( byte[], int, int ).
+     *
+     * @return The byte read, or -1 at EOF.
+     * @throws IOException on error
+     */
+    public int read() throws IOException {
+        int num = read(oneBuf, 0, 1);
+        return num == -1 ? -1 : ((int) oneBuf[0]) & BYTE_MASK;
+    }
+
+    /**
+     * Reads bytes from the current tar archive entry.
+     *
+     * This method is aware of the boundaries of the current
+     * entry in the archive and will deal with them as if they
+     * were this stream's start and EOF.
+     *
+     * @param buf The buffer into which to place bytes read.
+     * @param offset The offset at which to place bytes read.
+     * @param numToRead The number of bytes to read.
+     * @return The number of bytes read, or -1 at EOF.
+     * @throws IOException on error
+     */
+    public int read(byte[] buf, int offset, int numToRead) throws IOException {
+        int totalRead = 0;
+
+        if (entryOffset >= entrySize) {
+            return -1;
+        }
+
+        if ((numToRead + entryOffset) > entrySize) {
+            numToRead = (int) (entrySize - entryOffset);
+        }
+
+        if (readBuf != null) {
+            int sz = (numToRead > readBuf.length) ? readBuf.length
+                    : numToRead;
+
+            System.arraycopy(readBuf, 0, buf, offset, sz);
+
+            if (sz >= readBuf.length) {
+                readBuf = null;
+            } else {
+                int newLen = readBuf.length - sz;
+                byte[] newBuf = new byte[newLen];
+
+                System.arraycopy(readBuf, sz, newBuf, 0, newLen);
+
+                readBuf = newBuf;
+            }
+
+            totalRead += sz;
+            numToRead -= sz;
+            offset += sz;
+        }
+
+        while (numToRead > 0) {
+            byte[] rec = buffer.readRecord();
+
+            if (rec == null) {
+                // Unexpected EOF!
+                throw new IOException("unexpected EOF with " + numToRead
+                        + " bytes unread");
+            }
+
+            int sz = numToRead;
+            int recLen = rec.length;
+
+            if (recLen > sz) {
+                System.arraycopy(rec, 0, buf, offset, sz);
+
+                readBuf = new byte[recLen - sz];
+
+                System.arraycopy(rec, sz, readBuf, 0, recLen - sz);
+            } else {
+                sz = recLen;
+
+                System.arraycopy(rec, 0, buf, offset, recLen);
+            }
+
+            totalRead += sz;
+            numToRead -= sz;
+            offset += sz;
+        }
+
+        entryOffset += totalRead;
+
+        return totalRead;
+    }
+
+    /**
+     * Copies the contents of the current tar archive entry directly into
+     * an output stream.
+     *
+     * @param out The OutputStream into which to write the entry's data.
+     * @throws IOException on error
+     */
+    public void copyEntryContents(OutputStream out) throws IOException {
+        byte[] buf = new byte[LARGE_BUFFER_SIZE];
+
+        while (true) {
+            int numRead = read(buf, 0, buf.length);
+
+            if (numRead == -1) {
+                break;
+            }
+
+            out.write(buf, 0, numRead);
+        }
+    }
+}


Mime
View raw message