Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java
32288 views
/*1* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.fs;2627import java.nio.file.*;28import java.io.IOException;29import java.util.concurrent.ExecutionException;30import com.sun.nio.file.ExtendedCopyOption;3132import static sun.nio.fs.WindowsNativeDispatcher.*;33import static sun.nio.fs.WindowsConstants.*;3435/**36* Utility methods for copying and moving files.37*/3839class WindowsFileCopy {40private WindowsFileCopy() {41}4243/**44* Copy file from source to target45*/46static void copy(final WindowsPath source,47final WindowsPath target,48CopyOption... options)49throws IOException50{51// map options52boolean replaceExisting = false;53boolean copyAttributes = false;54boolean followLinks = true;55boolean interruptible = false;56for (CopyOption option: options) {57if (option == StandardCopyOption.REPLACE_EXISTING) {58replaceExisting = true;59continue;60}61if (option == LinkOption.NOFOLLOW_LINKS) {62followLinks = false;63continue;64}65if (option == StandardCopyOption.COPY_ATTRIBUTES) {66copyAttributes = true;67continue;68}69if (option == ExtendedCopyOption.INTERRUPTIBLE) {70interruptible = true;71continue;72}73if (option == null)74throw new NullPointerException();75throw new UnsupportedOperationException("Unsupported copy option");76}7778// check permissions. If the source file is a symbolic link then79// later we must also check LinkPermission80SecurityManager sm = System.getSecurityManager();81if (sm != null) {82source.checkRead();83target.checkWrite();84}8586// get attributes of source file87// attempt to get attributes of target file88// if both files are the same there is nothing to do89// if target exists and !replace then throw exception9091WindowsFileAttributes sourceAttrs = null;92WindowsFileAttributes targetAttrs = null;9394long sourceHandle = 0L;95try {96sourceHandle = source.openForReadAttributeAccess(followLinks);97} catch (WindowsException x) {98x.rethrowAsIOException(source);99}100try {101// source attributes102try {103sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);104} catch (WindowsException x) {105x.rethrowAsIOException(source);106}107108// open target (don't follow links)109long targetHandle = 0L;110try {111targetHandle = target.openForReadAttributeAccess(false);112try {113targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);114115// if both files are the same then nothing to do116if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {117return;118}119120// can't replace file121if (!replaceExisting) {122throw new FileAlreadyExistsException(123target.getPathForExceptionMessage());124}125126} finally {127CloseHandle(targetHandle);128}129} catch (WindowsException x) {130// ignore131}132133} finally {134CloseHandle(sourceHandle);135}136137// if source file is a symbolic link then we must check for LinkPermission138if (sm != null && sourceAttrs.isSymbolicLink()) {139sm.checkPermission(new LinkPermission("symbolic"));140}141142final String sourcePath = asWin32Path(source);143final String targetPath = asWin32Path(target);144145// if target exists then delete it.146if (targetAttrs != null) {147try {148if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {149RemoveDirectory(targetPath);150} else {151DeleteFile(targetPath);152}153} catch (WindowsException x) {154if (targetAttrs.isDirectory()) {155// ERROR_ALREADY_EXISTS is returned when attempting to delete156// non-empty directory on SAMBA servers.157if (x.lastError() == ERROR_DIR_NOT_EMPTY ||158x.lastError() == ERROR_ALREADY_EXISTS)159{160throw new DirectoryNotEmptyException(161target.getPathForExceptionMessage());162}163}164x.rethrowAsIOException(target);165}166}167168// Use CopyFileEx if the file is not a directory or junction169if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {170final int flags =171(source.getFileSystem().supportsLinks() && !followLinks) ?172COPY_FILE_COPY_SYMLINK : 0;173174if (interruptible) {175// interruptible copy176Cancellable copyTask = new Cancellable() {177@Override178public int cancelValue() {179return 1; // TRUE180}181@Override182public void implRun() throws IOException {183try {184CopyFileEx(sourcePath, targetPath, flags,185addressToPollForCancel());186} catch (WindowsException x) {187x.rethrowAsIOException(source, target);188}189}190};191try {192Cancellable.runInterruptibly(copyTask);193} catch (ExecutionException e) {194Throwable t = e.getCause();195if (t instanceof IOException)196throw (IOException)t;197throw new IOException(t);198}199} else {200// non-interruptible copy201try {202CopyFileEx(sourcePath, targetPath, flags, 0L);203} catch (WindowsException x) {204x.rethrowAsIOException(source, target);205}206}207if (copyAttributes) {208// CopyFileEx does not copy security attributes209try {210copySecurityAttributes(source, target, followLinks);211} catch (IOException x) {212// ignore213}214}215return;216}217218// copy directory or directory junction219try {220if (sourceAttrs.isDirectory()) {221CreateDirectory(targetPath, 0L);222} else {223String linkTarget = WindowsLinkSupport.readLink(source);224int flags = SYMBOLIC_LINK_FLAG_DIRECTORY;225CreateSymbolicLink(targetPath,226WindowsPath.addPrefixIfNeeded(linkTarget),227flags);228}229} catch (WindowsException x) {230x.rethrowAsIOException(target);231}232if (copyAttributes) {233// copy DOS/timestamps attributes234WindowsFileAttributeViews.Dos view =235WindowsFileAttributeViews.createDosView(target, false);236try {237view.setAttributes(sourceAttrs);238} catch (IOException x) {239if (sourceAttrs.isDirectory()) {240try {241RemoveDirectory(targetPath);242} catch (WindowsException ignore) { }243}244}245246// copy security attributes. If this fail it doesn't cause the move247// to fail.248try {249copySecurityAttributes(source, target, followLinks);250} catch (IOException ignore) { }251}252}253254/**255* Move file from source to target256*/257static void move(WindowsPath source, WindowsPath target, CopyOption... options)258throws IOException259{260// map options261boolean atomicMove = false;262boolean replaceExisting = false;263for (CopyOption option: options) {264if (option == StandardCopyOption.ATOMIC_MOVE) {265atomicMove = true;266continue;267}268if (option == StandardCopyOption.REPLACE_EXISTING) {269replaceExisting = true;270continue;271}272if (option == LinkOption.NOFOLLOW_LINKS) {273// ignore274continue;275}276if (option == null) throw new NullPointerException();277throw new UnsupportedOperationException("Unsupported copy option");278}279280SecurityManager sm = System.getSecurityManager();281if (sm != null) {282source.checkWrite();283target.checkWrite();284}285286final String sourcePath = asWin32Path(source);287final String targetPath = asWin32Path(target);288289// atomic case290if (atomicMove) {291try {292MoveFileEx(sourcePath, targetPath, MOVEFILE_REPLACE_EXISTING);293} catch (WindowsException x) {294if (x.lastError() == ERROR_NOT_SAME_DEVICE) {295throw new AtomicMoveNotSupportedException(296source.getPathForExceptionMessage(),297target.getPathForExceptionMessage(),298x.errorString());299}300x.rethrowAsIOException(source, target);301}302return;303}304305// get attributes of source file306// attempt to get attributes of target file307// if both files are the same there is nothing to do308// if target exists and !replace then throw exception309310WindowsFileAttributes sourceAttrs = null;311WindowsFileAttributes targetAttrs = null;312313long sourceHandle = 0L;314try {315sourceHandle = source.openForReadAttributeAccess(false);316} catch (WindowsException x) {317x.rethrowAsIOException(source);318}319try {320// source attributes321try {322sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);323} catch (WindowsException x) {324x.rethrowAsIOException(source);325}326327// open target (don't follow links)328long targetHandle = 0L;329try {330targetHandle = target.openForReadAttributeAccess(false);331try {332targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);333334// if both files are the same then nothing to do335if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {336return;337}338339// can't replace file340if (!replaceExisting) {341throw new FileAlreadyExistsException(342target.getPathForExceptionMessage());343}344345} finally {346CloseHandle(targetHandle);347}348} catch (WindowsException x) {349// ignore350}351352} finally {353CloseHandle(sourceHandle);354}355356// if target exists then delete it.357if (targetAttrs != null) {358try {359if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {360RemoveDirectory(targetPath);361} else {362DeleteFile(targetPath);363}364} catch (WindowsException x) {365if (targetAttrs.isDirectory()) {366// ERROR_ALREADY_EXISTS is returned when attempting to delete367// non-empty directory on SAMBA servers.368if (x.lastError() == ERROR_DIR_NOT_EMPTY ||369x.lastError() == ERROR_ALREADY_EXISTS)370{371throw new DirectoryNotEmptyException(372target.getPathForExceptionMessage());373}374}375x.rethrowAsIOException(target);376}377}378379// first try MoveFileEx (no options). If target is on same volume then380// all attributes (including security attributes) are preserved.381try {382MoveFileEx(sourcePath, targetPath, 0);383return;384} catch (WindowsException x) {385if (x.lastError() != ERROR_NOT_SAME_DEVICE)386x.rethrowAsIOException(source, target);387}388389// target is on different volume so use MoveFileEx with copy option390if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {391try {392MoveFileEx(sourcePath, targetPath, MOVEFILE_COPY_ALLOWED);393} catch (WindowsException x) {394x.rethrowAsIOException(source, target);395}396// MoveFileEx does not copy security attributes when moving397// across volumes.398try {399copySecurityAttributes(source, target, false);400} catch (IOException x) {401// ignore402}403return;404}405406// moving directory or directory-link to another file system407assert sourceAttrs.isDirectory() || sourceAttrs.isDirectoryLink();408409// create new directory or directory junction410try {411if (sourceAttrs.isDirectory()) {412CreateDirectory(targetPath, 0L);413} else {414String linkTarget = WindowsLinkSupport.readLink(source);415CreateSymbolicLink(targetPath,416WindowsPath.addPrefixIfNeeded(linkTarget),417SYMBOLIC_LINK_FLAG_DIRECTORY);418}419} catch (WindowsException x) {420x.rethrowAsIOException(target);421}422423// copy timestamps/DOS attributes424WindowsFileAttributeViews.Dos view =425WindowsFileAttributeViews.createDosView(target, false);426try {427view.setAttributes(sourceAttrs);428} catch (IOException x) {429// rollback430try {431RemoveDirectory(targetPath);432} catch (WindowsException ignore) { }433throw x;434}435436// copy security attributes. If this fails it doesn't cause the move437// to fail.438try {439copySecurityAttributes(source, target, false);440} catch (IOException ignore) { }441442// delete source443try {444RemoveDirectory(sourcePath);445} catch (WindowsException x) {446// rollback447try {448RemoveDirectory(targetPath);449} catch (WindowsException ignore) { }450// ERROR_ALREADY_EXISTS is returned when attempting to delete451// non-empty directory on SAMBA servers.452if (x.lastError() == ERROR_DIR_NOT_EMPTY ||453x.lastError() == ERROR_ALREADY_EXISTS)454{455throw new DirectoryNotEmptyException(456target.getPathForExceptionMessage());457}458x.rethrowAsIOException(source);459}460}461462463private static String asWin32Path(WindowsPath path) throws IOException {464try {465return path.getPathForWin32Calls();466} catch (WindowsException x) {467x.rethrowAsIOException(path);468return null;469}470}471472/**473* Copy DACL/owner/group from source to target474*/475private static void copySecurityAttributes(WindowsPath source,476WindowsPath target,477boolean followLinks)478throws IOException479{480String path = WindowsLinkSupport.getFinalPath(source, followLinks);481482// may need SeRestorePrivilege to set file owner483WindowsSecurity.Privilege priv =484WindowsSecurity.enablePrivilege("SeRestorePrivilege");485try {486int request = (DACL_SECURITY_INFORMATION |487OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);488NativeBuffer buffer =489WindowsAclFileAttributeView.getFileSecurity(path, request);490try {491try {492SetFileSecurity(target.getPathForWin32Calls(), request,493buffer.address());494} catch (WindowsException x) {495x.rethrowAsIOException(target);496}497} finally {498buffer.release();499}500} finally {501priv.drop();502}503}504}505506507