2
|
1 |
/*
|
5506
|
2 |
* Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
|
2
|
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
|
5506
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
2
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
5506
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
2
|
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 |
*
|
5506
|
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.
|
2
|
24 |
*/
|
|
25 |
|
|
26 |
package java.io;
|
|
27 |
|
|
28 |
import java.security.AccessController;
|
|
29 |
import sun.security.action.GetPropertyAction;
|
|
30 |
|
|
31 |
|
|
32 |
class UnixFileSystem extends FileSystem {
|
|
33 |
|
|
34 |
private final char slash;
|
|
35 |
private final char colon;
|
|
36 |
private final String javaHome;
|
|
37 |
|
|
38 |
public UnixFileSystem() {
|
|
39 |
slash = AccessController.doPrivileged(
|
|
40 |
new GetPropertyAction("file.separator")).charAt(0);
|
|
41 |
colon = AccessController.doPrivileged(
|
|
42 |
new GetPropertyAction("path.separator")).charAt(0);
|
|
43 |
javaHome = AccessController.doPrivileged(
|
|
44 |
new GetPropertyAction("java.home"));
|
|
45 |
}
|
|
46 |
|
|
47 |
|
|
48 |
/* -- Normalization and construction -- */
|
|
49 |
|
|
50 |
public char getSeparator() {
|
|
51 |
return slash;
|
|
52 |
}
|
|
53 |
|
|
54 |
public char getPathSeparator() {
|
|
55 |
return colon;
|
|
56 |
}
|
|
57 |
|
|
58 |
/* A normal Unix pathname contains no duplicate slashes and does not end
|
|
59 |
with a slash. It may be the empty string. */
|
|
60 |
|
|
61 |
/* Normalize the given pathname, whose length is len, starting at the given
|
|
62 |
offset; everything before this offset is already normal. */
|
|
63 |
private String normalize(String pathname, int len, int off) {
|
|
64 |
if (len == 0) return pathname;
|
|
65 |
int n = len;
|
|
66 |
while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;
|
|
67 |
if (n == 0) return "/";
|
|
68 |
StringBuffer sb = new StringBuffer(pathname.length());
|
|
69 |
if (off > 0) sb.append(pathname.substring(0, off));
|
|
70 |
char prevChar = 0;
|
|
71 |
for (int i = off; i < n; i++) {
|
|
72 |
char c = pathname.charAt(i);
|
|
73 |
if ((prevChar == '/') && (c == '/')) continue;
|
|
74 |
sb.append(c);
|
|
75 |
prevChar = c;
|
|
76 |
}
|
|
77 |
return sb.toString();
|
|
78 |
}
|
|
79 |
|
|
80 |
/* Check that the given pathname is normal. If not, invoke the real
|
|
81 |
normalizer on the part of the pathname that requires normalization.
|
|
82 |
This way we iterate through the whole pathname string only once. */
|
|
83 |
public String normalize(String pathname) {
|
|
84 |
int n = pathname.length();
|
|
85 |
char prevChar = 0;
|
|
86 |
for (int i = 0; i < n; i++) {
|
|
87 |
char c = pathname.charAt(i);
|
|
88 |
if ((prevChar == '/') && (c == '/'))
|
|
89 |
return normalize(pathname, n, i - 1);
|
|
90 |
prevChar = c;
|
|
91 |
}
|
|
92 |
if (prevChar == '/') return normalize(pathname, n, n - 1);
|
|
93 |
return pathname;
|
|
94 |
}
|
|
95 |
|
|
96 |
public int prefixLength(String pathname) {
|
|
97 |
if (pathname.length() == 0) return 0;
|
|
98 |
return (pathname.charAt(0) == '/') ? 1 : 0;
|
|
99 |
}
|
|
100 |
|
|
101 |
public String resolve(String parent, String child) {
|
|
102 |
if (child.equals("")) return parent;
|
|
103 |
if (child.charAt(0) == '/') {
|
|
104 |
if (parent.equals("/")) return child;
|
|
105 |
return parent + child;
|
|
106 |
}
|
|
107 |
if (parent.equals("/")) return parent + child;
|
|
108 |
return parent + '/' + child;
|
|
109 |
}
|
|
110 |
|
|
111 |
public String getDefaultParent() {
|
|
112 |
return "/";
|
|
113 |
}
|
|
114 |
|
|
115 |
public String fromURIPath(String path) {
|
|
116 |
String p = path;
|
|
117 |
if (p.endsWith("/") && (p.length() > 1)) {
|
|
118 |
// "/foo/" --> "/foo", but "/" --> "/"
|
|
119 |
p = p.substring(0, p.length() - 1);
|
|
120 |
}
|
|
121 |
return p;
|
|
122 |
}
|
|
123 |
|
|
124 |
|
|
125 |
/* -- Path operations -- */
|
|
126 |
|
|
127 |
public boolean isAbsolute(File f) {
|
|
128 |
return (f.getPrefixLength() != 0);
|
|
129 |
}
|
|
130 |
|
|
131 |
public String resolve(File f) {
|
|
132 |
if (isAbsolute(f)) return f.getPath();
|
|
133 |
return resolve(System.getProperty("user.dir"), f.getPath());
|
|
134 |
}
|
|
135 |
|
|
136 |
// Caches for canonicalization results to improve startup performance.
|
|
137 |
// The first cache handles repeated canonicalizations of the same path
|
|
138 |
// name. The prefix cache handles repeated canonicalizations within the
|
|
139 |
// same directory, and must not create results differing from the true
|
|
140 |
// canonicalization algorithm in canonicalize_md.c. For this reason the
|
|
141 |
// prefix cache is conservative and is not used for complex path names.
|
|
142 |
private ExpiringCache cache = new ExpiringCache();
|
|
143 |
// On Unix symlinks can jump anywhere in the file system, so we only
|
|
144 |
// treat prefixes in java.home as trusted and cacheable in the
|
|
145 |
// canonicalization algorithm
|
|
146 |
private ExpiringCache javaHomePrefixCache = new ExpiringCache();
|
|
147 |
|
|
148 |
public String canonicalize(String path) throws IOException {
|
|
149 |
if (!useCanonCaches) {
|
|
150 |
return canonicalize0(path);
|
|
151 |
} else {
|
|
152 |
String res = cache.get(path);
|
|
153 |
if (res == null) {
|
|
154 |
String dir = null;
|
|
155 |
String resDir = null;
|
|
156 |
if (useCanonPrefixCache) {
|
|
157 |
// Note that this can cause symlinks that should
|
|
158 |
// be resolved to a destination directory to be
|
|
159 |
// resolved to the directory they're contained in
|
|
160 |
dir = parentOrNull(path);
|
|
161 |
if (dir != null) {
|
|
162 |
resDir = javaHomePrefixCache.get(dir);
|
|
163 |
if (resDir != null) {
|
|
164 |
// Hit only in prefix cache; full path is canonical
|
|
165 |
String filename = path.substring(1 + dir.length());
|
|
166 |
res = resDir + slash + filename;
|
|
167 |
cache.put(dir + slash + filename, res);
|
|
168 |
}
|
|
169 |
}
|
|
170 |
}
|
|
171 |
if (res == null) {
|
|
172 |
res = canonicalize0(path);
|
|
173 |
cache.put(path, res);
|
|
174 |
if (useCanonPrefixCache &&
|
|
175 |
dir != null && dir.startsWith(javaHome)) {
|
|
176 |
resDir = parentOrNull(res);
|
|
177 |
// Note that we don't allow a resolved symlink
|
|
178 |
// to elsewhere in java.home to pollute the
|
|
179 |
// prefix cache (java.home prefix cache could
|
|
180 |
// just as easily be a set at this point)
|
|
181 |
if (resDir != null && resDir.equals(dir)) {
|
|
182 |
File f = new File(res);
|
|
183 |
if (f.exists() && !f.isDirectory()) {
|
|
184 |
javaHomePrefixCache.put(dir, resDir);
|
|
185 |
}
|
|
186 |
}
|
|
187 |
}
|
|
188 |
}
|
|
189 |
}
|
|
190 |
assert canonicalize0(path).equals(res) || path.startsWith(javaHome);
|
|
191 |
return res;
|
|
192 |
}
|
|
193 |
}
|
|
194 |
private native String canonicalize0(String path) throws IOException;
|
|
195 |
// Best-effort attempt to get parent of this path; used for
|
|
196 |
// optimization of filename canonicalization. This must return null for
|
|
197 |
// any cases where the code in canonicalize_md.c would throw an
|
|
198 |
// exception or otherwise deal with non-simple pathnames like handling
|
|
199 |
// of "." and "..". It may conservatively return null in other
|
|
200 |
// situations as well. Returning null will cause the underlying
|
|
201 |
// (expensive) canonicalization routine to be called.
|
|
202 |
static String parentOrNull(String path) {
|
|
203 |
if (path == null) return null;
|
|
204 |
char sep = File.separatorChar;
|
|
205 |
int last = path.length() - 1;
|
|
206 |
int idx = last;
|
|
207 |
int adjacentDots = 0;
|
|
208 |
int nonDotCount = 0;
|
|
209 |
while (idx > 0) {
|
|
210 |
char c = path.charAt(idx);
|
|
211 |
if (c == '.') {
|
|
212 |
if (++adjacentDots >= 2) {
|
|
213 |
// Punt on pathnames containing . and ..
|
|
214 |
return null;
|
|
215 |
}
|
|
216 |
} else if (c == sep) {
|
|
217 |
if (adjacentDots == 1 && nonDotCount == 0) {
|
|
218 |
// Punt on pathnames containing . and ..
|
|
219 |
return null;
|
|
220 |
}
|
|
221 |
if (idx == 0 ||
|
|
222 |
idx >= last - 1 ||
|
|
223 |
path.charAt(idx - 1) == sep) {
|
|
224 |
// Punt on pathnames containing adjacent slashes
|
|
225 |
// toward the end
|
|
226 |
return null;
|
|
227 |
}
|
|
228 |
return path.substring(0, idx);
|
|
229 |
} else {
|
|
230 |
++nonDotCount;
|
|
231 |
adjacentDots = 0;
|
|
232 |
}
|
|
233 |
--idx;
|
|
234 |
}
|
|
235 |
return null;
|
|
236 |
}
|
|
237 |
|
|
238 |
/* -- Attribute accessors -- */
|
|
239 |
|
|
240 |
public native int getBooleanAttributes0(File f);
|
|
241 |
|
|
242 |
public int getBooleanAttributes(File f) {
|
|
243 |
int rv = getBooleanAttributes0(f);
|
|
244 |
String name = f.getName();
|
|
245 |
boolean hidden = (name.length() > 0) && (name.charAt(0) == '.');
|
|
246 |
return rv | (hidden ? BA_HIDDEN : 0);
|
|
247 |
}
|
|
248 |
|
|
249 |
public native boolean checkAccess(File f, int access);
|
|
250 |
public native long getLastModifiedTime(File f);
|
|
251 |
public native long getLength(File f);
|
|
252 |
public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);
|
|
253 |
|
|
254 |
/* -- File operations -- */
|
|
255 |
|
|
256 |
public native boolean createFileExclusively(String path)
|
|
257 |
throws IOException;
|
|
258 |
public boolean delete(File f) {
|
|
259 |
// Keep canonicalization caches in sync after file deletion
|
|
260 |
// and renaming operations. Could be more clever than this
|
|
261 |
// (i.e., only remove/update affected entries) but probably
|
|
262 |
// not worth it since these entries expire after 30 seconds
|
|
263 |
// anyway.
|
|
264 |
cache.clear();
|
|
265 |
javaHomePrefixCache.clear();
|
|
266 |
return delete0(f);
|
|
267 |
}
|
|
268 |
private native boolean delete0(File f);
|
|
269 |
public native String[] list(File f);
|
|
270 |
public native boolean createDirectory(File f);
|
|
271 |
public boolean rename(File f1, File f2) {
|
|
272 |
// Keep canonicalization caches in sync after file deletion
|
|
273 |
// and renaming operations. Could be more clever than this
|
|
274 |
// (i.e., only remove/update affected entries) but probably
|
|
275 |
// not worth it since these entries expire after 30 seconds
|
|
276 |
// anyway.
|
|
277 |
cache.clear();
|
|
278 |
javaHomePrefixCache.clear();
|
|
279 |
return rename0(f1, f2);
|
|
280 |
}
|
|
281 |
private native boolean rename0(File f1, File f2);
|
|
282 |
public native boolean setLastModifiedTime(File f, long time);
|
|
283 |
public native boolean setReadOnly(File f);
|
|
284 |
|
|
285 |
|
|
286 |
/* -- Filesystem interface -- */
|
|
287 |
|
|
288 |
public File[] listRoots() {
|
|
289 |
try {
|
|
290 |
SecurityManager security = System.getSecurityManager();
|
|
291 |
if (security != null) {
|
|
292 |
security.checkRead("/");
|
|
293 |
}
|
|
294 |
return new File[] { new File("/") };
|
|
295 |
} catch (SecurityException x) {
|
|
296 |
return new File[0];
|
|
297 |
}
|
|
298 |
}
|
|
299 |
|
|
300 |
/* -- Disk usage -- */
|
|
301 |
public native long getSpace(File f, int t);
|
|
302 |
|
|
303 |
/* -- Basic infrastructure -- */
|
|
304 |
|
|
305 |
public int compare(File f1, File f2) {
|
|
306 |
return f1.getPath().compareTo(f2.getPath());
|
|
307 |
}
|
|
308 |
|
|
309 |
public int hashCode(File f) {
|
|
310 |
return f.getPath().hashCode() ^ 1234321;
|
|
311 |
}
|
|
312 |
|
|
313 |
|
|
314 |
private static native void initIDs();
|
|
315 |
|
|
316 |
static {
|
|
317 |
initIDs();
|
|
318 |
}
|
|
319 |
|
|
320 |
}
|