View Javadoc
1   /*
2    * Copyright (C) 2005-2015 Schlichtherle IT Services.
3    * All rights reserved. Use is subject to license terms.
4    */
5   package net.java.truevfs.comp.tardriver;
6   
7   import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
8   import java.io.IOException;
9   import java.util.Date;
10  import javax.annotation.CheckForNull;
11  import javax.annotation.Nullable;
12  import static net.java.truecommons.cio.Entry.Access.WRITE;
13  import static net.java.truecommons.cio.Entry.Size.DATA;
14  import static net.java.truecommons.cio.Entry.Size.STORAGE;
15  import static net.java.truecommons.cio.Entry.Type.DIRECTORY;
16  import static net.java.truecommons.cio.Entry.Type.FILE;
17  import net.java.truecommons.cio.IoBuffer;
18  import net.java.truecommons.shed.Releasable;
19  import net.java.truevfs.kernel.spec.FsArchiveEntries;
20  import net.java.truevfs.kernel.spec.FsArchiveEntry;
21  import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
22  
23  /**
24   * An entry in a TAR archive which implements the {@code FsArchiveEntry}
25   * interface.
26   *
27   * @author Christian Schlichtherle
28   */
29  public class TarDriverEntry
30  extends TarArchiveEntry
31  implements FsArchiveEntry, Releasable<IOException> {
32  
33      // Bit masks for initialized fields.
34      private static final int SIZE = 1, MODTIME = 1 << 1;
35  
36      private static final int TUREAD  = 0400; // Read by owner
37      private static final int TUWRITE = 0200; // Write by owner special
38      private static final int TUEXEC  = 0100; // Execute/search by owner
39      private static final int TGREAD  = 0040; // Read by group
40      private static final int TGWRITE = 0020; // Write by group
41      private static final int TGEXEC  = 0010; // Execute/search by group
42      private static final int TOREAD  = 0004; // Read by other
43      private static final int TOWRITE = 0002; // Write by other
44      private static final int TOEXEC  = 0001; // Execute/search by other
45  
46      private byte init; // bit flags for init state
47      private @CheckForNull IoBuffer buffer;
48  
49      public TarDriverEntry(final String name) {
50          super(name, true);
51          // Fix super class constructor.
52          super.setUserName(System.getProperty("user.name", "TrueVFS"));
53      }
54  
55      protected TarDriverEntry(
56              final String name,
57              final TarArchiveEntry template) {
58          super(name, true);
59          //this.init = SIZE | MODTIME;
60          super.setMode(template.getMode());
61          this.setModTime0(template.getModTime().getTime());
62          this.setSize0(template.getSize());
63          super.setUserId(template.getLongUserId());
64          super.setUserName(template.getUserName());
65          super.setGroupId(template.getLongGroupId());
66          super.setGroupName(template.getGroupName());
67          super.setLinkName(template.getLinkName());
68          super.setDevMajor(template.getDevMajor());
69          super.setDevMinor(template.getDevMinor());
70      }
71  
72      private boolean isInit(final int mask) { return 0 != (init & mask); }
73  
74      private void setInit(final int mask, final boolean init) {
75          if (init) this.init |=  mask;
76          else      this.init &= ~mask;
77      }
78  
79      @Nullable IoBuffer getBuffer() { return buffer; }
80  
81      void setBuffer(final @CheckForNull IoBuffer buffer) { this.buffer = buffer; }
82  
83      @Override
84      public void release() throws IOException {
85          if (null == buffer) return;
86          buffer.release();
87          buffer = null;
88      }
89  
90      @Override
91      public Type getType() { return isDirectory() ? DIRECTORY : FILE; }
92  
93      @Override
94      public long getSize() { return isInit(SIZE) ? super.getSize() : UNKNOWN; }
95  
96      @Override
97      public void setSize(long size) { setSize0(size); }
98  
99      private void setSize0(final long size) {
100         final boolean known = UNKNOWN != size;
101         super.setSize(known ? size : 0);
102         setInit(SIZE, known);
103     }
104 
105     @Override
106     public long getSize(final Size type) {
107         switch (type) {
108             case DATA:
109             case STORAGE:
110                 return getSize();
111             default:
112                 return UNKNOWN;
113         }
114     }
115 
116     @Override
117     public boolean setSize(final Size type, final long size) {
118         if (DATA != type) return false;
119         setSize(size);
120         return true;
121     }
122 
123     @Override
124     public Date getModTime() {
125         return isInit(MODTIME) ? super.getModTime() : new Date(UNKNOWN);
126     }
127 
128     @Override
129     public void setModTime(long time) { setModTime0(time); }
130 
131     private void setModTime0(final long time) {
132         final boolean known = UNKNOWN != time;
133         super.setModTime(known ? time : 0);
134         setInit(MODTIME, known);
135     }
136 
137     @Override
138     public void setModTime(Date time) { setModTime(time.getTime()); }
139 
140     @Override
141     public long getTime(Access type) {
142         if (WRITE != type) return UNKNOWN;
143         long time = getModTime().getTime();
144         return 0 <= time ? time : UNKNOWN;
145     }
146 
147     @Override
148     public boolean setTime(Access type, long time) {
149         if (WRITE != type) return false;
150         setModTime(time);
151         return true;
152     }
153 
154     @Override
155     @SuppressFBWarnings("NP_BOOLEAN_RETURN_NULL")
156     public Boolean isPermitted(final Access type, final Entity entity) {
157         if (!(entity instanceof PosixEntity)) return null;
158         switch ((PosixEntity) entity) {
159         case USER:
160             switch (type) {
161             case READ:
162                 return 0 != (super.getMode() & TUREAD);
163             case WRITE:
164                 return 0 != (super.getMode() & TUWRITE);
165             case EXECUTE:
166                 return 0 != (super.getMode() & TUEXEC);
167             }
168             break;
169         case GROUP:
170             switch (type) {
171             case READ:
172                 return 0 != (super.getMode() & TGREAD);
173             case WRITE:
174                 return 0 != (super.getMode() & TGWRITE);
175             case EXECUTE:
176                 return 0 != (super.getMode() & TGEXEC);
177             }
178             break;
179         case OTHER:
180             switch (type) {
181             case READ:
182                 return 0 != (super.getMode() & TOREAD);
183             case WRITE:
184                 return 0 != (super.getMode() & TOWRITE);
185             case EXECUTE:
186                 return 0 != (super.getMode() & TOEXEC);
187             }
188         }
189         return null;
190     }
191 
192     @Override
193     public boolean setPermitted(
194             final Access type,
195             final Entity entity,
196             final Boolean value) {
197         if (null == value || !(entity instanceof PosixEntity)) return false;
198         switch ((PosixEntity) entity) {
199         case USER:
200             switch (type) {
201             case READ:
202                 super.setMode(value ? super.getMode() | TUREAD : super.getMode() & ~TUREAD);
203                 return true;
204             case WRITE:
205                 super.setMode(value ? super.getMode() | TUWRITE : super.getMode() & ~TUWRITE);
206                 return true;
207             case EXECUTE:
208                 super.setMode(value ? super.getMode() | TUEXEC : super.getMode() & ~TUEXEC);
209                 return true;
210             }
211             break;
212         case GROUP:
213             switch (type) {
214             case READ:
215                 super.setMode(value ? super.getMode() | TGREAD : super.getMode() & ~TGREAD);
216                 return true;
217             case WRITE:
218                 super.setMode(value ? super.getMode() | TGWRITE : super.getMode() & ~TGWRITE);
219                 return true;
220             case EXECUTE:
221                 super.setMode(value ? super.getMode() | TGEXEC : super.getMode() & ~TGEXEC);
222                 return true;
223             }
224             break;
225         case OTHER:
226             switch (type) {
227             case READ:
228                 super.setMode(value ? super.getMode() | TOREAD : super.getMode() & ~TOREAD);
229                 return true;
230             case WRITE:
231                 super.setMode(value ? super.getMode() | TOWRITE : super.getMode() & ~TOWRITE);
232                 return true;
233             case EXECUTE:
234                 super.setMode(value ? super.getMode() | TOEXEC : super.getMode() & ~TOEXEC);
235                 return true;
236             }
237         }
238         return false;
239     }
240 
241     /**
242      * Returns a string representation of this object for debugging and logging
243      * purposes.
244      */
245     @Override
246     public String toString() { return FsArchiveEntries.toString(this); }
247 }