Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/fs/UnixCopyFile.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.security.AccessController;30import java.security.PrivilegedAction;31import java.util.concurrent.ExecutionException;32import java.util.concurrent.TimeUnit;33import com.sun.nio.file.ExtendedCopyOption;3435import static sun.nio.fs.UnixNativeDispatcher.*;36import static sun.nio.fs.UnixConstants.*;373839/**40* Unix implementation of Path#copyTo and Path#moveTo methods.41*/4243class UnixCopyFile {44private UnixCopyFile() { }4546// The flags that control how a file is copied or moved47private static class Flags {48boolean replaceExisting;49boolean atomicMove;50boolean followLinks;51boolean interruptible;5253// the attributes to copy54boolean copyBasicAttributes;55boolean copyPosixAttributes;56boolean copyNonPosixAttributes;5758// flags that indicate if we should fail if attributes cannot be copied59boolean failIfUnableToCopyBasic;60boolean failIfUnableToCopyPosix;61boolean failIfUnableToCopyNonPosix;6263static Flags fromCopyOptions(CopyOption... options) {64Flags flags = new Flags();65flags.followLinks = true;66for (CopyOption option: options) {67if (option == StandardCopyOption.REPLACE_EXISTING) {68flags.replaceExisting = true;69continue;70}71if (option == LinkOption.NOFOLLOW_LINKS) {72flags.followLinks = false;73continue;74}75if (option == StandardCopyOption.COPY_ATTRIBUTES) {76// copy all attributes but only fail if basic attributes77// cannot be copied78flags.copyBasicAttributes = true;79flags.copyPosixAttributes = true;80flags.copyNonPosixAttributes = true;81flags.failIfUnableToCopyBasic = true;82continue;83}84if (option == ExtendedCopyOption.INTERRUPTIBLE) {85flags.interruptible = true;86continue;87}88if (option == null)89throw new NullPointerException();90throw new UnsupportedOperationException("Unsupported copy option");91}92return flags;93}9495static Flags fromMoveOptions(CopyOption... options) {96Flags flags = new Flags();97for (CopyOption option: options) {98if (option == StandardCopyOption.ATOMIC_MOVE) {99flags.atomicMove = true;100continue;101}102if (option == StandardCopyOption.REPLACE_EXISTING) {103flags.replaceExisting = true;104continue;105}106if (option == LinkOption.NOFOLLOW_LINKS) {107// ignore108continue;109}110if (option == null)111throw new NullPointerException();112throw new UnsupportedOperationException("Unsupported copy option");113}114115// a move requires that all attributes be copied but only fail if116// the basic attributes cannot be copied117flags.copyBasicAttributes = true;118flags.copyPosixAttributes = true;119flags.copyNonPosixAttributes = true;120flags.failIfUnableToCopyBasic = true;121return flags;122}123}124125// copy directory from source to target126private static void copyDirectory(UnixPath source,127UnixFileAttributes attrs,128UnixPath target,129Flags flags)130throws IOException131{132try {133mkdir(target, attrs.mode());134} catch (UnixException x) {135x.rethrowAsIOException(target);136}137138// no attributes to copy139if (!flags.copyBasicAttributes &&140!flags.copyPosixAttributes &&141!flags.copyNonPosixAttributes) return;142143// open target directory if possible (this can fail when copying a144// directory for which we don't have read access).145int dfd = -1;146try {147dfd = open(target, O_RDONLY, 0);148} catch (UnixException x) {149// access to target directory required to copy named attributes150if (flags.copyNonPosixAttributes && flags.failIfUnableToCopyNonPosix) {151try { rmdir(target); } catch (UnixException ignore) { }152x.rethrowAsIOException(target);153}154}155156boolean done = false;157try {158// copy owner/group/permissions159if (flags.copyPosixAttributes){160try {161if (dfd >= 0) {162fchown(dfd, attrs.uid(), attrs.gid());163fchmod(dfd, attrs.mode());164} else {165chown(target, attrs.uid(), attrs.gid());166chmod(target, attrs.mode());167}168} catch (UnixException x) {169// unable to set owner/group170if (flags.failIfUnableToCopyPosix)171x.rethrowAsIOException(target);172}173}174// copy other attributes175if (flags.copyNonPosixAttributes && (dfd >= 0)) {176int sfd = -1;177try {178sfd = open(source, O_RDONLY, 0);179} catch (UnixException x) {180if (flags.failIfUnableToCopyNonPosix)181x.rethrowAsIOException(source);182}183if (sfd >= 0) {184source.getFileSystem().copyNonPosixAttributes(sfd, dfd);185close(sfd);186}187}188// copy time stamps last189if (flags.copyBasicAttributes) {190try {191if (dfd >= 0 && futimesSupported()) {192futimes(dfd,193attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),194attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));195} else {196utimes(target,197attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),198attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));199}200} catch (UnixException x) {201// unable to set times202if (flags.failIfUnableToCopyBasic)203x.rethrowAsIOException(target);204}205}206done = true;207} finally {208if (dfd >= 0)209close(dfd);210if (!done) {211// rollback212try { rmdir(target); } catch (UnixException ignore) { }213}214}215}216217// copy regular file from source to target218private static void copyFile(UnixPath source,219UnixFileAttributes attrs,220UnixPath target,221Flags flags,222long addressToPollForCancel)223throws IOException224{225int fi = -1;226try {227fi = open(source, O_RDONLY, 0);228} catch (UnixException x) {229x.rethrowAsIOException(source);230}231232try {233// open new file234int fo = -1;235try {236fo = open(target,237(O_WRONLY |238O_CREAT |239O_EXCL),240attrs.mode());241} catch (UnixException x) {242x.rethrowAsIOException(target);243}244245// set to true when file and attributes copied246boolean complete = false;247try {248// transfer bytes to target file249try {250transfer(fo, fi, addressToPollForCancel);251} catch (UnixException x) {252x.rethrowAsIOException(source, target);253}254// copy owner/permissions255if (flags.copyPosixAttributes) {256try {257fchown(fo, attrs.uid(), attrs.gid());258fchmod(fo, attrs.mode());259} catch (UnixException x) {260if (flags.failIfUnableToCopyPosix)261x.rethrowAsIOException(target);262}263}264// copy non POSIX attributes (depends on file system)265if (flags.copyNonPosixAttributes) {266source.getFileSystem().copyNonPosixAttributes(fi, fo);267}268// copy time attributes269if (flags.copyBasicAttributes) {270try {271if (futimesSupported()) {272futimes(fo,273attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),274attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));275} else {276utimes(target,277attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),278attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));279}280} catch (UnixException x) {281if (flags.failIfUnableToCopyBasic)282x.rethrowAsIOException(target);283}284}285complete = true;286} finally {287close(fo);288289// copy of file or attributes failed so rollback290if (!complete) {291try {292unlink(target);293} catch (UnixException ignore) { }294}295}296} finally {297close(fi);298}299}300301// copy symbolic link from source to target302private static void copyLink(UnixPath source,303UnixFileAttributes attrs,304UnixPath target,305Flags flags)306throws IOException307{308byte[] linktarget = null;309try {310linktarget = readlink(source);311} catch (UnixException x) {312x.rethrowAsIOException(source);313}314try {315symlink(linktarget, target);316317if (flags.copyPosixAttributes) {318try {319lchown(target, attrs.uid(), attrs.gid());320} catch (UnixException x) {321// ignore since link attributes not required to be copied322}323}324} catch (UnixException x) {325x.rethrowAsIOException(target);326}327}328329// copy special file from source to target330private static void copySpecial(UnixPath source,331UnixFileAttributes attrs,332UnixPath target,333Flags flags)334throws IOException335{336try {337mknod(target, attrs.mode(), attrs.rdev());338} catch (UnixException x) {339x.rethrowAsIOException(target);340}341boolean done = false;342try {343if (flags.copyPosixAttributes) {344try {345chown(target, attrs.uid(), attrs.gid());346chmod(target, attrs.mode());347} catch (UnixException x) {348if (flags.failIfUnableToCopyPosix)349x.rethrowAsIOException(target);350}351}352if (flags.copyBasicAttributes) {353try {354utimes(target,355attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),356attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));357} catch (UnixException x) {358if (flags.failIfUnableToCopyBasic)359x.rethrowAsIOException(target);360}361}362done = true;363} finally {364if (!done) {365try { unlink(target); } catch (UnixException ignore) { }366}367}368}369370// move file from source to target371static void move(UnixPath source, UnixPath target, CopyOption... options)372throws IOException373{374// permission check375SecurityManager sm = System.getSecurityManager();376if (sm != null) {377source.checkWrite();378target.checkWrite();379}380381// translate options into flags382Flags flags = Flags.fromMoveOptions(options);383384// handle atomic rename case385if (flags.atomicMove) {386try {387rename(source, target);388} catch (UnixException x) {389if (x.errno() == EXDEV) {390throw new AtomicMoveNotSupportedException(391source.getPathForExceptionMessage(),392target.getPathForExceptionMessage(),393x.errorString());394}395x.rethrowAsIOException(source, target);396}397return;398}399400// move using rename or copy+delete401UnixFileAttributes sourceAttrs = null;402UnixFileAttributes targetAttrs = null;403404// get attributes of source file (don't follow links)405try {406sourceAttrs = UnixFileAttributes.get(source, false);407} catch (UnixException x) {408x.rethrowAsIOException(source);409}410411// get attributes of target file (don't follow links)412try {413targetAttrs = UnixFileAttributes.get(target, false);414} catch (UnixException x) {415// ignore416}417boolean targetExists = (targetAttrs != null);418419// if the target exists:420// 1. check if source and target are the same file421// 2. throw exception if REPLACE_EXISTING option is not set422// 3. delete target if REPLACE_EXISTING option set423if (targetExists) {424if (sourceAttrs.isSameFile(targetAttrs))425return; // nothing to do as files are identical426if (!flags.replaceExisting) {427throw new FileAlreadyExistsException(428target.getPathForExceptionMessage());429}430431// attempt to delete target432try {433if (targetAttrs.isDirectory()) {434rmdir(target);435} else {436unlink(target);437}438} catch (UnixException x) {439// target is non-empty directory that can't be replaced.440if (targetAttrs.isDirectory() &&441(x.errno() == EEXIST || x.errno() == ENOTEMPTY))442{443throw new DirectoryNotEmptyException(444target.getPathForExceptionMessage());445}446x.rethrowAsIOException(target);447}448}449450// first try rename451try {452rename(source, target);453return;454} catch (UnixException x) {455if (x.errno() != EXDEV && x.errno() != EISDIR) {456x.rethrowAsIOException(source, target);457}458}459460// copy source to target461if (sourceAttrs.isDirectory()) {462copyDirectory(source, sourceAttrs, target, flags);463} else {464if (sourceAttrs.isSymbolicLink()) {465copyLink(source, sourceAttrs, target, flags);466} else {467if (sourceAttrs.isDevice()) {468copySpecial(source, sourceAttrs, target, flags);469} else {470copyFile(source, sourceAttrs, target, flags, 0L);471}472}473}474475// delete source476try {477if (sourceAttrs.isDirectory()) {478rmdir(source);479} else {480unlink(source);481}482} catch (UnixException x) {483// file was copied but unable to unlink the source file so attempt484// to remove the target and throw a reasonable exception485try {486if (sourceAttrs.isDirectory()) {487rmdir(target);488} else {489unlink(target);490}491} catch (UnixException ignore) { }492493if (sourceAttrs.isDirectory() &&494(x.errno() == EEXIST || x.errno() == ENOTEMPTY))495{496throw new DirectoryNotEmptyException(497source.getPathForExceptionMessage());498}499x.rethrowAsIOException(source);500}501}502503// copy file from source to target504static void copy(final UnixPath source,505final UnixPath target,506CopyOption... options) throws IOException507{508// permission checks509SecurityManager sm = System.getSecurityManager();510if (sm != null) {511source.checkRead();512target.checkWrite();513}514515// translate options into flags516final Flags flags = Flags.fromCopyOptions(options);517518UnixFileAttributes sourceAttrs = null;519UnixFileAttributes targetAttrs = null;520521// get attributes of source file522try {523sourceAttrs = UnixFileAttributes.get(source, flags.followLinks);524} catch (UnixException x) {525x.rethrowAsIOException(source);526}527528// if source file is symbolic link then we must check LinkPermission529if (sm != null && sourceAttrs.isSymbolicLink()) {530sm.checkPermission(new LinkPermission("symbolic"));531}532533// get attributes of target file (don't follow links)534try {535targetAttrs = UnixFileAttributes.get(target, false);536} catch (UnixException x) {537// ignore538}539boolean targetExists = (targetAttrs != null);540541// if the target exists:542// 1. check if source and target are the same file543// 2. throw exception if REPLACE_EXISTING option is not set544// 3. try to unlink the target545if (targetExists) {546if (sourceAttrs.isSameFile(targetAttrs))547return; // nothing to do as files are identical548if (!flags.replaceExisting)549throw new FileAlreadyExistsException(550target.getPathForExceptionMessage());551try {552if (targetAttrs.isDirectory()) {553rmdir(target);554} else {555unlink(target);556}557} catch (UnixException x) {558// target is non-empty directory that can't be replaced.559if (targetAttrs.isDirectory() &&560(x.errno() == EEXIST || x.errno() == ENOTEMPTY))561{562throw new DirectoryNotEmptyException(563target.getPathForExceptionMessage());564}565x.rethrowAsIOException(target);566}567}568569// do the copy570if (sourceAttrs.isDirectory()) {571copyDirectory(source, sourceAttrs, target, flags);572return;573}574if (sourceAttrs.isSymbolicLink()) {575copyLink(source, sourceAttrs, target, flags);576return;577}578if (!flags.interruptible) {579// non-interruptible file copy580copyFile(source, sourceAttrs, target, flags, 0L);581return;582}583584// interruptible file copy585final UnixFileAttributes attrsToCopy = sourceAttrs;586Cancellable copyTask = new Cancellable() {587@Override public void implRun() throws IOException {588copyFile(source, attrsToCopy, target, flags,589addressToPollForCancel());590}591};592try {593Cancellable.runInterruptibly(copyTask);594} catch (ExecutionException e) {595Throwable t = e.getCause();596if (t instanceof IOException)597throw (IOException)t;598throw new IOException(t);599}600}601602// -- native methods --603604static native void transfer(int dst, int src, long addressToPollForCancel)605throws UnixException;606607static {608AccessController.doPrivileged(new PrivilegedAction<Void>() {609@Override610public Void run() {611System.loadLibrary("nio");612return null;613}});614}615616}617618619