blob: a7a31396d1ce7b8c79c06ee478013ac64fbfb59d [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.tar;
20
21import java.io.File;
22import java.util.Date;
23import java.util.Locale;
24
25import org.apache.commons.compress.archivers.ArchiveEntry;
26
27/**
Torsten Curdt46ad24d2009-01-08 11:09:25 +000028 * This class represents an entry in a Tar archive. It consists
29 * of the entry's header, as well as the entry's File. Entries
30 * can be instantiated in one of three ways, depending on how
31 * they are to be used.
32 * <p>
33 * TarEntries that are created from the header bytes read from
34 * an archive are instantiated with the TarEntry( byte[] )
35 * constructor. These entries will be used when extracting from
36 * or listing the contents of an archive. These entries have their
37 * header filled in using the header bytes. They also set the File
38 * to null, since they reference an archive entry not a file.
39 * <p>
40 * TarEntries that are created from Files that are to be written
41 * into an archive are instantiated with the TarEntry( File )
42 * constructor. These entries have their header filled in using
43 * the File's information. They also keep a reference to the File
44 * for convenience when writing entries.
45 * <p>
46 * Finally, TarEntries can be constructed from nothing but a name.
47 * This allows the programmer to construct the entry by hand, for
48 * instance when only an InputStream is available for writing to
49 * the archive, and the header information is constructed from
50 * other information. In this case the header fields are set to
51 * defaults and the File is set to null.
Torsten Curdtca165392008-07-10 10:17:44 +000052 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +000053 * <p>
54 * The C structure for a Tar Entry's header is:
55 * <pre>
Torsten Curdtca165392008-07-10 10:17:44 +000056 * struct header {
Sebastian Bazley8118f822009-04-02 23:34:48 +000057 * char name[100]; // TarConstants.NAMELEN - offset 0
58 * char mode[8]; // TarConstants.MODELEN - offset 100
59 * char uid[8]; // TarConstants.UIDLEN - offset 108
60 * char gid[8]; // TarConstants.GIDLEN - offset 116
61 * char size[12]; // TarConstants.SIZELEN - offset 124
62 * char mtime[12]; // TarConstants.MODTIMELEN - offset 136
63 * char chksum[8]; // TarConstants.CHKSUMLEN - offset 148
64 * char linkflag[1]; // - offset 156
65 * char linkname[100]; // TarConstants.NAMELEN - offset 157
Sebastian Bazley24f9c9b2009-04-02 15:19:17 +000066 * The following fields are only present in new-style POSIX tar archives:
Sebastian Bazley8118f822009-04-02 23:34:48 +000067 * char magic[6]; // TarConstants.MAGICLEN - offset 257
68 * char version[2]; // TarConstants.VERSIONLEN - offset 263
69 * char uname[32]; // TarConstants.UNAMELEN - offset 265
70 * char gname[32]; // TarConstants.GNAMELEN - offset 297
71 * char devmajor[8]; // TarConstants.DEVLEN - offset 329
72 * char devminor[8]; // TarConstants.DEVLEN - offset 337
73 * char prefix[155]; // TarConstants.PREFIXLEN - offset 345
74 * // Used if "name" field is not long enough to hold the path
75 * char pad[12]; // NULs - offset 500
Torsten Curdtca165392008-07-10 10:17:44 +000076 * } header;
Sebastian Bazley24f9c9b2009-04-02 15:19:17 +000077 * All unused bytes are set to null.
78 * New-style GNU tar files are slightly different from the above.
Torsten Curdtca165392008-07-10 10:17:44 +000079 * </pre>
Sebastian Bazley99870ef2009-03-28 00:04:36 +000080 *
81 * @NotThreadSafe
Torsten Curdtca165392008-07-10 10:17:44 +000082 */
Torsten Curdtca165392008-07-10 10:17:44 +000083
Torsten Curdt46ad24d2009-01-08 11:09:25 +000084public class TarArchiveEntry implements TarConstants, ArchiveEntry {
85 /** The entry's name. */
Sebastian Bazley1d556702009-04-02 18:45:02 +000086 private String name;
Torsten Curdtca165392008-07-10 10:17:44 +000087
Torsten Curdt46ad24d2009-01-08 11:09:25 +000088 /** The entry's permission mode. */
89 private int mode;
Torsten Curdtca165392008-07-10 10:17:44 +000090
Torsten Curdt46ad24d2009-01-08 11:09:25 +000091 /** The entry's user id. */
92 private int userId;
Torsten Curdtca165392008-07-10 10:17:44 +000093
Torsten Curdt46ad24d2009-01-08 11:09:25 +000094 /** The entry's group id. */
95 private int groupId;
Torsten Curdtca165392008-07-10 10:17:44 +000096
Torsten Curdt46ad24d2009-01-08 11:09:25 +000097 /** The entry's size. */
98 private long size;
Torsten Curdtca165392008-07-10 10:17:44 +000099
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000100 /** The entry's modification time. */
101 private long modTime;
Torsten Curdtca165392008-07-10 10:17:44 +0000102
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000103 /** The entry's link flag. */
104 private byte linkFlag;
Torsten Curdtca165392008-07-10 10:17:44 +0000105
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000106 /** The entry's link name. */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000107 private String linkName;
Torsten Curdtca165392008-07-10 10:17:44 +0000108
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000109 /** The entry's magic tag. */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000110 private String magic;
Sebastian Bazley8118f822009-04-02 23:34:48 +0000111 /** The version of the format */
112 private String version;
Torsten Curdtca165392008-07-10 10:17:44 +0000113
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000114 /** The entry's user name. */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000115 private String userName;
Torsten Curdtca165392008-07-10 10:17:44 +0000116
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000117 /** The entry's group name. */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000118 private String groupName;
Torsten Curdtca165392008-07-10 10:17:44 +0000119
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000120 /** The entry's major device number. */
121 private int devMajor;
Torsten Curdtca165392008-07-10 10:17:44 +0000122
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000123 /** The entry's minor device number. */
124 private int devMinor;
Torsten Curdtca165392008-07-10 10:17:44 +0000125
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000126 /** The entry's file reference */
127 private File file;
Torsten Curdtca165392008-07-10 10:17:44 +0000128
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000129 /** Maximum length of a user's name in the tar file */
130 public static final int MAX_NAMELEN = 31;
Torsten Curdtca165392008-07-10 10:17:44 +0000131
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000132 /** Default permissions bits for directories */
133 public static final int DEFAULT_DIR_MODE = 040755;
Torsten Curdtca165392008-07-10 10:17:44 +0000134
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000135 /** Default permissions bits for files */
136 public static final int DEFAULT_FILE_MODE = 0100644;
Torsten Curdtca165392008-07-10 10:17:44 +0000137
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000138 /** Convert millis to seconds */
139 public static final int MILLIS_PER_SECOND = 1000;
Torsten Curdtca165392008-07-10 10:17:44 +0000140
141 /**
142 * Construct an empty entry and prepares the header values.
143 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000144 private TarArchiveEntry () {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000145 this.magic = MAGIC_POSIX;
Sebastian Bazley8118f822009-04-02 23:34:48 +0000146 this.version = VERSION_POSIX;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000147 this.name = "";
148 this.linkName = "";
Torsten Curdtca165392008-07-10 10:17:44 +0000149
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000150 String user = System.getProperty("user.name", "");
151
152 if (user.length() > MAX_NAMELEN) {
153 user = user.substring(0, MAX_NAMELEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000154 }
155
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000156 this.userId = 0;
157 this.groupId = 0;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000158 this.userName = user;
159 this.groupName = "";
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000160 this.file = null;
Torsten Curdtca165392008-07-10 10:17:44 +0000161 }
162
163 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000164 * Construct an entry with only a name. This allows the programmer
165 * to construct the entry's header "by hand". File is set to null.
Torsten Curdtca165392008-07-10 10:17:44 +0000166 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000167 * @param name the entry name
Torsten Curdtca165392008-07-10 10:17:44 +0000168 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000169 public TarArchiveEntry(String name) {
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000170 this(name, false);
171 }
172
173 /**
174 * Construct an entry with only a name. This allows the programmer
175 * to construct the entry's header "by hand". File is set to null.
176 *
177 * @param name the entry name
178 * @param preserveLeadingSlashes whether to allow leading slashes
179 * in the name.
180 */
181 public TarArchiveEntry(String name, boolean preserveLeadingSlashes) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000182 this();
183
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000184 name = normalizeFileName(name, preserveLeadingSlashes);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000185 boolean isDir = name.endsWith("/");
186
187 this.devMajor = 0;
188 this.devMinor = 0;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000189 this.name = name;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000190 this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE;
191 this.linkFlag = isDir ? LF_DIR : LF_NORMAL;
192 this.userId = 0;
193 this.groupId = 0;
194 this.size = 0;
195 this.modTime = (new Date()).getTime() / MILLIS_PER_SECOND;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000196 this.linkName = "";
197 this.userName = "";
198 this.groupName = "";
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000199 this.devMajor = 0;
200 this.devMinor = 0;
201
Torsten Curdtca165392008-07-10 10:17:44 +0000202 }
203
204 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000205 * Construct an entry with a name and a link flag.
Torsten Curdtca165392008-07-10 10:17:44 +0000206 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000207 * @param name the entry name
208 * @param linkFlag the entry link flag.
Torsten Curdtca165392008-07-10 10:17:44 +0000209 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000210 public TarArchiveEntry(String name, byte linkFlag) {
211 this(name);
212 this.linkFlag = linkFlag;
Torsten Curdtca165392008-07-10 10:17:44 +0000213 }
214
215 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000216 * Construct an entry for a file. File is set to file, and the
217 * header is constructed from information from the file.
Sebastian Bazleyfec51a12009-03-31 00:35:56 +0000218 * The name is set from the normalized file path.
Torsten Curdtca165392008-07-10 10:17:44 +0000219 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000220 * @param file The file that the entry represents.
Torsten Curdtca165392008-07-10 10:17:44 +0000221 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000222 public TarArchiveEntry(File file) {
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000223 this(file, normalizeFileName(file.getPath(), false));
Sebastian Bazleyfec51a12009-03-31 00:35:56 +0000224 }
225
226 /**
227 * Construct an entry for a file. File is set to file, and the
228 * header is constructed from information from the file.
229 *
230 * @param file The file that the entry represents.
231 * @param fileName the name to be used for the entry.
232 */
233 public TarArchiveEntry(File file, String fileName) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000234 this();
Torsten Curdtca165392008-07-10 10:17:44 +0000235
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000236 this.file = file;
Torsten Curdtca165392008-07-10 10:17:44 +0000237
Sebastian Bazley1d556702009-04-02 18:45:02 +0000238 this.linkName = "";
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000239
240 if (file.isDirectory()) {
241 this.mode = DEFAULT_DIR_MODE;
242 this.linkFlag = LF_DIR;
243
Sebastian Bazley1d556702009-04-02 18:45:02 +0000244 int nameLength = fileName.length();
Christian Grobmeier3bb92822009-05-04 09:15:01 +0000245 if (nameLength == 0 || fileName.charAt(nameLength - 1) != '/') {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000246 this.name = fileName + "/";
247 } else {
248 this.name = fileName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000249 }
Stefan Bodewigc013e282009-03-18 04:38:47 +0000250 this.size = 0;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000251 } else {
252 this.mode = DEFAULT_FILE_MODE;
253 this.linkFlag = LF_NORMAL;
Stefan Bodewigc013e282009-03-18 04:38:47 +0000254 this.size = file.length();
Sebastian Bazley1d556702009-04-02 18:45:02 +0000255 this.name = fileName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000256 }
257
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000258 this.modTime = file.lastModified() / MILLIS_PER_SECOND;
259 this.devMajor = 0;
260 this.devMinor = 0;
Torsten Curdtca165392008-07-10 10:17:44 +0000261 }
262
263 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000264 * Construct an entry from an archive's header bytes. File is set
265 * to null.
Torsten Curdtca165392008-07-10 10:17:44 +0000266 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000267 * @param headerBuf The header bytes from a tar archive entry.
Torsten Curdtca165392008-07-10 10:17:44 +0000268 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000269 public TarArchiveEntry(byte[] headerBuf) {
270 this();
271 parseTarHeader(headerBuf);
Torsten Curdtca165392008-07-10 10:17:44 +0000272 }
273
274 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000275 * Determine if the two entries are equal. Equality is determined
276 * by the header names being equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000277 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000278 * @param it Entry to be checked for equality.
279 * @return True if the entries are equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000280 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000281 public boolean equals(TarArchiveEntry it) {
282 return getName().equals(it.getName());
Torsten Curdtca165392008-07-10 10:17:44 +0000283 }
284
285 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000286 * Determine if the two entries are equal. Equality is determined
287 * by the header names being equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000288 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000289 * @param it Entry to be checked for equality.
290 * @return True if the entries are equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000291 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000292 public boolean equals(Object it) {
293 if (it == null || getClass() != it.getClass()) {
294 return false;
295 }
296 return equals((TarArchiveEntry) it);
Torsten Curdtca165392008-07-10 10:17:44 +0000297 }
298
299 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000300 * Hashcodes are based on entry names.
Torsten Curdtca165392008-07-10 10:17:44 +0000301 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000302 * @return the entry hashcode
Torsten Curdtca165392008-07-10 10:17:44 +0000303 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000304 public int hashCode() {
305 return getName().hashCode();
Torsten Curdtca165392008-07-10 10:17:44 +0000306 }
307
308 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000309 * Determine if the given entry is a descendant of this entry.
310 * Descendancy is determined by the name of the descendant
311 * starting with this entry's name.
Torsten Curdtca165392008-07-10 10:17:44 +0000312 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000313 * @param desc Entry to be checked as a descendent of this.
314 * @return True if entry is a descendant of this.
Torsten Curdtca165392008-07-10 10:17:44 +0000315 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000316 public boolean isDescendent(TarArchiveEntry desc) {
317 return desc.getName().startsWith(getName());
Torsten Curdtca165392008-07-10 10:17:44 +0000318 }
319
320 /**
321 * Get this entry's name.
322 *
323 * @return This entry's name.
324 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000325 public String getName() {
326 return name.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000327 }
328
329 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000330 * Set this entry's name.
Torsten Curdtca165392008-07-10 10:17:44 +0000331 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000332 * @param name This entry's new name.
Torsten Curdtca165392008-07-10 10:17:44 +0000333 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000334 public void setName(String name) {
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000335 this.name = normalizeFileName(name, false);
Torsten Curdtca165392008-07-10 10:17:44 +0000336 }
337
338 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000339 * Set the mode for this entry
Torsten Curdtca165392008-07-10 10:17:44 +0000340 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000341 * @param mode the mode for this entry
Torsten Curdtca165392008-07-10 10:17:44 +0000342 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000343 public void setMode(int mode) {
344 this.mode = mode;
Torsten Curdtca165392008-07-10 10:17:44 +0000345 }
346
347 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000348 * Get this entry's link name.
Torsten Curdtca165392008-07-10 10:17:44 +0000349 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000350 * @return This entry's link name.
Torsten Curdtca165392008-07-10 10:17:44 +0000351 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000352 public String getLinkName() {
353 return linkName.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000354 }
355
356 /**
357 * Get this entry's user id.
358 *
359 * @return This entry's user id.
360 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000361 public int getUserId() {
362 return userId;
363 }
364
365 /**
366 * Set this entry's user id.
367 *
368 * @param userId This entry's new user id.
369 */
370 public void setUserId(int userId) {
371 this.userId = userId;
372 }
373
374 /**
375 * Get this entry's group id.
376 *
377 * @return This entry's group id.
378 */
379 public int getGroupId() {
380 return groupId;
381 }
382
383 /**
384 * Set this entry's group id.
385 *
386 * @param groupId This entry's new group id.
387 */
388 public void setGroupId(int groupId) {
389 this.groupId = groupId;
Torsten Curdtca165392008-07-10 10:17:44 +0000390 }
391
392 /**
393 * Get this entry's user name.
394 *
395 * @return This entry's user name.
396 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000397 public String getUserName() {
398 return userName.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000399 }
400
401 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000402 * Set this entry's user name.
Torsten Curdtca165392008-07-10 10:17:44 +0000403 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000404 * @param userName This entry's new user name.
Torsten Curdtca165392008-07-10 10:17:44 +0000405 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000406 public void setUserName(String userName) {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000407 this.userName = userName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000408 }
409
410 /**
411 * Get this entry's group name.
412 *
413 * @return This entry's group name.
414 */
415 public String getGroupName() {
416 return groupName.toString();
417 }
418
419 /**
420 * Set this entry's group name.
421 *
422 * @param groupName This entry's new group name.
423 */
424 public void setGroupName(String groupName) {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000425 this.groupName = groupName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000426 }
427
428 /**
429 * Convenience method to set this entry's group and user ids.
430 *
431 * @param userId This entry's new user id.
432 * @param groupId This entry's new group id.
433 */
434 public void setIds(int userId, int groupId) {
435 setUserId(userId);
436 setGroupId(groupId);
437 }
438
439 /**
440 * Convenience method to set this entry's group and user names.
441 *
442 * @param userName This entry's new user name.
443 * @param groupName This entry's new group name.
444 */
445 public void setNames(String userName, String groupName) {
446 setUserName(userName);
447 setGroupName(groupName);
448 }
449
450 /**
451 * Set this entry's modification time. The parameter passed
452 * to this method is in "Java time".
453 *
454 * @param time This entry's new modification time.
455 */
456 public void setModTime(long time) {
457 modTime = time / MILLIS_PER_SECOND;
458 }
459
460 /**
461 * Set this entry's modification time.
462 *
463 * @param time This entry's new modification time.
464 */
465 public void setModTime(Date time) {
466 modTime = time.getTime() / MILLIS_PER_SECOND;
467 }
468
469 /**
470 * Set this entry's modification time.
471 *
472 * @return time This entry's new modification time.
473 */
474 public Date getModTime() {
475 return new Date(modTime * MILLIS_PER_SECOND);
476 }
477
Stefan Bodewig17ffd7f2009-08-01 14:52:15 +0000478 /** {@inheritDocs} */
479 public Date getLastModifiedDate() {
480 return getModTime();
481 }
482
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000483 /**
484 * Get this entry's file.
485 *
486 * @return This entry's file.
487 */
488 public File getFile() {
489 return file;
490 }
491
492 /**
493 * Get this entry's mode.
494 *
495 * @return This entry's mode.
496 */
497 public int getMode() {
498 return mode;
499 }
500
501 /**
502 * Get this entry's file size.
503 *
504 * @return This entry's file size.
505 */
506 public long getSize() {
507 return size;
508 }
509
510 /**
511 * Set this entry's file size.
512 *
513 * @param size This entry's new file size.
Sebastian Bazley26d12c52009-03-31 18:45:14 +0000514 * @throws IllegalArgumentException if the size is < 0
515 * or > {@link TarConstants#MAXSIZE} (077777777777L).
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000516 */
517 public void setSize(long size) {
Sebastian Bazley26d12c52009-03-31 18:45:14 +0000518 if (size > MAXSIZE || size < 0){
519 throw new IllegalArgumentException("Size is out of range: "+size);
520 }
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000521 this.size = size;
522 }
523
524
525 /**
526 * Indicate if this entry is a GNU long name block
527 *
528 * @return true if this is a long name extension provided by GNU tar
529 */
530 public boolean isGNULongNameEntry() {
531 return linkFlag == LF_GNUTYPE_LONGNAME
Stefan Bodewig75f92f62009-03-17 12:14:17 +0000532 && name.toString().equals(GNU_LONGLINK);
Torsten Curdtca165392008-07-10 10:17:44 +0000533 }
534
535 /**
536 * Return whether or not this entry represents a directory.
537 *
538 * @return True if this entry is a directory.
539 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000540 public boolean isDirectory() {
541 if (file != null) {
542 return file.isDirectory();
Torsten Curdtca165392008-07-10 10:17:44 +0000543 }
544
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000545 if (linkFlag == LF_DIR) {
Torsten Curdtca165392008-07-10 10:17:44 +0000546 return true;
547 }
548
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000549 if (getName().endsWith("/")) {
Torsten Curdtca165392008-07-10 10:17:44 +0000550 return true;
551 }
552
553 return false;
554 }
555
556 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000557 * If this entry represents a file, and the file is a directory, return
558 * an array of TarEntries for this entry's children.
Torsten Curdtca165392008-07-10 10:17:44 +0000559 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000560 * @return An array of TarEntry's for this entry's children.
Torsten Curdtca165392008-07-10 10:17:44 +0000561 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000562 public TarArchiveEntry[] getDirectoryEntries() {
563 if (file == null || !file.isDirectory()) {
564 return new TarArchiveEntry[0];
565 }
566
567 String[] list = file.list();
568 TarArchiveEntry[] result = new TarArchiveEntry[list.length];
569
570 for (int i = 0; i < list.length; ++i) {
571 result[i] = new TarArchiveEntry(new File(file, list[i]));
572 }
573
574 return result;
Torsten Curdtca165392008-07-10 10:17:44 +0000575 }
576
577 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000578 * Write an entry's header information to a header buffer.
Torsten Curdtca165392008-07-10 10:17:44 +0000579 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000580 * @param outbuf The tar entry header buffer to fill in.
Torsten Curdtca165392008-07-10 10:17:44 +0000581 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000582 public void writeEntryHeader(byte[] outbuf) {
583 int offset = 0;
584
Sebastian Bazley1d556702009-04-02 18:45:02 +0000585 offset = TarUtils.formatNameBytes(name, outbuf, offset, NAMELEN);
586 offset = TarUtils.formatOctalBytes(mode, outbuf, offset, MODELEN);
587 offset = TarUtils.formatOctalBytes(userId, outbuf, offset, UIDLEN);
588 offset = TarUtils.formatOctalBytes(groupId, outbuf, offset, GIDLEN);
589 offset = TarUtils.formatLongOctalBytes(size, outbuf, offset, SIZELEN);
590 offset = TarUtils.formatLongOctalBytes(modTime, outbuf, offset, MODTIMELEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000591
592 int csOffset = offset;
593
594 for (int c = 0; c < CHKSUMLEN; ++c) {
595 outbuf[offset++] = (byte) ' ';
596 }
597
598 outbuf[offset++] = linkFlag;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000599 offset = TarUtils.formatNameBytes(linkName, outbuf, offset, NAMELEN);
600 offset = TarUtils.formatNameBytes(magic, outbuf, offset, MAGICLEN);
Sebastian Bazley8118f822009-04-02 23:34:48 +0000601 offset = TarUtils.formatNameBytes(version, outbuf, offset, VERSIONLEN);
Sebastian Bazley1d556702009-04-02 18:45:02 +0000602 offset = TarUtils.formatNameBytes(userName, outbuf, offset, UNAMELEN);
603 offset = TarUtils.formatNameBytes(groupName, outbuf, offset, GNAMELEN);
604 offset = TarUtils.formatOctalBytes(devMajor, outbuf, offset, DEVLEN);
605 offset = TarUtils.formatOctalBytes(devMinor, outbuf, offset, DEVLEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000606
607 while (offset < outbuf.length) {
608 outbuf[offset++] = 0;
609 }
610
611 long chk = TarUtils.computeCheckSum(outbuf);
612
Sebastian Bazley1d556702009-04-02 18:45:02 +0000613 TarUtils.formatCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000614 }
615
616 /**
617 * Parse an entry's header information from a header buffer.
618 *
619 * @param header The tar entry header buffer to get information from.
620 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000621 public void parseTarHeader(byte[] header) {
Torsten Curdtca165392008-07-10 10:17:44 +0000622 int offset = 0;
623
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000624 name = TarUtils.parseName(header, offset, NAMELEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000625 offset += NAMELEN;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000626 mode = (int) TarUtils.parseOctal(header, offset, MODELEN);
627 offset += MODELEN;
628 userId = (int) TarUtils.parseOctal(header, offset, UIDLEN);
629 offset += UIDLEN;
630 groupId = (int) TarUtils.parseOctal(header, offset, GIDLEN);
631 offset += GIDLEN;
632 size = TarUtils.parseOctal(header, offset, SIZELEN);
633 offset += SIZELEN;
634 modTime = TarUtils.parseOctal(header, offset, MODTIMELEN);
635 offset += MODTIMELEN;
636 offset += CHKSUMLEN;
637 linkFlag = header[offset++];
638 linkName = TarUtils.parseName(header, offset, NAMELEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000639 offset += NAMELEN;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000640 magic = TarUtils.parseName(header, offset, MAGICLEN);
641 offset += MAGICLEN;
Sebastian Bazley8118f822009-04-02 23:34:48 +0000642 version = TarUtils.parseName(header, offset, VERSIONLEN);
643 offset += VERSIONLEN;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000644 userName = TarUtils.parseName(header, offset, UNAMELEN);
645 offset += UNAMELEN;
646 groupName = TarUtils.parseName(header, offset, GNAMELEN);
647 offset += GNAMELEN;
648 devMajor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
649 offset += DEVLEN;
650 devMinor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000651 }
Stefan Bodewig32eea1e2009-03-17 12:53:22 +0000652
653 /**
654 * Strips Windows' drive letter as well as any leading slashes,
655 * turns path separators into forward slahes.
656 */
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000657 private static String normalizeFileName(String fileName,
658 boolean preserveLeadingSlashes) {
Stefan Bodewig32eea1e2009-03-17 12:53:22 +0000659 String osname = System.getProperty("os.name").toLowerCase(Locale.US);
660
661 if (osname != null) {
662
663 // Strip off drive letters!
664 // REVIEW Would a better check be "(File.separator == '\')"?
665
666 if (osname.startsWith("windows")) {
667 if (fileName.length() > 2) {
668 char ch1 = fileName.charAt(0);
669 char ch2 = fileName.charAt(1);
670
671 if (ch2 == ':'
672 && ((ch1 >= 'a' && ch1 <= 'z')
673 || (ch1 >= 'A' && ch1 <= 'Z'))) {
674 fileName = fileName.substring(2);
675 }
676 }
677 } else if (osname.indexOf("netware") > -1) {
678 int colon = fileName.indexOf(':');
679 if (colon != -1) {
680 fileName = fileName.substring(colon + 1);
681 }
682 }
683 }
684
685 fileName = fileName.replace(File.separatorChar, '/');
686
687 // No absolute pathnames
688 // Windows (and Posix?) paths can start with "\\NetworkDrive\",
689 // so we loop on starting /'s.
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000690 while (!preserveLeadingSlashes && fileName.startsWith("/")) {
Stefan Bodewig32eea1e2009-03-17 12:53:22 +0000691 fileName = fileName.substring(1);
692 }
693 return fileName;
694 }
Torsten Curdtca165392008-07-10 10:17:44 +0000695}
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000696