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    }