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(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) {
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(String input) {
120 SoftReference<CharsetEncoder> ref = encoder.get();
121 CharsetEncoder ce = (ref != null) ? ref.get() : null;
122 if (ce == null) {
123 ce = Charset.defaultCharset().newEncoder()
124 .onMalformedInput(CodingErrorAction.REPORT)
125 .onUnmappableCharacter(CodingErrorAction.REPORT);
126 encoder.set(new SoftReference<CharsetEncoder>(ce));
127 }
128
129 char[] ca = 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 chacraters");
149 }
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 = new String(path); // platform encoding
762 return stringValue;
763 }
764
765 // -- file operations --
766
767 // package-private
768 int openForAttributeAccess(boolean followLinks) throws IOException {
769 int flags = O_RDONLY;
770 if (!followLinks) {
771 if (!supportsNoFollowLinks())
772 throw new IOException("NOFOLLOW_LINKS is not supported on this platform");
773 flags |= O_NOFOLLOW;
774 }
775 try {
776 return open(this, flags, 0);
777 } catch (UnixException x) {
778 // HACK: EINVAL instead of ELOOP on Solaris 10 prior to u4 (see 6460380)
779 if (getFileSystem().isSolaris() && x.errno() == EINVAL)
780 x.setError(ELOOP);
781
|
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) {
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 = Charset.defaultCharset().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 chacraters");
149 }
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(new String(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 (!supportsNoFollowLinks())
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
|