Add EncFSProgressListener to monitor operation progress
copyPath() movePath() and deletePath() now take an optional EncFSProgressListener in order to post progress events. This is useful for displaying progress of long running operations.
This commit is contained in:
parent
b494e51c1f
commit
80ffa6a78e
3 changed files with 333 additions and 35 deletions
src/main/java
|
@ -30,6 +30,7 @@ import org.mrpdaemon.sec.encfs.EncFSFile;
|
|||
import org.mrpdaemon.sec.encfs.EncFSFileInputStream;
|
||||
import org.mrpdaemon.sec.encfs.EncFSInvalidConfigException;
|
||||
import org.mrpdaemon.sec.encfs.EncFSInvalidPasswordException;
|
||||
import org.mrpdaemon.sec.encfs.EncFSProgressListener;
|
||||
import org.mrpdaemon.sec.encfs.EncFSUnsupportedException;
|
||||
import org.mrpdaemon.sec.encfs.EncFSUtil;
|
||||
import org.mrpdaemon.sec.encfs.EncFSVolume;
|
||||
|
@ -367,7 +368,7 @@ public class EncFSShell {
|
|||
try {
|
||||
result = volume.deletePath(
|
||||
EncFSVolume.combinePath(curDir, filePath),
|
||||
recursive);
|
||||
recursive, new EncFSShellProgressListener());
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out
|
||||
.println("File not found: '" + filePath + "'");
|
||||
|
@ -443,7 +444,8 @@ public class EncFSShell {
|
|||
|
||||
boolean result = false;
|
||||
try {
|
||||
result = volume.movePath(srcPath, dstPath);
|
||||
result = volume.movePath(srcPath, dstPath,
|
||||
new EncFSShellProgressListener());
|
||||
} catch (IOException e) {
|
||||
System.out.println(e.getMessage());
|
||||
continue;
|
||||
|
@ -514,7 +516,8 @@ public class EncFSShell {
|
|||
|
||||
boolean result = false;
|
||||
try {
|
||||
result = volume.copyPath(srcPath, dstPath);
|
||||
result = volume.copyPath(srcPath, dstPath,
|
||||
new EncFSShellProgressListener());
|
||||
} catch (IOException e) {
|
||||
System.out.println(e.getMessage());
|
||||
continue;
|
||||
|
@ -639,4 +642,35 @@ public class EncFSShell {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class EncFSShellProgressListener extends EncFSProgressListener {
|
||||
|
||||
int numProcessed = 0;
|
||||
|
||||
@Override
|
||||
public void handleEvent(int eventType) {
|
||||
switch (eventType) {
|
||||
case EncFSProgressListener.FILES_COUNTED_EVENT:
|
||||
break;
|
||||
case EncFSProgressListener.NEW_FILE_EVENT:
|
||||
if (this.getNumFiles() != 0) {
|
||||
System.out.println("[" + (numProcessed * 100)
|
||||
/ this.getNumFiles() + "%] Processing: "
|
||||
+ this.getCurrentFile());
|
||||
numProcessed++;
|
||||
} else {
|
||||
System.out.println("Processing: " + this.getCurrentFile());
|
||||
}
|
||||
break;
|
||||
case EncFSProgressListener.FILE_PROCESS_EVENT:
|
||||
break;
|
||||
case EncFSProgressListener.OP_COMPLETE_EVENT:
|
||||
System.out.println("[100%] Operation complete!");
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown event type: " + eventType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* EncFS Java Library
|
||||
* Copyright (C) 2011 Mark R. Pariente
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
package org.mrpdaemon.sec.encfs;
|
||||
|
||||
/**
|
||||
* Class representing a progress listener for long running operations
|
||||
*/
|
||||
public abstract class EncFSProgressListener {
|
||||
|
||||
/**
|
||||
* Event notifying that the number of affected files/directories have been
|
||||
* counted.
|
||||
*/
|
||||
public static final int FILES_COUNTED_EVENT = 0;
|
||||
|
||||
|
||||
/** Event notifying that a new file has started to be processed */
|
||||
public static final int NEW_FILE_EVENT = 1;
|
||||
|
||||
/** Event notifying that a single file or directory has been processed. */
|
||||
public static final int FILE_PROCESS_EVENT = 2;
|
||||
|
||||
/** Event notifying completion of the whole operation. */
|
||||
public static final int OP_COMPLETE_EVENT = 3;
|
||||
|
||||
// Name of the current file being operated on
|
||||
private String currentFile = null;
|
||||
|
||||
// Number of files being operated on
|
||||
private int numFiles = 0;
|
||||
|
||||
/**
|
||||
* Method that must be overridden by extending class to handle events posted
|
||||
* to the event listener
|
||||
*
|
||||
* @param eventType
|
||||
* Type of the event that just occured
|
||||
*/
|
||||
public abstract void handleEvent(int eventType);
|
||||
|
||||
/**
|
||||
* Get the name of the current file being operated on
|
||||
*
|
||||
* @return name of the current file being operated on
|
||||
*/
|
||||
public String getCurrentFile() {
|
||||
return currentFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total number of files that the operation will proceed on. Note
|
||||
* that this value is undefined until a FILES_COUNTED_EVENT is posted first
|
||||
*
|
||||
* @return total number of files that the operation will proceed on
|
||||
*/
|
||||
public int getNumFiles() {
|
||||
return numFiles;
|
||||
}
|
||||
|
||||
// Post an event to the progress listener
|
||||
protected void postEvent(int eventType) {
|
||||
handleEvent(eventType);
|
||||
}
|
||||
|
||||
// Set the current file
|
||||
protected void setCurrentFile(String fileName) {
|
||||
currentFile = fileName;
|
||||
postEvent(NEW_FILE_EVENT);
|
||||
}
|
||||
|
||||
// Set the total number of files being operated on
|
||||
protected void setNumFiles(int numFiles) {
|
||||
this.numFiles = numFiles;
|
||||
postEvent(FILES_COUNTED_EVENT);
|
||||
}
|
||||
}
|
|
@ -404,6 +404,28 @@ public class EncFSVolume {
|
|||
return combinePath(dirPath, file.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Count files and directories under the given file
|
||||
*
|
||||
* @param file
|
||||
* File to count under
|
||||
* @return Number of files/directories under the file
|
||||
*/
|
||||
public static int countFiles(EncFSFile file) {
|
||||
if (file.isDirectory()) {
|
||||
int dirCount = 1;
|
||||
try {
|
||||
for (EncFSFile subFile : file.listFiles()) {
|
||||
dirCount += countFiles(subFile);
|
||||
}
|
||||
} catch (Exception e) { /* Do nothing */
|
||||
}
|
||||
return dirCount;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration object for this volume
|
||||
*
|
||||
|
@ -740,12 +762,13 @@ public class EncFSVolume {
|
|||
}
|
||||
|
||||
// Recursive method to delete a directory tree
|
||||
private boolean recursiveDelete(EncFSFile file) throws IOException {
|
||||
private boolean recursiveDelete(EncFSFile file,
|
||||
EncFSProgressListener progressListener) throws IOException {
|
||||
boolean result = true;
|
||||
|
||||
if (file.isDirectory()) {
|
||||
for (EncFSFile subFile : file.listFiles()) {
|
||||
boolean subResult = recursiveDelete(subFile);
|
||||
boolean subResult = recursiveDelete(subFile, progressListener);
|
||||
if (subResult == false) {
|
||||
result = false;
|
||||
break;
|
||||
|
@ -753,15 +776,92 @@ public class EncFSVolume {
|
|||
}
|
||||
|
||||
if (result == true) {
|
||||
file.delete();
|
||||
if (progressListener != null) {
|
||||
progressListener.setCurrentFile(file.getPath());
|
||||
}
|
||||
|
||||
result = file.delete();
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener
|
||||
.postEvent(EncFSProgressListener.FILE_PROCESS_EVENT);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (progressListener != null) {
|
||||
progressListener.setCurrentFile(file.getPath());
|
||||
}
|
||||
|
||||
result = file.delete();
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener
|
||||
.postEvent(EncFSProgressListener.FILE_PROCESS_EVENT);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given file or directory in the EncFS volume
|
||||
*
|
||||
* @param filePath
|
||||
* Absolute volume path of the file/directory to delete
|
||||
* @param recursive
|
||||
* Whether to recursively delete directories. Without this option
|
||||
* deletePath will fail to delete non-empty directories
|
||||
* @param progressListener
|
||||
* Progress listener for getting individual file updates
|
||||
*
|
||||
* @return true if deletion succeeds, false otherwise
|
||||
*
|
||||
* @throws EncFSCorruptDataException
|
||||
* Filename encoding failed
|
||||
* @throws IOException
|
||||
* File provider returned I/O error
|
||||
* @throws EncFSChecksumException
|
||||
* Filename encoding failed
|
||||
*/
|
||||
public boolean deletePath(String filePath, boolean recursive,
|
||||
EncFSProgressListener progressListener)
|
||||
throws EncFSCorruptDataException, IOException {
|
||||
EncFSFile file = this.getFile(filePath);
|
||||
boolean result;
|
||||
|
||||
if (recursive == true) {
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener.setNumFiles(countFiles(file));
|
||||
}
|
||||
|
||||
result = recursiveDelete(file, progressListener);
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener
|
||||
.postEvent(EncFSProgressListener.OP_COMPLETE_EVENT);
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
if (progressListener != null) {
|
||||
progressListener.setNumFiles(1);
|
||||
progressListener.setCurrentFile(file.getPath());
|
||||
}
|
||||
|
||||
result = file.delete();
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener
|
||||
.postEvent(EncFSProgressListener.FILE_PROCESS_EVENT);
|
||||
progressListener
|
||||
.postEvent(EncFSProgressListener.OP_COMPLETE_EVENT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given file or directory in the EncFS volume
|
||||
*
|
||||
|
@ -782,18 +882,13 @@ public class EncFSVolume {
|
|||
*/
|
||||
public boolean deletePath(String filePath, boolean recursive)
|
||||
throws EncFSCorruptDataException, IOException {
|
||||
EncFSFile file = this.getFile(filePath);
|
||||
|
||||
if (recursive == true) {
|
||||
return recursiveDelete(file);
|
||||
} else {
|
||||
return file.delete();
|
||||
}
|
||||
return deletePath(filePath, recursive, null);
|
||||
}
|
||||
|
||||
// Helper function to perform copy/move path operations
|
||||
private boolean copyOrMovePath(String srcPath, String dstPath,
|
||||
PathOperation op) throws EncFSCorruptDataException, IOException {
|
||||
PathOperation op, EncFSProgressListener progressListener)
|
||||
throws EncFSCorruptDataException, IOException {
|
||||
validateAbsoluteFileName(srcPath, "srcPath");
|
||||
validateAbsoluteFileName(dstPath, "dstPath");
|
||||
|
||||
|
@ -836,18 +931,22 @@ public class EncFSVolume {
|
|||
// If dstPath doesn't exist this is a rename, keep dstPath as-is
|
||||
}
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener.setCurrentFile(dstPath);
|
||||
}
|
||||
|
||||
result = this.makeDir(dstPath);
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener
|
||||
.postEvent(EncFSProgressListener.FILE_PROCESS_EVENT);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
for (EncFSFile subFile : this.listFilesForPath(srcPath)) {
|
||||
boolean subResult;
|
||||
if (op == PathOperation.MOVE) {
|
||||
subResult = this.movePath(subFile.getPath(),
|
||||
combinePath(dstPath, subFile));
|
||||
} else {
|
||||
subResult = this.copyPath(subFile.getPath(),
|
||||
combinePath(dstPath, subFile));
|
||||
}
|
||||
boolean subResult = copyOrMovePath(subFile.getPath(),
|
||||
combinePath(dstPath, subFile), op, progressListener);
|
||||
|
||||
if (!subResult) {
|
||||
result = false;
|
||||
break;
|
||||
|
@ -877,28 +976,70 @@ public class EncFSVolume {
|
|||
EncFSFile dstFile = getFile(dstPath);
|
||||
|
||||
if (dstFile.isDirectory()) {
|
||||
if (op == PathOperation.MOVE) {
|
||||
return this.movePath(srcPath,
|
||||
combinePath(dstPath, srcFile));
|
||||
} else {
|
||||
return this.copyPath(srcPath,
|
||||
combinePath(dstPath, srcFile));
|
||||
}
|
||||
return copyOrMovePath(srcPath,
|
||||
combinePath(dstPath, srcFile), op, progressListener);
|
||||
} else {
|
||||
throw new IOException("Destination file " + dstPath
|
||||
+ " exists, can't overwrite!");
|
||||
}
|
||||
} else {
|
||||
// dstPath doesn't exist, perform normal copy/move
|
||||
if (op == PathOperation.MOVE) {
|
||||
return fileProvider.move(encSrcPath, encDstPath);
|
||||
} else {
|
||||
return srcFile.copy(createFile(dstPath));
|
||||
boolean result;
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener.setCurrentFile(dstPath);
|
||||
}
|
||||
|
||||
if (op == PathOperation.MOVE) {
|
||||
result = fileProvider.move(encSrcPath, encDstPath);
|
||||
} else {
|
||||
result = srcFile.copy(createFile(dstPath));
|
||||
}
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener
|
||||
.postEvent(EncFSProgressListener.FILE_PROCESS_EVENT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the source file or directory to the target file or directory
|
||||
*
|
||||
* @param srcPath
|
||||
* Absolute volume path of the source file or directory
|
||||
* @param dstPath
|
||||
* Absolute volume path of the target file or directory
|
||||
* @param progressListener
|
||||
* Progress listener for getting individual file updates
|
||||
*
|
||||
* @return true if copy succeeds, false otherwise
|
||||
*
|
||||
* @throws EncFSCorruptDataException
|
||||
* Filename encoding failed
|
||||
* @throws IOException
|
||||
* File provider returned I/O error
|
||||
*/
|
||||
public boolean copyPath(String srcPath, String dstPath,
|
||||
EncFSProgressListener progressListener)
|
||||
throws EncFSCorruptDataException, IOException {
|
||||
if (progressListener != null) {
|
||||
progressListener.setNumFiles(countFiles(getFile(srcPath)) + 1);
|
||||
}
|
||||
|
||||
boolean result = copyOrMovePath(srcPath, dstPath, PathOperation.COPY,
|
||||
progressListener);
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener.postEvent(EncFSProgressListener.OP_COMPLETE_EVENT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the source file or directory to the target file or directory
|
||||
*
|
||||
|
@ -916,7 +1057,41 @@ public class EncFSVolume {
|
|||
*/
|
||||
public boolean copyPath(String srcPath, String dstPath)
|
||||
throws EncFSCorruptDataException, IOException {
|
||||
return copyOrMovePath(srcPath, dstPath, PathOperation.COPY);
|
||||
return copyPath(srcPath, dstPath, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a file / directory
|
||||
*
|
||||
* @param srcPath
|
||||
* Absolute volume path of the file or directory to move
|
||||
* @param dstPath
|
||||
* Absolute volume path of the destination file or directory
|
||||
* @param progressListener
|
||||
* Progress listener for getting individual file updates
|
||||
*
|
||||
* @return true if the move succeeds, false otherwise
|
||||
*
|
||||
* @throws EncFSCorruptDataException
|
||||
* Filename encoding failed
|
||||
* @throws IOException
|
||||
* File provider returned I/O error
|
||||
*/
|
||||
public boolean movePath(String srcPath, String dstPath,
|
||||
EncFSProgressListener progressListener)
|
||||
throws EncFSCorruptDataException, IOException {
|
||||
if (progressListener != null) {
|
||||
progressListener.setNumFiles(countFiles(getFile(srcPath)) + 1);
|
||||
}
|
||||
|
||||
boolean result = copyOrMovePath(srcPath, dstPath, PathOperation.MOVE,
|
||||
progressListener);
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener.postEvent(EncFSProgressListener.OP_COMPLETE_EVENT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -936,7 +1111,7 @@ public class EncFSVolume {
|
|||
*/
|
||||
public boolean movePath(String srcPath, String dstPath)
|
||||
throws EncFSCorruptDataException, IOException {
|
||||
return copyOrMovePath(srcPath, dstPath, PathOperation.MOVE);
|
||||
return movePath(srcPath, dstPath, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue