mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +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
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.spi.FileTypeDetector;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
|
||||
public class DefaultFileTypeDetector {
|
||||
private DefaultFileTypeDetector() { }
|
||||
|
||||
public static FileTypeDetector create() {
|
||||
FileSystemProvider provider = FileSystems.getDefault().provider();
|
||||
return ((UnixFileSystemProvider)provider).getFileTypeDetector();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Copyright (c) 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 sun.nio.fs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* File type detector that uses a file extension to look up its MIME type
|
||||
* based on a mime.types file.
|
||||
*/
|
||||
|
||||
class MimeTypesFileTypeDetector extends AbstractFileTypeDetector {
|
||||
|
||||
// path to mime.types file
|
||||
private final Path mimeTypesFile;
|
||||
|
||||
// map of extension to MIME type
|
||||
private Map<String,String> mimeTypeMap;
|
||||
|
||||
// set to true when file loaded
|
||||
private volatile boolean loaded;
|
||||
|
||||
public MimeTypesFileTypeDetector(Path filePath) {
|
||||
mimeTypesFile = filePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String implProbeContentType(Path path) {
|
||||
Path fn = path.getFileName();
|
||||
if (fn == null)
|
||||
return null; // no file name
|
||||
|
||||
String ext = getExtension(fn.toString());
|
||||
if (ext.isEmpty())
|
||||
return null; // no extension
|
||||
|
||||
loadMimeTypes();
|
||||
if (mimeTypeMap == null || mimeTypeMap.isEmpty())
|
||||
return null;
|
||||
|
||||
// Case-sensitive search
|
||||
String mimeType;
|
||||
do {
|
||||
mimeType = mimeTypeMap.get(ext);
|
||||
if (mimeType == null)
|
||||
ext = getExtension(ext);
|
||||
} while (mimeType == null && !ext.isEmpty());
|
||||
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the mime types file, and store the type-extension mappings into
|
||||
* mimeTypeMap. The mime types file is not loaded until the first probe
|
||||
* to achieve the lazy initialization. It adopts double-checked locking
|
||||
* optimization to reduce the locking overhead.
|
||||
*/
|
||||
private void loadMimeTypes() {
|
||||
if (!loaded) {
|
||||
synchronized (this) {
|
||||
if (!loaded) {
|
||||
List<String> lines = AccessController.doPrivileged(
|
||||
new PrivilegedAction<>() {
|
||||
@Override
|
||||
public List<String> run() {
|
||||
try {
|
||||
return Files.readAllLines(mimeTypesFile,
|
||||
Charset.defaultCharset());
|
||||
} catch (IOException ignore) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mimeTypeMap = new HashMap<>(lines.size());
|
||||
String entry = "";
|
||||
for (String line : lines) {
|
||||
entry += line;
|
||||
if (entry.endsWith("\\")) {
|
||||
entry = entry.substring(0, entry.length() - 1);
|
||||
continue;
|
||||
}
|
||||
parseMimeEntry(entry);
|
||||
entry = "";
|
||||
}
|
||||
if (!entry.isEmpty()) {
|
||||
parseMimeEntry(entry);
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a mime-types entry, which can have the following formats.
|
||||
* 1) Simple space-delimited format
|
||||
* image/jpeg jpeg jpg jpe JPG
|
||||
*
|
||||
* 2) Netscape key-value pair format
|
||||
* type=application/x-java-jnlp-file desc="Java Web Start" exts="jnlp"
|
||||
* or
|
||||
* type=text/html exts=htm,html
|
||||
*/
|
||||
private void parseMimeEntry(String entry) {
|
||||
entry = entry.trim();
|
||||
if (entry.isEmpty() || entry.charAt(0) == '#')
|
||||
return;
|
||||
|
||||
entry = entry.replaceAll("\\s*#.*", "");
|
||||
int equalIdx = entry.indexOf('=');
|
||||
if (equalIdx > 0) {
|
||||
// Parse a mime-types command having the key-value pair format
|
||||
final String TYPEEQUAL = "type=";
|
||||
String typeRegex = "\\b" + TYPEEQUAL +
|
||||
"(\"\\p{Graph}+?/\\p{Graph}+?\"|\\p{Graph}+/\\p{Graph}+\\b)";
|
||||
Pattern typePattern = Pattern.compile(typeRegex);
|
||||
Matcher typeMatcher = typePattern.matcher(entry);
|
||||
|
||||
if (typeMatcher.find()) {
|
||||
String type = typeMatcher.group().substring(TYPEEQUAL.length());
|
||||
if (type.charAt(0) == '"') {
|
||||
type = type.substring(1, type.length() - 1);
|
||||
}
|
||||
|
||||
final String EXTEQUAL = "exts=";
|
||||
String extRegex = "\\b" + EXTEQUAL +
|
||||
"(\"[\\p{Graph}\\p{Blank}]+?\"|\\p{Graph}+\\b)";
|
||||
Pattern extPattern = Pattern.compile(extRegex);
|
||||
Matcher extMatcher = extPattern.matcher(entry);
|
||||
|
||||
if (extMatcher.find()) {
|
||||
String exts =
|
||||
extMatcher.group().substring(EXTEQUAL.length());
|
||||
if (exts.charAt(0) == '"') {
|
||||
exts = exts.substring(1, exts.length() - 1);
|
||||
}
|
||||
String[] extList = exts.split("[\\p{Blank}\\p{Punct}]+");
|
||||
for (String ext : extList) {
|
||||
putIfAbsent(ext, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Parse a mime-types command having the space-delimited format
|
||||
String[] elements = entry.split("\\s+");
|
||||
int i = 1;
|
||||
while (i < elements.length) {
|
||||
putIfAbsent(elements[i++], elements[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void putIfAbsent(String key, String value) {
|
||||
if (key != null && !key.isEmpty() &&
|
||||
value != null && !value.isEmpty() &&
|
||||
!mimeTypeMap.containsKey(key))
|
||||
{
|
||||
mimeTypeMap.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
294
src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java
Normal file
294
src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java
Normal file
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.channels.*;
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.JavaIOFileDescriptorAccess;
|
||||
import sun.nio.ch.FileChannelImpl;
|
||||
import sun.nio.ch.ThreadPool;
|
||||
import sun.nio.ch.SimpleAsynchronousFileChannelImpl;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
/**
|
||||
* Factory for FileChannels and AsynchronousFileChannels
|
||||
*/
|
||||
|
||||
class UnixChannelFactory {
|
||||
private static final JavaIOFileDescriptorAccess fdAccess =
|
||||
SharedSecrets.getJavaIOFileDescriptorAccess();
|
||||
|
||||
protected UnixChannelFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the flags from a user-supplied set of open options.
|
||||
*/
|
||||
protected static class Flags {
|
||||
boolean read;
|
||||
boolean write;
|
||||
boolean append;
|
||||
boolean truncateExisting;
|
||||
boolean noFollowLinks;
|
||||
boolean create;
|
||||
boolean createNew;
|
||||
boolean deleteOnClose;
|
||||
boolean sync;
|
||||
boolean dsync;
|
||||
|
||||
static Flags toFlags(Set<? extends OpenOption> options) {
|
||||
Flags flags = new Flags();
|
||||
for (OpenOption option: options) {
|
||||
if (option instanceof StandardOpenOption) {
|
||||
switch ((StandardOpenOption)option) {
|
||||
case READ : flags.read = true; break;
|
||||
case WRITE : flags.write = true; break;
|
||||
case APPEND : flags.append = true; break;
|
||||
case TRUNCATE_EXISTING : flags.truncateExisting = true; break;
|
||||
case CREATE : flags.create = true; break;
|
||||
case CREATE_NEW : flags.createNew = true; break;
|
||||
case DELETE_ON_CLOSE : flags.deleteOnClose = true; break;
|
||||
case SPARSE : /* ignore */ break;
|
||||
case SYNC : flags.sync = true; break;
|
||||
case DSYNC : flags.dsync = true; break;
|
||||
default: throw new UnsupportedOperationException();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (option == LinkOption.NOFOLLOW_LINKS && O_NOFOLLOW != 0) {
|
||||
flags.noFollowLinks = true;
|
||||
continue;
|
||||
}
|
||||
if (option == null)
|
||||
throw new NullPointerException();
|
||||
throw new UnsupportedOperationException(option + " not supported");
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a file channel from an existing (open) file descriptor
|
||||
*/
|
||||
static FileChannel newFileChannel(int fd, String path, boolean reading, boolean writing) {
|
||||
FileDescriptor fdObj = new FileDescriptor();
|
||||
fdAccess.set(fdObj, fd);
|
||||
return FileChannelImpl.open(fdObj, path, reading, writing, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a file channel by opening a file using a dfd/path pair
|
||||
*/
|
||||
static FileChannel newFileChannel(int dfd,
|
||||
UnixPath path,
|
||||
String pathForPermissionCheck,
|
||||
Set<? extends OpenOption> options,
|
||||
int mode)
|
||||
throws UnixException
|
||||
{
|
||||
Flags flags = Flags.toFlags(options);
|
||||
|
||||
// default is reading; append => writing
|
||||
if (!flags.read && !flags.write) {
|
||||
if (flags.append) {
|
||||
flags.write = true;
|
||||
} else {
|
||||
flags.read = true;
|
||||
}
|
||||
}
|
||||
|
||||
// validation
|
||||
if (flags.read && flags.append)
|
||||
throw new IllegalArgumentException("READ + APPEND not allowed");
|
||||
if (flags.append && flags.truncateExisting)
|
||||
throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
|
||||
|
||||
FileDescriptor fdObj = open(dfd, path, pathForPermissionCheck, flags, mode);
|
||||
return FileChannelImpl.open(fdObj, path.toString(), flags.read, flags.write, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a file channel by opening the given file.
|
||||
*/
|
||||
static FileChannel newFileChannel(UnixPath path,
|
||||
Set<? extends OpenOption> options,
|
||||
int mode)
|
||||
throws UnixException
|
||||
{
|
||||
return newFileChannel(-1, path, null, options, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an asynchronous file channel by opening the given file.
|
||||
*/
|
||||
static AsynchronousFileChannel newAsynchronousFileChannel(UnixPath path,
|
||||
Set<? extends OpenOption> options,
|
||||
int mode,
|
||||
ThreadPool pool)
|
||||
throws UnixException
|
||||
{
|
||||
Flags flags = Flags.toFlags(options);
|
||||
|
||||
// default is reading
|
||||
if (!flags.read && !flags.write) {
|
||||
flags.read = true;
|
||||
}
|
||||
|
||||
// validation
|
||||
if (flags.append)
|
||||
throw new UnsupportedOperationException("APPEND not allowed");
|
||||
|
||||
// for now use simple implementation
|
||||
FileDescriptor fdObj = open(-1, path, null, flags, mode);
|
||||
return SimpleAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens file based on parameters and options, returning a FileDescriptor
|
||||
* encapsulating the handle to the open file.
|
||||
*/
|
||||
protected static FileDescriptor open(int dfd,
|
||||
UnixPath path,
|
||||
String pathForPermissionCheck,
|
||||
Flags flags,
|
||||
int mode)
|
||||
throws UnixException
|
||||
{
|
||||
// map to oflags
|
||||
int oflags;
|
||||
if (flags.read && flags.write) {
|
||||
oflags = O_RDWR;
|
||||
} else {
|
||||
oflags = (flags.write) ? O_WRONLY : O_RDONLY;
|
||||
}
|
||||
if (flags.write) {
|
||||
if (flags.truncateExisting)
|
||||
oflags |= O_TRUNC;
|
||||
if (flags.append)
|
||||
oflags |= O_APPEND;
|
||||
|
||||
// create flags
|
||||
if (flags.createNew) {
|
||||
byte[] pathForSysCall = path.asByteArray();
|
||||
|
||||
// throw exception if file name is "." to avoid confusing error
|
||||
if ((pathForSysCall[pathForSysCall.length-1] == '.') &&
|
||||
(pathForSysCall.length == 1 ||
|
||||
(pathForSysCall[pathForSysCall.length-2] == '/')))
|
||||
{
|
||||
throw new UnixException(EEXIST);
|
||||
}
|
||||
oflags |= (O_CREAT | O_EXCL);
|
||||
} else {
|
||||
if (flags.create)
|
||||
oflags |= O_CREAT;
|
||||
}
|
||||
}
|
||||
|
||||
// follow links by default
|
||||
boolean followLinks = true;
|
||||
if (!flags.createNew && (flags.noFollowLinks || flags.deleteOnClose)) {
|
||||
if (flags.deleteOnClose && O_NOFOLLOW == 0) {
|
||||
try {
|
||||
if (UnixFileAttributes.get(path, false).isSymbolicLink())
|
||||
throw new UnixException("DELETE_ON_CLOSE specified and file is a symbolic link");
|
||||
} catch (UnixException x) {
|
||||
if (!flags.create || x.errno() != ENOENT)
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
followLinks = false;
|
||||
oflags |= O_NOFOLLOW;
|
||||
}
|
||||
|
||||
if (flags.dsync)
|
||||
oflags |= O_DSYNC;
|
||||
if (flags.sync)
|
||||
oflags |= O_SYNC;
|
||||
|
||||
// permission check before we open the file
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
if (pathForPermissionCheck == null)
|
||||
pathForPermissionCheck = path.getPathForPermissionCheck();
|
||||
if (flags.read)
|
||||
sm.checkRead(pathForPermissionCheck);
|
||||
if (flags.write)
|
||||
sm.checkWrite(pathForPermissionCheck);
|
||||
if (flags.deleteOnClose)
|
||||
sm.checkDelete(pathForPermissionCheck);
|
||||
}
|
||||
|
||||
int fd;
|
||||
try {
|
||||
if (dfd >= 0) {
|
||||
fd = openat(dfd, path.asByteArray(), oflags, mode);
|
||||
} else {
|
||||
fd = UnixNativeDispatcher.open(path, oflags, mode);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
// Linux error can be EISDIR or EEXIST when file exists
|
||||
if (flags.createNew && (x.errno() == EISDIR)) {
|
||||
x.setError(EEXIST);
|
||||
}
|
||||
|
||||
// handle ELOOP to avoid confusing message
|
||||
if (!followLinks && (x.errno() == ELOOP)) {
|
||||
x = new UnixException(x.getMessage() + " (NOFOLLOW_LINKS specified)");
|
||||
}
|
||||
|
||||
throw x;
|
||||
}
|
||||
|
||||
// unlink file immediately if delete on close. The spec is clear that
|
||||
// an implementation cannot guarantee to unlink the correct file when
|
||||
// replaced by an attacker after it is opened.
|
||||
if (flags.deleteOnClose) {
|
||||
try {
|
||||
if (dfd >= 0) {
|
||||
unlinkat(dfd, path.asByteArray(), 0);
|
||||
} else {
|
||||
unlink(path);
|
||||
}
|
||||
} catch (UnixException ignore) {
|
||||
// best-effort
|
||||
}
|
||||
}
|
||||
|
||||
// create java.io.FileDescriptor
|
||||
FileDescriptor fdObj = new FileDescriptor();
|
||||
fdAccess.set(fdObj, fd);
|
||||
fdAccess.setAppend(fdObj, flags.append);
|
||||
return fdObj;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@END_COPYRIGHT@@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* On Solaris, "sun" is defined as a macro. Undefine to make package
|
||||
declaration valid */
|
||||
#undef sun
|
||||
|
||||
/* To be able to name the Java constants the same as the C constants without
|
||||
having the preprocessor rewrite those identifiers, add PREFIX_ to all
|
||||
identifiers matching a C constant. The PREFIX_ is filtered out in the
|
||||
makefile. */
|
||||
|
||||
@@START_HERE@@
|
||||
|
||||
package sun.nio.fs;
|
||||
class UnixConstants {
|
||||
private UnixConstants() { }
|
||||
static final int PREFIX_O_RDONLY = O_RDONLY;
|
||||
static final int PREFIX_O_WRONLY = O_WRONLY;
|
||||
static final int PREFIX_O_RDWR = O_RDWR;
|
||||
static final int PREFIX_O_APPEND = O_APPEND;
|
||||
static final int PREFIX_O_CREAT = O_CREAT;
|
||||
static final int PREFIX_O_EXCL = O_EXCL;
|
||||
static final int PREFIX_O_TRUNC = O_TRUNC;
|
||||
static final int PREFIX_O_SYNC = O_SYNC;
|
||||
|
||||
#ifndef O_DSYNC
|
||||
// At least FreeBSD doesn't define O_DSYNC
|
||||
static final int PREFIX_O_DSYNC = O_SYNC;
|
||||
#else
|
||||
static final int PREFIX_O_DSYNC = O_DSYNC;
|
||||
#endif
|
||||
|
||||
#ifdef O_NOFOLLOW
|
||||
static final int PREFIX_O_NOFOLLOW = O_NOFOLLOW;
|
||||
#else
|
||||
// not supported (dummy values will not be used at runtime).
|
||||
static final int PREFIX_O_NOFOLLOW = 00;
|
||||
#endif
|
||||
|
||||
|
||||
static final int PREFIX_S_IAMB =
|
||||
(S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
|
||||
static final int PREFIX_S_IRUSR = S_IRUSR;
|
||||
static final int PREFIX_S_IWUSR = S_IWUSR;
|
||||
static final int PREFIX_S_IXUSR = S_IXUSR;
|
||||
static final int PREFIX_S_IRGRP = S_IRGRP;
|
||||
static final int PREFIX_S_IWGRP = S_IWGRP;
|
||||
static final int PREFIX_S_IXGRP = S_IXGRP;
|
||||
static final int PREFIX_S_IROTH = S_IROTH;
|
||||
static final int PREFIX_S_IWOTH = S_IWOTH;
|
||||
static final int PREFIX_S_IXOTH = S_IXOTH;
|
||||
|
||||
static final int PREFIX_S_IFMT = S_IFMT;
|
||||
static final int PREFIX_S_IFREG = S_IFREG;
|
||||
static final int PREFIX_S_IFDIR = S_IFDIR;
|
||||
static final int PREFIX_S_IFLNK = S_IFLNK;
|
||||
static final int PREFIX_S_IFCHR = S_IFCHR;
|
||||
static final int PREFIX_S_IFBLK = S_IFBLK;
|
||||
static final int PREFIX_S_IFIFO = S_IFIFO;
|
||||
static final int PREFIX_R_OK = R_OK;
|
||||
static final int PREFIX_W_OK = W_OK;
|
||||
static final int PREFIX_X_OK = X_OK;
|
||||
static final int PREFIX_F_OK = F_OK;
|
||||
static final int PREFIX_ENOENT = ENOENT;
|
||||
static final int PREFIX_ENXIO = ENXIO;
|
||||
static final int PREFIX_EACCES = EACCES;
|
||||
static final int PREFIX_EEXIST = EEXIST;
|
||||
static final int PREFIX_ENOTDIR = ENOTDIR;
|
||||
static final int PREFIX_EINVAL = EINVAL;
|
||||
static final int PREFIX_EXDEV = EXDEV;
|
||||
static final int PREFIX_EISDIR = EISDIR;
|
||||
static final int PREFIX_ENOTEMPTY = ENOTEMPTY;
|
||||
static final int PREFIX_ENOSPC = ENOSPC;
|
||||
static final int PREFIX_EAGAIN = EAGAIN;
|
||||
static final int PREFIX_ENOSYS = ENOSYS;
|
||||
static final int PREFIX_ELOOP = ELOOP;
|
||||
static final int PREFIX_EROFS = EROFS;
|
||||
|
||||
#ifndef ENODATA
|
||||
// Only used in Linux java source, provide any value so it compiles
|
||||
static final int PREFIX_ENODATA = ELAST;
|
||||
#else
|
||||
static final int PREFIX_ENODATA = ENODATA;
|
||||
#endif
|
||||
|
||||
static final int PREFIX_ERANGE = ERANGE;
|
||||
static final int PREFIX_EMFILE = EMFILE;
|
||||
|
||||
// flags used with openat/unlinkat/etc.
|
||||
#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_REMOVEDIR)
|
||||
static final int PREFIX_AT_SYMLINK_NOFOLLOW = AT_SYMLINK_NOFOLLOW;
|
||||
static final int PREFIX_AT_REMOVEDIR = AT_REMOVEDIR;
|
||||
#else
|
||||
// not supported (dummy values will not be used at runtime).
|
||||
static final int PREFIX_AT_SYMLINK_NOFOLLOW = 00;
|
||||
static final int PREFIX_AT_REMOVEDIR = 00;
|
||||
#endif
|
||||
|
||||
}
|
622
src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java
Normal file
622
src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java
Normal file
|
@ -0,0 +1,622 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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 sun.nio.fs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.AtomicMoveNotSupportedException;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.LinkPermission;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
|
||||
/**
|
||||
* Unix implementation of Path#copyTo and Path#moveTo methods.
|
||||
*/
|
||||
|
||||
class UnixCopyFile {
|
||||
private UnixCopyFile() { }
|
||||
|
||||
// The flags that control how a file is copied or moved
|
||||
private static class Flags {
|
||||
boolean replaceExisting;
|
||||
boolean atomicMove;
|
||||
boolean followLinks;
|
||||
boolean interruptible;
|
||||
|
||||
// the attributes to copy
|
||||
boolean copyBasicAttributes;
|
||||
boolean copyPosixAttributes;
|
||||
boolean copyNonPosixAttributes;
|
||||
|
||||
// flags that indicate if we should fail if attributes cannot be copied
|
||||
boolean failIfUnableToCopyBasic;
|
||||
boolean failIfUnableToCopyPosix;
|
||||
boolean failIfUnableToCopyNonPosix;
|
||||
|
||||
static Flags fromCopyOptions(CopyOption... options) {
|
||||
Flags flags = new Flags();
|
||||
flags.followLinks = true;
|
||||
for (CopyOption option: options) {
|
||||
if (option == StandardCopyOption.REPLACE_EXISTING) {
|
||||
flags.replaceExisting = true;
|
||||
continue;
|
||||
}
|
||||
if (option == LinkOption.NOFOLLOW_LINKS) {
|
||||
flags.followLinks = false;
|
||||
continue;
|
||||
}
|
||||
if (option == StandardCopyOption.COPY_ATTRIBUTES) {
|
||||
// copy all attributes but only fail if basic attributes
|
||||
// cannot be copied
|
||||
flags.copyBasicAttributes = true;
|
||||
flags.copyPosixAttributes = true;
|
||||
flags.copyNonPosixAttributes = true;
|
||||
flags.failIfUnableToCopyBasic = true;
|
||||
continue;
|
||||
}
|
||||
if (ExtendedOptions.INTERRUPTIBLE.matches(option)) {
|
||||
flags.interruptible = true;
|
||||
continue;
|
||||
}
|
||||
if (option == null)
|
||||
throw new NullPointerException();
|
||||
throw new UnsupportedOperationException("Unsupported copy option");
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static Flags fromMoveOptions(CopyOption... options) {
|
||||
Flags flags = new Flags();
|
||||
for (CopyOption option: options) {
|
||||
if (option == StandardCopyOption.ATOMIC_MOVE) {
|
||||
flags.atomicMove = true;
|
||||
continue;
|
||||
}
|
||||
if (option == StandardCopyOption.REPLACE_EXISTING) {
|
||||
flags.replaceExisting = true;
|
||||
continue;
|
||||
}
|
||||
if (option == LinkOption.NOFOLLOW_LINKS) {
|
||||
// ignore
|
||||
continue;
|
||||
}
|
||||
if (option == null)
|
||||
throw new NullPointerException();
|
||||
throw new UnsupportedOperationException("Unsupported copy option");
|
||||
}
|
||||
|
||||
// a move requires that all attributes be copied but only fail if
|
||||
// the basic attributes cannot be copied
|
||||
flags.copyBasicAttributes = true;
|
||||
flags.copyPosixAttributes = true;
|
||||
flags.copyNonPosixAttributes = true;
|
||||
flags.failIfUnableToCopyBasic = true;
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
// copy directory from source to target
|
||||
private static void copyDirectory(UnixPath source,
|
||||
UnixFileAttributes attrs,
|
||||
UnixPath target,
|
||||
Flags flags)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
mkdir(target, attrs.mode());
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
|
||||
// no attributes to copy
|
||||
if (!flags.copyBasicAttributes &&
|
||||
!flags.copyPosixAttributes &&
|
||||
!flags.copyNonPosixAttributes) return;
|
||||
|
||||
// open target directory if possible (this can fail when copying a
|
||||
// directory for which we don't have read access).
|
||||
int dfd = -1;
|
||||
try {
|
||||
dfd = open(target, O_RDONLY, 0);
|
||||
} catch (UnixException x) {
|
||||
// access to target directory required to copy named attributes
|
||||
if (flags.copyNonPosixAttributes && flags.failIfUnableToCopyNonPosix) {
|
||||
try { rmdir(target); } catch (UnixException ignore) { }
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
|
||||
boolean done = false;
|
||||
try {
|
||||
// copy owner/group/permissions
|
||||
if (flags.copyPosixAttributes){
|
||||
try {
|
||||
if (dfd >= 0) {
|
||||
fchown(dfd, attrs.uid(), attrs.gid());
|
||||
fchmod(dfd, attrs.mode());
|
||||
} else {
|
||||
chown(target, attrs.uid(), attrs.gid());
|
||||
chmod(target, attrs.mode());
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
// unable to set owner/group
|
||||
if (flags.failIfUnableToCopyPosix)
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
// copy other attributes
|
||||
if (flags.copyNonPosixAttributes && (dfd >= 0)) {
|
||||
int sfd = -1;
|
||||
try {
|
||||
sfd = open(source, O_RDONLY, 0);
|
||||
} catch (UnixException x) {
|
||||
if (flags.failIfUnableToCopyNonPosix)
|
||||
x.rethrowAsIOException(source);
|
||||
}
|
||||
if (sfd >= 0) {
|
||||
source.getFileSystem().copyNonPosixAttributes(sfd, dfd);
|
||||
close(sfd);
|
||||
}
|
||||
}
|
||||
// copy time stamps last
|
||||
if (flags.copyBasicAttributes) {
|
||||
try {
|
||||
if (dfd >= 0 && futimesSupported()) {
|
||||
futimes(dfd,
|
||||
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
|
||||
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
|
||||
} else {
|
||||
utimes(target,
|
||||
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
|
||||
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
// unable to set times
|
||||
if (flags.failIfUnableToCopyBasic)
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
done = true;
|
||||
} finally {
|
||||
if (dfd >= 0)
|
||||
close(dfd);
|
||||
if (!done) {
|
||||
// rollback
|
||||
try { rmdir(target); } catch (UnixException ignore) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy regular file from source to target
|
||||
private static void copyFile(UnixPath source,
|
||||
UnixFileAttributes attrs,
|
||||
UnixPath target,
|
||||
Flags flags,
|
||||
long addressToPollForCancel)
|
||||
throws IOException
|
||||
{
|
||||
int fi = -1;
|
||||
try {
|
||||
fi = open(source, O_RDONLY, 0);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(source);
|
||||
}
|
||||
|
||||
try {
|
||||
// open new file
|
||||
int fo = -1;
|
||||
try {
|
||||
fo = open(target,
|
||||
(O_WRONLY |
|
||||
O_CREAT |
|
||||
O_EXCL),
|
||||
attrs.mode());
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
|
||||
// set to true when file and attributes copied
|
||||
boolean complete = false;
|
||||
try {
|
||||
// transfer bytes to target file
|
||||
try {
|
||||
transfer(fo, fi, addressToPollForCancel);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(source, target);
|
||||
}
|
||||
// copy owner/permissions
|
||||
if (flags.copyPosixAttributes) {
|
||||
try {
|
||||
fchown(fo, attrs.uid(), attrs.gid());
|
||||
fchmod(fo, attrs.mode());
|
||||
} catch (UnixException x) {
|
||||
if (flags.failIfUnableToCopyPosix)
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
// copy non POSIX attributes (depends on file system)
|
||||
if (flags.copyNonPosixAttributes) {
|
||||
source.getFileSystem().copyNonPosixAttributes(fi, fo);
|
||||
}
|
||||
// copy time attributes
|
||||
if (flags.copyBasicAttributes) {
|
||||
try {
|
||||
if (futimesSupported()) {
|
||||
futimes(fo,
|
||||
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
|
||||
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
|
||||
} else {
|
||||
utimes(target,
|
||||
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
|
||||
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
if (flags.failIfUnableToCopyBasic)
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
complete = true;
|
||||
} finally {
|
||||
close(fo);
|
||||
|
||||
// copy of file or attributes failed so rollback
|
||||
if (!complete) {
|
||||
try {
|
||||
unlink(target);
|
||||
} catch (UnixException ignore) { }
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
close(fi);
|
||||
}
|
||||
}
|
||||
|
||||
// copy symbolic link from source to target
|
||||
private static void copyLink(UnixPath source,
|
||||
UnixFileAttributes attrs,
|
||||
UnixPath target,
|
||||
Flags flags)
|
||||
throws IOException
|
||||
{
|
||||
byte[] linktarget = null;
|
||||
try {
|
||||
linktarget = readlink(source);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(source);
|
||||
}
|
||||
try {
|
||||
symlink(linktarget, target);
|
||||
|
||||
if (flags.copyPosixAttributes) {
|
||||
try {
|
||||
lchown(target, attrs.uid(), attrs.gid());
|
||||
} catch (UnixException x) {
|
||||
// ignore since link attributes not required to be copied
|
||||
}
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
|
||||
// copy special file from source to target
|
||||
private static void copySpecial(UnixPath source,
|
||||
UnixFileAttributes attrs,
|
||||
UnixPath target,
|
||||
Flags flags)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
mknod(target, attrs.mode(), attrs.rdev());
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
boolean done = false;
|
||||
try {
|
||||
if (flags.copyPosixAttributes) {
|
||||
try {
|
||||
chown(target, attrs.uid(), attrs.gid());
|
||||
chmod(target, attrs.mode());
|
||||
} catch (UnixException x) {
|
||||
if (flags.failIfUnableToCopyPosix)
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
if (flags.copyBasicAttributes) {
|
||||
try {
|
||||
utimes(target,
|
||||
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
|
||||
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
|
||||
} catch (UnixException x) {
|
||||
if (flags.failIfUnableToCopyBasic)
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
done = true;
|
||||
} finally {
|
||||
if (!done) {
|
||||
try { unlink(target); } catch (UnixException ignore) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move file from source to target
|
||||
static void move(UnixPath source, UnixPath target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
// permission check
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
source.checkWrite();
|
||||
target.checkWrite();
|
||||
}
|
||||
|
||||
// translate options into flags
|
||||
Flags flags = Flags.fromMoveOptions(options);
|
||||
|
||||
// handle atomic rename case
|
||||
if (flags.atomicMove) {
|
||||
try {
|
||||
rename(source, target);
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() == EXDEV) {
|
||||
throw new AtomicMoveNotSupportedException(
|
||||
source.getPathForExceptionMessage(),
|
||||
target.getPathForExceptionMessage(),
|
||||
x.errorString());
|
||||
}
|
||||
x.rethrowAsIOException(source, target);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// move using rename or copy+delete
|
||||
UnixFileAttributes sourceAttrs = null;
|
||||
UnixFileAttributes targetAttrs = null;
|
||||
|
||||
// get attributes of source file (don't follow links)
|
||||
try {
|
||||
sourceAttrs = UnixFileAttributes.get(source, false);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(source);
|
||||
}
|
||||
|
||||
// get attributes of target file (don't follow links)
|
||||
try {
|
||||
targetAttrs = UnixFileAttributes.get(target, false);
|
||||
} catch (UnixException x) {
|
||||
// ignore
|
||||
}
|
||||
boolean targetExists = (targetAttrs != null);
|
||||
|
||||
// if the target exists:
|
||||
// 1. check if source and target are the same file
|
||||
// 2. throw exception if REPLACE_EXISTING option is not set
|
||||
// 3. delete target if REPLACE_EXISTING option set
|
||||
if (targetExists) {
|
||||
if (sourceAttrs.isSameFile(targetAttrs))
|
||||
return; // nothing to do as files are identical
|
||||
if (!flags.replaceExisting) {
|
||||
throw new FileAlreadyExistsException(
|
||||
target.getPathForExceptionMessage());
|
||||
}
|
||||
|
||||
// attempt to delete target
|
||||
try {
|
||||
if (targetAttrs.isDirectory()) {
|
||||
rmdir(target);
|
||||
} else {
|
||||
unlink(target);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
// target is non-empty directory that can't be replaced.
|
||||
if (targetAttrs.isDirectory() &&
|
||||
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
|
||||
{
|
||||
throw new DirectoryNotEmptyException(
|
||||
target.getPathForExceptionMessage());
|
||||
}
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
|
||||
// first try rename
|
||||
try {
|
||||
rename(source, target);
|
||||
return;
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() != EXDEV && x.errno() != EISDIR) {
|
||||
x.rethrowAsIOException(source, target);
|
||||
}
|
||||
}
|
||||
|
||||
// copy source to target
|
||||
if (sourceAttrs.isDirectory()) {
|
||||
copyDirectory(source, sourceAttrs, target, flags);
|
||||
} else {
|
||||
if (sourceAttrs.isSymbolicLink()) {
|
||||
copyLink(source, sourceAttrs, target, flags);
|
||||
} else {
|
||||
if (sourceAttrs.isDevice()) {
|
||||
copySpecial(source, sourceAttrs, target, flags);
|
||||
} else {
|
||||
copyFile(source, sourceAttrs, target, flags, 0L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete source
|
||||
try {
|
||||
if (sourceAttrs.isDirectory()) {
|
||||
rmdir(source);
|
||||
} else {
|
||||
unlink(source);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
// file was copied but unable to unlink the source file so attempt
|
||||
// to remove the target and throw a reasonable exception
|
||||
try {
|
||||
if (sourceAttrs.isDirectory()) {
|
||||
rmdir(target);
|
||||
} else {
|
||||
unlink(target);
|
||||
}
|
||||
} catch (UnixException ignore) { }
|
||||
|
||||
if (sourceAttrs.isDirectory() &&
|
||||
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
|
||||
{
|
||||
throw new DirectoryNotEmptyException(
|
||||
source.getPathForExceptionMessage());
|
||||
}
|
||||
x.rethrowAsIOException(source);
|
||||
}
|
||||
}
|
||||
|
||||
// copy file from source to target
|
||||
static void copy(final UnixPath source,
|
||||
final UnixPath target,
|
||||
CopyOption... options) throws IOException
|
||||
{
|
||||
// permission checks
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
source.checkRead();
|
||||
target.checkWrite();
|
||||
}
|
||||
|
||||
// translate options into flags
|
||||
final Flags flags = Flags.fromCopyOptions(options);
|
||||
|
||||
UnixFileAttributes sourceAttrs = null;
|
||||
UnixFileAttributes targetAttrs = null;
|
||||
|
||||
// get attributes of source file
|
||||
try {
|
||||
sourceAttrs = UnixFileAttributes.get(source, flags.followLinks);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(source);
|
||||
}
|
||||
|
||||
// if source file is symbolic link then we must check LinkPermission
|
||||
if (sm != null && sourceAttrs.isSymbolicLink()) {
|
||||
sm.checkPermission(new LinkPermission("symbolic"));
|
||||
}
|
||||
|
||||
// get attributes of target file (don't follow links)
|
||||
try {
|
||||
targetAttrs = UnixFileAttributes.get(target, false);
|
||||
} catch (UnixException x) {
|
||||
// ignore
|
||||
}
|
||||
boolean targetExists = (targetAttrs != null);
|
||||
|
||||
// if the target exists:
|
||||
// 1. check if source and target are the same file
|
||||
// 2. throw exception if REPLACE_EXISTING option is not set
|
||||
// 3. try to unlink the target
|
||||
if (targetExists) {
|
||||
if (sourceAttrs.isSameFile(targetAttrs))
|
||||
return; // nothing to do as files are identical
|
||||
if (!flags.replaceExisting)
|
||||
throw new FileAlreadyExistsException(
|
||||
target.getPathForExceptionMessage());
|
||||
try {
|
||||
if (targetAttrs.isDirectory()) {
|
||||
rmdir(target);
|
||||
} else {
|
||||
unlink(target);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
// target is non-empty directory that can't be replaced.
|
||||
if (targetAttrs.isDirectory() &&
|
||||
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
|
||||
{
|
||||
throw new DirectoryNotEmptyException(
|
||||
target.getPathForExceptionMessage());
|
||||
}
|
||||
x.rethrowAsIOException(target);
|
||||
}
|
||||
}
|
||||
|
||||
// do the copy
|
||||
if (sourceAttrs.isDirectory()) {
|
||||
copyDirectory(source, sourceAttrs, target, flags);
|
||||
return;
|
||||
}
|
||||
if (sourceAttrs.isSymbolicLink()) {
|
||||
copyLink(source, sourceAttrs, target, flags);
|
||||
return;
|
||||
}
|
||||
if (!flags.interruptible) {
|
||||
// non-interruptible file copy
|
||||
copyFile(source, sourceAttrs, target, flags, 0L);
|
||||
return;
|
||||
}
|
||||
|
||||
// interruptible file copy
|
||||
final UnixFileAttributes attrsToCopy = sourceAttrs;
|
||||
Cancellable copyTask = new Cancellable() {
|
||||
@Override public void implRun() throws IOException {
|
||||
copyFile(source, attrsToCopy, target, flags,
|
||||
addressToPollForCancel());
|
||||
}
|
||||
};
|
||||
try {
|
||||
Cancellable.runInterruptibly(copyTask);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException)
|
||||
throw (IOException)t;
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
// -- native methods --
|
||||
|
||||
static native void transfer(int dst, int src, long addressToPollForCancel)
|
||||
throws UnixException;
|
||||
|
||||
static {
|
||||
AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
System.loadLibrary("nio");
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
|
||||
}
|
221
src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java
Normal file
221
src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.locks.*;
|
||||
import java.io.IOException;
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
|
||||
/**
|
||||
* Unix implementation of java.nio.file.DirectoryStream
|
||||
*/
|
||||
|
||||
class UnixDirectoryStream
|
||||
implements DirectoryStream<Path>
|
||||
{
|
||||
// path to directory when originally opened
|
||||
private final UnixPath dir;
|
||||
|
||||
// directory pointer (returned by opendir)
|
||||
private final long dp;
|
||||
|
||||
// filter (may be null)
|
||||
private final DirectoryStream.Filter<? super Path> filter;
|
||||
|
||||
// used to coordinate closing of directory stream
|
||||
private final ReentrantReadWriteLock streamLock =
|
||||
new ReentrantReadWriteLock(true);
|
||||
|
||||
// indicates if directory stream is open (synchronize on closeLock)
|
||||
private volatile boolean isClosed;
|
||||
|
||||
// directory iterator
|
||||
private Iterator<Path> iterator;
|
||||
|
||||
/**
|
||||
* Initializes a new instance
|
||||
*/
|
||||
UnixDirectoryStream(UnixPath dir, long dp, DirectoryStream.Filter<? super Path> filter) {
|
||||
this.dir = dir;
|
||||
this.dp = dp;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
protected final UnixPath directory() {
|
||||
return dir;
|
||||
}
|
||||
|
||||
protected final Lock readLock() {
|
||||
return streamLock.readLock();
|
||||
}
|
||||
|
||||
protected final Lock writeLock() {
|
||||
return streamLock.writeLock();
|
||||
}
|
||||
|
||||
protected final boolean isOpen() {
|
||||
return !isClosed;
|
||||
}
|
||||
|
||||
protected final boolean closeImpl() throws IOException {
|
||||
if (!isClosed) {
|
||||
isClosed = true;
|
||||
try {
|
||||
closedir(dp);
|
||||
} catch (UnixException x) {
|
||||
throw new IOException(x.errorString());
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
throws IOException
|
||||
{
|
||||
writeLock().lock();
|
||||
try {
|
||||
closeImpl();
|
||||
} finally {
|
||||
writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected final Iterator<Path> iterator(DirectoryStream<Path> ds) {
|
||||
if (isClosed) {
|
||||
throw new IllegalStateException("Directory stream is closed");
|
||||
}
|
||||
synchronized (this) {
|
||||
if (iterator != null)
|
||||
throw new IllegalStateException("Iterator already obtained");
|
||||
iterator = new UnixDirectoryIterator();
|
||||
return iterator;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Path> iterator() {
|
||||
return iterator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator implementation
|
||||
*/
|
||||
private class UnixDirectoryIterator implements Iterator<Path> {
|
||||
// true when at EOF
|
||||
private boolean atEof;
|
||||
|
||||
// next entry to return
|
||||
private Path nextEntry;
|
||||
|
||||
UnixDirectoryIterator() {
|
||||
atEof = false;
|
||||
}
|
||||
|
||||
// Return true if file name is "." or ".."
|
||||
private boolean isSelfOrParent(byte[] nameAsBytes) {
|
||||
if (nameAsBytes[0] == '.') {
|
||||
if ((nameAsBytes.length == 1) ||
|
||||
(nameAsBytes.length == 2 && nameAsBytes[1] == '.')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns next entry (or null)
|
||||
private Path readNextEntry() {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
for (;;) {
|
||||
byte[] nameAsBytes = null;
|
||||
|
||||
// prevent close while reading
|
||||
readLock().lock();
|
||||
try {
|
||||
if (isOpen()) {
|
||||
nameAsBytes = readdir(dp);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
IOException ioe = x.asIOException(dir);
|
||||
throw new DirectoryIteratorException(ioe);
|
||||
} finally {
|
||||
readLock().unlock();
|
||||
}
|
||||
|
||||
// EOF
|
||||
if (nameAsBytes == null) {
|
||||
atEof = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
// ignore "." and ".."
|
||||
if (!isSelfOrParent(nameAsBytes)) {
|
||||
Path entry = dir.resolve(nameAsBytes);
|
||||
|
||||
// return entry if no filter or filter accepts it
|
||||
try {
|
||||
if (filter == null || filter.accept(entry))
|
||||
return entry;
|
||||
} catch (IOException ioe) {
|
||||
throw new DirectoryIteratorException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean hasNext() {
|
||||
if (nextEntry == null && !atEof)
|
||||
nextEntry = readNextEntry();
|
||||
return nextEntry != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Path next() {
|
||||
Path result;
|
||||
if (nextEntry == null && !atEof) {
|
||||
result = readNextEntry();
|
||||
} else {
|
||||
result = nextEntry;
|
||||
nextEntry = null;
|
||||
}
|
||||
if (result == null)
|
||||
throw new NoSuchElementException();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
122
src/java.base/unix/classes/sun/nio/fs/UnixException.java
Normal file
122
src/java.base/unix/classes/sun/nio/fs/UnixException.java
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Internal exception thrown by native methods when error detected.
|
||||
*/
|
||||
|
||||
class UnixException extends Exception {
|
||||
static final long serialVersionUID = 7227016794320723218L;
|
||||
|
||||
private int errno;
|
||||
private String msg;
|
||||
|
||||
UnixException(int errno) {
|
||||
this.errno = errno;
|
||||
this.msg = null;
|
||||
}
|
||||
|
||||
UnixException(String msg) {
|
||||
this.errno = 0;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
int errno() {
|
||||
return errno;
|
||||
}
|
||||
|
||||
void setError(int errno) {
|
||||
this.errno = errno;
|
||||
this.msg = null;
|
||||
}
|
||||
|
||||
String errorString() {
|
||||
if (msg != null) {
|
||||
return msg;
|
||||
} else {
|
||||
return Util.toString(UnixNativeDispatcher.strerror(errno()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return errorString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable fillInStackTrace() {
|
||||
// This is an internal exception; the stack trace is irrelevant.
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map well known errors to specific exceptions where possible; otherwise
|
||||
* return more general FileSystemException.
|
||||
*/
|
||||
private IOException translateToIOException(String file, String other) {
|
||||
// created with message rather than errno
|
||||
if (msg != null)
|
||||
return new IOException(msg);
|
||||
|
||||
// handle specific cases
|
||||
if (errno() == UnixConstants.EACCES)
|
||||
return new AccessDeniedException(file, other, null);
|
||||
if (errno() == UnixConstants.ENOENT)
|
||||
return new NoSuchFileException(file, other, null);
|
||||
if (errno() == UnixConstants.EEXIST)
|
||||
return new FileAlreadyExistsException(file, other, null);
|
||||
if (errno() == UnixConstants.ELOOP)
|
||||
return new FileSystemException(file, other, errorString()
|
||||
+ " or unable to access attributes of symbolic link");
|
||||
|
||||
// fallback to the more general exception
|
||||
return new FileSystemException(file, other, errorString());
|
||||
}
|
||||
|
||||
void rethrowAsIOException(String file) throws IOException {
|
||||
IOException x = translateToIOException(file, null);
|
||||
throw x;
|
||||
}
|
||||
|
||||
void rethrowAsIOException(UnixPath file, UnixPath other) throws IOException {
|
||||
String a = (file == null) ? null : file.getPathForExceptionMessage();
|
||||
String b = (other == null) ? null : other.getPathForExceptionMessage();
|
||||
IOException x = translateToIOException(a, b);
|
||||
throw x;
|
||||
}
|
||||
|
||||
void rethrowAsIOException(UnixPath file) throws IOException {
|
||||
rethrowAsIOException(file, null);
|
||||
}
|
||||
|
||||
IOException asIOException(UnixPath file) {
|
||||
return translateToIOException(file.getPathForExceptionMessage(), null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.io.IOException;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
|
||||
class UnixFileAttributeViews {
|
||||
|
||||
static class Basic extends AbstractBasicFileAttributeView {
|
||||
protected final UnixPath file;
|
||||
protected final boolean followLinks;
|
||||
|
||||
Basic(UnixPath file, boolean followLinks) {
|
||||
this.file = file;
|
||||
this.followLinks = followLinks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicFileAttributes readAttributes() throws IOException {
|
||||
file.checkRead();
|
||||
try {
|
||||
UnixFileAttributes attrs =
|
||||
UnixFileAttributes.get(file, followLinks);
|
||||
return attrs.asBasicFileAttributes();
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimes(FileTime lastModifiedTime,
|
||||
FileTime lastAccessTime,
|
||||
FileTime createTime) throws IOException
|
||||
{
|
||||
// null => don't change
|
||||
if (lastModifiedTime == null && lastAccessTime == null) {
|
||||
// no effect
|
||||
return;
|
||||
}
|
||||
|
||||
// permission check
|
||||
file.checkWrite();
|
||||
|
||||
boolean haveFd = false;
|
||||
boolean useFutimes = false;
|
||||
int fd = -1;
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
if (fd != -1) {
|
||||
haveFd = true;
|
||||
useFutimes = futimesSupported();
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() != UnixConstants.ENXIO) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// assert followLinks || !UnixFileAttributes.get(fd).isSymbolicLink();
|
||||
|
||||
// if not changing both attributes then need existing attributes
|
||||
if (lastModifiedTime == null || lastAccessTime == null) {
|
||||
try {
|
||||
UnixFileAttributes attrs = haveFd ?
|
||||
UnixFileAttributes.get(fd) :
|
||||
UnixFileAttributes.get(file, followLinks);
|
||||
if (lastModifiedTime == null)
|
||||
lastModifiedTime = attrs.lastModifiedTime();
|
||||
if (lastAccessTime == null)
|
||||
lastAccessTime = attrs.lastAccessTime();
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
|
||||
// uptime times
|
||||
long modValue = lastModifiedTime.to(TimeUnit.MICROSECONDS);
|
||||
long accessValue= lastAccessTime.to(TimeUnit.MICROSECONDS);
|
||||
|
||||
boolean retry = false;
|
||||
try {
|
||||
if (useFutimes) {
|
||||
futimes(fd, accessValue, modValue);
|
||||
} else {
|
||||
utimes(file, accessValue, modValue);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
// if futimes/utimes fails with EINVAL and one/both of the times is
|
||||
// negative then we adjust the value to the epoch and retry.
|
||||
if (x.errno() == UnixConstants.EINVAL &&
|
||||
(modValue < 0L || accessValue < 0L)) {
|
||||
retry = true;
|
||||
} else {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
if (retry) {
|
||||
if (modValue < 0L) modValue = 0L;
|
||||
if (accessValue < 0L) accessValue= 0L;
|
||||
try {
|
||||
if (useFutimes) {
|
||||
futimes(fd, accessValue, modValue);
|
||||
} else {
|
||||
utimes(file, accessValue, modValue);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Posix extends Basic implements PosixFileAttributeView {
|
||||
private static final String PERMISSIONS_NAME = "permissions";
|
||||
private static final String OWNER_NAME = "owner";
|
||||
private static final String GROUP_NAME = "group";
|
||||
|
||||
// the names of the posix attributes (includes basic)
|
||||
static final Set<String> posixAttributeNames =
|
||||
Util.newSet(basicAttributeNames, PERMISSIONS_NAME, OWNER_NAME, GROUP_NAME);
|
||||
|
||||
Posix(UnixPath file, boolean followLinks) {
|
||||
super(file, followLinks);
|
||||
}
|
||||
|
||||
final void checkReadExtended() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
file.checkRead();
|
||||
sm.checkPermission(new RuntimePermission("accessUserInformation"));
|
||||
}
|
||||
}
|
||||
|
||||
final void checkWriteExtended() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
file.checkWrite();
|
||||
sm.checkPermission(new RuntimePermission("accessUserInformation"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "posix";
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setAttribute(String attribute, Object value)
|
||||
throws IOException
|
||||
{
|
||||
if (attribute.equals(PERMISSIONS_NAME)) {
|
||||
setPermissions((Set<PosixFilePermission>)value);
|
||||
return;
|
||||
}
|
||||
if (attribute.equals(OWNER_NAME)) {
|
||||
setOwner((UserPrincipal)value);
|
||||
return;
|
||||
}
|
||||
if (attribute.equals(GROUP_NAME)) {
|
||||
setGroup((GroupPrincipal)value);
|
||||
return;
|
||||
}
|
||||
super.setAttribute(attribute, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by readAttributes or sub-classes to add all matching posix
|
||||
* attributes to the builder
|
||||
*/
|
||||
final void addRequestedPosixAttributes(PosixFileAttributes attrs,
|
||||
AttributesBuilder builder)
|
||||
{
|
||||
addRequestedBasicAttributes(attrs, builder);
|
||||
if (builder.match(PERMISSIONS_NAME))
|
||||
builder.add(PERMISSIONS_NAME, attrs.permissions());
|
||||
if (builder.match(OWNER_NAME))
|
||||
builder.add(OWNER_NAME, attrs.owner());
|
||||
if (builder.match(GROUP_NAME))
|
||||
builder.add(GROUP_NAME, attrs.group());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,Object> readAttributes(String[] requested)
|
||||
throws IOException
|
||||
{
|
||||
AttributesBuilder builder =
|
||||
AttributesBuilder.create(posixAttributeNames, requested);
|
||||
PosixFileAttributes attrs = readAttributes();
|
||||
addRequestedPosixAttributes(attrs, builder);
|
||||
return builder.unmodifiableMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixFileAttributes readAttributes() throws IOException {
|
||||
checkReadExtended();
|
||||
try {
|
||||
return UnixFileAttributes.get(file, followLinks);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
// chmod
|
||||
final void setMode(int mode) throws IOException {
|
||||
checkWriteExtended();
|
||||
try {
|
||||
if (followLinks) {
|
||||
chmod(file, mode);
|
||||
} else {
|
||||
int fd = file.openForAttributeAccess(false);
|
||||
try {
|
||||
fchmod(fd, mode);
|
||||
} finally {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
|
||||
// chown
|
||||
final void setOwners(int uid, int gid) throws IOException {
|
||||
checkWriteExtended();
|
||||
try {
|
||||
if (followLinks) {
|
||||
chown(file, uid, gid);
|
||||
} else {
|
||||
lchown(file, uid, gid);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermissions(Set<PosixFilePermission> perms)
|
||||
throws IOException
|
||||
{
|
||||
setMode(UnixFileModeAttribute.toUnixMode(perms));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwner(UserPrincipal owner)
|
||||
throws IOException
|
||||
{
|
||||
if (owner == null)
|
||||
throw new NullPointerException("'owner' is null");
|
||||
if (!(owner instanceof UnixUserPrincipals.User))
|
||||
throw new ProviderMismatchException();
|
||||
if (owner instanceof UnixUserPrincipals.Group)
|
||||
throw new IOException("'owner' parameter can't be a group");
|
||||
int uid = ((UnixUserPrincipals.User)owner).uid();
|
||||
setOwners(uid, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserPrincipal getOwner() throws IOException {
|
||||
return readAttributes().owner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroup(GroupPrincipal group)
|
||||
throws IOException
|
||||
{
|
||||
if (group == null)
|
||||
throw new NullPointerException("'owner' is null");
|
||||
if (!(group instanceof UnixUserPrincipals.Group))
|
||||
throw new ProviderMismatchException();
|
||||
int gid = ((UnixUserPrincipals.Group)group).gid();
|
||||
setOwners(-1, gid);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Unix extends Posix {
|
||||
private static final String MODE_NAME = "mode";
|
||||
private static final String INO_NAME = "ino";
|
||||
private static final String DEV_NAME = "dev";
|
||||
private static final String RDEV_NAME = "rdev";
|
||||
private static final String NLINK_NAME = "nlink";
|
||||
private static final String UID_NAME = "uid";
|
||||
private static final String GID_NAME = "gid";
|
||||
private static final String CTIME_NAME = "ctime";
|
||||
|
||||
// the names of the unix attributes (including posix)
|
||||
static final Set<String> unixAttributeNames =
|
||||
Util.newSet(posixAttributeNames,
|
||||
MODE_NAME, INO_NAME, DEV_NAME, RDEV_NAME,
|
||||
NLINK_NAME, UID_NAME, GID_NAME, CTIME_NAME);
|
||||
|
||||
Unix(UnixPath file, boolean followLinks) {
|
||||
super(file, followLinks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "unix";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String attribute, Object value)
|
||||
throws IOException
|
||||
{
|
||||
if (attribute.equals(MODE_NAME)) {
|
||||
setMode((Integer)value);
|
||||
return;
|
||||
}
|
||||
if (attribute.equals(UID_NAME)) {
|
||||
setOwners((Integer)value, -1);
|
||||
return;
|
||||
}
|
||||
if (attribute.equals(GID_NAME)) {
|
||||
setOwners(-1, (Integer)value);
|
||||
return;
|
||||
}
|
||||
super.setAttribute(attribute, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,Object> readAttributes(String[] requested)
|
||||
throws IOException
|
||||
{
|
||||
AttributesBuilder builder =
|
||||
AttributesBuilder.create(unixAttributeNames, requested);
|
||||
UnixFileAttributes attrs = readAttributes();
|
||||
addRequestedPosixAttributes(attrs, builder);
|
||||
if (builder.match(MODE_NAME))
|
||||
builder.add(MODE_NAME, attrs.mode());
|
||||
if (builder.match(INO_NAME))
|
||||
builder.add(INO_NAME, attrs.ino());
|
||||
if (builder.match(DEV_NAME))
|
||||
builder.add(DEV_NAME, attrs.dev());
|
||||
if (builder.match(RDEV_NAME))
|
||||
builder.add(RDEV_NAME, attrs.rdev());
|
||||
if (builder.match(NLINK_NAME))
|
||||
builder.add(NLINK_NAME, attrs.nlink());
|
||||
if (builder.match(UID_NAME))
|
||||
builder.add(UID_NAME, attrs.uid());
|
||||
if (builder.match(GID_NAME))
|
||||
builder.add(GID_NAME, attrs.gid());
|
||||
if (builder.match(CTIME_NAME))
|
||||
builder.add(CTIME_NAME, attrs.ctime());
|
||||
return builder.unmodifiableMap();
|
||||
}
|
||||
}
|
||||
|
||||
static Basic createBasicView(UnixPath file, boolean followLinks) {
|
||||
return new Basic(file, followLinks);
|
||||
}
|
||||
|
||||
static Posix createPosixView(UnixPath file, boolean followLinks) {
|
||||
return new Posix(file, followLinks);
|
||||
}
|
||||
|
||||
static Unix createUnixView(UnixPath file, boolean followLinks) {
|
||||
return new Unix(file, followLinks);
|
||||
}
|
||||
|
||||
static FileOwnerAttributeViewImpl createOwnerView(UnixPath file, boolean followLinks) {
|
||||
return new FileOwnerAttributeViewImpl(createPosixView(file, followLinks));
|
||||
}
|
||||
}
|
314
src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java
Normal file
314
src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Unix implementation of PosixFileAttributes.
|
||||
*/
|
||||
|
||||
class UnixFileAttributes
|
||||
implements PosixFileAttributes
|
||||
{
|
||||
private int st_mode;
|
||||
private long st_ino;
|
||||
private long st_dev;
|
||||
private long st_rdev;
|
||||
private int st_nlink;
|
||||
private int st_uid;
|
||||
private int st_gid;
|
||||
private long st_size;
|
||||
private long st_atime_sec;
|
||||
private long st_atime_nsec;
|
||||
private long st_mtime_sec;
|
||||
private long st_mtime_nsec;
|
||||
private long st_ctime_sec;
|
||||
private long st_ctime_nsec;
|
||||
private long st_birthtime_sec;
|
||||
|
||||
// created lazily
|
||||
private volatile UserPrincipal owner;
|
||||
private volatile GroupPrincipal group;
|
||||
private volatile UnixFileKey key;
|
||||
|
||||
private UnixFileAttributes() {
|
||||
}
|
||||
|
||||
// get the UnixFileAttributes for a given file
|
||||
static UnixFileAttributes get(UnixPath path, boolean followLinks)
|
||||
throws UnixException
|
||||
{
|
||||
UnixFileAttributes attrs = new UnixFileAttributes();
|
||||
if (followLinks) {
|
||||
UnixNativeDispatcher.stat(path, attrs);
|
||||
} else {
|
||||
UnixNativeDispatcher.lstat(path, attrs);
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
// get the UnixFileAttributes for an open file
|
||||
static UnixFileAttributes get(int fd) throws UnixException {
|
||||
UnixFileAttributes attrs = new UnixFileAttributes();
|
||||
UnixNativeDispatcher.fstat(fd, attrs);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
// get the UnixFileAttributes for a given file, relative to open directory
|
||||
static UnixFileAttributes get(int dfd, UnixPath path, boolean followLinks)
|
||||
throws UnixException
|
||||
{
|
||||
UnixFileAttributes attrs = new UnixFileAttributes();
|
||||
int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW;
|
||||
UnixNativeDispatcher.fstatat(dfd, path.asByteArray(), flag, attrs);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
// package-private
|
||||
boolean isSameFile(UnixFileAttributes attrs) {
|
||||
return ((st_ino == attrs.st_ino) && (st_dev == attrs.st_dev));
|
||||
}
|
||||
|
||||
// package-private
|
||||
int mode() { return st_mode; }
|
||||
long ino() { return st_ino; }
|
||||
long dev() { return st_dev; }
|
||||
long rdev() { return st_rdev; }
|
||||
int nlink() { return st_nlink; }
|
||||
int uid() { return st_uid; }
|
||||
int gid() { return st_gid; }
|
||||
|
||||
private static FileTime toFileTime(long sec, long nsec) {
|
||||
if (nsec == 0) {
|
||||
return FileTime.from(sec, TimeUnit.SECONDS);
|
||||
} else {
|
||||
// truncate to microseconds to avoid overflow with timestamps
|
||||
// way out into the future. We can re-visit this if FileTime
|
||||
// is updated to define a from(secs,nsecs) method.
|
||||
long micro = sec*1000000L + nsec/1000L;
|
||||
return FileTime.from(micro, TimeUnit.MICROSECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
FileTime ctime() {
|
||||
return toFileTime(st_ctime_sec, st_ctime_nsec);
|
||||
}
|
||||
|
||||
boolean isDevice() {
|
||||
int type = st_mode & UnixConstants.S_IFMT;
|
||||
return (type == UnixConstants.S_IFCHR ||
|
||||
type == UnixConstants.S_IFBLK ||
|
||||
type == UnixConstants.S_IFIFO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastModifiedTime() {
|
||||
return toFileTime(st_mtime_sec, st_mtime_nsec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastAccessTime() {
|
||||
return toFileTime(st_atime_sec, st_atime_nsec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime creationTime() {
|
||||
if (UnixNativeDispatcher.birthtimeSupported()) {
|
||||
return FileTime.from(st_birthtime_sec, TimeUnit.SECONDS);
|
||||
} else {
|
||||
// return last modified when birth time not supported
|
||||
return lastModifiedTime();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegularFile() {
|
||||
return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSymbolicLink() {
|
||||
return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFLNK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOther() {
|
||||
int type = st_mode & UnixConstants.S_IFMT;
|
||||
return (type != UnixConstants.S_IFREG &&
|
||||
type != UnixConstants.S_IFDIR &&
|
||||
type != UnixConstants.S_IFLNK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return st_size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixFileKey fileKey() {
|
||||
if (key == null) {
|
||||
synchronized (this) {
|
||||
if (key == null) {
|
||||
key = new UnixFileKey(st_dev, st_ino);
|
||||
}
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserPrincipal owner() {
|
||||
if (owner == null) {
|
||||
synchronized (this) {
|
||||
if (owner == null) {
|
||||
owner = UnixUserPrincipals.fromUid(st_uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupPrincipal group() {
|
||||
if (group == null) {
|
||||
synchronized (this) {
|
||||
if (group == null) {
|
||||
group = UnixUserPrincipals.fromGid(st_gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PosixFilePermission> permissions() {
|
||||
int bits = (st_mode & UnixConstants.S_IAMB);
|
||||
HashSet<PosixFilePermission> perms = new HashSet<>();
|
||||
|
||||
if ((bits & UnixConstants.S_IRUSR) > 0)
|
||||
perms.add(PosixFilePermission.OWNER_READ);
|
||||
if ((bits & UnixConstants.S_IWUSR) > 0)
|
||||
perms.add(PosixFilePermission.OWNER_WRITE);
|
||||
if ((bits & UnixConstants.S_IXUSR) > 0)
|
||||
perms.add(PosixFilePermission.OWNER_EXECUTE);
|
||||
|
||||
if ((bits & UnixConstants.S_IRGRP) > 0)
|
||||
perms.add(PosixFilePermission.GROUP_READ);
|
||||
if ((bits & UnixConstants.S_IWGRP) > 0)
|
||||
perms.add(PosixFilePermission.GROUP_WRITE);
|
||||
if ((bits & UnixConstants.S_IXGRP) > 0)
|
||||
perms.add(PosixFilePermission.GROUP_EXECUTE);
|
||||
|
||||
if ((bits & UnixConstants.S_IROTH) > 0)
|
||||
perms.add(PosixFilePermission.OTHERS_READ);
|
||||
if ((bits & UnixConstants.S_IWOTH) > 0)
|
||||
perms.add(PosixFilePermission.OTHERS_WRITE);
|
||||
if ((bits & UnixConstants.S_IXOTH) > 0)
|
||||
perms.add(PosixFilePermission.OTHERS_EXECUTE);
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
// wrap this object with BasicFileAttributes object to prevent leaking of
|
||||
// user information
|
||||
BasicFileAttributes asBasicFileAttributes() {
|
||||
return UnixAsBasicFileAttributes.wrap(this);
|
||||
}
|
||||
|
||||
// unwrap BasicFileAttributes to get the underlying UnixFileAttributes
|
||||
// object. Returns null is not wrapped.
|
||||
static UnixFileAttributes toUnixFileAttributes(BasicFileAttributes attrs) {
|
||||
if (attrs instanceof UnixFileAttributes)
|
||||
return (UnixFileAttributes)attrs;
|
||||
if (attrs instanceof UnixAsBasicFileAttributes) {
|
||||
return ((UnixAsBasicFileAttributes)attrs).unwrap();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// wrap a UnixFileAttributes object as a BasicFileAttributes
|
||||
private static class UnixAsBasicFileAttributes implements BasicFileAttributes {
|
||||
private final UnixFileAttributes attrs;
|
||||
|
||||
private UnixAsBasicFileAttributes(UnixFileAttributes attrs) {
|
||||
this.attrs = attrs;
|
||||
}
|
||||
|
||||
static UnixAsBasicFileAttributes wrap(UnixFileAttributes attrs) {
|
||||
return new UnixAsBasicFileAttributes(attrs);
|
||||
}
|
||||
|
||||
UnixFileAttributes unwrap() {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastModifiedTime() {
|
||||
return attrs.lastModifiedTime();
|
||||
}
|
||||
@Override
|
||||
public FileTime lastAccessTime() {
|
||||
return attrs.lastAccessTime();
|
||||
}
|
||||
@Override
|
||||
public FileTime creationTime() {
|
||||
return attrs.creationTime();
|
||||
}
|
||||
@Override
|
||||
public boolean isRegularFile() {
|
||||
return attrs.isRegularFile();
|
||||
}
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return attrs.isDirectory();
|
||||
}
|
||||
@Override
|
||||
public boolean isSymbolicLink() {
|
||||
return attrs.isSymbolicLink();
|
||||
}
|
||||
@Override
|
||||
public boolean isOther() {
|
||||
return attrs.isOther();
|
||||
}
|
||||
@Override
|
||||
public long size() {
|
||||
return attrs.size();
|
||||
}
|
||||
@Override
|
||||
public Object fileKey() {
|
||||
return attrs.fileKey();
|
||||
}
|
||||
}
|
||||
}
|
67
src/java.base/unix/classes/sun/nio/fs/UnixFileKey.java
Normal file
67
src/java.base/unix/classes/sun/nio/fs/UnixFileKey.java
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009, 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 sun.nio.fs;
|
||||
|
||||
/**
|
||||
* Container for device/inode to uniquely identify file.
|
||||
*/
|
||||
|
||||
class UnixFileKey {
|
||||
private final long st_dev;
|
||||
private final long st_ino;
|
||||
|
||||
UnixFileKey(long st_dev, long st_ino) {
|
||||
this.st_dev = st_dev;
|
||||
this.st_ino = st_ino;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int)(st_dev ^ (st_dev >>> 32)) +
|
||||
(int)(st_ino ^ (st_ino >>> 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (!(obj instanceof UnixFileKey))
|
||||
return false;
|
||||
UnixFileKey other = (UnixFileKey)obj;
|
||||
return (this.st_dev == other.st_dev) && (this.st_ino == other.st_ino);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(dev=")
|
||||
.append(Long.toHexString(st_dev))
|
||||
.append(",ino=")
|
||||
.append(st_ino)
|
||||
.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.*;
|
||||
|
||||
class UnixFileModeAttribute {
|
||||
static final int ALL_PERMISSIONS =
|
||||
UnixConstants.S_IRUSR | UnixConstants.S_IWUSR | UnixConstants.S_IXUSR |
|
||||
UnixConstants.S_IRGRP | UnixConstants.S_IWGRP | UnixConstants.S_IXGRP |
|
||||
UnixConstants.S_IROTH | UnixConstants.S_IWOTH | UnixConstants. S_IXOTH;
|
||||
|
||||
static final int ALL_READWRITE =
|
||||
UnixConstants.S_IRUSR | UnixConstants.S_IWUSR |
|
||||
UnixConstants.S_IRGRP | UnixConstants.S_IWGRP |
|
||||
UnixConstants.S_IROTH | UnixConstants.S_IWOTH;
|
||||
|
||||
static final int TEMPFILE_PERMISSIONS =
|
||||
UnixConstants.S_IRUSR | UnixConstants.S_IWUSR | UnixConstants.S_IXUSR;
|
||||
|
||||
private UnixFileModeAttribute() {
|
||||
}
|
||||
|
||||
static int toUnixMode(Set<PosixFilePermission> perms) {
|
||||
int mode = 0;
|
||||
for (PosixFilePermission perm: perms) {
|
||||
if (perm == null)
|
||||
throw new NullPointerException();
|
||||
switch (perm) {
|
||||
case OWNER_READ : mode |= UnixConstants.S_IRUSR; break;
|
||||
case OWNER_WRITE : mode |= UnixConstants.S_IWUSR; break;
|
||||
case OWNER_EXECUTE : mode |= UnixConstants.S_IXUSR; break;
|
||||
case GROUP_READ : mode |= UnixConstants.S_IRGRP; break;
|
||||
case GROUP_WRITE : mode |= UnixConstants.S_IWGRP; break;
|
||||
case GROUP_EXECUTE : mode |= UnixConstants.S_IXGRP; break;
|
||||
case OTHERS_READ : mode |= UnixConstants.S_IROTH; break;
|
||||
case OTHERS_WRITE : mode |= UnixConstants.S_IWOTH; break;
|
||||
case OTHERS_EXECUTE : mode |= UnixConstants.S_IXOTH; break;
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static int toUnixMode(int defaultMode, FileAttribute<?>... attrs) {
|
||||
int mode = defaultMode;
|
||||
for (FileAttribute<?> attr: attrs) {
|
||||
String name = attr.name();
|
||||
if (!name.equals("posix:permissions") && !name.equals("unix:permissions")) {
|
||||
throw new UnsupportedOperationException("'" + attr.name() +
|
||||
"' not supported as initial attribute");
|
||||
}
|
||||
mode = toUnixMode((Set<PosixFilePermission>)attr.value());
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
}
|
266
src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java
Normal file
266
src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Base implementation of FileStore for Unix/like implementations.
|
||||
*/
|
||||
|
||||
abstract class UnixFileStore
|
||||
extends FileStore
|
||||
{
|
||||
// original path of file that identified file system
|
||||
private final UnixPath file;
|
||||
|
||||
// device ID
|
||||
private final long dev;
|
||||
|
||||
// entry in the mount tab
|
||||
private final UnixMountEntry entry;
|
||||
|
||||
// return the device ID where the given file resides
|
||||
private static long devFor(UnixPath file) throws IOException {
|
||||
try {
|
||||
return UnixFileAttributes.get(file, true).dev();
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return 0L; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
UnixFileStore(UnixPath file) throws IOException {
|
||||
this.file = file;
|
||||
this.dev = devFor(file);
|
||||
this.entry = findMountEntry();
|
||||
}
|
||||
|
||||
UnixFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
|
||||
this.file = new UnixPath(fs, entry.dir());
|
||||
this.dev = (entry.dev() == 0L) ? devFor(this.file) : entry.dev();
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the mount entry for the file store
|
||||
*/
|
||||
abstract UnixMountEntry findMountEntry() throws IOException;
|
||||
|
||||
UnixPath file() {
|
||||
return file;
|
||||
}
|
||||
|
||||
long dev() {
|
||||
return dev;
|
||||
}
|
||||
|
||||
UnixMountEntry entry() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return entry.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return entry.fstype();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return entry.isReadOnly();
|
||||
}
|
||||
|
||||
// uses statvfs to read the file system information
|
||||
private UnixFileStoreAttributes readAttributes() throws IOException {
|
||||
try {
|
||||
return UnixFileStoreAttributes.get(file);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compile happy
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalSpace() throws IOException {
|
||||
UnixFileStoreAttributes attrs = readAttributes();
|
||||
return attrs.blockSize() * attrs.totalBlocks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUsableSpace() throws IOException {
|
||||
UnixFileStoreAttributes attrs = readAttributes();
|
||||
return attrs.blockSize() * attrs.availableBlocks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnallocatedSpace() throws IOException {
|
||||
UnixFileStoreAttributes attrs = readAttributes();
|
||||
return attrs.blockSize() * attrs.freeBlocks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> view)
|
||||
{
|
||||
if (view == null)
|
||||
throw new NullPointerException();
|
||||
return (V) null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String attribute) throws IOException {
|
||||
if (attribute.equals("totalSpace"))
|
||||
return getTotalSpace();
|
||||
if (attribute.equals("usableSpace"))
|
||||
return getUsableSpace();
|
||||
if (attribute.equals("unallocatedSpace"))
|
||||
return getUnallocatedSpace();
|
||||
throw new UnsupportedOperationException("'" + attribute + "' not recognized");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
if (type == BasicFileAttributeView.class)
|
||||
return true;
|
||||
if (type == PosixFileAttributeView.class ||
|
||||
type == FileOwnerAttributeView.class)
|
||||
{
|
||||
// lookup fstypes.properties
|
||||
FeatureStatus status = checkIfFeaturePresent("posix");
|
||||
// assume supported if UNKNOWN
|
||||
return (status != FeatureStatus.NOT_PRESENT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(String name) {
|
||||
if (name.equals("basic") || name.equals("unix"))
|
||||
return true;
|
||||
if (name.equals("posix"))
|
||||
return supportsFileAttributeView(PosixFileAttributeView.class);
|
||||
if (name.equals("owner"))
|
||||
return supportsFileAttributeView(FileOwnerAttributeView.class);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object ob) {
|
||||
if (ob == this)
|
||||
return true;
|
||||
if (!(ob instanceof UnixFileStore))
|
||||
return false;
|
||||
UnixFileStore other = (UnixFileStore)ob;
|
||||
return (this.dev == other.dev) &&
|
||||
Arrays.equals(this.entry.dir(), other.entry.dir()) &&
|
||||
this.entry.name().equals(other.entry.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int)(dev ^ (dev >>> 32)) ^ Arrays.hashCode(entry.dir());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(Util.toString(entry.dir()));
|
||||
sb.append(" (");
|
||||
sb.append(entry.name());
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// -- fstypes.properties --
|
||||
|
||||
private static final Object loadLock = new Object();
|
||||
private static volatile Properties props;
|
||||
|
||||
enum FeatureStatus {
|
||||
PRESENT,
|
||||
NOT_PRESENT,
|
||||
UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns status to indicate if file system supports a given feature
|
||||
*/
|
||||
FeatureStatus checkIfFeaturePresent(String feature) {
|
||||
if (props == null) {
|
||||
synchronized (loadLock) {
|
||||
if (props == null) {
|
||||
props = AccessController.doPrivileged(
|
||||
new PrivilegedAction<>() {
|
||||
@Override
|
||||
public Properties run() {
|
||||
return loadProperties();
|
||||
}});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String value = props.getProperty(type());
|
||||
if (value != null) {
|
||||
String[] values = value.split("\\s");
|
||||
for (String s: values) {
|
||||
s = s.trim().toLowerCase();
|
||||
if (s.equals(feature)) {
|
||||
return FeatureStatus.PRESENT;
|
||||
}
|
||||
if (s.startsWith("no")) {
|
||||
s = s.substring(2);
|
||||
if (s.equals(feature)) {
|
||||
return FeatureStatus.NOT_PRESENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FeatureStatus.UNKNOWN;
|
||||
}
|
||||
|
||||
private static Properties loadProperties() {
|
||||
Properties result = new Properties();
|
||||
String fstypes = System.getProperty("java.home") + "/lib/fstypes.properties";
|
||||
Path file = Paths.get(fstypes);
|
||||
try {
|
||||
try (ReadableByteChannel rbc = Files.newByteChannel(file)) {
|
||||
result.load(Channels.newReader(rbc, "UTF-8"));
|
||||
}
|
||||
} catch (IOException x) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009, 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 sun.nio.fs;
|
||||
|
||||
class UnixFileStoreAttributes {
|
||||
private long f_frsize; // block size
|
||||
private long f_blocks; // total
|
||||
private long f_bfree; // free
|
||||
private long f_bavail; // usable
|
||||
|
||||
private UnixFileStoreAttributes() {
|
||||
}
|
||||
|
||||
static UnixFileStoreAttributes get(UnixPath path) throws UnixException {
|
||||
UnixFileStoreAttributes attrs = new UnixFileStoreAttributes();
|
||||
UnixNativeDispatcher.statvfs(path, attrs);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
long blockSize() {
|
||||
return f_frsize;
|
||||
}
|
||||
|
||||
long totalBlocks() {
|
||||
return f_blocks;
|
||||
}
|
||||
|
||||
long freeBlocks() {
|
||||
return f_bfree;
|
||||
}
|
||||
|
||||
long availableBlocks() {
|
||||
return f_bavail;
|
||||
}
|
||||
|
||||
}
|
360
src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java
Normal file
360
src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java
Normal file
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.nio.file.spi.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* Base implementation of FileSystem for Unix-like implementations.
|
||||
*/
|
||||
|
||||
abstract class UnixFileSystem
|
||||
extends FileSystem
|
||||
{
|
||||
private final UnixFileSystemProvider provider;
|
||||
private final byte[] defaultDirectory;
|
||||
private final boolean needToResolveAgainstDefaultDirectory;
|
||||
private final UnixPath rootDirectory;
|
||||
|
||||
// package-private
|
||||
UnixFileSystem(UnixFileSystemProvider provider, String dir) {
|
||||
this.provider = provider;
|
||||
this.defaultDirectory = Util.toBytes(UnixPath.normalizeAndCheck(dir));
|
||||
if (this.defaultDirectory[0] != '/') {
|
||||
throw new RuntimeException("default directory must be absolute");
|
||||
}
|
||||
|
||||
// if process-wide chdir is allowed or default directory is not the
|
||||
// process working directory then paths must be resolved against the
|
||||
// default directory.
|
||||
String propValue = GetPropertyAction
|
||||
.privilegedGetProperty("sun.nio.fs.chdirAllowed", "false");
|
||||
boolean chdirAllowed = (propValue.length() == 0) ?
|
||||
true : Boolean.valueOf(propValue);
|
||||
if (chdirAllowed) {
|
||||
this.needToResolveAgainstDefaultDirectory = true;
|
||||
} else {
|
||||
byte[] cwd = UnixNativeDispatcher.getcwd();
|
||||
boolean defaultIsCwd = (cwd.length == defaultDirectory.length);
|
||||
if (defaultIsCwd) {
|
||||
for (int i=0; i<cwd.length; i++) {
|
||||
if (cwd[i] != defaultDirectory[i]) {
|
||||
defaultIsCwd = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.needToResolveAgainstDefaultDirectory = !defaultIsCwd;
|
||||
}
|
||||
|
||||
// the root directory
|
||||
this.rootDirectory = new UnixPath(this, "/");
|
||||
}
|
||||
|
||||
// package-private
|
||||
byte[] defaultDirectory() {
|
||||
return defaultDirectory;
|
||||
}
|
||||
|
||||
boolean needToResolveAgainstDefaultDirectory() {
|
||||
return needToResolveAgainstDefaultDirectory;
|
||||
}
|
||||
|
||||
UnixPath rootDirectory() {
|
||||
return rootDirectory;
|
||||
}
|
||||
|
||||
boolean isSolaris() {
|
||||
return false;
|
||||
}
|
||||
|
||||
static List<String> standardFileAttributeViews() {
|
||||
return Arrays.asList("basic", "posix", "unix", "owner");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final FileSystemProvider provider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSeparator() {
|
||||
return "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isOpen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void close() throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies non-POSIX attributes from the source to target file.
|
||||
*
|
||||
* Copying a file preserving attributes, or moving a file, will preserve
|
||||
* the file owner/group/permissions/timestamps but it does not preserve
|
||||
* other non-POSIX attributes. This method is invoked by the
|
||||
* copy or move operation to preserve these attributes. It should copy
|
||||
* extended attributes, ACLs, or other attributes.
|
||||
*
|
||||
* @param sfd
|
||||
* Open file descriptor to source file
|
||||
* @param tfd
|
||||
* Open file descriptor to target file
|
||||
*/
|
||||
void copyNonPosixAttributes(int sfd, int tfd) {
|
||||
// no-op by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Unix systems only have a single root directory (/)
|
||||
*/
|
||||
@Override
|
||||
public final Iterable<Path> getRootDirectories() {
|
||||
final List<Path> allowedList =
|
||||
Collections.unmodifiableList(Arrays.asList((Path)rootDirectory));
|
||||
return new Iterable<>() {
|
||||
public Iterator<Path> iterator() {
|
||||
try {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkRead(rootDirectory.toString());
|
||||
return allowedList.iterator();
|
||||
} catch (SecurityException x) {
|
||||
List<Path> disallowed = Collections.emptyList();
|
||||
return disallowed.iterator();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object to iterate over entries in mounttab or equivalent
|
||||
*/
|
||||
abstract Iterable<UnixMountEntry> getMountEntries();
|
||||
|
||||
/**
|
||||
* Returns a FileStore to represent the file system for the given mount
|
||||
* mount.
|
||||
*/
|
||||
abstract FileStore getFileStore(UnixMountEntry entry) throws IOException;
|
||||
|
||||
/**
|
||||
* Iterator returned by getFileStores method.
|
||||
*/
|
||||
private class FileStoreIterator implements Iterator<FileStore> {
|
||||
private final Iterator<UnixMountEntry> entries;
|
||||
private FileStore next;
|
||||
|
||||
FileStoreIterator() {
|
||||
this.entries = getMountEntries().iterator();
|
||||
}
|
||||
|
||||
private FileStore readNext() {
|
||||
assert Thread.holdsLock(this);
|
||||
for (;;) {
|
||||
if (!entries.hasNext())
|
||||
return null;
|
||||
UnixMountEntry entry = entries.next();
|
||||
|
||||
// skip entries with the "ignore" option
|
||||
if (entry.isIgnored())
|
||||
continue;
|
||||
|
||||
// check permission to read mount point
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
sm.checkRead(Util.toString(entry.dir()));
|
||||
} catch (SecurityException x) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try {
|
||||
return getFileStore(entry);
|
||||
} catch (IOException ignore) {
|
||||
// ignore as per spec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean hasNext() {
|
||||
if (next != null)
|
||||
return true;
|
||||
next = readNext();
|
||||
return next != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized FileStore next() {
|
||||
if (next == null)
|
||||
next = readNext();
|
||||
if (next == null) {
|
||||
throw new NoSuchElementException();
|
||||
} else {
|
||||
FileStore result = next;
|
||||
next = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Iterable<FileStore> getFileStores() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
|
||||
} catch (SecurityException se) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
return new Iterable<>() {
|
||||
public Iterator<FileStore> iterator() {
|
||||
return new FileStoreIterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Path getPath(String first, String... more) {
|
||||
String path;
|
||||
if (more.length == 0) {
|
||||
path = first;
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(first);
|
||||
for (String segment: more) {
|
||||
if (segment.length() > 0) {
|
||||
if (sb.length() > 0)
|
||||
sb.append('/');
|
||||
sb.append(segment);
|
||||
}
|
||||
}
|
||||
path = sb.toString();
|
||||
}
|
||||
return new UnixPath(this, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathMatcher getPathMatcher(String syntaxAndInput) {
|
||||
int pos = syntaxAndInput.indexOf(':');
|
||||
if (pos <= 0 || pos == syntaxAndInput.length())
|
||||
throw new IllegalArgumentException();
|
||||
String syntax = syntaxAndInput.substring(0, pos);
|
||||
String input = syntaxAndInput.substring(pos+1);
|
||||
|
||||
String expr;
|
||||
if (syntax.equalsIgnoreCase(GLOB_SYNTAX)) {
|
||||
expr = Globs.toUnixRegexPattern(input);
|
||||
} else {
|
||||
if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) {
|
||||
expr = input;
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Syntax '" + syntax +
|
||||
"' not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
// return matcher
|
||||
final Pattern pattern = compilePathMatchPattern(expr);
|
||||
|
||||
return new PathMatcher() {
|
||||
@Override
|
||||
public boolean matches(Path path) {
|
||||
return pattern.matcher(path.toString()).matches();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static final String GLOB_SYNTAX = "glob";
|
||||
private static final String REGEX_SYNTAX = "regex";
|
||||
|
||||
@Override
|
||||
public final UserPrincipalLookupService getUserPrincipalLookupService() {
|
||||
return LookupService.instance;
|
||||
}
|
||||
|
||||
private static class LookupService {
|
||||
static final UserPrincipalLookupService instance =
|
||||
new UserPrincipalLookupService() {
|
||||
@Override
|
||||
public UserPrincipal lookupPrincipalByName(String name)
|
||||
throws IOException
|
||||
{
|
||||
return UnixUserPrincipals.lookupUser(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupPrincipal lookupPrincipalByGroupName(String group)
|
||||
throws IOException
|
||||
{
|
||||
return UnixUserPrincipals.lookupGroup(group);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Override if the platform has different path match requirement, such as
|
||||
// case insensitive or Unicode canonical equal on MacOSX
|
||||
Pattern compilePathMatchPattern(String expr) {
|
||||
return Pattern.compile(expr);
|
||||
}
|
||||
|
||||
// Override if the platform uses different Unicode normalization form
|
||||
// for native file path. For example on MacOSX, the native path is stored
|
||||
// in Unicode NFD form.
|
||||
char[] normalizeNativePath(char[] path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// Override if the native file path use non-NFC form. For example on MacOSX,
|
||||
// the native path is stored in Unicode NFD form, the path need to be
|
||||
// normalized back to NFC before passed back to Java level.
|
||||
String normalizeJavaPath(String path) {
|
||||
return path;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,557 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.nio.file.spi.FileTypeDetector;
|
||||
import java.nio.channels.*;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.io.IOException;
|
||||
import java.io.FilePermission;
|
||||
import java.util.*;
|
||||
import java.security.AccessController;
|
||||
|
||||
import sun.nio.ch.ThreadPool;
|
||||
import sun.security.util.SecurityConstants;
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
/**
|
||||
* Base implementation of FileSystemProvider
|
||||
*/
|
||||
|
||||
public abstract class UnixFileSystemProvider
|
||||
extends AbstractFileSystemProvider
|
||||
{
|
||||
private static final String USER_DIR = "user.dir";
|
||||
private final UnixFileSystem theFileSystem;
|
||||
|
||||
public UnixFileSystemProvider() {
|
||||
String userDir = System.getProperty(USER_DIR);
|
||||
theFileSystem = newFileSystem(userDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new file system using the given default directory.
|
||||
*/
|
||||
abstract UnixFileSystem newFileSystem(String dir);
|
||||
|
||||
@Override
|
||||
public final String getScheme() {
|
||||
return "file";
|
||||
}
|
||||
|
||||
private void checkUri(URI uri) {
|
||||
if (!uri.getScheme().equalsIgnoreCase(getScheme()))
|
||||
throw new IllegalArgumentException("URI does not match this provider");
|
||||
if (uri.getRawAuthority() != null)
|
||||
throw new IllegalArgumentException("Authority component present");
|
||||
String path = uri.getPath();
|
||||
if (path == null)
|
||||
throw new IllegalArgumentException("Path component is undefined");
|
||||
if (!path.equals("/"))
|
||||
throw new IllegalArgumentException("Path component should be '/'");
|
||||
if (uri.getRawQuery() != null)
|
||||
throw new IllegalArgumentException("Query component present");
|
||||
if (uri.getRawFragment() != null)
|
||||
throw new IllegalArgumentException("Fragment component present");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final FileSystem newFileSystem(URI uri, Map<String,?> env) {
|
||||
checkUri(uri);
|
||||
throw new FileSystemAlreadyExistsException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final FileSystem getFileSystem(URI uri) {
|
||||
checkUri(uri);
|
||||
return theFileSystem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(URI uri) {
|
||||
return UnixUriUtils.fromUri(theFileSystem, uri);
|
||||
}
|
||||
|
||||
UnixPath checkPath(Path obj) {
|
||||
if (obj == null)
|
||||
throw new NullPointerException();
|
||||
if (!(obj instanceof UnixPath))
|
||||
throw new ProviderMismatchException();
|
||||
return (UnixPath)obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends FileAttributeView> V getFileAttributeView(Path obj,
|
||||
Class<V> type,
|
||||
LinkOption... options)
|
||||
{
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
boolean followLinks = Util.followLinks(options);
|
||||
if (type == BasicFileAttributeView.class)
|
||||
return (V) UnixFileAttributeViews.createBasicView(file, followLinks);
|
||||
if (type == PosixFileAttributeView.class)
|
||||
return (V) UnixFileAttributeViews.createPosixView(file, followLinks);
|
||||
if (type == FileOwnerAttributeView.class)
|
||||
return (V) UnixFileAttributeViews.createOwnerView(file, followLinks);
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
return (V) null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends BasicFileAttributes> A readAttributes(Path file,
|
||||
Class<A> type,
|
||||
LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
Class<? extends BasicFileAttributeView> view;
|
||||
if (type == BasicFileAttributes.class)
|
||||
view = BasicFileAttributeView.class;
|
||||
else if (type == PosixFileAttributes.class)
|
||||
view = PosixFileAttributeView.class;
|
||||
else if (type == null)
|
||||
throw new NullPointerException();
|
||||
else
|
||||
throw new UnsupportedOperationException();
|
||||
return (A) getFileAttributeView(file, view, options).readAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DynamicFileAttributeView getFileAttributeView(Path obj,
|
||||
String name,
|
||||
LinkOption... options)
|
||||
{
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
boolean followLinks = Util.followLinks(options);
|
||||
if (name.equals("basic"))
|
||||
return UnixFileAttributeViews.createBasicView(file, followLinks);
|
||||
if (name.equals("posix"))
|
||||
return UnixFileAttributeViews.createPosixView(file, followLinks);
|
||||
if (name.equals("unix"))
|
||||
return UnixFileAttributeViews.createUnixView(file, followLinks);
|
||||
if (name.equals("owner"))
|
||||
return UnixFileAttributeViews.createOwnerView(file, followLinks);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileChannel newFileChannel(Path obj,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath file = checkPath(obj);
|
||||
int mode = UnixFileModeAttribute
|
||||
.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
|
||||
try {
|
||||
return UnixChannelFactory.newFileChannel(file, options, mode);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousFileChannel newAsynchronousFileChannel(Path obj,
|
||||
Set<? extends OpenOption> options,
|
||||
ExecutorService executor,
|
||||
FileAttribute<?>... attrs) throws IOException
|
||||
{
|
||||
UnixPath file = checkPath(obj);
|
||||
int mode = UnixFileModeAttribute
|
||||
.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
|
||||
ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);
|
||||
try {
|
||||
return UnixChannelFactory
|
||||
.newAsynchronousFileChannel(file, options, mode, pool);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SeekableByteChannel newByteChannel(Path obj,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
int mode = UnixFileModeAttribute
|
||||
.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
|
||||
try {
|
||||
return UnixChannelFactory.newFileChannel(file, options, mode);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean implDelete(Path obj, boolean failIfNotExists) throws IOException {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
file.checkDelete();
|
||||
|
||||
// need file attributes to know if file is directory
|
||||
UnixFileAttributes attrs = null;
|
||||
try {
|
||||
attrs = UnixFileAttributes.get(file, false);
|
||||
if (attrs.isDirectory()) {
|
||||
rmdir(file);
|
||||
} else {
|
||||
unlink(file);
|
||||
}
|
||||
return true;
|
||||
} catch (UnixException x) {
|
||||
// no-op if file does not exist
|
||||
if (!failIfNotExists && x.errno() == ENOENT)
|
||||
return false;
|
||||
|
||||
// DirectoryNotEmptyException if not empty
|
||||
if (attrs != null && attrs.isDirectory() &&
|
||||
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
|
||||
throw new DirectoryNotEmptyException(file.getPathForExceptionMessage());
|
||||
|
||||
x.rethrowAsIOException(file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(Path source, Path target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
UnixCopyFile.copy(UnixPath.toUnixPath(source),
|
||||
UnixPath.toUnixPath(target),
|
||||
options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(Path source, Path target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
UnixCopyFile.move(UnixPath.toUnixPath(source),
|
||||
UnixPath.toUnixPath(target),
|
||||
options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAccess(Path obj, AccessMode... modes) throws IOException {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
boolean e = false;
|
||||
boolean r = false;
|
||||
boolean w = false;
|
||||
boolean x = false;
|
||||
|
||||
if (modes.length == 0) {
|
||||
e = true;
|
||||
} else {
|
||||
for (AccessMode mode: modes) {
|
||||
switch (mode) {
|
||||
case READ : r = true; break;
|
||||
case WRITE : w = true; break;
|
||||
case EXECUTE : x = true; break;
|
||||
default: throw new AssertionError("Should not get here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mode = 0;
|
||||
if (e || r) {
|
||||
file.checkRead();
|
||||
mode |= (r) ? R_OK : F_OK;
|
||||
}
|
||||
if (w) {
|
||||
file.checkWrite();
|
||||
mode |= W_OK;
|
||||
}
|
||||
if (x) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
// not cached
|
||||
sm.checkExec(file.getPathForPermissionCheck());
|
||||
}
|
||||
mode |= X_OK;
|
||||
}
|
||||
try {
|
||||
access(file, mode);
|
||||
} catch (UnixException exc) {
|
||||
exc.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameFile(Path obj1, Path obj2) throws IOException {
|
||||
UnixPath file1 = UnixPath.toUnixPath(obj1);
|
||||
if (file1.equals(obj2))
|
||||
return true;
|
||||
if (obj2 == null)
|
||||
throw new NullPointerException();
|
||||
if (!(obj2 instanceof UnixPath))
|
||||
return false;
|
||||
UnixPath file2 = (UnixPath)obj2;
|
||||
|
||||
// check security manager access to both files
|
||||
file1.checkRead();
|
||||
file2.checkRead();
|
||||
|
||||
UnixFileAttributes attrs1;
|
||||
UnixFileAttributes attrs2;
|
||||
try {
|
||||
attrs1 = UnixFileAttributes.get(file1, true);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file1);
|
||||
return false; // keep compiler happy
|
||||
}
|
||||
try {
|
||||
attrs2 = UnixFileAttributes.get(file2, true);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file2);
|
||||
return false; // keep compiler happy
|
||||
}
|
||||
return attrs1.isSameFile(attrs2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden(Path obj) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
file.checkRead();
|
||||
UnixPath name = file.getFileName();
|
||||
if (name == null)
|
||||
return false;
|
||||
return (name.asByteArray()[0] == '.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FileStore to represent the file system where the given file
|
||||
* reside.
|
||||
*/
|
||||
abstract FileStore getFileStore(UnixPath path) throws IOException;
|
||||
|
||||
@Override
|
||||
public FileStore getFileStore(Path obj) throws IOException {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
|
||||
file.checkRead();
|
||||
}
|
||||
return getFileStore(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(Path obj, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath dir = UnixPath.toUnixPath(obj);
|
||||
dir.checkWrite();
|
||||
|
||||
int mode = UnixFileModeAttribute.toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs);
|
||||
try {
|
||||
mkdir(dir, mode);
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() == EISDIR)
|
||||
throw new FileAlreadyExistsException(dir.toString());
|
||||
x.rethrowAsIOException(dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath dir = UnixPath.toUnixPath(obj);
|
||||
dir.checkRead();
|
||||
if (filter == null)
|
||||
throw new NullPointerException();
|
||||
|
||||
// can't return SecureDirectoryStream on kernels that don't support openat
|
||||
// or O_NOFOLLOW
|
||||
if (!openatSupported() || O_NOFOLLOW == 0) {
|
||||
try {
|
||||
long ptr = opendir(dir);
|
||||
return new UnixDirectoryStream(dir, ptr, filter);
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() == ENOTDIR)
|
||||
throw new NotDirectoryException(dir.getPathForExceptionMessage());
|
||||
x.rethrowAsIOException(dir);
|
||||
}
|
||||
}
|
||||
|
||||
// open directory and dup file descriptor for use by
|
||||
// opendir/readdir/closedir
|
||||
int dfd1 = -1;
|
||||
int dfd2 = -1;
|
||||
long dp = 0L;
|
||||
try {
|
||||
dfd1 = open(dir, O_RDONLY, 0);
|
||||
dfd2 = dup(dfd1);
|
||||
dp = fdopendir(dfd1);
|
||||
} catch (UnixException x) {
|
||||
if (dfd1 != -1)
|
||||
UnixNativeDispatcher.close(dfd1);
|
||||
if (dfd2 != -1)
|
||||
UnixNativeDispatcher.close(dfd2);
|
||||
if (x.errno() == UnixConstants.ENOTDIR)
|
||||
throw new NotDirectoryException(dir.getPathForExceptionMessage());
|
||||
x.rethrowAsIOException(dir);
|
||||
}
|
||||
return new UnixSecureDirectoryStream(dir, dp, dfd2, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath link = UnixPath.toUnixPath(obj1);
|
||||
UnixPath target = UnixPath.toUnixPath(obj2);
|
||||
|
||||
// no attributes supported when creating links
|
||||
if (attrs.length > 0) {
|
||||
UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE
|
||||
throw new UnsupportedOperationException("Initial file attributes" +
|
||||
"not supported when creating symbolic link");
|
||||
}
|
||||
|
||||
// permission check
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new LinkPermission("symbolic"));
|
||||
link.checkWrite();
|
||||
}
|
||||
|
||||
// create link
|
||||
try {
|
||||
symlink(target.asByteArray(), link);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(link);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createLink(Path obj1, Path obj2) throws IOException {
|
||||
UnixPath link = UnixPath.toUnixPath(obj1);
|
||||
UnixPath existing = UnixPath.toUnixPath(obj2);
|
||||
|
||||
// permission check
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new LinkPermission("hard"));
|
||||
link.checkWrite();
|
||||
existing.checkWrite();
|
||||
}
|
||||
try {
|
||||
link(existing, link);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(link, existing);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path readSymbolicLink(Path obj1) throws IOException {
|
||||
UnixPath link = UnixPath.toUnixPath(obj1);
|
||||
// permission check
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
FilePermission perm = new FilePermission(link.getPathForPermissionCheck(),
|
||||
SecurityConstants.FILE_READLINK_ACTION);
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
try {
|
||||
byte[] target = readlink(link);
|
||||
return new UnixPath(link.getFileSystem(), target);
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() == UnixConstants.EINVAL)
|
||||
throw new NotLinkException(link.getPathForExceptionMessage());
|
||||
x.rethrowAsIOException(link);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isDirectory(Path obj) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
file.checkRead();
|
||||
int mode = UnixNativeDispatcher.stat(file);
|
||||
return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isRegularFile(Path obj) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
file.checkRead();
|
||||
int mode = UnixNativeDispatcher.stat(file);
|
||||
return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean exists(Path obj) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
file.checkRead();
|
||||
return UnixNativeDispatcher.exists(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code FileTypeDetector} for this platform.
|
||||
*/
|
||||
FileTypeDetector getFileTypeDetector() {
|
||||
return new AbstractFileTypeDetector() {
|
||||
@Override
|
||||
public String implProbeContentType(Path file) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code FileTypeDetector} that chains the given array of file
|
||||
* type detectors. When the {@code implProbeContentType} method is invoked
|
||||
* then each of the detectors is invoked in turn, the result from the
|
||||
* first to detect the file type is returned.
|
||||
*/
|
||||
final FileTypeDetector chain(final AbstractFileTypeDetector... detectors) {
|
||||
return new AbstractFileTypeDetector() {
|
||||
@Override
|
||||
protected String implProbeContentType(Path file) throws IOException {
|
||||
for (AbstractFileTypeDetector detector : detectors) {
|
||||
String result = detector.implProbeContentType(file);
|
||||
if (result != null && !result.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
85
src/java.base/unix/classes/sun/nio/fs/UnixMountEntry.java
Normal file
85
src/java.base/unix/classes/sun/nio/fs/UnixMountEntry.java
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, 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 sun.nio.fs;
|
||||
|
||||
/**
|
||||
* Represents an entry in the mount table.
|
||||
*/
|
||||
|
||||
class UnixMountEntry {
|
||||
private byte[] name; // file system name
|
||||
private byte[] dir; // directory (mount point)
|
||||
private byte[] fstype; // ufs, nfs, ...
|
||||
private byte[] opts; // mount options
|
||||
private long dev; // device ID
|
||||
|
||||
private volatile String fstypeAsString;
|
||||
private volatile String optionsAsString;
|
||||
|
||||
UnixMountEntry() {
|
||||
}
|
||||
|
||||
String name() {
|
||||
return Util.toString(name);
|
||||
}
|
||||
|
||||
String fstype() {
|
||||
if (fstypeAsString == null)
|
||||
fstypeAsString = Util.toString(fstype);
|
||||
return fstypeAsString;
|
||||
}
|
||||
|
||||
byte[] dir() {
|
||||
return dir;
|
||||
}
|
||||
|
||||
long dev() {
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the mount entry has the given option.
|
||||
*/
|
||||
boolean hasOption(String requested) {
|
||||
if (optionsAsString == null)
|
||||
optionsAsString = Util.toString(opts);
|
||||
for (String opt: Util.split(optionsAsString, ',')) {
|
||||
if (opt.equals(requested))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// generic option
|
||||
boolean isIgnored() {
|
||||
return hasOption("ignore");
|
||||
}
|
||||
|
||||
// generic option
|
||||
boolean isReadOnly() {
|
||||
return hasOption("ro");
|
||||
}
|
||||
}
|
616
src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java
Normal file
616
src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java
Normal file
|
@ -0,0 +1,616 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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 sun.nio.fs;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Unix system and library calls.
|
||||
*/
|
||||
|
||||
class UnixNativeDispatcher {
|
||||
protected UnixNativeDispatcher() { }
|
||||
|
||||
// returns a NativeBuffer containing the given path
|
||||
private static NativeBuffer copyToNativeBuffer(UnixPath path) {
|
||||
byte[] cstr = path.getByteArrayForSysCalls();
|
||||
int size = cstr.length + 1;
|
||||
NativeBuffer buffer = NativeBuffers.getNativeBufferFromCache(size);
|
||||
if (buffer == null) {
|
||||
buffer = NativeBuffers.allocNativeBuffer(size);
|
||||
} else {
|
||||
// buffer already contains the path
|
||||
if (buffer.owner() == path)
|
||||
return buffer;
|
||||
}
|
||||
NativeBuffers.copyCStringToNativeBuffer(cstr, buffer);
|
||||
buffer.setOwner(path);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* char *getcwd(char *buf, size_t size);
|
||||
*/
|
||||
static native byte[] getcwd();
|
||||
|
||||
/**
|
||||
* int dup(int filedes)
|
||||
*/
|
||||
static native int dup(int filedes) throws UnixException;
|
||||
|
||||
/**
|
||||
* int open(const char* path, int oflag, mode_t mode)
|
||||
*/
|
||||
static int open(UnixPath path, int flags, int mode) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
return open0(buffer.address(), flags, mode);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native int open0(long pathAddress, int flags, int mode)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* int openat(int dfd, const char* path, int oflag, mode_t mode)
|
||||
*/
|
||||
static int openat(int dfd, byte[] path, int flags, int mode) throws UnixException {
|
||||
NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
|
||||
try {
|
||||
return openat0(dfd, buffer.address(), flags, mode);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native int openat0(int dfd, long pathAddress, int flags, int mode)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* close(int filedes). If fd is -1 this is a no-op.
|
||||
*/
|
||||
static void close(int fd) {
|
||||
if (fd != -1) {
|
||||
close0(fd);
|
||||
}
|
||||
}
|
||||
private static native void close0(int fd);
|
||||
|
||||
/**
|
||||
* FILE* fopen(const char *filename, const char* mode);
|
||||
*/
|
||||
static long fopen(UnixPath filename, String mode) throws UnixException {
|
||||
NativeBuffer pathBuffer = copyToNativeBuffer(filename);
|
||||
NativeBuffer modeBuffer = NativeBuffers.asNativeBuffer(Util.toBytes(mode));
|
||||
try {
|
||||
return fopen0(pathBuffer.address(), modeBuffer.address());
|
||||
} finally {
|
||||
modeBuffer.release();
|
||||
pathBuffer.release();
|
||||
}
|
||||
}
|
||||
private static native long fopen0(long pathAddress, long modeAddress)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* fclose(FILE* stream)
|
||||
*/
|
||||
static native void fclose(long stream) throws UnixException;
|
||||
|
||||
/**
|
||||
* link(const char* existing, const char* new)
|
||||
*/
|
||||
static void link(UnixPath existing, UnixPath newfile) throws UnixException {
|
||||
NativeBuffer existingBuffer = copyToNativeBuffer(existing);
|
||||
NativeBuffer newBuffer = copyToNativeBuffer(newfile);
|
||||
try {
|
||||
link0(existingBuffer.address(), newBuffer.address());
|
||||
} finally {
|
||||
newBuffer.release();
|
||||
existingBuffer.release();
|
||||
}
|
||||
}
|
||||
private static native void link0(long existingAddress, long newAddress)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* unlink(const char* path)
|
||||
*/
|
||||
static void unlink(UnixPath path) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
unlink0(buffer.address());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void unlink0(long pathAddress) throws UnixException;
|
||||
|
||||
/**
|
||||
* unlinkat(int dfd, const char* path, int flag)
|
||||
*/
|
||||
static void unlinkat(int dfd, byte[] path, int flag) throws UnixException {
|
||||
NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
|
||||
try {
|
||||
unlinkat0(dfd, buffer.address(), flag);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void unlinkat0(int dfd, long pathAddress, int flag)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* mknod(const char* path, mode_t mode, dev_t dev)
|
||||
*/
|
||||
static void mknod(UnixPath path, int mode, long dev) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
mknod0(buffer.address(), mode, dev);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void mknod0(long pathAddress, int mode, long dev)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* rename(const char* old, const char* new)
|
||||
*/
|
||||
static void rename(UnixPath from, UnixPath to) throws UnixException {
|
||||
NativeBuffer fromBuffer = copyToNativeBuffer(from);
|
||||
NativeBuffer toBuffer = copyToNativeBuffer(to);
|
||||
try {
|
||||
rename0(fromBuffer.address(), toBuffer.address());
|
||||
} finally {
|
||||
toBuffer.release();
|
||||
fromBuffer.release();
|
||||
}
|
||||
}
|
||||
private static native void rename0(long fromAddress, long toAddress)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* renameat(int fromfd, const char* old, int tofd, const char* new)
|
||||
*/
|
||||
static void renameat(int fromfd, byte[] from, int tofd, byte[] to) throws UnixException {
|
||||
NativeBuffer fromBuffer = NativeBuffers.asNativeBuffer(from);
|
||||
NativeBuffer toBuffer = NativeBuffers.asNativeBuffer(to);
|
||||
try {
|
||||
renameat0(fromfd, fromBuffer.address(), tofd, toBuffer.address());
|
||||
} finally {
|
||||
toBuffer.release();
|
||||
fromBuffer.release();
|
||||
}
|
||||
}
|
||||
private static native void renameat0(int fromfd, long fromAddress, int tofd, long toAddress)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* mkdir(const char* path, mode_t mode)
|
||||
*/
|
||||
static void mkdir(UnixPath path, int mode) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
mkdir0(buffer.address(), mode);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void mkdir0(long pathAddress, int mode) throws UnixException;
|
||||
|
||||
/**
|
||||
* rmdir(const char* path)
|
||||
*/
|
||||
static void rmdir(UnixPath path) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
rmdir0(buffer.address());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void rmdir0(long pathAddress) throws UnixException;
|
||||
|
||||
/**
|
||||
* readlink(const char* path, char* buf, size_t bufsize)
|
||||
*
|
||||
* @return link target
|
||||
*/
|
||||
static byte[] readlink(UnixPath path) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
return readlink0(buffer.address());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native byte[] readlink0(long pathAddress) throws UnixException;
|
||||
|
||||
/**
|
||||
* realpath(const char* path, char* resolved_name)
|
||||
*
|
||||
* @return resolved path
|
||||
*/
|
||||
static byte[] realpath(UnixPath path) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
return realpath0(buffer.address());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native byte[] realpath0(long pathAddress) throws UnixException;
|
||||
|
||||
/**
|
||||
* symlink(const char* name1, const char* name2)
|
||||
*/
|
||||
static void symlink(byte[] name1, UnixPath name2) throws UnixException {
|
||||
NativeBuffer targetBuffer = NativeBuffers.asNativeBuffer(name1);
|
||||
NativeBuffer linkBuffer = copyToNativeBuffer(name2);
|
||||
try {
|
||||
symlink0(targetBuffer.address(), linkBuffer.address());
|
||||
} finally {
|
||||
linkBuffer.release();
|
||||
targetBuffer.release();
|
||||
}
|
||||
}
|
||||
private static native void symlink0(long name1, long name2)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* stat(const char* path, struct stat* buf)
|
||||
*/
|
||||
static void stat(UnixPath path, UnixFileAttributes attrs) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
stat0(buffer.address(), attrs);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void stat0(long pathAddress, UnixFileAttributes attrs)
|
||||
throws UnixException;
|
||||
|
||||
|
||||
/**
|
||||
* stat(const char* path, struct stat* buf)
|
||||
*
|
||||
* @return st_mode (file type and mode) or 0 if an error occurs.
|
||||
*/
|
||||
static int stat(UnixPath path) {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
return stat1(buffer.address());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native int stat1(long pathAddress);
|
||||
|
||||
|
||||
/**
|
||||
* lstat(const char* path, struct stat* buf)
|
||||
*/
|
||||
static void lstat(UnixPath path, UnixFileAttributes attrs) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
lstat0(buffer.address(), attrs);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void lstat0(long pathAddress, UnixFileAttributes attrs)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* fstat(int filedes, struct stat* buf)
|
||||
*/
|
||||
static native void fstat(int fd, UnixFileAttributes attrs) throws UnixException;
|
||||
|
||||
/**
|
||||
* fstatat(int filedes,const char* path, struct stat* buf, int flag)
|
||||
*/
|
||||
static void fstatat(int dfd, byte[] path, int flag, UnixFileAttributes attrs)
|
||||
throws UnixException
|
||||
{
|
||||
NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
|
||||
try {
|
||||
fstatat0(dfd, buffer.address(), flag, attrs);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void fstatat0(int dfd, long pathAddress, int flag,
|
||||
UnixFileAttributes attrs) throws UnixException;
|
||||
|
||||
/**
|
||||
* chown(const char* path, uid_t owner, gid_t group)
|
||||
*/
|
||||
static void chown(UnixPath path, int uid, int gid) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
chown0(buffer.address(), uid, gid);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void chown0(long pathAddress, int uid, int gid)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* lchown(const char* path, uid_t owner, gid_t group)
|
||||
*/
|
||||
static void lchown(UnixPath path, int uid, int gid) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
lchown0(buffer.address(), uid, gid);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void lchown0(long pathAddress, int uid, int gid)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* fchown(int filedes, uid_t owner, gid_t group)
|
||||
*/
|
||||
static native void fchown(int fd, int uid, int gid) throws UnixException;
|
||||
|
||||
/**
|
||||
* chmod(const char* path, mode_t mode)
|
||||
*/
|
||||
static void chmod(UnixPath path, int mode) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
chmod0(buffer.address(), mode);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void chmod0(long pathAddress, int mode)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* fchmod(int fildes, mode_t mode)
|
||||
*/
|
||||
static native void fchmod(int fd, int mode) throws UnixException;
|
||||
|
||||
/**
|
||||
* utimes(conar char* path, const struct timeval times[2])
|
||||
*/
|
||||
static void utimes(UnixPath path, long times0, long times1)
|
||||
throws UnixException
|
||||
{
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
utimes0(buffer.address(), times0, times1);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void utimes0(long pathAddress, long times0, long times1)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* futimes(int fildes,, const struct timeval times[2])
|
||||
*/
|
||||
static native void futimes(int fd, long times0, long times1) throws UnixException;
|
||||
|
||||
/**
|
||||
* DIR *opendir(const char* dirname)
|
||||
*/
|
||||
static long opendir(UnixPath path) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
return opendir0(buffer.address());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native long opendir0(long pathAddress) throws UnixException;
|
||||
|
||||
/**
|
||||
* DIR* fdopendir(int filedes)
|
||||
*/
|
||||
static native long fdopendir(int dfd) throws UnixException;
|
||||
|
||||
|
||||
/**
|
||||
* closedir(DIR* dirp)
|
||||
*/
|
||||
static native void closedir(long dir) throws UnixException;
|
||||
|
||||
/**
|
||||
* struct dirent* readdir(DIR *dirp)
|
||||
*
|
||||
* @return dirent->d_name
|
||||
*/
|
||||
static native byte[] readdir(long dir) throws UnixException;
|
||||
|
||||
/**
|
||||
* size_t read(int fildes, void* buf, size_t nbyte)
|
||||
*/
|
||||
static native int read(int fildes, long buf, int nbyte) throws UnixException;
|
||||
|
||||
/**
|
||||
* size_t writeint fildes, void* buf, size_t nbyte)
|
||||
*/
|
||||
static native int write(int fildes, long buf, int nbyte) throws UnixException;
|
||||
|
||||
/**
|
||||
* access(const char* path, int amode);
|
||||
*/
|
||||
static void access(UnixPath path, int amode) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
access0(buffer.address(), amode);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void access0(long pathAddress, int amode) throws UnixException;
|
||||
|
||||
/**
|
||||
* access(constant char* path, F_OK)
|
||||
*
|
||||
* @return true if the file exists, false otherwise
|
||||
*/
|
||||
static boolean exists(UnixPath path) {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
return exists0(buffer.address());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native boolean exists0(long pathAddress);
|
||||
|
||||
|
||||
/**
|
||||
* struct passwd *getpwuid(uid_t uid);
|
||||
*
|
||||
* @return passwd->pw_name
|
||||
*/
|
||||
static native byte[] getpwuid(int uid) throws UnixException;
|
||||
|
||||
/**
|
||||
* struct group *getgrgid(gid_t gid);
|
||||
*
|
||||
* @return group->gr_name
|
||||
*/
|
||||
static native byte[] getgrgid(int gid) throws UnixException;
|
||||
|
||||
/**
|
||||
* struct passwd *getpwnam(const char *name);
|
||||
*
|
||||
* @return passwd->pw_uid
|
||||
*/
|
||||
static int getpwnam(String name) throws UnixException {
|
||||
NativeBuffer buffer = NativeBuffers.asNativeBuffer(Util.toBytes(name));
|
||||
try {
|
||||
return getpwnam0(buffer.address());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native int getpwnam0(long nameAddress) throws UnixException;
|
||||
|
||||
/**
|
||||
* struct group *getgrnam(const char *name);
|
||||
*
|
||||
* @return group->gr_name
|
||||
*/
|
||||
static int getgrnam(String name) throws UnixException {
|
||||
NativeBuffer buffer = NativeBuffers.asNativeBuffer(Util.toBytes(name));
|
||||
try {
|
||||
return getgrnam0(buffer.address());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native int getgrnam0(long nameAddress) throws UnixException;
|
||||
|
||||
/**
|
||||
* statvfs(const char* path, struct statvfs *buf)
|
||||
*/
|
||||
static void statvfs(UnixPath path, UnixFileStoreAttributes attrs)
|
||||
throws UnixException
|
||||
{
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
statvfs0(buffer.address(), attrs);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void statvfs0(long pathAddress, UnixFileStoreAttributes attrs)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* long int pathconf(const char *path, int name);
|
||||
*/
|
||||
static long pathconf(UnixPath path, int name) throws UnixException {
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
return pathconf0(buffer.address(), name);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native long pathconf0(long pathAddress, int name)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* long fpathconf(int fildes, int name);
|
||||
*/
|
||||
static native long fpathconf(int filedes, int name) throws UnixException;
|
||||
|
||||
/**
|
||||
* char* strerror(int errnum)
|
||||
*/
|
||||
static native byte[] strerror(int errnum);
|
||||
|
||||
/**
|
||||
* Capabilities
|
||||
*/
|
||||
private static final int SUPPORTS_OPENAT = 1 << 1; // syscalls
|
||||
private static final int SUPPORTS_FUTIMES = 1 << 2;
|
||||
private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features
|
||||
private static final int capabilities;
|
||||
|
||||
/**
|
||||
* Supports openat and other *at calls.
|
||||
*/
|
||||
static boolean openatSupported() {
|
||||
return (capabilities & SUPPORTS_OPENAT) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports futimes or futimesat
|
||||
*/
|
||||
static boolean futimesSupported() {
|
||||
return (capabilities & SUPPORTS_FUTIMES) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports file birth (creation) time attribute
|
||||
*/
|
||||
static boolean birthtimeSupported() {
|
||||
return (capabilities & SUPPORTS_BIRTHTIME) != 0;
|
||||
}
|
||||
|
||||
private static native int init();
|
||||
static {
|
||||
AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("nio");
|
||||
return null;
|
||||
}});
|
||||
capabilities = init();
|
||||
}
|
||||
}
|
922
src/java.base/unix/classes/sun/nio/fs/UnixPath.java
Normal file
922
src/java.base/unix/classes/sun/nio/fs/UnixPath.java
Normal file
|
@ -0,0 +1,922 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.charset.*;
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
import java.lang.ref.SoftReference;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
/**
|
||||
* Solaris/Linux implementation of java.nio.file.Path
|
||||
*/
|
||||
|
||||
class UnixPath implements Path {
|
||||
private static ThreadLocal<SoftReference<CharsetEncoder>> encoder =
|
||||
new ThreadLocal<SoftReference<CharsetEncoder>>();
|
||||
|
||||
// FIXME - eliminate this reference to reduce space
|
||||
private final UnixFileSystem fs;
|
||||
|
||||
// internal representation
|
||||
private final byte[] path;
|
||||
|
||||
// String representation (created lazily)
|
||||
private volatile String stringValue;
|
||||
|
||||
// cached hashcode (created lazily, no need to be volatile)
|
||||
private int hash;
|
||||
|
||||
// array of offsets of elements in path (created lazily)
|
||||
private volatile int[] offsets;
|
||||
|
||||
UnixPath(UnixFileSystem fs, byte[] path) {
|
||||
this.fs = fs;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
UnixPath(UnixFileSystem fs, String input) {
|
||||
// removes redundant slashes and checks for invalid characters
|
||||
this(fs, encode(fs, normalizeAndCheck(input)));
|
||||
}
|
||||
|
||||
// package-private
|
||||
// removes redundant slashes and check input for invalid characters
|
||||
static String normalizeAndCheck(String input) {
|
||||
int n = input.length();
|
||||
char prevChar = 0;
|
||||
for (int i=0; i < n; i++) {
|
||||
char c = input.charAt(i);
|
||||
if ((c == '/') && (prevChar == '/'))
|
||||
return normalize(input, n, i - 1);
|
||||
checkNotNul(input, c);
|
||||
prevChar = c;
|
||||
}
|
||||
if (prevChar == '/')
|
||||
return normalize(input, n, n - 1);
|
||||
return input;
|
||||
}
|
||||
|
||||
private static void checkNotNul(String input, char c) {
|
||||
if (c == '\u0000')
|
||||
throw new InvalidPathException(input, "Nul character not allowed");
|
||||
}
|
||||
|
||||
private static String normalize(String input, int len, int off) {
|
||||
if (len == 0)
|
||||
return input;
|
||||
int n = len;
|
||||
while ((n > 0) && (input.charAt(n - 1) == '/')) n--;
|
||||
if (n == 0)
|
||||
return "/";
|
||||
StringBuilder sb = new StringBuilder(input.length());
|
||||
if (off > 0)
|
||||
sb.append(input.substring(0, off));
|
||||
char prevChar = 0;
|
||||
for (int i=off; i < n; i++) {
|
||||
char c = input.charAt(i);
|
||||
if ((c == '/') && (prevChar == '/'))
|
||||
continue;
|
||||
checkNotNul(input, c);
|
||||
sb.append(c);
|
||||
prevChar = c;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// encodes the given path-string into a sequence of bytes
|
||||
private static byte[] encode(UnixFileSystem fs, String input) {
|
||||
SoftReference<CharsetEncoder> ref = encoder.get();
|
||||
CharsetEncoder ce = (ref != null) ? ref.get() : null;
|
||||
if (ce == null) {
|
||||
ce = Util.jnuEncoding().newEncoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
encoder.set(new SoftReference<>(ce));
|
||||
}
|
||||
|
||||
char[] ca = fs.normalizeNativePath(input.toCharArray());
|
||||
|
||||
// size output buffer for worse-case size
|
||||
byte[] ba = new byte[(int)(ca.length * (double)ce.maxBytesPerChar())];
|
||||
|
||||
// encode
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
ce.reset();
|
||||
CoderResult cr = ce.encode(cb, bb, true);
|
||||
boolean error;
|
||||
if (!cr.isUnderflow()) {
|
||||
error = true;
|
||||
} else {
|
||||
cr = ce.flush(bb);
|
||||
error = !cr.isUnderflow();
|
||||
}
|
||||
if (error) {
|
||||
throw new InvalidPathException(input,
|
||||
"Malformed input or input contains unmappable characters");
|
||||
}
|
||||
|
||||
// trim result to actual length if required
|
||||
int len = bb.position();
|
||||
if (len != ba.length)
|
||||
ba = Arrays.copyOf(ba, len);
|
||||
|
||||
return ba;
|
||||
}
|
||||
|
||||
// package-private
|
||||
byte[] asByteArray() {
|
||||
return path;
|
||||
}
|
||||
|
||||
// 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)
|
||||
throw new NullPointerException();
|
||||
if (!(obj instanceof UnixPath))
|
||||
throw new ProviderMismatchException();
|
||||
return (UnixPath)obj;
|
||||
}
|
||||
|
||||
// create offset list if not already created
|
||||
private void 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 = new int[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
|
||||
private boolean isEmpty() {
|
||||
return path.length == 0;
|
||||
}
|
||||
|
||||
// returns an empty path
|
||||
private UnixPath emptyPath() {
|
||||
return new UnixPath(getFileSystem(), new byte[0]);
|
||||
}
|
||||
|
||||
|
||||
// return true if this path has "." or ".."
|
||||
private boolean hasDotOrDotDot() {
|
||||
int n = getNameCount();
|
||||
for (int i=0; i<n; i++) {
|
||||
byte[] bytes = getName(i).path;
|
||||
if ((bytes.length == 1 && bytes[0] == '.'))
|
||||
return true;
|
||||
if ((bytes.length == 2 && bytes[0] == '.') && bytes[1] == '.') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixFileSystem getFileSystem() {
|
||||
return fs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixPath getRoot() {
|
||||
if (path.length > 0 && path[0] == '/') {
|
||||
return getFileSystem().rootDirectory();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixPath getFileName() {
|
||||
initOffsets();
|
||||
|
||||
int count = offsets.length;
|
||||
|
||||
// no elements so no name
|
||||
if (count == 0)
|
||||
return null;
|
||||
|
||||
// one name element and no root component
|
||||
if (count == 1 && path.length > 0 && path[0] != '/')
|
||||
return this;
|
||||
|
||||
int lastOffset = offsets[count-1];
|
||||
int len = path.length - lastOffset;
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(path, lastOffset, result, 0, len);
|
||||
return new UnixPath(getFileSystem(), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixPath getParent() {
|
||||
initOffsets();
|
||||
|
||||
int count = offsets.length;
|
||||
if (count == 0) {
|
||||
// no elements so no parent
|
||||
return null;
|
||||
}
|
||||
int len = offsets[count-1] - 1;
|
||||
if (len <= 0) {
|
||||
// parent is root only (may be null)
|
||||
return getRoot();
|
||||
}
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(path, 0, result, 0, len);
|
||||
return new UnixPath(getFileSystem(), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNameCount() {
|
||||
initOffsets();
|
||||
return offsets.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixPath getName(int index) {
|
||||
initOffsets();
|
||||
if (index < 0)
|
||||
throw new IllegalArgumentException();
|
||||
if (index >= offsets.length)
|
||||
throw new 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 = new byte[len];
|
||||
System.arraycopy(path, begin, result, 0, len);
|
||||
return new UnixPath(getFileSystem(), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixPath subpath(int beginIndex, int endIndex) {
|
||||
initOffsets();
|
||||
|
||||
if (beginIndex < 0)
|
||||
throw new IllegalArgumentException();
|
||||
if (beginIndex >= offsets.length)
|
||||
throw new IllegalArgumentException();
|
||||
if (endIndex > offsets.length)
|
||||
throw new IllegalArgumentException();
|
||||
if (beginIndex >= endIndex) {
|
||||
throw new 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 = new byte[len];
|
||||
System.arraycopy(path, begin, result, 0, len);
|
||||
return new UnixPath(getFileSystem(), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbsolute() {
|
||||
return (path.length > 0 && path[0] == '/');
|
||||
}
|
||||
|
||||
// Resolve child against given base
|
||||
private static byte[] resolve(byte[] base, byte[] child) {
|
||||
int baseLength = base.length;
|
||||
int childLength = child.length;
|
||||
if (childLength == 0)
|
||||
return base;
|
||||
if (baseLength == 0 || child[0] == '/')
|
||||
return child;
|
||||
byte[] result;
|
||||
if (baseLength == 1 && base[0] == '/') {
|
||||
result = new byte[childLength + 1];
|
||||
result[0] = '/';
|
||||
System.arraycopy(child, 0, result, 1, childLength);
|
||||
} else {
|
||||
result = new byte[baseLength + 1 + childLength];
|
||||
System.arraycopy(base, 0, result, 0, baseLength);
|
||||
result[base.length] = '/';
|
||||
System.arraycopy(child, 0, result, baseLength+1, childLength);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixPath resolve(Path obj) {
|
||||
byte[] other = toUnixPath(obj).path;
|
||||
if (other.length > 0 && other[0] == '/')
|
||||
return ((UnixPath)obj);
|
||||
byte[] result = resolve(path, other);
|
||||
return new UnixPath(getFileSystem(), result);
|
||||
}
|
||||
|
||||
UnixPath resolve(byte[] other) {
|
||||
return resolve(new UnixPath(getFileSystem(), other));
|
||||
}
|
||||
|
||||
@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())
|
||||
throw new 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()) {
|
||||
throw new 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 = new byte[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);
|
||||
return new UnixPath(getFileSystem(), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixPath normalize() {
|
||||
final int count = getNameCount();
|
||||
if (count == 0 || isEmpty())
|
||||
return this;
|
||||
|
||||
boolean[] ignore = new boolean[count]; // true => ignore name
|
||||
int[] size = new int[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)
|
||||
return this;
|
||||
|
||||
// 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 = new byte[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++] = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
return new UnixPath(getFileSystem(), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startsWith(Path other) {
|
||||
if (!(Objects.requireNonNull(other) instanceof UnixPath))
|
||||
return false;
|
||||
UnixPath that = (UnixPath)other;
|
||||
|
||||
// other path is longer
|
||||
if (that.path.length > path.length)
|
||||
return false;
|
||||
|
||||
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)
|
||||
return false;
|
||||
|
||||
// same number of elements so must be exact match
|
||||
if ((thatOffsetCount == thisOffsetCount) &&
|
||||
(path.length != that.path.length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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))
|
||||
return false;
|
||||
}
|
||||
|
||||
// offsets match so need to compare bytes
|
||||
int i=0;
|
||||
while (i < that.path.length) {
|
||||
if (this.path[i] != that.path[i])
|
||||
return false;
|
||||
i++;
|
||||
}
|
||||
|
||||
// final check that match is on name boundary
|
||||
if (i < path.length && this.path[i] != '/')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean endsWith(Path other) {
|
||||
if (!(Objects.requireNonNull(other) instanceof UnixPath))
|
||||
return false;
|
||||
UnixPath that = (UnixPath)other;
|
||||
|
||||
int thisLen = path.length;
|
||||
int thatLen = that.path.length;
|
||||
|
||||
// other path is longer
|
||||
if (thatLen > thisLen)
|
||||
return false;
|
||||
|
||||
// other path is the empty path
|
||||
if (thisLen > 0 && thatLen == 0)
|
||||
return false;
|
||||
|
||||
// other path is absolute so this path must be absolute
|
||||
if (that.isAbsolute() && !this.isAbsolute())
|
||||
return false;
|
||||
|
||||
int thisOffsetCount = getNameCount();
|
||||
int thatOffsetCount = that.getNameCount();
|
||||
|
||||
// given path has more elements that this path
|
||||
if (thatOffsetCount > thisOffsetCount) {
|
||||
return false;
|
||||
} else {
|
||||
// same number of elements
|
||||
if (thatOffsetCount == thisOffsetCount) {
|
||||
if (thisOffsetCount == 0)
|
||||
return true;
|
||||
int expectedLen = thisLen;
|
||||
if (this.isAbsolute() && !that.isAbsolute())
|
||||
expectedLen--;
|
||||
if (thatLen != expectedLen)
|
||||
return false;
|
||||
} else {
|
||||
// this path has more elements so given path must be relative
|
||||
if (that.isAbsolute())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// compare bytes
|
||||
int thisPos = offsets[thisOffsetCount - thatOffsetCount];
|
||||
int thatPos = that.offsets[0];
|
||||
if ((thatLen - thatPos) != (thisLen - thisPos))
|
||||
return false;
|
||||
while (thatPos < thatLen) {
|
||||
if (this.path[thisPos++] != that.path[thatPos++])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int 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
|
||||
public boolean equals(Object ob) {
|
||||
if ((ob != null) && (ob instanceof UnixPath)) {
|
||||
return compareTo((Path)ob) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int 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)
|
||||
throw new UnixException
|
||||
("NOFOLLOW_LINKS is not supported on this platform");
|
||||
flags |= O_NOFOLLOW;
|
||||
}
|
||||
try {
|
||||
return open(this, flags, 0);
|
||||
} catch (UnixException x) {
|
||||
// HACK: EINVAL instead of ELOOP on Solaris 10 prior to u4 (see 6460380)
|
||||
if (getFileSystem().isSolaris() && x.errno() == EINVAL)
|
||||
x.setError(ELOOP);
|
||||
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
void checkRead() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkRead(getPathForPermissionCheck());
|
||||
}
|
||||
|
||||
void checkWrite() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkWrite(getPathForPermissionCheck());
|
||||
}
|
||||
|
||||
void checkDelete() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkDelete(getPathForPermissionCheck());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixPath toAbsolutePath() {
|
||||
if (isAbsolute()) {
|
||||
return this;
|
||||
}
|
||||
// The path is relative so need to resolve against default directory,
|
||||
// taking care not to reveal the user.dir
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPropertyAccess("user.dir");
|
||||
}
|
||||
return new 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);
|
||||
return new 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);
|
||||
|
||||
// eliminate "."
|
||||
if ((element.asByteArray().length == 1) && (element.asByteArray()[0] == '.'))
|
||||
continue;
|
||||
|
||||
// cannot eliminate ".." if previous element is a link
|
||||
if ((element.asByteArray().length == 2) && (element.asByteArray()[0] == '.') &&
|
||||
(element.asByteArray()[1] == '.'))
|
||||
{
|
||||
UnixFileAttributes attrs = null;
|
||||
try {
|
||||
attrs = UnixFileAttributes.get(result, false);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(result);
|
||||
}
|
||||
if (!attrs.isSymbolicLink()) {
|
||||
result = result.getParent();
|
||||
if (result == null) {
|
||||
result = fs.rootDirectory();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result = result.resolve(element);
|
||||
}
|
||||
|
||||
// check file exists (without following links)
|
||||
try {
|
||||
UnixFileAttributes.get(result, false);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI toUri() {
|
||||
return UnixUriUtils.toUri(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WatchKey register(WatchService watcher,
|
||||
WatchEvent.Kind<?>[] events,
|
||||
WatchEvent.Modifier... modifiers)
|
||||
throws IOException
|
||||
{
|
||||
if (watcher == null)
|
||||
throw new NullPointerException();
|
||||
if (!(watcher instanceof AbstractWatchService))
|
||||
throw new ProviderMismatchException();
|
||||
checkRead();
|
||||
return ((AbstractWatchService)watcher).register(this, events, modifiers);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,557 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2011, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.io.IOException;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
/**
|
||||
* Unix implementation of SecureDirectoryStream.
|
||||
*/
|
||||
|
||||
class UnixSecureDirectoryStream
|
||||
implements SecureDirectoryStream<Path>
|
||||
{
|
||||
private final UnixDirectoryStream ds;
|
||||
private final int dfd;
|
||||
|
||||
UnixSecureDirectoryStream(UnixPath dir,
|
||||
long dp,
|
||||
int dfd,
|
||||
DirectoryStream.Filter<? super Path> filter)
|
||||
{
|
||||
this.ds = new UnixDirectoryStream(dir, dp, filter);
|
||||
this.dfd = dfd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
throws IOException
|
||||
{
|
||||
ds.writeLock().lock();
|
||||
try {
|
||||
if (ds.closeImpl()) {
|
||||
UnixNativeDispatcher.close(dfd);
|
||||
}
|
||||
} finally {
|
||||
ds.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Path> iterator() {
|
||||
return ds.iterator(this);
|
||||
}
|
||||
|
||||
private UnixPath getName(Path obj) {
|
||||
if (obj == null)
|
||||
throw new NullPointerException();
|
||||
if (!(obj instanceof UnixPath))
|
||||
throw new ProviderMismatchException();
|
||||
return (UnixPath)obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens sub-directory in this directory
|
||||
*/
|
||||
@Override
|
||||
public SecureDirectoryStream<Path> newDirectoryStream(Path obj,
|
||||
LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath file = getName(obj);
|
||||
UnixPath child = ds.directory().resolve(file);
|
||||
boolean followLinks = Util.followLinks(options);
|
||||
|
||||
// permission check using name resolved against original path of directory
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
child.checkRead();
|
||||
}
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
|
||||
// open directory and create new secure directory stream
|
||||
int newdfd1 = -1;
|
||||
int newdfd2 = -1;
|
||||
long ptr = 0L;
|
||||
try {
|
||||
int flags = O_RDONLY;
|
||||
if (!followLinks)
|
||||
flags |= O_NOFOLLOW;
|
||||
newdfd1 = openat(dfd, file.asByteArray(), flags , 0);
|
||||
newdfd2 = dup(newdfd1);
|
||||
ptr = fdopendir(newdfd1);
|
||||
} catch (UnixException x) {
|
||||
if (newdfd1 != -1)
|
||||
UnixNativeDispatcher.close(newdfd1);
|
||||
if (newdfd2 != -1)
|
||||
UnixNativeDispatcher.close(newdfd2);
|
||||
if (x.errno() == UnixConstants.ENOTDIR)
|
||||
throw new NotDirectoryException(file.toString());
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
return new UnixSecureDirectoryStream(child, ptr, newdfd2, null);
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens file in this directory
|
||||
*/
|
||||
@Override
|
||||
public SeekableByteChannel newByteChannel(Path obj,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath file = getName(obj);
|
||||
|
||||
int mode = UnixFileModeAttribute
|
||||
.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
|
||||
|
||||
// path for permission check
|
||||
String pathToCheck = ds.directory().resolve(file).getPathForPermissionCheck();
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
try {
|
||||
return UnixChannelFactory.newFileChannel(dfd, file, pathToCheck, options, mode);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes file/directory in this directory. Works in a race-free manner
|
||||
* when invoked with flags.
|
||||
*/
|
||||
private void implDelete(Path obj, boolean haveFlags, int flags)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath file = getName(obj);
|
||||
|
||||
// permission check using name resolved against original path of directory
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
ds.directory().resolve(file).checkDelete();
|
||||
}
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
|
||||
if (!haveFlags) {
|
||||
// need file attribute to know if file is directory. This creates
|
||||
// a race in that the file may be replaced by a directory or a
|
||||
// directory replaced by a file between the time we query the
|
||||
// file type and unlink it.
|
||||
UnixFileAttributes attrs = null;
|
||||
try {
|
||||
attrs = UnixFileAttributes.get(dfd, file, false);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
flags = (attrs.isDirectory()) ? AT_REMOVEDIR : 0;
|
||||
}
|
||||
|
||||
try {
|
||||
unlinkat(dfd, file.asByteArray(), flags);
|
||||
} catch (UnixException x) {
|
||||
if ((flags & AT_REMOVEDIR) != 0) {
|
||||
if (x.errno() == EEXIST || x.errno() == ENOTEMPTY) {
|
||||
throw new DirectoryNotEmptyException(null);
|
||||
}
|
||||
}
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteFile(Path file) throws IOException {
|
||||
implDelete(file, true, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteDirectory(Path dir) throws IOException {
|
||||
implDelete(dir, true, AT_REMOVEDIR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename/move file in this directory to another (open) directory
|
||||
*/
|
||||
@Override
|
||||
public void move(Path fromObj, SecureDirectoryStream<Path> dir, Path toObj)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath from = getName(fromObj);
|
||||
UnixPath to = getName(toObj);
|
||||
if (dir == null)
|
||||
throw new NullPointerException();
|
||||
if (!(dir instanceof UnixSecureDirectoryStream))
|
||||
throw new ProviderMismatchException();
|
||||
UnixSecureDirectoryStream that = (UnixSecureDirectoryStream)dir;
|
||||
|
||||
// permission check
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
this.ds.directory().resolve(from).checkWrite();
|
||||
that.ds.directory().resolve(to).checkWrite();
|
||||
}
|
||||
|
||||
// lock ordering doesn't matter
|
||||
this.ds.readLock().lock();
|
||||
try {
|
||||
that.ds.readLock().lock();
|
||||
try {
|
||||
if (!this.ds.isOpen() || !that.ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
try {
|
||||
renameat(this.dfd, from.asByteArray(), that.dfd, to.asByteArray());
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() == EXDEV) {
|
||||
throw new AtomicMoveNotSupportedException(
|
||||
from.toString(), to.toString(), x.errorString());
|
||||
}
|
||||
x.rethrowAsIOException(from, to);
|
||||
}
|
||||
} finally {
|
||||
that.ds.readLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
this.ds.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <V extends FileAttributeView> V getFileAttributeViewImpl(UnixPath file,
|
||||
Class<V> type,
|
||||
boolean followLinks)
|
||||
{
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
Class<?> c = type;
|
||||
if (c == BasicFileAttributeView.class) {
|
||||
return (V) new BasicFileAttributeViewImpl(file, followLinks);
|
||||
}
|
||||
if (c == PosixFileAttributeView.class || c == FileOwnerAttributeView.class) {
|
||||
return (V) new PosixFileAttributeViewImpl(file, followLinks);
|
||||
}
|
||||
// TBD - should also support AclFileAttributeView
|
||||
return (V) null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns file attribute view bound to this directory
|
||||
*/
|
||||
@Override
|
||||
public <V extends FileAttributeView> V getFileAttributeView(Class<V> type) {
|
||||
return getFileAttributeViewImpl(null, type, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns file attribute view bound to dfd/filename.
|
||||
*/
|
||||
@Override
|
||||
public <V extends FileAttributeView> V getFileAttributeView(Path obj,
|
||||
Class<V> type,
|
||||
LinkOption... options)
|
||||
{
|
||||
UnixPath file = getName(obj);
|
||||
boolean followLinks = Util.followLinks(options);
|
||||
return getFileAttributeViewImpl(file, type, followLinks);
|
||||
}
|
||||
|
||||
/**
|
||||
* A BasicFileAttributeView implementation that using a dfd/name pair.
|
||||
*/
|
||||
private class BasicFileAttributeViewImpl
|
||||
implements BasicFileAttributeView
|
||||
{
|
||||
final UnixPath file;
|
||||
final boolean followLinks;
|
||||
|
||||
BasicFileAttributeViewImpl(UnixPath file, boolean followLinks)
|
||||
{
|
||||
this.file = file;
|
||||
this.followLinks = followLinks;
|
||||
}
|
||||
|
||||
int open() throws IOException {
|
||||
int oflags = O_RDONLY;
|
||||
if (!followLinks)
|
||||
oflags |= O_NOFOLLOW;
|
||||
try {
|
||||
return openat(dfd, file.asByteArray(), oflags, 0);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return -1; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
private void checkWriteAccess() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
if (file == null) {
|
||||
ds.directory().checkWrite();
|
||||
} else {
|
||||
ds.directory().resolve(file).checkWrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "basic";
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicFileAttributes readAttributes() throws IOException {
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
if (file == null) {
|
||||
ds.directory().checkRead();
|
||||
} else {
|
||||
ds.directory().resolve(file).checkRead();
|
||||
}
|
||||
}
|
||||
try {
|
||||
UnixFileAttributes attrs = (file == null) ?
|
||||
UnixFileAttributes.get(dfd) :
|
||||
UnixFileAttributes.get(dfd, file, followLinks);
|
||||
|
||||
// SECURITY: must return as BasicFileAttribute
|
||||
return attrs.asBasicFileAttributes();
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimes(FileTime lastModifiedTime,
|
||||
FileTime lastAccessTime,
|
||||
FileTime createTime) // ignore
|
||||
throws IOException
|
||||
{
|
||||
checkWriteAccess();
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
|
||||
int fd = (file == null) ? dfd : open();
|
||||
try {
|
||||
// if not changing both attributes then need existing attributes
|
||||
if (lastModifiedTime == null || lastAccessTime == null) {
|
||||
try {
|
||||
UnixFileAttributes attrs = UnixFileAttributes.get(fd);
|
||||
if (lastModifiedTime == null)
|
||||
lastModifiedTime = attrs.lastModifiedTime();
|
||||
if (lastAccessTime == null)
|
||||
lastAccessTime = attrs.lastAccessTime();
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
// update times
|
||||
try {
|
||||
futimes(fd,
|
||||
lastAccessTime.to(TimeUnit.MICROSECONDS),
|
||||
lastModifiedTime.to(TimeUnit.MICROSECONDS));
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
} finally {
|
||||
if (file != null)
|
||||
UnixNativeDispatcher.close(fd);
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A PosixFileAttributeView implementation that using a dfd/name pair.
|
||||
*/
|
||||
private class PosixFileAttributeViewImpl
|
||||
extends BasicFileAttributeViewImpl implements PosixFileAttributeView
|
||||
{
|
||||
PosixFileAttributeViewImpl(UnixPath file, boolean followLinks) {
|
||||
super(file, followLinks);
|
||||
}
|
||||
|
||||
private void checkWriteAndUserAccess() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
super.checkWriteAccess();
|
||||
sm.checkPermission(new RuntimePermission("accessUserInformation"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "posix";
|
||||
}
|
||||
|
||||
@Override
|
||||
public PosixFileAttributes readAttributes() throws IOException {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
if (file == null)
|
||||
ds.directory().checkRead();
|
||||
else
|
||||
ds.directory().resolve(file).checkRead();
|
||||
sm.checkPermission(new RuntimePermission("accessUserInformation"));
|
||||
}
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
|
||||
try {
|
||||
UnixFileAttributes attrs = (file == null) ?
|
||||
UnixFileAttributes.get(dfd) :
|
||||
UnixFileAttributes.get(dfd, file, followLinks);
|
||||
return attrs;
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermissions(Set<PosixFilePermission> perms)
|
||||
throws IOException
|
||||
{
|
||||
// permission check
|
||||
checkWriteAndUserAccess();
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
|
||||
int fd = (file == null) ? dfd : open();
|
||||
try {
|
||||
fchmod(fd, UnixFileModeAttribute.toUnixMode(perms));
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
} finally {
|
||||
if (file != null && fd >= 0)
|
||||
UnixNativeDispatcher.close(fd);
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void setOwners(int uid, int gid) throws IOException {
|
||||
// permission check
|
||||
checkWriteAndUserAccess();
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
|
||||
int fd = (file == null) ? dfd : open();
|
||||
try {
|
||||
fchown(fd, uid, gid);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
} finally {
|
||||
if (file != null && fd >= 0)
|
||||
UnixNativeDispatcher.close(fd);
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserPrincipal getOwner() throws IOException {
|
||||
return readAttributes().owner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwner(UserPrincipal owner)
|
||||
throws IOException
|
||||
{
|
||||
if (!(owner instanceof UnixUserPrincipals.User))
|
||||
throw new ProviderMismatchException();
|
||||
if (owner instanceof UnixUserPrincipals.Group)
|
||||
throw new IOException("'owner' parameter can't be a group");
|
||||
int uid = ((UnixUserPrincipals.User)owner).uid();
|
||||
setOwners(uid, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroup(GroupPrincipal group)
|
||||
throws IOException
|
||||
{
|
||||
if (!(group instanceof UnixUserPrincipals.Group))
|
||||
throw new ProviderMismatchException();
|
||||
int gid = ((UnixUserPrincipals.Group)group).gid();
|
||||
setOwners(-1, gid);
|
||||
}
|
||||
}
|
||||
}
|
246
src/java.base/unix/classes/sun/nio/fs/UnixUriUtils.java
Normal file
246
src/java.base/unix/classes/sun/nio/fs/UnixUriUtils.java
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Unix specific Path <--> URI conversion
|
||||
*/
|
||||
|
||||
class UnixUriUtils {
|
||||
private UnixUriUtils() { }
|
||||
|
||||
/**
|
||||
* Converts URI to Path
|
||||
*/
|
||||
static Path fromUri(UnixFileSystem fs, URI uri) {
|
||||
if (!uri.isAbsolute())
|
||||
throw new IllegalArgumentException("URI is not absolute");
|
||||
if (uri.isOpaque())
|
||||
throw new IllegalArgumentException("URI is not hierarchical");
|
||||
String scheme = uri.getScheme();
|
||||
if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
|
||||
throw new IllegalArgumentException("URI scheme is not \"file\"");
|
||||
if (uri.getRawAuthority() != null)
|
||||
throw new IllegalArgumentException("URI has an authority component");
|
||||
if (uri.getRawFragment() != null)
|
||||
throw new IllegalArgumentException("URI has a fragment component");
|
||||
if (uri.getRawQuery() != null)
|
||||
throw new IllegalArgumentException("URI has a query component");
|
||||
|
||||
// compatibility with java.io.File
|
||||
if (!uri.toString().startsWith("file:///"))
|
||||
return new File(uri).toPath();
|
||||
|
||||
// transformation use raw path
|
||||
String p = uri.getRawPath();
|
||||
int len = p.length();
|
||||
if (len == 0)
|
||||
throw new IllegalArgumentException("URI path component is empty");
|
||||
|
||||
// transform escaped octets and unescaped characters to bytes
|
||||
if (p.endsWith("/") && len > 1)
|
||||
len--;
|
||||
byte[] result = new byte[len];
|
||||
int rlen = 0;
|
||||
int pos = 0;
|
||||
while (pos < len) {
|
||||
char c = p.charAt(pos++);
|
||||
byte b;
|
||||
if (c == '%') {
|
||||
assert (pos+2) <= len;
|
||||
char c1 = p.charAt(pos++);
|
||||
char c2 = p.charAt(pos++);
|
||||
b = (byte)((decode(c1) << 4) | decode(c2));
|
||||
if (b == 0)
|
||||
throw new IllegalArgumentException("Nul character not allowed");
|
||||
} else {
|
||||
assert c < 0x80;
|
||||
b = (byte)c;
|
||||
}
|
||||
result[rlen++] = b;
|
||||
}
|
||||
if (rlen != result.length)
|
||||
result = Arrays.copyOf(result, rlen);
|
||||
|
||||
return new UnixPath(fs, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Path to URI
|
||||
*/
|
||||
static URI toUri(UnixPath up) {
|
||||
byte[] path = up.toAbsolutePath().asByteArray();
|
||||
StringBuilder sb = new StringBuilder("file:///");
|
||||
assert path[0] == '/';
|
||||
for (int i=1; i<path.length; i++) {
|
||||
char c = (char)(path[i] & 0xff);
|
||||
if (match(c, L_PATH, H_PATH)) {
|
||||
sb.append(c);
|
||||
} else {
|
||||
sb.append('%');
|
||||
sb.append(hexDigits[(c >> 4) & 0x0f]);
|
||||
sb.append(hexDigits[(c) & 0x0f]);
|
||||
}
|
||||
}
|
||||
|
||||
// trailing slash if directory
|
||||
if (sb.charAt(sb.length()-1) != '/') {
|
||||
int mode = UnixNativeDispatcher.stat(up);
|
||||
if ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR)
|
||||
sb.append('/');
|
||||
}
|
||||
|
||||
try {
|
||||
return new URI(sb.toString());
|
||||
} catch (URISyntaxException x) {
|
||||
throw new AssertionError(x); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
// The following is copied from java.net.URI
|
||||
|
||||
// Compute the low-order mask for the characters in the given string
|
||||
private static long lowMask(String chars) {
|
||||
int n = chars.length();
|
||||
long m = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = chars.charAt(i);
|
||||
if (c < 64)
|
||||
m |= (1L << c);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
// Compute the high-order mask for the characters in the given string
|
||||
private static long highMask(String chars) {
|
||||
int n = chars.length();
|
||||
long m = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = chars.charAt(i);
|
||||
if ((c >= 64) && (c < 128))
|
||||
m |= (1L << (c - 64));
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
// Compute a low-order mask for the characters
|
||||
// between first and last, inclusive
|
||||
private static long lowMask(char first, char last) {
|
||||
long m = 0;
|
||||
int f = Math.max(Math.min(first, 63), 0);
|
||||
int l = Math.max(Math.min(last, 63), 0);
|
||||
for (int i = f; i <= l; i++)
|
||||
m |= 1L << i;
|
||||
return m;
|
||||
}
|
||||
|
||||
// Compute a high-order mask for the characters
|
||||
// between first and last, inclusive
|
||||
private static long highMask(char first, char last) {
|
||||
long m = 0;
|
||||
int f = Math.max(Math.min(first, 127), 64) - 64;
|
||||
int l = Math.max(Math.min(last, 127), 64) - 64;
|
||||
for (int i = f; i <= l; i++)
|
||||
m |= 1L << i;
|
||||
return m;
|
||||
}
|
||||
|
||||
// Tell whether the given character is permitted by the given mask pair
|
||||
private static boolean match(char c, long lowMask, long highMask) {
|
||||
if (c < 64)
|
||||
return ((1L << c) & lowMask) != 0;
|
||||
if (c < 128)
|
||||
return ((1L << (c - 64)) & highMask) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// decode
|
||||
private static int decode(char c) {
|
||||
if ((c >= '0') && (c <= '9'))
|
||||
return c - '0';
|
||||
if ((c >= 'a') && (c <= 'f'))
|
||||
return c - 'a' + 10;
|
||||
if ((c >= 'A') && (c <= 'F'))
|
||||
return c - 'A' + 10;
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
|
||||
// "8" | "9"
|
||||
private static final long L_DIGIT = lowMask('0', '9');
|
||||
private static final long H_DIGIT = 0L;
|
||||
|
||||
// upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
|
||||
// "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
|
||||
// "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
|
||||
private static final long L_UPALPHA = 0L;
|
||||
private static final long H_UPALPHA = highMask('A', 'Z');
|
||||
|
||||
// lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
|
||||
// "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
|
||||
// "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
|
||||
private static final long L_LOWALPHA = 0L;
|
||||
private static final long H_LOWALPHA = highMask('a', 'z');
|
||||
|
||||
// alpha = lowalpha | upalpha
|
||||
private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
|
||||
private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
|
||||
|
||||
// alphanum = alpha | digit
|
||||
private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
|
||||
private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
|
||||
|
||||
// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
|
||||
// "(" | ")"
|
||||
private static final long L_MARK = lowMask("-_.!~*'()");
|
||||
private static final long H_MARK = highMask("-_.!~*'()");
|
||||
|
||||
// unreserved = alphanum | mark
|
||||
private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
|
||||
private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
|
||||
|
||||
// pchar = unreserved | escaped |
|
||||
// ":" | "@" | "&" | "=" | "+" | "$" | ","
|
||||
private static final long L_PCHAR
|
||||
= L_UNRESERVED | lowMask(":@&=+$,");
|
||||
private static final long H_PCHAR
|
||||
= H_UNRESERVED | highMask(":@&=+$,");
|
||||
|
||||
// All valid path characters
|
||||
private static final long L_PATH = L_PCHAR | lowMask(";/");
|
||||
private static final long H_PATH = H_PCHAR | highMask(";/");
|
||||
|
||||
private static final char[] hexDigits = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
}
|
181
src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java
Normal file
181
src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, 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 sun.nio.fs;
|
||||
|
||||
import java.nio.file.attribute.*;
|
||||
import java.io.IOException;
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
|
||||
/**
|
||||
* Unix implementation of java.nio.file.attribute.UserPrincipal
|
||||
*/
|
||||
|
||||
class UnixUserPrincipals {
|
||||
private static User createSpecial(String name) { return new User(-1, name); }
|
||||
|
||||
static final User SPECIAL_OWNER = createSpecial("OWNER@");
|
||||
static final User SPECIAL_GROUP = createSpecial("GROUP@");
|
||||
static final User SPECIAL_EVERYONE = createSpecial("EVERYONE@");
|
||||
|
||||
static class User implements UserPrincipal {
|
||||
private final int id; // uid or gid
|
||||
private final boolean isGroup;
|
||||
private final String name;
|
||||
|
||||
private User(int id, boolean isGroup, String name) {
|
||||
this.id = id;
|
||||
this.isGroup = isGroup;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
User(int id, String name) {
|
||||
this(id, false, name);
|
||||
}
|
||||
|
||||
int uid() {
|
||||
if (isGroup)
|
||||
throw new AssertionError();
|
||||
return id;
|
||||
}
|
||||
|
||||
int gid() {
|
||||
if (isGroup)
|
||||
return id;
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
boolean isSpecial() {
|
||||
return id == -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (!(obj instanceof User))
|
||||
return false;
|
||||
User other = (User)obj;
|
||||
if ((this.id != other.id) ||
|
||||
(this.isGroup != other.isGroup)) {
|
||||
return false;
|
||||
}
|
||||
// specials
|
||||
if (this.id == -1 && other.id == -1)
|
||||
return this.name.equals(other.name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (id != -1) ? id : name.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
static class Group extends User implements GroupPrincipal {
|
||||
Group(int id, String name) {
|
||||
super(id, true, name);
|
||||
}
|
||||
}
|
||||
|
||||
// return UserPrincipal representing given uid
|
||||
static User fromUid(int uid) {
|
||||
String name = null;
|
||||
try {
|
||||
name = Util.toString(getpwuid(uid));
|
||||
} catch (UnixException x) {
|
||||
name = Integer.toString(uid);
|
||||
}
|
||||
return new User(uid, name);
|
||||
}
|
||||
|
||||
// return GroupPrincipal representing given gid
|
||||
static Group fromGid(int gid) {
|
||||
String name = null;
|
||||
try {
|
||||
name = Util.toString(getgrgid(gid));
|
||||
} catch (UnixException x) {
|
||||
name = Integer.toString(gid);
|
||||
}
|
||||
return new Group(gid, name);
|
||||
}
|
||||
|
||||
// lookup user or group name
|
||||
private static int lookupName(String name, boolean isGroup)
|
||||
throws IOException
|
||||
{
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new RuntimePermission("lookupUserInformation"));
|
||||
}
|
||||
int id = -1;
|
||||
try {
|
||||
id = (isGroup) ? getgrnam(name) : getpwnam(name);
|
||||
} catch (UnixException x) {
|
||||
throw new IOException(name + ": " + x.errorString());
|
||||
}
|
||||
if (id == -1) {
|
||||
// lookup failed, allow input to be uid or gid
|
||||
try {
|
||||
id = Integer.parseInt(name);
|
||||
} catch (NumberFormatException ignore) {
|
||||
throw new UserPrincipalNotFoundException(name);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
|
||||
}
|
||||
|
||||
// lookup user name
|
||||
static UserPrincipal lookupUser(String name) throws IOException {
|
||||
if (name.equals(SPECIAL_OWNER.getName()))
|
||||
return SPECIAL_OWNER;
|
||||
if (name.equals(SPECIAL_GROUP.getName()))
|
||||
return SPECIAL_GROUP;
|
||||
if (name.equals(SPECIAL_EVERYONE.getName()))
|
||||
return SPECIAL_EVERYONE;
|
||||
int uid = lookupName(name, false);
|
||||
return new User(uid, name);
|
||||
}
|
||||
|
||||
// lookup group name
|
||||
static GroupPrincipal lookupGroup(String group)
|
||||
throws IOException
|
||||
{
|
||||
int gid = lookupName(group, true);
|
||||
return new Group(gid, group);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue