Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/provider/FileInputStreamPool.java
41159 views
1
/*
2
* Copyright (c) 2014, 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
26
package sun.security.provider;
27
28
import java.io.*;
29
import java.lang.ref.ReferenceQueue;
30
import java.lang.ref.WeakReference;
31
import java.util.concurrent.ConcurrentHashMap;
32
import java.util.concurrent.ConcurrentMap;
33
34
/**
35
* A pool of {@code InputStream}s opened from distinct files. Only a single
36
* instance is ever opened from the same file. This is used to read special
37
* infinite files like {@code /dev/random} where the current file pointer is not
38
* relevant, so multiple readers can share the same file descriptor and
39
* consequently the same {@code InputStream}.
40
*/
41
class FileInputStreamPool {
42
43
/**
44
* a pool of: StreamRef -> UnclosableInputStream -> FileInputStream(s)
45
*/
46
private static final ConcurrentMap<File, StreamRef> pool =
47
new ConcurrentHashMap<>();
48
49
/**
50
* a reference queue of cleared StreamRef(s)
51
*/
52
private static final ReferenceQueue<UnclosableInputStream> refQueue =
53
new ReferenceQueue<>();
54
55
/**
56
* This method opens an underlying {@link java.io.FileInputStream} for a
57
* given {@code file} and returns a wrapper over it. The wrapper is shared
58
* among multiple readers of the same {@code file} and ignores
59
* {@link java.io.InputStream#close()} requests. The underlying stream is
60
* closed when all references to the wrapper are relinquished.
61
*
62
* @param file the file to be opened for reading.
63
* @return a shared {@link java.io.InputStream} instance opened from given
64
* file.
65
* @throws FileNotFoundException if the file does not exist, is a directory
66
* rather than a regular file, or for some
67
* other reason cannot be opened for reading.
68
* @throws SecurityException if a security manager exists and its
69
* <code>checkRead</code> method denies read
70
* access to the file.
71
*/
72
static InputStream getInputStream(File file) throws IOException {
73
74
// expunge any cleared references
75
StreamRef oldRref;
76
while ((oldRref = (StreamRef) refQueue.poll()) != null) {
77
pool.remove(oldRref.file, oldRref);
78
}
79
80
// canonicalize the path
81
// (this also checks the read permission on the file if SecurityManager
82
// is present, so no checking is needed later when we just return the
83
// already opened stream)
84
File cfile = file.getCanonicalFile();
85
86
// check if it exists in pool
87
oldRref = pool.get(cfile);
88
UnclosableInputStream oldStream = (oldRref == null)
89
? null
90
: oldRref.get();
91
StreamRef newRef = null;
92
UnclosableInputStream newStream = null;
93
94
// retry loop
95
while (true) {
96
if (oldStream != null) {
97
// close our optimistically opened stream 1st (if we opened it)
98
if (newStream != null) {
99
try {
100
newStream.getWrappedStream().close();
101
} catch (IOException ignore) {
102
// can't do anything here
103
}
104
}
105
// return it
106
return oldStream;
107
} else {
108
// we need to open new stream optimistically (if not already)
109
if (newStream == null) {
110
newStream = new UnclosableInputStream(
111
new FileInputStream(cfile));
112
newRef = new StreamRef(cfile, newStream, refQueue);
113
}
114
// either try to install newRef or replace oldRef with newRef
115
if (oldRref == null) {
116
oldRref = pool.putIfAbsent(cfile, newRef);
117
} else {
118
oldRref = pool.replace(cfile, oldRref, newRef)
119
? null
120
: pool.get(cfile);
121
}
122
if (oldRref == null) {
123
// success
124
return newStream;
125
} else {
126
// lost race
127
oldStream = oldRref.get();
128
// another loop
129
}
130
}
131
}
132
}
133
134
private static class StreamRef extends WeakReference<UnclosableInputStream> {
135
final File file;
136
137
StreamRef(File file,
138
UnclosableInputStream stream,
139
ReferenceQueue<UnclosableInputStream> refQueue) {
140
super(stream, refQueue);
141
this.file = file;
142
}
143
}
144
145
private static final class UnclosableInputStream extends FilterInputStream {
146
UnclosableInputStream(InputStream in) {
147
super(in);
148
}
149
150
@Override
151
public void close() throws IOException {
152
// Ignore close attempts since underlying InputStream is shared.
153
}
154
155
InputStream getWrappedStream() {
156
return in;
157
}
158
}
159
}
160
161