mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-11 19:08:23 +00:00
8356493: (fs) SecureDirectoryStream missing some capabilities
This commit is contained in:
parent
c755345177
commit
8667bca08f
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2025, 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
|
||||
@ -135,6 +135,182 @@ public interface SecureDirectoryStream<T>
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a new and empty file, failing if the file already exists.
|
||||
*
|
||||
* <p>This method works in a similar manner to {@linkplain Files#createFile
|
||||
* Files.createFile}. If the {@code path} parameter is an {@linkplain
|
||||
* Path#isAbsolute absolute} path then it locates the file to create. If
|
||||
* the parameter is a relative path then it is located relative to this
|
||||
* open directory.
|
||||
*
|
||||
* <p> The {@code attrs} parameter is optional with effects as specified
|
||||
* for {@linkplain Files#createFile Files.createFile}.
|
||||
*
|
||||
* @param path
|
||||
* the path of the file to create
|
||||
* @param attrs
|
||||
* an optional list of file attributes to set atomically when
|
||||
* creating the file
|
||||
*
|
||||
* @return the file
|
||||
*
|
||||
* @throws ClosedDirectoryStreamException
|
||||
* if the directory stream is closed
|
||||
* @throws UnsupportedOperationException
|
||||
* if the array contains an attribute that cannot be set atomically
|
||||
* when creating the directory
|
||||
* @throws FileAlreadyExistsException
|
||||
* if a file could not otherwise be created because a file of
|
||||
* that name already exists <i>(optional specific exception)</i>
|
||||
* @throws IOException
|
||||
* if an I/O error occurs or the parent directory does not exist
|
||||
*
|
||||
* @since 26
|
||||
*/
|
||||
Path createFile(Path path, FileAttribute<?>... attrs)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a new directory, failing if a file of that name already exists.
|
||||
*
|
||||
* <p>This method works in a similar manner to {@linkplain
|
||||
* Files#createDirectory Files.createDirectory}. If the {@code path}
|
||||
* parameter is an {@linkplain Path#isAbsolute absolute} path then it
|
||||
* locates the directory to create. If the parameter is a relative path
|
||||
* then it is located relative to this open directory.
|
||||
*
|
||||
* <p> The {@code attrs} parameter is optional with effects as specified
|
||||
* for {@linkplain Files#createDirectory Files.createDirectory}.
|
||||
*
|
||||
* @param dir
|
||||
* the path of the directory to create
|
||||
* @param attrs
|
||||
* an optional list of file attributes to set atomically when
|
||||
* creating the directory
|
||||
*
|
||||
* @return the directory
|
||||
*
|
||||
* @throws ClosedDirectoryStreamException
|
||||
* if the directory stream is closed
|
||||
* @throws UnsupportedOperationException
|
||||
* if the array contains an attribute that cannot be set atomically
|
||||
* when creating the directory
|
||||
* @throws FileAlreadyExistsException
|
||||
* if a directory could not otherwise be created because a file of
|
||||
* that name already exists <i>(optional specific exception)</i>
|
||||
* @throws IOException
|
||||
* if an I/O error occurs or the parent directory does not exist
|
||||
*
|
||||
* @since 26
|
||||
*/
|
||||
Path createDirectory(Path dir, FileAttribute<?>... attrs)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a new link (directory entry) for an existing file <i>(optional
|
||||
* operation)</i>.
|
||||
*
|
||||
* <p>This method works in a similar manner to {@linkplain Files#createLink
|
||||
* Files.createLink}. If the {@code link} parameter is an {@link
|
||||
* Path#isAbsolute absolute} path then it locates the link file. If the
|
||||
* {@code link} parameter is a relative path then it is located relative to
|
||||
* this open directory. If the {@code existing} parameter is an absolute
|
||||
* path then it locates the target file (the {@code targetdir} parameter is
|
||||
* ignored). If the {@code existing} parameter is a relative path it is
|
||||
* located relative to the open directory identified by the {@code
|
||||
* targetdir} parameter.
|
||||
*
|
||||
* @param link
|
||||
* the link (directory entry) to create
|
||||
* @param targetdir
|
||||
* the destination directory
|
||||
* @param existing
|
||||
* a path to an existing file
|
||||
*
|
||||
* @return the path to the link (directory entry)
|
||||
*
|
||||
* @throws ClosedDirectoryStreamException
|
||||
* if the directory stream is closed
|
||||
* @throws UnsupportedOperationException
|
||||
* if the implementation does not support adding an existing file
|
||||
* to a directory
|
||||
* @throws FileAlreadyExistsException
|
||||
* if the entry could not otherwise be created because a file of
|
||||
* that name already exists <i>(optional specific exception)</i>
|
||||
* @throws NoSuchFileException
|
||||
* if the file specified by the combination of {@code targetdir}
|
||||
* and {@code existing} does not exist
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*
|
||||
* @since 26
|
||||
*/
|
||||
Path createLink(T link, SecureDirectoryStream<T> targetdir, T existing)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a symbolic link to a target <i>(optional operation)</i>.
|
||||
*
|
||||
* <p>This method works in a similar manner to {@linkplain Files#createSymbolicLink
|
||||
* Files.createSymbolicLink}. If the {@code link} parameter is an {@link
|
||||
* Path#isAbsolute absolute} path then it locates the link file. If the
|
||||
* {@code link} parameter is a relative path then it is located relative to
|
||||
* this open directory. The {@code target} parameter is the target of the
|
||||
* link and behaves as specified for {@linkplain Files#createSymbolicLink
|
||||
* Files.createSymbolicLink}.
|
||||
*
|
||||
* @param link
|
||||
* the path of the symbolic link to create
|
||||
* @param target
|
||||
* the target of the symbolic link
|
||||
* @param attrs
|
||||
* the array of attributes to set atomically when creating the
|
||||
* symbolic link
|
||||
*
|
||||
* @return the path to the symbolic link
|
||||
*
|
||||
* @throws ClosedDirectoryStreamException
|
||||
* if the directory stream is closed
|
||||
* @throws UnsupportedOperationException
|
||||
* if the implementation does not support symbolic links or the
|
||||
* array contains an attribute that cannot be set atomically when
|
||||
* creating the symbolic link
|
||||
* @throws FileAlreadyExistsException
|
||||
* if a file with the name already exists <i>(optional specific
|
||||
* exception)</i>
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
Path createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Reads the target of a symbolic link <i>(optional operation)</i>.
|
||||
*
|
||||
* <p>This method works in a similar manner to {@linkplain Files#readSymbolicLink
|
||||
* Files.readSymbolicLink}. If the {@code link} parameter is an {@link
|
||||
* Path#isAbsolute absolute} path then it locates the link file. If the
|
||||
* {@code link} parameter is a relative path then it is located relative to
|
||||
* this open directory.
|
||||
*
|
||||
* @param link
|
||||
* the path to the symbolic link
|
||||
*
|
||||
* @return a {@code Path} object representing the target of the link
|
||||
*
|
||||
* @throws ClosedDirectoryStreamException
|
||||
* if the directory stream is closed
|
||||
* @throws UnsupportedOperationException
|
||||
* if the implementation does not support symbolic links
|
||||
* @throws NotLinkException
|
||||
* if the target could otherwise not be read because the file
|
||||
* is not a symbolic link <i>(optional specific exception)</i>
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
Path readSymbolicLink(Path link) throws IOException;
|
||||
|
||||
/**
|
||||
* Deletes a file.
|
||||
*
|
||||
@ -185,8 +361,8 @@ public interface SecureDirectoryStream<T>
|
||||
/**
|
||||
* Move a file from this directory to another directory.
|
||||
*
|
||||
* <p> This method works in a similar manner to {@link Files#move move}
|
||||
* method when the {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} option
|
||||
* <p> This method works in a similar manner to {@link Files#move Files.move}
|
||||
* when the {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} option
|
||||
* is specified. That is, this method moves a file as an atomic file system
|
||||
* operation. If the {@code srcpath} parameter is an {@link Path#isAbsolute
|
||||
* absolute} path then it locates the source file. If the parameter is a
|
||||
|
||||
@ -358,10 +358,10 @@ public abstract class UnixFileSystemProvider
|
||||
if (attrs == null) {
|
||||
break;
|
||||
}
|
||||
UnixFileKey fileKey = attrs.fileKey();
|
||||
if (!attrs.isSymbolicLink()) {
|
||||
break;
|
||||
}
|
||||
UnixFileKey fileKey = attrs.fileKey();
|
||||
if (!fileKeys.add(fileKey)) {
|
||||
throw new UnixException(ELOOP);
|
||||
}
|
||||
|
||||
@ -133,6 +133,21 @@ class UnixNativeDispatcher {
|
||||
private static native void link0(long existingAddress, long newAddress)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* linkat(int fd1, const char *name1, int fd2, const char *name2, int flag)
|
||||
*/
|
||||
static void linkat(int dfd1, UnixPath path1, int dfd2, UnixPath path2)
|
||||
throws UnixException
|
||||
{
|
||||
try (NativeBuffer buffer1 = copyToNativeBuffer(path1);
|
||||
NativeBuffer buffer2 = copyToNativeBuffer(path2)) {
|
||||
linkat0(dfd1, buffer1.address(), dfd2, buffer2.address());
|
||||
}
|
||||
}
|
||||
private static native void linkat0(int dfd1, long addr1,
|
||||
int dfd2, long addr2)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* unlink(const char* path)
|
||||
*/
|
||||
@ -199,6 +214,19 @@ class UnixNativeDispatcher {
|
||||
}
|
||||
private static native void mkdir0(long pathAddress, int mode) throws UnixException;
|
||||
|
||||
/**
|
||||
* mkdirat(int dfd, const char *path, mode_t mode)
|
||||
*/
|
||||
static void mkdirat(int dfd, UnixPath path, int mode)
|
||||
throws UnixException
|
||||
{
|
||||
try (NativeBuffer buffer = copyToNativeBuffer(path)) {
|
||||
mkdirat0(dfd, buffer.address(), mode);
|
||||
}
|
||||
}
|
||||
private static native void mkdirat0(int dfd, long pathAddress, int mode)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* rmdir(const char* path)
|
||||
*/
|
||||
@ -221,6 +249,18 @@ class UnixNativeDispatcher {
|
||||
}
|
||||
private static native byte[] readlink0(long pathAddress) throws UnixException;
|
||||
|
||||
/**
|
||||
* readlinkat(int fd, const char* path, char* buf, size_t bufsize)
|
||||
*
|
||||
* @return link target
|
||||
*/
|
||||
static byte[] readlinkat(int fd, UnixPath path) throws UnixException {
|
||||
try (NativeBuffer buffer = copyToNativeBuffer(path)) {
|
||||
return readlinkat0(fd, buffer.address());
|
||||
}
|
||||
}
|
||||
private static native byte[] readlinkat0(int fd, long pathAddress) throws UnixException;
|
||||
|
||||
/**
|
||||
* realpath(const char* path, char* resolved_name)
|
||||
*
|
||||
@ -245,6 +285,20 @@ class UnixNativeDispatcher {
|
||||
private static native void symlink0(long name1, long name2)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* symlinkat(const char* name1, int fd, const char* name2)
|
||||
*/
|
||||
static void symlinkat(byte[] name1, int fd, UnixPath name2)
|
||||
throws UnixException
|
||||
{
|
||||
try (NativeBuffer targetBuffer = NativeBuffers.asNativeBuffer(name1);
|
||||
NativeBuffer linkBuffer = copyToNativeBuffer(name2)) {
|
||||
symlinkat0(targetBuffer.address(), fd, linkBuffer.address());
|
||||
}
|
||||
}
|
||||
private static native void symlinkat0(long name1, int dfd, long name2)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* stat(const char* path, struct stat* buf)
|
||||
*/
|
||||
|
||||
@ -27,11 +27,35 @@ package sun.nio.fs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.*;
|
||||
import java.nio.file.AtomicMoveNotSupportedException;
|
||||
import java.nio.file.ClosedDirectoryStreamException;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.NotLinkException;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.ProviderMismatchException;
|
||||
import java.nio.file.SecureDirectoryStream;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.attribute.FileOwnerAttributeView;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.nio.file.attribute.GroupPrincipal;
|
||||
import java.nio.file.attribute.PosixFileAttributes;
|
||||
import java.nio.file.attribute.PosixFileAttributeView;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.nio.file.attribute.UserPrincipal;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.nio.file.StandardOpenOption.CREATE_NEW;
|
||||
import static java.nio.file.StandardOpenOption.WRITE;
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
@ -154,6 +178,129 @@ class UnixSecureDirectoryStream
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path createFile(Path path, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
newByteChannel(path, Set.of(CREATE_NEW, WRITE), attrs).close();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path createDirectory(Path dir, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath file = getName(dir);
|
||||
|
||||
int mode = UnixFileModeAttribute
|
||||
.toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs);
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
try {
|
||||
mkdirat(dfd, file, mode);
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() == EISDIR)
|
||||
throw new FileAlreadyExistsException(file.toString());
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path createLink(Path link, SecureDirectoryStream<Path> dir,
|
||||
Path target)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath linkpath = UnixPath.toUnixPath(link);
|
||||
UnixPath targetpath = UnixPath.toUnixPath(target);
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
try {
|
||||
UnixSecureDirectoryStream that = (UnixSecureDirectoryStream)dir;
|
||||
linkat(that.dfd, targetpath, this.dfd, linkpath);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(linkpath, targetpath);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path createSymbolicLink(Path link, Path target,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
UnixPath linkpath = UnixPath.toUnixPath(link);
|
||||
UnixPath targetpath = UnixPath.toUnixPath(target);
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
try {
|
||||
symlinkat(targetpath.asByteArray(), dfd, linkpath);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(linkpath, targetpath);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
} finally {
|
||||
ds.readLock().unlock();
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path readSymbolicLink(Path link) throws IOException {
|
||||
UnixPath linkpath = getName(link);
|
||||
|
||||
ds.readLock().lock();
|
||||
try {
|
||||
if (!ds.isOpen())
|
||||
throw new ClosedDirectoryStreamException();
|
||||
try {
|
||||
UnixFileAttributes attrs =
|
||||
UnixFileAttributes.getIfExists(linkpath, false);
|
||||
if (attrs != null && !attrs.isSymbolicLink())
|
||||
throw new NotLinkException(linkpath.toString());
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(linkpath);
|
||||
}
|
||||
try {
|
||||
byte[] target = readlinkat(dfd, linkpath);
|
||||
return new UnixPath(linkpath.getFileSystem(), target);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(linkpath);
|
||||
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.
|
||||
|
||||
@ -989,6 +989,18 @@ Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this,
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_mkdirat0(JNIEnv* env, jclass this,
|
||||
jint dfd, jlong pathAddress, jint mode)
|
||||
{
|
||||
const char* path = (const char*)jlong_to_ptr(pathAddress);
|
||||
|
||||
/* EINTR not listed as a possible error */
|
||||
if (mkdirat(dfd, path, (mode_t)mode) == -1) {
|
||||
throwUnixException(env, errno);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this,
|
||||
jlong pathAddress)
|
||||
@ -1015,6 +1027,20 @@ Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this,
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_linkat0(JNIEnv* env, jclass this,
|
||||
int dfd1, long addr1,
|
||||
int dfd2, long addr2)
|
||||
{
|
||||
int err;
|
||||
const char* name1 = (const char*)jlong_to_ptr(addr1);
|
||||
const char* name2 = (const char*)jlong_to_ptr(addr2);
|
||||
|
||||
RESTARTABLE(linkat(dfd1, name1, dfd2, name2, AT_SYMLINK_FOLLOW), err);
|
||||
if (err == -1) {
|
||||
throwUnixException(env, errno);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this,
|
||||
@ -1089,6 +1115,19 @@ Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this,
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_symlinkat0(JNIEnv* env, jclass this,
|
||||
jlong targetAddress, jint dfd, jlong linkAddress)
|
||||
{
|
||||
const char* target = (const char*)jlong_to_ptr(targetAddress);
|
||||
const char* link = (const char*)jlong_to_ptr(linkAddress);
|
||||
|
||||
/* EINTR not listed as a possible error */
|
||||
if (symlinkat(target, dfd, link) == -1) {
|
||||
throwUnixException(env, errno);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this,
|
||||
jlong pathAddress)
|
||||
@ -1119,6 +1158,36 @@ Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this,
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_readlinkat0(JNIEnv* env, jclass this,
|
||||
jint fd, jlong pathAddress)
|
||||
{
|
||||
jbyteArray result = NULL;
|
||||
char target[PATH_MAX+1];
|
||||
const char* path = (const char*)jlong_to_ptr(pathAddress);
|
||||
|
||||
/* EINTR not listed as a possible error */
|
||||
int n = readlinkat(fd, path, target, sizeof(target));
|
||||
if (n == -1) {
|
||||
throwUnixException(env, errno);
|
||||
} else {
|
||||
jsize len;
|
||||
if (n == sizeof(target)) {
|
||||
/* Traditionally readlink(2) should not return more than */
|
||||
/* PATH_MAX bytes (no terminating null byte is appended). */
|
||||
throwUnixException(env, ENAMETOOLONG);
|
||||
return NULL;
|
||||
}
|
||||
target[n] = '\0';
|
||||
len = (jsize)strlen(target);
|
||||
result = (*env)->NewByteArray(env, len);
|
||||
if (result != NULL) {
|
||||
(*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this,
|
||||
jlong pathAddress)
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 4313887 6838333 8343020 8357425
|
||||
* @bug 4313887 6838333 8343020 8357425 8356493
|
||||
* @summary Unit test for java.nio.file.SecureDirectoryStream
|
||||
* @requires (os.family == "linux" | os.family == "mac" | os.family == "aix")
|
||||
* @library .. /test/lib
|
||||
@ -31,21 +31,24 @@
|
||||
*/
|
||||
|
||||
import java.nio.file.*;
|
||||
import static java.nio.file.Files.*;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import static java.nio.file.LinkOption.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.nio.channels.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import static java.nio.file.Files.*;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import static java.nio.file.LinkOption.*;
|
||||
|
||||
import jdk.test.lib.Platform;
|
||||
|
||||
public class SecureDS {
|
||||
static boolean supportsSymbolicLinks;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
Path dir = TestUtil.createTemporaryDirectory();
|
||||
String cwd = System.getProperty("user.dir");
|
||||
Path dir = TestUtil.createTemporaryDirectory(cwd);
|
||||
System.err.println("Top level test directory: " + dir);
|
||||
try {
|
||||
DirectoryStream<Path> stream = newDirectoryStream(dir);
|
||||
stream.close();
|
||||
@ -164,6 +167,141 @@ public class SecureDS {
|
||||
} catch (IOException x) { }
|
||||
}
|
||||
|
||||
// Test: createFile
|
||||
Path somefile = Path.of("somefile");
|
||||
// - absolute -
|
||||
Path absfile = dir.resolve(somefile);
|
||||
stream.createFile(absfile);
|
||||
assertTrue(exists(absfile));
|
||||
assertTrue(isRegularFile(absfile));
|
||||
try {
|
||||
stream.createFile(absfile);
|
||||
shouldNotGetHere();
|
||||
} catch (FileAlreadyExistsException x) {
|
||||
}
|
||||
stream.deleteFile(absfile);
|
||||
// - relative -
|
||||
Path relfile = dir2.resolve(somefile);
|
||||
stream.createFile(relfile);
|
||||
assertTrue(exists(relfile));
|
||||
assertTrue(isRegularFile(relfile));
|
||||
try {
|
||||
stream.createFile(relfile);
|
||||
shouldNotGetHere();
|
||||
} catch (FileAlreadyExistsException x) {
|
||||
}
|
||||
stream.deleteFile(relfile);
|
||||
|
||||
// Test: createDirectory
|
||||
Path somedir = Path.of("somedir");
|
||||
// - absolute -
|
||||
Path absdir = dir.resolve(somedir);
|
||||
stream.createDirectory(absdir);
|
||||
assertTrue(exists(absdir));
|
||||
assertTrue(isDirectory(absdir));
|
||||
try {
|
||||
stream.createDirectory(absdir);
|
||||
shouldNotGetHere();
|
||||
} catch (FileAlreadyExistsException x) {
|
||||
}
|
||||
stream.deleteDirectory(absdir);
|
||||
// - relative -
|
||||
Path reldir = dir2.resolve(somedir);
|
||||
stream.createDirectory(somedir);
|
||||
assertTrue(exists(reldir));
|
||||
assertTrue(isDirectory(reldir));
|
||||
try {
|
||||
stream.createDirectory(reldir);
|
||||
shouldNotGetHere();
|
||||
} catch (FileAlreadyExistsException x) {
|
||||
}
|
||||
stream.deleteDirectory(reldir);
|
||||
|
||||
// Test: createLink
|
||||
Path somehardlink = Path.of("somehardlink");
|
||||
Path someexisting = Path.of("someexisting");
|
||||
|
||||
// - absolute -
|
||||
Path abshardlink = dir.resolve(somehardlink);
|
||||
Path absexisting = dir.resolve(someexisting);
|
||||
createFile(absexisting);
|
||||
String text1 = "I simply don't know what to say.";
|
||||
writeString(absexisting, text1);
|
||||
stream.createLink(abshardlink, stream, absexisting);
|
||||
assertTrue(exists(abshardlink));
|
||||
assertTrue(text1.equals(readString(abshardlink)));
|
||||
try {
|
||||
stream.createLink(abshardlink, stream, absexisting);
|
||||
shouldNotGetHere();
|
||||
} catch (FileAlreadyExistsException x) {
|
||||
}
|
||||
stream.deleteFile(absexisting);
|
||||
try {
|
||||
stream.createLink(abshardlink, stream, absexisting);
|
||||
shouldNotGetHere();
|
||||
} catch (NoSuchFileException x) {
|
||||
}
|
||||
stream.deleteFile(abshardlink);
|
||||
// - relative -
|
||||
Path relhardlink = dir2.resolve(somehardlink);
|
||||
Path relexisting = dir2.resolve(someexisting);
|
||||
createFile(relexisting);
|
||||
String text2 = "I still don't know what to say.";
|
||||
writeString(relexisting, text2);
|
||||
stream.createLink(somehardlink, stream, someexisting);
|
||||
assertTrue(exists(relhardlink));
|
||||
assertTrue(text2.equals(readString(relhardlink)));
|
||||
try {
|
||||
stream.createLink(somehardlink, stream, someexisting);
|
||||
shouldNotGetHere();
|
||||
} catch (FileAlreadyExistsException x) {
|
||||
}
|
||||
stream.deleteFile(relexisting);
|
||||
try {
|
||||
stream.createLink(somehardlink, stream, someexisting);
|
||||
shouldNotGetHere();
|
||||
} catch (NoSuchFileException x) {
|
||||
}
|
||||
stream.deleteFile(relhardlink);
|
||||
|
||||
if (supportsSymbolicLinks) {
|
||||
// Tests: createSymbolicLink and readSymbolicLink
|
||||
Path target = dir.resolve(Path.of("target"));
|
||||
assertTrue(exists(createFile(target)));
|
||||
Path somesymlink = Path.of("somesymlink");
|
||||
|
||||
// - absolute -
|
||||
Path abssymlink = dir.resolve(somesymlink);
|
||||
stream.createSymbolicLink(abssymlink, target);
|
||||
assertTrue(exists(abssymlink, NOFOLLOW_LINKS));
|
||||
assertTrue(isSymbolicLink(abssymlink));
|
||||
try {
|
||||
stream.createSymbolicLink(abssymlink, target);
|
||||
shouldNotGetHere();
|
||||
} catch (FileAlreadyExistsException x) {
|
||||
}
|
||||
assertTrue(target.equals(stream.readSymbolicLink(abssymlink)));
|
||||
try {
|
||||
stream.readSymbolicLink(target);
|
||||
shouldNotGetHere();
|
||||
} catch (NotLinkException x) {
|
||||
}
|
||||
delete(target);
|
||||
stream.deleteFile(abssymlink);
|
||||
// - relative -
|
||||
Path relsymlink = dir2.resolve(somesymlink);
|
||||
stream.createSymbolicLink(somesymlink, target);
|
||||
assertTrue(exists(relsymlink, NOFOLLOW_LINKS));
|
||||
assertTrue(isSymbolicLink(relsymlink));
|
||||
try {
|
||||
stream.createSymbolicLink(relsymlink, target);
|
||||
shouldNotGetHere();
|
||||
} catch (FileAlreadyExistsException x) {
|
||||
}
|
||||
assertTrue(target.equals(stream.readSymbolicLink(relsymlink)));
|
||||
stream.deleteFile(relsymlink);
|
||||
}
|
||||
|
||||
// Test: delete
|
||||
if (supportsSymbolicLinks) {
|
||||
stream.deleteFile(link1Entry);
|
||||
@ -346,6 +484,42 @@ public class SecureDS {
|
||||
stream.newDirectoryStream(null);
|
||||
shouldNotGetHere();
|
||||
} catch (NullPointerException x) { }
|
||||
try {
|
||||
stream.createFile(null);
|
||||
shouldNotGetHere();
|
||||
} catch (NullPointerException x) { }
|
||||
try {
|
||||
stream.createDirectory(null);
|
||||
shouldNotGetHere();
|
||||
} catch (NullPointerException x) { }
|
||||
Path link = Path.of("link");
|
||||
try {
|
||||
stream.createLink(null, stream, file);
|
||||
shouldNotGetHere();
|
||||
} catch (NullPointerException x) { }
|
||||
try {
|
||||
stream.createLink(link, null, file);
|
||||
shouldNotGetHere();
|
||||
} catch (NullPointerException x) { }
|
||||
try {
|
||||
stream.createLink(link, stream, null);
|
||||
shouldNotGetHere();
|
||||
} catch (NullPointerException x) { }
|
||||
if (supportsSymbolicLinks) {
|
||||
Path symlink = Path.of("symlink");
|
||||
try {
|
||||
stream.createSymbolicLink(null, file);
|
||||
shouldNotGetHere();
|
||||
} catch (NullPointerException x) { }
|
||||
try {
|
||||
stream.createSymbolicLink(symlink, null);
|
||||
shouldNotGetHere();
|
||||
} catch (NullPointerException x) { }
|
||||
try {
|
||||
stream.readSymbolicLink(null);
|
||||
shouldNotGetHere();
|
||||
} catch (NullPointerException x) { }
|
||||
}
|
||||
try {
|
||||
stream.deleteFile(null);
|
||||
shouldNotGetHere();
|
||||
@ -372,6 +546,32 @@ public class SecureDS {
|
||||
stream.move(file, stream, file);
|
||||
shouldNotGetHere();
|
||||
} catch (ClosedDirectoryStreamException x) { }
|
||||
try {
|
||||
stream.createFile(Path.of("nofile"));
|
||||
shouldNotGetHere();
|
||||
} catch (ClosedDirectoryStreamException x) { }
|
||||
try {
|
||||
stream.createDirectory(Path.of("nodir"));
|
||||
shouldNotGetHere();
|
||||
} catch (ClosedDirectoryStreamException x) { }
|
||||
link = Path.of("nohardlink");
|
||||
Path target = Path.of("nohardtarget");
|
||||
try {
|
||||
stream.createLink(link, null, target);
|
||||
shouldNotGetHere();
|
||||
} catch (ClosedDirectoryStreamException x) { }
|
||||
if (supportsSymbolicLinks) {
|
||||
link = Path.of("nosymlink");
|
||||
target = Path.of("nosofttarget");
|
||||
try {
|
||||
stream.createSymbolicLink(link, target);
|
||||
shouldNotGetHere();
|
||||
} catch (ClosedDirectoryStreamException x) { }
|
||||
try {
|
||||
stream.readSymbolicLink(link);
|
||||
shouldNotGetHere();
|
||||
} catch (ClosedDirectoryStreamException x) { }
|
||||
}
|
||||
try {
|
||||
stream.deleteFile(file);
|
||||
shouldNotGetHere();
|
||||
@ -385,6 +585,10 @@ public class SecureDS {
|
||||
if (!b) throw new RuntimeException("Assertion failed");
|
||||
}
|
||||
|
||||
static void assertFalse(boolean b) {
|
||||
if (b) throw new RuntimeException("Assertion failed");
|
||||
}
|
||||
|
||||
static void shouldNotGetHere() {
|
||||
assertTrue(false);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user