Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java
41159 views
1
/*
2
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
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.ByteArrayInputStream;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.OutputStream;
31
import java.nio.ByteBuffer;
32
import java.nio.channels.Channels;
33
import java.nio.channels.FileChannel;
34
import java.nio.channels.NonWritableChannelException;
35
import java.nio.channels.ReadableByteChannel;
36
import java.nio.channels.SeekableByteChannel;
37
import java.nio.file.ClosedFileSystemException;
38
import java.nio.file.CopyOption;
39
import java.nio.file.DirectoryStream;
40
import java.nio.file.FileStore;
41
import java.nio.file.FileSystem;
42
import java.nio.file.FileSystemException;
43
import java.nio.file.InvalidPathException;
44
import java.nio.file.LinkOption;
45
import java.nio.file.NoSuchFileException;
46
import java.nio.file.NotDirectoryException;
47
import java.nio.file.OpenOption;
48
import java.nio.file.Path;
49
import java.nio.file.PathMatcher;
50
import java.nio.file.ReadOnlyFileSystemException;
51
import java.nio.file.StandardOpenOption;
52
import java.nio.file.WatchService;
53
import java.nio.file.attribute.FileAttribute;
54
import java.nio.file.attribute.FileTime;
55
import java.nio.file.attribute.UserPrincipalLookupService;
56
import java.nio.file.spi.FileSystemProvider;
57
import java.util.ArrayList;
58
import java.util.Arrays;
59
import java.util.Collections;
60
import java.util.HashSet;
61
import java.util.Iterator;
62
import java.util.Map;
63
import java.util.Objects;
64
import java.util.Set;
65
import java.util.regex.Pattern;
66
import jdk.internal.jimage.ImageReader.Node;
67
import static java.util.stream.Collectors.toList;
68
69
/**
70
* jrt file system implementation built on System jimage files.
71
*
72
* @implNote This class needs to maintain JDK 8 source compatibility.
73
*
74
* It is used internally in the JDK to implement jimage/jrtfs access,
75
* but also compiled and delivered as part of the jrtfs.jar to support access
76
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
77
*/
78
class JrtFileSystem extends FileSystem {
79
80
private final JrtFileSystemProvider provider;
81
private final JrtPath rootPath = new JrtPath(this, "/");
82
private volatile boolean isOpen;
83
private volatile boolean isClosable;
84
private SystemImage image;
85
86
JrtFileSystem(JrtFileSystemProvider provider, Map<String, ?> env)
87
throws IOException
88
{
89
this.provider = provider;
90
this.image = SystemImage.open(); // open image file
91
this.isOpen = true;
92
this.isClosable = env != null;
93
}
94
95
// FileSystem method implementations
96
@Override
97
public boolean isOpen() {
98
return isOpen;
99
}
100
101
@Override
102
public void close() throws IOException {
103
if (!isClosable)
104
throw new UnsupportedOperationException();
105
cleanup();
106
}
107
108
@Override
109
public FileSystemProvider provider() {
110
return provider;
111
}
112
113
@Override
114
public Iterable<Path> getRootDirectories() {
115
return Collections.singleton(getRootPath());
116
}
117
118
@Override
119
public JrtPath getPath(String first, String... more) {
120
if (more.length == 0) {
121
return new JrtPath(this, first);
122
}
123
StringBuilder sb = new StringBuilder();
124
sb.append(first);
125
for (String path : more) {
126
if (!path.isEmpty()) {
127
if (sb.length() > 0) {
128
sb.append('/');
129
}
130
sb.append(path);
131
}
132
}
133
return new JrtPath(this, sb.toString());
134
}
135
136
@Override
137
public final boolean isReadOnly() {
138
return true;
139
}
140
141
@Override
142
public final UserPrincipalLookupService getUserPrincipalLookupService() {
143
throw new UnsupportedOperationException();
144
}
145
146
@Override
147
public final WatchService newWatchService() {
148
throw new UnsupportedOperationException();
149
}
150
151
@Override
152
public final Iterable<FileStore> getFileStores() {
153
return Collections.singleton(getFileStore(getRootPath()));
154
}
155
156
private static final Set<String> supportedFileAttributeViews
157
= Collections.unmodifiableSet(
158
new HashSet<String>(Arrays.asList("basic", "jrt")));
159
160
@Override
161
public final Set<String> supportedFileAttributeViews() {
162
return supportedFileAttributeViews;
163
}
164
165
@Override
166
public final String toString() {
167
return "jrt:/";
168
}
169
170
@Override
171
public final String getSeparator() {
172
return "/";
173
}
174
175
@Override
176
public PathMatcher getPathMatcher(String syntaxAndInput) {
177
int pos = syntaxAndInput.indexOf(':');
178
if (pos <= 0 || pos == syntaxAndInput.length()) {
179
throw new IllegalArgumentException("pos is " + pos);
180
}
181
String syntax = syntaxAndInput.substring(0, pos);
182
String input = syntaxAndInput.substring(pos + 1);
183
String expr;
184
if (syntax.equalsIgnoreCase("glob")) {
185
expr = JrtUtils.toRegexPattern(input);
186
} else if (syntax.equalsIgnoreCase("regex")) {
187
expr = input;
188
} else {
189
throw new UnsupportedOperationException("Syntax '" + syntax
190
+ "' not recognized");
191
}
192
// return matcher
193
final Pattern pattern = Pattern.compile(expr);
194
return (Path path) -> pattern.matcher(path.toString()).matches();
195
}
196
197
JrtPath resolveLink(JrtPath path) throws IOException {
198
Node node = checkNode(path);
199
if (node.isLink()) {
200
node = node.resolveLink();
201
return new JrtPath(this, node.getName()); // TBD, normalized?
202
}
203
return path;
204
}
205
206
JrtFileAttributes getFileAttributes(JrtPath path, LinkOption... options)
207
throws IOException {
208
Node node = checkNode(path);
209
if (node.isLink() && followLinks(options)) {
210
return new JrtFileAttributes(node.resolveLink(true));
211
}
212
return new JrtFileAttributes(node);
213
}
214
215
/**
216
* returns the list of child paths of the given directory "path"
217
*
218
* @param path name of the directory whose content is listed
219
* @return iterator for child paths of the given directory path
220
*/
221
Iterator<Path> iteratorOf(JrtPath path, DirectoryStream.Filter<? super Path> filter)
222
throws IOException {
223
Node node = checkNode(path).resolveLink(true);
224
if (!node.isDirectory()) {
225
throw new NotDirectoryException(path.getName());
226
}
227
if (filter == null) {
228
return node.getChildren()
229
.stream()
230
.map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName())))
231
.iterator();
232
}
233
return node.getChildren()
234
.stream()
235
.map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName())))
236
.filter(p -> { try { return filter.accept(p);
237
} catch (IOException x) {}
238
return false;
239
})
240
.iterator();
241
}
242
243
// returns the content of the file resource specified by the path
244
byte[] getFileContent(JrtPath path) throws IOException {
245
Node node = checkNode(path);
246
if (node.isDirectory()) {
247
throw new FileSystemException(path + " is a directory");
248
}
249
//assert node.isResource() : "resource node expected here";
250
return image.getResource(node);
251
}
252
253
/////////////// Implementation details below this point //////////
254
255
// static utility methods
256
static ReadOnlyFileSystemException readOnly() {
257
return new ReadOnlyFileSystemException();
258
}
259
260
// do the supplied options imply that we have to chase symlinks?
261
static boolean followLinks(LinkOption... options) {
262
if (options != null) {
263
for (LinkOption lo : options) {
264
Objects.requireNonNull(lo);
265
if (lo == LinkOption.NOFOLLOW_LINKS) {
266
return false;
267
} else {
268
throw new AssertionError("should not reach here");
269
}
270
}
271
}
272
return true;
273
}
274
275
// check that the options passed are supported by (read-only) jrt file system
276
static void checkOptions(Set<? extends OpenOption> options) {
277
// check for options of null type and option is an intance of StandardOpenOption
278
for (OpenOption option : options) {
279
Objects.requireNonNull(option);
280
if (!(option instanceof StandardOpenOption)) {
281
throw new IllegalArgumentException(
282
"option class: " + option.getClass());
283
}
284
}
285
if (options.contains(StandardOpenOption.WRITE) ||
286
options.contains(StandardOpenOption.APPEND)) {
287
throw readOnly();
288
}
289
}
290
291
// clean up this file system - called from finalize and close
292
synchronized void cleanup() throws IOException {
293
if (isOpen) {
294
isOpen = false;
295
image.close();
296
image = null;
297
}
298
}
299
300
// These methods throw read only file system exception
301
final void setTimes(JrtPath jrtPath, FileTime mtime, FileTime atime, FileTime ctime)
302
throws IOException {
303
throw readOnly();
304
}
305
306
// These methods throw read only file system exception
307
final void createDirectory(JrtPath jrtPath, FileAttribute<?>... attrs) throws IOException {
308
throw readOnly();
309
}
310
311
final void deleteFile(JrtPath jrtPath, boolean failIfNotExists)
312
throws IOException {
313
throw readOnly();
314
}
315
316
final OutputStream newOutputStream(JrtPath jrtPath, OpenOption... options)
317
throws IOException {
318
throw readOnly();
319
}
320
321
final void copyFile(boolean deletesrc, JrtPath srcPath, JrtPath dstPath, CopyOption... options)
322
throws IOException {
323
throw readOnly();
324
}
325
326
final FileChannel newFileChannel(JrtPath path,
327
Set<? extends OpenOption> options,
328
FileAttribute<?>... attrs)
329
throws IOException {
330
throw new UnsupportedOperationException("newFileChannel");
331
}
332
333
final InputStream newInputStream(JrtPath path) throws IOException {
334
return new ByteArrayInputStream(getFileContent(path));
335
}
336
337
final SeekableByteChannel newByteChannel(JrtPath path,
338
Set<? extends OpenOption> options,
339
FileAttribute<?>... attrs)
340
throws IOException {
341
checkOptions(options);
342
343
byte[] buf = getFileContent(path);
344
final ReadableByteChannel rbc
345
= Channels.newChannel(new ByteArrayInputStream(buf));
346
final long size = buf.length;
347
return new SeekableByteChannel() {
348
long read = 0;
349
350
@Override
351
public boolean isOpen() {
352
return rbc.isOpen();
353
}
354
355
@Override
356
public long position() throws IOException {
357
return read;
358
}
359
360
@Override
361
public SeekableByteChannel position(long pos)
362
throws IOException {
363
throw new UnsupportedOperationException();
364
}
365
366
@Override
367
public int read(ByteBuffer dst) throws IOException {
368
int n = rbc.read(dst);
369
if (n > 0) {
370
read += n;
371
}
372
return n;
373
}
374
375
@Override
376
public SeekableByteChannel truncate(long size)
377
throws IOException {
378
throw new NonWritableChannelException();
379
}
380
381
@Override
382
public int write(ByteBuffer src) throws IOException {
383
throw new NonWritableChannelException();
384
}
385
386
@Override
387
public long size() throws IOException {
388
return size;
389
}
390
391
@Override
392
public void close() throws IOException {
393
rbc.close();
394
}
395
};
396
}
397
398
final JrtFileStore getFileStore(JrtPath path) {
399
return new JrtFileStore(path);
400
}
401
402
final void ensureOpen() throws IOException {
403
if (!isOpen()) {
404
throw new ClosedFileSystemException();
405
}
406
}
407
408
final JrtPath getRootPath() {
409
return rootPath;
410
}
411
412
boolean isSameFile(JrtPath path1, JrtPath path2) throws IOException {
413
return checkNode(path1) == checkNode(path2);
414
}
415
416
boolean isLink(JrtPath path) throws IOException {
417
return checkNode(path).isLink();
418
}
419
420
boolean exists(JrtPath path) throws IOException {
421
try {
422
checkNode(path);
423
} catch (NoSuchFileException exp) {
424
return false;
425
}
426
return true;
427
}
428
429
boolean isDirectory(JrtPath path, boolean resolveLinks)
430
throws IOException {
431
Node node = checkNode(path);
432
return resolveLinks && node.isLink()
433
? node.resolveLink(true).isDirectory()
434
: node.isDirectory();
435
}
436
437
JrtPath toRealPath(JrtPath path, LinkOption... options)
438
throws IOException {
439
Node node = checkNode(path);
440
if (followLinks(options) && node.isLink()) {
441
node = node.resolveLink();
442
}
443
// image node holds the real/absolute path name
444
return new JrtPath(this, node.getName(), true);
445
}
446
447
private Node lookup(String path) {
448
try {
449
return image.findNode(path);
450
} catch (RuntimeException | IOException ex) {
451
throw new InvalidPathException(path, ex.toString());
452
}
453
}
454
455
private Node lookupSymbolic(String path) {
456
int i = 1;
457
while (i < path.length()) {
458
i = path.indexOf('/', i);
459
if (i == -1) {
460
break;
461
}
462
String prefix = path.substring(0, i);
463
Node node = lookup(prefix);
464
if (node == null) {
465
break;
466
}
467
if (node.isLink()) {
468
Node link = node.resolveLink(true);
469
// resolved symbolic path concatenated to the rest of the path
470
String resPath = link.getName() + path.substring(i);
471
node = lookup(resPath);
472
return node != null ? node : lookupSymbolic(resPath);
473
}
474
i++;
475
}
476
return null;
477
}
478
479
Node checkNode(JrtPath path) throws IOException {
480
ensureOpen();
481
String p = path.getResolvedPath();
482
Node node = lookup(p);
483
if (node == null) {
484
node = lookupSymbolic(p);
485
if (node == null) {
486
throw new NoSuchFileException(p);
487
}
488
}
489
return node;
490
}
491
}
492
493