    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one
    003     * or more contributor license agreements.  See the NOTICE file
    004     * distributed with this work for additional information
    005     * regarding copyright ownership.  The ASF licenses this file
    006     * to you under the Apache License, Version 2.0 (the
    007     * "License"); you may not use this file except in compliance
    008     * with the License.  You may obtain a copy of the License at
    009     *
    010     * http://www.apache.org/licenses/LICENSE-2.0
    011     *
    012     * Unless required by applicable law or agreed to in writing,
    013     * software distributed under the License is distributed on an
    014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    015     * KIND, either express or implied.  See the License for the
    016     * specific language governing permissions and limitations
    017     * under the License.
    018     */
    019    package org.apache.commons.compress.archivers.ar;
    020
    021    import java.io.File;
    022
    023    import org.apache.commons.compress.archivers.ArchiveEntry;
    024
    025    /**
    026     * Represents an archive entry in the "ar" format.
    027     *
    028     * Each AR archive starts with "!<arch>" followed by a LF. After these 8 bytes
    029     * the archive entries are listed. The format of an entry header is as it follows:
    030     *
    031     * <pre>
    032     * START BYTE   END BYTE    NAME                    FORMAT      LENGTH
    033     * 0            15          File name               ASCII       16
    034     * 16           27          Modification timestamp  Decimal     12
    035     * 28           33          Owner ID                Decimal     6
    036     * 34           39          Group ID                Decimal     6
    037     * 40           47          File mode               Octal       8
    038     * 48           57          File size (bytes)       Decimal     10
    039     * 58           59          File magic              \140\012    2
    040     * </pre>
    041     *
    042     * This specifies that an ar archive entry header contains 60 bytes.
    043     *
    044     * Due to the limitation of the file name length to 16 bytes GNU and BSD has
    045     * their own variants of this format. This formats are currently not supported
    046     * and file names with a bigger size than 16 bytes are not possible at the
    047     * moment.
    048     *
    049     * @Immutable
    050     */
    051    public class ArArchiveEntry implements ArchiveEntry {
    052
    053        /** The header for each entry */
    054        public static final String HEADER = "!<arch>\n";
    055
    056        /** The trailer for each entry */
    057        public static final String TRAILER = "`\012";
    058
    059        /**
    060         * SVR4/GNU adds a trailing / to names; BSD does not.
    061         * They also vary in how names longer than 16 characters are represented.
    062         * (Not yet supported by this implementation)
    063         */
    064        private final String name;
    065            private final int userId;
    066            private final int groupId;
    067            private final int mode;
    068        private static final int DEFAULT_MODE = 33188; // = (octal) 0100644
    069            private final long lastModified;
    070            private final long length;
    071
    072            public ArArchiveEntry(String name, long length) {
    073                    this(name, length, 0, 0, DEFAULT_MODE, System.currentTimeMillis());
    074            }
    075
    076            public ArArchiveEntry(String name, long length, int userId, int groupId, int mode, long lastModified) {
    077                    this.name = name;
    078                    this.length = length;
    079                    this.userId = userId;
    080                    this.groupId = groupId;
    081                    this.mode = mode;
    082                    this.lastModified = lastModified;
    083            }
    084
    085            public ArArchiveEntry(File inputFile, String entryName) {
    086                // TODO sort out mode
    087            this(entryName, inputFile.isFile() ? inputFile.length() : 0, 0, 0, 0, inputFile.lastModified());
    088        }
    089
    090        public long getSize() {
    091                    return this.getLength();
    092            }
    093
    094            public String getName() {
    095                    return name;
    096            }
    097
    098            public int getUserId() {
    099                    return userId;
    100            }
    101
    102            public int getGroupId() {
    103                    return groupId;
    104            }
    105
    106            public int getMode() {
    107                    return mode;
    108            }
    109
    110            public long getLastModified() {
    111                    return lastModified;
    112            }
    113
    114            public long getLength() {
    115                    return length;
    116            }
    117
    118            public boolean isDirectory() {
    119                    return false;
    120            }
    121
    122        /* (non-Javadoc)
    123         * @see java.lang.Object#hashCode()
    124         */
    125        public int hashCode() {
    126            final int prime = 31;
    127            int result = 1;
    128            result = prime * result + ((name == null) ? 0 : name.hashCode());
    129            return result;
    130        }
    131
    132        /* (non-Javadoc)
    133         * @see java.lang.Object#equals(java.lang.Object)
    134         */
    135        public boolean equals(Object obj) {
    136            if (this == obj) {
    137                return true;
    138            }
    139            if (obj == null || getClass() != obj.getClass()) {
    140                return false;
    141            }
    142            ArArchiveEntry other = (ArArchiveEntry) obj;
    143            if (name == null) {
    144                if (other.name != null) {
    145                    return false;
    146                }
    147            } else if (!name.equals(other.name)) {
    148                return false;
    149            }
    150            return true;
    151        }
    152    }