blob: fdba86c1034d3efb3c813700e90b186ca5f912dd [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 Bazley24f9c9b2009-04-02 15:19:17 +000057 * char name[100]; // TarConstants.NAMELEN
58 * char mode[8]; // TarConstants.MODELEN
59 * char uid[8]; // TarConstants.UIDLEN
60 * char gid[8]; // TarConstants.GIDLEN
61 * char size[12]; // TarConstants.SIZELEN
62 * char mtime[12]; // TarConstants.MODTIMELEN
63 * char chksum[8]; // TarConstants.CHKSUMLEN
64 * char linkflag[1];
65 * char linkname[100]; // TarConstants.NAMELEN
66 * The following fields are only present in new-style POSIX tar archives:
67 * char magic[8]; // TarConstants.MAGICLEN
68 * TODO: Posix/GNU split this into magic[6] and char version[2];
69 * char uname[32]; // TarConstants.UNAMELEN
70 * char gname[32]; // TarConstants.GNAMELEN
71 * char devmajor[8]; // TarConstants.DEVLEN
72 * char devminor[8]; // TarConstants.DEVLEN
73 * char prefix[155]; // Used if "name" field is not long enough to hold the path
74 * char pad[12]; // NULs
Torsten Curdtca165392008-07-10 10:17:44 +000075 * } header;
Sebastian Bazley24f9c9b2009-04-02 15:19:17 +000076 * All unused bytes are set to null.
77 * New-style GNU tar files are slightly different from the above.
Torsten Curdtca165392008-07-10 10:17:44 +000078 * </pre>
Sebastian Bazley99870ef2009-03-28 00:04:36 +000079 *
80 * @NotThreadSafe
Torsten Curdtca165392008-07-10 10:17:44 +000081 */
Torsten Curdtca165392008-07-10 10:17:44 +000082
Torsten Curdt46ad24d2009-01-08 11:09:25 +000083public class TarArchiveEntry implements TarConstants, ArchiveEntry {
84 /** The entry's name. */
Sebastian Bazley1d556702009-04-02 18:45:02 +000085 private String name;
Torsten Curdtca165392008-07-10 10:17:44 +000086
Torsten Curdt46ad24d2009-01-08 11:09:25 +000087 /** The entry's permission mode. */
88 private int mode;
Torsten Curdtca165392008-07-10 10:17:44 +000089
Torsten Curdt46ad24d2009-01-08 11:09:25 +000090 /** The entry's user id. */
91 private int userId;
Torsten Curdtca165392008-07-10 10:17:44 +000092
Torsten Curdt46ad24d2009-01-08 11:09:25 +000093 /** The entry's group id. */
94 private int groupId;
Torsten Curdtca165392008-07-10 10:17:44 +000095
Torsten Curdt46ad24d2009-01-08 11:09:25 +000096 /** The entry's size. */
97 private long size;
Torsten Curdtca165392008-07-10 10:17:44 +000098
Torsten Curdt46ad24d2009-01-08 11:09:25 +000099 /** The entry's modification time. */
100 private long modTime;
Torsten Curdtca165392008-07-10 10:17:44 +0000101
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000102 /** The entry's link flag. */
103 private byte linkFlag;
Torsten Curdtca165392008-07-10 10:17:44 +0000104
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000105 /** The entry's link name. */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000106 private String linkName;
Torsten Curdtca165392008-07-10 10:17:44 +0000107
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000108 /** The entry's magic tag. */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000109 private String magic;
Torsten Curdtca165392008-07-10 10:17:44 +0000110
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000111 /** The entry's user name. */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000112 private String userName;
Torsten Curdtca165392008-07-10 10:17:44 +0000113
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000114 /** The entry's group name. */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000115 private String groupName;
Torsten Curdtca165392008-07-10 10:17:44 +0000116
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000117 /** The entry's major device number. */
118 private int devMajor;
Torsten Curdtca165392008-07-10 10:17:44 +0000119
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000120 /** The entry's minor device number. */
121 private int devMinor;
Torsten Curdtca165392008-07-10 10:17:44 +0000122
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000123 /** The entry's file reference */
124 private File file;
Torsten Curdtca165392008-07-10 10:17:44 +0000125
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000126 /** Maximum length of a user's name in the tar file */
127 public static final int MAX_NAMELEN = 31;
Torsten Curdtca165392008-07-10 10:17:44 +0000128
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000129 /** Default permissions bits for directories */
130 public static final int DEFAULT_DIR_MODE = 040755;
Torsten Curdtca165392008-07-10 10:17:44 +0000131
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000132 /** Default permissions bits for files */
133 public static final int DEFAULT_FILE_MODE = 0100644;
Torsten Curdtca165392008-07-10 10:17:44 +0000134
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000135 /** Convert millis to seconds */
136 public static final int MILLIS_PER_SECOND = 1000;
Torsten Curdtca165392008-07-10 10:17:44 +0000137
138 /**
139 * Construct an empty entry and prepares the header values.
140 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000141 private TarArchiveEntry () {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000142 this.magic = MAGIC_POSIX;
143 this.name = "";
144 this.linkName = "";
Torsten Curdtca165392008-07-10 10:17:44 +0000145
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000146 String user = System.getProperty("user.name", "");
147
148 if (user.length() > MAX_NAMELEN) {
149 user = user.substring(0, MAX_NAMELEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000150 }
151
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000152 this.userId = 0;
153 this.groupId = 0;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000154 this.userName = user;
155 this.groupName = "";
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000156 this.file = null;
Torsten Curdtca165392008-07-10 10:17:44 +0000157 }
158
159 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000160 * Construct an entry with only a name. This allows the programmer
161 * to construct the entry's header "by hand". File is set to null.
Torsten Curdtca165392008-07-10 10:17:44 +0000162 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000163 * @param name the entry name
Torsten Curdtca165392008-07-10 10:17:44 +0000164 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000165 public TarArchiveEntry(String name) {
166 this();
167
Stefan Bodewig32eea1e2009-03-17 12:53:22 +0000168 name = normalizeFileName(name);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000169 boolean isDir = name.endsWith("/");
170
171 this.devMajor = 0;
172 this.devMinor = 0;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000173 this.name = name;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000174 this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE;
175 this.linkFlag = isDir ? LF_DIR : LF_NORMAL;
176 this.userId = 0;
177 this.groupId = 0;
178 this.size = 0;
179 this.modTime = (new Date()).getTime() / MILLIS_PER_SECOND;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000180 this.linkName = "";
181 this.userName = "";
182 this.groupName = "";
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000183 this.devMajor = 0;
184 this.devMinor = 0;
185
Torsten Curdtca165392008-07-10 10:17:44 +0000186 }
187
188 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000189 * Construct an entry with a name and a link flag.
Torsten Curdtca165392008-07-10 10:17:44 +0000190 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000191 * @param name the entry name
192 * @param linkFlag the entry link flag.
Torsten Curdtca165392008-07-10 10:17:44 +0000193 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000194 public TarArchiveEntry(String name, byte linkFlag) {
195 this(name);
196 this.linkFlag = linkFlag;
Torsten Curdtca165392008-07-10 10:17:44 +0000197 }
198
199 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000200 * Construct an entry for a file. File is set to file, and the
201 * header is constructed from information from the file.
Sebastian Bazleyfec51a12009-03-31 00:35:56 +0000202 * The name is set from the normalized file path.
Torsten Curdtca165392008-07-10 10:17:44 +0000203 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000204 * @param file The file that the entry represents.
Torsten Curdtca165392008-07-10 10:17:44 +0000205 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000206 public TarArchiveEntry(File file) {
Sebastian Bazleyfec51a12009-03-31 00:35:56 +0000207 this(file, normalizeFileName(file.getPath()));
208 }
209
210 /**
211 * Construct an entry for a file. File is set to file, and the
212 * header is constructed from information from the file.
213 *
214 * @param file The file that the entry represents.
215 * @param fileName the name to be used for the entry.
216 */
217 public TarArchiveEntry(File file, String fileName) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000218 this();
Torsten Curdtca165392008-07-10 10:17:44 +0000219
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000220 this.file = file;
Torsten Curdtca165392008-07-10 10:17:44 +0000221
Sebastian Bazley1d556702009-04-02 18:45:02 +0000222 this.linkName = "";
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000223
224 if (file.isDirectory()) {
225 this.mode = DEFAULT_DIR_MODE;
226 this.linkFlag = LF_DIR;
227
Sebastian Bazley1d556702009-04-02 18:45:02 +0000228 int nameLength = fileName.length();
Stefan Bodewig32eea1e2009-03-17 12:53:22 +0000229 if (nameLength == 0 || name.charAt(nameLength - 1) != '/') {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000230 this.name = fileName + "/";
231 } else {
232 this.name = fileName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000233 }
Stefan Bodewigc013e282009-03-18 04:38:47 +0000234 this.size = 0;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000235 } else {
236 this.mode = DEFAULT_FILE_MODE;
237 this.linkFlag = LF_NORMAL;
Stefan Bodewigc013e282009-03-18 04:38:47 +0000238 this.size = file.length();
Sebastian Bazley1d556702009-04-02 18:45:02 +0000239 this.name = fileName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000240 }
241
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000242 this.modTime = file.lastModified() / MILLIS_PER_SECOND;
243 this.devMajor = 0;
244 this.devMinor = 0;
Torsten Curdtca165392008-07-10 10:17:44 +0000245 }
246
247 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000248 * Construct an entry from an archive's header bytes. File is set
249 * to null.
Torsten Curdtca165392008-07-10 10:17:44 +0000250 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000251 * @param headerBuf The header bytes from a tar archive entry.
Torsten Curdtca165392008-07-10 10:17:44 +0000252 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000253 public TarArchiveEntry(byte[] headerBuf) {
254 this();
255 parseTarHeader(headerBuf);
Torsten Curdtca165392008-07-10 10:17:44 +0000256 }
257
258 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000259 * Determine if the two entries are equal. Equality is determined
260 * by the header names being equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000261 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000262 * @param it Entry to be checked for equality.
263 * @return True if the entries are equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000264 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000265 public boolean equals(TarArchiveEntry it) {
266 return getName().equals(it.getName());
Torsten Curdtca165392008-07-10 10:17:44 +0000267 }
268
269 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000270 * Determine if the two entries are equal. Equality is determined
271 * by the header names being equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000272 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000273 * @param it Entry to be checked for equality.
274 * @return True if the entries are equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000275 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000276 public boolean equals(Object it) {
277 if (it == null || getClass() != it.getClass()) {
278 return false;
279 }
280 return equals((TarArchiveEntry) it);
Torsten Curdtca165392008-07-10 10:17:44 +0000281 }
282
283 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000284 * Hashcodes are based on entry names.
Torsten Curdtca165392008-07-10 10:17:44 +0000285 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000286 * @return the entry hashcode
Torsten Curdtca165392008-07-10 10:17:44 +0000287 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000288 public int hashCode() {
289 return getName().hashCode();
Torsten Curdtca165392008-07-10 10:17:44 +0000290 }
291
292 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000293 * Determine if the given entry is a descendant of this entry.
294 * Descendancy is determined by the name of the descendant
295 * starting with this entry's name.
Torsten Curdtca165392008-07-10 10:17:44 +0000296 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000297 * @param desc Entry to be checked as a descendent of this.
298 * @return True if entry is a descendant of this.
Torsten Curdtca165392008-07-10 10:17:44 +0000299 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000300 public boolean isDescendent(TarArchiveEntry desc) {
301 return desc.getName().startsWith(getName());
Torsten Curdtca165392008-07-10 10:17:44 +0000302 }
303
304 /**
305 * Get this entry's name.
306 *
307 * @return This entry's name.
308 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000309 public String getName() {
310 return name.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000311 }
312
313 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000314 * Set this entry's name.
Torsten Curdtca165392008-07-10 10:17:44 +0000315 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000316 * @param name This entry's new name.
Torsten Curdtca165392008-07-10 10:17:44 +0000317 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000318 public void setName(String name) {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000319 this.name = normalizeFileName(name);
Torsten Curdtca165392008-07-10 10:17:44 +0000320 }
321
322 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000323 * Set the mode for this entry
Torsten Curdtca165392008-07-10 10:17:44 +0000324 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000325 * @param mode the mode for this entry
Torsten Curdtca165392008-07-10 10:17:44 +0000326 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000327 public void setMode(int mode) {
328 this.mode = mode;
Torsten Curdtca165392008-07-10 10:17:44 +0000329 }
330
331 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000332 * Get this entry's link name.
Torsten Curdtca165392008-07-10 10:17:44 +0000333 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000334 * @return This entry's link name.
Torsten Curdtca165392008-07-10 10:17:44 +0000335 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000336 public String getLinkName() {
337 return linkName.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000338 }
339
340 /**
341 * Get this entry's user id.
342 *
343 * @return This entry's user id.
344 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000345 public int getUserId() {
346 return userId;
347 }
348
349 /**
350 * Set this entry's user id.
351 *
352 * @param userId This entry's new user id.
353 */
354 public void setUserId(int userId) {
355 this.userId = userId;
356 }
357
358 /**
359 * Get this entry's group id.
360 *
361 * @return This entry's group id.
362 */
363 public int getGroupId() {
364 return groupId;
365 }
366
367 /**
368 * Set this entry's group id.
369 *
370 * @param groupId This entry's new group id.
371 */
372 public void setGroupId(int groupId) {
373 this.groupId = groupId;
Torsten Curdtca165392008-07-10 10:17:44 +0000374 }
375
376 /**
377 * Get this entry's user name.
378 *
379 * @return This entry's user name.
380 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000381 public String getUserName() {
382 return userName.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000383 }
384
385 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000386 * Set this entry's user name.
Torsten Curdtca165392008-07-10 10:17:44 +0000387 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000388 * @param userName This entry's new user name.
Torsten Curdtca165392008-07-10 10:17:44 +0000389 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000390 public void setUserName(String userName) {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000391 this.userName = userName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000392 }
393
394 /**
395 * Get this entry's group name.
396 *
397 * @return This entry's group name.
398 */
399 public String getGroupName() {
400 return groupName.toString();
401 }
402
403 /**
404 * Set this entry's group name.
405 *
406 * @param groupName This entry's new group name.
407 */
408 public void setGroupName(String groupName) {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000409 this.groupName = groupName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000410 }
411
412 /**
413 * Convenience method to set this entry's group and user ids.
414 *
415 * @param userId This entry's new user id.
416 * @param groupId This entry's new group id.
417 */
418 public void setIds(int userId, int groupId) {
419 setUserId(userId);
420 setGroupId(groupId);
421 }
422
423 /**
424 * Convenience method to set this entry's group and user names.
425 *
426 * @param userName This entry's new user name.
427 * @param groupName This entry's new group name.
428 */
429 public void setNames(String userName, String groupName) {
430 setUserName(userName);
431 setGroupName(groupName);
432 }
433
434 /**
435 * Set this entry's modification time. The parameter passed
436 * to this method is in "Java time".
437 *
438 * @param time This entry's new modification time.
439 */
440 public void setModTime(long time) {
441 modTime = time / MILLIS_PER_SECOND;
442 }
443
444 /**
445 * Set this entry's modification time.
446 *
447 * @param time This entry's new modification time.
448 */
449 public void setModTime(Date time) {
450 modTime = time.getTime() / MILLIS_PER_SECOND;
451 }
452
453 /**
454 * Set this entry's modification time.
455 *
456 * @return time This entry's new modification time.
457 */
458 public Date getModTime() {
459 return new Date(modTime * MILLIS_PER_SECOND);
460 }
461
462 /**
463 * Get this entry's file.
464 *
465 * @return This entry's file.
466 */
467 public File getFile() {
468 return file;
469 }
470
471 /**
472 * Get this entry's mode.
473 *
474 * @return This entry's mode.
475 */
476 public int getMode() {
477 return mode;
478 }
479
480 /**
481 * Get this entry's file size.
482 *
483 * @return This entry's file size.
484 */
485 public long getSize() {
486 return size;
487 }
488
489 /**
490 * Set this entry's file size.
491 *
492 * @param size This entry's new file size.
Sebastian Bazley26d12c52009-03-31 18:45:14 +0000493 * @throws IllegalArgumentException if the size is < 0
494 * or > {@link TarConstants#MAXSIZE} (077777777777L).
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000495 */
496 public void setSize(long size) {
Sebastian Bazley26d12c52009-03-31 18:45:14 +0000497 if (size > MAXSIZE || size < 0){
498 throw new IllegalArgumentException("Size is out of range: "+size);
499 }
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000500 this.size = size;
501 }
502
503
504 /**
505 * Indicate if this entry is a GNU long name block
506 *
507 * @return true if this is a long name extension provided by GNU tar
508 */
509 public boolean isGNULongNameEntry() {
510 return linkFlag == LF_GNUTYPE_LONGNAME
Stefan Bodewig75f92f62009-03-17 12:14:17 +0000511 && name.toString().equals(GNU_LONGLINK);
Torsten Curdtca165392008-07-10 10:17:44 +0000512 }
513
514 /**
515 * Return whether or not this entry represents a directory.
516 *
517 * @return True if this entry is a directory.
518 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000519 public boolean isDirectory() {
520 if (file != null) {
521 return file.isDirectory();
Torsten Curdtca165392008-07-10 10:17:44 +0000522 }
523
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000524 if (linkFlag == LF_DIR) {
Torsten Curdtca165392008-07-10 10:17:44 +0000525 return true;
526 }
527
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000528 if (getName().endsWith("/")) {
Torsten Curdtca165392008-07-10 10:17:44 +0000529 return true;
530 }
531
532 return false;
533 }
534
535 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000536 * If this entry represents a file, and the file is a directory, return
537 * an array of TarEntries for this entry's children.
Torsten Curdtca165392008-07-10 10:17:44 +0000538 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000539 * @return An array of TarEntry's for this entry's children.
Torsten Curdtca165392008-07-10 10:17:44 +0000540 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000541 public TarArchiveEntry[] getDirectoryEntries() {
542 if (file == null || !file.isDirectory()) {
543 return new TarArchiveEntry[0];
544 }
545
546 String[] list = file.list();
547 TarArchiveEntry[] result = new TarArchiveEntry[list.length];
548
549 for (int i = 0; i < list.length; ++i) {
550 result[i] = new TarArchiveEntry(new File(file, list[i]));
551 }
552
553 return result;
Torsten Curdtca165392008-07-10 10:17:44 +0000554 }
555
556 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000557 * Write an entry's header information to a header buffer.
Torsten Curdtca165392008-07-10 10:17:44 +0000558 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000559 * @param outbuf The tar entry header buffer to fill in.
Torsten Curdtca165392008-07-10 10:17:44 +0000560 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000561 public void writeEntryHeader(byte[] outbuf) {
562 int offset = 0;
563
Sebastian Bazley1d556702009-04-02 18:45:02 +0000564 offset = TarUtils.formatNameBytes(name, outbuf, offset, NAMELEN);
565 offset = TarUtils.formatOctalBytes(mode, outbuf, offset, MODELEN);
566 offset = TarUtils.formatOctalBytes(userId, outbuf, offset, UIDLEN);
567 offset = TarUtils.formatOctalBytes(groupId, outbuf, offset, GIDLEN);
568 offset = TarUtils.formatLongOctalBytes(size, outbuf, offset, SIZELEN);
569 offset = TarUtils.formatLongOctalBytes(modTime, outbuf, offset, MODTIMELEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000570
571 int csOffset = offset;
572
573 for (int c = 0; c < CHKSUMLEN; ++c) {
574 outbuf[offset++] = (byte) ' ';
575 }
576
577 outbuf[offset++] = linkFlag;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000578 offset = TarUtils.formatNameBytes(linkName, outbuf, offset, NAMELEN);
579 offset = TarUtils.formatNameBytes(magic, outbuf, offset, MAGICLEN);
580 offset = TarUtils.formatNameBytes(userName, outbuf, offset, UNAMELEN);
581 offset = TarUtils.formatNameBytes(groupName, outbuf, offset, GNAMELEN);
582 offset = TarUtils.formatOctalBytes(devMajor, outbuf, offset, DEVLEN);
583 offset = TarUtils.formatOctalBytes(devMinor, outbuf, offset, DEVLEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000584
585 while (offset < outbuf.length) {
586 outbuf[offset++] = 0;
587 }
588
589 long chk = TarUtils.computeCheckSum(outbuf);
590
Sebastian Bazley1d556702009-04-02 18:45:02 +0000591 TarUtils.formatCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000592 }
593
594 /**
595 * Parse an entry's header information from a header buffer.
596 *
597 * @param header The tar entry header buffer to get information from.
598 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000599 public void parseTarHeader(byte[] header) {
Torsten Curdtca165392008-07-10 10:17:44 +0000600 int offset = 0;
601
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000602 name = TarUtils.parseName(header, offset, NAMELEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000603 offset += NAMELEN;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000604 mode = (int) TarUtils.parseOctal(header, offset, MODELEN);
605 offset += MODELEN;
606 userId = (int) TarUtils.parseOctal(header, offset, UIDLEN);
607 offset += UIDLEN;
608 groupId = (int) TarUtils.parseOctal(header, offset, GIDLEN);
609 offset += GIDLEN;
610 size = TarUtils.parseOctal(header, offset, SIZELEN);
611 offset += SIZELEN;
612 modTime = TarUtils.parseOctal(header, offset, MODTIMELEN);
613 offset += MODTIMELEN;
614 offset += CHKSUMLEN;
615 linkFlag = header[offset++];
616 linkName = TarUtils.parseName(header, offset, NAMELEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000617 offset += NAMELEN;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000618 magic = TarUtils.parseName(header, offset, MAGICLEN);
619 offset += MAGICLEN;
620 userName = TarUtils.parseName(header, offset, UNAMELEN);
621 offset += UNAMELEN;
622 groupName = TarUtils.parseName(header, offset, GNAMELEN);
623 offset += GNAMELEN;
624 devMajor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
625 offset += DEVLEN;
626 devMinor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000627 }
Stefan Bodewig32eea1e2009-03-17 12:53:22 +0000628
629 /**
630 * Strips Windows' drive letter as well as any leading slashes,
631 * turns path separators into forward slahes.
632 */
633 private static String normalizeFileName(String fileName) {
634 String osname = System.getProperty("os.name").toLowerCase(Locale.US);
635
636 if (osname != null) {
637
638 // Strip off drive letters!
639 // REVIEW Would a better check be "(File.separator == '\')"?
640
641 if (osname.startsWith("windows")) {
642 if (fileName.length() > 2) {
643 char ch1 = fileName.charAt(0);
644 char ch2 = fileName.charAt(1);
645
646 if (ch2 == ':'
647 && ((ch1 >= 'a' && ch1 <= 'z')
648 || (ch1 >= 'A' && ch1 <= 'Z'))) {
649 fileName = fileName.substring(2);
650 }
651 }
652 } else if (osname.indexOf("netware") > -1) {
653 int colon = fileName.indexOf(':');
654 if (colon != -1) {
655 fileName = fileName.substring(colon + 1);
656 }
657 }
658 }
659
660 fileName = fileName.replace(File.separatorChar, '/');
661
662 // No absolute pathnames
663 // Windows (and Posix?) paths can start with "\\NetworkDrive\",
664 // so we loop on starting /'s.
665 while (fileName.startsWith("/")) {
666 fileName = fileName.substring(1);
667 }
668 return fileName;
669 }
Torsten Curdtca165392008-07-10 10:17:44 +0000670}
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000671