1
25
26 package java.io;
27
28 import java.security.AccessController;
29 import java.util.Locale;
30 import sun.security.action.GetPropertyAction;
31
32
38 class WinNTFileSystem extends FileSystem {
39
40 private final char slash;
41 private final char altSlash;
42 private final char semicolon;
43
44 public WinNTFileSystem() {
45 slash = AccessController.doPrivileged(
46 new GetPropertyAction("file.separator")).charAt(0);
47 semicolon = AccessController.doPrivileged(
48 new GetPropertyAction("path.separator")).charAt(0);
49 altSlash = (this.slash == '\\') ? '/' : '\\';
50 }
51
52 private boolean isSlash(char c) {
53 return (c == '\\') || (c == '/');
54 }
55
56 private boolean isLetter(char c) {
57 return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
58 }
59
60 private String slashify(String p) {
61 if ((p.length() > 0) && (p.charAt(0) != slash)) return slash + p;
62 else return p;
63 }
64
65
66
67 @Override
68 public char getSeparator() {
69 return slash;
70 }
71
72 @Override
73 public char getPathSeparator() {
74 return semicolon;
75 }
76
77
80 @Override
81 public String normalize(String path) {
82 int n = path.length();
83 char slash = this.slash;
84 char altSlash = this.altSlash;
85 char prev = 0;
86 for (int i = 0; i < n; i++) {
87 char c = path.charAt(i);
88 if (c == altSlash)
89 return normalize(path, n, (prev == slash) ? i - 1 : i);
90 if ((c == slash) && (prev == slash) && (i > 1))
91 return normalize(path, n, i - 1);
92 if ((c == ':') && (i > 1))
93 return normalize(path, n, 0);
94 prev = c;
95 }
96 if (prev == slash) return normalize(path, n, n - 1);
97 return path;
98 }
99
100
102 private String normalize(String path, int len, int off) {
103 if (len == 0) return path;
104 if (off < 3) off = 0;
105 int src;
106 char slash = this.slash;
107 StringBuffer sb = new StringBuffer(len);
108
109 if (off == 0) {
110
111 src = normalizePrefix(path, len, sb);
112 } else {
113
114 src = off;
115 sb.append(path.substring(0, off));
116 }
117
118
120 while (src < len) {
121 char c = path.charAt(src++);
122 if (isSlash(c)) {
123 while ((src < len) && isSlash(path.charAt(src))) src++;
124 if (src == len) {
125
126 int sn = sb.length();
127 if ((sn == 2) && (sb.charAt(1) == ':')) {
128
129 sb.append(slash);
130 break;
131 }
132 if (sn == 0) {
133
134 sb.append(slash);
135 break;
136 }
137 if ((sn == 1) && (isSlash(sb.charAt(0)))) {
138
145 sb.append(slash);
146 break;
147 }
148
150 break;
151 } else {
152 sb.append(slash);
153 }
154 } else {
155 sb.append(c);
156 }
157 }
158
159 String rv = sb.toString();
160 return rv;
161 }
162
163
175 private int normalizePrefix(String path, int len, StringBuffer sb) {
176 int src = 0;
177 while ((src < len) && isSlash(path.charAt(src))) src++;
178 char c;
179 if ((len - src >= 2)
180 && isLetter(c = path.charAt(src))
181 && path.charAt(src + 1) == ':') {
182
186 sb.append(c);
187 sb.append(':');
188 src += 2;
189 } else {
190 src = 0;
191 if ((len >= 2)
192 && isSlash(path.charAt(0))
193 && isSlash(path.charAt(1))) {
194
199 src = 1;
200 sb.append(slash);
201 }
202 }
203 return src;
204 }
205
206 @Override
207 public int prefixLength(String path) {
208 char slash = this.slash;
209 int n = path.length();
210 if (n == 0) return 0;
211 char c0 = path.charAt(0);
212 char c1 = (n > 1) ? path.charAt(1) : 0;
213 if (c0 == slash) {
214 if (c1 == slash) return 2;
215 return 1;
216 }
217 if (isLetter(c0) && (c1 == ':')) {
218 if ((n > 2) && (path.charAt(2) == slash))
219 return 3;
220 return 2;
221 }
222 return 0;
223 }
224
225 @Override
226 public String resolve(String parent, String child) {
227 int pn = parent.length();
228 if (pn == 0) return child;
229 int cn = child.length();
230 if (cn == 0) return parent;
231
232 String c = child;
233 int childStart = 0;
234 int parentEnd = pn;
235
236 if ((cn > 1) && (c.charAt(0) == slash)) {
237 if (c.charAt(1) == slash) {
238
239 childStart = 2;
240 } else {
241
242 childStart = 1;
243
244 }
245 if (cn == childStart) {
246 if (parent.charAt(pn - 1) == slash)
247 return parent.substring(0, pn - 1);
248 return parent;
249 }
250 }
251
252 if (parent.charAt(pn - 1) == slash)
253 parentEnd--;
254
255 int strlen = parentEnd + cn - childStart;
256 char[] theChars = null;
257 if (child.charAt(childStart) == slash) {
258 theChars = new char[strlen];
259 parent.getChars(0, parentEnd, theChars, 0);
260 child.getChars(childStart, cn, theChars, parentEnd);
261 } else {
262 theChars = new char[strlen + 1];
263 parent.getChars(0, parentEnd, theChars, 0);
264 theChars[parentEnd] = slash;
265 child.getChars(childStart, cn, theChars, parentEnd + 1);
266 }
267 return new String(theChars);
268 }
269
270 @Override
271 public String getDefaultParent() {
272 return ("" + slash);
273 }
274
275 @Override
276 public String fromURIPath(String path) {
277 String p = path;
278 if ((p.length() > 2) && (p.charAt(2) == ':')) {
279
280 p = p.substring(1);
281
282 if ((p.length() > 3) && p.endsWith("/"))
283 p = p.substring(0, p.length() - 1);
284 } else if ((p.length() > 1) && p.endsWith("/")) {
285
286 p = p.substring(0, p.length() - 1);
287 }
288 return p;
289 }
290
291
292
293 @Override
294 public boolean isAbsolute(File f) {
295 int pl = f.getPrefixLength();
296 return (((pl == 2) && (f.getPath().charAt(0) == slash))
297 || (pl == 3));
298 }
299
300 @Override
301 public String resolve(File f) {
302 String path = f.getPath();
303 int pl = f.getPrefixLength();
304 if ((pl == 2) && (path.charAt(0) == slash))
305 return path;
306 if (pl == 3)
307 return path;
308 if (pl == 0)
309 return getUserPath() + slashify(path);
310 if (pl == 1) {
311 String up = getUserPath();
312 String ud = getDrive(up);
313 if (ud != null) return ud + path;
314 return up + path;
315 }
316 if (pl == 2) {
317 String up = getUserPath();
318 String ud = getDrive(up);
319 if ((ud != null) && path.startsWith(ud))
320 return up + slashify(path.substring(2));
321 char drive = path.charAt(0);
322 String dir = getDriveDirectory(drive);
323 String np;
324 if (dir != null) {
325
328 String p = drive + (':' + dir + slashify(path.substring(2)));
329 SecurityManager security = System.getSecurityManager();
330 try {
331 if (security != null) security.checkRead(p);
332 } catch (SecurityException x) {
333
334 throw new SecurityException("Cannot resolve path " + path);
335 }
336 return p;
337 }
338 return drive + ":" + slashify(path.substring(2));
339 }
340 throw new InternalError("Unresolvable path: " + path);
341 }
342
343 private String getUserPath() {
344
346 return normalize(System.getProperty("user.dir"));
347 }
348
349 private String getDrive(String path) {
350 int pl = prefixLength(path);
351 return (pl == 3) ? path.substring(0, 2) : null;
352 }
353
354 private static String[] driveDirCache = new String[26];
355
356 private static int driveIndex(char d) {
357 if ((d >= 'a') && (d <= 'z')) return d - 'a';
358 if ((d >= 'A') && (d <= 'Z')) return d - 'A';
359 return -1;
360 }
361
362 private native String getDriveDirectory(int drive);
363
364 private String getDriveDirectory(char drive) {
365 int i = driveIndex(drive);
366 if (i < 0) return null;
367 String s = driveDirCache[i];
368 if (s != null) return s;
369 s = getDriveDirectory(i + 1);
370 driveDirCache[i] = s;
371 return s;
372 }
373
374
375
376
377
378
379
380 private ExpiringCache cache = new ExpiringCache();
381 private ExpiringCache prefixCache = new ExpiringCache();
382
383 @Override
384 public String canonicalize(String path) throws IOException {
385
386 int len = path.length();
387 if ((len == 2) &&
388 (isLetter(path.charAt(0))) &&
389 (path.charAt(1) == ':')) {
390 char c = path.charAt(0);
391 if ((c >= 'A') && (c <= 'Z'))
392 return path;
393 return "" + ((char) (c-32)) + ':';
394 } else if ((len == 3) &&
395 (isLetter(path.charAt(0))) &&
396 (path.charAt(1) == ':') &&
397 (path.charAt(2) == '\\')) {
398 char c = path.charAt(0);
399 if ((c >= 'A') && (c <= 'Z'))
400 return path;
401 return "" + ((char) (c-32)) + ':' + '\\';
402 }
403 if (!useCanonCaches) {
404 return canonicalize0(path);
405 } else {
406 String res = cache.get(path);
407 if (res == null) {
408 String dir = null;
409 String resDir = null;
410 if (useCanonPrefixCache) {
411 dir = parentOrNull(path);
412 if (dir != null) {
413 resDir = prefixCache.get(dir);
414 if (resDir != null) {
415
421 String filename = path.substring(1 + dir.length());
422 res = canonicalizeWithPrefix(resDir, filename);
423 cache.put(dir + File.separatorChar + filename, res);
424 }
425 }
426 }
427 if (res == null) {
428 res = canonicalize0(path);
429 cache.put(path, res);
430 if (useCanonPrefixCache && dir != null) {
431 resDir = parentOrNull(res);
432 if (resDir != null) {
433 File f = new File(res);
434 if (f.exists() && !f.isDirectory()) {
435 prefixCache.put(dir, resDir);
436 }
437 }
438 }
439 }
440 }
441 return res;
442 }
443 }
444
445 private native String canonicalize0(String path)
446 throws IOException;
447
448 private String canonicalizeWithPrefix(String canonicalPrefix,
449 String filename) throws IOException
450 {
451 return canonicalizeWithPrefix0(canonicalPrefix,
452 canonicalPrefix + File.separatorChar + filename);
453 }
454
455
456
457
458 private native String canonicalizeWithPrefix0(String canonicalPrefix,
459 String pathWithCanonicalPrefix)
460 throws IOException;
461
462
463
464
465
466
467
468
469 private static String parentOrNull(String path) {
470 if (path == null) return null;
471 char sep = File.separatorChar;
472 char altSep = '/';
473 int last = path.length() - 1;
474 int idx = last;
475 int adjacentDots = 0;
476 int nonDotCount = 0;
477 while (idx > 0) {
478 char c = path.charAt(idx);
479 if (c == '.') {
480 if (++adjacentDots >= 2) {
481
482 return null;
483 }
484 if (nonDotCount == 0) {
485
486 return null;
487 }
488 } else if (c == sep) {
489 if (adjacentDots == 1 && nonDotCount == 0) {
490
491 return null;
492 }
493 if (idx == 0 ||
494 idx >= last - 1 ||
495 path.charAt(idx - 1) == sep ||
496 path.charAt(idx - 1) == altSep) {
497
498
499 return null;
500 }
501 return path.substring(0, idx);
502 } else if (c == altSep) {
503
504
505 return null;
506 } else if (c == '*' || c == '?') {
507
508 return null;
509 } else {
510 ++nonDotCount;
511 adjacentDots = 0;
512 }
513 --idx;
514 }
515 return null;
516 }
517
518
519
520 @Override
521 public native int getBooleanAttributes(File f);
522
523 @Override
524 public native boolean checkAccess(File f, int access);
525
526 @Override
527 public native long getLastModifiedTime(File f);
528
529 @Override
530 public native long getLength(File f);
531
532 @Override
533 public native boolean setPermission(File f, int access, boolean enable,
534 boolean owneronly);
535
536
537
538 @Override
539 public native boolean createFileExclusively(String path)
540 throws IOException;
541
542 @Override
543 public native String[] list(File f);
544
545 @Override
546 public native boolean createDirectory(File f);
547
548 @Override
549 public native boolean setLastModifiedTime(File f, long time);
550
551 @Override
552 public native boolean setReadOnly(File f);
553
554 @Override
555 public boolean delete(File f) {
556
557
558
559
560
561 cache.clear();
562 prefixCache.clear();
563 return delete0(f);
564 }
565
566 private native boolean delete0(File f);
567
568 @Override
569 public boolean rename(File f1, File f2) {
570
571
572
573
574
575 cache.clear();
576 prefixCache.clear();
577 return rename0(f1, f2);
578 }
579
580 private native boolean rename0(File f1, File f2);
581
582
583
584 @Override
585 public File[] listRoots() {
586 int ds = listRoots0();
587 int n = 0;
588 for (int i = 0; i < 26; i++) {
589 if (((ds >> i) & 1) != 0) {
590 if (!access((char)('A' + i) + ":" + slash))
591 ds &= ~(1 << i);
592 else
593 n++;
594 }
595 }
596 File[] fs = new File[n];
597 int j = 0;
598 char slash = this.slash;
599 for (int i = 0; i < 26; i++) {
600 if (((ds >> i) & 1) != 0)
601 fs[j++] = new File((char)('A' + i) + ":" + slash);
602 }
603 return fs;
604 }
605
606 private static native int listRoots0();
607
608 private boolean access(String path) {
609 try {
610 SecurityManager security = System.getSecurityManager();
611 if (security != null) security.checkRead(path);
612 return true;
613 } catch (SecurityException x) {
614 return false;
615 }
616 }
617
618
619
620 @Override
621 public long getSpace(File f, int t) {
622 if (f.exists()) {
623 return getSpace0(f, t);
624 }
625 return 0;
626 }
627
628 private native long getSpace0(File f, int t);
629
630
631
632 @Override
633 public int compare(File f1, File f2) {
634 return f1.getPath().compareToIgnoreCase(f2.getPath());
635 }
636
637 @Override
638 public int hashCode(File f) {
639
640 return f.getPath().toLowerCase(Locale.ENGLISH).hashCode() ^ 1234321;
641 }
642
643 private static native void initIDs();
644
645 static {
646 initIDs();
647 }
648 }
649