gboolean fm_deep_count_job_run(FmJob* job) { FmDeepCountJob* dc = (FmDeepCountJob*)job; GList* l; l = fm_list_peek_head_link(dc->paths); for(; !fm_job_is_cancelled(job) && l; l=l->next) { FmPath* path = FM_PATH(l->data); if(fm_path_is_native(path)) /* if it's a native file, use posix APIs */ deep_count_posix( dc, path ); else { GFile* gf = fm_path_to_gfile(path); deep_count_gio( dc, NULL, gf ); g_object_unref(gf); } } return TRUE; }
static gboolean deep_count_gio(FmDeepCountJob* job, GFileInfo* inf, GFile* gf) { FmJob* fmjob = FM_JOB(job); GError* err = NULL; GFileType type; const char* fs_id; gboolean descend; if(inf) g_object_ref(inf); else { _retry_query_info: inf = g_file_query_info(gf, query_str, (job->flags & FM_DC_JOB_FOLLOW_LINKS) ? 0 : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, fm_job_get_cancellable(fmjob), &err); if(!inf) { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; if(act == FM_JOB_RETRY) goto _retry_query_info; return FALSE; } } if(fm_job_is_cancelled(fmjob)) { g_object_unref(inf); return FALSE; } type = g_file_info_get_file_type(inf); descend = TRUE; ++job->count; job->total_size += g_file_info_get_size(inf); job->total_ondisk_size += g_file_info_get_attribute_uint64(inf, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE); /* prepare for moving across different devices */ if( job->flags & FM_DC_JOB_PREPARE_MOVE ) { fs_id = g_file_info_get_attribute_string(inf, G_FILE_ATTRIBUTE_ID_FILESYSTEM); if( g_strcmp0(fs_id, job->dest_fs_id) != 0 ) { /* files on different device requires an additional 'delete' for the source file. */ ++job->total_size; /* this is for the additional delete */ ++job->total_ondisk_size; ++job->count; } else descend = FALSE; } if( type == G_FILE_TYPE_DIRECTORY ) { FmPath* fm_path = fm_path_new_for_gfile(gf); /* check if we need to decends into the dir. */ /* trash:/// doesn't support deleting files recursively */ if(job->flags & FM_DC_JOB_PREPARE_DELETE && fm_path_is_trash(fm_path) && ! fm_path_is_trash_root(fm_path)) descend = FALSE; else { /* only descends into files on the same filesystem */ if( job->flags & FM_DC_JOB_SAME_FS ) { fs_id = g_file_info_get_attribute_string(inf, G_FILE_ATTRIBUTE_ID_FILESYSTEM); descend = (g_strcmp0(fs_id, job->dest_fs_id) == 0); } } fm_path_unref(fm_path); g_object_unref(inf); inf = NULL; if(descend) { GFileEnumerator* enu; _retry_enum_children: enu = g_file_enumerate_children(gf, query_str, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, fm_job_get_cancellable(fmjob), &err); if(enu) { while( !fm_job_is_cancelled(fmjob) ) { inf = g_file_enumerator_next_file(enu, fm_job_get_cancellable(fmjob), &err); if(inf) { GFile* child = g_file_get_child(gf, g_file_info_get_name(inf)); deep_count_gio(job, inf, child); g_object_unref(child); g_object_unref(inf); inf = NULL; } else { if(err) /* error! */ { /* FM_JOB_RETRY is not supported */ /*FmJobErrorAction act = */ fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; } else { /* EOF is reached, do nothing. */ break; } } } g_file_enumerator_close(enu, NULL, NULL); g_object_unref(enu); } else { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; if(act == FM_JOB_RETRY) goto _retry_enum_children; } } } else g_object_unref(inf); return TRUE; }