001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.archivers.dump;
020
021import java.util.Collections;
022import java.util.Date;
023import java.util.EnumSet;
024import java.util.HashSet;
025import java.util.Set;
026
027import org.apache.commons.compress.archivers.ArchiveEntry;
028
029/**
030 * This class represents an entry in a Dump archive. It consists of the entry's header, the entry's File and any extended attributes.
031 * <p>
032 * DumpEntries that are created from the header bytes read from an archive are instantiated with the DumpArchiveEntry( byte[] ) constructor. These entries will
033 * 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
034 * to null, since they reference an archive entry not a file.
035 * <p>
036 * 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
037 * 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
038 * and the File is set to null.
039 *
040 * <p>
041 * The C structure for a Dump Entry's header is:
042 *
043 * <pre>
044 * #define TP_BSIZE    1024          // size of each file block
045 * #define NTREC       10            // number of blocks to write at once
046 * #define HIGHDENSITYTREC 32        // number of blocks to write on high-density tapes
047 * #define TP_NINDIR   (TP_BSIZE/2)  // number if indirect inodes in record
048 * #define TP_NINOS    (TP_NINDIR / sizeof (int32_t))
049 * #define LBLSIZE     16
050 * #define NAMELEN     64
051 *
052 * #define OFS_MAGIC     (int) 60011  // old format magic value
053 * #define NFS_MAGIC     (int) 60012  // new format magic value
054 * #define FS_UFS2_MAGIC (int) 0x19540119
055 * #define CHECKSUM      (int) 84446  // constant used in checksum algorithm
056 *
057 * struct  s_spcl {
058 *   int32_t c_type;             // record type (see below)
059 *   int32_t <strong>c_date</strong>;             // date of this dump
060 *   int32_t <strong>c_ddate</strong>;            // date of previous dump
061 *   int32_t c_volume;           // dump volume number
062 *   u_int32_t c_tapea;          // logical block of this record
063 *   dump_ino_t c_ino;           // number of inode
064 *   int32_t <strong>c_magic</strong>;            // magic number (see above)
065 *   int32_t c_checksum;         // record checksum
066 * #ifdef  __linux__
067 *   struct  new_bsd_inode c_dinode;
068 * #else
069 * #ifdef sunos
070 *   struct  new_bsd_inode c_dinode;
071 * #else
072 *   struct  dinode  c_dinode;   // ownership and mode of inode
073 * #endif
074 * #endif
075 *   int32_t c_count;            // number of valid c_addr entries
076 *   union u_data c_data;        // see above
077 *   char    <strong>c_label[LBLSIZE]</strong>;   // dump label
078 *   int32_t <strong>c_level</strong>;            // level of this dump
079 *   char    <strong>c_filesys[NAMELEN]</strong>; // name of dumpped file system
080 *   char    <strong>c_dev[NAMELEN]</strong>;     // name of dumpped device
081 *   char    <strong>c_host[NAMELEN]</strong>;    // name of dumpped host
082 *   int32_t c_flags;            // additional information (see below)
083 *   int32_t c_firstrec;         // first record on volume
084 *   int32_t c_ntrec;            // blocksize on volume
085 *   int32_t c_extattributes;    // additional inode info (see below)
086 *   int32_t c_spare[30];        // reserved for future uses
087 * } s_spcl;
088 *
089 * //
090 * // flag values
091 * //
092 * #define DR_NEWHEADER     0x0001  // new format tape header
093 * #define DR_NEWINODEFMT   0x0002  // new format inodes on tape
094 * #define DR_COMPRESSED    0x0080  // dump tape is compressed
095 * #define DR_METAONLY      0x0100  // only the metadata of the inode has been dumped
096 * #define DR_INODEINFO     0x0002  // [SIC] TS_END header contains c_inos information
097 * #define DR_EXTATTRIBUTES 0x8000
098 *
099 * //
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 &lt;ufs/ufs/dinode.h&gt; 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 =&gt; data; 0 =&gt; 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 */
174public 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}