/* * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
// use this path when making system/library calls byte[] getByteArrayForSysCalls() { // resolve against default directory if required (chdir allowed or // file system default directory is not working directory) if (getFileSystem().needToResolveAgainstDefaultDirectory()) { return resolve(getFileSystem().defaultDirectory(), path);
} else { if (!isEmpty()) { return path;
} else { // empty path case will access current directory byte[] here = { '.' }; return here;
}
}
}
// use this message when throwing exceptions
String getPathForExceptionMessage() { return toString();
}
// use this path for permission checks
String getPathForPermissionCheck() { if (getFileSystem().needToResolveAgainstDefaultDirectory()) { return Util.toString(getByteArrayForSysCalls());
} else { return toString();
}
}
// Checks that the given file is a UnixPath static UnixPath toUnixPath(Path obj) { if (obj == null) thrownew NullPointerException(); if (!(obj instanceof UnixPath)) thrownew ProviderMismatchException(); return (UnixPath)obj;
}
// create offset list if not already created privatevoid initOffsets() { if (offsets == null) { int count, index;
// count names
count = 0;
index = 0; if (isEmpty()) { // empty path has one name
count = 1;
} else { while (index < path.length) { byte c = path[index++]; if (c != '/') {
count++; while (index < path.length && path[index] != '/')
index++;
}
}
}
// populate offsets int[] result = newint[count];
count = 0;
index = 0; while (index < path.length) { byte c = path[index]; if (c == '/') {
index++;
} else {
result[count++] = index++; while (index < path.length && path[index] != '/')
index++;
}
} synchronized (this) { if (offsets == null)
offsets = result;
}
}
}
// returns {@code true} if this path is an empty path boolean isEmpty() { return path.length == 0;
}
@Override public UnixPath getFileName() {
initOffsets();
int count = offsets.length;
// no elements so no name if (count == 0) returnnull;
// one name element and no root component if (count == 1 && path.length > 0 && path[0] != '/') returnthis;
int lastOffset = offsets[count-1]; int len = path.length - lastOffset; byte[] result = newbyte[len];
System.arraycopy(path, lastOffset, result, 0, len); returnnew UnixPath(getFileSystem(), result);
}
@Override public UnixPath getParent() {
initOffsets();
int count = offsets.length; if (count == 0) { // no elements so no parent returnnull;
} int len = offsets[count-1] - 1; if (len <= 0) { // parent is root only (may be null) return getRoot();
} byte[] result = newbyte[len];
System.arraycopy(path, 0, result, 0, len); returnnew UnixPath(getFileSystem(), result);
}
@Override public UnixPath getName(int index) {
initOffsets(); if (index < 0) thrownew IllegalArgumentException(); if (index >= offsets.length) thrownew IllegalArgumentException();
int begin = offsets[index]; int len; if (index == (offsets.length-1)) {
len = path.length - begin;
} else {
len = offsets[index+1] - begin - 1;
}
// construct result byte[] result = newbyte[len];
System.arraycopy(path, begin, result, 0, len); returnnew UnixPath(getFileSystem(), result);
}
@Override public UnixPath subpath(int beginIndex, int endIndex) {
initOffsets();
if (beginIndex < 0) thrownew IllegalArgumentException(); if (beginIndex >= offsets.length) thrownew IllegalArgumentException(); if (endIndex > offsets.length) thrownew IllegalArgumentException(); if (beginIndex >= endIndex) { thrownew IllegalArgumentException();
}
// starting offset and length int begin = offsets[beginIndex]; int len; if (endIndex == offsets.length) {
len = path.length - begin;
} else {
len = offsets[endIndex] - begin - 1;
}
// construct result byte[] result = newbyte[len];
System.arraycopy(path, begin, result, 0, len); returnnew UnixPath(getFileSystem(), result);
}
@Override public UnixPath relativize(Path obj) {
UnixPath child = toUnixPath(obj); if (child.equals(this)) return emptyPath();
// can only relativize paths of the same type if (this.isAbsolute() != child.isAbsolute()) thrownew IllegalArgumentException("'other' is different type of Path");
// this path is the empty path if (this.isEmpty()) return child;
UnixPath base = this; if (base.hasDotOrDotDot() || child.hasDotOrDotDot()) {
base = base.normalize();
child = child.normalize();
}
int baseCount = base.getNameCount(); int childCount = child.getNameCount();
// skip matching names int n = Math.min(baseCount, childCount); int i = 0; while (i < n) { if (!base.getName(i).equals(child.getName(i))) break;
i++;
}
// remaining elements in child
UnixPath childRemaining; boolean isChildEmpty; if (i == childCount) {
childRemaining = emptyPath();
isChildEmpty = true;
} else {
childRemaining = child.subpath(i, childCount);
isChildEmpty = childRemaining.isEmpty();
}
// matched all of base if (i == baseCount) { return childRemaining;
}
// the remainder of base cannot contain ".."
UnixPath baseRemaining = base.subpath(i, baseCount); if (baseRemaining.hasDotOrDotDot()) { thrownew IllegalArgumentException("Unable to compute relative "
+ " path from " + this + " to " + obj);
} if (baseRemaining.isEmpty()) return childRemaining;
// number of ".." needed int dotdots = baseRemaining.getNameCount(); if (dotdots == 0) { return childRemaining;
}
// result is a "../" for each remaining name in base followed by the // remaining names in child. If the remainder is the empty path // then we don't add the final trailing slash. int len = dotdots*3 + childRemaining.path.length; if (isChildEmpty) { assert childRemaining.isEmpty();
len--;
} byte[] result = newbyte[len]; int pos = 0; while (dotdots > 0) {
result[pos++] = (byte)'.';
result[pos++] = (byte)'.'; if (isChildEmpty) { if (dotdots > 1) result[pos++] = (byte)'/';
} else {
result[pos++] = (byte)'/';
}
dotdots--;
}
System.arraycopy(childRemaining.path,0, result, pos,
childRemaining.path.length); returnnew UnixPath(getFileSystem(), result);
}
@Override public UnixPath normalize() { finalint count = getNameCount(); if (count == 0 || isEmpty()) returnthis;
boolean[] ignore = newboolean[count]; // true => ignore name int[] size = newint[count]; // length of name int remaining = count; // number of names remaining boolean hasDotDot = false; // has at least one .. boolean isAbsolute = isAbsolute();
// first pass: // 1. compute length of names // 2. mark all occurrences of "." to ignore // 3. and look for any occurrences of ".." for (int i=0; i<count; i++) { int begin = offsets[i]; int len; if (i == (offsets.length-1)) {
len = path.length - begin;
} else {
len = offsets[i+1] - begin - 1;
}
size[i] = len;
if (path[begin] == '.') { if (len == 1) {
ignore[i] = true; // ignore "."
remaining--;
} else { if (path[begin+1] == '.') // ".." found
hasDotDot = true;
}
}
}
// multiple passes to eliminate all occurrences of name/.. if (hasDotDot) { int prevRemaining; do {
prevRemaining = remaining; int prevName = -1; for (int i=0; i<count; i++) { if (ignore[i]) continue;
// not a ".." if (size[i] != 2) {
prevName = i; continue;
}
int begin = offsets[i]; if (path[begin] != '.' || path[begin+1] != '.') {
prevName = i; continue;
}
// ".." found if (prevName >= 0) { // name/<ignored>/.. found so mark name and ".." to be // ignored
ignore[prevName] = true;
ignore[i] = true;
remaining = remaining - 2;
prevName = -1;
} else { // Case: /<ignored>/.. so mark ".." as ignored if (isAbsolute) { boolean hasPrevious = false; for (int j=0; j<i; j++) { if (!ignore[j]) {
hasPrevious = true; break;
}
} if (!hasPrevious) { // all proceeding names are ignored
ignore[i] = true;
remaining--;
}
}
}
}
} while (prevRemaining > remaining);
}
// no redundant names if (remaining == count) returnthis;
// corner case - all names removed if (remaining == 0) { return isAbsolute ? getFileSystem().rootDirectory() : emptyPath();
}
// compute length of result int len = remaining - 1; if (isAbsolute)
len++;
for (int i=0; i<count; i++) { if (!ignore[i])
len += size[i];
} byte[] result = newbyte[len];
// copy names into result int pos = 0; if (isAbsolute)
result[pos++] = '/'; for (int i=0; i<count; i++) { if (!ignore[i]) {
System.arraycopy(path, offsets[i], result, pos, size[i]);
pos += size[i]; if (--remaining > 0) {
result[pos++] = '/';
}
}
} returnnew UnixPath(getFileSystem(), result);
}
@Override publicboolean startsWith(Path other) { if (!(Objects.requireNonNull(other) instanceof UnixPath)) returnfalse;
UnixPath that = (UnixPath)other;
// other path is longer if (that.path.length > path.length) returnfalse;
int thisOffsetCount = getNameCount(); int thatOffsetCount = that.getNameCount();
// other path has no name elements if (thatOffsetCount == 0 && this.isAbsolute()) { return that.isEmpty() ? false : true;
}
// given path has more elements that this path if (thatOffsetCount > thisOffsetCount) returnfalse;
// same number of elements so must be exact match if ((thatOffsetCount == thisOffsetCount) &&
(path.length != that.path.length)) { returnfalse;
}
// check offsets of elements match for (int i=0; i<thatOffsetCount; i++) {
Integer o1 = offsets[i];
Integer o2 = that.offsets[i]; if (!o1.equals(o2)) returnfalse;
}
// offsets match so need to compare bytes int i=0; while (i < that.path.length) { if (this.path[i] != that.path[i]) returnfalse;
i++;
}
// final check that match is on name boundary if (i < path.length && this.path[i] != '/') returnfalse;
returntrue;
}
@Override publicboolean endsWith(Path other) { if (!(Objects.requireNonNull(other) instanceof UnixPath)) returnfalse;
UnixPath that = (UnixPath)other;
int thisLen = path.length; int thatLen = that.path.length;
// other path is longer if (thatLen > thisLen) returnfalse;
// other path is the empty path if (thisLen > 0 && thatLen == 0) returnfalse;
// other path is absolute so this path must be absolute if (that.isAbsolute() && !this.isAbsolute()) returnfalse;
int thisOffsetCount = getNameCount(); int thatOffsetCount = that.getNameCount();
// given path has more elements that this path if (thatOffsetCount > thisOffsetCount) { returnfalse;
} else { // same number of elements if (thatOffsetCount == thisOffsetCount) { if (thisOffsetCount == 0) returntrue; int expectedLen = thisLen; if (this.isAbsolute() && !that.isAbsolute())
expectedLen--; if (thatLen != expectedLen) returnfalse;
} else { // this path has more elements so given path must be relative if (that.isAbsolute()) returnfalse;
}
}
// compare bytes int thisPos = offsets[thisOffsetCount - thatOffsetCount]; int thatPos = that.offsets[0]; if ((thatLen - thatPos) != (thisLen - thisPos)) returnfalse; while (thatPos < thatLen) { if (this.path[thisPos++] != that.path[thatPos++]) returnfalse;
}
returntrue;
}
@Override publicint compareTo(Path other) { int len1 = path.length; int len2 = ((UnixPath) other).path.length;
int n = Math.min(len1, len2); byte v1[] = path; byte v2[] = ((UnixPath) other).path;
int k = 0; while (k < n) { int c1 = v1[k] & 0xff; int c2 = v2[k] & 0xff; if (c1 != c2) { return c1 - c2;
}
k++;
} return len1 - len2;
}
@Override publicint hashCode() { // OK if two or more threads compute hash int h = hash; if (h == 0) { for (int i = 0; i< path.length; i++) {
h = 31*h + (path[i] & 0xff);
}
hash = h;
} return h;
}
@Override public String toString() { // OK if two or more threads create a String if (stringValue == null) {
stringValue = fs.normalizeJavaPath(Util.toString(path)); // platform encoding
} return stringValue;
}
// -- file operations --
// package-private int openForAttributeAccess(boolean followLinks) throws UnixException { int flags = O_RDONLY; if (!followLinks) { if (O_NOFOLLOW == 0) thrownew UnixException
("NOFOLLOW_LINKS is not supported on this platform");
flags |= O_NOFOLLOW;
} return open(this, flags, 0);
}
void checkRead() {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager(); if (sm != null)
sm.checkRead(getPathForPermissionCheck());
}
void checkWrite() {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager(); if (sm != null)
sm.checkWrite(getPathForPermissionCheck());
}
void checkDelete() {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager(); if (sm != null)
sm.checkDelete(getPathForPermissionCheck());
}
@Override public UnixPath toAbsolutePath() { if (isAbsolute()) { returnthis;
} // The path is relative so need to resolve against default directory, // taking care not to reveal the user.dir
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager(); if (sm != null) {
sm.checkPropertyAccess("user.dir");
} returnnew UnixPath(getFileSystem(),
resolve(getFileSystem().defaultDirectory(), path));
}
@Override public Path toRealPath(LinkOption... options) throws IOException {
checkRead();
UnixPath absolute = toAbsolutePath();
// if resolving links then use realpath if (Util.followLinks(options)) { try { byte[] rp = realpath(absolute); returnnew UnixPath(getFileSystem(), rp);
} catch (UnixException x) {
x.rethrowAsIOException(this);
}
}
// if not resolving links then eliminate "." and also ".." // where the previous element is not a link.
UnixPath result = fs.rootDirectory(); for (int i = 0; i < absolute.getNameCount(); i++) {
UnixPath element = absolute.getName(i);
// Return if the file system is not both case insensitive and retentive if (!fs.isCaseInsensitiveAndPreserving()) return result;
UnixPath path = fs.rootDirectory();
// Traverse the result obtained above from the root downward, leaving // any '..' elements intact, and replacing other elements with the // entry in the same directory which has an equal key for (int i = 0; i < result.getNameCount(); i++ ) {
UnixPath element = result.getName(i);
// If the element is "..", append it directly and continue if (element.toString().equals("..")) {
path = path.resolve(element); continue;
}
// Derive full path to element and check readability
UnixPath elementPath = path.resolve(element);
// Obtain the file key of elementPath
UnixFileAttributes attrs = null; try {
attrs = UnixFileAttributes.get(elementPath, false);
} catch (UnixException x) {
x.rethrowAsIOException(result);
} final UnixFileKey elementKey = attrs.fileKey();
// Obtain the stream of entries in the directory corresponding // to the path constructed thus far, and extract the entry whose // key is equal to the key of the current element
FileSystemProvider provider = getFileSystem().provider();
DirectoryStream.Filter<Path> filter = (p) -> { returntrue; }; try (DirectoryStream<Path> entries = provider.newDirectoryStream(path, filter)) { boolean found = false; for (Path entry : entries) {
UnixPath p = path.resolve(entry.getFileName());
UnixFileAttributes attributes = null; try {
attributes = UnixFileAttributes.get(p, false);
UnixFileKey key = attributes.fileKey(); if (key.equals(elementKey)) {
path = path.resolve(entry);
found = true; break;
}
} catch (UnixException ignore) { continue;
}
}
// Fallback which should in theory never happen if (!found) {
path = path.resolve(element);
}
}
}
return path;
}
@Override public URI toUri() { return UnixUriUtils.toUri(this);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.