You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libfm-qt-packaging/src/core/deletejob.cpp

152 lines
4.4 KiB

#include "deletejob.h"
#include "totalsizejob.h"
#include "fileinfo_p.h"
namespace Fm {
bool DeleteJob::deleteFile(const FilePath& path, GFileInfoPtr inf) {
ErrorAction act = ErrorAction::CONTINUE;
while(!inf) {
GErrorPtr err;
inf = GFileInfoPtr{
g_file_query_info(path.gfile().get(), "standard::*",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable().get(), &err),
false
};
if(err) {
act = emitError(err, ErrorSeverity::SEVERE);
if(act == ErrorAction::ABORT) {
return false;
}
if(act != ErrorAction::RETRY) {
break;
}
}
}
/* currently processed file. */
setCurrentFile(path);
if(g_file_info_get_file_type(inf.get()) == G_FILE_TYPE_DIRECTORY) {
// delete the content of the dir prior to deleting itself
deleteDirContent(path, inf);
}
bool hasError = false;
while(!isCancelled()) {
GErrorPtr err;
// try to delete the path directly
if(g_file_delete(path.gfile().get(), cancellable().get(), &err)) {
break;
}
if(err) {
// FIXME: error handling
/* if it's non-empty dir then descent into it then try again */
/* trash root gives G_IO_ERROR_PERMISSION_DENIED */
if(err.domain() == G_IO_ERROR && err.code() == G_IO_ERROR_NOT_EMPTY) {
deleteDirContent(path, inf);
}
else if(err.domain() == G_IO_ERROR && err.code() == G_IO_ERROR_PERMISSION_DENIED) {
/* special case for trash:/// */
/* FIXME: is there any better way to handle this? */
auto scheme = path.uriScheme();
if(g_strcmp0(scheme.get(), "trash") == 0) {
break;
}
}
act = emitError(err, ErrorSeverity::MODERATE);
if(act != ErrorAction::RETRY) {
hasError = true;
break;
}
}
}
addFinishedAmount(g_file_info_get_size(inf.get()), 1);
return !hasError;
}
bool DeleteJob::deleteDirContent(const FilePath& path, GFileInfoPtr inf) {
#if 0
FmFolder* sub_folder;
/* special handling for trash:/// */
if(!g_file_is_native(gf)) {
char* scheme = g_file_get_uri_scheme(gf);
if(g_strcmp0(scheme, "trash") == 0) {
/* little trick: basename of trash root is /. */
char* basename = g_file_get_basename(gf);
if(basename && basename[0] == G_DIR_SEPARATOR) {
is_trash_root = true;
}
g_free(basename);
}
g_free(scheme);
}
#endif
GErrorPtr err;
GFileEnumeratorPtr enu {
g_file_enumerate_children(path.gfile().get(), gfile_info_query_attribs,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable().get(), &err),
false
};
if(!enu) {
emitError(err, ErrorSeverity::MODERATE);
return false;
}
bool hasError = false;
while(!isCancelled()) {
inf = GFileInfoPtr{
g_file_enumerator_next_file(enu.get(), cancellable().get(), &err),
false
};
if(inf) {
auto subPath = path.child(g_file_info_get_name(inf.get()));
if(!deleteFile(subPath, inf)) {
continue;
}
}
else {
if(err) {
emitError(err, ErrorSeverity::MODERATE);
/* ErrorAction::RETRY is not supported here */
hasError = true;
}
else { /* EOF */
}
break;
}
}
g_file_enumerator_close(enu.get(), nullptr, nullptr);
return !hasError;
}
void DeleteJob::exec() {
/* prepare the job, count total work needed with FmDeepCountJob */
TotalSizeJob totalSizeJob{paths_, TotalSizeJob::Flags::PREPARE_DELETE};
connect(&totalSizeJob, &TotalSizeJob::error, this, &DeleteJob::error);
connect(this, &DeleteJob::cancelled, &totalSizeJob, &TotalSizeJob::cancel);
totalSizeJob.run();
if(isCancelled()) {
return;
}
setTotalAmount(totalSizeJob.totalSize(), totalSizeJob.fileCount());
Q_EMIT preparedToRun();
for(auto& path : paths_) {
if(isCancelled()) {
break;
}
deleteFile(path, GFileInfoPtr{nullptr});
}
}
} // namespace Fm