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