Home » openjdk-7 » sun » nio » fs » [javadoc | source]

    1   /*
    2    * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package sun.nio.fs;
   27   
   28   import java.nio.file;
   29   import java.io.IOException;
   30   import java.util.concurrent.ExecutionException;
   31   import com.sun.nio.file.ExtendedCopyOption;
   32   
   33   import static sun.nio.fs.WindowsNativeDispatcher.*;
   34   import static sun.nio.fs.WindowsConstants.*;
   35   
   36   /**
   37    * Utility methods for copying and moving files.
   38    */
   39   
   40   class WindowsFileCopy {
   41       private WindowsFileCopy() {
   42       }
   43   
   44       /**
   45        * Copy file from source to target
   46        */
   47       static void copy(final WindowsPath source,
   48                        final WindowsPath target,
   49                        CopyOption... options)
   50           throws IOException
   51       {
   52           // map options
   53           boolean replaceExisting = false;
   54           boolean copyAttributes = false;
   55           boolean followLinks = true;
   56           boolean interruptible = false;
   57           for (CopyOption option: options) {
   58               if (option == StandardCopyOption.REPLACE_EXISTING) {
   59                   replaceExisting = true;
   60                   continue;
   61               }
   62               if (option == LinkOption.NOFOLLOW_LINKS) {
   63                   followLinks = false;
   64                   continue;
   65               }
   66               if (option == StandardCopyOption.COPY_ATTRIBUTES) {
   67                   copyAttributes = true;
   68                   continue;
   69               }
   70               if (option == ExtendedCopyOption.INTERRUPTIBLE) {
   71                   interruptible = true;
   72                   continue;
   73               }
   74               if (option == null)
   75                   throw new NullPointerException();
   76               throw new UnsupportedOperationException("Unsupported copy option");
   77           }
   78   
   79           // check permissions. If the source file is a symbolic link then
   80           // later we must also check LinkPermission
   81           SecurityManager sm = System.getSecurityManager();
   82           if (sm != null) {
   83               source.checkRead();
   84               target.checkWrite();
   85           }
   86   
   87           // get attributes of source file
   88           // attempt to get attributes of target file
   89           // if both files are the same there is nothing to do
   90           // if target exists and !replace then throw exception
   91   
   92           WindowsFileAttributes sourceAttrs = null;
   93           WindowsFileAttributes targetAttrs = null;
   94   
   95           long sourceHandle = 0L;
   96           try {
   97               sourceHandle = source.openForReadAttributeAccess(followLinks);
   98           } catch (WindowsException x) {
   99               x.rethrowAsIOException(source);
  100           }
  101           try {
  102               // source attributes
  103               try {
  104                   sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);
  105               } catch (WindowsException x) {
  106                   x.rethrowAsIOException(source);
  107               }
  108   
  109               // open target (don't follow links)
  110               long targetHandle = 0L;
  111               try {
  112                   targetHandle = target.openForReadAttributeAccess(false);
  113                   try {
  114                       targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);
  115   
  116                       // if both files are the same then nothing to do
  117                       if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {
  118                           return;
  119                       }
  120   
  121                       // can't replace file
  122                       if (!replaceExisting) {
  123                           throw new FileAlreadyExistsException(
  124                               target.getPathForExceptionMessage());
  125                       }
  126   
  127                   } finally {
  128                       CloseHandle(targetHandle);
  129                   }
  130               } catch (WindowsException x) {
  131                   // ignore
  132               }
  133   
  134           } finally {
  135               CloseHandle(sourceHandle);
  136           }
  137   
  138           // if source file is a symbolic link then we must check for LinkPermission
  139           if (sm != null && sourceAttrs.isSymbolicLink()) {
  140               sm.checkPermission(new LinkPermission("symbolic"));
  141           }
  142   
  143           final String sourcePath = asWin32Path(source);
  144           final String targetPath = asWin32Path(target);
  145   
  146           // if target exists then delete it.
  147           if (targetAttrs != null) {
  148               try {
  149                   if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {
  150                       RemoveDirectory(targetPath);
  151                   } else {
  152                       DeleteFile(targetPath);
  153                   }
  154               } catch (WindowsException x) {
  155                   if (targetAttrs.isDirectory()) {
  156                       // ERROR_ALREADY_EXISTS is returned when attempting to delete
  157                       // non-empty directory on SAMBA servers.
  158                       if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
  159                           x.lastError() == ERROR_ALREADY_EXISTS)
  160                       {
  161                           throw new DirectoryNotEmptyException(
  162                               target.getPathForExceptionMessage());
  163                       }
  164                   }
  165                   x.rethrowAsIOException(target);
  166               }
  167           }
  168   
  169           // Use CopyFileEx if the file is not a directory or junction
  170           if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {
  171               final int flags =
  172                   (source.getFileSystem().supportsLinks() && !followLinks) ?
  173                   COPY_FILE_COPY_SYMLINK : 0;
  174   
  175               if (interruptible) {
  176                   // interruptible copy
  177                   Cancellable copyTask = new Cancellable() {
  178                       @Override
  179                       public int cancelValue() {
  180                           return 1;  // TRUE
  181                       }
  182                       @Override
  183                       public void implRun() throws IOException {
  184                           try {
  185                               CopyFileEx(sourcePath, targetPath, flags,
  186                                          addressToPollForCancel());
  187                           } catch (WindowsException x) {
  188                               x.rethrowAsIOException(source, target);
  189                           }
  190                       }
  191                   };
  192                   try {
  193                       Cancellable.runInterruptibly(copyTask);
  194                   } catch (ExecutionException e) {
  195                       Throwable t = e.getCause();
  196                       if (t instanceof IOException)
  197                           throw (IOException)t;
  198                       throw new IOException(t);
  199                   }
  200               } else {
  201                   // non-interruptible copy
  202                   try {
  203                       CopyFileEx(sourcePath, targetPath, flags, 0L);
  204                   } catch (WindowsException x) {
  205                       x.rethrowAsIOException(source, target);
  206                   }
  207               }
  208               if (copyAttributes) {
  209                   // CopyFileEx does not copy security attributes
  210                   try {
  211                       copySecurityAttributes(source, target, followLinks);
  212                   } catch (IOException x) {
  213                       // ignore
  214                   }
  215               }
  216               return;
  217           }
  218   
  219           // copy directory or directory junction
  220           try {
  221               if (sourceAttrs.isDirectory()) {
  222                   CreateDirectory(targetPath, 0L);
  223               } else {
  224                   String linkTarget = WindowsLinkSupport.readLink(source);
  225                   int flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
  226                   CreateSymbolicLink(targetPath,
  227                                      addPrefixIfNeeded(linkTarget),
  228                                      flags);
  229               }
  230           } catch (WindowsException x) {
  231               x.rethrowAsIOException(target);
  232           }
  233           if (copyAttributes) {
  234               // copy DOS/timestamps attributes
  235               WindowsFileAttributeViews.Dos view =
  236                   WindowsFileAttributeViews.createDosView(target, false);
  237               try {
  238                   view.setAttributes(sourceAttrs);
  239               } catch (IOException x) {
  240                   if (sourceAttrs.isDirectory()) {
  241                       try {
  242                           RemoveDirectory(targetPath);
  243                       } catch (WindowsException ignore) { }
  244                   }
  245               }
  246   
  247               // copy security attributes. If this fail it doesn't cause the move
  248               // to fail.
  249               try {
  250                   copySecurityAttributes(source, target, followLinks);
  251               } catch (IOException ignore) { }
  252           }
  253       }
  254   
  255       /**
  256        * Move file from source to target
  257        */
  258       static void move(WindowsPath source, WindowsPath target, CopyOption... options)
  259           throws IOException
  260       {
  261           // map options
  262           boolean atomicMove = false;
  263           boolean replaceExisting = false;
  264           for (CopyOption option: options) {
  265               if (option == StandardCopyOption.ATOMIC_MOVE) {
  266                   atomicMove = true;
  267                   continue;
  268               }
  269               if (option == StandardCopyOption.REPLACE_EXISTING) {
  270                   replaceExisting = true;
  271                   continue;
  272               }
  273               if (option == LinkOption.NOFOLLOW_LINKS) {
  274                   // ignore
  275                   continue;
  276               }
  277               if (option == null) throw new NullPointerException();
  278               throw new UnsupportedOperationException("Unsupported copy option");
  279           }
  280   
  281           SecurityManager sm = System.getSecurityManager();
  282           if (sm != null) {
  283               source.checkWrite();
  284               target.checkWrite();
  285           }
  286   
  287           final String sourcePath = asWin32Path(source);
  288           final String targetPath = asWin32Path(target);
  289   
  290           // atomic case
  291           if (atomicMove) {
  292               try {
  293                   MoveFileEx(sourcePath, targetPath, MOVEFILE_REPLACE_EXISTING);
  294               } catch (WindowsException x) {
  295                   if (x.lastError() == ERROR_NOT_SAME_DEVICE) {
  296                       throw new AtomicMoveNotSupportedException(
  297                           source.getPathForExceptionMessage(),
  298                           target.getPathForExceptionMessage(),
  299                           x.errorString());
  300                   }
  301                   x.rethrowAsIOException(source, target);
  302               }
  303               return;
  304           }
  305   
  306           // get attributes of source file
  307           // attempt to get attributes of target file
  308           // if both files are the same there is nothing to do
  309           // if target exists and !replace then throw exception
  310   
  311           WindowsFileAttributes sourceAttrs = null;
  312           WindowsFileAttributes targetAttrs = null;
  313   
  314           long sourceHandle = 0L;
  315           try {
  316               sourceHandle = source.openForReadAttributeAccess(false);
  317           } catch (WindowsException x) {
  318               x.rethrowAsIOException(source);
  319           }
  320           try {
  321               // source attributes
  322               try {
  323                   sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);
  324               } catch (WindowsException x) {
  325                   x.rethrowAsIOException(source);
  326               }
  327   
  328               // open target (don't follow links)
  329               long targetHandle = 0L;
  330               try {
  331                   targetHandle = target.openForReadAttributeAccess(false);
  332                   try {
  333                       targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);
  334   
  335                       // if both files are the same then nothing to do
  336                       if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {
  337                           return;
  338                       }
  339   
  340                       // can't replace file
  341                       if (!replaceExisting) {
  342                           throw new FileAlreadyExistsException(
  343                               target.getPathForExceptionMessage());
  344                       }
  345   
  346                   } finally {
  347                       CloseHandle(targetHandle);
  348                   }
  349               } catch (WindowsException x) {
  350                   // ignore
  351               }
  352   
  353           } finally {
  354               CloseHandle(sourceHandle);
  355           }
  356   
  357           // if target exists then delete it.
  358           if (targetAttrs != null) {
  359               try {
  360                   if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {
  361                       RemoveDirectory(targetPath);
  362                   } else {
  363                       DeleteFile(targetPath);
  364                   }
  365               } catch (WindowsException x) {
  366                   if (targetAttrs.isDirectory()) {
  367                       // ERROR_ALREADY_EXISTS is returned when attempting to delete
  368                       // non-empty directory on SAMBA servers.
  369                       if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
  370                           x.lastError() == ERROR_ALREADY_EXISTS)
  371                       {
  372                           throw new DirectoryNotEmptyException(
  373                               target.getPathForExceptionMessage());
  374                       }
  375                   }
  376                   x.rethrowAsIOException(target);
  377               }
  378           }
  379   
  380           // first try MoveFileEx (no options). If target is on same volume then
  381           // all attributes (including security attributes) are preserved.
  382           try {
  383               MoveFileEx(sourcePath, targetPath, 0);
  384               return;
  385           } catch (WindowsException x) {
  386               if (x.lastError() != ERROR_NOT_SAME_DEVICE)
  387                   x.rethrowAsIOException(source, target);
  388           }
  389   
  390           // target is on different volume so use MoveFileEx with copy option
  391           if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {
  392               try {
  393                   MoveFileEx(sourcePath, targetPath, MOVEFILE_COPY_ALLOWED);
  394               } catch (WindowsException x) {
  395                   x.rethrowAsIOException(source, target);
  396               }
  397               // MoveFileEx does not copy security attributes when moving
  398               // across volumes.
  399               try {
  400                   copySecurityAttributes(source, target, false);
  401               } catch (IOException x) {
  402                   // ignore
  403               }
  404               return;
  405           }
  406   
  407           // moving directory or directory-link to another file system
  408           assert sourceAttrs.isDirectory() || sourceAttrs.isDirectoryLink();
  409   
  410           // create new directory or directory junction
  411           try {
  412               if (sourceAttrs.isDirectory()) {
  413                   CreateDirectory(targetPath, 0L);
  414               } else {
  415                   String linkTarget = WindowsLinkSupport.readLink(source);
  416                   CreateSymbolicLink(targetPath,
  417                                      addPrefixIfNeeded(linkTarget),
  418                                      SYMBOLIC_LINK_FLAG_DIRECTORY);
  419               }
  420           } catch (WindowsException x) {
  421               x.rethrowAsIOException(target);
  422           }
  423   
  424           // copy timestamps/DOS attributes
  425           WindowsFileAttributeViews.Dos view =
  426                   WindowsFileAttributeViews.createDosView(target, false);
  427           try {
  428               view.setAttributes(sourceAttrs);
  429           } catch (IOException x) {
  430               // rollback
  431               try {
  432                   RemoveDirectory(targetPath);
  433               } catch (WindowsException ignore) { }
  434               throw x;
  435           }
  436   
  437           // copy security attributes. If this fails it doesn't cause the move
  438           // to fail.
  439           try {
  440               copySecurityAttributes(source, target, false);
  441           } catch (IOException ignore) { }
  442   
  443           // delete source
  444           try {
  445               RemoveDirectory(sourcePath);
  446           } catch (WindowsException x) {
  447               // rollback
  448               try {
  449                   RemoveDirectory(targetPath);
  450               } catch (WindowsException ignore) { }
  451               // ERROR_ALREADY_EXISTS is returned when attempting to delete
  452               // non-empty directory on SAMBA servers.
  453               if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
  454                   x.lastError() == ERROR_ALREADY_EXISTS)
  455               {
  456                   throw new DirectoryNotEmptyException(
  457                       target.getPathForExceptionMessage());
  458               }
  459               x.rethrowAsIOException(source);
  460           }
  461       }
  462   
  463   
  464       private static String asWin32Path(WindowsPath path) throws IOException {
  465           try {
  466               return path.getPathForWin32Calls();
  467           } catch (WindowsException x) {
  468               x.rethrowAsIOException(path);
  469               return null;
  470           }
  471       }
  472   
  473       /**
  474        * Copy DACL/owner/group from source to target
  475        */
  476       private static void copySecurityAttributes(WindowsPath source,
  477                                                  WindowsPath target,
  478                                                  boolean followLinks)
  479           throws IOException
  480       {
  481           String path = WindowsLinkSupport.getFinalPath(source, followLinks);
  482   
  483           // may need SeRestorePrivilege to set file owner
  484           WindowsSecurity.Privilege priv =
  485               WindowsSecurity.enablePrivilege("SeRestorePrivilege");
  486           try {
  487               int request = (DACL_SECURITY_INFORMATION |
  488                   OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
  489               NativeBuffer buffer =
  490                   WindowsAclFileAttributeView.getFileSecurity(path, request);
  491               try {
  492                   try {
  493                       SetFileSecurity(target.getPathForWin32Calls(), request,
  494                           buffer.address());
  495                   } catch (WindowsException x) {
  496                       x.rethrowAsIOException(target);
  497                   }
  498               } finally {
  499                   buffer.release();
  500               }
  501           } finally {
  502               priv.drop();
  503           }
  504       }
  505   
  506       /**
  507        * Add long path prefix to path if required
  508        */
  509       private static String addPrefixIfNeeded(String path) {
  510           if (path.length() > 248) {
  511               if (path.startsWith("\\\\")) {
  512                   path = "\\\\?\\UNC" + path.substring(1, path.length());
  513               } else {
  514                   path = "\\\\?\\" + path;
  515               }
  516           }
  517           return path;
  518       }
  519   }

Home » openjdk-7 » sun » nio » fs » [javadoc | source]