HADOOP-6703. Prevent renaming a file, directory or symbolic link to itself. Contributed by Eli Collins.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@938788 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Suresh Srinivas 2010-04-28 05:45:40 +00:00
parent b212ed99c5
commit e333072144
4 changed files with 152 additions and 3 deletions

View File

@ -361,6 +361,9 @@ Trunk (unreleased changes)
HADOOP-6690. FilterFileSystem correctly handles setTimes call.
(Rodrigo Schmidt via dhruba)
HADOOP-6703. Prevent renaming a file, directory or symbolic link to
itself. (Eli Collins via suresh)
HADOOP-6710. Symbolic umask for file creation is not conformant with posix.
(suresh)

View File

@ -603,6 +603,14 @@ public abstract class AbstractFileSystem {
dstStatus = null;
}
if (dstStatus != null) {
if (dst.equals(src)) {
throw new FileAlreadyExistsException(
"The source "+src+" and destination "+dst+" are the same");
}
if (srcStatus.isSymlink() && dst.equals(srcStatus.getSymlink())) {
throw new FileAlreadyExistsException(
"Cannot rename symlink "+src+" to its target "+dst);
}
if (srcStatus.isDir() != dstStatus.isDir()) {
throw new IOException("Source " + src + " Destination " + dst
+ " both should be either file or directory");

View File

@ -824,6 +824,26 @@ public abstract class FileContextMainOperationsBaseTest {
rename(src, dst, true, false, true, Rename.OVERWRITE);
}
@Test
public void testRenameFileToItself() throws Exception {
if (!renameSupported()) return;
Path src = getTestRootPath(fc, "test/hadoop/file");
createFile(src);
try {
rename(src, src, false, true, false, Rename.NONE);
Assert.fail("Renamed file to itself");
} catch (IOException e) {
Assert.assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
// Also fails with overwrite
try {
rename(src, src, false, true, false, Rename.OVERWRITE);
Assert.fail("Renamed file to itself");
} catch (IOException e) {
Assert.assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
}
@Test
public void testRenameFileAsExistingFile() throws Exception {
if (!renameSupported()) return;
@ -869,6 +889,26 @@ public abstract class FileContextMainOperationsBaseTest {
}
}
@Test
public void testRenameDirectoryToItself() throws Exception {
if (!renameSupported()) return;
Path src = getTestRootPath(fc, "test/hadoop/dir");
fc.mkdir(src, FileContext.DEFAULT_PERM, true);
try {
rename(src, src, false, true, false, Rename.NONE);
Assert.fail("Renamed directory to itself");
} catch (IOException e) {
Assert.assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
// Also fails with overwrite
try {
rename(src, src, false, true, false, Rename.OVERWRITE);
Assert.fail("Renamed directory to itself");
} catch (IOException e) {
Assert.assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
}
@Test
public void testRenameDirectoryToNonExistentParent() throws Exception {
if (!renameSupported()) return;

View File

@ -51,6 +51,10 @@ public abstract class FileContextSymlinkBaseTest {
abstract protected String testBaseDir2();
abstract protected URI testURI();
protected IOException unwrapException(IOException e) {
return e;
}
protected static void createAndWriteFile(FileContext fc, Path p)
throws IOException {
FSDataOutputStream out;
@ -766,7 +770,25 @@ public abstract class FileContextSymlinkBaseTest {
assertFalse(fc.exists(file));
assertTrue(fc.exists(fileNewViaLink));
}
@Test
/** Rename a symlink to itself */
public void testRenameSymlinkToItself() throws IOException {
Path link = new Path(testBaseDir1(), "linkToFile1");
fc.createSymlink(new Path("/doestNotExist"), link, false);
try {
fc.rename(link, link);
} catch (IOException e) {
assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
// Fails with overwrite as well
try {
fc.rename(link, link, Rename.OVERWRITE);
} catch (IOException e) {
assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
}
@Test
/** Rename a symlink */
public void testRenameSymlink() throws IOException {
@ -786,8 +808,84 @@ public abstract class FileContextSymlinkBaseTest {
} catch (IOException x) {
// Expected
}
}
}
@Test
/** Rename a symlink to the file it links to */
public void testRenameSymlinkToFileItLinksTo() throws IOException {
/* NB: The rename is not atomic, so file is deleted before renaming
* linkToFile. In this interval linkToFile is dangling and local file
* system does not handle dangling links because File.exists returns
* false for dangling links. */
if ("file".equals(getScheme())) {
return;
}
Path file = new Path(testBaseDir1(), "file");
Path link = new Path(testBaseDir1(), "linkToFile");
createAndWriteFile(file);
fc.createSymlink(file, link, false);
try {
fc.rename(link, file);
fail("Renamed symlink to its target");
} catch (IOException e) {
assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
// Check the rename didn't happen
assertTrue(fc.isFile(file));
assertTrue(fc.exists(link));
assertTrue(fc.getFileLinkStatus(link).isSymlink());
assertEquals(file, fc.getLinkTarget(link));
try {
fc.rename(link, file, Rename.OVERWRITE);
fail("Renamed symlink to its target");
} catch (IOException e) {
assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
// Check the rename didn't happen
assertTrue(fc.isFile(file));
assertTrue(fc.exists(link));
assertTrue(fc.getFileLinkStatus(link).isSymlink());
assertEquals(file, fc.getLinkTarget(link));
}
@Test
/** Rename a symlink to the directory it links to */
public void testRenameSymlinkToDirItLinksTo() throws IOException {
/* NB: The rename is not atomic, so dir is deleted before renaming
* linkToFile. In this interval linkToFile is dangling and local file
* system does not handle dangling links because File.exists returns
* false for dangling links. */
if ("file".equals(getScheme())) {
return;
}
Path dir = new Path(testBaseDir1(), "dir");
Path link = new Path(testBaseDir1(), "linkToDir");
fc.mkdir(dir, FileContext.DEFAULT_PERM, false);
fc.createSymlink(dir, link, false);
try {
fc.rename(link, dir);
fail("Renamed symlink to its target");
} catch (IOException e) {
assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
// Check the rename didn't happen
assertTrue(fc.isDirectory(dir));
assertTrue(fc.exists(link));
assertTrue(fc.getFileLinkStatus(link).isSymlink());
assertEquals(dir, fc.getLinkTarget(link));
try {
fc.rename(link, dir, Rename.OVERWRITE);
fail("Renamed symlink to its target");
} catch (IOException e) {
assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
}
// Check the rename didn't happen
assertTrue(fc.isDirectory(dir));
assertTrue(fc.exists(link));
assertTrue(fc.getFileLinkStatus(link).isSymlink());
assertEquals(dir, fc.getLinkTarget(link));
}
@Test
/** Test renaming symlink target */
public void testMoveLinkTarget() throws IOException {