View Javadoc
1   /**
2    *
3    * Copyright 2004 The Apache Software Foundation
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.codehaus.plexus.archiver;
18  
19  import javax.annotation.Nonnull;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStream;
24  
25  import org.codehaus.plexus.archiver.resources.PlexusIoVirtualSymlinkResource;
26  import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributes;
27  import org.codehaus.plexus.components.io.functions.ResourceAttributeSupplier;
28  import org.codehaus.plexus.components.io.resources.PlexusIoFileResource;
29  import org.codehaus.plexus.components.io.resources.PlexusIoResource;
30  import org.codehaus.plexus.components.io.resources.PlexusIoResourceCollection;
31  import org.codehaus.plexus.components.io.resources.ResourceFactory;
32  
33  import static org.codehaus.plexus.components.io.resources.ResourceFactory.createResource;
34  
35  public class ArchiveEntry {
36  
37      public static final String ROLE = ArchiveEntry.class.getName();
38  
39      public static final int FILE = 1;
40  
41      public static final int DIRECTORY = 2;
42  
43      public static final int SYMLINK = 3;
44  
45      @Nonnull
46      private final PlexusIoResource resource;
47  
48      private final String name;
49  
50      private final int type;
51  
52      private final int mode;
53  
54      private final int defaultDirMode; // Sometimes a directory needs to be created. Which mode should it be ?
55      // this mode is at the time of the creation of the archive entry, which is an important distinction
56  
57      private PlexusIoResourceAttributes attributes;
58  
59      private final boolean addSynchronously;
60  
61      /**
62       * @param name the filename as it will appear in the archive. This is platform-specific
63       * normalized with File.separatorChar
64       * @param resource original filename
65       * @param type FILE or DIRECTORY
66       * @param mode octal unix style permissions
67       * @param collection
68       * @param defaultDirMode
69       */
70      private ArchiveEntry(
71              String name,
72              @Nonnull PlexusIoResource resource,
73              int type,
74              int mode,
75              PlexusIoResourceCollection collection,
76              int defaultDirMode) {
77          try {
78              this.name = name;
79              this.defaultDirMode = defaultDirMode;
80              this.resource = collection != null ? collection.resolve(resource) : resource;
81              this.attributes = (resource instanceof ResourceAttributeSupplier)
82                      ? ((ResourceAttributeSupplier) resource).getAttributes()
83                      : null;
84              this.type = type;
85              int permissions = mode;
86  
87              if (mode == PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE && this.attributes == null) {
88                  permissions = resource.isFile()
89                          ? Archiver.DEFAULT_FILE_MODE
90                          : resource.isSymbolicLink() ? Archiver.DEFAULT_SYMLILNK_MODE : Archiver.DEFAULT_DIR_MODE;
91              }
92  
93              this.mode = permissions == PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE
94                      ? permissions
95                      : (permissions & UnixStat.PERM_MASK)
96                              | (type == FILE
97                                      ? UnixStat.FILE_FLAG
98                                      : type == SYMLINK ? UnixStat.LINK_FLAG : UnixStat.DIR_FLAG);
99  
100             this.addSynchronously = (collection != null && !collection.isConcurrentAccessSupported());
101         } catch (IOException e) {
102             throw new ArchiverException("Error resolving resource " + resource.getName(), e);
103         }
104     }
105 
106     /**
107      * @return the filename of this entry in the archive.
108      */
109     public String getName() {
110         return name;
111     }
112 
113     /**
114      * @return The original file that will be stored in the archive.
115      *
116      * @deprecated As of 1.0-alpha-10, file entries are no longer backed
117      * by files, but by instances of {@link PlexusIoResource}.
118      * Consequently, you should use {@link #getInputStream()}-
119      */
120     @Deprecated
121     public File getFile() {
122         if (resource instanceof PlexusIoFileResource) {
123             return ((PlexusIoFileResource) resource).getFile();
124         }
125         return null;
126     }
127 
128     /**
129      * @return The resource contents.
130      */
131     public InputStream getInputStream() throws IOException {
132         return resource.getContents();
133     }
134 
135     /**
136      * @return FILE or DIRECTORY
137      */
138     public int getType() {
139         return type;
140     }
141 
142     /**
143      * @return octal user/group/other unix like permissions.
144      */
145     public int getMode() {
146         if (mode != -1) {
147             return mode;
148         }
149 
150         if (attributes != null && attributes.getOctalMode() > -1) {
151             return attributes.getOctalMode();
152         }
153 
154         return ((type == FILE
155                                 ? Archiver.DEFAULT_FILE_MODE
156                                 : type == SYMLINK ? Archiver.DEFAULT_SYMLILNK_MODE : Archiver.DEFAULT_DIR_MODE)
157                         & UnixStat.PERM_MASK)
158                 | (type == FILE ? UnixStat.FILE_FLAG : type == SYMLINK ? UnixStat.LINK_FLAG : UnixStat.DIR_FLAG);
159     }
160 
161     /**
162      * Indicates if this entry should be added to the archive synchronously
163      * before adding the next entry and/or accessing the next entry of {@link ResourceIterator}.
164      *
165      * @return {@code true} if this entry should be added synchronously
166      */
167     public boolean shouldAddSynchronously() {
168         return addSynchronously;
169     }
170 
171     public static ArchiveEntry createFileEntry(
172             String target,
173             PlexusIoResource resource,
174             int permissions,
175             PlexusIoResourceCollection collection,
176             int defaultDirectoryPermissions)
177             throws ArchiverException {
178         if (resource.isDirectory()) {
179             throw new ArchiverException("Not a file: " + resource.getName());
180         }
181         final int type = resource.isSymbolicLink() ? SYMLINK : FILE;
182         return new ArchiveEntry(target, resource, type, permissions, collection, defaultDirectoryPermissions);
183     }
184 
185     public static ArchiveEntry createFileEntry(
186             String target, File file, int permissions, int defaultDirectoryPermissions)
187             throws ArchiverException, IOException {
188         if (!file.isFile()) {
189             throw new ArchiverException("Not a file: " + file);
190         }
191 
192         final PlexusIoResource res = ResourceFactory.createResource(file);
193 
194         final int type;
195         if (res.isSymbolicLink()) {
196             type = SYMLINK;
197             permissions = permissions & ~(UnixStat.FILE_FLAG); // remove file flag again .doh.
198         } else {
199             type = FILE; // File flag was there already. This is a bit of a mess !
200         }
201 
202         return new ArchiveEntry(target, res, type, permissions, null, defaultDirectoryPermissions);
203     }
204 
205     public static ArchiveEntry createDirectoryEntry(
206             String target, @Nonnull PlexusIoResource resource, int permissions, int defaultDirectoryPermissions)
207             throws ArchiverException {
208         if (!resource.isDirectory()) {
209             throw new ArchiverException("Not a directory: " + resource.getName());
210         }
211         final int type;
212         if (resource.isSymbolicLink()) {
213             type = SYMLINK;
214             permissions = permissions & ~(UnixStat.DIR_FLAG); // remove dir flag again .doh.
215         } else {
216             type = DIRECTORY; // Dir flag was there already. This is a bit of a mess !
217         }
218         return new ArchiveEntry(target, resource, type, permissions, null, defaultDirectoryPermissions);
219     }
220 
221     public static ArchiveEntry createDirectoryEntry(
222             String target, final File file, int permissions, int defaultDirMode1)
223             throws ArchiverException, IOException {
224         if (!file.isDirectory()) {
225             throw new ArchiverException("Not a directory: " + file);
226         }
227 
228         final PlexusIoResource res = createResource(file);
229         return new ArchiveEntry(target, res, DIRECTORY, permissions, null, defaultDirMode1);
230     }
231 
232     public static ArchiveEntry createSymlinkEntry(
233             String symlinkName, int permissions, String symlinkDestination, int defaultDirectoryPermissions) {
234         final ArchiveEntry archiveEntry = new ArchiveEntry(
235                 symlinkName,
236                 new PlexusIoVirtualSymlinkResource(new File(symlinkName), symlinkDestination),
237                 SYMLINK,
238                 permissions,
239                 null,
240                 defaultDirectoryPermissions);
241 
242         return archiveEntry;
243     }
244 
245     public PlexusIoResourceAttributes getResourceAttributes() {
246         return attributes;
247     }
248 
249     public void setResourceAttributes(PlexusIoResourceAttributes attributes) {
250         this.attributes = attributes;
251     }
252 
253     public @Nonnull PlexusIoResource getResource() {
254         return resource;
255     }
256 
257     public int getDefaultDirMode() {
258         return defaultDirMode;
259     }
260 }