893N/A/*
3909N/A * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
893N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
893N/A *
893N/A * This code is free software; you can redistribute it and/or modify it
893N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
893N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
893N/A *
893N/A * This code is distributed in the hope that it will be useful, but WITHOUT
893N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
893N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
893N/A * version 2 for more details (a copy is included in the LICENSE file that
893N/A * accompanied this code).
893N/A *
893N/A * You should have received a copy of the GNU General Public License version
893N/A * 2 along with this work; if not, write to the Free Software Foundation,
893N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
893N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
893N/A */
893N/A
893N/Apackage sun.nio.fs;
893N/A
893N/Aimport java.nio.file.*;
893N/Aimport java.nio.file.attribute.*;
893N/Aimport java.nio.channels.*;
893N/Aimport java.net.URI;
893N/Aimport java.util.concurrent.ExecutorService;
3471N/Aimport java.io.*;
893N/Aimport java.util.*;
3471N/Aimport java.security.AccessController;
3471N/Aimport sun.misc.Unsafe;
3471N/Aimport sun.nio.ch.ThreadPool;
3471N/Aimport sun.security.util.SecurityConstants;
893N/A
3471N/Aimport static sun.nio.fs.WindowsNativeDispatcher.*;
6091N/Aimport static sun.nio.fs.WindowsSecurity.*;
3471N/Aimport static sun.nio.fs.WindowsConstants.*;
893N/A
893N/Apublic class WindowsFileSystemProvider
3471N/A extends AbstractFileSystemProvider
893N/A{
3471N/A private static final Unsafe unsafe = Unsafe.getUnsafe();
3471N/A
893N/A private static final String USER_DIR = "user.dir";
893N/A private final WindowsFileSystem theFileSystem;
893N/A
893N/A public WindowsFileSystemProvider() {
893N/A theFileSystem = new WindowsFileSystem(this, System.getProperty(USER_DIR));
893N/A }
893N/A
893N/A @Override
893N/A public String getScheme() {
893N/A return "file";
893N/A }
893N/A
893N/A private void checkUri(URI uri) {
893N/A if (!uri.getScheme().equalsIgnoreCase(getScheme()))
893N/A throw new IllegalArgumentException("URI does not match this provider");
893N/A if (uri.getAuthority() != null)
893N/A throw new IllegalArgumentException("Authority component present");
893N/A if (uri.getPath() == null)
893N/A throw new IllegalArgumentException("Path component is undefined");
893N/A if (!uri.getPath().equals("/"))
893N/A throw new IllegalArgumentException("Path component should be '/'");
893N/A if (uri.getQuery() != null)
893N/A throw new IllegalArgumentException("Query component present");
893N/A if (uri.getFragment() != null)
893N/A throw new IllegalArgumentException("Fragment component present");
893N/A }
893N/A
893N/A @Override
893N/A public FileSystem newFileSystem(URI uri, Map<String,?> env)
893N/A throws IOException
893N/A {
893N/A checkUri(uri);
893N/A throw new FileSystemAlreadyExistsException();
893N/A }
893N/A
893N/A @Override
893N/A public final FileSystem getFileSystem(URI uri) {
893N/A checkUri(uri);
893N/A return theFileSystem;
893N/A }
893N/A
893N/A @Override
893N/A public Path getPath(URI uri) {
893N/A return WindowsUriSupport.fromUri(theFileSystem, uri);
893N/A }
893N/A
893N/A @Override
893N/A public FileChannel newFileChannel(Path path,
893N/A Set<? extends OpenOption> options,
893N/A FileAttribute<?>... attrs)
893N/A throws IOException
893N/A {
893N/A if (path == null)
893N/A throw new NullPointerException();
893N/A if (!(path instanceof WindowsPath))
893N/A throw new ProviderMismatchException();
893N/A WindowsPath file = (WindowsPath)path;
893N/A
893N/A WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs);
893N/A try {
893N/A return WindowsChannelFactory
893N/A .newFileChannel(file.getPathForWin32Calls(),
893N/A file.getPathForPermissionCheck(),
893N/A options,
893N/A sd.address());
893N/A } catch (WindowsException x) {
893N/A x.rethrowAsIOException(file);
893N/A return null;
893N/A } finally {
893N/A if (sd != null)
893N/A sd.release();
893N/A }
893N/A }
893N/A
893N/A @Override
893N/A public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
893N/A Set<? extends OpenOption> options,
893N/A ExecutorService executor,
893N/A FileAttribute<?>... attrs)
893N/A throws IOException
893N/A {
893N/A if (path == null)
893N/A throw new NullPointerException();
893N/A if (!(path instanceof WindowsPath))
893N/A throw new ProviderMismatchException();
893N/A WindowsPath file = (WindowsPath)path;
893N/A ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);
893N/A WindowsSecurityDescriptor sd =
893N/A WindowsSecurityDescriptor.fromAttribute(attrs);
893N/A try {
893N/A return WindowsChannelFactory
893N/A .newAsynchronousFileChannel(file.getPathForWin32Calls(),
893N/A file.getPathForPermissionCheck(),
893N/A options,
893N/A sd.address(),
893N/A pool);
893N/A } catch (WindowsException x) {
893N/A x.rethrowAsIOException(file);
893N/A return null;
893N/A } finally {
893N/A if (sd != null)
893N/A sd.release();
893N/A }
893N/A }
3471N/A
3471N/A @Override
3471N/A @SuppressWarnings("unchecked")
3471N/A public <V extends FileAttributeView> V
3471N/A getFileAttributeView(Path obj, Class<V> view, LinkOption... options)
3471N/A {
3471N/A WindowsPath file = WindowsPath.toWindowsPath(obj);
3471N/A if (view == null)
3471N/A throw new NullPointerException();
3899N/A boolean followLinks = Util.followLinks(options);
3471N/A if (view == BasicFileAttributeView.class)
3471N/A return (V) WindowsFileAttributeViews.createBasicView(file, followLinks);
3471N/A if (view == DosFileAttributeView.class)
3471N/A return (V) WindowsFileAttributeViews.createDosView(file, followLinks);
3471N/A if (view == AclFileAttributeView.class)
3471N/A return (V) new WindowsAclFileAttributeView(file, followLinks);
3471N/A if (view == FileOwnerAttributeView.class)
3471N/A return (V) new FileOwnerAttributeViewImpl(
3471N/A new WindowsAclFileAttributeView(file, followLinks));
3471N/A if (view == UserDefinedFileAttributeView.class)
3471N/A return (V) new WindowsUserDefinedFileAttributeView(file, followLinks);
3471N/A return (V) null;
3471N/A }
3471N/A
3471N/A @Override
3471N/A @SuppressWarnings("unchecked")
3471N/A public <A extends BasicFileAttributes> A readAttributes(Path file,
3471N/A Class<A> type,
3471N/A LinkOption... options)
3471N/A throws IOException
3471N/A {
3471N/A Class<? extends BasicFileAttributeView> view;
3471N/A if (type == BasicFileAttributes.class)
3471N/A view = BasicFileAttributeView.class;
3471N/A else if (type == DosFileAttributes.class)
3471N/A view = DosFileAttributeView.class;
3471N/A else if (type == null)
3471N/A throw new NullPointerException();
3471N/A else
3471N/A throw new UnsupportedOperationException();
3471N/A return (A) getFileAttributeView(file, view, options).readAttributes();
3471N/A }
3471N/A
3471N/A @Override
3471N/A public DynamicFileAttributeView getFileAttributeView(Path obj, String name, LinkOption... options) {
3471N/A WindowsPath file = WindowsPath.toWindowsPath(obj);
3899N/A boolean followLinks = Util.followLinks(options);
3471N/A if (name.equals("basic"))
3471N/A return WindowsFileAttributeViews.createBasicView(file, followLinks);
3471N/A if (name.equals("dos"))
3471N/A return WindowsFileAttributeViews.createDosView(file, followLinks);
3471N/A if (name.equals("acl"))
3471N/A return new WindowsAclFileAttributeView(file, followLinks);
3471N/A if (name.equals("owner"))
3471N/A return new FileOwnerAttributeViewImpl(
3471N/A new WindowsAclFileAttributeView(file, followLinks));
3471N/A if (name.equals("user"))
3471N/A return new WindowsUserDefinedFileAttributeView(file, followLinks);
3471N/A return null;
3471N/A }
3471N/A
3471N/A @Override
3471N/A public SeekableByteChannel newByteChannel(Path obj,
3471N/A Set<? extends OpenOption> options,
3471N/A FileAttribute<?>... attrs)
3471N/A throws IOException
3471N/A {
3471N/A WindowsPath file = WindowsPath.toWindowsPath(obj);
3471N/A WindowsSecurityDescriptor sd =
3471N/A WindowsSecurityDescriptor.fromAttribute(attrs);
3471N/A try {
3471N/A return WindowsChannelFactory
3471N/A .newFileChannel(file.getPathForWin32Calls(),
3471N/A file.getPathForPermissionCheck(),
3471N/A options,
3471N/A sd.address());
3471N/A } catch (WindowsException x) {
3471N/A x.rethrowAsIOException(file);
3471N/A return null; // keep compiler happy
3471N/A } finally {
3471N/A sd.release();
3471N/A }
3471N/A }
3471N/A
3471N/A @Override
3471N/A boolean implDelete(Path obj, boolean failIfNotExists) throws IOException {
3471N/A WindowsPath file = WindowsPath.toWindowsPath(obj);
3471N/A file.checkDelete();
3471N/A
3471N/A WindowsFileAttributes attrs = null;
3471N/A try {
3471N/A // need to know if file is a directory or junction
3471N/A attrs = WindowsFileAttributes.get(file, false);
3471N/A if (attrs.isDirectory() || attrs.isDirectoryLink()) {
3471N/A RemoveDirectory(file.getPathForWin32Calls());
3471N/A } else {
3471N/A DeleteFile(file.getPathForWin32Calls());
3471N/A }
3471N/A return true;
3471N/A } catch (WindowsException x) {
3471N/A
3471N/A // no-op if file does not exist
3471N/A if (!failIfNotExists &&
3471N/A (x.lastError() == ERROR_FILE_NOT_FOUND ||
3471N/A x.lastError() == ERROR_PATH_NOT_FOUND)) return false;
3471N/A
3471N/A if (attrs != null && attrs.isDirectory()) {
3471N/A // ERROR_ALREADY_EXISTS is returned when attempting to delete
3471N/A // non-empty directory on SAMBA servers.
3471N/A if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
3471N/A x.lastError() == ERROR_ALREADY_EXISTS)
3471N/A {
3471N/A throw new DirectoryNotEmptyException(
3471N/A file.getPathForExceptionMessage());
3471N/A }
3471N/A }
3471N/A x.rethrowAsIOException(file);
3471N/A return false;
3471N/A }
3471N/A }
3471N/A
3471N/A @Override
3471N/A public void copy(Path source, Path target, CopyOption... options)
3471N/A throws IOException
3471N/A {
3471N/A WindowsFileCopy.copy(WindowsPath.toWindowsPath(source),
3471N/A WindowsPath.toWindowsPath(target),
3471N/A options);
3471N/A }
3471N/A
3471N/A @Override
3471N/A public void move(Path source, Path target, CopyOption... options)
3471N/A throws IOException
3471N/A {
3471N/A WindowsFileCopy.move(WindowsPath.toWindowsPath(source),
3471N/A WindowsPath.toWindowsPath(target),
3471N/A options);
3471N/A }
3471N/A
3471N/A /**
6091N/A * Checks the file security against desired access.
3471N/A */
6091N/A private static boolean hasDesiredAccess(WindowsPath file, int rights) throws IOException {
6091N/A // read security descriptor containing ACL (symlinks are followed)
6091N/A boolean hasRights = false;
3471N/A String target = WindowsLinkSupport.getFinalPath(file, true);
3471N/A NativeBuffer aclBuffer = WindowsAclFileAttributeView
6091N/A .getFileSecurity(target,
6091N/A DACL_SECURITY_INFORMATION
6091N/A | OWNER_SECURITY_INFORMATION
6091N/A | GROUP_SECURITY_INFORMATION);
3471N/A try {
6091N/A hasRights = checkAccessMask(aclBuffer.address(), rights,
6091N/A FILE_GENERIC_READ,
6091N/A FILE_GENERIC_WRITE,
6091N/A FILE_GENERIC_EXECUTE,
6091N/A FILE_ALL_ACCESS);
6091N/A } catch (WindowsException exc) {
6091N/A exc.rethrowAsIOException(file);
3471N/A } finally {
3471N/A aclBuffer.release();
3471N/A }
6091N/A return hasRights;
3471N/A }
3471N/A
5279N/A /**
5279N/A * Checks if the given file(or directory) exists and is readable.
5279N/A */
5279N/A private void checkReadAccess(WindowsPath file) throws IOException {
5279N/A try {
5279N/A Set<OpenOption> opts = Collections.emptySet();
5279N/A FileChannel fc = WindowsChannelFactory
5279N/A .newFileChannel(file.getPathForWin32Calls(),
5279N/A file.getPathForPermissionCheck(),
5279N/A opts,
5279N/A 0L);
5279N/A fc.close();
5279N/A } catch (WindowsException exc) {
5279N/A // Windows errors are very inconsistent when the file is a directory
5279N/A // (ERROR_PATH_NOT_FOUND returned for root directories for example)
5279N/A // so we retry by attempting to open it as a directory.
5279N/A try {
5279N/A new WindowsDirectoryStream(file, null).close();
5279N/A } catch (IOException ioe) {
5279N/A // translate and throw original exception
5279N/A exc.rethrowAsIOException(file);
5279N/A }
5279N/A }
5279N/A }
5279N/A
3471N/A @Override
3471N/A public void checkAccess(Path obj, AccessMode... modes) throws IOException {
3471N/A WindowsPath file = WindowsPath.toWindowsPath(obj);
3471N/A
3471N/A boolean r = false;
3471N/A boolean w = false;
3471N/A boolean x = false;
3471N/A for (AccessMode mode: modes) {
3471N/A switch (mode) {
3471N/A case READ : r = true; break;
3471N/A case WRITE : w = true; break;
3471N/A case EXECUTE : x = true; break;
3471N/A default: throw new AssertionError("Should not get here");
3471N/A }
3471N/A }
3471N/A
5279N/A // special-case read access to avoid needing to determine effective
5279N/A // access to file; default if modes not specified
5279N/A if (!w && !x) {
5279N/A checkReadAccess(file);
5279N/A return;
5279N/A }
5279N/A
3471N/A int mask = 0;
3471N/A if (r) {
3471N/A file.checkRead();
3471N/A mask |= FILE_READ_DATA;
3471N/A }
3471N/A if (w) {
3471N/A file.checkWrite();
3471N/A mask |= FILE_WRITE_DATA;
3471N/A }
3471N/A if (x) {
3471N/A SecurityManager sm = System.getSecurityManager();
3471N/A if (sm != null)
3471N/A sm.checkExec(file.getPathForPermissionCheck());
3471N/A mask |= FILE_EXECUTE;
3471N/A }
3471N/A
6091N/A if (!hasDesiredAccess(file, mask))
3471N/A throw new AccessDeniedException(
3471N/A file.getPathForExceptionMessage(), null,
6091N/A "Permissions does not allow requested access");
3471N/A
3471N/A // for write access we neeed to check if the DOS readonly attribute
3471N/A // and if the volume is read-only
3471N/A if (w) {
3471N/A try {
3471N/A WindowsFileAttributes attrs = WindowsFileAttributes.get(file, true);
3471N/A if (!attrs.isDirectory() && attrs.isReadOnly())
3471N/A throw new AccessDeniedException(
3471N/A file.getPathForExceptionMessage(), null,
3471N/A "DOS readonly attribute is set");
3471N/A } catch (WindowsException exc) {
3471N/A exc.rethrowAsIOException(file);
3471N/A }
3471N/A
3471N/A if (WindowsFileStore.create(file).isReadOnly()) {
3471N/A throw new AccessDeniedException(
3471N/A file.getPathForExceptionMessage(), null, "Read-only file system");
3471N/A }
3471N/A }
3471N/A }
3471N/A
3471N/A @Override
3471N/A public boolean isSameFile(Path obj1, Path obj2) throws IOException {
3471N/A WindowsPath file1 = WindowsPath.toWindowsPath(obj1);
3471N/A if (file1.equals(obj2))
3471N/A return true;
3471N/A if (obj2 == null)
3471N/A throw new NullPointerException();
3471N/A if (!(obj2 instanceof WindowsPath))
3471N/A return false;
3471N/A WindowsPath file2 = (WindowsPath)obj2;
3471N/A
3471N/A // check security manager access to both files
3471N/A file1.checkRead();
3471N/A file2.checkRead();
3471N/A
3471N/A // open both files and see if they are the same
3471N/A long h1 = 0L;
3471N/A try {
3471N/A h1 = file1.openForReadAttributeAccess(true);
3471N/A } catch (WindowsException x) {
3471N/A x.rethrowAsIOException(file1);
3471N/A }
3471N/A try {
3471N/A WindowsFileAttributes attrs1 = null;
3471N/A try {
3471N/A attrs1 = WindowsFileAttributes.readAttributes(h1);
3471N/A } catch (WindowsException x) {
3471N/A x.rethrowAsIOException(file1);
3471N/A }
3471N/A long h2 = 0L;
3471N/A try {
3471N/A h2 = file2.openForReadAttributeAccess(true);
3471N/A } catch (WindowsException x) {
3471N/A x.rethrowAsIOException(file2);
3471N/A }
3471N/A try {
3471N/A WindowsFileAttributes attrs2 = null;
3471N/A try {
3471N/A attrs2 = WindowsFileAttributes.readAttributes(h2);
3471N/A } catch (WindowsException x) {
3471N/A x.rethrowAsIOException(file2);
3471N/A }
3471N/A return WindowsFileAttributes.isSameFile(attrs1, attrs2);
3471N/A } finally {
3471N/A CloseHandle(h2);
3471N/A }
3471N/A } finally {
3471N/A CloseHandle(h1);
3471N/A }
3471N/A }
3471N/A
3471N/A @Override
3471N/A public boolean isHidden(Path obj) throws IOException {
3471N/A WindowsPath file = WindowsPath.toWindowsPath(obj);
3471N/A file.checkRead();
3471N/A WindowsFileAttributes attrs = null;
3471N/A try {
3471N/A attrs = WindowsFileAttributes.get(file, true);
3471N/A } catch (WindowsException x) {
3471N/A x.rethrowAsIOException(file);
3471N/A }
3471N/A // DOS hidden attribute not meaningful when set on directories
3471N/A if (attrs.isDirectory())
3471N/A return false;
3471N/A return attrs.isHidden();
3471N/A }
3471N/A
3471N/A @Override
3471N/A public FileStore getFileStore(Path obj) throws IOException {
3471N/A WindowsPath file = WindowsPath.toWindowsPath(obj);
3471N/A SecurityManager sm = System.getSecurityManager();
3471N/A if (sm != null) {
3471N/A sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
3471N/A file.checkRead();
3471N/A }
3471N/A return WindowsFileStore.create(file);
3471N/A }
3471N/A
3471N/A
3471N/A @Override
3471N/A public void createDirectory(Path obj, FileAttribute<?>... attrs)
3471N/A throws IOException
3471N/A {
3471N/A WindowsPath dir = WindowsPath.toWindowsPath(obj);
3471N/A dir.checkWrite();
3471N/A WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs);
3471N/A try {
3471N/A CreateDirectory(dir.getPathForWin32Calls(), sd.address());
3471N/A } catch (WindowsException x) {
3471N/A x.rethrowAsIOException(dir);
3471N/A } finally {
3471N/A sd.release();
3471N/A }
3471N/A }
3471N/A
3471N/A @Override
3471N/A public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter)
3471N/A throws IOException
3471N/A {
3471N/A WindowsPath dir = WindowsPath.toWindowsPath(obj);
3471N/A dir.checkRead();
3471N/A if (filter == null)
3471N/A throw new NullPointerException();
3471N/A return new WindowsDirectoryStream(dir, filter);
3471N/A }
3471N/A
3471N/A @Override
3471N/A public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs)
3471N/A throws IOException
3471N/A {
3471N/A WindowsPath link = WindowsPath.toWindowsPath(obj1);
3471N/A WindowsPath target = WindowsPath.toWindowsPath(obj2);
3471N/A
3471N/A if (!link.getFileSystem().supportsLinks()) {
3471N/A throw new UnsupportedOperationException("Symbolic links not supported "
3471N/A + "on this operating system");
3471N/A }
3471N/A
3471N/A // no attributes allowed
3471N/A if (attrs.length > 0) {
3471N/A WindowsSecurityDescriptor.fromAttribute(attrs); // may throw NPE or UOE
3471N/A throw new UnsupportedOperationException("Initial file attributes" +
3471N/A "not supported when creating symbolic link");
3471N/A }
3471N/A
3471N/A // permission check
3471N/A SecurityManager sm = System.getSecurityManager();
3471N/A if (sm != null) {
3471N/A sm.checkPermission(new LinkPermission("symbolic"));
3471N/A link.checkWrite();
3471N/A }
3471N/A
3471N/A /**
3471N/A * Throw I/O exception for the drive-relative case because Windows
3471N/A * creates a link with the resolved target for this case.
3471N/A */
3471N/A if (target.type() == WindowsPathType.DRIVE_RELATIVE) {
3471N/A throw new IOException("Cannot create symbolic link to working directory relative target");
3471N/A }
3471N/A
3471N/A /*
3471N/A * Windows treates symbolic links to directories differently than it
3471N/A * does to other file types. For that reason we need to check if the
3471N/A * target is a directory (or a directory junction).
3471N/A */
3471N/A WindowsPath resolvedTarget;
3471N/A if (target.type() == WindowsPathType.RELATIVE) {
3471N/A WindowsPath parent = link.getParent();
3471N/A resolvedTarget = (parent == null) ? target : parent.resolve(target);
3471N/A } else {
3471N/A resolvedTarget = link.resolve(target);
3471N/A }
3471N/A int flags = 0;
3471N/A try {
3471N/A WindowsFileAttributes wattrs = WindowsFileAttributes.get(resolvedTarget, false);
3471N/A if (wattrs.isDirectory() || wattrs.isDirectoryLink())
3471N/A flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
3471N/A } catch (WindowsException x) {
3471N/A // unable to access target so assume target is not a directory
3471N/A }
3471N/A
3471N/A // create the link
3471N/A try {
3471N/A CreateSymbolicLink(link.getPathForWin32Calls(),
3471N/A WindowsPath.addPrefixIfNeeded(target.toString()),
3471N/A flags);
3471N/A } catch (WindowsException x) {
3471N/A if (x.lastError() == ERROR_INVALID_REPARSE_DATA) {
3471N/A x.rethrowAsIOException(link, target);
3471N/A } else {
3471N/A x.rethrowAsIOException(link);
3471N/A }
3471N/A }
3471N/A }
3471N/A
3471N/A @Override
3471N/A public void createLink(Path obj1, Path obj2) throws IOException {
3471N/A WindowsPath link = WindowsPath.toWindowsPath(obj1);
3471N/A WindowsPath existing = WindowsPath.toWindowsPath(obj2);
3471N/A
3471N/A // permission check
3471N/A SecurityManager sm = System.getSecurityManager();
3471N/A if (sm != null) {
3471N/A sm.checkPermission(new LinkPermission("hard"));
3471N/A link.checkWrite();
3471N/A existing.checkWrite();
3471N/A }
3471N/A
3471N/A // create hard link
3471N/A try {
3471N/A CreateHardLink(link.getPathForWin32Calls(),
3471N/A existing.getPathForWin32Calls());
3471N/A } catch (WindowsException x) {
3471N/A x.rethrowAsIOException(link, existing);
3471N/A }
3471N/A }
3471N/A
3471N/A @Override
3471N/A public Path readSymbolicLink(Path obj1) throws IOException {
3471N/A WindowsPath link = WindowsPath.toWindowsPath(obj1);
3471N/A WindowsFileSystem fs = link.getFileSystem();
3471N/A if (!fs.supportsLinks()) {
3471N/A throw new UnsupportedOperationException("symbolic links not supported");
3471N/A }
3471N/A
3471N/A // permission check
3471N/A SecurityManager sm = System.getSecurityManager();
3471N/A if (sm != null) {
3471N/A FilePermission perm = new FilePermission(link.getPathForPermissionCheck(),
3471N/A SecurityConstants.FILE_READLINK_ACTION);
3471N/A AccessController.checkPermission(perm);
3471N/A }
3471N/A
3471N/A String target = WindowsLinkSupport.readLink(link);
3471N/A return WindowsPath.createFromNormalizedPath(fs, target);
3471N/A }
893N/A}