blob: 712959310b197822d99dd34a1a755f9e3e7a8c75 [file] [log] [blame]
Stefan Bodewig054452a2011-08-15 10:47:04 +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.dump;
20
21import java.util.Collections;
22import java.util.Date;
23import java.util.EnumSet;
24import java.util.HashSet;
25import java.util.Set;
26import 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 */
179public 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 Bodewig34e93902011-08-16 04:04:07 +0000185 private long atime;
186 private long mtime;
Stefan Bodewig054452a2011-08-15 10:47:04 +0000187 private int uid;
188 private int gid;
189
Stefan Bodewig34e93902011-08-16 04:04:07 +0000190 /**
191 * Currently unused
192 */
Gary D. Gregorya67d5622013-01-22 12:48:16 +0000193 private final DumpArchiveSummary summary = null;
Stefan Bodewig054452a2011-08-15 10:47:04 +0000194
195 // this information is available from standard index.
Gary D. Gregorya67d5622013-01-22 12:48:16 +0000196 private final TapeSegmentHeader header = new TapeSegmentHeader();
Stefan Bodewig054452a2011-08-15 10:47:04 +0000197 private String simpleName;
Stefan Bodewig281591e2011-08-17 14:49:08 +0000198 private String originalName;
Stefan Bodewig054452a2011-08-15 10:47:04 +0000199
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 Bodewig34e93902011-08-16 04:04:07 +0000205 private long ctime;
Stefan Bodewig054452a2011-08-15 10:47:04 +0000206 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 Bodewig281591e2011-08-17 14:49:08 +0000221 setName(name);
Stefan Bodewig054452a2011-08-15 10:47:04 +0000222 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 Bodewig054452a2011-08-15 10:47:04 +0000235 setType(type);
Stefan Bodewigf51fee12011-10-27 08:51:20 +0000236 setName(name);
237 this.simpleName = simpleName;
Stefan Bodewig054452a2011-08-15 10:47:04 +0000238 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 Bazley2e44b5b2011-08-15 15:08:33 +0000250 * @return the path of the entry.
Stefan Bodewig054452a2011-08-15 10:47:04 +0000251 */
252 public String getSimpleName() {
253 return simpleName;
254 }
255
256 /**
257 * Sets the path of the entry.
Stefan Bodewig054452a2011-08-15 10:47:04 +0000258 */
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 Bodewig34e93902011-08-16 04:04:07 +0000288 return new Date(ctime);
Stefan Bodewig054452a2011-08-15 10:47:04 +0000289 }
290
291 /**
292 * Set the file creation time.
293 */
294 public void setCreationTime(Date ctime) {
Stefan Bodewig34e93902011-08-16 04:04:07 +0000295 this.ctime = ctime.getTime();
Stefan Bodewig054452a2011-08-15 10:47:04 +0000296 }
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 Bodewig34e93902011-08-16 04:04:07 +0000397 } else if (o == null || !o.getClass().equals(getClass())) {
Stefan Bodewig054452a2011-08-15 10:47:04 +0000398 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 Bodewig34e93902011-08-16 04:04:07 +0000411 if ((summary == null && rhs.summary != null)
412 || (summary != null && !summary.equals(rhs.summary))) {
Stefan Bodewig054452a2011-08-15 10:47:04 +0000413 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 Bodewig07ec3532011-08-16 03:13:32 +0000434 static DumpArchiveEntry parse(byte[] buffer) {
Stefan Bodewig054452a2011-08-15 10:47:04 +0000435 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 Bodewig34e93902011-08-16 04:04:07 +0000470 entry.ctime = t;
Stefan Bodewig054452a2011-08-15 10:47:04 +0000471
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 Bodewig07ec3532011-08-16 03:13:32 +0000501 void update(byte[] buffer) {
Stefan Bodewig054452a2011-08-15 10:47:04 +0000502 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 Bodewig07ec3532011-08-16 03:13:32 +0000520 static class TapeSegmentHeader {
Stefan Bodewig054452a2011-08-15 10:47:04 +0000521 private DumpArchiveConstants.SEGMENT_TYPE type;
522 private int volume;
523 private int ino;
524 private int count;
525 private int holes;
Gary D. Gregorya67d5622013-01-22 12:48:16 +0000526 private final byte[] cdata = new byte[512]; // map of any 'holes'
Stefan Bodewig054452a2011-08-15 10:47:04 +0000527
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 Bazley2e44b5b2011-08-15 15:08:33 +0000559 * @return the name of the entry.
Stefan Bodewig054452a2011-08-15 10:47:04 +0000560 */
561 public String getName() {
562 return name;
563 }
564
565 /**
Stefan Bodewig281591e2011-08-17 14:49:08 +0000566 * 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 Bodewig054452a2011-08-15 10:47:04 +0000574 * Sets the name of the entry.
Stefan Bodewig054452a2011-08-15 10:47:04 +0000575 */
Stefan Bodewig281591e2011-08-17 14:49:08 +0000576 public final void setName(String name) {
577 this.originalName = name;
578 if (name != null) {
Stefan Bodewig281591e2011-08-17 14:49:08 +0000579 if (isDirectory() && !name.endsWith("/")) {
580 name += "/";
581 }
Stefan Bodewig6715dba2011-08-18 04:27:07 +0000582 if (name.startsWith("./")) {
583 name = name.substring(2);
584 }
Stefan Bodewig281591e2011-08-17 14:49:08 +0000585 }
Stefan Bodewig054452a2011-08-15 10:47:04 +0000586 this.name = name;
587 }
588
Stefan Bodewig054452a2011-08-15 10:47:04 +0000589 public Date getLastModifiedDate() {
Stefan Bodewig34e93902011-08-16 04:04:07 +0000590 return new Date(mtime);
Stefan Bodewig054452a2011-08-15 10:47:04 +0000591 }
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 Bodewigb0e55a12011-08-17 14:07:12 +0000675 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 Bodewig054452a2011-08-15 10:47:04 +0000682 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 Bodewig34e93902011-08-16 04:04:07 +0000696 this.mtime = mtime.getTime();
Stefan Bodewig054452a2011-08-15 10:47:04 +0000697 }
698
699 /**
700 * Returns the time the file was last accessed.
701 */
702 public Date getAccessTime() {
Stefan Bodewig34e93902011-08-16 04:04:07 +0000703 return new Date(atime);
Stefan Bodewig054452a2011-08-15 10:47:04 +0000704 }
705
706 /**
707 * Set the time the file was last accessed.
708 */
709 public void setAccessTime(Date atime) {
Stefan Bodewig34e93902011-08-16 04:04:07 +0000710 this.atime = atime.getTime();
Stefan Bodewig054452a2011-08-15 10:47:04 +0000711 }
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 Bazley578aefd2012-03-31 12:15:22 +0000751
Stefan Bodewig054452a2011-08-15 10:47:04 +0000752 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 Bazley39c93f42012-03-31 12:30:09 +0000770
Stefan Bodewig054452a2011-08-15 10:47:04 +0000771 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 Bazley578aefd2012-03-31 12:15:22 +0000784
Stefan Bodewig054452a2011-08-15 10:47:04 +0000785 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}