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