1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs2.provider.tar;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.nio.file.Files;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.Objects;
27 import java.util.zip.GZIPInputStream;
28
29 import org.apache.commons.compress.archivers.ArchiveEntry;
30 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
31 import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.commons.vfs2.Capability;
35 import org.apache.commons.vfs2.FileName;
36 import org.apache.commons.vfs2.FileNotFoundException;
37 import org.apache.commons.vfs2.FileObject;
38 import org.apache.commons.vfs2.FileSystemException;
39 import org.apache.commons.vfs2.FileSystemOptions;
40 import org.apache.commons.vfs2.Selectors;
41 import org.apache.commons.vfs2.VfsLog;
42 import org.apache.commons.vfs2.provider.AbstractFileName;
43 import org.apache.commons.vfs2.provider.AbstractFileSystem;
44 import org.apache.commons.vfs2.provider.UriParser;
45 import org.apache.commons.vfs2.provider.bzip2.Bzip2FileObject;
46
47
48
49
50 public class TarFileSystem extends AbstractFileSystem {
51 private static final Log LOG = LogFactory.getLog(TarFileSystem.class);
52
53 private static final char[] ENC = {'!'};
54
55 private final File file;
56
57 private TarArchiveInputStream tarFile;
58
59
60
61
62 private final Map<FileName, FileObject> cache = new HashMap<>();
63
64
65
66
67
68
69
70
71
72 protected TarFileSystem(final AbstractFileName rootName, final FileObject parentLayer,
73 final FileSystemOptions fileSystemOptions) throws FileSystemException {
74 super(rootName, parentLayer, fileSystemOptions);
75
76
77 file = parentLayer.getFileSystem().replicateFile(parentLayer, Selectors.SELECT_SELF);
78
79
80 if (!file.exists()) {
81
82 tarFile = null;
83 }
84
85
86 }
87
88
89
90
91 @Override
92 protected void addCapabilities(final Collection<Capability> caps) {
93 caps.addAll(TarFileProvider.capabilities);
94 }
95
96
97
98
99 @Override
100 protected FileObject createFile(final AbstractFileName name) throws FileSystemException {
101
102 return new TarFileObject(name, null, this, false);
103 }
104
105
106
107
108
109
110
111
112 protected TarArchiveInputStream createTarFile(final File file) throws FileSystemException {
113 try {
114 if ("tgz".equalsIgnoreCase(getRootName().getScheme())) {
115 return new TarArchiveInputStream(new GZIPInputStream(Files.newInputStream(file.toPath())));
116 }
117 if ("tbz2".equalsIgnoreCase(getRootName().getScheme())) {
118 return new TarArchiveInputStream(
119 Bzip2FileObject.wrapInputStream(file.getAbsolutePath(), Files.newInputStream(file.toPath())));
120 }
121 return new TarArchiveInputStream(Files.newInputStream(file.toPath()));
122 } catch (final IOException ioe) {
123 throw new FileSystemException("vfs.provider.tar/open-tar-file.error", file, ioe);
124 }
125 }
126
127
128
129
130
131
132
133
134 protected TarFileObject createTarFileObject(final AbstractFileName fileName, final TarArchiveEntry entry) {
135 return new TarFileObject(fileName, entry, this, true);
136 }
137
138 @Override
139 protected void doCloseCommunicationLink() {
140
141 try {
142 if (tarFile != null) {
143 tarFile.close();
144 tarFile = null;
145 }
146 } catch (final IOException e) {
147
148 VfsLog.warn(getLogger(), LOG, "vfs.provider.tar/close-tar-file.error :" + file, e);
149 }
150 }
151
152
153
154
155 @Override
156 protected FileObject getFileFromCache(final FileName name) {
157 return cache.get(name);
158 }
159
160
161
162
163
164
165
166
167 public InputStream getInputStream(final TarArchiveEntry entry) throws FileSystemException {
168 Objects.requireNonNull(entry, "entry");
169 resetTarFile();
170 try {
171 ArchiveEntry next;
172 while ((next = tarFile.getNextEntry()) != null) {
173 if (next.equals(entry)) {
174 return tarFile;
175 }
176 }
177 throw new FileNotFoundException(entry.toString());
178 } catch (final IOException e) {
179 throw new FileSystemException(e);
180 }
181 }
182
183
184
185
186
187
188
189 protected TarArchiveInputStream getTarFile() throws FileSystemException {
190 if (tarFile == null && file.exists()) {
191 recreateTarFile();
192 }
193 return tarFile;
194 }
195
196 @Override
197 public void init() throws FileSystemException {
198 super.init();
199
200
201 try {
202 TarArchiveEntry entry;
203 while ((entry = getTarFile().getNextTarEntry()) != null) {
204 final AbstractFileName name = (AbstractFileName) getFileSystemManager().resolveName(getRootName(),
205 UriParser.encode(entry.getName(), ENC));
206
207
208 TarFileObject fileObj;
209 if (entry.isDirectory() && getFileFromCache(name) != null) {
210 fileObj = (TarFileObject) getFileFromCache(name);
211 fileObj.setTarEntry(entry);
212 continue;
213 }
214
215 fileObj = createTarFileObject(name, entry);
216 putFileToCache(fileObj);
217
218
219
220 TarFileObject parent = null;
221 for (AbstractFileName parentName = (AbstractFileName) name
222 .getParent(); parentName != null; fileObj = parent, parentName = (AbstractFileName) parentName
223 .getParent()) {
224
225 parent = (TarFileObject) getFileFromCache(parentName);
226 if (parent == null) {
227 parent = createTarFileObject(parentName, null);
228 putFileToCache(parent);
229 }
230
231
232 parent.attachChild(fileObj.getName());
233 }
234 }
235 } catch (final IOException e) {
236 throw new FileSystemException(e);
237 } finally {
238 closeCommunicationLink();
239 }
240 }
241
242
243
244
245 @Override
246 protected void putFileToCache(final FileObject file) {
247 cache.put(file.getName(), file);
248 }
249
250
251
252
253
254 private void recreateTarFile() throws FileSystemException {
255 if (tarFile != null) {
256 try {
257 tarFile.close();
258 } catch (final IOException e) {
259 throw new FileSystemException("vfs.provider.tar/close-tar-file.error", file, e);
260 }
261 tarFile = null;
262 }
263 tarFile = createTarFile(file);
264 }
265
266
267
268
269 @Override
270 protected void removeFileFromCache(final FileName name) {
271 cache.remove(name);
272 }
273
274
275
276
277
278
279 protected void resetTarFile() throws FileSystemException {
280
281
282
283 if (file.exists()) {
284 recreateTarFile();
285 }
286 }
287 }