mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 16:44:36 +02:00
8364277
: (fs) BasicFileAttributes.isDirectory and isOther return true for NTFS directory junctions when links not followed
Reviewed-by: alanb
This commit is contained in:
parent
90ea42f716
commit
02e187119d
6 changed files with 228 additions and 25 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -72,8 +72,9 @@ class WindowsConstants {
|
||||||
public static final int BACKUP_SPARSE_BLOCK = 0x00000009;
|
public static final int BACKUP_SPARSE_BLOCK = 0x00000009;
|
||||||
|
|
||||||
// reparse point/symbolic link related constants
|
// reparse point/symbolic link related constants
|
||||||
public static final int IO_REPARSE_TAG_SYMLINK = 0xA000000C;
|
|
||||||
public static final int IO_REPARSE_TAG_AF_UNIX = 0x80000023;
|
public static final int IO_REPARSE_TAG_AF_UNIX = 0x80000023;
|
||||||
|
public static final int IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003;
|
||||||
|
public static final int IO_REPARSE_TAG_SYMLINK = 0xA000000C;
|
||||||
public static final int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;
|
public static final int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;
|
||||||
public static final int SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1;
|
public static final int SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1;
|
||||||
public static final int SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2;
|
public static final int SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -412,6 +412,10 @@ class WindowsFileAttributes
|
||||||
return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);
|
return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isDirectoryJunction() {
|
||||||
|
return reparseTag == IO_REPARSE_TAG_MOUNT_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSymbolicLink() {
|
public boolean isSymbolicLink() {
|
||||||
return reparseTag == IO_REPARSE_TAG_SYMLINK;
|
return reparseTag == IO_REPARSE_TAG_SYMLINK;
|
||||||
|
@ -423,10 +427,8 @@ class WindowsFileAttributes
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirectory() {
|
public boolean isDirectory() {
|
||||||
// ignore FILE_ATTRIBUTE_DIRECTORY attribute if file is a sym link
|
return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0 &&
|
||||||
if (isSymbolicLink())
|
(fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0);
|
||||||
return false;
|
|
||||||
return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -243,7 +243,8 @@ class WindowsFileSystemProvider
|
||||||
try {
|
try {
|
||||||
// need to know if file is a directory or junction
|
// need to know if file is a directory or junction
|
||||||
attrs = WindowsFileAttributes.get(file, false);
|
attrs = WindowsFileAttributes.get(file, false);
|
||||||
if (attrs.isDirectory() || attrs.isDirectoryLink()) {
|
if (attrs.isDirectory() || attrs.isDirectoryLink() ||
|
||||||
|
attrs.isDirectoryJunction()) {
|
||||||
RemoveDirectory(file.getPathForWin32Calls());
|
RemoveDirectory(file.getPathForWin32Calls());
|
||||||
} else {
|
} else {
|
||||||
DeleteFile(file.getPathForWin32Calls());
|
DeleteFile(file.getPathForWin32Calls());
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -22,9 +22,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* @test
|
/* @test
|
||||||
* @bug 4313887 6838333
|
* @bug 4313887 6838333 8364277
|
||||||
* @summary Unit test for java.nio.file.attribute.BasicFileAttributeView
|
* @summary Unit test for java.nio.file.attribute.BasicFileAttributeView
|
||||||
* @library ../..
|
* @library ../.. /test/lib
|
||||||
|
* @build jdk.test.lib.Platform
|
||||||
|
* jdk.test.lib.util.FileUtils
|
||||||
|
* @run main/othervm --enable-native-access=ALL-UNNAMED Basic
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
|
@ -33,6 +36,9 @@ import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
|
import jdk.test.lib.Platform;
|
||||||
|
import jdk.test.lib.util.FileUtils;
|
||||||
|
|
||||||
public class Basic {
|
public class Basic {
|
||||||
|
|
||||||
static void check(boolean okay, String msg) {
|
static void check(boolean okay, String msg) {
|
||||||
|
@ -97,6 +103,17 @@ public class Basic {
|
||||||
check(!attrs.isOther(), "is not other");
|
check(!attrs.isOther(), "is not other");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void checkAttributesOfJunction(Path junction)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
BasicFileAttributes attrs =
|
||||||
|
Files.readAttributes(junction, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
|
||||||
|
check(!attrs.isSymbolicLink(), "is a link");
|
||||||
|
check(!attrs.isDirectory(), "is a directory");
|
||||||
|
check(!attrs.isRegularFile(), "is not a regular file");
|
||||||
|
check(attrs.isOther(), "is other");
|
||||||
|
}
|
||||||
|
|
||||||
static void attributeReadWriteTests(Path dir)
|
static void attributeReadWriteTests(Path dir)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
@ -114,12 +131,18 @@ public class Basic {
|
||||||
Path link = dir.resolve("link");
|
Path link = dir.resolve("link");
|
||||||
try {
|
try {
|
||||||
Files.createSymbolicLink(link, file);
|
Files.createSymbolicLink(link, file);
|
||||||
} catch (UnsupportedOperationException x) {
|
checkAttributesOfLink(link);
|
||||||
return;
|
} catch (IOException | UnsupportedOperationException x) {
|
||||||
} catch (IOException x) {
|
if (!Platform.isWindows())
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkAttributesOfLink(link);
|
|
||||||
|
// NTFS junctions are Windows-only
|
||||||
|
if (Platform.isWindows()) {
|
||||||
|
Path junction = dir.resolve("junction");
|
||||||
|
FileUtils.createWinDirectoryJunction(junction, dir);
|
||||||
|
checkAttributesOfJunction(junction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
package jdk.test.lib.util;
|
package jdk.test.lib.util;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
@ -33,6 +34,7 @@ import java.lang.management.ManagementFactory;
|
||||||
import java.nio.file.DirectoryNotEmptyException;
|
import java.nio.file.DirectoryNotEmptyException;
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.LinkOption;
|
||||||
import java.nio.file.NoSuchFileException;
|
import java.nio.file.NoSuchFileException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.SimpleFileVisitor;
|
import java.nio.file.SimpleFileVisitor;
|
||||||
|
@ -64,6 +66,14 @@ public final class FileUtils {
|
||||||
private static final int MAX_RETRY_DELETE_TIMES = IS_WINDOWS ? 15 : 0;
|
private static final int MAX_RETRY_DELETE_TIMES = IS_WINDOWS ? 15 : 0;
|
||||||
private static volatile boolean nativeLibLoaded;
|
private static volatile boolean nativeLibLoaded;
|
||||||
|
|
||||||
|
@SuppressWarnings("restricted")
|
||||||
|
private static void loadNativeLib() {
|
||||||
|
if (!nativeLibLoaded) {
|
||||||
|
System.loadLibrary("FileUtils");
|
||||||
|
nativeLibLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a file, retrying if necessary.
|
* Deletes a file, retrying if necessary.
|
||||||
*
|
*
|
||||||
|
@ -392,14 +402,10 @@ public final class FileUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the current process handle count
|
// Return the current process handle count
|
||||||
@SuppressWarnings("restricted")
|
|
||||||
public static long getProcessHandleCount() {
|
public static long getProcessHandleCount() {
|
||||||
if (IS_WINDOWS) {
|
if (IS_WINDOWS) {
|
||||||
if (!nativeLibLoaded) {
|
loadNativeLib();
|
||||||
System.loadLibrary("FileUtils");
|
return getWinProcessHandleCount0();
|
||||||
nativeLibLoaded = true;
|
|
||||||
}
|
|
||||||
return getWinProcessHandleCount();
|
|
||||||
} else {
|
} else {
|
||||||
return ((UnixOperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean()).getOpenFileDescriptorCount();
|
return ((UnixOperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean()).getOpenFileDescriptorCount();
|
||||||
}
|
}
|
||||||
|
@ -443,7 +449,23 @@ public final class FileUtils {
|
||||||
Files.write(path, lines);
|
Files.write(path, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long getWinProcessHandleCount();
|
// Create a directory junction with the specified target
|
||||||
|
public static boolean createWinDirectoryJunction(Path junction, Path target)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
assert IS_WINDOWS;
|
||||||
|
|
||||||
|
// Convert "target" to its real path
|
||||||
|
target = target.toRealPath();
|
||||||
|
|
||||||
|
// Create a directory junction
|
||||||
|
loadNativeLib();
|
||||||
|
return createWinDirectoryJunction0(junction.toString(), target.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native long getWinProcessHandleCount0();
|
||||||
|
private static native boolean createWinDirectoryJunction0(String junction,
|
||||||
|
String target) throws IOException;
|
||||||
|
|
||||||
// Possible command locations and arguments
|
// Possible command locations and arguments
|
||||||
static String[][] lsCommands = new String[][] {
|
static String[][] lsCommands = new String[][] {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -27,9 +27,49 @@
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
|
#include "jni_util.h"
|
||||||
|
#include <string.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <fileapi.h>
|
||||||
|
#include <handleapi.h>
|
||||||
|
#include <ioapiset.h>
|
||||||
|
#include <winioctl.h>
|
||||||
|
#include <errhandlingapi.h>
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_jdk_test_lib_util_FileUtils_getWinProcessHandleCount(JNIEnv *env)
|
// Based on Microsoft documentation
|
||||||
|
#define MAX_REPARSE_BUFFER_SIZE 16384
|
||||||
|
|
||||||
|
// Unavailable in standard header files:
|
||||||
|
// copied from Microsoft documentation
|
||||||
|
typedef struct _REPARSE_DATA_BUFFER {
|
||||||
|
ULONG ReparseTag;
|
||||||
|
USHORT ReparseDataLength;
|
||||||
|
USHORT Reserved;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
ULONG Flags;
|
||||||
|
WCHAR PathBuffer[1];
|
||||||
|
} SymbolicLinkReparseBuffer;
|
||||||
|
struct {
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
WCHAR PathBuffer[1];
|
||||||
|
} MountPointReparseBuffer;
|
||||||
|
struct {
|
||||||
|
UCHAR DataBuffer[1];
|
||||||
|
} GenericReparseBuffer;
|
||||||
|
} DUMMYUNIONNAME;
|
||||||
|
} REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER;
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL
|
||||||
|
Java_jdk_test_lib_util_FileUtils_getWinProcessHandleCount0
|
||||||
|
(JNIEnv* env)
|
||||||
{
|
{
|
||||||
DWORD handleCount;
|
DWORD handleCount;
|
||||||
HANDLE handle = GetCurrentProcess();
|
HANDLE handle = GetCurrentProcess();
|
||||||
|
@ -40,4 +80,118 @@ JNIEXPORT jlong JNICALL Java_jdk_test_lib_util_FileUtils_getWinProcessHandleCoun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void throwIOExceptionWithLastError(JNIEnv* env) {
|
||||||
|
#define BUFSIZE 256
|
||||||
|
DWORD errval;
|
||||||
|
WCHAR buf[BUFSIZE];
|
||||||
|
|
||||||
|
if ((errval = GetLastError()) != 0) {
|
||||||
|
jsize n = FormatMessageW(
|
||||||
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, errval, 0, buf, BUFSIZE, NULL);
|
||||||
|
|
||||||
|
jclass ioExceptionClass = (*env)->FindClass(env, "java/io/IOException");
|
||||||
|
(*env)->ThrowNew(env, ioExceptionClass, (const char*) buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_jdk_test_lib_util_FileUtils_createWinDirectoryJunction0
|
||||||
|
(JNIEnv* env, jclass unused, jstring sjunction, jstring starget)
|
||||||
|
{
|
||||||
|
BOOL error = FALSE;
|
||||||
|
|
||||||
|
const jshort bpc = sizeof(wchar_t); // bytes per character
|
||||||
|
HANDLE hJunction = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
const jchar* junction = (*env)->GetStringChars(env, sjunction, NULL);
|
||||||
|
const jchar* target = (*env)->GetStringChars(env, starget, NULL);
|
||||||
|
if (junction == NULL || target == NULL) {
|
||||||
|
jclass npeClass = (*env)->FindClass(env, "java/lang/NullPointerException");
|
||||||
|
(*env)->ThrowNew(env, npeClass, NULL);
|
||||||
|
error = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
USHORT wlen = (USHORT)0;
|
||||||
|
USHORT blen = (USHORT)0;
|
||||||
|
void* lpInBuffer = NULL;
|
||||||
|
if (!error) {
|
||||||
|
wlen = (USHORT)wcslen(target);
|
||||||
|
blen = (USHORT)(wlen * sizeof(wchar_t));
|
||||||
|
lpInBuffer = calloc(MAX_REPARSE_BUFFER_SIZE, sizeof(char));
|
||||||
|
if (lpInBuffer == NULL) {
|
||||||
|
jclass oomeClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
|
||||||
|
(*env)->ThrowNew(env, oomeClass, NULL);
|
||||||
|
error = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
if (CreateDirectoryW(junction, NULL) == 0) {
|
||||||
|
throwIOExceptionWithLastError(env);
|
||||||
|
error = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
hJunction = CreateFileW(junction, GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_OPEN_REPARSE_POINT
|
||||||
|
| FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||||
|
if (hJunction == INVALID_HANDLE_VALUE) {
|
||||||
|
throwIOExceptionWithLastError(env);
|
||||||
|
error = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
PREPARSE_DATA_BUFFER reparseBuffer = (PREPARSE_DATA_BUFFER)lpInBuffer;
|
||||||
|
reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
||||||
|
reparseBuffer->Reserved = 0;
|
||||||
|
WCHAR* prefix = L"\\??\\";
|
||||||
|
USHORT prefixLength = (USHORT)(bpc * wcslen(prefix));
|
||||||
|
reparseBuffer->MountPointReparseBuffer.SubstituteNameOffset = 0;
|
||||||
|
reparseBuffer->MountPointReparseBuffer.SubstituteNameLength =
|
||||||
|
prefixLength + blen;
|
||||||
|
reparseBuffer->MountPointReparseBuffer.PrintNameOffset =
|
||||||
|
prefixLength + blen + sizeof(WCHAR);
|
||||||
|
reparseBuffer->MountPointReparseBuffer.PrintNameLength = blen;
|
||||||
|
memcpy(&reparseBuffer->MountPointReparseBuffer.PathBuffer,
|
||||||
|
prefix, prefixLength);
|
||||||
|
memcpy(&reparseBuffer->MountPointReparseBuffer.PathBuffer[prefixLength/bpc],
|
||||||
|
target, blen);
|
||||||
|
memcpy(&reparseBuffer->MountPointReparseBuffer.PathBuffer[prefixLength/bpc + blen/bpc + 1],
|
||||||
|
target, blen);
|
||||||
|
reparseBuffer->ReparseDataLength =
|
||||||
|
(USHORT)(sizeof(reparseBuffer->MountPointReparseBuffer) +
|
||||||
|
prefixLength + bpc*blen + bpc);
|
||||||
|
DWORD nInBufferSize = FIELD_OFFSET(REPARSE_DATA_BUFFER,
|
||||||
|
MountPointReparseBuffer) + reparseBuffer->ReparseDataLength;
|
||||||
|
BOOL result = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT,
|
||||||
|
lpInBuffer, nInBufferSize,
|
||||||
|
NULL, 0, NULL, NULL);
|
||||||
|
if (result == 0) {
|
||||||
|
throwIOExceptionWithLastError(env);
|
||||||
|
error = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (junction != NULL) {
|
||||||
|
(*env)->ReleaseStringChars(env, sjunction, junction);
|
||||||
|
if (target != NULL) {
|
||||||
|
(*env)->ReleaseStringChars(env, starget, target);
|
||||||
|
if (lpInBuffer != NULL) {
|
||||||
|
free(lpInBuffer);
|
||||||
|
if (hJunction != INVALID_HANDLE_VALUE) {
|
||||||
|
// Ignore any error in CloseHandle
|
||||||
|
CloseHandle(hJunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error ? JNI_FALSE : JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue