6595866: File does work with symbolic links (win,vista)
Reviewed-by: sherman
This commit is contained in:
parent
7c86823f01
commit
41a783f149
@ -51,13 +51,25 @@ static struct {
|
||||
jfieldID path;
|
||||
} ids;
|
||||
|
||||
/**
|
||||
* GetFinalPathNameByHandle is available on Windows Vista and newer
|
||||
*/
|
||||
typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
|
||||
static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
|
||||
{
|
||||
HANDLE handle;
|
||||
jclass fileClass = (*env)->FindClass(env, "java/io/File");
|
||||
if (!fileClass) return;
|
||||
ids.path =
|
||||
(*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
|
||||
handle = LoadLibrary("kernel32");
|
||||
if (handle != NULL) {
|
||||
GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
|
||||
GetProcAddress(handle, "GetFinalPathNameByHandleW");
|
||||
}
|
||||
}
|
||||
|
||||
/* -- Path operations -- */
|
||||
@ -65,6 +77,138 @@ Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
|
||||
extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
|
||||
extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
|
||||
|
||||
/**
|
||||
* Retrieves the fully resolved (final) path for the given path or NULL
|
||||
* if the function fails.
|
||||
*/
|
||||
static WCHAR* getFinalPath(const WCHAR *path)
|
||||
{
|
||||
HANDLE h;
|
||||
WCHAR *result;
|
||||
DWORD error;
|
||||
|
||||
/* Need Windows Vista or newer to get the final path */
|
||||
if (GetFinalPathNameByHandle_func == NULL)
|
||||
return NULL;
|
||||
|
||||
h = CreateFileW(path,
|
||||
FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_DELETE |
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
|
||||
/**
|
||||
* Allocate a buffer for the resolved path. For a long path we may need
|
||||
* to allocate a larger buffer.
|
||||
*/
|
||||
result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR));
|
||||
if (result != NULL) {
|
||||
DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0);
|
||||
if (len >= MAX_PATH) {
|
||||
/* retry with a buffer of the right size */
|
||||
result = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR));
|
||||
if (result != NULL) {
|
||||
len = (*GetFinalPathNameByHandle_func)(h, result, len, 0);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
if (len > 0) {
|
||||
/**
|
||||
* Strip prefix (should be \\?\ or \\?\UNC)
|
||||
*/
|
||||
if (result[0] == L'\\' && result[1] == L'\\' &&
|
||||
result[2] == L'?' && result[3] == L'\\')
|
||||
{
|
||||
int isUnc = (result[4] == L'U' &&
|
||||
result[5] == L'N' &&
|
||||
result[6] == L'C');
|
||||
int prefixLen = (isUnc) ? 7 : 4;
|
||||
/* actual result length (includes terminator) */
|
||||
int resultLen = len - prefixLen + (isUnc ? 1 : 0) + 1;
|
||||
|
||||
/* copy result without prefix into new buffer */
|
||||
WCHAR *tmp = (WCHAR*)malloc(resultLen * sizeof(WCHAR));
|
||||
if (tmp == NULL) {
|
||||
len = 0;
|
||||
} else {
|
||||
WCHAR *p = result;
|
||||
p += prefixLen;
|
||||
if (isUnc) {
|
||||
WCHAR *p2 = tmp;
|
||||
p2[0] = L'\\';
|
||||
p2++;
|
||||
wcscpy(p2, p);
|
||||
} else {
|
||||
wcscpy(tmp, p);
|
||||
}
|
||||
free(result);
|
||||
result = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* unable to get final path */
|
||||
if (len == 0 && result != NULL) {
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
error = GetLastError();
|
||||
if (CloseHandle(h))
|
||||
SetLastError(error);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves file information for the specified file. If the file is
|
||||
* symbolic link then the information on fully resolved target is
|
||||
* returned.
|
||||
*/
|
||||
static BOOL getFileInformation(const WCHAR *path,
|
||||
BY_HANDLE_FILE_INFORMATION *finfo)
|
||||
{
|
||||
BOOL result;
|
||||
DWORD error;
|
||||
HANDLE h = CreateFileW(path,
|
||||
FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_DELETE |
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
result = GetFileInformationByHandle(h, finfo);
|
||||
error = GetLastError();
|
||||
if (CloseHandle(h))
|
||||
SetLastError(error);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given attributes are the attributes of a reparse point, then
|
||||
* read and return the attributes of the final target.
|
||||
*/
|
||||
DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)
|
||||
{
|
||||
if ((a != INVALID_FILE_ATTRIBUTES) &&
|
||||
((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
|
||||
{
|
||||
BY_HANDLE_FILE_INFORMATION finfo;
|
||||
BOOL res = getFileInformation(path, &finfo);
|
||||
a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
|
||||
jstring pathname)
|
||||
@ -202,12 +346,15 @@ Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this,
|
||||
return rv;
|
||||
if (!isReservedDeviceNameW(pathbuf)) {
|
||||
if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) {
|
||||
rv = (java_io_FileSystem_BA_EXISTS
|
||||
| ((wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
? java_io_FileSystem_BA_DIRECTORY
|
||||
: java_io_FileSystem_BA_REGULAR)
|
||||
| ((wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
||||
? java_io_FileSystem_BA_HIDDEN : 0));
|
||||
DWORD a = getFinalAttributesIfReparsePoint(pathbuf, wfad.dwFileAttributes);
|
||||
if (a != INVALID_FILE_ATTRIBUTES) {
|
||||
rv = (java_io_FileSystem_BA_EXISTS
|
||||
| ((a & FILE_ATTRIBUTE_DIRECTORY)
|
||||
? java_io_FileSystem_BA_DIRECTORY
|
||||
: java_io_FileSystem_BA_REGULAR)
|
||||
| ((a & FILE_ATTRIBUTE_HIDDEN)
|
||||
? java_io_FileSystem_BA_HIDDEN : 0));
|
||||
}
|
||||
} else { /* pagefile.sys is a special case */
|
||||
if (GetLastError() == ERROR_SHARING_VIOLATION) {
|
||||
rv = java_io_FileSystem_BA_EXISTS;
|
||||
@ -234,6 +381,7 @@ JNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this,
|
||||
if (pathbuf == NULL)
|
||||
return JNI_FALSE;
|
||||
attr = GetFileAttributesW(pathbuf);
|
||||
attr = getFinalAttributesIfReparsePoint(pathbuf, attr);
|
||||
free(pathbuf);
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
return JNI_FALSE;
|
||||
@ -272,6 +420,20 @@ Java_java_io_WinNTFileSystem_setPermission(JNIEnv *env, jobject this,
|
||||
if (pathbuf == NULL)
|
||||
return JNI_FALSE;
|
||||
a = GetFileAttributesW(pathbuf);
|
||||
|
||||
/* if reparse point, get final target */
|
||||
if ((a != INVALID_FILE_ATTRIBUTES) &&
|
||||
((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
|
||||
{
|
||||
WCHAR *fp = getFinalPath(pathbuf);
|
||||
if (fp == NULL) {
|
||||
a = INVALID_FILE_ATTRIBUTES;
|
||||
} else {
|
||||
free(pathbuf);
|
||||
pathbuf = fp;
|
||||
a = GetFileAttributesW(pathbuf);
|
||||
}
|
||||
}
|
||||
if (a != INVALID_FILE_ATTRIBUTES) {
|
||||
if (enable)
|
||||
a = a & ~FILE_ATTRIBUTE_READONLY;
|
||||
@ -305,7 +467,7 @@ Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
|
||||
/* Open existing or fail */
|
||||
OPEN_EXISTING,
|
||||
/* Backup semantics for directories */
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
/* No template file */
|
||||
NULL);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
@ -332,7 +494,16 @@ Java_java_io_WinNTFileSystem_getLength(JNIEnv *env, jobject this, jobject file)
|
||||
if (GetFileAttributesExW(pathbuf,
|
||||
GetFileExInfoStandard,
|
||||
&wfad)) {
|
||||
rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;
|
||||
if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
|
||||
rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow;
|
||||
} else {
|
||||
/* file is a reparse point so read attributes of final target */
|
||||
BY_HANDLE_FILE_INFORMATION finfo;
|
||||
if (getFileInformation(pathbuf, &finfo)) {
|
||||
rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) +
|
||||
finfo.nFileSizeLow;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (GetLastError() == ERROR_SHARING_VIOLATION) {
|
||||
/* The error is "share violation", which means the file/dir
|
||||
@ -360,31 +531,29 @@ Java_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls,
|
||||
if (pathbuf == NULL)
|
||||
return JNI_FALSE;
|
||||
h = CreateFileW(
|
||||
pathbuf, /* Wide char path name */
|
||||
GENERIC_READ | GENERIC_WRITE, /* Read and write permission */
|
||||
pathbuf, /* Wide char path name */
|
||||
GENERIC_READ | GENERIC_WRITE, /* Read and write permission */
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */
|
||||
NULL, /* Security attributes */
|
||||
CREATE_NEW, /* creation disposition */
|
||||
FILE_ATTRIBUTE_NORMAL, /* flags and attributes */
|
||||
NULL, /* Security attributes */
|
||||
CREATE_NEW, /* creation disposition */
|
||||
FILE_ATTRIBUTE_NORMAL |
|
||||
FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */
|
||||
NULL);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
DWORD error = GetLastError();
|
||||
if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
|
||||
|
||||
// If a directory by the named path already exists,
|
||||
// return false (behavior of solaris and linux) instead of
|
||||
// throwing an exception
|
||||
DWORD fattr = GetFileAttributesW(pathbuf);
|
||||
if ((fattr == INVALID_FILE_ATTRIBUTES) ||
|
||||
(fattr & ~FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
// return false rather than throwing an exception when there is
|
||||
// an existing file.
|
||||
DWORD a = GetFileAttributesW(pathbuf);
|
||||
if (a == INVALID_FILE_ATTRIBUTES) {
|
||||
SetLastError(error);
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
|
||||
}
|
||||
}
|
||||
free(pathbuf);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
}
|
||||
free(pathbuf);
|
||||
CloseHandle(h);
|
||||
return JNI_TRUE;
|
||||
@ -396,9 +565,9 @@ removeFileOrDirectory(const jchar *path)
|
||||
/* Returns 0 on success */
|
||||
DWORD a;
|
||||
|
||||
SetFileAttributesW(path, 0);
|
||||
SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
|
||||
a = GetFileAttributesW(path);
|
||||
if (a == ((DWORD)-1)) {
|
||||
if (a == INVALID_FILE_ATTRIBUTES) {
|
||||
return 1;
|
||||
} else if (a & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
return !RemoveDirectoryW(path);
|
||||
@ -578,8 +747,13 @@ Java_java_io_WinNTFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
|
||||
HANDLE h;
|
||||
if (pathbuf == NULL)
|
||||
return JNI_FALSE;
|
||||
h = CreateFileW(pathbuf, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
h = CreateFileW(pathbuf,
|
||||
FILE_WRITE_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
0);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
LARGE_INTEGER modTime;
|
||||
FILETIME t;
|
||||
@ -607,6 +781,21 @@ Java_java_io_WinNTFileSystem_setReadOnly(JNIEnv *env, jobject this,
|
||||
if (pathbuf == NULL)
|
||||
return JNI_FALSE;
|
||||
a = GetFileAttributesW(pathbuf);
|
||||
|
||||
/* if reparse point, get final target */
|
||||
if ((a != INVALID_FILE_ATTRIBUTES) &&
|
||||
((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0))
|
||||
{
|
||||
WCHAR *fp = getFinalPath(pathbuf);
|
||||
if (fp == NULL) {
|
||||
a = INVALID_FILE_ATTRIBUTES;
|
||||
} else {
|
||||
free(pathbuf);
|
||||
pathbuf = fp;
|
||||
a = GetFileAttributesW(pathbuf);
|
||||
}
|
||||
}
|
||||
|
||||
if (a != INVALID_FILE_ATTRIBUTES) {
|
||||
if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY))
|
||||
rv = JNI_TRUE;
|
||||
|
380
jdk/test/java/io/File/SymLinks.java
Normal file
380
jdk/test/java/io/File/SymLinks.java
Normal file
@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 6595866
|
||||
* @summary Test java.io.File operations with sym links
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.*;
|
||||
import static java.nio.file.LinkOption.*;
|
||||
|
||||
public class SymLinks {
|
||||
final static PrintStream out = System.out;
|
||||
|
||||
final static File top = new File(System.getProperty("test.dir", "."));
|
||||
|
||||
// files used by the test
|
||||
|
||||
final static File file = new File(top, "foofile");
|
||||
final static File link2file = new File(top, "link2file");
|
||||
final static File link2link2file = new File(top, "link2link2file");
|
||||
|
||||
final static File dir = new File(top, "foodir");
|
||||
final static File link2dir = new File(top, "link2dir");
|
||||
final static File link2link2dir = new File(top, "link2link2dir");
|
||||
|
||||
final static File link2nobody = new File(top, "link2nobody");
|
||||
final static File link2link2nobody = new File(top, "link2link2nobody");
|
||||
|
||||
/**
|
||||
* Setup files, directories, and sym links used by test.
|
||||
*/
|
||||
static void setup() throws IOException {
|
||||
// link2link2file -> link2file -> foofile
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
try {
|
||||
fos.write(new byte[16*1024]);
|
||||
} finally {
|
||||
fos.close();
|
||||
}
|
||||
mklink(link2file, file);
|
||||
mklink(link2link2file, link2file);
|
||||
|
||||
// link2link2dir -> link2dir -> dir
|
||||
assertTrue(dir.mkdir());
|
||||
mklink(link2dir, dir);
|
||||
mklink(link2link2dir, link2dir);
|
||||
|
||||
// link2link2nobody -> link2nobody -> <does-not-exist>
|
||||
mklink(link2nobody, new File(top, "DoesNotExist"));
|
||||
mklink(link2link2nobody, link2nobody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove files, directories, and sym links used by test.
|
||||
*/
|
||||
static void cleanup() throws IOException {
|
||||
if (file != null)
|
||||
file.delete();
|
||||
if (link2file != null)
|
||||
link2file.toPath().deleteIfExists();
|
||||
if (link2link2file != null)
|
||||
link2link2file.toPath().deleteIfExists();
|
||||
if (dir != null)
|
||||
dir.delete();
|
||||
if (link2dir != null)
|
||||
link2dir.toPath().deleteIfExists();
|
||||
if (link2link2dir != null)
|
||||
link2link2dir.toPath().deleteIfExists();
|
||||
if (link2nobody != null)
|
||||
link2nobody.toPath().deleteIfExists();
|
||||
if (link2link2nobody != null)
|
||||
link2link2nobody.toPath().deleteIfExists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sym link source->target
|
||||
*/
|
||||
static void mklink(File source, File target) throws IOException {
|
||||
source.toPath().createSymbolicLink(target.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the "link" exists and is a sym link.
|
||||
*/
|
||||
static boolean isSymLink(File link) {
|
||||
try {
|
||||
BasicFileAttributes attrs =
|
||||
Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS);
|
||||
return attrs.isSymbolicLink();
|
||||
} catch (IOException x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modified time of a sym link.
|
||||
*/
|
||||
static long lastModifiedOfSymLink(File link) throws IOException {
|
||||
BasicFileAttributes attrs =
|
||||
Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS);
|
||||
assertTrue(attrs.isSymbolicLink());
|
||||
return attrs.lastModifiedTime().toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if sym links are supported on the file system where
|
||||
* "dir" exists.
|
||||
*/
|
||||
static boolean supportsSymLinks(File dir) {
|
||||
Path link = dir.toPath().resolve("link");
|
||||
Path target = dir.toPath().resolve("target");
|
||||
try {
|
||||
link.createSymbolicLink(target);
|
||||
link.delete();
|
||||
return true;
|
||||
} catch (UnsupportedOperationException x) {
|
||||
return false;
|
||||
} catch (IOException x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void assertTrue(boolean v) {
|
||||
if (!v) throw new RuntimeException("Test failed");
|
||||
}
|
||||
|
||||
static void assertFalse(boolean v) {
|
||||
assertTrue(!v);
|
||||
}
|
||||
|
||||
static void header(String h) {
|
||||
out.println();
|
||||
out.println();
|
||||
out.println("-- " + h + " --");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests go here.
|
||||
*/
|
||||
static void go() throws IOException {
|
||||
|
||||
// check setup
|
||||
assertTrue(file.isFile());
|
||||
assertTrue(isSymLink(link2file));
|
||||
assertTrue(isSymLink(link2link2file));
|
||||
assertTrue(dir.isDirectory());
|
||||
assertTrue(isSymLink(link2dir));
|
||||
assertTrue(isSymLink(link2link2dir));
|
||||
assertTrue(isSymLink(link2nobody));
|
||||
assertTrue(isSymLink(link2link2nobody));
|
||||
|
||||
header("createNewFile");
|
||||
|
||||
assertFalse(file.createNewFile());
|
||||
assertFalse(link2file.createNewFile());
|
||||
assertFalse(link2link2file.createNewFile());
|
||||
assertFalse(dir.createNewFile());
|
||||
assertFalse(link2dir.createNewFile());
|
||||
assertFalse(link2link2dir.createNewFile());
|
||||
assertFalse(link2nobody.createNewFile());
|
||||
assertFalse(link2link2nobody.createNewFile());
|
||||
|
||||
header("mkdir");
|
||||
|
||||
assertFalse(file.mkdir());
|
||||
assertFalse(link2file.mkdir());
|
||||
assertFalse(link2link2file.mkdir());
|
||||
assertFalse(dir.mkdir());
|
||||
assertFalse(link2dir.mkdir());
|
||||
assertFalse(link2link2dir.mkdir());
|
||||
assertFalse(link2nobody.mkdir());
|
||||
assertFalse(link2link2nobody.mkdir());
|
||||
|
||||
header("delete");
|
||||
|
||||
File link = new File(top, "mylink");
|
||||
try {
|
||||
mklink(link, file);
|
||||
assertTrue(link.delete());
|
||||
assertTrue(!isSymLink(link));
|
||||
assertTrue(file.exists());
|
||||
|
||||
mklink(link, link2file);
|
||||
assertTrue(link.delete());
|
||||
assertTrue(!isSymLink(link));
|
||||
assertTrue(link2file.exists());
|
||||
|
||||
mklink(link, dir);
|
||||
assertTrue(link.delete());
|
||||
assertTrue(!isSymLink(link));
|
||||
assertTrue(dir.exists());
|
||||
|
||||
mklink(link, link2dir);
|
||||
assertTrue(link.delete());
|
||||
assertTrue(!isSymLink(link));
|
||||
assertTrue(link2dir.exists());
|
||||
|
||||
mklink(link, link2nobody);
|
||||
assertTrue(link.delete());
|
||||
assertTrue(!isSymLink(link));
|
||||
assertTrue(isSymLink(link2nobody));
|
||||
|
||||
} finally {
|
||||
link.toPath().deleteIfExists();
|
||||
}
|
||||
|
||||
header("renameTo");
|
||||
|
||||
File newlink = new File(top, "newlink");
|
||||
assertTrue(link2file.renameTo(newlink));
|
||||
try {
|
||||
assertTrue(file.exists());
|
||||
assertTrue(isSymLink(newlink));
|
||||
assertTrue(!isSymLink(link2file));
|
||||
} finally {
|
||||
newlink.renameTo(link2file); // restore link
|
||||
}
|
||||
|
||||
assertTrue(link2dir.renameTo(newlink));
|
||||
try {
|
||||
assertTrue(dir.exists());
|
||||
assertTrue(isSymLink(newlink));
|
||||
assertTrue(!isSymLink(link2dir));
|
||||
} finally {
|
||||
newlink.renameTo(link2dir); // restore link
|
||||
}
|
||||
|
||||
header("list");
|
||||
|
||||
final String name = "entry";
|
||||
File entry = new File(dir, name);
|
||||
try {
|
||||
assertTrue(dir.list().length == 0); // directory should be empty
|
||||
assertTrue(link2dir.list().length == 0);
|
||||
assertTrue(link2link2dir.list().length == 0);
|
||||
|
||||
assertTrue(entry.createNewFile());
|
||||
assertTrue(dir.list().length == 1);
|
||||
assertTrue(dir.list()[0].equals(name));
|
||||
|
||||
// access directory by following links
|
||||
assertTrue(link2dir.list().length == 1);
|
||||
assertTrue(link2dir.list()[0].equals(name));
|
||||
assertTrue(link2link2dir.list().length == 1);
|
||||
assertTrue(link2link2dir.list()[0].equals(name));
|
||||
|
||||
// files that are not directories
|
||||
assertTrue(link2file.list() == null);
|
||||
assertTrue(link2nobody.list() == null);
|
||||
|
||||
} finally {
|
||||
entry.delete();
|
||||
}
|
||||
|
||||
header("isXXX");
|
||||
|
||||
assertTrue(file.isFile());
|
||||
assertTrue(link2file.isFile());
|
||||
assertTrue(link2link2file.isFile());
|
||||
|
||||
assertTrue(dir.isDirectory());
|
||||
assertTrue(link2dir.isDirectory());
|
||||
assertTrue(link2link2dir.isDirectory());
|
||||
|
||||
// on Windows we test with the DOS hidden attribute set
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
DosFileAttributeView view = file.toPath()
|
||||
.getFileAttributeView(DosFileAttributeView.class);
|
||||
view.setHidden(true);
|
||||
try {
|
||||
assertTrue(file.isHidden());
|
||||
assertTrue(link2file.isHidden());
|
||||
assertTrue(link2link2file.isHidden());
|
||||
} finally {
|
||||
view.setHidden(false);
|
||||
}
|
||||
assertFalse(file.isHidden());
|
||||
assertFalse(link2file.isHidden());
|
||||
assertFalse(link2link2file.isHidden());
|
||||
}
|
||||
|
||||
header("length");
|
||||
|
||||
long len = file.length();
|
||||
assertTrue(len > 0L);
|
||||
// these tests should follow links
|
||||
assertTrue(link2file.length() == len);
|
||||
assertTrue(link2link2file.length() == len);
|
||||
assertTrue(link2nobody.length() == 0L);
|
||||
|
||||
header("lastModified / setLastModified");
|
||||
|
||||
// need time to diff between link and file
|
||||
long origLastModified = file.lastModified();
|
||||
assertTrue(origLastModified != 0L);
|
||||
try { Thread.sleep(2000); } catch (InterruptedException x) { }
|
||||
file.setLastModified(System.currentTimeMillis());
|
||||
|
||||
long lastModified = file.lastModified();
|
||||
assertTrue(lastModified != origLastModified);
|
||||
assertTrue(lastModifiedOfSymLink(link2file) != lastModified);
|
||||
assertTrue(lastModifiedOfSymLink(link2link2file) != lastModified);
|
||||
assertTrue(link2file.lastModified() == lastModified);
|
||||
assertTrue(link2link2file.lastModified() == lastModified);
|
||||
assertTrue(link2nobody.lastModified() == 0L);
|
||||
|
||||
origLastModified = dir.lastModified();
|
||||
assertTrue(origLastModified != 0L);
|
||||
dir.setLastModified(0L);
|
||||
assertTrue(dir.lastModified() == 0L);
|
||||
assertTrue(link2dir.lastModified() == 0L);
|
||||
assertTrue(link2link2dir.lastModified() == 0L);
|
||||
dir.setLastModified(origLastModified);
|
||||
|
||||
header("setXXX / canXXX");
|
||||
|
||||
assertTrue(file.canRead());
|
||||
assertTrue(file.canWrite());
|
||||
assertTrue(link2file.canRead());
|
||||
assertTrue(link2file.canWrite());
|
||||
assertTrue(link2link2file.canRead());
|
||||
assertTrue(link2link2file.canWrite());
|
||||
|
||||
if (file.setReadOnly()) {
|
||||
assertFalse(file.canWrite());
|
||||
assertFalse(link2file.canWrite());
|
||||
assertFalse(link2link2file.canWrite());
|
||||
|
||||
assertTrue(file.setWritable(true)); // make writable
|
||||
assertTrue(file.canWrite());
|
||||
assertTrue(link2file.canWrite());
|
||||
assertTrue(link2link2file.canWrite());
|
||||
|
||||
assertTrue(link2file.setReadOnly()); // make read only
|
||||
assertFalse(file.canWrite());
|
||||
assertFalse(link2file.canWrite());
|
||||
assertFalse(link2link2file.canWrite());
|
||||
|
||||
assertTrue(link2link2file.setWritable(true)); // make writable
|
||||
assertTrue(file.canWrite());
|
||||
assertTrue(link2file.canWrite());
|
||||
assertTrue(link2link2file.canWrite());
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
if (supportsSymLinks(top)) {
|
||||
try {
|
||||
setup();
|
||||
go();
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user