Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/unix/classes/sun/nio/fs/UnixPath.java
41137 views
1
/*
2
* Copyright (c) 2008, 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 sun.nio.fs;
27
28
import java.nio.file.*;
29
import java.nio.charset.*;
30
import java.io.*;
31
import java.net.URI;
32
import java.util.*;
33
34
import jdk.internal.access.JavaLangAccess;
35
import jdk.internal.access.SharedSecrets;
36
37
import static sun.nio.fs.UnixNativeDispatcher.*;
38
import static sun.nio.fs.UnixConstants.*;
39
40
/**
41
* Linux/Mac implementation of java.nio.file.Path
42
*/
43
class UnixPath implements Path {
44
45
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
46
47
private final UnixFileSystem fs;
48
49
// internal representation
50
private final byte[] path;
51
52
// String representation (created lazily)
53
private volatile String stringValue;
54
55
// cached hashcode (created lazily, no need to be volatile)
56
private int hash;
57
58
// array of offsets of elements in path (created lazily)
59
private volatile int[] offsets;
60
61
UnixPath(UnixFileSystem fs, byte[] path) {
62
this.fs = fs;
63
this.path = path;
64
}
65
66
UnixPath(UnixFileSystem fs, String input) {
67
// removes redundant slashes and checks for invalid characters
68
this(fs, encode(fs, normalizeAndCheck(input)));
69
}
70
71
// package-private
72
// removes redundant slashes and check input for invalid characters
73
static String normalizeAndCheck(String input) {
74
int n = input.length();
75
char prevChar = 0;
76
for (int i=0; i < n; i++) {
77
char c = input.charAt(i);
78
if ((c == '/') && (prevChar == '/'))
79
return normalize(input, n, i - 1);
80
checkNotNul(input, c);
81
prevChar = c;
82
}
83
if (prevChar == '/')
84
return normalize(input, n, n - 1);
85
return input;
86
}
87
88
private static void checkNotNul(String input, char c) {
89
if (c == '\u0000')
90
throw new InvalidPathException(input, "Nul character not allowed");
91
}
92
93
private static String normalize(String input, int len, int off) {
94
if (len == 0)
95
return input;
96
int n = len;
97
while ((n > 0) && (input.charAt(n - 1) == '/')) n--;
98
if (n == 0)
99
return "/";
100
StringBuilder sb = new StringBuilder(input.length());
101
if (off > 0)
102
sb.append(input.substring(0, off));
103
char prevChar = 0;
104
for (int i=off; i < n; i++) {
105
char c = input.charAt(i);
106
if ((c == '/') && (prevChar == '/'))
107
continue;
108
checkNotNul(input, c);
109
sb.append(c);
110
prevChar = c;
111
}
112
return sb.toString();
113
}
114
115
// encodes the given path-string into a sequence of bytes
116
private static byte[] encode(UnixFileSystem fs, String input) {
117
input = fs.normalizeNativePath(input);
118
try {
119
return JLA.getBytesNoRepl(input, Util.jnuEncoding());
120
} catch (CharacterCodingException cce) {
121
throw new InvalidPathException(input,
122
"Malformed input or input contains unmappable characters");
123
}
124
}
125
126
// package-private
127
byte[] asByteArray() {
128
return path;
129
}
130
131
// use this path when making system/library calls
132
byte[] getByteArrayForSysCalls() {
133
// resolve against default directory if required (chdir allowed or
134
// file system default directory is not working directory)
135
if (getFileSystem().needToResolveAgainstDefaultDirectory()) {
136
return resolve(getFileSystem().defaultDirectory(), path);
137
} else {
138
if (!isEmpty()) {
139
return path;
140
} else {
141
// empty path case will access current directory
142
byte[] here = { '.' };
143
return here;
144
}
145
}
146
}
147
148
// use this message when throwing exceptions
149
String getPathForExceptionMessage() {
150
return toString();
151
}
152
153
// use this path for permission checks
154
String getPathForPermissionCheck() {
155
if (getFileSystem().needToResolveAgainstDefaultDirectory()) {
156
return Util.toString(getByteArrayForSysCalls());
157
} else {
158
return toString();
159
}
160
}
161
162
// Checks that the given file is a UnixPath
163
static UnixPath toUnixPath(Path obj) {
164
if (obj == null)
165
throw new NullPointerException();
166
if (!(obj instanceof UnixPath))
167
throw new ProviderMismatchException();
168
return (UnixPath)obj;
169
}
170
171
// create offset list if not already created
172
private void initOffsets() {
173
if (offsets == null) {
174
int count, index;
175
176
// count names
177
count = 0;
178
index = 0;
179
if (isEmpty()) {
180
// empty path has one name
181
count = 1;
182
} else {
183
while (index < path.length) {
184
byte c = path[index++];
185
if (c != '/') {
186
count++;
187
while (index < path.length && path[index] != '/')
188
index++;
189
}
190
}
191
}
192
193
// populate offsets
194
int[] result = new int[count];
195
count = 0;
196
index = 0;
197
while (index < path.length) {
198
byte c = path[index];
199
if (c == '/') {
200
index++;
201
} else {
202
result[count++] = index++;
203
while (index < path.length && path[index] != '/')
204
index++;
205
}
206
}
207
synchronized (this) {
208
if (offsets == null)
209
offsets = result;
210
}
211
}
212
}
213
214
// returns {@code true} if this path is an empty path
215
boolean isEmpty() {
216
return path.length == 0;
217
}
218
219
// returns an empty path
220
private UnixPath emptyPath() {
221
return new UnixPath(getFileSystem(), new byte[0]);
222
}
223
224
225
// return true if this path has "." or ".."
226
private boolean hasDotOrDotDot() {
227
int n = getNameCount();
228
for (int i=0; i<n; i++) {
229
byte[] bytes = getName(i).path;
230
if ((bytes.length == 1 && bytes[0] == '.'))
231
return true;
232
if ((bytes.length == 2 && bytes[0] == '.') && bytes[1] == '.') {
233
return true;
234
}
235
}
236
return false;
237
}
238
239
@Override
240
public UnixFileSystem getFileSystem() {
241
return fs;
242
}
243
244
@Override
245
public UnixPath getRoot() {
246
if (path.length > 0 && path[0] == '/') {
247
return getFileSystem().rootDirectory();
248
} else {
249
return null;
250
}
251
}
252
253
@Override
254
public UnixPath getFileName() {
255
initOffsets();
256
257
int count = offsets.length;
258
259
// no elements so no name
260
if (count == 0)
261
return null;
262
263
// one name element and no root component
264
if (count == 1 && path.length > 0 && path[0] != '/')
265
return this;
266
267
int lastOffset = offsets[count-1];
268
int len = path.length - lastOffset;
269
byte[] result = new byte[len];
270
System.arraycopy(path, lastOffset, result, 0, len);
271
return new UnixPath(getFileSystem(), result);
272
}
273
274
@Override
275
public UnixPath getParent() {
276
initOffsets();
277
278
int count = offsets.length;
279
if (count == 0) {
280
// no elements so no parent
281
return null;
282
}
283
int len = offsets[count-1] - 1;
284
if (len <= 0) {
285
// parent is root only (may be null)
286
return getRoot();
287
}
288
byte[] result = new byte[len];
289
System.arraycopy(path, 0, result, 0, len);
290
return new UnixPath(getFileSystem(), result);
291
}
292
293
@Override
294
public int getNameCount() {
295
initOffsets();
296
return offsets.length;
297
}
298
299
@Override
300
public UnixPath getName(int index) {
301
initOffsets();
302
if (index < 0)
303
throw new IllegalArgumentException();
304
if (index >= offsets.length)
305
throw new IllegalArgumentException();
306
307
int begin = offsets[index];
308
int len;
309
if (index == (offsets.length-1)) {
310
len = path.length - begin;
311
} else {
312
len = offsets[index+1] - begin - 1;
313
}
314
315
// construct result
316
byte[] result = new byte[len];
317
System.arraycopy(path, begin, result, 0, len);
318
return new UnixPath(getFileSystem(), result);
319
}
320
321
@Override
322
public UnixPath subpath(int beginIndex, int endIndex) {
323
initOffsets();
324
325
if (beginIndex < 0)
326
throw new IllegalArgumentException();
327
if (beginIndex >= offsets.length)
328
throw new IllegalArgumentException();
329
if (endIndex > offsets.length)
330
throw new IllegalArgumentException();
331
if (beginIndex >= endIndex) {
332
throw new IllegalArgumentException();
333
}
334
335
// starting offset and length
336
int begin = offsets[beginIndex];
337
int len;
338
if (endIndex == offsets.length) {
339
len = path.length - begin;
340
} else {
341
len = offsets[endIndex] - begin - 1;
342
}
343
344
// construct result
345
byte[] result = new byte[len];
346
System.arraycopy(path, begin, result, 0, len);
347
return new UnixPath(getFileSystem(), result);
348
}
349
350
@Override
351
public boolean isAbsolute() {
352
return (path.length > 0 && path[0] == '/');
353
}
354
355
// Resolve child against given base
356
private static byte[] resolve(byte[] base, byte[] child) {
357
int baseLength = base.length;
358
int childLength = child.length;
359
if (childLength == 0)
360
return base;
361
if (baseLength == 0 || child[0] == '/')
362
return child;
363
byte[] result;
364
if (baseLength == 1 && base[0] == '/') {
365
result = new byte[childLength + 1];
366
result[0] = '/';
367
System.arraycopy(child, 0, result, 1, childLength);
368
} else {
369
result = new byte[baseLength + 1 + childLength];
370
System.arraycopy(base, 0, result, 0, baseLength);
371
result[base.length] = '/';
372
System.arraycopy(child, 0, result, baseLength+1, childLength);
373
}
374
return result;
375
}
376
377
@Override
378
public UnixPath resolve(Path obj) {
379
byte[] other = toUnixPath(obj).path;
380
if (other.length > 0 && other[0] == '/')
381
return ((UnixPath)obj);
382
byte[] result = resolve(path, other);
383
return new UnixPath(getFileSystem(), result);
384
}
385
386
UnixPath resolve(byte[] other) {
387
return resolve(new UnixPath(getFileSystem(), other));
388
}
389
390
@Override
391
public UnixPath relativize(Path obj) {
392
UnixPath child = toUnixPath(obj);
393
if (child.equals(this))
394
return emptyPath();
395
396
// can only relativize paths of the same type
397
if (this.isAbsolute() != child.isAbsolute())
398
throw new IllegalArgumentException("'other' is different type of Path");
399
400
// this path is the empty path
401
if (this.isEmpty())
402
return child;
403
404
UnixPath base = this;
405
if (base.hasDotOrDotDot() || child.hasDotOrDotDot()) {
406
base = base.normalize();
407
child = child.normalize();
408
}
409
410
int baseCount = base.getNameCount();
411
int childCount = child.getNameCount();
412
413
// skip matching names
414
int n = Math.min(baseCount, childCount);
415
int i = 0;
416
while (i < n) {
417
if (!base.getName(i).equals(child.getName(i)))
418
break;
419
i++;
420
}
421
422
// remaining elements in child
423
UnixPath childRemaining;
424
boolean isChildEmpty;
425
if (i == childCount) {
426
childRemaining = emptyPath();
427
isChildEmpty = true;
428
} else {
429
childRemaining = child.subpath(i, childCount);
430
isChildEmpty = childRemaining.isEmpty();
431
}
432
433
// matched all of base
434
if (i == baseCount) {
435
return childRemaining;
436
}
437
438
// the remainder of base cannot contain ".."
439
UnixPath baseRemaining = base.subpath(i, baseCount);
440
if (baseRemaining.hasDotOrDotDot()) {
441
throw new IllegalArgumentException("Unable to compute relative "
442
+ " path from " + this + " to " + obj);
443
}
444
if (baseRemaining.isEmpty())
445
return childRemaining;
446
447
// number of ".." needed
448
int dotdots = baseRemaining.getNameCount();
449
if (dotdots == 0) {
450
return childRemaining;
451
}
452
453
// result is a "../" for each remaining name in base followed by the
454
// remaining names in child. If the remainder is the empty path
455
// then we don't add the final trailing slash.
456
int len = dotdots*3 + childRemaining.path.length;
457
if (isChildEmpty) {
458
assert childRemaining.isEmpty();
459
len--;
460
}
461
byte[] result = new byte[len];
462
int pos = 0;
463
while (dotdots > 0) {
464
result[pos++] = (byte)'.';
465
result[pos++] = (byte)'.';
466
if (isChildEmpty) {
467
if (dotdots > 1) result[pos++] = (byte)'/';
468
} else {
469
result[pos++] = (byte)'/';
470
}
471
dotdots--;
472
}
473
System.arraycopy(childRemaining.path,0, result, pos,
474
childRemaining.path.length);
475
return new UnixPath(getFileSystem(), result);
476
}
477
478
@Override
479
public UnixPath normalize() {
480
final int count = getNameCount();
481
if (count == 0 || isEmpty())
482
return this;
483
484
boolean[] ignore = new boolean[count]; // true => ignore name
485
int[] size = new int[count]; // length of name
486
int remaining = count; // number of names remaining
487
boolean hasDotDot = false; // has at least one ..
488
boolean isAbsolute = isAbsolute();
489
490
// first pass:
491
// 1. compute length of names
492
// 2. mark all occurrences of "." to ignore
493
// 3. and look for any occurrences of ".."
494
for (int i=0; i<count; i++) {
495
int begin = offsets[i];
496
int len;
497
if (i == (offsets.length-1)) {
498
len = path.length - begin;
499
} else {
500
len = offsets[i+1] - begin - 1;
501
}
502
size[i] = len;
503
504
if (path[begin] == '.') {
505
if (len == 1) {
506
ignore[i] = true; // ignore "."
507
remaining--;
508
}
509
else {
510
if (path[begin+1] == '.') // ".." found
511
hasDotDot = true;
512
}
513
}
514
}
515
516
// multiple passes to eliminate all occurrences of name/..
517
if (hasDotDot) {
518
int prevRemaining;
519
do {
520
prevRemaining = remaining;
521
int prevName = -1;
522
for (int i=0; i<count; i++) {
523
if (ignore[i])
524
continue;
525
526
// not a ".."
527
if (size[i] != 2) {
528
prevName = i;
529
continue;
530
}
531
532
int begin = offsets[i];
533
if (path[begin] != '.' || path[begin+1] != '.') {
534
prevName = i;
535
continue;
536
}
537
538
// ".." found
539
if (prevName >= 0) {
540
// name/<ignored>/.. found so mark name and ".." to be
541
// ignored
542
ignore[prevName] = true;
543
ignore[i] = true;
544
remaining = remaining - 2;
545
prevName = -1;
546
} else {
547
// Case: /<ignored>/.. so mark ".." as ignored
548
if (isAbsolute) {
549
boolean hasPrevious = false;
550
for (int j=0; j<i; j++) {
551
if (!ignore[j]) {
552
hasPrevious = true;
553
break;
554
}
555
}
556
if (!hasPrevious) {
557
// all proceeding names are ignored
558
ignore[i] = true;
559
remaining--;
560
}
561
}
562
}
563
}
564
} while (prevRemaining > remaining);
565
}
566
567
// no redundant names
568
if (remaining == count)
569
return this;
570
571
// corner case - all names removed
572
if (remaining == 0) {
573
return isAbsolute ? getFileSystem().rootDirectory() : emptyPath();
574
}
575
576
// compute length of result
577
int len = remaining - 1;
578
if (isAbsolute)
579
len++;
580
581
for (int i=0; i<count; i++) {
582
if (!ignore[i])
583
len += size[i];
584
}
585
byte[] result = new byte[len];
586
587
// copy names into result
588
int pos = 0;
589
if (isAbsolute)
590
result[pos++] = '/';
591
for (int i=0; i<count; i++) {
592
if (!ignore[i]) {
593
System.arraycopy(path, offsets[i], result, pos, size[i]);
594
pos += size[i];
595
if (--remaining > 0) {
596
result[pos++] = '/';
597
}
598
}
599
}
600
return new UnixPath(getFileSystem(), result);
601
}
602
603
@Override
604
public boolean startsWith(Path other) {
605
if (!(Objects.requireNonNull(other) instanceof UnixPath))
606
return false;
607
UnixPath that = (UnixPath)other;
608
609
// other path is longer
610
if (that.path.length > path.length)
611
return false;
612
613
int thisOffsetCount = getNameCount();
614
int thatOffsetCount = that.getNameCount();
615
616
// other path has no name elements
617
if (thatOffsetCount == 0 && this.isAbsolute()) {
618
return that.isEmpty() ? false : true;
619
}
620
621
// given path has more elements that this path
622
if (thatOffsetCount > thisOffsetCount)
623
return false;
624
625
// same number of elements so must be exact match
626
if ((thatOffsetCount == thisOffsetCount) &&
627
(path.length != that.path.length)) {
628
return false;
629
}
630
631
// check offsets of elements match
632
for (int i=0; i<thatOffsetCount; i++) {
633
Integer o1 = offsets[i];
634
Integer o2 = that.offsets[i];
635
if (!o1.equals(o2))
636
return false;
637
}
638
639
// offsets match so need to compare bytes
640
int i=0;
641
while (i < that.path.length) {
642
if (this.path[i] != that.path[i])
643
return false;
644
i++;
645
}
646
647
// final check that match is on name boundary
648
if (i < path.length && this.path[i] != '/')
649
return false;
650
651
return true;
652
}
653
654
@Override
655
public boolean endsWith(Path other) {
656
if (!(Objects.requireNonNull(other) instanceof UnixPath))
657
return false;
658
UnixPath that = (UnixPath)other;
659
660
int thisLen = path.length;
661
int thatLen = that.path.length;
662
663
// other path is longer
664
if (thatLen > thisLen)
665
return false;
666
667
// other path is the empty path
668
if (thisLen > 0 && thatLen == 0)
669
return false;
670
671
// other path is absolute so this path must be absolute
672
if (that.isAbsolute() && !this.isAbsolute())
673
return false;
674
675
int thisOffsetCount = getNameCount();
676
int thatOffsetCount = that.getNameCount();
677
678
// given path has more elements that this path
679
if (thatOffsetCount > thisOffsetCount) {
680
return false;
681
} else {
682
// same number of elements
683
if (thatOffsetCount == thisOffsetCount) {
684
if (thisOffsetCount == 0)
685
return true;
686
int expectedLen = thisLen;
687
if (this.isAbsolute() && !that.isAbsolute())
688
expectedLen--;
689
if (thatLen != expectedLen)
690
return false;
691
} else {
692
// this path has more elements so given path must be relative
693
if (that.isAbsolute())
694
return false;
695
}
696
}
697
698
// compare bytes
699
int thisPos = offsets[thisOffsetCount - thatOffsetCount];
700
int thatPos = that.offsets[0];
701
if ((thatLen - thatPos) != (thisLen - thisPos))
702
return false;
703
while (thatPos < thatLen) {
704
if (this.path[thisPos++] != that.path[thatPos++])
705
return false;
706
}
707
708
return true;
709
}
710
711
@Override
712
public int compareTo(Path other) {
713
int len1 = path.length;
714
int len2 = ((UnixPath) other).path.length;
715
716
int n = Math.min(len1, len2);
717
byte v1[] = path;
718
byte v2[] = ((UnixPath) other).path;
719
720
int k = 0;
721
while (k < n) {
722
int c1 = v1[k] & 0xff;
723
int c2 = v2[k] & 0xff;
724
if (c1 != c2) {
725
return c1 - c2;
726
}
727
k++;
728
}
729
return len1 - len2;
730
}
731
732
@Override
733
public boolean equals(Object ob) {
734
if (ob instanceof UnixPath path) {
735
return compareTo(path) == 0;
736
}
737
return false;
738
}
739
740
@Override
741
public int hashCode() {
742
// OK if two or more threads compute hash
743
int h = hash;
744
if (h == 0) {
745
for (int i = 0; i< path.length; i++) {
746
h = 31*h + (path[i] & 0xff);
747
}
748
hash = h;
749
}
750
return h;
751
}
752
753
@Override
754
public String toString() {
755
// OK if two or more threads create a String
756
if (stringValue == null) {
757
stringValue = fs.normalizeJavaPath(Util.toString(path)); // platform encoding
758
}
759
return stringValue;
760
}
761
762
// -- file operations --
763
764
// package-private
765
int openForAttributeAccess(boolean followLinks) throws UnixException {
766
int flags = O_RDONLY;
767
if (!followLinks) {
768
if (O_NOFOLLOW == 0)
769
throw new UnixException
770
("NOFOLLOW_LINKS is not supported on this platform");
771
flags |= O_NOFOLLOW;
772
}
773
return open(this, flags, 0);
774
}
775
776
void checkRead() {
777
@SuppressWarnings("removal")
778
SecurityManager sm = System.getSecurityManager();
779
if (sm != null)
780
sm.checkRead(getPathForPermissionCheck());
781
}
782
783
void checkWrite() {
784
@SuppressWarnings("removal")
785
SecurityManager sm = System.getSecurityManager();
786
if (sm != null)
787
sm.checkWrite(getPathForPermissionCheck());
788
}
789
790
void checkDelete() {
791
@SuppressWarnings("removal")
792
SecurityManager sm = System.getSecurityManager();
793
if (sm != null)
794
sm.checkDelete(getPathForPermissionCheck());
795
}
796
797
@Override
798
public UnixPath toAbsolutePath() {
799
if (isAbsolute()) {
800
return this;
801
}
802
// The path is relative so need to resolve against default directory,
803
// taking care not to reveal the user.dir
804
@SuppressWarnings("removal")
805
SecurityManager sm = System.getSecurityManager();
806
if (sm != null) {
807
sm.checkPropertyAccess("user.dir");
808
}
809
return new UnixPath(getFileSystem(),
810
resolve(getFileSystem().defaultDirectory(), path));
811
}
812
813
@Override
814
public Path toRealPath(LinkOption... options) throws IOException {
815
checkRead();
816
817
UnixPath absolute = toAbsolutePath();
818
819
// if resolving links then use realpath
820
if (Util.followLinks(options)) {
821
try {
822
byte[] rp = realpath(absolute);
823
return new UnixPath(getFileSystem(), rp);
824
} catch (UnixException x) {
825
x.rethrowAsIOException(this);
826
}
827
}
828
829
// if not resolving links then eliminate "." and also ".."
830
// where the previous element is not a link.
831
UnixPath result = fs.rootDirectory();
832
for (int i=0; i<absolute.getNameCount(); i++) {
833
UnixPath element = absolute.getName(i);
834
835
// eliminate "."
836
if ((element.asByteArray().length == 1) && (element.asByteArray()[0] == '.'))
837
continue;
838
839
// cannot eliminate ".." if previous element is a link
840
if ((element.asByteArray().length == 2) && (element.asByteArray()[0] == '.') &&
841
(element.asByteArray()[1] == '.'))
842
{
843
UnixFileAttributes attrs = null;
844
try {
845
attrs = UnixFileAttributes.get(result, false);
846
} catch (UnixException x) {
847
x.rethrowAsIOException(result);
848
}
849
if (!attrs.isSymbolicLink()) {
850
result = result.getParent();
851
if (result == null) {
852
result = fs.rootDirectory();
853
}
854
continue;
855
}
856
}
857
result = result.resolve(element);
858
}
859
860
// check file exists (without following links)
861
try {
862
UnixFileAttributes.get(result, false);
863
} catch (UnixException x) {
864
x.rethrowAsIOException(result);
865
}
866
return result;
867
}
868
869
@Override
870
public URI toUri() {
871
return UnixUriUtils.toUri(this);
872
}
873
874
@Override
875
public WatchKey register(WatchService watcher,
876
WatchEvent.Kind<?>[] events,
877
WatchEvent.Modifier... modifiers)
878
throws IOException
879
{
880
if (watcher == null)
881
throw new NullPointerException();
882
if (!(watcher instanceof AbstractWatchService))
883
throw new ProviderMismatchException();
884
checkRead();
885
return ((AbstractWatchService)watcher).register(this, events, modifiers);
886
}
887
}
888
889