diff options
| author | Jorge Ruesga <jorge@ruesga.com> | 2012-11-05 23:47:21 +0100 |
|---|---|---|
| committer | Jorge Ruesga <jorge@ruesga.com> | 2012-11-05 23:47:21 +0100 |
| commit | b1d5cd1b4e1dc605032072e91a0a8c76515ec030 (patch) | |
| tree | 5c228cf8f4b8c42cfe762784fd14992a45b90863 | |
| parent | 9fe2cd7b099aaa8cf2c5eb5941af1f49797958eb (diff) | |
| download | android_packages_apps_CMFileManager-b1d5cd1b4e1dc605032072e91a0a8c76515ec030.tar.gz android_packages_apps_CMFileManager-b1d5cd1b4e1dc605032072e91a0a8c76515ec030.tar.bz2 android_packages_apps_CMFileManager-b1d5cd1b4e1dc605032072e91a0a8c76515ec030.zip | |
CMFileManager: Fix mv operation on Cross-device link failure
Issue https://github.com/jruesga/CMFileManager/issues/31.
The busybox mv command returns a failure when files are moved between filesystem (Cross-device
link failure). This changes fix this failure by:
* Replace mv command for a "mv or cp+rm" operation.
* rm operation occurs over source mount point so this need to be mounted prior to execute this
new command.
* Fix the stderr buffer filling on error.
Change-Id: If113ad810e7daffeb8379589789b2855eda14908
20 files changed, 233 insertions, 50 deletions
diff --git a/res/xml/command_list.xml b/res/xml/command_list.xml index 5da670f4..c79aee77 100644 --- a/res/xml/command_list.xml +++ b/res/xml/command_list.xml @@ -64,7 +64,7 @@ <command commandId="cp" commandPath="/system/xbin/cp" commandArgs="-af %1$s %2$s" /> <command commandId="link" commandPath="/system/bin/ln" commandArgs="-s %1$s %2$s" /> <command commandId="mkdir" commandPath="/system/bin/mkdir" commandArgs="-p %1$s" /> - <command commandId="mv" commandPath="/system/bin/mv" commandArgs="%1$s %2$s" /> + <command commandId="mv" commandPath="/system/bin/mv" commandArgs="%1$s %2$s || ( /system/xbin/cp -af %1$s %2$s && /system/bin/rm -R %1$s )" /> <command commandId="rm" commandPath="/system/bin/rm" commandArgs="%1$s" /> <command commandId="rmdir" commandPath="/system/bin/rm" commandArgs="-R %1$s" /> diff --git a/src/com/cyanogenmod/filemanager/commands/WritableExecutable.java b/src/com/cyanogenmod/filemanager/commands/WritableExecutable.java index 111b2575..f00702a6 100644 --- a/src/com/cyanogenmod/filemanager/commands/WritableExecutable.java +++ b/src/com/cyanogenmod/filemanager/commands/WritableExecutable.java @@ -25,9 +25,16 @@ import com.cyanogenmod.filemanager.model.MountPoint; public interface WritableExecutable extends SyncResultExecutable { /** - * Method that return the mount point that the program use to write. + * Method that return the source mount point that the program use to write. * - * @return MountPoint The mount point reference. + * @return MountPoint The source mount point reference. */ - MountPoint getWritableMountPoint(); + MountPoint getSrcWritableMountPoint(); + + /** + * Method that return the destination mount point that the program use to write. + * + * @return MountPoint The destination mount point reference. + */ + MountPoint getDstWritableMountPoint(); } diff --git a/src/com/cyanogenmod/filemanager/commands/java/CopyCommand.java b/src/com/cyanogenmod/filemanager/commands/java/CopyCommand.java index befea638..3e1e316f 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/CopyCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/CopyCommand.java @@ -100,7 +100,15 @@ public class CopyCommand extends Program implements CopyExecutable { * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mDst); } diff --git a/src/com/cyanogenmod/filemanager/commands/java/CreateDirCommand.java b/src/com/cyanogenmod/filemanager/commands/java/CreateDirCommand.java index 749134c8..4a2ed51b 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/CreateDirCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/CreateDirCommand.java @@ -95,7 +95,15 @@ public class CreateDirCommand extends Program implements CreateDirExecutable { * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mPath); } } diff --git a/src/com/cyanogenmod/filemanager/commands/java/CreateFileCommand.java b/src/com/cyanogenmod/filemanager/commands/java/CreateFileCommand.java index fa9b5bff..ab9901f5 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/CreateFileCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/CreateFileCommand.java @@ -105,7 +105,15 @@ public class CreateFileCommand extends Program implements CreateFileExecutable { * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mPath); } } diff --git a/src/com/cyanogenmod/filemanager/commands/java/DeleteDirCommand.java b/src/com/cyanogenmod/filemanager/commands/java/DeleteDirCommand.java index 3af8c90e..07e9498d 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/DeleteDirCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/DeleteDirCommand.java @@ -100,7 +100,15 @@ public class DeleteDirCommand extends Program implements DeleteDirExecutable { * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mPath); } diff --git a/src/com/cyanogenmod/filemanager/commands/java/DeleteFileCommand.java b/src/com/cyanogenmod/filemanager/commands/java/DeleteFileCommand.java index 8b6505ae..d635eab8 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/DeleteFileCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/DeleteFileCommand.java @@ -100,7 +100,15 @@ public class DeleteFileCommand extends Program implements DeleteFileExecutable { * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mPath); } } diff --git a/src/com/cyanogenmod/filemanager/commands/java/MoveCommand.java b/src/com/cyanogenmod/filemanager/commands/java/MoveCommand.java index f19486db..f94e7f1f 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/MoveCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/MoveCommand.java @@ -95,7 +95,15 @@ public class MoveCommand extends Program implements MoveExecutable { * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return MountPointHelper.getMountPointFromDirectory(this.mSrc); + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mDst); } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/ChangeOwnerCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/ChangeOwnerCommand.java index 6821a3a6..999ac540 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/ChangeOwnerCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/ChangeOwnerCommand.java @@ -86,7 +86,15 @@ public class ChangeOwnerCommand extends SyncResultProgram implements ChangeOwner * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mFileName); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/ChangePermissionsCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/ChangePermissionsCommand.java index 3fc2e08d..4c2bf60a 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/ChangePermissionsCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/ChangePermissionsCommand.java @@ -84,7 +84,15 @@ public class ChangePermissionsCommand * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mFileName); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/CopyCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/CopyCommand.java index a1e50b34..abd021a9 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/CopyCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/CopyCommand.java @@ -81,7 +81,15 @@ public class CopyCommand extends SyncResultProgram implements CopyExecutable { * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mDst); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/CreateDirCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/CreateDirCommand.java index d80184bb..56e73e5b 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/CreateDirCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/CreateDirCommand.java @@ -80,7 +80,15 @@ public class CreateDirCommand extends SyncResultProgram implements CreateDirExec * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mFileName); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/CreateFileCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/CreateFileCommand.java index e60085d3..f67ebcf5 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/CreateFileCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/CreateFileCommand.java @@ -81,7 +81,15 @@ public class CreateFileCommand extends SyncResultProgram implements CreateFileEx * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mFileName); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/DeleteDirCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/DeleteDirCommand.java index 533f47d6..9dc80eb7 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/DeleteDirCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/DeleteDirCommand.java @@ -80,7 +80,15 @@ public class DeleteDirCommand extends SyncResultProgram implements DeleteDirExec * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mFileName); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/DeleteFileCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/DeleteFileCommand.java index 59d3f84a..e4f202ec 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/DeleteFileCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/DeleteFileCommand.java @@ -80,7 +80,15 @@ public class DeleteFileCommand extends SyncResultProgram implements DeleteFileEx * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mFileName); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/LinkCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/LinkCommand.java index 31ae067d..9dc0ac7c 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/LinkCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/LinkCommand.java @@ -82,7 +82,15 @@ public class LinkCommand extends SyncResultProgram implements LinkExecutable { * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mLink); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/MoveCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/MoveCommand.java index 1915f2d2..a91e508a 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/MoveCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/MoveCommand.java @@ -35,6 +35,7 @@ public class MoveCommand extends SyncResultProgram implements MoveExecutable { private static final String ID = "mv"; //$NON-NLS-1$ private Boolean mRet; + private final String mSrc; private final String mDst; /** @@ -46,6 +47,7 @@ public class MoveCommand extends SyncResultProgram implements MoveExecutable { */ public MoveCommand(String src, String dst) throws InvalidCommandDefinitionException { super(ID, src, dst); + this.mSrc = src; this.mDst = dst; } @@ -81,7 +83,15 @@ public class MoveCommand extends SyncResultProgram implements MoveExecutable { * {@inheritDoc} */ @Override - public MountPoint getWritableMountPoint() { + public MountPoint getSrcWritableMountPoint() { + return MountPointHelper.getMountPointFromDirectory(this.mSrc); + } + + /** + * {@inheritDoc} + */ + @Override + public MountPoint getDstWritableMountPoint() { return MountPointHelper.getMountPointFromDirectory(this.mDst); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/Shell.java b/src/com/cyanogenmod/filemanager/commands/shell/Shell.java index d8e176c2..648dcfd1 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/Shell.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/Shell.java @@ -121,8 +121,9 @@ public abstract class Shell extends Command { } if (err.indexOf("Read-only file system") != -1) { //$NON-NLS-1$ if (program instanceof WritableExecutable) { + // This error could be caused by dst or src. No matter which. Use dst. throw new ReadOnlyFilesystemException( - ((WritableExecutable)program).getWritableMountPoint()); + ((WritableExecutable)program).getDstWritableMountPoint()); } throw new ExecutionException("Read-only file system"); //$NON-NLS-1$ } diff --git a/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java b/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java index 5374c828..f5924847 100644 --- a/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java +++ b/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java @@ -564,6 +564,12 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis //Check if invocation was successfully or not if (!program.isIgnoreShellStdErrCheck()) { + //Wait for stderr buffer to be filled + if (exitCode != 0) { + try { + Thread.sleep(100L); + } catch (Throwable ex) {/**NON BLOCK**/} + } this.mShell.checkStdErr(this.mActiveCommand, exitCode, this.mSbErr.toString()); } this.mShell.checkExitCode(exitCode); @@ -836,9 +842,7 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis ShellConsole.this.mActiveCommand != null && ShellConsole.this.mActiveCommand instanceof AsyncResultProgram; - // Exit if active command is cancelled - if (ShellConsole.this.mCancelled) continue; - + // Add to stderr String s = new String(data, 0, read); ShellConsole.this.mSbErr.append(s); sb.append(s); diff --git a/src/com/cyanogenmod/filemanager/util/CommandHelper.java b/src/com/cyanogenmod/filemanager/util/CommandHelper.java index eaf725a9..11b6f35f 100644 --- a/src/com/cyanogenmod/filemanager/util/CommandHelper.java +++ b/src/com/cyanogenmod/filemanager/util/CommandHelper.java @@ -1280,7 +1280,7 @@ public final class CommandHelper { if (executable1.getResult().booleanValue()) { // Configure the rest of attributes of the wrapper listener wrapperListener.mUnmount = unmount; - wrapperListener.mMountPoint = executable1.getWritableMountPoint(); + wrapperListener.mMountPoint = executable1.getDstWritableMountPoint(); //- Write WriteExecutable executable2 = @@ -1346,7 +1346,7 @@ public final class CommandHelper { if (executable2.getResult().booleanValue()) { // Configure the rest of attributes of the wrapper listener wrapperListener.mUnmount = unmount; - wrapperListener.mMountPoint = executable2.getWritableMountPoint(); + wrapperListener.mMountPoint = executable2.getDstWritableMountPoint(); //- Compress execute(context, executable1, c); @@ -1409,7 +1409,7 @@ public final class CommandHelper { if (executable2.getResult().booleanValue()) { // Configure the rest of attributes of the wrapper listener wrapperListener.mUnmount = unmount; - wrapperListener.mMountPoint = executable2.getWritableMountPoint(); + wrapperListener.mMountPoint = executable2.getDstWritableMountPoint(); //- Compress execute(context, executable1, c); @@ -1483,7 +1483,7 @@ public final class CommandHelper { if (((Boolean)executable2.getResult()).booleanValue()) { // Configure the rest of attributes of the wrapper listener wrapperListener.mUnmount = unmount; - wrapperListener.mMountPoint = executable2.getWritableMountPoint(); + wrapperListener.mMountPoint = executable2.getDstWritableMountPoint(); //- Compress execute(context, executable1, c); @@ -1602,12 +1602,33 @@ public final class CommandHelper { CommandNotFoundException, ReadOnlyFilesystemException { //Retrieve the mount point information to check if a remount operation is required - boolean needMount = false; - MountPoint mp = executable.getWritableMountPoint(); - if (mp != null) { - if (MountPointHelper.isMountAllowed(mp)) { - if (!MountPointHelper.isReadWrite(mp)) { - needMount = true; + //There are 2 mount points: destination and source. Check both + // - Destination + boolean needMountDst = false; + MountPoint mpDst = executable.getDstWritableMountPoint(); + if (mpDst != null) { + if (MountPointHelper.isMountAllowed(mpDst)) { + if (!MountPointHelper.isReadWrite(mpDst)) { + needMountDst = true; + } else { + //Mount point is already read-write + } + } else { + //For security or physical reasons the mount point can't be + //mounted as read-write. Execute the command + //and notify to the user + } + } else { + //Don't have information about the mount point. Execute the command + //and notify to the user + } + // - Source + boolean needMountSrc = false; + MountPoint mpSrc = executable.getSrcWritableMountPoint(); + if (mpSrc != null) { + if (MountPointHelper.isMountAllowed(mpSrc)) { + if (!MountPointHelper.isReadWrite(mpSrc)) { + needMountSrc = true; } else { //Mount point is already read-write } @@ -1622,24 +1643,40 @@ public final class CommandHelper { } //Create the mount/unmount executables - MountExecutable mountExecutable = null; - MountExecutable unmountExecutable = null; - if (needMount) { - mountExecutable = + MountExecutable mountDstExecutable = null; + MountExecutable unmountDstExecutable = null; + if (needMountDst) { + mountDstExecutable = console.getExecutableFactory().newCreator(). - createMountExecutable(mp, true); - unmountExecutable = + createMountExecutable(mpDst, true); + unmountDstExecutable = console.getExecutableFactory().newCreator(). - createMountExecutable(mp, false); + createMountExecutable(mpDst, false); + } + MountExecutable mountSrcExecutable = null; + MountExecutable unmountSrcExecutable = null; + if (needMountSrc) { + mountSrcExecutable = + console.getExecutableFactory().newCreator(). + createMountExecutable(mpSrc, true); + unmountSrcExecutable = + console.getExecutableFactory().newCreator(). + createMountExecutable(mpSrc, false); } //Execute the commands - boolean mountExecuted = false; + boolean mountExecutedDst = false; + boolean mountExecutedSrc = false; try { - if (needMount) { + if (needMountDst) { //Execute the mount command - console.execute(mountExecutable); - mountExecuted = true; + console.execute(mountDstExecutable); + mountExecutedDst = true; + } + if (needMountSrc) { + //Execute the mount command + console.execute(mountSrcExecutable); + mountExecutedSrc = true; } //Execute the command @@ -1647,14 +1684,22 @@ public final class CommandHelper { } catch (InsufficientPermissionsException ipEx) { //Configure the commands to execute - if (needMount && !mountExecuted) { + if (needMountDst && !mountExecutedDst) { + //The failed operation was the mount rw operation + //This operations is already in the exception in the fifo queue + ipEx.addExecutable(executable); + } else if (needMountSrc && !mountExecutedSrc) { //The failed operation was the mount rw operation //This operations is already in the exception in the fifo queue ipEx.addExecutable(executable); } - if (needMount) { + if (needMountDst) { + //A mount operation was executed or will be executed + ipEx.addExecutable(unmountDstExecutable); + } + if (needMountSrc) { //A mount operation was executed or will be executed - ipEx.addExecutable(unmountExecutable); + ipEx.addExecutable(unmountSrcExecutable); } //Rethrow the exception @@ -1663,14 +1708,18 @@ public final class CommandHelper { } finally { //If previously was a mount successful execution, then execute //and unmount operation - if (mountExecuted && !leaveDeviceMounted) { + if (mountExecutedDst && !leaveDeviceMounted) { + //Execute the unmount command + console.execute(unmountDstExecutable); + } + if (mountExecutedSrc && !leaveDeviceMounted) { //Execute the unmount command - console.execute(unmountExecutable); + console.execute(unmountSrcExecutable); } } // If the needed unmount was executed - return mountExecuted && leaveDeviceMounted; + return (mountExecutedDst || mountExecutedSrc) && leaveDeviceMounted; } /** |
