blob: 4eb4b1adefadddfc12db6dff1c89f2551ea06859 [file] [log] [blame]
Torsten Curdtca165392008-07-10 10:17:44 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.commons.compress.archivers.ar;
20
Sebastian Bazleyfec51a12009-03-31 00:35:56 +000021import java.io.File;
Stefan Bodewig17ffd7f2009-08-01 14:52:15 +000022import java.util.Date;
Sebastian Bazleyfec51a12009-03-31 00:35:56 +000023
Torsten Curdtca165392008-07-10 10:17:44 +000024import org.apache.commons.compress.archivers.ArchiveEntry;
25
Sebastian Bazley1d3d6ea2009-03-14 02:24:54 +000026/**
27 * Represents an archive entry in the "ar" format.
Sebastian Bazleya91e7c72009-03-27 21:13:51 +000028 *
Christian Grobmeier272aafd2009-04-07 16:56:00 +000029 * Each AR archive starts with "!<arch>" followed by a LF. After these 8 bytes
30 * the archive entries are listed. The format of an entry header is as it follows:
31 *
Sebastian Bazleyb7bcdc22009-04-14 15:49:33 +000032 * <pre>
Sebastian Bazley5dd3a972009-04-14 15:37:46 +000033 * START BYTE END BYTE NAME FORMAT LENGTH
Christian Grobmeier272aafd2009-04-07 16:56:00 +000034 * 0 15 File name ASCII 16
35 * 16 27 Modification timestamp Decimal 12
36 * 28 33 Owner ID Decimal 6
37 * 34 39 Group ID Decimal 6
38 * 40 47 File mode Octal 8
39 * 48 57 File size (bytes) Decimal 10
40 * 58 59 File magic \140\012 2
Sebastian Bazleyb7bcdc22009-04-14 15:49:33 +000041 * </pre>
Christian Grobmeier272aafd2009-04-07 16:56:00 +000042 *
43 * This specifies that an ar archive entry header contains 60 bytes.
44 *
Stefan Bodewiga19e5f32011-07-23 03:04:09 +000045 * Due to the limitation of the file name length to 16 bytes GNU and
46 * BSD has their own variants of this format. Currently Commons
Stefan Bodewig93e861d2013-01-20 20:16:13 +000047 * Compress can read but not write the GNU variant. It fully supports
Stefan Bodewig46212e52013-01-20 17:07:40 +000048 * the BSD variant.
Christian Grobmeier272aafd2009-04-07 16:56:00 +000049 *
Gary D. Gregory68244212011-07-29 14:04:17 +000050 * @see <a href="http://www.freebsd.org/cgi/man.cgi?query=ar&sektion=5">ar man page</a>
Stefan Bodewig541898f2011-07-20 14:23:20 +000051 *
Sebastian Bazleya91e7c72009-03-27 21:13:51 +000052 * @Immutable
Sebastian Bazley1d3d6ea2009-03-14 02:24:54 +000053 */
Torsten Curdtca165392008-07-10 10:17:44 +000054public class ArArchiveEntry implements ArchiveEntry {
55
Sebastian Bazley6140bf02009-03-28 15:48:15 +000056 /** The header for each entry */
57 public static final String HEADER = "!<arch>\n";
58
59 /** The trailer for each entry */
60 public static final String TRAILER = "`\012";
Stefan Bodewig06fbac92009-08-01 14:53:32 +000061
Sebastian Bazley7ef91072009-04-01 10:09:01 +000062 /**
63 * SVR4/GNU adds a trailing / to names; BSD does not.
64 * They also vary in how names longer than 16 characters are represented.
Stefan Bodewiga19e5f32011-07-23 03:04:09 +000065 * (Not yet fully supported by this implementation)
Sebastian Bazley7ef91072009-04-01 10:09:01 +000066 */
Sebastian Bazleyfd648e22009-03-28 15:05:30 +000067 private final String name;
Stefan Bodewig06fbac92009-08-01 14:53:32 +000068 private final int userId;
69 private final int groupId;
70 private final int mode;
Sebastian Bazleyfd648e22009-03-28 15:05:30 +000071 private static final int DEFAULT_MODE = 33188; // = (octal) 0100644
Stefan Bodewig06fbac92009-08-01 14:53:32 +000072 private final long lastModified;
73 private final long length;
Torsten Curdtca165392008-07-10 10:17:44 +000074
Stefan Bodewigcc3d4182009-08-01 15:04:22 +000075 /**
76 * Create a new instance using a couple of default values.
77 *
78 * <p>Sets userId and groupId to 0, the octal file mode to 644 and
79 * the last modified time to the current time.</p>
80 *
81 * @param name name of the entry
82 * @param length length of the entry in bytes
83 */
Stefan Bodewig06fbac92009-08-01 14:53:32 +000084 public ArArchiveEntry(String name, long length) {
Stefan Bodewigcc3d4182009-08-01 15:04:22 +000085 this(name, length, 0, 0, DEFAULT_MODE,
86 System.currentTimeMillis() / 1000);
Stefan Bodewig06fbac92009-08-01 14:53:32 +000087 }
Torsten Curdtca165392008-07-10 10:17:44 +000088
Stefan Bodewigcc3d4182009-08-01 15:04:22 +000089 /**
90 * Create a new instance.
91 *
92 * @param name name of the entry
93 * @param length length of the entry in bytes
94 * @param userId numeric user id
95 * @param groupId numeric group id
96 * @param mode file mode
97 * @param lastModified last modified time in seconds since the epoch
98 */
99 public ArArchiveEntry(String name, long length, int userId, int groupId,
100 int mode, long lastModified) {
Stefan Bodewig06fbac92009-08-01 14:53:32 +0000101 this.name = name;
102 this.length = length;
103 this.userId = userId;
104 this.groupId = groupId;
105 this.mode = mode;
106 this.lastModified = lastModified;
107 }
108
Stefan Bodewigcc3d4182009-08-01 15:04:22 +0000109 /**
110 * Create a new instance using the attributes of the given file
111 */
Stefan Bodewig06fbac92009-08-01 14:53:32 +0000112 public ArArchiveEntry(File inputFile, String entryName) {
113 // TODO sort out mode
Stefan Bodewigcc3d4182009-08-01 15:04:22 +0000114 this(entryName, inputFile.isFile() ? inputFile.length() : 0,
Stefan Bodewig4efda702009-08-21 07:05:07 +0000115 0, 0, DEFAULT_MODE, inputFile.lastModified() / 1000);
Sebastian Bazleyfec51a12009-03-31 00:35:56 +0000116 }
117
118 public long getSize() {
Stefan Bodewig06fbac92009-08-01 14:53:32 +0000119 return this.getLength();
120 }
121
122 public String getName() {
123 return name;
124 }
125
126 public int getUserId() {
127 return userId;
128 }
129
130 public int getGroupId() {
131 return groupId;
132 }
133
134 public int getMode() {
135 return mode;
136 }
137
Stefan Bodewigcc3d4182009-08-01 15:04:22 +0000138 /**
139 * Last modified time in seconds since the epoch.
140 */
Stefan Bodewig06fbac92009-08-01 14:53:32 +0000141 public long getLastModified() {
142 return lastModified;
143 }
144
Stefan Bodewig17ffd7f2009-08-01 14:52:15 +0000145 public Date getLastModifiedDate() {
146 return new Date(1000 * getLastModified());
147 }
148
Stefan Bodewig06fbac92009-08-01 14:53:32 +0000149 public long getLength() {
150 return length;
151 }
Torsten Curdtd6612b62009-01-07 13:48:42 +0000152
Stefan Bodewig06fbac92009-08-01 14:53:32 +0000153 public boolean isDirectory() {
154 return false;
155 }
Christian Grobmeier28c23fb2009-04-17 05:14:49 +0000156
Stefan Bodewig46628ef2011-08-06 16:30:40 +0000157 @Override
Christian Grobmeier28c23fb2009-04-17 05:14:49 +0000158 public int hashCode() {
159 final int prime = 31;
160 int result = 1;
161 result = prime * result + ((name == null) ? 0 : name.hashCode());
162 return result;
163 }
164
Stefan Bodewig46628ef2011-08-06 16:30:40 +0000165 @Override
Christian Grobmeier28c23fb2009-04-17 05:14:49 +0000166 public boolean equals(Object obj) {
167 if (this == obj) {
168 return true;
169 }
170 if (obj == null || getClass() != obj.getClass()) {
171 return false;
172 }
173 ArArchiveEntry other = (ArArchiveEntry) obj;
174 if (name == null) {
175 if (other.name != null) {
176 return false;
177 }
178 } else if (!name.equals(other.name)) {
179 return false;
180 }
181 return true;
182 }
Torsten Curdtca165392008-07-10 10:17:44 +0000183}