1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. 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.apache.commons.vfs2.provider.tar;
18
19 import java.io.InputStream;
20 import java.util.HashSet;
21
22 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
23 import org.apache.commons.lang3.ArrayUtils;
24 import org.apache.commons.vfs2.FileName;
25 import org.apache.commons.vfs2.FileSystemException;
26 import org.apache.commons.vfs2.FileType;
27 import org.apache.commons.vfs2.provider.AbstractFileName;
28 import org.apache.commons.vfs2.provider.AbstractFileObject;
29
30 /**
31 * A file in a Tar file system.
32 */
33 public class TarFileObject extends AbstractFileObject<TarFileSystem> {
34
35 /** The TarArchiveEntry */
36 private TarArchiveEntry entry;
37 private final HashSet<String> children = new HashSet<>();
38 private FileType type;
39
40 protected TarFileObject(final AbstractFileName name, final TarArchiveEntry entry, final TarFileSystem fs,
41 final boolean tarExists) {
42 super(name, fs);
43 setTarEntry(entry);
44 if (!tarExists) {
45 type = FileType.IMAGINARY;
46 }
47 }
48
49 /**
50 * Sets the details for this file object.
51 *
52 * Consider this method package private. TODO Might be made package private in the next major version.
53 *
54 * @param entry Tar archive entry.
55 */
56 protected void setTarEntry(final TarArchiveEntry entry) {
57 if (this.entry != null) {
58 return;
59 }
60
61 if (entry == null || entry.isDirectory()) {
62 type = FileType.FOLDER;
63 } else {
64 type = FileType.FILE;
65 }
66
67 this.entry = entry;
68 }
69
70 /**
71 * Attaches a child.
72 *
73 * @param childName Name of child to remember.
74 */
75 protected void attachChild(final FileName childName) {
76 children.add(childName.getBaseName());
77 }
78
79 /**
80 * Determines if this file can be written to.
81 *
82 * @return {@code true} if this file is writable, {@code false} if not.
83 * @throws FileSystemException if an error occurs.
84 */
85 @Override
86 public boolean isWriteable() throws FileSystemException {
87 return false;
88 }
89
90 /**
91 * Returns the file's type.
92 */
93 @Override
94 protected FileType doGetType() {
95 return type;
96 }
97
98 /**
99 * Lists the children of the file.
100 */
101 @Override
102 protected String[] doListChildren() {
103 try {
104 if (!getType().hasChildren()) {
105 return null;
106 }
107 } catch (final FileSystemException e) {
108 // should not happen as the type has already been cached.
109 throw new RuntimeException(e);
110 }
111
112 return children.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
113 }
114
115 /**
116 * Returns the size of the file content (in bytes). Is only called if {@link #doGetType} returns
117 * {@link FileType#FILE}.
118 */
119 @Override
120 protected long doGetContentSize() {
121 if (entry == null) {
122 return 0;
123 }
124
125 return entry.getSize();
126 }
127
128 /**
129 * Returns the last modified time of this file.
130 */
131 @Override
132 protected long doGetLastModifiedTime() throws Exception {
133 if (entry == null) {
134 return 0;
135 }
136
137 return entry.getModTime().getTime();
138 }
139
140 /**
141 * Creates an input stream to read the file content from. Is only called if {@link #doGetType} returns
142 * {@link FileType#FILE}. The input stream returned by this method is guaranteed to be closed before this method is
143 * called again.
144 */
145 @Override
146 protected InputStream doGetInputStream(final int bufferSize) throws Exception {
147 // VFS-210: zip allows to gather an input stream even from a directory and will
148 // return -1 on the first read. getType should not be expensive and keeps the tests
149 // running
150 if (!getType().hasContent()) {
151 throw new FileSystemException("vfs.provider/read-not-file.error", getName());
152 }
153
154 return getAbstractFileSystem().getInputStream(entry);
155 }
156 }