Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 1 | /* |
| 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 | */ |
| 19 | package org.apache.commons.compress.archivers.dump; |
| 20 | |
| 21 | import java.util.Collections; |
| 22 | import java.util.Date; |
| 23 | import java.util.EnumSet; |
| 24 | import java.util.HashSet; |
| 25 | import java.util.Set; |
| 26 | import org.apache.commons.compress.archivers.ArchiveEntry; |
| 27 | |
| 28 | /** |
| 29 | * This class represents an entry in a Dump archive. It consists |
| 30 | * of the entry's header, the entry's File and any extended attributes. |
| 31 | * <p> |
| 32 | * DumpEntries that are created from the header bytes read from |
| 33 | * an archive are instantiated with the DumpArchiveEntry( byte[] ) |
| 34 | * constructor. These entries will be used when extracting from |
| 35 | * or listing the contents of an archive. These entries have their |
| 36 | * header filled in using the header bytes. They also set the File |
| 37 | * to null, since they reference an archive entry not a file. |
| 38 | * <p> |
| 39 | * DumpEntries can also be constructed from nothing but a name. |
| 40 | * This allows the programmer to construct the entry by hand, for |
| 41 | * instance when only an InputStream is available for writing to |
| 42 | * the archive, and the header information is constructed from |
| 43 | * other information. In this case the header fields are set to |
| 44 | * defaults and the File is set to null. |
| 45 | * |
| 46 | * <p> |
| 47 | * The C structure for a Dump Entry's header is: |
| 48 | * <pre> |
| 49 | * #define TP_BSIZE 1024 // size of each file block |
| 50 | * #define NTREC 10 // number of blocks to write at once |
| 51 | * #define HIGHDENSITYTREC 32 // number of blocks to write on high-density tapes |
| 52 | * #define TP_NINDIR (TP_BSIZE/2) // number if indirect inodes in record |
| 53 | * #define TP_NINOS (TP_NINDIR / sizeof (int32_t)) |
| 54 | * #define LBLSIZE 16 |
| 55 | * #define NAMELEN 64 |
| 56 | * |
| 57 | * #define OFS_MAGIC (int)60011 // old format magic value |
| 58 | * #define NFS_MAGIC (int)60012 // new format magic value |
| 59 | * #define FS_UFS2_MAGIC (int)0x19540119 |
| 60 | * #define CHECKSUM (int)84446 // constant used in checksum algorithm |
| 61 | * |
| 62 | * struct s_spcl { |
| 63 | * int32_t c_type; // record type (see below) |
| 64 | * int32_t <b>c_date</b>; // date of this dump |
| 65 | * int32_t <b>c_ddate</b>; // date of previous dump |
| 66 | * int32_t c_volume; // dump volume number |
| 67 | * u_int32_t c_tapea; // logical block of this record |
| 68 | * dump_ino_t c_ino; // number of inode |
| 69 | * int32_t <b>c_magic</b>; // magic number (see above) |
| 70 | * int32_t c_checksum; // record checksum |
| 71 | * #ifdef __linux__ |
| 72 | * struct new_bsd_inode c_dinode; |
| 73 | * #else |
| 74 | * #ifdef sunos |
| 75 | * struct new_bsd_inode c_dinode; |
| 76 | * #else |
| 77 | * struct dinode c_dinode; // ownership and mode of inode |
| 78 | * #endif |
| 79 | * #endif |
| 80 | * int32_t c_count; // number of valid c_addr entries |
| 81 | * union u_data c_data; // see above |
| 82 | * char <b>c_label[LBLSIZE]</b>; // dump label |
| 83 | * int32_t <b>c_level</b>; // level of this dump |
| 84 | * char <b>c_filesys[NAMELEN]</b>; // name of dumpped file system |
| 85 | * char <b>c_dev[NAMELEN]</b>; // name of dumpped device |
| 86 | * char <b>c_host[NAMELEN]</b>; // name of dumpped host |
| 87 | * int32_t c_flags; // additional information (see below) |
| 88 | * int32_t c_firstrec; // first record on volume |
| 89 | * int32_t c_ntrec; // blocksize on volume |
| 90 | * int32_t c_extattributes; // additional inode info (see below) |
| 91 | * int32_t c_spare[30]; // reserved for future uses |
| 92 | * } s_spcl; |
| 93 | * |
| 94 | * // |
| 95 | * // flag values |
| 96 | * // |
| 97 | * #define DR_NEWHEADER 0x0001 // new format tape header |
| 98 | * #define DR_NEWINODEFMT 0x0002 // new format inodes on tape |
| 99 | * #define DR_COMPRESSED 0x0080 // dump tape is compressed |
| 100 | * #define DR_METAONLY 0x0100 // only the metadata of the inode has been dumped |
| 101 | * #define DR_INODEINFO 0x0002 // [SIC] TS_END header contains c_inos information |
| 102 | * #define DR_EXTATTRIBUTES 0x8000 |
| 103 | * |
| 104 | * // |
| 105 | * // extattributes inode info |
| 106 | * // |
| 107 | * #define EXT_REGULAR 0 |
| 108 | * #define EXT_MACOSFNDRINFO 1 |
| 109 | * #define EXT_MACOSRESFORK 2 |
| 110 | * #define EXT_XATTR 3 |
| 111 | * |
| 112 | * // used for EA on tape |
| 113 | * #define EXT2_GOOD_OLD_INODE_SIZE 128 |
| 114 | * #define EXT2_XATTR_MAGIC 0xEA020000 // block EA |
| 115 | * #define EXT2_XATTR_MAGIC2 0xEA020001 // in inode EA |
| 116 | * </pre> |
| 117 | * The fields in <b>bold</b> are the same for all blocks. (This permitted |
| 118 | * multiple dumps to be written to a single tape.) |
| 119 | * </p> |
| 120 | * |
| 121 | * <p> |
| 122 | * The C structure for the inode (file) information is: |
| 123 | * <pre> |
| 124 | * struct bsdtimeval { // **** alpha-*-linux is deviant |
| 125 | * __u32 tv_sec; |
| 126 | * __u32 tv_usec; |
| 127 | * }; |
| 128 | * |
| 129 | * #define NDADDR 12 |
| 130 | * #define NIADDR 3 |
| 131 | * |
| 132 | * // |
| 133 | * // This is the new (4.4) BSD inode structure |
| 134 | * // copied from the FreeBSD 2.0 <ufs/ufs/dinode.h> include file |
| 135 | * // |
| 136 | * struct new_bsd_inode { |
| 137 | * __u16 di_mode; // file type, standard Unix permissions |
| 138 | * __s16 di_nlink; // number of hard links to file. |
| 139 | * union { |
| 140 | * __u16 oldids[2]; |
| 141 | * __u32 inumber; |
| 142 | * } di_u; |
| 143 | * u_quad_t di_size; // file size |
| 144 | * struct bsdtimeval di_atime; // time file was last accessed |
| 145 | * struct bsdtimeval di_mtime; // time file was last modified |
| 146 | * struct bsdtimeval di_ctime; // time file was created |
| 147 | * __u32 di_db[NDADDR]; |
| 148 | * __u32 di_ib[NIADDR]; |
| 149 | * __u32 di_flags; // |
| 150 | * __s32 di_blocks; // number of disk blocks |
| 151 | * __s32 di_gen; // generation number |
| 152 | * __u32 di_uid; // user id (see /etc/passwd) |
| 153 | * __u32 di_gid; // group id (see /etc/group) |
| 154 | * __s32 di_spare[2]; // unused |
| 155 | * }; |
| 156 | * </pre> |
| 157 | * It is important to note that the header DOES NOT have the name of the |
| 158 | * file. It can't since hard links mean that you may have multiple filenames |
| 159 | * for a single physical file. You must read the contents of the directory |
| 160 | * entries to learn the mapping(s) from filename to inode. |
| 161 | * </p> |
| 162 | * |
| 163 | * <p> |
| 164 | * The C structure that indicates if a specific block is a real block |
| 165 | * that contains data or is a sparse block that is not persisted to the |
| 166 | * disk is: |
| 167 | * <pre> |
| 168 | * #define TP_BSIZE 1024 |
| 169 | * #define TP_NINDIR (TP_BSIZE/2) |
| 170 | * |
| 171 | * union u_data { |
| 172 | * char s_addrs[TP_NINDIR]; // 1 => data; 0 => hole in inode |
| 173 | * int32_t s_inos[TP_NINOS]; // table of first inode on each volume |
| 174 | * } u_data; |
| 175 | * </pre></p> |
| 176 | * |
| 177 | * @NotThreadSafe |
| 178 | */ |
| 179 | public class DumpArchiveEntry implements ArchiveEntry { |
| 180 | private String name; |
| 181 | private TYPE type = TYPE.UNKNOWN; |
| 182 | private int mode; |
| 183 | private Set<PERMISSION> permissions = Collections.emptySet(); |
| 184 | private long size; |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 185 | private long atime; |
| 186 | private long mtime; |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 187 | private int uid; |
| 188 | private int gid; |
| 189 | |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 190 | /** |
| 191 | * Currently unused |
| 192 | */ |
Gary D. Gregory | a67d562 | 2013-01-22 12:48:16 +0000 | [diff] [blame] | 193 | private final DumpArchiveSummary summary = null; |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 194 | |
| 195 | // this information is available from standard index. |
Gary D. Gregory | a67d562 | 2013-01-22 12:48:16 +0000 | [diff] [blame] | 196 | private final TapeSegmentHeader header = new TapeSegmentHeader(); |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 197 | private String simpleName; |
Stefan Bodewig | 281591e | 2011-08-17 14:49:08 +0000 | [diff] [blame] | 198 | private String originalName; |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 199 | |
| 200 | // this information is available from QFA index |
| 201 | private int volume; |
| 202 | private long offset; |
| 203 | private int ino; |
| 204 | private int nlink; |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 205 | private long ctime; |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 206 | private int generation; |
| 207 | private boolean isDeleted; |
| 208 | |
| 209 | /** |
| 210 | * Default constructor. |
| 211 | */ |
| 212 | public DumpArchiveEntry() { |
| 213 | } |
| 214 | |
| 215 | /** |
| 216 | * Constructor taking only filename. |
| 217 | * @param name pathname |
| 218 | * @param simpleName actual filename. |
| 219 | */ |
| 220 | public DumpArchiveEntry(String name, String simpleName) { |
Stefan Bodewig | 281591e | 2011-08-17 14:49:08 +0000 | [diff] [blame] | 221 | setName(name); |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 222 | this.simpleName = simpleName; |
| 223 | } |
| 224 | |
| 225 | /** |
| 226 | * Constructor taking name, inode and type. |
| 227 | * |
| 228 | * @param name |
| 229 | * @param simpleName |
| 230 | * @param ino |
| 231 | * @param type |
| 232 | */ |
| 233 | protected DumpArchiveEntry(String name, String simpleName, int ino, |
| 234 | TYPE type) { |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 235 | setType(type); |
Stefan Bodewig | f51fee1 | 2011-10-27 08:51:20 +0000 | [diff] [blame] | 236 | setName(name); |
| 237 | this.simpleName = simpleName; |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 238 | this.ino = ino; |
| 239 | this.offset = 0; |
| 240 | } |
| 241 | |
| 242 | /** |
| 243 | * Constructor taking tape buffer. |
| 244 | * @param buffer |
| 245 | * @param offset |
| 246 | */ |
| 247 | |
| 248 | /** |
| 249 | * Returns the path of the entry. |
Sebastian Bazley | 2e44b5b | 2011-08-15 15:08:33 +0000 | [diff] [blame] | 250 | * @return the path of the entry. |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 251 | */ |
| 252 | public String getSimpleName() { |
| 253 | return simpleName; |
| 254 | } |
| 255 | |
| 256 | /** |
| 257 | * Sets the path of the entry. |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 258 | */ |
| 259 | protected void setSimpleName(String simpleName) { |
| 260 | this.simpleName = simpleName; |
| 261 | } |
| 262 | |
| 263 | /** |
| 264 | * Returns the ino of the entry. |
| 265 | */ |
| 266 | public int getIno() { |
| 267 | return header.getIno(); |
| 268 | } |
| 269 | |
| 270 | /** |
| 271 | * Return the number of hard links to the entry. |
| 272 | */ |
| 273 | public int getNlink() { |
| 274 | return nlink; |
| 275 | } |
| 276 | |
| 277 | /** |
| 278 | * Set the number of hard links. |
| 279 | */ |
| 280 | public void setNlink(int nlink) { |
| 281 | this.nlink = nlink; |
| 282 | } |
| 283 | |
| 284 | /** |
| 285 | * Get file creation time. |
| 286 | */ |
| 287 | public Date getCreationTime() { |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 288 | return new Date(ctime); |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 289 | } |
| 290 | |
| 291 | /** |
| 292 | * Set the file creation time. |
| 293 | */ |
| 294 | public void setCreationTime(Date ctime) { |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 295 | this.ctime = ctime.getTime(); |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | /** |
| 299 | * Return the generation of the file. |
| 300 | */ |
| 301 | public int getGeneration() { |
| 302 | return generation; |
| 303 | } |
| 304 | |
| 305 | /** |
| 306 | * Set the generation of the file. |
| 307 | */ |
| 308 | public void setGeneration(int generation) { |
| 309 | this.generation = generation; |
| 310 | } |
| 311 | |
| 312 | /** |
| 313 | * Has this file been deleted? (On valid on incremental dumps.) |
| 314 | */ |
| 315 | public boolean isDeleted() { |
| 316 | return isDeleted; |
| 317 | } |
| 318 | |
| 319 | /** |
| 320 | * Set whether this file has been deleted. |
| 321 | */ |
| 322 | public void setDeleted(boolean isDeleted) { |
| 323 | this.isDeleted = isDeleted; |
| 324 | } |
| 325 | |
| 326 | /** |
| 327 | * Return the offset within the archive |
| 328 | */ |
| 329 | public long getOffset() { |
| 330 | return offset; |
| 331 | } |
| 332 | |
| 333 | /** |
| 334 | * Set the offset within the archive. |
| 335 | */ |
| 336 | public void setOffset(long offset) { |
| 337 | this.offset = offset; |
| 338 | } |
| 339 | |
| 340 | /** |
| 341 | * Return the tape volume where this file is located. |
| 342 | */ |
| 343 | public int getVolume() { |
| 344 | return volume; |
| 345 | } |
| 346 | |
| 347 | /** |
| 348 | * Set the tape volume. |
| 349 | */ |
| 350 | public void setVolume(int volume) { |
| 351 | this.volume = volume; |
| 352 | } |
| 353 | |
| 354 | /** |
| 355 | * Return the type of the tape segment header. |
| 356 | */ |
| 357 | public DumpArchiveConstants.SEGMENT_TYPE getHeaderType() { |
| 358 | return header.getType(); |
| 359 | } |
| 360 | |
| 361 | /** |
| 362 | * Return the number of records in this segment. |
| 363 | */ |
| 364 | public int getHeaderCount() { |
| 365 | return header.getCount(); |
| 366 | } |
| 367 | |
| 368 | /** |
| 369 | * Return the number of sparse records in this segment. |
| 370 | */ |
| 371 | public int getHeaderHoles() { |
| 372 | return header.getHoles(); |
| 373 | } |
| 374 | |
| 375 | /** |
| 376 | * Is this a sparse record? |
| 377 | */ |
| 378 | public boolean isSparseRecord(int idx) { |
| 379 | return (header.getCdata(idx) & 0x01) == 0; |
| 380 | } |
| 381 | |
| 382 | /** |
| 383 | * @see java.lang.Object#hashCode() |
| 384 | */ |
| 385 | @Override |
| 386 | public int hashCode() { |
| 387 | return ino; |
| 388 | } |
| 389 | |
| 390 | /** |
| 391 | * @see java.lang.Object#equals(Object o) |
| 392 | */ |
| 393 | @Override |
| 394 | public boolean equals(Object o) { |
| 395 | if (o == this) { |
| 396 | return true; |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 397 | } else if (o == null || !o.getClass().equals(getClass())) { |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 398 | return false; |
| 399 | } |
| 400 | |
| 401 | DumpArchiveEntry rhs = (DumpArchiveEntry) o; |
| 402 | |
| 403 | if ((header == null) || (rhs.header == null)) { |
| 404 | return false; |
| 405 | } |
| 406 | |
| 407 | if (ino != rhs.ino) { |
| 408 | return false; |
| 409 | } |
| 410 | |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 411 | if ((summary == null && rhs.summary != null) |
| 412 | || (summary != null && !summary.equals(rhs.summary))) { |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 413 | return false; |
| 414 | } |
| 415 | |
| 416 | return true; |
| 417 | } |
| 418 | |
| 419 | /** |
| 420 | * @see java.lang.Object#toString() |
| 421 | */ |
| 422 | @Override |
| 423 | public String toString() { |
| 424 | return getName(); |
| 425 | } |
| 426 | |
| 427 | /** |
| 428 | * Populate the dump archive entry and tape segment header with |
| 429 | * the contents of the buffer. |
| 430 | * |
| 431 | * @param buffer |
| 432 | * @throws Exception |
| 433 | */ |
Stefan Bodewig | 07ec353 | 2011-08-16 03:13:32 +0000 | [diff] [blame] | 434 | static DumpArchiveEntry parse(byte[] buffer) { |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 435 | DumpArchiveEntry entry = new DumpArchiveEntry(); |
| 436 | TapeSegmentHeader header = entry.header; |
| 437 | |
| 438 | header.type = DumpArchiveConstants.SEGMENT_TYPE.find(DumpArchiveUtil.convert32( |
| 439 | buffer, 0)); |
| 440 | |
| 441 | //header.dumpDate = new Date(1000L * DumpArchiveUtil.convert32(buffer, 4)); |
| 442 | //header.previousDumpDate = new Date(1000L * DumpArchiveUtil.convert32( |
| 443 | // buffer, 8)); |
| 444 | header.volume = DumpArchiveUtil.convert32(buffer, 12); |
| 445 | //header.tapea = DumpArchiveUtil.convert32(buffer, 16); |
| 446 | entry.ino = header.ino = DumpArchiveUtil.convert32(buffer, 20); |
| 447 | |
| 448 | //header.magic = DumpArchiveUtil.convert32(buffer, 24); |
| 449 | //header.checksum = DumpArchiveUtil.convert32(buffer, 28); |
| 450 | int m = DumpArchiveUtil.convert16(buffer, 32); |
| 451 | |
| 452 | // determine the type of the file. |
| 453 | entry.setType(TYPE.find((m >> 12) & 0x0F)); |
| 454 | |
| 455 | // determine the standard permissions |
| 456 | entry.setMode(m); |
| 457 | |
| 458 | entry.nlink = DumpArchiveUtil.convert16(buffer, 34); |
| 459 | // inumber, oldids? |
| 460 | entry.setSize(DumpArchiveUtil.convert64(buffer, 40)); |
| 461 | |
| 462 | long t = (1000L * DumpArchiveUtil.convert32(buffer, 48)) + |
| 463 | (DumpArchiveUtil.convert32(buffer, 52) / 1000); |
| 464 | entry.setAccessTime(new Date(t)); |
| 465 | t = (1000L * DumpArchiveUtil.convert32(buffer, 56)) + |
| 466 | (DumpArchiveUtil.convert32(buffer, 60) / 1000); |
| 467 | entry.setLastModifiedDate(new Date(t)); |
| 468 | t = (1000L * DumpArchiveUtil.convert32(buffer, 64)) + |
| 469 | (DumpArchiveUtil.convert32(buffer, 68) / 1000); |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 470 | entry.ctime = t; |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 471 | |
| 472 | // db: 72-119 - direct blocks |
| 473 | // id: 120-131 - indirect blocks |
| 474 | //entry.flags = DumpArchiveUtil.convert32(buffer, 132); |
| 475 | //entry.blocks = DumpArchiveUtil.convert32(buffer, 136); |
| 476 | entry.generation = DumpArchiveUtil.convert32(buffer, 140); |
| 477 | entry.setUserId(DumpArchiveUtil.convert32(buffer, 144)); |
| 478 | entry.setGroupId(DumpArchiveUtil.convert32(buffer, 148)); |
| 479 | // two 32-bit spare values. |
| 480 | header.count = DumpArchiveUtil.convert32(buffer, 160); |
| 481 | |
| 482 | header.holes = 0; |
| 483 | |
| 484 | for (int i = 0; (i < 512) && (i < header.count); i++) { |
| 485 | if (buffer[164 + i] == 0) { |
| 486 | header.holes++; |
| 487 | } |
| 488 | } |
| 489 | |
| 490 | System.arraycopy(buffer, 164, header.cdata, 0, 512); |
| 491 | |
| 492 | entry.volume = header.getVolume(); |
| 493 | |
| 494 | //entry.isSummaryOnly = false; |
| 495 | return entry; |
| 496 | } |
| 497 | |
| 498 | /** |
| 499 | * Update entry with information from next tape segment header. |
| 500 | */ |
Stefan Bodewig | 07ec353 | 2011-08-16 03:13:32 +0000 | [diff] [blame] | 501 | void update(byte[] buffer) { |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 502 | header.volume = DumpArchiveUtil.convert32(buffer, 16); |
| 503 | header.count = DumpArchiveUtil.convert32(buffer, 160); |
| 504 | |
| 505 | header.holes = 0; |
| 506 | |
| 507 | for (int i = 0; (i < 512) && (i < header.count); i++) { |
| 508 | if (buffer[164 + i] == 0) { |
| 509 | header.holes++; |
| 510 | } |
| 511 | } |
| 512 | |
| 513 | System.arraycopy(buffer, 164, header.cdata, 0, 512); |
| 514 | } |
| 515 | |
| 516 | /** |
| 517 | * Archive entry as stored on tape. There is one TSH for (at most) |
| 518 | * every 512k in the file. |
| 519 | */ |
Stefan Bodewig | 07ec353 | 2011-08-16 03:13:32 +0000 | [diff] [blame] | 520 | static class TapeSegmentHeader { |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 521 | private DumpArchiveConstants.SEGMENT_TYPE type; |
| 522 | private int volume; |
| 523 | private int ino; |
| 524 | private int count; |
| 525 | private int holes; |
Gary D. Gregory | a67d562 | 2013-01-22 12:48:16 +0000 | [diff] [blame] | 526 | private final byte[] cdata = new byte[512]; // map of any 'holes' |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 527 | |
| 528 | public DumpArchiveConstants.SEGMENT_TYPE getType() { |
| 529 | return type; |
| 530 | } |
| 531 | |
| 532 | public int getVolume() { |
| 533 | return volume; |
| 534 | } |
| 535 | |
| 536 | public int getIno() { |
| 537 | return ino; |
| 538 | } |
| 539 | |
| 540 | void setIno(int ino) { |
| 541 | this.ino = ino; |
| 542 | } |
| 543 | |
| 544 | public int getCount() { |
| 545 | return count; |
| 546 | } |
| 547 | |
| 548 | public int getHoles() { |
| 549 | return holes; |
| 550 | } |
| 551 | |
| 552 | public int getCdata(int idx) { |
| 553 | return cdata[idx]; |
| 554 | } |
| 555 | } |
| 556 | |
| 557 | /** |
| 558 | * Returns the name of the entry. |
Sebastian Bazley | 2e44b5b | 2011-08-15 15:08:33 +0000 | [diff] [blame] | 559 | * @return the name of the entry. |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 560 | */ |
| 561 | public String getName() { |
| 562 | return name; |
| 563 | } |
| 564 | |
| 565 | /** |
Stefan Bodewig | 281591e | 2011-08-17 14:49:08 +0000 | [diff] [blame] | 566 | * Returns the unmodified name of the entry. |
| 567 | * @return the name of the entry. |
| 568 | */ |
| 569 | String getOriginalName() { |
| 570 | return originalName; |
| 571 | } |
| 572 | |
| 573 | /** |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 574 | * Sets the name of the entry. |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 575 | */ |
Stefan Bodewig | 281591e | 2011-08-17 14:49:08 +0000 | [diff] [blame] | 576 | public final void setName(String name) { |
| 577 | this.originalName = name; |
| 578 | if (name != null) { |
Stefan Bodewig | 281591e | 2011-08-17 14:49:08 +0000 | [diff] [blame] | 579 | if (isDirectory() && !name.endsWith("/")) { |
| 580 | name += "/"; |
| 581 | } |
Stefan Bodewig | 6715dba | 2011-08-18 04:27:07 +0000 | [diff] [blame] | 582 | if (name.startsWith("./")) { |
| 583 | name = name.substring(2); |
| 584 | } |
Stefan Bodewig | 281591e | 2011-08-17 14:49:08 +0000 | [diff] [blame] | 585 | } |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 586 | this.name = name; |
| 587 | } |
| 588 | |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 589 | public Date getLastModifiedDate() { |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 590 | return new Date(mtime); |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 591 | } |
| 592 | |
| 593 | /** |
| 594 | * Is this a directory? |
| 595 | */ |
| 596 | public boolean isDirectory() { |
| 597 | return type == TYPE.DIRECTORY; |
| 598 | } |
| 599 | |
| 600 | /** |
| 601 | * Is this a regular file? |
| 602 | */ |
| 603 | public boolean isFile() { |
| 604 | return type == TYPE.FILE; |
| 605 | } |
| 606 | |
| 607 | /** |
| 608 | * Is this a network device? |
| 609 | */ |
| 610 | public boolean isSocket() { |
| 611 | return type == TYPE.SOCKET; |
| 612 | } |
| 613 | |
| 614 | /** |
| 615 | * Is this a character device? |
| 616 | */ |
| 617 | public boolean isChrDev() { |
| 618 | return type == TYPE.CHRDEV; |
| 619 | } |
| 620 | |
| 621 | /** |
| 622 | * Is this a block device? |
| 623 | */ |
| 624 | public boolean isBlkDev() { |
| 625 | return type == TYPE.BLKDEV; |
| 626 | } |
| 627 | |
| 628 | /** |
| 629 | * Is this a fifo/pipe? |
| 630 | */ |
| 631 | public boolean isFifo() { |
| 632 | return type == TYPE.FIFO; |
| 633 | } |
| 634 | |
| 635 | /** |
| 636 | * Get the type of the entry. |
| 637 | */ |
| 638 | public TYPE getType() { |
| 639 | return type; |
| 640 | } |
| 641 | |
| 642 | /** |
| 643 | * Set the type of the entry. |
| 644 | */ |
| 645 | public void setType(TYPE type) { |
| 646 | this.type = type; |
| 647 | } |
| 648 | |
| 649 | /** |
| 650 | * Return the access permissions on the entry. |
| 651 | */ |
| 652 | public int getMode() { |
| 653 | return mode; |
| 654 | } |
| 655 | |
| 656 | /** |
| 657 | * Set the access permissions on the entry. |
| 658 | */ |
| 659 | public void setMode(int mode) { |
| 660 | this.mode = mode & 07777; |
| 661 | this.permissions = PERMISSION.find(mode); |
| 662 | } |
| 663 | |
| 664 | /** |
| 665 | * Returns the permissions on the entry. |
| 666 | */ |
| 667 | public Set<PERMISSION> getPermissions() { |
| 668 | return permissions; |
| 669 | } |
| 670 | |
| 671 | /** |
| 672 | * Returns the size of the entry. |
| 673 | */ |
| 674 | public long getSize() { |
Stefan Bodewig | b0e55a1 | 2011-08-17 14:07:12 +0000 | [diff] [blame] | 675 | return isDirectory() ? SIZE_UNKNOWN : size; |
| 676 | } |
| 677 | |
| 678 | /** |
| 679 | * Returns the size of the entry as read from the archive. |
| 680 | */ |
| 681 | long getEntrySize() { |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 682 | return size; |
| 683 | } |
| 684 | |
| 685 | /** |
| 686 | * Set the size of the entry. |
| 687 | */ |
| 688 | public void setSize(long size) { |
| 689 | this.size = size; |
| 690 | } |
| 691 | |
| 692 | /** |
| 693 | * Set the time the file was last modified. |
| 694 | */ |
| 695 | public void setLastModifiedDate(Date mtime) { |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 696 | this.mtime = mtime.getTime(); |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 697 | } |
| 698 | |
| 699 | /** |
| 700 | * Returns the time the file was last accessed. |
| 701 | */ |
| 702 | public Date getAccessTime() { |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 703 | return new Date(atime); |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 704 | } |
| 705 | |
| 706 | /** |
| 707 | * Set the time the file was last accessed. |
| 708 | */ |
| 709 | public void setAccessTime(Date atime) { |
Stefan Bodewig | 34e9390 | 2011-08-16 04:04:07 +0000 | [diff] [blame] | 710 | this.atime = atime.getTime(); |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 711 | } |
| 712 | |
| 713 | /** |
| 714 | * Return the user id. |
| 715 | */ |
| 716 | public int getUserId() { |
| 717 | return uid; |
| 718 | } |
| 719 | |
| 720 | /** |
| 721 | * Set the user id. |
| 722 | */ |
| 723 | public void setUserId(int uid) { |
| 724 | this.uid = uid; |
| 725 | } |
| 726 | |
| 727 | /** |
| 728 | * Return the group id |
| 729 | */ |
| 730 | public int getGroupId() { |
| 731 | return gid; |
| 732 | } |
| 733 | |
| 734 | /** |
| 735 | * Set the group id. |
| 736 | */ |
| 737 | public void setGroupId(int gid) { |
| 738 | this.gid = gid; |
| 739 | } |
| 740 | |
| 741 | public enum TYPE { |
| 742 | WHITEOUT(14), |
| 743 | SOCKET(12), |
| 744 | LINK(10), |
| 745 | FILE(8), |
| 746 | BLKDEV(6), |
| 747 | DIRECTORY(4), |
| 748 | CHRDEV(2), |
| 749 | FIFO(1), |
| 750 | UNKNOWN(15); |
Sebastian Bazley | 578aefd | 2012-03-31 12:15:22 +0000 | [diff] [blame] | 751 | |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 752 | private int code; |
| 753 | |
| 754 | private TYPE(int code) { |
| 755 | this.code = code; |
| 756 | } |
| 757 | |
| 758 | public static TYPE find(int code) { |
| 759 | TYPE type = UNKNOWN; |
| 760 | |
| 761 | for (TYPE t : TYPE.values()) { |
| 762 | if (code == t.code) { |
| 763 | type = t; |
| 764 | } |
| 765 | } |
| 766 | |
| 767 | return type; |
| 768 | } |
| 769 | } |
Sebastian Bazley | 39c93f4 | 2012-03-31 12:30:09 +0000 | [diff] [blame] | 770 | |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 771 | public enum PERMISSION { |
| 772 | SETUID(04000), |
| 773 | SETGUI(02000), |
| 774 | STICKY(01000), |
| 775 | USER_READ(00400), |
| 776 | USER_WRITE(00200), |
| 777 | USER_EXEC(00100), |
| 778 | GROUP_READ(00040), |
| 779 | GROUP_WRITE(00020), |
| 780 | GROUP_EXEC(00010), |
| 781 | WORLD_READ(00004), |
| 782 | WORLD_WRITE(00002), |
| 783 | WORLD_EXEC(00001); |
Sebastian Bazley | 578aefd | 2012-03-31 12:15:22 +0000 | [diff] [blame] | 784 | |
Stefan Bodewig | 054452a | 2011-08-15 10:47:04 +0000 | [diff] [blame] | 785 | private int code; |
| 786 | |
| 787 | private PERMISSION(int code) { |
| 788 | this.code = code; |
| 789 | } |
| 790 | |
| 791 | public static Set<PERMISSION> find(int code) { |
| 792 | Set<PERMISSION> set = new HashSet<PERMISSION>(); |
| 793 | |
| 794 | for (PERMISSION p : PERMISSION.values()) { |
| 795 | if ((code & p.code) == p.code) { |
| 796 | set.add(p); |
| 797 | } |
| 798 | } |
| 799 | |
| 800 | if (set.isEmpty()) { |
| 801 | return Collections.emptySet(); |
| 802 | } |
| 803 | |
| 804 | return EnumSet.copyOf(set); |
| 805 | } |
| 806 | } |
| 807 | } |