Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.base/unix/classes/java/io/UnixFileSystem.java
67849 views
1
/*
2
* Copyright (c) 1998, 2022, 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 boolean isInvalid(File f) {
146
return f.getPath().indexOf('\u0000') < 0 ? false : true;
147
}
148
149
@Override
150
public String resolve(File f) {
151
if (isAbsolute(f)) return f.getPath();
152
@SuppressWarnings("removal")
153
SecurityManager sm = System.getSecurityManager();
154
if (sm != null) {
155
sm.checkPropertyAccess("user.dir");
156
}
157
return resolve(userDir, f.getPath());
158
}
159
160
// Caches for canonicalization results to improve startup performance.
161
// The first cache handles repeated canonicalizations of the same path
162
// name. The prefix cache handles repeated canonicalizations within the
163
// same directory, and must not create results differing from the true
164
// canonicalization algorithm in canonicalize_md.c. For this reason the
165
// prefix cache is conservative and is not used for complex path names.
166
private final ExpiringCache cache;
167
// On Unix symlinks can jump anywhere in the file system, so we only
168
// treat prefixes in java.home as trusted and cacheable in the
169
// canonicalization algorithm
170
private final ExpiringCache javaHomePrefixCache;
171
172
@Override
173
public String canonicalize(String path) throws IOException {
174
if (!useCanonCaches) {
175
return canonicalize0(path);
176
} else {
177
String res = cache.get(path);
178
if (res == null) {
179
String dir = null;
180
String resDir;
181
if (useCanonPrefixCache) {
182
// Note that this can cause symlinks that should
183
// be resolved to a destination directory to be
184
// resolved to the directory they're contained in
185
dir = parentOrNull(path);
186
if (dir != null) {
187
resDir = javaHomePrefixCache.get(dir);
188
if (resDir != null) {
189
// Hit only in prefix cache; full path is canonical
190
String filename = path.substring(1 + dir.length());
191
res = resDir + slash + filename;
192
cache.put(dir + slash + filename, res);
193
}
194
}
195
}
196
if (res == null) {
197
res = canonicalize0(path);
198
cache.put(path, res);
199
if (useCanonPrefixCache &&
200
dir != null && dir.startsWith(javaHome)) {
201
resDir = parentOrNull(res);
202
// Note that we don't allow a resolved symlink
203
// to elsewhere in java.home to pollute the
204
// prefix cache (java.home prefix cache could
205
// just as easily be a set at this point)
206
if (resDir != null && resDir.equals(dir)) {
207
File f = new File(res);
208
if (f.exists() && !f.isDirectory()) {
209
javaHomePrefixCache.put(dir, resDir);
210
}
211
}
212
}
213
}
214
}
215
return res;
216
}
217
}
218
private native String canonicalize0(String path) throws IOException;
219
// Best-effort attempt to get parent of this path; used for
220
// optimization of filename canonicalization. This must return null for
221
// any cases where the code in canonicalize_md.c would throw an
222
// exception or otherwise deal with non-simple pathnames like handling
223
// of "." and "..". It may conservatively return null in other
224
// situations as well. Returning null will cause the underlying
225
// (expensive) canonicalization routine to be called.
226
static String parentOrNull(String path) {
227
if (path == null) return null;
228
char sep = File.separatorChar;
229
int last = path.length() - 1;
230
int idx = last;
231
int adjacentDots = 0;
232
int nonDotCount = 0;
233
while (idx > 0) {
234
char c = path.charAt(idx);
235
if (c == '.') {
236
if (++adjacentDots >= 2) {
237
// Punt on pathnames containing . and ..
238
return null;
239
}
240
} else if (c == sep) {
241
if (adjacentDots == 1 && nonDotCount == 0) {
242
// Punt on pathnames containing . and ..
243
return null;
244
}
245
if (idx == 0 ||
246
idx >= last - 1 ||
247
path.charAt(idx - 1) == sep) {
248
// Punt on pathnames containing adjacent slashes
249
// toward the end
250
return null;
251
}
252
return path.substring(0, idx);
253
} else {
254
++nonDotCount;
255
adjacentDots = 0;
256
}
257
--idx;
258
}
259
return null;
260
}
261
262
/* -- Attribute accessors -- */
263
264
public native int getBooleanAttributes0(File f);
265
266
@Override
267
public int getBooleanAttributes(File f) {
268
int rv = getBooleanAttributes0(f);
269
return rv | isHidden(f);
270
}
271
272
@Override
273
public boolean hasBooleanAttributes(File f, int attributes) {
274
int rv = getBooleanAttributes0(f);
275
if ((attributes & BA_HIDDEN) != 0) {
276
rv |= isHidden(f);
277
}
278
return (rv & attributes) == attributes;
279
}
280
281
private static int isHidden(File f) {
282
return f.getName().startsWith(".") ? BA_HIDDEN : 0;
283
}
284
285
@Override
286
public native boolean checkAccess(File f, int access);
287
288
@Override
289
public native long getLastModifiedTime(File f);
290
291
@Override
292
public native long getLength(File f);
293
294
@Override
295
public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);
296
297
/* -- File operations -- */
298
299
@Override
300
public native boolean createFileExclusively(String path)
301
throws IOException;
302
303
@Override
304
public boolean delete(File f) {
305
// Keep canonicalization caches in sync after file deletion
306
// and renaming operations. Could be more clever than this
307
// (i.e., only remove/update affected entries) but probably
308
// not worth it since these entries expire after 30 seconds
309
// anyway.
310
if (useCanonCaches) {
311
cache.clear();
312
}
313
if (useCanonPrefixCache) {
314
javaHomePrefixCache.clear();
315
}
316
return delete0(f);
317
}
318
private native boolean delete0(File f);
319
320
@Override
321
public native String[] list(File f);
322
323
@Override
324
public native boolean createDirectory(File f);
325
326
@Override
327
public boolean rename(File f1, File f2) {
328
// Keep canonicalization caches in sync after file deletion
329
// and renaming operations. Could be more clever than this
330
// (i.e., only remove/update affected entries) but probably
331
// not worth it since these entries expire after 30 seconds
332
// anyway.
333
if (useCanonCaches) {
334
cache.clear();
335
}
336
if (useCanonPrefixCache) {
337
javaHomePrefixCache.clear();
338
}
339
return rename0(f1, f2);
340
}
341
private native boolean rename0(File f1, File f2);
342
343
@Override
344
public native boolean setLastModifiedTime(File f, long time);
345
346
@Override
347
public native boolean setReadOnly(File f);
348
349
/* -- Filesystem interface -- */
350
351
@Override
352
public File[] listRoots() {
353
try {
354
@SuppressWarnings("removal")
355
SecurityManager security = System.getSecurityManager();
356
if (security != null) {
357
security.checkRead("/");
358
}
359
return new File[] { new File("/") };
360
} catch (SecurityException x) {
361
return new File[0];
362
}
363
}
364
365
/* -- Disk usage -- */
366
367
@Override
368
public native long getSpace(File f, int t);
369
370
/* -- Basic infrastructure -- */
371
372
private native long getNameMax0(String path);
373
374
@Override
375
public int getNameMax(String path) {
376
long nameMax = getNameMax0(path);
377
if (nameMax > Integer.MAX_VALUE) {
378
nameMax = Integer.MAX_VALUE;
379
}
380
return (int)nameMax;
381
}
382
383
@Override
384
public int compare(File f1, File f2) {
385
return f1.getPath().compareTo(f2.getPath());
386
}
387
388
@Override
389
public int hashCode(File f) {
390
return f.getPath().hashCode() ^ 1234321;
391
}
392
393
394
private static native void initIDs();
395
396
static {
397
initIDs();
398
}
399
}
400
401