diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 51bf76f324..1c9fdc2a65 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -1766,14 +1766,20 @@ public final class FilePath implements Serializable { act(new FileCallable() { private static final long serialVersionUID = 1L; public Void invoke(File f, VirtualChannel channel) throws IOException { + // JENKINS-16846: if f.getName() is the same as one of the files/directories in f, + // then the rename op will fail + File tmp = new File(f.getAbsolutePath()+".__rename"); + if (!f.renameTo(tmp)) + throw new IOException("Failed to rename "+f+" to "+tmp); + File t = new File(target.getRemote()); - for(File child : f.listFiles()) { + for(File child : tmp.listFiles()) { File target = new File(t, child.getName()); if(!child.renameTo(target)) throw new IOException("Failed to rename "+child+" to "+target); } - f.delete(); + tmp.delete(); return null; } }); diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java index 5e32218296..529fcd937e 100644 --- a/core/src/test/java/hudson/FilePathTest.java +++ b/core/src/test/java/hudson/FilePathTest.java @@ -618,4 +618,33 @@ public class FilePathTest extends ChannelTestCase { return new ByteArrayInputStream(buf.toByteArray()); } + + @Bug(16846) + public void testMoveAllChildrenTo() throws IOException, InterruptedException { + final File tmp = Util.createTempDir(); + try + { + final String dirname = "sub"; + final File top = new File(tmp, "test"); + final File sub = new File(top, dirname); + final File subsub = new File(sub, dirname); + + subsub.mkdirs(); + + final File subFile1 = new File( sub.getAbsolutePath() + "/file1.txt" ); + subFile1.createNewFile(); + final File subFile2 = new File( subsub.getAbsolutePath() + "/file2.txt" ); + subFile2.createNewFile(); + + final FilePath src = new FilePath(sub); + final FilePath dst = new FilePath(top); + + // test conflict subdir + src.moveAllChildrenTo(dst); + } + finally + { + Util.deleteRecursive(tmp); + } + } }