8201407: Files.move throws DirectoryNonEmptyException when moving directory across file system

Reviewed-by: alanb
This commit is contained in:
Brian Burkhalter 2018-06-07 07:43:29 -07:00
parent 9f39d8c408
commit e9f3b0e527
4 changed files with 41 additions and 7 deletions
src/java.base
share/classes/java/nio/file
unix/classes/sun/nio/fs
windows/classes/sun/nio/fs
test/jdk/java/nio/file/Files

@ -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 @@ public final class Files {
* 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.

@ -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 @@ class UnixCopyFile {
}
}
// 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 @@ class UnixCopyFile {
// copy source to target
if (sourceAttrs.isDirectory()) {
ensureEmptyDir(source);
copyDirectory(source, sourceAttrs, target, flags);
} else {
if (sourceAttrs.isSymbolicLink()) {

@ -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 @@ class WindowsFileCopy {
}
}
// 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 @@ class WindowsFileCopy {
// create new directory or directory junction
try {
if (sourceAttrs.isDirectory()) {
ensureEmptyDir(source);
CreateDirectory(targetPath, 0L);
} else {
String linkTarget = WindowsLinkSupport.readLink(source);

@ -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 @@ public class CopyAndMove {
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);