8201407: Files.move throws DirectoryNonEmptyException when moving directory across file system
authorbpb
Thu, 07 Jun 2018 07:43:29 -0700
changeset 50447 3111982511ee
parent 50446 39ca7558bc43
child 50448 db8036093504
8201407: Files.move throws DirectoryNonEmptyException when moving directory across file system Reviewed-by: alanb
src/java.base/share/classes/java/nio/file/Files.java
src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java
src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java
test/jdk/java/nio/file/Files/CopyAndMove.java
--- a/src/java.base/share/classes/java/nio/file/Files.java	Thu Jun 07 15:10:06 2018 +0200
+++ b/src/java.base/share/classes/java/nio/file/Files.java	Thu Jun 07 07:43:29 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1391,8 +1391,9 @@
      *          specific exception)</i>
      * @throws  DirectoryNotEmptyException
      *          the {@code REPLACE_EXISTING} option is specified but the file
-     *          cannot be replaced because it is a non-empty directory
-     *          <i>(optional specific exception)</i>
+     *          cannot be replaced because it is a non-empty directory, or the
+     *          source is a non-empty directory containing entries that would
+     *          be required to be moved <i>(optional specific exceptions)</i>
      * @throws  AtomicMoveNotSupportedException
      *          if the options array contains the {@code ATOMIC_MOVE} option but
      *          the file cannot be moved as an atomic file system operation.
--- a/src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java	Thu Jun 07 15:10:06 2018 +0200
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java	Thu Jun 07 07:43:29 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -373,6 +373,22 @@
         }
     }
 
+    // throw a DirectoryNotEmpty exception if appropriate
+    static void ensureEmptyDir(UnixPath dir) throws IOException {
+        try {
+            long ptr = opendir(dir);
+            try (UnixDirectoryStream stream =
+                new UnixDirectoryStream(dir, ptr, e -> true)) {
+                if (stream.iterator().hasNext()) {
+                    throw new DirectoryNotEmptyException(
+                        dir.getPathForExceptionMessage());
+                }
+            }
+        } catch (UnixException e) {
+            e.rethrowAsIOException(dir);
+        }
+    }
+
     // move file from source to target
     static void move(UnixPath source, UnixPath target, CopyOption... options)
         throws IOException
@@ -465,6 +481,7 @@
 
         // copy source to target
         if (sourceAttrs.isDirectory()) {
+            ensureEmptyDir(source);
             copyDirectory(source, sourceAttrs, target, flags);
         } else {
             if (sourceAttrs.isSymbolicLink()) {
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java	Thu Jun 07 15:10:06 2018 +0200
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java	Thu Jun 07 07:43:29 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -249,6 +249,17 @@
         }
     }
 
+    // throw a DirectoryNotEmpty exception if not empty
+    static void ensureEmptyDir(WindowsPath dir) throws IOException {
+        try (WindowsDirectoryStream dirStream =
+            new WindowsDirectoryStream(dir, (e) -> true)) {
+            if (dirStream.iterator().hasNext()) {
+                throw new DirectoryNotEmptyException(
+                    dir.getPathForExceptionMessage());
+            }
+        }
+    }
+
     /**
      * Move file from source to target
      */
@@ -407,6 +418,7 @@
         // create new directory or directory junction
         try {
             if (sourceAttrs.isDirectory()) {
+                ensureEmptyDir(source);
                 CreateDirectory(targetPath, 0L);
             } else {
                 String linkTarget = WindowsLinkSupport.readLink(source);
--- a/test/jdk/java/nio/file/Files/CopyAndMove.java	Thu Jun 07 15:10:06 2018 +0200
+++ b/test/jdk/java/nio/file/Files/CopyAndMove.java	Thu Jun 07 07:43:29 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 4313887 6838333 6917021 7006126 6950237 8006645
+ * @bug 4313887 6838333 6917021 7006126 6950237 8006645 8201407
  * @summary Unit test for java.nio.file.Files copy and move methods (use -Dseed=X to set PRNG seed)
  * @library .. /test/lib
  * @build jdk.test.lib.RandomFactory
@@ -448,6 +448,10 @@
                 moveAndVerify(source, target);
                 throw new RuntimeException("IOException expected");
             } catch (IOException x) {
+                if (!(x instanceof DirectoryNotEmptyException)) {
+                    throw new RuntimeException
+                        ("DirectoryNotEmptyException expected", x);
+                }
             }
             delete(source.resolve("foo"));
             delete(source);