Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/unix/classes/java/io/UnixFileSystem.java
41134 views
1
/*
2
* Copyright (c) 1998, 2021, 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 java.io;
27
28
import java.util.Properties;
29
30
import jdk.internal.util.StaticProperty;
31
import sun.security.action.GetPropertyAction;
32
33
34
class UnixFileSystem extends FileSystem {
35
36
private final char slash;
37
private final char colon;
38
private final String javaHome;
39
private final String userDir;
40
41
public UnixFileSystem() {
42
Properties props = GetPropertyAction.privilegedGetProperties();
43
slash = props.getProperty("file.separator").charAt(0);
44
colon = props.getProperty("path.separator").charAt(0);
45
javaHome = StaticProperty.javaHome();
46
userDir = StaticProperty.userDir();
47
cache = useCanonCaches ? new ExpiringCache() : null;
48
javaHomePrefixCache = useCanonPrefixCache ? new ExpiringCache() : null;
49
}
50
51
52
/* -- Normalization and construction -- */
53
54
@Override
55
public char getSeparator() {
56
return slash;
57
}
58
59
@Override
60
public char getPathSeparator() {
61
return colon;
62
}
63
64
/* A normal Unix pathname contains no duplicate slashes and does not end
65
with a slash. It may be the empty string. */
66
67
/**
68
* Normalize the given pathname, starting at the given
69
* offset; everything before off is already normal, and there's at least
70
* one duplicate or trailing slash to be removed
71
*/
72
private String normalize(String pathname, int off) {
73
int n = pathname.length();
74
while ((n > off) && (pathname.charAt(n - 1) == '/')) n--;
75
if (n == 0) return "/";
76
if (n == off) return pathname.substring(0, off);
77
78
StringBuilder sb = new StringBuilder(n);
79
if (off > 0) sb.append(pathname, 0, off);
80
char prevChar = 0;
81
for (int i = off; i < n; i++) {
82
char c = pathname.charAt(i);
83
if ((prevChar == '/') && (c == '/')) continue;
84
sb.append(c);
85
prevChar = c;
86
}
87
return sb.toString();
88
}
89
90
/* Check that the given pathname is normal. If not, invoke the real
91
normalizer on the part of the pathname that requires normalization.
92
This way we iterate through the whole pathname string only once. */
93
@Override
94
public String normalize(String pathname) {
95
int doubleSlash = pathname.indexOf("//");
96
if (doubleSlash >= 0) {
97
return normalize(pathname, doubleSlash);
98
}
99
if (pathname.endsWith("/")) {
100
return normalize(pathname, pathname.length() - 1);
101
}
102
return pathname;
103
}
104
105
@Override
106
public int prefixLength(String pathname) {
107
return pathname.startsWith("/") ? 1 : 0;
108
}
109
110
@Override
111
public String resolve(String parent, String child) {
112
if (child.isEmpty()) return parent;
113
if (child.charAt(0) == '/') {
114
if (parent.equals("/")) return child;
115
return parent + child;
116
}
117
if (parent.equals("/")) return parent + child;
118
return parent + '/' + child;
119
}
120
121
@Override
122
public String getDefaultParent() {
123
return "/";
124
}
125
126
@Override
127
public String fromURIPath(String path) {
128
String p = path;
129
if (p.endsWith("/") && (p.length() > 1)) {
130
// "/foo/" --> "/foo", but "/" --> "/"
131
p = p.substring(0, p.length() - 1);
132
}
133
return p;
134
}
135
136
137
/* -- Path operations -- */
138
139
@Override
140
public boolean isAbsolute(File f) {
141
return (f.getPrefixLength() != 0);
142
}
143
144
@Override
145
public String resolve(File f) {
146
if (isAbsolute(f)) return f.getPath();
147
@SuppressWarnings("removal")
148
SecurityManager sm = System.getSecurityManager();
149
if (sm != null) {
150
sm.checkPropertyAccess("user.dir");
151
}
152
return resolve(userDir, f.getPath());
153
}
154
155
// Caches for canonicalization results to improve startup performance.
156
// The first cache handles repeated canonicalizations of the same path
157
// name. The prefix cache handles repeated canonicalizations within the
158
// same directory, and must not create results differing from the true
159
// canonicalization algorithm in canonicalize_md.c. For this reason the
160
// prefix cache is conservative and is not used for complex path names.
161
private final ExpiringCache cache;
162
// On Unix symlinks can jump anywhere in the file system, so we only
163
// treat prefixes in java.home as trusted and cacheable in the
164
// canonicalization algorithm
165
private final ExpiringCache javaHomePrefixCache;
166
167
@Override
168
public String canonicalize(String path) throws IOException {
169
if (!useCanonCaches) {
170
return canonicalize0(path);
171
} else {
172
String res = cache.get(path);
173
if (res == null) {
174
String dir = null;
175
String resDir;
176
if (useCanonPrefixCache) {
177
// Note that this can cause symlinks that should
178
// be resolved to a destination directory to be
179
// resolved to the directory they're contained in
180
dir = parentOrNull(path);
181
if (dir != null) {
182
resDir = javaHomePrefixCache.get(dir);
183
if (resDir != null) {
184
// Hit only in prefix cache; full path is canonical
185
String filename = path.substring(1 + dir.length());
186
res = resDir + slash + filename;
187
cache.put(dir + slash + filename, res);
188
}
189
}
190
}
191
if (res == null) {
192
res = canonicalize0(path);
193
cache.put(path, res);
194
if (useCanonPrefixCache &&
195
dir != null && dir.startsWith(javaHome)) {
196
resDir = parentOrNull(res);
197
// Note that we don't allow a resolved symlink
198
// to elsewhere in java.home to pollute the
199
// prefix cache (java.home prefix cache could
200
// just as easily be a set at this point)
201
if (resDir != null && resDir.equals(dir)) {
202
File f = new File(res);
203
if (f.exists() && !f.isDirectory()) {
204
javaHomePrefixCache.put(dir, resDir);
205
}
206
}
207
}
208
}
209
}
210
return res;
211
}
212
}
213
private native String canonicalize0(String path) throws IOException;
214
// Best-effort attempt to get parent of this path; used for
215
// optimization of filename canonicalization. This must return null for
216
// any cases where the code in canonicalize_md.c would throw an
217
// exception or otherwise deal with non-simple pathnames like handling
218
// of "." and "..". It may conservatively return null in other
219
// situations as well. Returning null will cause the underlying
220
// (expensive) canonicalization routine to be called.
221
static String parentOrNull(String path) {
222
if (path == null) return null;
223
char sep = File.separatorChar;
224
int last = path.length() - 1;
225
int idx = last;
226
int adjacentDots = 0;
227
int nonDotCount = 0;
228
while (idx > 0) {
229
char c = path.charAt(idx);
230
if (c == '.') {
231
if (++adjacentDots >= 2) {
232
// Punt on pathnames containing . and ..
233
return null;
234
}
235
} else if (c == sep) {
236
if (adjacentDots == 1 && nonDotCount == 0) {
237
// Punt on pathnames containing . and ..
238
return null;
239
}
240
if (idx == 0 ||
241
idx >= last - 1 ||
242
path.charAt(idx - 1) == sep) {
243
// Punt on pathnames containing adjacent slashes
244
// toward the end
245
return null;
246
}
247
return path.substring(0, idx);
248
} else {
249
++nonDotCount;
250
adjacentDots = 0;
251
}
252
--idx;
253
}
254
return null;
255
}
256
257
/* -- Attribute accessors -- */
258
259
public native int getBooleanAttributes0(File f);
260
261
@Override
262
public int getBooleanAttributes(File f) {
263
int rv = getBooleanAttributes0(f);
264
return rv | isHidden(f);
265
}
266
267
@Override
268
public boolean hasBooleanAttributes(File f, int attributes) {
269
int rv = getBooleanAttributes0(f);
270
if ((attributes & BA_HIDDEN) != 0) {
271
rv |= isHidden(f);
272
}
273
return (rv & attributes) == attributes;
274
}
275
276
private static int isHidden(File f) {
277
return f.getName().startsWith(".") ? BA_HIDDEN : 0;
278
}
279
280
@Override
281
public native boolean checkAccess(File f, int access);
282
283
@Override
284
public native long getLastModifiedTime(File f);
285
286
@Override
287
public native long getLength(File f);
288
289
@Override
290
public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);
291
292
/* -- File operations -- */
293
294
@Override
295
public native boolean createFileExclusively(String path)
296
throws IOException;
297
298
@Override
299
public boolean delete(File f) {
300
// Keep canonicalization caches in sync after file deletion
301
// and renaming operations. Could be more clever than this
302
// (i.e., only remove/update affected entries) but probably
303
// not worth it since these entries expire after 30 seconds
304
// anyway.
305
if (useCanonCaches) {
306
cache.clear();
307
}
308
if (useCanonPrefixCache) {
309
javaHomePrefixCache.clear();
310
}
311
return delete0(f);
312
}
313
private native boolean delete0(File f);
314
315
@Override
316
public native String[] list(File f);
317
318
@Override
319
public native boolean createDirectory(File f);
320
321
@Override
322
public boolean rename(File f1, File f2) {
323
// Keep canonicalization caches in sync after file deletion
324
// and renaming operations. Could be more clever than this
325
// (i.e., only remove/update affected entries) but probably
326
// not worth it since these entries expire after 30 seconds
327
// anyway.
328
if (useCanonCaches) {
329
cache.clear();
330
}
331
if (useCanonPrefixCache) {
332
javaHomePrefixCache.clear();
333
}
334
return rename0(f1, f2);
335
}
336
private native boolean rename0(File f1, File f2);
337
338
@Override
339
public native boolean setLastModifiedTime(File f, long time);
340
341
@Override
342
public native boolean setReadOnly(File f);
343
344
/* -- Filesystem interface -- */
345
346
@Override
347
public File[] listRoots() {
348
try {
349
@SuppressWarnings("removal")
350
SecurityManager security = System.getSecurityManager();
351
if (security != null) {
352
security.checkRead("/");
353
}
354
return new File[] { new File("/") };
355
} catch (SecurityException x) {
356
return new File[0];
357
}
358
}
359
360
/* -- Disk usage -- */
361
362
@Override
363
public native long getSpace(File f, int t);
364
365
/* -- Basic infrastructure -- */
366
367
private native long getNameMax0(String path);
368
369
@Override
370
public int getNameMax(String path) {
371
long nameMax = getNameMax0(path);
372
if (nameMax > Integer.MAX_VALUE) {
373
nameMax = Integer.MAX_VALUE;
374
}
375
return (int)nameMax;
376
}
377
378
@Override
379
public int compare(File f1, File f2) {
380
return f1.getPath().compareTo(f2.getPath());
381
}
382
383
@Override
384
public int hashCode(File f) {
385
return f.getPath().hashCode() ^ 1234321;
386
}
387
388
389
private static native void initIDs();
390
391
static {
392
initIDs();
393
}
394
}
395
396