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