19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package jdk.internal.jrtfs;
26
27 import java.io.IOException;
28 import java.nio.file.LinkOption;
29 import java.nio.file.FileSystemException;
30 import java.nio.file.InvalidPathException;
31 import java.nio.file.NoSuchFileException;
32 import java.nio.file.NotDirectoryException;
33 import java.nio.file.Path;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.function.Function;
40 import static java.util.stream.Collectors.toList;
41 import jdk.internal.jimage.ImageReader;
42 import jdk.internal.jimage.ImageReader.Node;
43 import jdk.internal.jimage.UTF8String;
44
45 /**
46 * jrt file system implementation built on System jimage files.
47 */
48 class JrtFileSystem extends AbstractJrtFileSystem {
49
50 // System image reader
51 private ImageReader bootImage;
52 // root path
53 private final JrtPath rootPath;
54 private volatile boolean isOpen;
55
56 // open a .jimage and build directory structure
57 private static ImageReader openImage(Path path) throws IOException {
58 ImageReader image = ImageReader.open(path.toString());
86 }
87
88 @Override
89 protected void finalize() throws Throwable {
90 try {
91 cleanup();
92 } catch (IOException ignored) {
93 }
94 super.finalize();
95 }
96
97 // AbstractJrtFileSystem method implementations
98 @Override
99 JrtPath getRootPath() {
100 return rootPath;
101 }
102
103 @Override
104 boolean isSameFile(AbstractJrtPath p1, AbstractJrtPath p2) throws IOException {
105 ensureOpen();
106 NodeAndImage n1 = findNode(p1.getName());
107 NodeAndImage n2 = findNode(p2.getName());
108 return n1.node.equals(n2.node);
109 }
110
111 @Override
112 boolean isLink(AbstractJrtPath jrtPath) throws IOException {
113 return checkNode(jrtPath.getName()).node.isLink();
114 }
115
116 @Override
117 AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException {
118 NodeAndImage ni = checkNode(jrtPath.getName());
119 if (ni.node.isLink()) {
120 Node node = ni.node.resolveLink();
121 return toJrtPath(node.getName().getBytesCopy());
122 }
123
124 return jrtPath;
125 }
126
127 @Override
128 JrtFileAttributes getFileAttributes(byte[] path, LinkOption... options)
129 throws IOException {
130 NodeAndImage ni = checkNode(path);
131 if (ni.node.isLink() && followLinks(options)) {
132 return new JrtFileAttributes(ni.node.resolveLink(true));
133 }
134 return new JrtFileAttributes(ni.node);
135 }
136
137 @Override
138 boolean exists(byte[] path) throws IOException {
139 try {
140 checkNode(path);
141 } catch (NoSuchFileException exp) {
142 return false;
143 }
144 return true;
145 }
146
147 @Override
148 boolean isDirectory(byte[] path, boolean resolveLinks)
149 throws IOException {
150 NodeAndImage ni = checkNode(path);
151 return resolveLinks && ni.node.isLink()
152 ? ni.node.resolveLink(true).isDirectory()
153 : ni.node.isDirectory();
154 }
155
156 @Override
157 Iterator<Path> iteratorOf(byte[] path, String childPrefix)
158 throws IOException {
159 NodeAndImage ni = checkNode(path);
160 Node node = ni.node.resolveLink(true);
161
162 if (!node.isDirectory()) {
163 throw new NotDirectoryException(getString(path));
164 }
165
166 if (node.isRootDir()) {
167 return rootDirIterator(path, childPrefix);
168 } else if (node.isModulesDir()) {
169 return modulesDirIterator(path, childPrefix);
170 } else if (node.isPackagesDir()) {
171 return packagesDirIterator(path, childPrefix);
172 }
173
174 return nodesToIterator(toJrtPath(path), childPrefix, node.getChildren());
175 }
176
177 @Override
178 byte[] getFileContent(byte[] path) throws IOException {
179 final NodeAndImage ni = checkResource(path);
180 return ni.getResource();
181 }
182
183 // Implementation details below this point
184 // clean up this file system - called from finalize and close
185 private void cleanup() throws IOException {
186 if (!isOpen) {
187 return;
188 }
189
190 synchronized (this) {
191 isOpen = false;
192
193 // close all image reader and null out
194 bootImage.close();
195 bootImage = null;
196 }
197 }
198
199 private static class NodeAndImage {
200
201 final Node node;
202 final ImageReader image;
203
204 NodeAndImage(Node node, ImageReader image) {
205 this.node = node;
206 this.image = image;
207 }
208
209 byte[] getResource() throws IOException {
210 return image.getResource(node);
211 }
212 }
213
214 private NodeAndImage lookup(byte[] path) {
215 ImageReader image = bootImage;
216 Node node;
217 try {
218 node = bootImage.findNode(path);
219 } catch (RuntimeException re) {
220 throw new InvalidPathException(getString(path), re.toString());
221 }
222 return node != null ? new NodeAndImage(node, image) : null;
223 }
224
225 private NodeAndImage lookupSymbolic(byte[] path) {
226 for (int i = 1; i < path.length; i++) {
227 if (path[i] == (byte) '/') {
228 byte[] prefix = Arrays.copyOfRange(path, 0, i);
229 NodeAndImage ni = lookup(prefix);
230 if (ni == null) {
231 break;
232 }
233
234 if (ni.node.isLink()) {
235 Node link = ni.node.resolveLink(true);
236 // resolved symbolic path concatenated to the rest of the path
237 UTF8String resPath = link.getName().concat(new UTF8String(path, i));
238 byte[] resPathBytes = resPath.getBytesCopy();
239 ni = lookup(resPathBytes);
240 return ni != null ? ni : lookupSymbolic(resPathBytes);
241 }
242 }
243 }
244
245 return null;
246 }
247
248 private NodeAndImage findNode(byte[] path) throws IOException {
249 NodeAndImage ni = lookup(path);
250 if (ni == null) {
251 ni = lookupSymbolic(path);
252 if (ni == null) {
253 throw new NoSuchFileException(getString(path));
254 }
255 }
256 return ni;
257 }
258
259 private NodeAndImage checkNode(byte[] path) throws IOException {
260 ensureOpen();
261 return findNode(path);
262 }
263
264 private NodeAndImage checkResource(byte[] path) throws IOException {
265 NodeAndImage ni = checkNode(path);
266 if (ni.node.isDirectory()) {
267 throw new FileSystemException(getString(path) + " is a directory");
268 }
269
270 assert ni.node.isResource() : "resource node expected here";
271 return ni;
272 }
273
274 private JrtPath toJrtPath(String path) {
275 return toJrtPath(getBytes(path));
276 }
277
278 private JrtPath toJrtPath(byte[] path) {
279 return new JrtPath(this, path);
280 }
281
282 private Iterator<Path> nodesToIterator(Path path, String childPrefix, List<Node> childNodes) {
283 Function<Node, Path> f = childPrefix == null
284 ? child -> toJrtPath(child.getNameString())
285 : child -> toJrtPath(childPrefix + child.getNameString().substring(1));
286 return childNodes.stream().map(f).collect(toList()).iterator();
287 }
288
289 private List<Node> rootChildren;
290
291 private synchronized void initRootChildren(byte[] path) {
292 if (rootChildren == null) {
293 rootChildren = new ArrayList<>();
294 rootChildren.addAll(bootImage.findNode(path).getChildren());
295 }
296 }
297
298 private Iterator<Path> rootDirIterator(byte[] path, String childPrefix) throws IOException {
299 initRootChildren(path);
300 return nodesToIterator(rootPath, childPrefix, rootChildren);
301 }
302
303 private List<Node> modulesChildren;
304
305 private synchronized void initModulesChildren(byte[] path) {
306 if (modulesChildren == null) {
307 modulesChildren = new ArrayList<>();
308 modulesChildren.addAll(bootImage.findNode(path).getChildren());
309 }
310 }
311
312 private Iterator<Path> modulesDirIterator(byte[] path, String childPrefix) throws IOException {
313 initModulesChildren(path);
314 return nodesToIterator(new JrtPath(this, path), childPrefix, modulesChildren);
315 }
316
317 private List<Node> packagesChildren;
318
319 private synchronized void initPackagesChildren(byte[] path) {
320 if (packagesChildren == null) {
321 packagesChildren = new ArrayList<>();
322 packagesChildren.addAll(bootImage.findNode(path).getChildren());
323 }
324 }
325
326 private Iterator<Path> packagesDirIterator(byte[] path, String childPrefix) throws IOException {
327 initPackagesChildren(path);
328 return nodesToIterator(new JrtPath(this, path), childPrefix, packagesChildren);
329 }
330 }
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package jdk.internal.jrtfs;
26
27 import java.io.IOException;
28 import java.nio.file.LinkOption;
29 import java.nio.file.FileSystemException;
30 import java.nio.file.InvalidPathException;
31 import java.nio.file.NoSuchFileException;
32 import java.nio.file.NotDirectoryException;
33 import java.nio.file.Path;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Objects;
40 import java.util.function.Function;
41 import static java.util.stream.Collectors.toList;
42 import jdk.internal.jimage.ImageReader;
43 import jdk.internal.jimage.ImageReader.Node;
44 import jdk.internal.jimage.UTF8String;
45
46 /**
47 * jrt file system implementation built on System jimage files.
48 */
49 class JrtFileSystem extends AbstractJrtFileSystem {
50
51 // System image reader
52 private ImageReader bootImage;
53 // root path
54 private final JrtPath rootPath;
55 private volatile boolean isOpen;
56
57 // open a .jimage and build directory structure
58 private static ImageReader openImage(Path path) throws IOException {
59 ImageReader image = ImageReader.open(path.toString());
87 }
88
89 @Override
90 protected void finalize() throws Throwable {
91 try {
92 cleanup();
93 } catch (IOException ignored) {
94 }
95 super.finalize();
96 }
97
98 // AbstractJrtFileSystem method implementations
99 @Override
100 JrtPath getRootPath() {
101 return rootPath;
102 }
103
104 @Override
105 boolean isSameFile(AbstractJrtPath p1, AbstractJrtPath p2) throws IOException {
106 ensureOpen();
107 Node node1 = findNode(p1);
108 Node node2 = findNode(p2);
109 return node1.equals(node2);
110 }
111
112 @Override
113 boolean isLink(AbstractJrtPath jrtPath) throws IOException {
114 return checkNode(jrtPath).isLink();
115 }
116
117 @Override
118 AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException {
119 Node node = checkNode(jrtPath);
120 if (node.isLink()) {
121 node = node.resolveLink();
122 return toJrtPath(node.getName().getBytesCopy());
123 }
124
125 return jrtPath;
126 }
127
128 @Override
129 JrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options)
130 throws IOException {
131 Node node = checkNode(jrtPath);
132 if (node.isLink() && followLinks(options)) {
133 return new JrtFileAttributes(node.resolveLink(true));
134 }
135 return new JrtFileAttributes(node);
136 }
137
138 @Override
139 boolean exists(AbstractJrtPath jrtPath) throws IOException {
140 try {
141 checkNode(jrtPath);
142 } catch (NoSuchFileException exp) {
143 return false;
144 }
145 return true;
146 }
147
148 @Override
149 boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks)
150 throws IOException {
151 Node node = checkNode(jrtPath);
152 return resolveLinks && node.isLink()
153 ? node.resolveLink(true).isDirectory()
154 : node.isDirectory();
155 }
156
157 @Override
158 Iterator<Path> iteratorOf(AbstractJrtPath jrtPath) throws IOException {
159 Node node = checkNode(jrtPath).resolveLink(true);
160 if (!node.isDirectory()) {
161 throw new NotDirectoryException(getString(jrtPath.getName()));
162 }
163
164 if (node.isRootDir()) {
165 return rootDirIterator(jrtPath);
166 } else if (node.isModulesDir()) {
167 return modulesDirIterator(jrtPath);
168 } else if (node.isPackagesDir()) {
169 return packagesDirIterator(jrtPath);
170 }
171
172 return nodesToIterator(jrtPath, node.getChildren());
173 }
174
175 @Override
176 byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException {
177 final Node node = checkResource(jrtPath);
178 return bootImage.getResource(node);
179 }
180
181 // Implementation details below this point
182 // clean up this file system - called from finalize and close
183 private void cleanup() throws IOException {
184 if (!isOpen) {
185 return;
186 }
187
188 synchronized (this) {
189 isOpen = false;
190
191 // close all image reader and null out
192 bootImage.close();
193 bootImage = null;
194 }
195 }
196
197 private Node lookup(byte[] path) {
198 Node node = null;
199 try {
200 node = bootImage.findNode(path);
201 } catch (RuntimeException re) {
202 throw new InvalidPathException(getString(path), re.toString());
203 }
204 return node;
205 }
206
207 private Node lookupSymbolic(byte[] path) {
208 for (int i = 1; i < path.length; i++) {
209 if (path[i] == (byte) '/') {
210 byte[] prefix = Arrays.copyOfRange(path, 0, i);
211 Node node = lookup(prefix);
212 if (node == null) {
213 break;
214 }
215
216 if (node.isLink()) {
217 Node link = node.resolveLink(true);
218 // resolved symbolic path concatenated to the rest of the path
219 UTF8String resPath = link.getName().concat(new UTF8String(path, i));
220 byte[] resPathBytes = resPath.getBytesCopy();
221 node = lookup(resPathBytes);
222 return node != null ? node : lookupSymbolic(resPathBytes);
223 }
224 }
225 }
226
227 return null;
228 }
229
230 private Node findNode(AbstractJrtPath jrtPath) throws IOException {
231 return findNode(jrtPath.getResolvedPath());
232 }
233
234 private Node findNode(byte[] path) throws IOException {
235 Node node = lookup(path);
236 if (node == null) {
237 node = lookupSymbolic(path);
238 if (node == null) {
239 throw new NoSuchFileException(getString(path));
240 }
241 }
242 return node;
243 }
244
245 private Node checkNode(AbstractJrtPath jrtPath) throws IOException {
246 return checkNode(jrtPath.getResolvedPath());
247 }
248
249 private Node checkNode(byte[] path) throws IOException {
250 ensureOpen();
251 return findNode(path);
252 }
253
254 private Node checkResource(AbstractJrtPath jrtPath) throws IOException {
255 return checkResource(jrtPath.getResolvedPath());
256 }
257
258 private Node checkResource(byte[] path) throws IOException {
259 Node node = checkNode(path);
260 if (node.isDirectory()) {
261 throw new FileSystemException(getString(path) + " is a directory");
262 }
263
264 assert node.isResource() : "resource node expected here";
265 return node;
266 }
267
268 private JrtPath toJrtPath(String path) {
269 return toJrtPath(getBytes(path));
270 }
271
272 private JrtPath toJrtPath(byte[] path) {
273 return new JrtPath(this, path);
274 }
275
276 private Iterator<Path> nodesToIterator(AbstractJrtPath dir, List<Node> childNodes) {
277 Function<Node, Path> nodeToPath =
278 child -> dir.resolve(
279 toJrtPath(child.getNameString()).getFileName());
280 return childNodes.stream().
281 map(nodeToPath).collect(toList()).
282 iterator();
283 }
284
285 private List<Node> rootChildren;
286
287 private synchronized void initRootChildren(AbstractJrtPath jrtPath) throws IOException {
288 if (rootChildren == null) {
289 rootChildren = new ArrayList<>();
290 rootChildren.addAll(findNode(jrtPath).getChildren());
291 }
292 }
293
294 private Iterator<Path> rootDirIterator(AbstractJrtPath jrtPath) throws IOException {
295 initRootChildren(jrtPath);
296 return nodesToIterator(jrtPath, rootChildren);
297 }
298
299 private List<Node> modulesChildren;
300
301 private synchronized void initModulesChildren(AbstractJrtPath jrtPath) throws IOException {
302 if (modulesChildren == null) {
303 modulesChildren = new ArrayList<>();
304 modulesChildren.addAll(findNode(jrtPath).getChildren());
305 }
306 }
307
308 private Iterator<Path> modulesDirIterator(AbstractJrtPath jrtPath) throws IOException {
309 initModulesChildren(jrtPath);
310 return nodesToIterator(jrtPath, modulesChildren);
311 }
312
313 private List<Node> packagesChildren;
314
315 private synchronized void initPackagesChildren(AbstractJrtPath jrtPath) throws IOException {
316 if (packagesChildren == null) {
317 packagesChildren = new ArrayList<>();
318 packagesChildren.addAll(findNode(jrtPath).getChildren());
319 }
320 }
321
322 private Iterator<Path> packagesDirIterator(AbstractJrtPath jrtPath) throws IOException {
323 initPackagesChildren(jrtPath);
324 return nodesToIterator(jrtPath, packagesChildren);
325 }
326 }
|