mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
40
src/java.base/unix/classes/java/io/DefaultFileSystem.java
Normal file
40
src/java.base/unix/classes/java/io/DefaultFileSystem.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*/
|
||||
|
||||
package java.io;
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
class DefaultFileSystem {
|
||||
|
||||
/**
|
||||
* Return the FileSystem object for Unix-based platform.
|
||||
*/
|
||||
public static FileSystem getFileSystem() {
|
||||
return new UnixFileSystem();
|
||||
}
|
||||
}
|
247
src/java.base/unix/classes/java/io/FileDescriptor.java
Normal file
247
src/java.base/unix/classes/java/io/FileDescriptor.java
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2015, 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.
|
||||
*/
|
||||
|
||||
package java.io;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jdk.internal.misc.JavaIOFileDescriptorAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
|
||||
/**
|
||||
* Instances of the file descriptor class serve as an opaque handle
|
||||
* to the underlying machine-specific structure representing an open
|
||||
* file, an open socket, or another source or sink of bytes. The
|
||||
* main practical use for a file descriptor is to create a
|
||||
* <code>FileInputStream</code> or <code>FileOutputStream</code> to
|
||||
* contain it.
|
||||
* <p>
|
||||
* Applications should not create their own file descriptors.
|
||||
*
|
||||
* @author Pavani Diwanji
|
||||
* @see java.io.FileInputStream
|
||||
* @see java.io.FileOutputStream
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class FileDescriptor {
|
||||
|
||||
private int fd;
|
||||
|
||||
private Closeable parent;
|
||||
private List<Closeable> otherParents;
|
||||
private boolean closed;
|
||||
|
||||
/**
|
||||
* true, if file is opened for appending.
|
||||
*/
|
||||
private boolean append;
|
||||
|
||||
/**
|
||||
* Constructs an (invalid) FileDescriptor
|
||||
* object.
|
||||
*/
|
||||
public FileDescriptor() {
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
private FileDescriptor(int fd) {
|
||||
this.fd = fd;
|
||||
this.append = getAppend(fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* A handle to the standard input stream. Usually, this file
|
||||
* descriptor is not used directly, but rather via the input stream
|
||||
* known as <code>System.in</code>.
|
||||
*
|
||||
* @see java.lang.System#in
|
||||
*/
|
||||
public static final FileDescriptor in = new FileDescriptor(0);
|
||||
|
||||
/**
|
||||
* A handle to the standard output stream. Usually, this file
|
||||
* descriptor is not used directly, but rather via the output stream
|
||||
* known as <code>System.out</code>.
|
||||
* @see java.lang.System#out
|
||||
*/
|
||||
public static final FileDescriptor out = new FileDescriptor(1);
|
||||
|
||||
/**
|
||||
* A handle to the standard error stream. Usually, this file
|
||||
* descriptor is not used directly, but rather via the output stream
|
||||
* known as <code>System.err</code>.
|
||||
*
|
||||
* @see java.lang.System#err
|
||||
*/
|
||||
public static final FileDescriptor err = new FileDescriptor(2);
|
||||
|
||||
/**
|
||||
* Tests if this file descriptor object is valid.
|
||||
*
|
||||
* @return <code>true</code> if the file descriptor object represents a
|
||||
* valid, open file, socket, or other active I/O connection;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean valid() {
|
||||
return fd != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force all system buffers to synchronize with the underlying
|
||||
* device. This method returns after all modified data and
|
||||
* attributes of this FileDescriptor have been written to the
|
||||
* relevant device(s). In particular, if this FileDescriptor
|
||||
* refers to a physical storage medium, such as a file in a file
|
||||
* system, sync will not return until all in-memory modified copies
|
||||
* of buffers associated with this FileDescriptor have been
|
||||
* written to the physical medium.
|
||||
*
|
||||
* sync is meant to be used by code that requires physical
|
||||
* storage (such as a file) to be in a known state For
|
||||
* example, a class that provided a simple transaction facility
|
||||
* might use sync to ensure that all changes to a file caused
|
||||
* by a given transaction were recorded on a storage medium.
|
||||
*
|
||||
* sync only affects buffers downstream of this FileDescriptor. If
|
||||
* any in-memory buffering is being done by the application (for
|
||||
* example, by a BufferedOutputStream object), those buffers must
|
||||
* be flushed into the FileDescriptor (for example, by invoking
|
||||
* OutputStream.flush) before that data will be affected by sync.
|
||||
*
|
||||
* @exception SyncFailedException
|
||||
* Thrown when the buffers cannot be flushed,
|
||||
* or because the system cannot guarantee that all the
|
||||
* buffers have been synchronized with physical media.
|
||||
* @since 1.1
|
||||
*/
|
||||
public native void sync() throws SyncFailedException;
|
||||
|
||||
/* This routine initializes JNI field offsets for the class */
|
||||
private static native void initIDs();
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
|
||||
// Set up JavaIOFileDescriptorAccess in SharedSecrets
|
||||
static {
|
||||
SharedSecrets.setJavaIOFileDescriptorAccess(
|
||||
new JavaIOFileDescriptorAccess() {
|
||||
public void set(FileDescriptor obj, int fd) {
|
||||
obj.fd = fd;
|
||||
}
|
||||
|
||||
public int get(FileDescriptor obj) {
|
||||
return obj.fd;
|
||||
}
|
||||
|
||||
public void setAppend(FileDescriptor obj, boolean append) {
|
||||
obj.append = append;
|
||||
}
|
||||
|
||||
public boolean getAppend(FileDescriptor obj) {
|
||||
return obj.append;
|
||||
}
|
||||
|
||||
public void setHandle(FileDescriptor obj, long handle) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public long getHandle(FileDescriptor obj) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if the file was opened for appending.
|
||||
*/
|
||||
private static native boolean getAppend(int fd);
|
||||
|
||||
/*
|
||||
* Package private methods to track referents.
|
||||
* If multiple streams point to the same FileDescriptor, we cycle
|
||||
* through the list of all referents and call close()
|
||||
*/
|
||||
|
||||
/**
|
||||
* Attach a Closeable to this FD for tracking.
|
||||
* parent reference is added to otherParents when
|
||||
* needed to make closeAll simpler.
|
||||
*/
|
||||
synchronized void attach(Closeable c) {
|
||||
if (parent == null) {
|
||||
// first caller gets to do this
|
||||
parent = c;
|
||||
} else if (otherParents == null) {
|
||||
otherParents = new ArrayList<>();
|
||||
otherParents.add(parent);
|
||||
otherParents.add(c);
|
||||
} else {
|
||||
otherParents.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycle through all Closeables sharing this FD and call
|
||||
* close() on each one.
|
||||
*
|
||||
* The caller closeable gets to call close0().
|
||||
*/
|
||||
@SuppressWarnings("try")
|
||||
synchronized void closeAll(Closeable releaser) throws IOException {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
IOException ioe = null;
|
||||
try (releaser) {
|
||||
if (otherParents != null) {
|
||||
for (Closeable referent : otherParents) {
|
||||
try {
|
||||
referent.close();
|
||||
} catch(IOException x) {
|
||||
if (ioe == null) {
|
||||
ioe = x;
|
||||
} else {
|
||||
ioe.addSuppressed(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(IOException ex) {
|
||||
/*
|
||||
* If releaser close() throws IOException
|
||||
* add other exceptions as suppressed.
|
||||
*/
|
||||
if (ioe != null)
|
||||
ex.addSuppressed(ioe);
|
||||
ioe = ex;
|
||||
} finally {
|
||||
if (ioe != null)
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
327
src/java.base/unix/classes/java/io/UnixFileSystem.java
Normal file
327
src/java.base/unix/classes/java/io/UnixFileSystem.java
Normal file
|
@ -0,0 +1,327 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2016, 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.
|
||||
*/
|
||||
|
||||
package java.io;
|
||||
|
||||
import java.util.Properties;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
|
||||
class UnixFileSystem extends FileSystem {
|
||||
|
||||
private final char slash;
|
||||
private final char colon;
|
||||
private final String javaHome;
|
||||
|
||||
public UnixFileSystem() {
|
||||
Properties props = GetPropertyAction.privilegedGetProperties();
|
||||
slash = props.getProperty("file.separator").charAt(0);
|
||||
colon = props.getProperty("path.separator").charAt(0);
|
||||
javaHome = props.getProperty("java.home");
|
||||
}
|
||||
|
||||
|
||||
/* -- Normalization and construction -- */
|
||||
|
||||
public char getSeparator() {
|
||||
return slash;
|
||||
}
|
||||
|
||||
public char getPathSeparator() {
|
||||
return colon;
|
||||
}
|
||||
|
||||
/* A normal Unix pathname contains no duplicate slashes and does not end
|
||||
with a slash. It may be the empty string. */
|
||||
|
||||
/* Normalize the given pathname, whose length is len, starting at the given
|
||||
offset; everything before this offset is already normal. */
|
||||
private String normalize(String pathname, int len, int off) {
|
||||
if (len == 0) return pathname;
|
||||
int n = len;
|
||||
while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;
|
||||
if (n == 0) return "/";
|
||||
StringBuilder sb = new StringBuilder(pathname.length());
|
||||
if (off > 0) sb.append(pathname, 0, off);
|
||||
char prevChar = 0;
|
||||
for (int i = off; i < n; i++) {
|
||||
char c = pathname.charAt(i);
|
||||
if ((prevChar == '/') && (c == '/')) continue;
|
||||
sb.append(c);
|
||||
prevChar = c;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/* Check that the given pathname is normal. If not, invoke the real
|
||||
normalizer on the part of the pathname that requires normalization.
|
||||
This way we iterate through the whole pathname string only once. */
|
||||
public String normalize(String pathname) {
|
||||
int n = pathname.length();
|
||||
char prevChar = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = pathname.charAt(i);
|
||||
if ((prevChar == '/') && (c == '/'))
|
||||
return normalize(pathname, n, i - 1);
|
||||
prevChar = c;
|
||||
}
|
||||
if (prevChar == '/') return normalize(pathname, n, n - 1);
|
||||
return pathname;
|
||||
}
|
||||
|
||||
public int prefixLength(String pathname) {
|
||||
if (pathname.length() == 0) return 0;
|
||||
return (pathname.charAt(0) == '/') ? 1 : 0;
|
||||
}
|
||||
|
||||
public String resolve(String parent, String child) {
|
||||
if (child.equals("")) return parent;
|
||||
if (child.charAt(0) == '/') {
|
||||
if (parent.equals("/")) return child;
|
||||
return parent + child;
|
||||
}
|
||||
if (parent.equals("/")) return parent + child;
|
||||
return parent + '/' + child;
|
||||
}
|
||||
|
||||
public String getDefaultParent() {
|
||||
return "/";
|
||||
}
|
||||
|
||||
public String fromURIPath(String path) {
|
||||
String p = path;
|
||||
if (p.endsWith("/") && (p.length() > 1)) {
|
||||
// "/foo/" --> "/foo", but "/" --> "/"
|
||||
p = p.substring(0, p.length() - 1);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/* -- Path operations -- */
|
||||
|
||||
public boolean isAbsolute(File f) {
|
||||
return (f.getPrefixLength() != 0);
|
||||
}
|
||||
|
||||
public String resolve(File f) {
|
||||
if (isAbsolute(f)) return f.getPath();
|
||||
return resolve(System.getProperty("user.dir"), f.getPath());
|
||||
}
|
||||
|
||||
// Caches for canonicalization results to improve startup performance.
|
||||
// The first cache handles repeated canonicalizations of the same path
|
||||
// name. The prefix cache handles repeated canonicalizations within the
|
||||
// same directory, and must not create results differing from the true
|
||||
// canonicalization algorithm in canonicalize_md.c. For this reason the
|
||||
// prefix cache is conservative and is not used for complex path names.
|
||||
private ExpiringCache cache = new ExpiringCache();
|
||||
// On Unix symlinks can jump anywhere in the file system, so we only
|
||||
// treat prefixes in java.home as trusted and cacheable in the
|
||||
// canonicalization algorithm
|
||||
private ExpiringCache javaHomePrefixCache = new ExpiringCache();
|
||||
|
||||
public String canonicalize(String path) throws IOException {
|
||||
if (!useCanonCaches) {
|
||||
return canonicalize0(path);
|
||||
} else {
|
||||
String res = cache.get(path);
|
||||
if (res == null) {
|
||||
String dir = null;
|
||||
String resDir = null;
|
||||
if (useCanonPrefixCache) {
|
||||
// Note that this can cause symlinks that should
|
||||
// be resolved to a destination directory to be
|
||||
// resolved to the directory they're contained in
|
||||
dir = parentOrNull(path);
|
||||
if (dir != null) {
|
||||
resDir = javaHomePrefixCache.get(dir);
|
||||
if (resDir != null) {
|
||||
// Hit only in prefix cache; full path is canonical
|
||||
String filename = path.substring(1 + dir.length());
|
||||
res = resDir + slash + filename;
|
||||
cache.put(dir + slash + filename, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res == null) {
|
||||
res = canonicalize0(path);
|
||||
cache.put(path, res);
|
||||
if (useCanonPrefixCache &&
|
||||
dir != null && dir.startsWith(javaHome)) {
|
||||
resDir = parentOrNull(res);
|
||||
// Note that we don't allow a resolved symlink
|
||||
// to elsewhere in java.home to pollute the
|
||||
// prefix cache (java.home prefix cache could
|
||||
// just as easily be a set at this point)
|
||||
if (resDir != null && resDir.equals(dir)) {
|
||||
File f = new File(res);
|
||||
if (f.exists() && !f.isDirectory()) {
|
||||
javaHomePrefixCache.put(dir, resDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
private native String canonicalize0(String path) throws IOException;
|
||||
// Best-effort attempt to get parent of this path; used for
|
||||
// optimization of filename canonicalization. This must return null for
|
||||
// any cases where the code in canonicalize_md.c would throw an
|
||||
// exception or otherwise deal with non-simple pathnames like handling
|
||||
// of "." and "..". It may conservatively return null in other
|
||||
// situations as well. Returning null will cause the underlying
|
||||
// (expensive) canonicalization routine to be called.
|
||||
static String parentOrNull(String path) {
|
||||
if (path == null) return null;
|
||||
char sep = File.separatorChar;
|
||||
int last = path.length() - 1;
|
||||
int idx = last;
|
||||
int adjacentDots = 0;
|
||||
int nonDotCount = 0;
|
||||
while (idx > 0) {
|
||||
char c = path.charAt(idx);
|
||||
if (c == '.') {
|
||||
if (++adjacentDots >= 2) {
|
||||
// Punt on pathnames containing . and ..
|
||||
return null;
|
||||
}
|
||||
} else if (c == sep) {
|
||||
if (adjacentDots == 1 && nonDotCount == 0) {
|
||||
// Punt on pathnames containing . and ..
|
||||
return null;
|
||||
}
|
||||
if (idx == 0 ||
|
||||
idx >= last - 1 ||
|
||||
path.charAt(idx - 1) == sep) {
|
||||
// Punt on pathnames containing adjacent slashes
|
||||
// toward the end
|
||||
return null;
|
||||
}
|
||||
return path.substring(0, idx);
|
||||
} else {
|
||||
++nonDotCount;
|
||||
adjacentDots = 0;
|
||||
}
|
||||
--idx;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* -- Attribute accessors -- */
|
||||
|
||||
public native int getBooleanAttributes0(File f);
|
||||
|
||||
public int getBooleanAttributes(File f) {
|
||||
int rv = getBooleanAttributes0(f);
|
||||
String name = f.getName();
|
||||
boolean hidden = (name.length() > 0) && (name.charAt(0) == '.');
|
||||
return rv | (hidden ? BA_HIDDEN : 0);
|
||||
}
|
||||
|
||||
public native boolean checkAccess(File f, int access);
|
||||
public native long getLastModifiedTime(File f);
|
||||
public native long getLength(File f);
|
||||
public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);
|
||||
|
||||
/* -- File operations -- */
|
||||
|
||||
public native boolean createFileExclusively(String path)
|
||||
throws IOException;
|
||||
public boolean delete(File f) {
|
||||
// Keep canonicalization caches in sync after file deletion
|
||||
// and renaming operations. Could be more clever than this
|
||||
// (i.e., only remove/update affected entries) but probably
|
||||
// not worth it since these entries expire after 30 seconds
|
||||
// anyway.
|
||||
cache.clear();
|
||||
javaHomePrefixCache.clear();
|
||||
return delete0(f);
|
||||
}
|
||||
private native boolean delete0(File f);
|
||||
public native String[] list(File f);
|
||||
public native boolean createDirectory(File f);
|
||||
public boolean rename(File f1, File f2) {
|
||||
// Keep canonicalization caches in sync after file deletion
|
||||
// and renaming operations. Could be more clever than this
|
||||
// (i.e., only remove/update affected entries) but probably
|
||||
// not worth it since these entries expire after 30 seconds
|
||||
// anyway.
|
||||
cache.clear();
|
||||
javaHomePrefixCache.clear();
|
||||
return rename0(f1, f2);
|
||||
}
|
||||
private native boolean rename0(File f1, File f2);
|
||||
public native boolean setLastModifiedTime(File f, long time);
|
||||
public native boolean setReadOnly(File f);
|
||||
|
||||
|
||||
/* -- Filesystem interface -- */
|
||||
|
||||
public File[] listRoots() {
|
||||
try {
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkRead("/");
|
||||
}
|
||||
return new File[] { new File("/") };
|
||||
} catch (SecurityException x) {
|
||||
return new File[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* -- Disk usage -- */
|
||||
public native long getSpace(File f, int t);
|
||||
|
||||
/* -- Basic infrastructure -- */
|
||||
|
||||
private native long getNameMax0(String path);
|
||||
|
||||
public int getNameMax(String path) {
|
||||
long nameMax = getNameMax0(path);
|
||||
if (nameMax > Integer.MAX_VALUE) {
|
||||
nameMax = Integer.MAX_VALUE;
|
||||
}
|
||||
return (int)nameMax;
|
||||
}
|
||||
|
||||
public int compare(File f1, File f2) {
|
||||
return f1.getPath().compareTo(f2.getPath());
|
||||
}
|
||||
|
||||
public int hashCode(File f) {
|
||||
return f.getPath().hashCode() ^ 1234321;
|
||||
}
|
||||
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue