blob: 84282759bd5a5fe8cac482fe8ec5c777bb2065ad [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;
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +000022import java.io.IOException;
Torsten Curdtca165392008-07-10 10:17:44 +000023import java.util.Date;
24import java.util.Locale;
25
26import org.apache.commons.compress.archivers.ArchiveEntry;
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +000027import org.apache.commons.compress.archivers.zip.ZipEncoding;
Sebastian Bazley70d0fce2012-03-31 11:19:10 +000028import org.apache.commons.compress.utils.ArchiveUtils;
Torsten Curdtca165392008-07-10 10:17:44 +000029
30/**
Torsten Curdt46ad24d2009-01-08 11:09:25 +000031 * This class represents an entry in a Tar archive. It consists
32 * of the entry's header, as well as the entry's File. Entries
33 * can be instantiated in one of three ways, depending on how
34 * they are to be used.
35 * <p>
36 * TarEntries that are created from the header bytes read from
37 * an archive are instantiated with the TarEntry( byte[] )
38 * constructor. These entries will be used when extracting from
39 * or listing the contents of an archive. These entries have their
40 * header filled in using the header bytes. They also set the File
41 * to null, since they reference an archive entry not a file.
42 * <p>
43 * TarEntries that are created from Files that are to be written
44 * into an archive are instantiated with the TarEntry( File )
45 * constructor. These entries have their header filled in using
46 * the File's information. They also keep a reference to the File
47 * for convenience when writing entries.
48 * <p>
49 * Finally, TarEntries can be constructed from nothing but a name.
50 * This allows the programmer to construct the entry by hand, for
51 * instance when only an InputStream is available for writing to
52 * the archive, and the header information is constructed from
53 * other information. In this case the header fields are set to
54 * defaults and the File is set to null.
Torsten Curdtca165392008-07-10 10:17:44 +000055 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +000056 * <p>
57 * The C structure for a Tar Entry's header is:
58 * <pre>
Torsten Curdtca165392008-07-10 10:17:44 +000059 * struct header {
Sebastian Bazley8118f822009-04-02 23:34:48 +000060 * char name[100]; // TarConstants.NAMELEN - offset 0
61 * char mode[8]; // TarConstants.MODELEN - offset 100
62 * char uid[8]; // TarConstants.UIDLEN - offset 108
63 * char gid[8]; // TarConstants.GIDLEN - offset 116
64 * char size[12]; // TarConstants.SIZELEN - offset 124
65 * char mtime[12]; // TarConstants.MODTIMELEN - offset 136
66 * char chksum[8]; // TarConstants.CHKSUMLEN - offset 148
67 * char linkflag[1]; // - offset 156
68 * char linkname[100]; // TarConstants.NAMELEN - offset 157
Sebastian Bazley24f9c9b2009-04-02 15:19:17 +000069 * The following fields are only present in new-style POSIX tar archives:
Sebastian Bazley8118f822009-04-02 23:34:48 +000070 * char magic[6]; // TarConstants.MAGICLEN - offset 257
71 * char version[2]; // TarConstants.VERSIONLEN - offset 263
72 * char uname[32]; // TarConstants.UNAMELEN - offset 265
73 * char gname[32]; // TarConstants.GNAMELEN - offset 297
74 * char devmajor[8]; // TarConstants.DEVLEN - offset 329
75 * char devminor[8]; // TarConstants.DEVLEN - offset 337
76 * char prefix[155]; // TarConstants.PREFIXLEN - offset 345
77 * // Used if "name" field is not long enough to hold the path
78 * char pad[12]; // NULs - offset 500
Torsten Curdtca165392008-07-10 10:17:44 +000079 * } header;
Sebastian Bazley24f9c9b2009-04-02 15:19:17 +000080 * All unused bytes are set to null.
81 * New-style GNU tar files are slightly different from the above.
Sebastian Bazley16dc21b2012-02-23 00:16:07 +000082 * For values of size larger than 077777777777L (11 7s)
83 * or uid and gid larger than 07777777L (7 7s)
84 * the sign bit of the first byte is set, and the rest of the
85 * field is the binary representation of the number.
86 * See TarUtils.parseOctalOrBinary.
Torsten Curdtca165392008-07-10 10:17:44 +000087 * </pre>
Sebastian Bazley99870ef2009-03-28 00:04:36 +000088 *
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +000089 * <p>
90 * The C structure for a old GNU Tar Entry's header is:
91 * <pre>
92 * struct oldgnu_header {
93 * char unused_pad1[345]; // TarConstants.PAD1LEN_GNU - offset 0
94 * char atime[12]; // TarConstants.ATIMELEN_GNU - offset 345
95 * char ctime[12]; // TarConstants.CTIMELEN_GNU - offset 357
96 * char offset[12]; // TarConstants.OFFSETLEN_GNU - offset 369
97 * char longnames[4]; // TarConstants.LONGNAMESLEN_GNU - offset 381
98 * char unused_pad2; // TarConstants.PAD2LEN_GNU - offset 385
99 * struct sparse sp[4]; // TarConstants.SPARSELEN_GNU - offset 386
100 * char isextended; // TarConstants.ISEXTENDEDLEN_GNU - offset 482
101 * char realsize[12]; // TarConstants.REALSIZELEN_GNU - offset 483
102 * char unused_pad[17]; // TarConstants.PAD3LEN_GNU - offset 495
103 * };
104 * </pre>
105 * Whereas, "struct sparse" is:
106 * <pre>
107 * struct sparse {
108 * char offset[12]; // offset 0
109 * char numbytes[12]; // offset 12
110 * };
111 * </pre>
112 *
Sebastian Bazley99870ef2009-03-28 00:04:36 +0000113 * @NotThreadSafe
Torsten Curdtca165392008-07-10 10:17:44 +0000114 */
Torsten Curdtca165392008-07-10 10:17:44 +0000115
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000116public class TarArchiveEntry implements TarConstants, ArchiveEntry {
117 /** The entry's name. */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000118 private String name = "";
Torsten Curdtca165392008-07-10 10:17:44 +0000119
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000120 /** The entry's permission mode. */
121 private int mode;
Torsten Curdtca165392008-07-10 10:17:44 +0000122
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000123 /** The entry's user id. */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000124 private int userId = 0;
Torsten Curdtca165392008-07-10 10:17:44 +0000125
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000126 /** The entry's group id. */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000127 private int groupId = 0;
Torsten Curdtca165392008-07-10 10:17:44 +0000128
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000129 /** The entry's size. */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000130 private long size = 0;
Torsten Curdtca165392008-07-10 10:17:44 +0000131
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000132 /** The entry's modification time. */
133 private long modTime;
Torsten Curdtca165392008-07-10 10:17:44 +0000134
Stefan Bodewig811fb4e2012-07-07 05:19:39 +0000135 /** If the header checksum is reasonably correct. */
136 private boolean checkSumOK;
137
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000138 /** The entry's link flag. */
139 private byte linkFlag;
Torsten Curdtca165392008-07-10 10:17:44 +0000140
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000141 /** The entry's link name. */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000142 private String linkName = "";
Torsten Curdtca165392008-07-10 10:17:44 +0000143
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000144 /** The entry's magic tag. */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000145 private String magic = MAGIC_POSIX;
Sebastian Bazley8118f822009-04-02 23:34:48 +0000146 /** The version of the format */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000147 private String version = VERSION_POSIX;
Torsten Curdtca165392008-07-10 10:17:44 +0000148
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000149 /** The entry's user name. */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000150 private String userName;
Torsten Curdtca165392008-07-10 10:17:44 +0000151
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000152 /** The entry's group name. */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000153 private String groupName = "";
Torsten Curdtca165392008-07-10 10:17:44 +0000154
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000155 /** The entry's major device number. */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000156 private int devMajor = 0;
Torsten Curdtca165392008-07-10 10:17:44 +0000157
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000158 /** The entry's minor device number. */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000159 private int devMinor = 0;
Torsten Curdtca165392008-07-10 10:17:44 +0000160
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +0000161 /** If an extension sparse header follows. */
162 private boolean isExtended;
163
164 /** The entry's real size in case of a sparse file. */
165 private long realSize;
166
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000167 /** The entry's file reference */
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000168 private final File file;
Torsten Curdtca165392008-07-10 10:17:44 +0000169
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000170 /** Maximum length of a user's name in the tar file */
171 public static final int MAX_NAMELEN = 31;
Torsten Curdtca165392008-07-10 10:17:44 +0000172
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000173 /** Default permissions bits for directories */
174 public static final int DEFAULT_DIR_MODE = 040755;
Torsten Curdtca165392008-07-10 10:17:44 +0000175
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000176 /** Default permissions bits for files */
177 public static final int DEFAULT_FILE_MODE = 0100644;
Torsten Curdtca165392008-07-10 10:17:44 +0000178
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000179 /** Convert millis to seconds */
180 public static final int MILLIS_PER_SECOND = 1000;
Torsten Curdtca165392008-07-10 10:17:44 +0000181
182 /**
183 * Construct an empty entry and prepares the header values.
184 */
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000185 private TarArchiveEntry() {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000186 String user = System.getProperty("user.name", "");
187
188 if (user.length() > MAX_NAMELEN) {
189 user = user.substring(0, MAX_NAMELEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000190 }
191
Sebastian Bazley1d556702009-04-02 18:45:02 +0000192 this.userName = user;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000193 this.file = null;
Torsten Curdtca165392008-07-10 10:17:44 +0000194 }
195
196 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000197 * Construct an entry with only a name. This allows the programmer
198 * to construct the entry's header "by hand". File is set to null.
Torsten Curdtca165392008-07-10 10:17:44 +0000199 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000200 * @param name the entry name
Torsten Curdtca165392008-07-10 10:17:44 +0000201 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000202 public TarArchiveEntry(String name) {
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000203 this(name, false);
204 }
205
206 /**
207 * Construct an entry with only a name. This allows the programmer
208 * to construct the entry's header "by hand". File is set to null.
209 *
210 * @param name the entry name
211 * @param preserveLeadingSlashes whether to allow leading slashes
212 * in the name.
Sebastian Bazley6209f812010-05-10 17:36:40 +0000213 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000214 * @since 1.1
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000215 */
216 public TarArchiveEntry(String name, boolean preserveLeadingSlashes) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000217 this();
218
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000219 name = normalizeFileName(name, preserveLeadingSlashes);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000220 boolean isDir = name.endsWith("/");
221
Sebastian Bazley1d556702009-04-02 18:45:02 +0000222 this.name = name;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000223 this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE;
224 this.linkFlag = isDir ? LF_DIR : LF_NORMAL;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000225 this.modTime = (new Date()).getTime() / MILLIS_PER_SECOND;
Sebastian Bazley1d556702009-04-02 18:45:02 +0000226 this.userName = "";
Torsten Curdtca165392008-07-10 10:17:44 +0000227 }
228
229 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000230 * Construct an entry with a name and a link flag.
Torsten Curdtca165392008-07-10 10:17:44 +0000231 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000232 * @param name the entry name
233 * @param linkFlag the entry link flag.
Torsten Curdtca165392008-07-10 10:17:44 +0000234 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000235 public TarArchiveEntry(String name, byte linkFlag) {
Stefan Bodewig65837142013-01-01 17:30:48 +0000236 this(name, linkFlag, false);
237 }
238
239 /**
240 * Construct an entry with a name and a link flag.
Stefan Bodewig31184ea2013-03-10 18:56:06 +0000241 *
Stefan Bodewig65837142013-01-01 17:30:48 +0000242 * @param name the entry name
243 * @param linkFlag the entry link flag.
244 * @param preserveLeadingSlashes whether to allow leading slashes
245 * in the name.
246 *
247 * @since 1.5
248 */
249 public TarArchiveEntry(String name, byte linkFlag, boolean preserveLeadingSlashes) {
250 this(name, preserveLeadingSlashes);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000251 this.linkFlag = linkFlag;
Stefan Bodewig7bb5d882009-10-08 12:07:19 +0000252 if (linkFlag == LF_GNUTYPE_LONGNAME) {
253 magic = MAGIC_GNU;
254 version = VERSION_GNU_SPACE;
255 }
Torsten Curdtca165392008-07-10 10:17:44 +0000256 }
257
258 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000259 * Construct an entry for a file. File is set to file, and the
260 * header is constructed from information from the file.
Sebastian Bazleyfec51a12009-03-31 00:35:56 +0000261 * The name is set from the normalized file path.
Torsten Curdtca165392008-07-10 10:17:44 +0000262 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000263 * @param file The file that the entry represents.
Torsten Curdtca165392008-07-10 10:17:44 +0000264 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000265 public TarArchiveEntry(File file) {
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000266 this(file, normalizeFileName(file.getPath(), false));
Sebastian Bazleyfec51a12009-03-31 00:35:56 +0000267 }
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +0000268
Sebastian Bazleyfec51a12009-03-31 00:35:56 +0000269 /**
270 * Construct an entry for a file. File is set to file, and the
271 * header is constructed from information from the file.
272 *
273 * @param file The file that the entry represents.
274 * @param fileName the name to be used for the entry.
275 */
276 public TarArchiveEntry(File file, String fileName) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000277 this.file = file;
Torsten Curdtca165392008-07-10 10:17:44 +0000278
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000279 if (file.isDirectory()) {
280 this.mode = DEFAULT_DIR_MODE;
281 this.linkFlag = LF_DIR;
282
Sebastian Bazley1d556702009-04-02 18:45:02 +0000283 int nameLength = fileName.length();
Christian Grobmeier3bb92822009-05-04 09:15:01 +0000284 if (nameLength == 0 || fileName.charAt(nameLength - 1) != '/') {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000285 this.name = fileName + "/";
286 } else {
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +0000287 this.name = fileName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000288 }
289 } else {
290 this.mode = DEFAULT_FILE_MODE;
291 this.linkFlag = LF_NORMAL;
Stefan Bodewigc013e282009-03-18 04:38:47 +0000292 this.size = file.length();
Sebastian Bazley1d556702009-04-02 18:45:02 +0000293 this.name = fileName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000294 }
295
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000296 this.modTime = file.lastModified() / MILLIS_PER_SECOND;
Stefan Bodewigc0a99232013-01-01 17:10:05 +0000297 this.userName = "";
Torsten Curdtca165392008-07-10 10:17:44 +0000298 }
299
300 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000301 * Construct an entry from an archive's header bytes. File is set
302 * to null.
Torsten Curdtca165392008-07-10 10:17:44 +0000303 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000304 * @param headerBuf The header bytes from a tar archive entry.
Sebastian Bazleyb23b5c82012-02-23 00:57:54 +0000305 * @throws IllegalArgumentException if any of the numeric fields have an invalid format
Torsten Curdtca165392008-07-10 10:17:44 +0000306 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000307 public TarArchiveEntry(byte[] headerBuf) {
Stefan Bodewige4ee3762012-03-18 17:46:32 +0000308 this();
309 parseTarHeader(headerBuf);
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000310 }
311
312 /**
313 * Construct an entry from an archive's header bytes. File is set
314 * to null.
315 *
316 * @param headerBuf The header bytes from a tar archive entry.
317 * @param encoding encoding to use for file names
Sebastian Bazleyddbca722013-03-11 14:14:47 +0000318 * @since 1.4
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000319 * @throws IllegalArgumentException if any of the numeric fields have an invalid format
320 */
Stefan Bodewige4ee3762012-03-18 17:46:32 +0000321 public TarArchiveEntry(byte[] headerBuf, ZipEncoding encoding)
322 throws IOException {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000323 this();
Stefan Bodewige4ee3762012-03-18 17:46:32 +0000324 parseTarHeader(headerBuf, encoding);
Torsten Curdtca165392008-07-10 10:17:44 +0000325 }
326
327 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000328 * Determine if the two entries are equal. Equality is determined
329 * by the header names being equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000330 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000331 * @param it Entry to be checked for equality.
332 * @return True if the entries are equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000333 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000334 public boolean equals(TarArchiveEntry it) {
335 return getName().equals(it.getName());
Torsten Curdtca165392008-07-10 10:17:44 +0000336 }
337
338 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000339 * Determine if the two entries are equal. Equality is determined
340 * by the header names being equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000341 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000342 * @param it Entry to be checked for equality.
343 * @return True if the entries are equal.
Torsten Curdtca165392008-07-10 10:17:44 +0000344 */
Stefan Bodewig46628ef2011-08-06 16:30:40 +0000345 @Override
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000346 public boolean equals(Object it) {
347 if (it == null || getClass() != it.getClass()) {
348 return false;
349 }
350 return equals((TarArchiveEntry) it);
Torsten Curdtca165392008-07-10 10:17:44 +0000351 }
352
353 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000354 * Hashcodes are based on entry names.
Torsten Curdtca165392008-07-10 10:17:44 +0000355 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000356 * @return the entry hashcode
Torsten Curdtca165392008-07-10 10:17:44 +0000357 */
Stefan Bodewig46628ef2011-08-06 16:30:40 +0000358 @Override
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000359 public int hashCode() {
360 return getName().hashCode();
Torsten Curdtca165392008-07-10 10:17:44 +0000361 }
362
363 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000364 * Determine if the given entry is a descendant of this entry.
365 * Descendancy is determined by the name of the descendant
366 * starting with this entry's name.
Torsten Curdtca165392008-07-10 10:17:44 +0000367 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000368 * @param desc Entry to be checked as a descendent of this.
369 * @return True if entry is a descendant of this.
Torsten Curdtca165392008-07-10 10:17:44 +0000370 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000371 public boolean isDescendent(TarArchiveEntry desc) {
372 return desc.getName().startsWith(getName());
Torsten Curdtca165392008-07-10 10:17:44 +0000373 }
374
375 /**
376 * Get this entry's name.
377 *
378 * @return This entry's name.
379 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000380 public String getName() {
381 return name.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000382 }
383
384 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000385 * Set this entry's name.
Torsten Curdtca165392008-07-10 10:17:44 +0000386 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000387 * @param name This entry's new name.
Torsten Curdtca165392008-07-10 10:17:44 +0000388 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000389 public void setName(String name) {
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +0000390 this.name = normalizeFileName(name, false);
Torsten Curdtca165392008-07-10 10:17:44 +0000391 }
392
393 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000394 * Set the mode for this entry
Torsten Curdtca165392008-07-10 10:17:44 +0000395 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000396 * @param mode the mode for this entry
Torsten Curdtca165392008-07-10 10:17:44 +0000397 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000398 public void setMode(int mode) {
399 this.mode = mode;
Torsten Curdtca165392008-07-10 10:17:44 +0000400 }
401
402 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000403 * Get this entry's link name.
Torsten Curdtca165392008-07-10 10:17:44 +0000404 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000405 * @return This entry's link name.
Torsten Curdtca165392008-07-10 10:17:44 +0000406 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000407 public String getLinkName() {
408 return linkName.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000409 }
410
411 /**
Sebastian Bazley5b85bf12010-05-10 10:59:23 +0000412 * Set this entry's link name.
Sebastian Bazley6209f812010-05-10 17:36:40 +0000413 *
414 * @param link the link name to use.
415 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000416 * @since 1.1
Sebastian Bazley5b85bf12010-05-10 10:59:23 +0000417 */
418 public void setLinkName(String link) {
Sebastian Bazley6209f812010-05-10 17:36:40 +0000419 this.linkName = link;
Sebastian Bazley5b85bf12010-05-10 10:59:23 +0000420 }
421
422 /**
Torsten Curdtca165392008-07-10 10:17:44 +0000423 * Get this entry's user id.
424 *
425 * @return This entry's user id.
426 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000427 public int getUserId() {
428 return userId;
429 }
430
431 /**
432 * Set this entry's user id.
433 *
434 * @param userId This entry's new user id.
435 */
436 public void setUserId(int userId) {
437 this.userId = userId;
438 }
439
440 /**
441 * Get this entry's group id.
442 *
443 * @return This entry's group id.
444 */
445 public int getGroupId() {
446 return groupId;
447 }
448
449 /**
450 * Set this entry's group id.
451 *
452 * @param groupId This entry's new group id.
453 */
454 public void setGroupId(int groupId) {
455 this.groupId = groupId;
Torsten Curdtca165392008-07-10 10:17:44 +0000456 }
457
458 /**
459 * Get this entry's user name.
460 *
461 * @return This entry's user name.
462 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000463 public String getUserName() {
464 return userName.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000465 }
466
467 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000468 * Set this entry's user name.
Torsten Curdtca165392008-07-10 10:17:44 +0000469 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000470 * @param userName This entry's new user name.
Torsten Curdtca165392008-07-10 10:17:44 +0000471 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000472 public void setUserName(String userName) {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000473 this.userName = userName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000474 }
475
476 /**
477 * Get this entry's group name.
478 *
479 * @return This entry's group name.
480 */
481 public String getGroupName() {
482 return groupName.toString();
483 }
484
485 /**
486 * Set this entry's group name.
487 *
488 * @param groupName This entry's new group name.
489 */
490 public void setGroupName(String groupName) {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000491 this.groupName = groupName;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000492 }
493
494 /**
495 * Convenience method to set this entry's group and user ids.
496 *
497 * @param userId This entry's new user id.
498 * @param groupId This entry's new group id.
499 */
500 public void setIds(int userId, int groupId) {
501 setUserId(userId);
502 setGroupId(groupId);
503 }
504
505 /**
506 * Convenience method to set this entry's group and user names.
507 *
508 * @param userName This entry's new user name.
509 * @param groupName This entry's new group name.
510 */
511 public void setNames(String userName, String groupName) {
512 setUserName(userName);
513 setGroupName(groupName);
514 }
515
516 /**
517 * Set this entry's modification time. The parameter passed
518 * to this method is in "Java time".
519 *
520 * @param time This entry's new modification time.
521 */
522 public void setModTime(long time) {
523 modTime = time / MILLIS_PER_SECOND;
524 }
525
526 /**
527 * Set this entry's modification time.
528 *
529 * @param time This entry's new modification time.
530 */
531 public void setModTime(Date time) {
532 modTime = time.getTime() / MILLIS_PER_SECOND;
533 }
534
535 /**
536 * Set this entry's modification time.
537 *
538 * @return time This entry's new modification time.
539 */
540 public Date getModTime() {
541 return new Date(modTime * MILLIS_PER_SECOND);
542 }
543
Stefan Bodewig17ffd7f2009-08-01 14:52:15 +0000544 public Date getLastModifiedDate() {
545 return getModTime();
546 }
547
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000548 /**
Stefan Bodewig811fb4e2012-07-07 05:19:39 +0000549 * Get this entry's checksum status.
550 *
551 * @return if the header checksum is reasonably correct
552 * @see TarUtils#verifyCheckSum(byte[])
553 * @since 1.5
554 */
555 public boolean isCheckSumOK() {
556 return checkSumOK;
557 }
558
559 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000560 * Get this entry's file.
561 *
562 * @return This entry's file.
563 */
564 public File getFile() {
565 return file;
566 }
567
568 /**
569 * Get this entry's mode.
570 *
571 * @return This entry's mode.
572 */
573 public int getMode() {
574 return mode;
575 }
576
577 /**
578 * Get this entry's file size.
579 *
580 * @return This entry's file size.
581 */
582 public long getSize() {
583 return size;
584 }
585
586 /**
587 * Set this entry's file size.
588 *
589 * @param size This entry's new file size.
Stefan Bodewiga6fbdae2011-12-08 14:03:57 +0000590 * @throws IllegalArgumentException if the size is &lt; 0.
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000591 */
592 public void setSize(long size) {
Stefan Bodewig5dad1122011-12-07 11:34:34 +0000593 if (size < 0){
Stefan Bodewiga6fbdae2011-12-08 14:03:57 +0000594 throw new IllegalArgumentException("Size is out of range: "+size);
Stefan Bodewig5dad1122011-12-07 11:34:34 +0000595 }
596 this.size = size;
597 }
598
599 /**
Stefan Bodewig5b13f842012-03-09 17:19:53 +0000600 * Get this entry's major device number.
601 *
602 * @return This entry's major device number.
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000603 * @since 1.4
Stefan Bodewig5b13f842012-03-09 17:19:53 +0000604 */
605 public int getDevMajor() {
606 return devMajor;
607 }
608
609 /**
610 * Set this entry's major device number.
611 *
612 * @param devNo This entry's major device number.
613 * @throws IllegalArgumentException if the devNo is &lt; 0.
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000614 * @since 1.4
Stefan Bodewig5b13f842012-03-09 17:19:53 +0000615 */
616 public void setDevMajor(int devNo) {
617 if (devNo < 0){
618 throw new IllegalArgumentException("Major device number is out of "
619 + "range: " + devNo);
620 }
621 this.devMajor = devNo;
622 }
623
624 /**
625 * Get this entry's minor device number.
626 *
627 * @return This entry's minor device number.
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000628 * @since 1.4
Stefan Bodewig5b13f842012-03-09 17:19:53 +0000629 */
630 public int getDevMinor() {
631 return devMinor;
632 }
633
634 /**
635 * Set this entry's minor device number.
636 *
637 * @param devNo This entry's minor device number.
638 * @throws IllegalArgumentException if the devNo is &lt; 0.
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000639 * @since 1.4
Stefan Bodewig5b13f842012-03-09 17:19:53 +0000640 */
641 public void setDevMinor(int devNo) {
642 if (devNo < 0){
643 throw new IllegalArgumentException("Minor device number is out of "
644 + "range: " + devNo);
645 }
646 this.devMinor = devNo;
647 }
648
649 /**
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +0000650 * Indicates in case of a sparse file if an extension sparse header
651 * follows.
652 *
653 * @return true if an extension sparse header follows.
654 */
655 public boolean isExtended() {
656 return isExtended;
657 }
658
659 /**
660 * Get this entry's real file size in case of a sparse file.
661 *
662 * @return This entry's real file size.
663 */
664 public long getRealSize() {
665 return realSize;
666 }
667
668 /**
669 * Indicate if this entry is a GNU sparse block
670 *
671 * @return true if this is a sparse extension provided by GNU tar
672 */
673 public boolean isGNUSparse() {
674 return linkFlag == LF_GNUTYPE_SPARSE;
675 }
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000676
677 /**
Stefan Bodewig601e4d72013-06-03 09:20:30 +0000678 * Indicate if this entry is a GNU long linkname block
679 *
680 * @return true if this is a long name extension provided by GNU tar
681 */
682 public boolean isGNULongLinkEntry() {
683 return linkFlag == LF_GNUTYPE_LONGLINK
684 && name.equals(GNU_LONGLINK);
685 }
686
687 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000688 * Indicate if this entry is a GNU long name block
689 *
690 * @return true if this is a long name extension provided by GNU tar
691 */
692 public boolean isGNULongNameEntry() {
693 return linkFlag == LF_GNUTYPE_LONGNAME
Stefan Bodewigf36320a2012-06-10 05:39:52 +0000694 && name.equals(GNU_LONGLINK);
Torsten Curdtca165392008-07-10 10:17:44 +0000695 }
696
697 /**
Sebastian Bazley33cd35e2010-05-09 20:38:20 +0000698 * Check if this is a Pax header.
699 *
Gary D. Gregoryaa1a75c2012-03-31 22:40:47 +0000700 * @return {@code true} if this is a Pax header.
Sebastian Bazley6209f812010-05-10 17:36:40 +0000701 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000702 * @since 1.1
703 *
Sebastian Bazley33cd35e2010-05-09 20:38:20 +0000704 */
705 public boolean isPaxHeader(){
Sebastian Bazley05b6eb12010-05-10 01:43:08 +0000706 return linkFlag == LF_PAX_EXTENDED_HEADER_LC
707 || linkFlag == LF_PAX_EXTENDED_HEADER_UC;
708 }
709
710 /**
711 * Check if this is a Pax header.
712 *
Gary D. Gregoryaa1a75c2012-03-31 22:40:47 +0000713 * @return {@code true} if this is a Pax header.
Sebastian Bazley6209f812010-05-10 17:36:40 +0000714 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000715 * @since 1.1
Sebastian Bazley05b6eb12010-05-10 01:43:08 +0000716 */
717 public boolean isGlobalPaxHeader(){
718 return linkFlag == LF_PAX_GLOBAL_EXTENDED_HEADER;
Sebastian Bazley33cd35e2010-05-09 20:38:20 +0000719 }
720
721 /**
Torsten Curdtca165392008-07-10 10:17:44 +0000722 * Return whether or not this entry represents a directory.
723 *
724 * @return True if this entry is a directory.
725 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000726 public boolean isDirectory() {
727 if (file != null) {
728 return file.isDirectory();
Torsten Curdtca165392008-07-10 10:17:44 +0000729 }
730
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000731 if (linkFlag == LF_DIR) {
Torsten Curdtca165392008-07-10 10:17:44 +0000732 return true;
733 }
734
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000735 if (getName().endsWith("/")) {
Torsten Curdtca165392008-07-10 10:17:44 +0000736 return true;
737 }
738
739 return false;
740 }
741
742 /**
Stefan Bodewig86aaf842010-10-29 15:03:49 +0000743 * Check if this is a "normal file"
744 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000745 * @since 1.2
Stefan Bodewig86aaf842010-10-29 15:03:49 +0000746 */
747 public boolean isFile() {
748 if (file != null) {
749 return file.isFile();
750 }
751 if (linkFlag == LF_OLDNORM || linkFlag == LF_NORMAL) {
752 return true;
753 }
754 return !getName().endsWith("/");
755 }
756
757 /**
758 * Check if this is a symbolic link entry.
759 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000760 * @since 1.2
Stefan Bodewig86aaf842010-10-29 15:03:49 +0000761 */
762 public boolean isSymbolicLink() {
763 return linkFlag == LF_SYMLINK;
764 }
765
766 /**
767 * Check if this is a link entry.
768 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000769 * @since 1.2
Stefan Bodewig86aaf842010-10-29 15:03:49 +0000770 */
771 public boolean isLink() {
772 return linkFlag == LF_LINK;
773 }
774
775 /**
776 * Check if this is a character device entry.
777 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000778 * @since 1.2
Stefan Bodewig86aaf842010-10-29 15:03:49 +0000779 */
780 public boolean isCharacterDevice() {
781 return linkFlag == LF_CHR;
782 }
783
784 /**
785 * Check if this is a block device entry.
786 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000787 * @since 1.2
Stefan Bodewig86aaf842010-10-29 15:03:49 +0000788 */
789 public boolean isBlockDevice() {
790 return linkFlag == LF_BLK;
791 }
792
793 /**
794 * Check if this is a FIFO (pipe) entry.
795 *
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000796 * @since 1.2
Stefan Bodewig86aaf842010-10-29 15:03:49 +0000797 */
798 public boolean isFIFO() {
799 return linkFlag == LF_FIFO;
800 }
801
802 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000803 * If this entry represents a file, and the file is a directory, return
804 * an array of TarEntries for this entry's children.
Torsten Curdtca165392008-07-10 10:17:44 +0000805 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000806 * @return An array of TarEntry's for this entry's children.
Torsten Curdtca165392008-07-10 10:17:44 +0000807 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000808 public TarArchiveEntry[] getDirectoryEntries() {
809 if (file == null || !file.isDirectory()) {
810 return new TarArchiveEntry[0];
811 }
812
813 String[] list = file.list();
814 TarArchiveEntry[] result = new TarArchiveEntry[list.length];
815
816 for (int i = 0; i < list.length; ++i) {
817 result[i] = new TarArchiveEntry(new File(file, list[i]));
818 }
819
820 return result;
Torsten Curdtca165392008-07-10 10:17:44 +0000821 }
822
823 /**
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000824 * Write an entry's header information to a header buffer.
Torsten Curdtca165392008-07-10 10:17:44 +0000825 *
Stefan Bodewiga6fbdae2011-12-08 14:03:57 +0000826 * <p>This method does not use the star/GNU tar/BSD tar extensions.</p>
827 *
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000828 * @param outbuf The tar entry header buffer to fill in.
Torsten Curdtca165392008-07-10 10:17:44 +0000829 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000830 public void writeEntryHeader(byte[] outbuf) {
Stefan Bodewig32619a82012-03-20 20:27:07 +0000831 try {
832 writeEntryHeader(outbuf, TarUtils.DEFAULT_ENCODING, false);
833 } catch (IOException ex) {
834 try {
835 writeEntryHeader(outbuf, TarUtils.FALLBACK_ENCODING, false);
836 } catch (IOException ex2) {
837 // impossible
838 throw new RuntimeException(ex2);
839 }
840 }
Stefan Bodewiga6fbdae2011-12-08 14:03:57 +0000841 }
842
843 /**
844 * Write an entry's header information to a header buffer.
845 *
846 * @param outbuf The tar entry header buffer to fill in.
Stefan Bodewig32619a82012-03-20 20:27:07 +0000847 * @param encoding encoding to use when writing the file name.
Stefan Bodewiga6fbdae2011-12-08 14:03:57 +0000848 * @param starMode whether to use the star/GNU tar/BSD tar
Stefan Bodewigbe286da2012-03-05 19:34:12 +0000849 * extension for numeric fields if their value doesn't fit in the
850 * maximum size of standard tar archives
Gary D. Gregory2bd0dd42012-04-01 13:02:39 +0000851 * @since 1.4
Stefan Bodewiga6fbdae2011-12-08 14:03:57 +0000852 */
Stefan Bodewig32619a82012-03-20 20:27:07 +0000853 public void writeEntryHeader(byte[] outbuf, ZipEncoding encoding,
854 boolean starMode) throws IOException {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000855 int offset = 0;
856
Stefan Bodewig32619a82012-03-20 20:27:07 +0000857 offset = TarUtils.formatNameBytes(name, outbuf, offset, NAMELEN,
858 encoding);
Stefan Bodewigbe286da2012-03-05 19:34:12 +0000859 offset = writeEntryHeaderField(mode, outbuf, offset, MODELEN, starMode);
860 offset = writeEntryHeaderField(userId, outbuf, offset, UIDLEN,
861 starMode);
862 offset = writeEntryHeaderField(groupId, outbuf, offset, GIDLEN,
863 starMode);
864 offset = writeEntryHeaderField(size, outbuf, offset, SIZELEN, starMode);
865 offset = writeEntryHeaderField(modTime, outbuf, offset, MODTIMELEN,
866 starMode);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000867
868 int csOffset = offset;
869
870 for (int c = 0; c < CHKSUMLEN; ++c) {
871 outbuf[offset++] = (byte) ' ';
872 }
873
874 outbuf[offset++] = linkFlag;
Stefan Bodewig32619a82012-03-20 20:27:07 +0000875 offset = TarUtils.formatNameBytes(linkName, outbuf, offset, NAMELEN,
876 encoding);
Sebastian Bazley1d556702009-04-02 18:45:02 +0000877 offset = TarUtils.formatNameBytes(magic, outbuf, offset, MAGICLEN);
Sebastian Bazley8118f822009-04-02 23:34:48 +0000878 offset = TarUtils.formatNameBytes(version, outbuf, offset, VERSIONLEN);
Stefan Bodewig32619a82012-03-20 20:27:07 +0000879 offset = TarUtils.formatNameBytes(userName, outbuf, offset, UNAMELEN,
880 encoding);
881 offset = TarUtils.formatNameBytes(groupName, outbuf, offset, GNAMELEN,
882 encoding);
Stefan Bodewigbe286da2012-03-05 19:34:12 +0000883 offset = writeEntryHeaderField(devMajor, outbuf, offset, DEVLEN,
884 starMode);
885 offset = writeEntryHeaderField(devMinor, outbuf, offset, DEVLEN,
886 starMode);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000887
888 while (offset < outbuf.length) {
889 outbuf[offset++] = 0;
890 }
891
892 long chk = TarUtils.computeCheckSum(outbuf);
893
Sebastian Bazley1d556702009-04-02 18:45:02 +0000894 TarUtils.formatCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN);
Torsten Curdtca165392008-07-10 10:17:44 +0000895 }
896
Stefan Bodewigbe286da2012-03-05 19:34:12 +0000897 private int writeEntryHeaderField(long value, byte[] outbuf, int offset,
898 int length, boolean starMode) {
899 if (!starMode && (value < 0
900 || value >= (1l << (3 * (length - 1))))) {
901 // value doesn't fit into field when written as octal
902 // number, will be written to PAX header or causes an
903 // error
904 return TarUtils.formatLongOctalBytes(0, outbuf, offset, length);
905 }
906 return TarUtils.formatLongOctalOrBinaryBytes(value, outbuf, offset,
907 length);
908 }
909
Torsten Curdtca165392008-07-10 10:17:44 +0000910 /**
911 * Parse an entry's header information from a header buffer.
912 *
913 * @param header The tar entry header buffer to get information from.
Sebastian Bazleyb23b5c82012-02-23 00:57:54 +0000914 * @throws IllegalArgumentException if any of the numeric fields have an invalid format
Torsten Curdtca165392008-07-10 10:17:44 +0000915 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000916 public void parseTarHeader(byte[] header) {
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000917 try {
918 parseTarHeader(header, TarUtils.DEFAULT_ENCODING);
919 } catch (IOException ex) {
920 try {
921 parseTarHeader(header, TarUtils.DEFAULT_ENCODING, true);
922 } catch (IOException ex2) {
923 // not really possible
924 throw new RuntimeException(ex2);
925 }
926 }
927 }
928
929 /**
930 * Parse an entry's header information from a header buffer.
931 *
932 * @param header The tar entry header buffer to get information from.
933 * @param encoding encoding to use for file names
Sebastian Bazleyddbca722013-03-11 14:14:47 +0000934 * @since 1.4
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000935 * @throws IllegalArgumentException if any of the numeric fields
936 * have an invalid format
937 */
938 public void parseTarHeader(byte[] header, ZipEncoding encoding)
939 throws IOException {
940 parseTarHeader(header, encoding, false);
941 }
942
943 private void parseTarHeader(byte[] header, ZipEncoding encoding,
944 final boolean oldStyle)
945 throws IOException {
Torsten Curdtca165392008-07-10 10:17:44 +0000946 int offset = 0;
947
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000948 name = oldStyle ? TarUtils.parseName(header, offset, NAMELEN)
949 : TarUtils.parseName(header, offset, NAMELEN, encoding);
Torsten Curdtca165392008-07-10 10:17:44 +0000950 offset += NAMELEN;
Stefan Bodewig6c71a2b2012-03-04 07:28:12 +0000951 mode = (int) TarUtils.parseOctalOrBinary(header, offset, MODELEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000952 offset += MODELEN;
Sebastian Bazley7ee6b672012-02-22 23:42:49 +0000953 userId = (int) TarUtils.parseOctalOrBinary(header, offset, UIDLEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000954 offset += UIDLEN;
Sebastian Bazley7ee6b672012-02-22 23:42:49 +0000955 groupId = (int) TarUtils.parseOctalOrBinary(header, offset, GIDLEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000956 offset += GIDLEN;
Stefan Bodewig68465642011-12-05 09:58:04 +0000957 size = TarUtils.parseOctalOrBinary(header, offset, SIZELEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000958 offset += SIZELEN;
Stefan Bodewig6c71a2b2012-03-04 07:28:12 +0000959 modTime = TarUtils.parseOctalOrBinary(header, offset, MODTIMELEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000960 offset += MODTIMELEN;
Stefan Bodewig811fb4e2012-07-07 05:19:39 +0000961 checkSumOK = TarUtils.verifyCheckSum(header);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000962 offset += CHKSUMLEN;
963 linkFlag = header[offset++];
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000964 linkName = oldStyle ? TarUtils.parseName(header, offset, NAMELEN)
965 : TarUtils.parseName(header, offset, NAMELEN, encoding);
Torsten Curdtca165392008-07-10 10:17:44 +0000966 offset += NAMELEN;
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000967 magic = TarUtils.parseName(header, offset, MAGICLEN);
968 offset += MAGICLEN;
Sebastian Bazley8118f822009-04-02 23:34:48 +0000969 version = TarUtils.parseName(header, offset, VERSIONLEN);
970 offset += VERSIONLEN;
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000971 userName = oldStyle ? TarUtils.parseName(header, offset, UNAMELEN)
972 : TarUtils.parseName(header, offset, UNAMELEN, encoding);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000973 offset += UNAMELEN;
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000974 groupName = oldStyle ? TarUtils.parseName(header, offset, GNAMELEN)
975 : TarUtils.parseName(header, offset, GNAMELEN, encoding);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000976 offset += GNAMELEN;
Stefan Bodewig6c71a2b2012-03-04 07:28:12 +0000977 devMajor = (int) TarUtils.parseOctalOrBinary(header, offset, DEVLEN);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000978 offset += DEVLEN;
Stefan Bodewig6c71a2b2012-03-04 07:28:12 +0000979 devMinor = (int) TarUtils.parseOctalOrBinary(header, offset, DEVLEN);
Sebastian Bazley33cd35e2010-05-09 20:38:20 +0000980 offset += DEVLEN;
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +0000981
982 int type = evaluateType(header);
983 switch (type) {
984 case FORMAT_OLDGNU: {
985 offset += ATIMELEN_GNU;
986 offset += CTIMELEN_GNU;
987 offset += OFFSETLEN_GNU;
988 offset += LONGNAMESLEN_GNU;
989 offset += PAD2LEN_GNU;
990 offset += SPARSELEN_GNU;
991 isExtended = TarUtils.parseBoolean(header, offset);
992 offset += ISEXTENDEDLEN_GNU;
993 realSize = TarUtils.parseOctal(header, offset, REALSIZELEN_GNU);
994 offset += REALSIZELEN_GNU;
995 break;
Sebastian Bazley5b25f6c2010-05-10 09:36:15 +0000996 }
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +0000997 case FORMAT_POSIX:
998 default: {
Stefan Bodewig69ceb4e2012-03-18 17:16:51 +0000999 String prefix = oldStyle
1000 ? TarUtils.parseName(header, offset, PREFIXLEN)
1001 : TarUtils.parseName(header, offset, PREFIXLEN, encoding);
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +00001002 // SunOS tar -E does not add / to directory names, so fix
1003 // up to be consistent
1004 if (isDirectory() && !name.endsWith("/")){
1005 name = name + "/";
1006 }
1007 if (prefix.length() > 0){
1008 name = prefix + "/" + name;
1009 }
1010 }
Sebastian Bazley33cd35e2010-05-09 20:38:20 +00001011 }
Torsten Curdtca165392008-07-10 10:17:44 +00001012 }
Stefan Bodewig32eea1e2009-03-17 12:53:22 +00001013
1014 /**
1015 * Strips Windows' drive letter as well as any leading slashes,
1016 * turns path separators into forward slahes.
1017 */
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +00001018 private static String normalizeFileName(String fileName,
1019 boolean preserveLeadingSlashes) {
Stefan Bodewigbed564b2010-02-18 12:34:02 +00001020 String osname = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
Stefan Bodewig32eea1e2009-03-17 12:53:22 +00001021
1022 if (osname != null) {
1023
1024 // Strip off drive letters!
1025 // REVIEW Would a better check be "(File.separator == '\')"?
1026
1027 if (osname.startsWith("windows")) {
1028 if (fileName.length() > 2) {
1029 char ch1 = fileName.charAt(0);
1030 char ch2 = fileName.charAt(1);
1031
1032 if (ch2 == ':'
1033 && ((ch1 >= 'a' && ch1 <= 'z')
1034 || (ch1 >= 'A' && ch1 <= 'Z'))) {
1035 fileName = fileName.substring(2);
1036 }
1037 }
1038 } else if (osname.indexOf("netware") > -1) {
1039 int colon = fileName.indexOf(':');
1040 if (colon != -1) {
1041 fileName = fileName.substring(colon + 1);
1042 }
1043 }
1044 }
1045
1046 fileName = fileName.replace(File.separatorChar, '/');
1047
1048 // No absolute pathnames
1049 // Windows (and Posix?) paths can start with "\\NetworkDrive\",
1050 // so we loop on starting /'s.
Stefan Bodewig3e2ddad2009-08-25 08:11:44 +00001051 while (!preserveLeadingSlashes && fileName.startsWith("/")) {
Stefan Bodewig32eea1e2009-03-17 12:53:22 +00001052 fileName = fileName.substring(1);
1053 }
1054 return fileName;
1055 }
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +00001056
1057 /**
1058 * Evaluate an entry's header format from a header buffer.
1059 *
1060 * @param header The tar entry header buffer to evaluate the format for.
1061 * @return format type
1062 */
1063 private int evaluateType(byte[] header) {
Sebastian Bazley70d0fce2012-03-31 11:19:10 +00001064 if (ArchiveUtils.matchAsciiBuffer(MAGIC_GNU, header, MAGIC_OFFSET, MAGICLEN)) {
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +00001065 return FORMAT_OLDGNU;
Sebastian Bazleya0e435e2012-03-31 10:59:47 +00001066 }
Sebastian Bazley70d0fce2012-03-31 11:19:10 +00001067 if (ArchiveUtils.matchAsciiBuffer(MAGIC_POSIX, header, MAGIC_OFFSET, MAGICLEN)) {
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +00001068 return FORMAT_POSIX;
Sebastian Bazleya0e435e2012-03-31 10:59:47 +00001069 }
Stefan Bodewigaa9d0bc2011-07-23 05:03:52 +00001070 return 0;
1071 }
Torsten Curdtca165392008-07-10 10:17:44 +00001072}
Torsten Curdt46ad24d2009-01-08 11:09:25 +00001073