Browse Source

Use NIO2 to implement FileUtils.rename() and expose options

- use NIO2's Files.move() to reimplement rename()
- provide a second method accepting CopyOptions which can be used to 
  request atomic move.

Change-Id: Ibcf722978e65745218a1ccda45344ca295911659
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
stable-4.1
Matthias Sohn 10 years ago
parent
commit
548ba66a37
  1. 12
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java
  2. 61
      org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java

12
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java

@ -48,6 +48,8 @@ import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -83,4 +85,14 @@ public class FileUtils7Test {
assertTrue(dir.exists()); assertTrue(dir.exists());
assertTrue(file.exists()); assertTrue(file.exists());
} }
@Test
public void testAtomicMove() throws IOException {
File src = new File(trash, "src");
Files.createFile(src.toPath());
File dst = new File(trash, "dst");
FileUtils.rename(src, dst, StandardCopyOption.ATOMIC_MOVE);
assertFalse(Files.exists(src.toPath()));
assertTrue(Files.exists(dst.toPath()));
}
} }

61
org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java

@ -48,9 +48,12 @@ package org.eclipse.jgit.util;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.FileLock; import java.nio.channels.FileLock;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.CopyOption;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.LinkOption; import java.nio.file.LinkOption;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.text.Normalizer; import java.text.Normalizer;
import java.text.Normalizer.Form; import java.text.Normalizer.Form;
@ -212,30 +215,68 @@ public class FileUtils {
*/ */
public static void rename(final File src, final File dst) public static void rename(final File src, final File dst)
throws IOException { throws IOException {
rename(src, dst, StandardCopyOption.REPLACE_EXISTING);
}
/**
* Rename a file or folder using the passed {@link CopyOption}s. If the
* rename fails and if we are running on a filesystem where it makes sense
* to repeat a failing rename then repeat the rename operation up to 9 times
* with 100ms sleep time between two calls. Furthermore if the destination
* exists and is a directory hierarchy with only directories in it, the
* whole directory hierarchy will be deleted. If the target represents a
* non-empty directory structure, empty subdirectories within that structure
* may or may not be deleted even if the method fails. Furthermore if the
* destination exists and is a file then the file will be replaced if
* {@link StandardCopyOption#REPLACE_EXISTING} has been set. If
* {@link StandardCopyOption#ATOMIC_MOVE} has been set the rename will be
* done atomically or fail with an {@link AtomicMoveNotSupportedException}
*
* @param src
* the old file
* @param dst
* the new file
* @param options
* options to pass to
* {@link Files#move(java.nio.file.Path, java.nio.file.Path, CopyOption...)}
* @throws AtomicMoveNotSupportedException
* if file cannot be moved as an atomic file system operation
* @throws IOException
* @since 4.1
*/
public static void rename(final File src, final File dst,
CopyOption... options)
throws AtomicMoveNotSupportedException, IOException {
int attempts = FS.DETECTED.retryFailedLockFileCommit() ? 10 : 1; int attempts = FS.DETECTED.retryFailedLockFileCommit() ? 10 : 1;
while (--attempts >= 0) { while (--attempts >= 0) {
if (src.renameTo(dst)) try {
Files.move(src.toPath(), dst.toPath(), options);
return; return;
} catch (AtomicMoveNotSupportedException e) {
throw e;
} catch (IOException e) {
try { try {
if (!dst.delete()) if (!dst.delete()) {
delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE); delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
}
// On *nix there is no try, you do or do not // On *nix there is no try, you do or do not
if (src.renameTo(dst)) Files.move(src.toPath(), dst.toPath(), options);
return; return;
} catch (IOException e) { } catch (IOException e2) {
// ignore and continue retry // ignore and continue retry
} }
}
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new IOException(MessageFormat.format( throw new IOException(
JGitText.get().renameFileFailed, src.getAbsolutePath(), MessageFormat.format(JGitText.get().renameFileFailed,
dst.getAbsolutePath())); src.getAbsolutePath(), dst.getAbsolutePath()));
} }
} }
throw new IOException(MessageFormat.format( throw new IOException(
JGitText.get().renameFileFailed, src.getAbsolutePath(), MessageFormat.format(JGitText.get().renameFileFailed,
dst.getAbsolutePath())); src.getAbsolutePath(), dst.getAbsolutePath()));
} }
/** /**

Loading…
Cancel
Save