Interruptable computing of directory size.

file.h: new type and functions for status dialog
of directory computing size. Added required includes.
(compute_dir_size): changed return value. Added new parameters
to handle status dialig.
Fixed comments.

file.c: new functions for status dialog of directory
computing size.
(compute_dir_size): interruptable dir size computing.
Changed return value. Added new parameters to handle status dialig.
(panel_compute_totals): likewise.
(panel_operate): likewise.

cmd.c (single_dirsize_cmd): interruptable dir size computing.
(dirsizes_cmd): likewise.
This commit is contained in:
Andrew Borodin 2009-04-12 18:17:08 +04:00
parent f021c090f9
commit 11bc00bea9
3 changed files with 181 additions and 29 deletions

View File

@ -37,7 +37,7 @@
#include "global.h"
#include "cmd.h" /* Our definitions */
#include "fileopctx.h" /* file_op_context_new() */
#include "file.h" /* copy_file_file() */
#include "file.h" /* file operation routines */
#include "find.h" /* do_find() */
#include "hotlist.h" /* hotlist_cmd() */
#include "tree.h" /* tree_chdir() */
@ -1197,13 +1197,21 @@ single_dirsize_cmd (void)
file_entry *entry;
off_t marked;
double total;
ComputeDirSizeUI *ui;
ui = compute_dir_size_create_ui ();
entry = &(panel->dir.list[panel->selected]);
if (S_ISDIR (entry->st.st_mode) && strcmp(entry->fname, "..") != 0) {
total = 0.0;
compute_dir_size (entry->fname, &marked, &total);
entry->st.st_size = (off_t) total;
entry->f.dir_size_computed = 1;
if (compute_dir_size (entry->fname, ui, compute_dir_size_update_ui,
&marked, &total) == FILE_CONT) {
entry->st.st_size = (off_t) total;
entry->f.dir_size_computed = 1;
}
compute_dir_size_destroy_ui (ui);
}
if (mark_moves_down)
@ -1213,25 +1221,35 @@ single_dirsize_cmd (void)
panel->dirty = 1;
}
void
void
dirsizes_cmd (void)
{
WPanel *panel = current_panel;
int i;
off_t marked;
double total;
ComputeDirSizeUI *ui;
ui = compute_dir_size_create_ui ();
for (i = 0; i < panel->count; i++)
if (S_ISDIR (panel->dir.list [i].st.st_mode) &&
((panel->dirs_marked && panel->dir.list [i].f.marked) ||
!panel->dirs_marked) &&
strcmp (panel->dir.list [i].fname, "..") != 0) {
if (S_ISDIR (panel->dir.list [i].st.st_mode)
&& ((panel->dirs_marked && panel->dir.list [i].f.marked)
|| !panel->dirs_marked)
&& strcmp (panel->dir.list [i].fname, "..") != 0) {
total = 0.0l;
compute_dir_size (panel->dir.list [i].fname, &marked, &total);
if (compute_dir_size (panel->dir.list [i].fname,
ui, compute_dir_size_update_ui,
&marked, &total) != FILE_CONT)
break;
panel->dir.list [i].st.st_size = (off_t) total;
panel->dir.list [i].f.dir_size_computed = 1;
}
compute_dir_size_destroy_ui (ui);
recalculate_panel_summary (panel);
panel_re_sort (panel);
panel->dirty = 1;

View File

@ -1474,26 +1474,113 @@ panel_get_file (WPanel *panel, struct stat *stat_buf)
return NULL;
}
ComputeDirSizeUI *
compute_dir_size_create_ui (void)
{
ComputeDirSizeUI *ui;
char *b_name = N_("&Abort");
#ifdef ENABLE_NLS
b_name = _(b_name);
#endif
ui = g_new (ComputeDirSizeUI, 1);
ui->dlg = create_dlg (0, 0, 8, COLS/2, dialog_colors, NULL,
NULL, _("Directory size"), DLG_CENTER | DLG_TRYUP);
ui->dirname = label_new (3, 3, "");
add_widget (ui->dlg, ui->dirname);
add_widget (ui->dlg,
button_new (5, (ui->dlg->cols - strlen (b_name))/2,
FILE_ABORT, NORMAL_BUTTON, b_name, NULL));
/* We will manage the dialog without any help,
that's why we have to call init_dlg */
init_dlg (ui->dlg);
return ui;
}
void
compute_dir_size_destroy_ui (ComputeDirSizeUI *ui)
{
if (ui != NULL) {
/* schedule to update passive panel */
other_panel->dirty = 1;
/* close and destroy dialog */
dlg_run_done (ui->dlg);
destroy_dlg (ui->dlg);
g_free (ui);
}
}
FileProgressStatus
compute_dir_size_update_ui (const void *ui, const char *dirname)
{
const ComputeDirSizeUI *this = (const ComputeDirSizeUI *) ui;
char *msg;
int c;
Gpm_Event event;
if (ui == NULL)
return FILE_CONT;
msg = g_strdup_printf (_("Scanning: %s"), dirname);
label_set_text (this->dirname, name_trunc (msg, this->dlg->cols - 6));
g_free (msg);
event.x = -1; /* Don't show the GPM cursor */
c = get_event (&event, 0, 0);
if (c == EV_NONE)
return FILE_CONT;
/* Reinitialize to avoid old values after events other than
selecting a button */
this->dlg->ret_value = FILE_CONT;
dlg_process_event (this->dlg, c, &event);
switch (this->dlg->ret_value) {
case B_CANCEL:
case FILE_ABORT:
return FILE_ABORT;
default:
return FILE_CONT;
}
}
/**
* compute_dir_size:
*
* Computes the number of bytes used by the files in a directory
*/
void
compute_dir_size (const char *dirname, off_t *ret_marked, double *ret_total)
FileProgressStatus
compute_dir_size (const char *dirname, const void *ui,
compute_dir_size_callback cback,
off_t *ret_marked, double *ret_total)
{
DIR *dir;
struct dirent *dirent;
FileProgressStatus ret = FILE_CONT;
dir = mc_opendir (dirname);
if (!dir)
return;
if (dir == NULL)
return ret;
while ((dirent = mc_readdir (dir)) != NULL) {
struct stat s;
char *fullname;
int res;
struct stat s;
ret = (cback != NULL) ? cback (ui, dirname) : FILE_CONT;
if (ret != FILE_CONT)
break;
if (strcmp (dirent->d_name, ".") == 0)
continue;
@ -1501,19 +1588,23 @@ compute_dir_size (const char *dirname, off_t *ret_marked, double *ret_total)
continue;
fullname = concat_dir_and_file (dirname, dirent->d_name);
res = mc_lstat (fullname, &s);
if (res != 0) {
g_free (fullname);
continue;
break;
}
if (S_ISDIR (s.st_mode)) {
off_t subdir_count = 0;
double subdir_bytes = 0;
compute_dir_size (fullname, &subdir_count, &subdir_bytes);
ret = compute_dir_size (fullname, ui, cback, &subdir_count, &subdir_bytes);
if (ret != FILE_CONT) {
g_free (fullname);
break;
}
*ret_marked += subdir_count;
*ret_total += subdir_bytes;
@ -1521,10 +1612,13 @@ compute_dir_size (const char *dirname, off_t *ret_marked, double *ret_total)
(*ret_marked)++;
*ret_total += s.st_size;
}
g_free (fullname);
}
mc_closedir (dir);
return ret;
}
/**
@ -1535,8 +1629,10 @@ compute_dir_size (const char *dirname, off_t *ret_marked, double *ret_total)
* as required. In addition, it checks to see if it will
* overwrite any files by doing the copy.
*/
static void
panel_compute_totals (WPanel *panel, off_t *ret_marked, double *ret_total)
static FileProgressStatus
panel_compute_totals (WPanel *panel, const void *ui,
compute_dir_size_callback cback,
off_t *ret_marked, double *ret_total)
{
int i;
@ -1555,19 +1651,27 @@ panel_compute_totals (WPanel *panel, off_t *ret_marked, double *ret_total)
char *dir_name;
off_t subdir_count = 0;
double subdir_bytes = 0;
FileProgressStatus status;
dir_name =
concat_dir_and_file (panel->cwd, panel->dir.list[i].fname);
compute_dir_size (dir_name, &subdir_count, &subdir_bytes);
status = compute_dir_size (dir_name, ui, cback,
&subdir_count, &subdir_bytes);
g_free (dir_name);
if (status != FILE_CONT)
return FILE_ABORT;
*ret_marked += subdir_count;
*ret_total += subdir_bytes;
g_free (dir_name);
} else {
(*ret_marked)++;
*ret_total += s->st_size;
}
}
return FILE_CONT;
}
/*
@ -1940,8 +2044,18 @@ panel_operate (void *source_panel, FileOperation operation,
/* Initialize variables for progress bars */
if (operation != OP_MOVE && verbose && file_op_compute_totals) {
panel_compute_totals (panel, &ctx->progress_count,
&ctx->progress_bytes);
ComputeDirSizeUI *ui;
FileProgressStatus status;
ui = compute_dir_size_create_ui ();
status = panel_compute_totals (panel,
ui, compute_dir_size_update_ui,
&ctx->progress_count, &ctx->progress_bytes);
compute_dir_size_destroy_ui (ui);
if (status != FILE_CONT)
goto clean_up;
ctx->progress_totals_computed = 1;
} else {
ctx->progress_totals_computed = 0;

View File

@ -1,7 +1,12 @@
/* File and directory operation routines for Midnight Commander */
#ifndef MC_FILE_H
#define MC_FILE_H
#include "global.h"
#include "fileopctx.h"
#include "dialog.h" /* Dlg_head */
#include "widget.h" /* WLabel */
struct link;
@ -25,9 +30,24 @@ extern int file_op_compute_totals;
/* Report error with one file */
FileProgressStatus file_error (const char *format, const char *file);
/* Query routines */
/* Compute directory size */
/* callback to update status dialog */
typedef FileProgressStatus (*compute_dir_size_callback)(const void *ui, const char *dirname);
void compute_dir_size (const char *dirname, off_t *ret_marked,
double *ret_total);
/* return value is FILE_CONT or FILE_ABORT */
FileProgressStatus compute_dir_size (const char *dirname, const void *ui,
compute_dir_size_callback cback,
off_t *ret_marked, double *ret_total);
#endif
/* status dialog of durectory size computing */
typedef struct {
Dlg_head *dlg;
WLabel *dirname;
} ComputeDirSizeUI;
ComputeDirSizeUI *compute_dir_size_create_ui (void);
void compute_dir_size_destroy_ui (ComputeDirSizeUI *ui);
FileProgressStatus compute_dir_size_update_ui (const void *ui, const char *dirname);
#endif /* MC_FILE_H */