use of com.mucommander.commons.file.archive.AbstractArchiveFile in project mucommander by mucommander.
the class UnpackJob method jobCompleted.
// //////////////////////
// Overridden methods //
// //////////////////////
@Override
protected void jobCompleted() {
super.jobCompleted();
// If the destination files are located inside an archive, optimize the archive file
AbstractArchiveFile archiveFile = baseDestFolder.getParentArchive();
if (archiveFile != null && archiveFile.isArchive() && archiveFile.isWritable())
optimizeArchive((AbstractRWArchiveFile) archiveFile);
// Unselect all files in the active table upon successful completion
if (selectedEntries != null) {
ActionManager.performAction(UnmarkAllAction.Descriptor.ACTION_ID, getMainFrame());
}
}
use of com.mucommander.commons.file.archive.AbstractArchiveFile in project mucommander by mucommander.
the class UnpackJob method processFile.
/**
* Unpacks the given archive file. If the file is a directory, its children will be processed recursively.
* If the file is not an archive file nor a directory, it is not processed and <code>false</code> is returned.
*
* @param file the file to unpack
* @param recurseParams unused
* @return <code>true</code> if the file has been processed successfully
*/
@Override
protected boolean processFile(AbstractFile file, Object recurseParams) {
// Stop if interrupted
if (getState() == FileJobState.INTERRUPTED)
return false;
// Destination folder
AbstractFile destFolder = baseDestFolder;
// If the file is a directory, process its children recursively
if (file.isDirectory()) {
do {
// Loop for retries
try {
// List files inside archive file (can throw an IOException)
AbstractFile[] archiveFiles = getCurrentFile().ls();
// Recurse on zip's contents
for (int j = 0; j < archiveFiles.length && getState() != FileJobState.INTERRUPTED; j++) {
// Notify job that we're starting to process this file (needed for recursive calls to processFile)
nextFile(archiveFiles[j]);
// Recurse
processFile(archiveFiles[j], destFolder);
}
// Return true when complete
return true;
} catch (IOException e) {
// File could not be uncompressed properly
DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_read_file", getCurrentFilename()));
// Retry loops
if (ret == FileJobAction.RETRY)
continue;
// cancel, skip or close dialog will simply return false
return false;
}
} while (true);
}
// Abort if the file is neither an archive file nor a directory
if (!file.isArchive())
return false;
// 'Cast' the file as an archive file
AbstractArchiveFile archiveFile = file.getAncestor(AbstractArchiveFile.class);
String destSeparator = destFolder.getSeparator();
// Unpack the archive, copying entries one by one, in the iterator's order
try (ArchiveEntryIterator iterator = archiveFile.getEntryIterator()) {
ArchiveEntry entry;
while ((entry = iterator.nextEntry()) != null && getState() != FileJobState.INTERRUPTED) {
String entryPath = entry.getPath();
boolean processEntry = false;
if (selectedEntries == null) {
// Entries are processed
processEntry = true;
} else {
// We need to determine if the entry should be processed or not
// Process this entry if the selectedEntries set contains this entry, or a parent of this entry
int nbSelectedEntries = selectedEntries.size();
for (int i = 0; i < nbSelectedEntries; i++) {
ArchiveEntry selectedEntry = selectedEntries.get(i);
// selectedEntry is a parent of the current entry.
if (selectedEntry.isDirectory()) {
if (entryPath.startsWith(selectedEntry.getPath())) {
processEntry = true;
break;
// Note: we can't remove selectedEntryPath from the set, we still need it
}
} else if (entryPath.equals(selectedEntry.getPath())) {
// If the (regular file) entry is in the set, remove it as we no longer need it (will speed up
// subsequent searches)
processEntry = true;
selectedEntries.remove(i);
break;
}
}
}
if (!processEntry)
continue;
DefaultMutableTreeNode entryNode = archiveFile.getArchiveEntryNode(entryPath);
if (entryNode != null) {
ArchiveEntry archiveEntry = (ArchiveEntry) entryNode.getUserObject();
if (archiveEntry.isSymbolicLink()) {
Files.createSymbolicLink(FileSystems.getDefault().getPath(destFolder.getPath(), entry.getName()), FileSystems.getDefault().getPath(entry.getLinkTarget()));
continue;
}
}
// Resolve the entry file
AbstractFile entryFile = archiveFile.getArchiveEntryFile(entryPath);
// Notify the job that we're starting to process this file
nextFile(entryFile);
// Figure out the destination file's path, relatively to the base destination folder
String relDestPath = baseArchiveDepth == 0 ? entry.getPath() : PathUtils.removeLeadingFragments(entry.getPath(), "/", baseArchiveDepth);
if (newName != null)
relDestPath = newName + (PathUtils.getDepth(relDestPath, "/") <= 1 ? "" : "/" + PathUtils.removeLeadingFragments(relDestPath, "/", 1));
if (!"/".equals(destSeparator))
relDestPath = relDestPath.replace("/", destSeparator);
// Create destination AbstractFile instance
AbstractFile destFile = destFolder.getChild(relDestPath);
// Check for ZipSlip (see https://snyk.io/research/zip-slip-vulnerability)
do {
if (destFolder.isParentOf(destFile))
break;
DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("unpack.entry_out_of_target_dir", destFile.getName()));
// Retry loops
if (ret == FileJobAction.RETRY)
continue;
// Cancel, skip or close dialog returns false
return false;
} while (true);
// Check if the file does not already exist in the destination
destFile = checkForCollision(entryFile, destFolder, destFile, false);
if (destFile == null) {
// A collision occurred and either the file was skipped, or the user cancelled the job
continue;
}
// If the entry is a directory ...
if (entryFile.isDirectory()) {
// Create the directory in the destination, if it doesn't already exist
if (!(destFile.exists() && destFile.isDirectory())) {
// Loop for retry
do {
try {
// Use mkdirs() instead of mkdir() to create any parent folder that doesn't exist yet
destFile.mkdirs();
} catch (IOException e) {
// Unable to create folder
DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_create_folder", entryFile.getName()));
// Retry loops
if (ret == FileJobAction.RETRY)
continue;
// Cancel or close dialog return false
return false;
// Skip continues
}
break;
} while (true);
}
} else // The entry is a regular file, copy it
{
// Create the file's parent directory(s) if it doesn't already exist
AbstractFile destParentFile = destFile.getParent();
if (!destParentFile.exists()) {
// Use mkdirs() instead of mkdir() to create any parent folder that doesn't exist yet
destParentFile.mkdirs();
}
// some archive file implementations (such as TAR) can speed things by an order of magnitude.
if (!tryCopyFile(new ProxiedEntryFile(entryFile, entry, archiveFile, iterator), destFile, append, errorDialogTitle))
return false;
}
}
return true;
} catch (IOException e) {
showErrorDialog(errorDialogTitle, Translator.get("cannot_read_file", archiveFile.getName()));
}
return false;
}
use of com.mucommander.commons.file.archive.AbstractArchiveFile in project mucommander by mucommander.
the class CopyJob method jobCompleted.
// //////////////////////
// Overridden methods //
// //////////////////////
@Override
protected void jobCompleted() {
super.jobCompleted();
baseDestFolder.postCopyHook();
// If the destination files are located inside an archive, optimize the archive file
AbstractArchiveFile archiveFile = baseDestFolder.getParentArchive();
if (archiveFile != null && archiveFile.isArchive() && archiveFile.isWritable())
optimizeArchive((AbstractRWArchiveFile) archiveFile);
// select the copied file in the active table after this job has finished (and hasn't been cancelled)
if (files.size() == 1 && newName != null && baseDestFolder.equalsCanonical(files.elementAt(0).getParent())) {
// Resolve new file instance now that it exists: some remote files do not immediately update file attributes
// after creation, we need to get an instance that reflects the newly created file attributes
selectFileWhenFinished(FileFactory.getFile(baseDestFolder.getAbsolutePath(true) + newName));
}
}
use of com.mucommander.commons.file.archive.AbstractArchiveFile in project mucommander by mucommander.
the class DeleteJob method jobCompleted.
@Override
protected void jobCompleted() {
super.jobCompleted();
// If the source files are located inside an archive, optimize the archive file
AbstractArchiveFile archiveFile = getBaseSourceFolder().getParentArchive();
if (archiveFile != null && archiveFile.isArchive() && archiveFile.isWritable()) {
while (true) {
try {
archiveToOptimize = ((AbstractRWArchiveFile) archiveFile);
isOptimizingArchive = true;
archiveToOptimize.optimizeArchive();
break;
} catch (IOException e) {
if (showErrorDialog(errorDialogTitle, Translator.get("error_while_optimizing_archive", archiveFile.getName())) == FileJobAction.RETRY)
continue;
break;
}
}
isOptimizingArchive = true;
}
}
Aggregations