diff --git a/gnome/gdialogs.c b/gnome/gdialogs.c index 348455434..8e8d3b763 100644 --- a/gnome/gdialogs.c +++ b/gnome/gdialogs.c @@ -134,7 +134,7 @@ file_progress_show_count (long done, long total) } FileProgressStatus -file_progress_show_bytes (long done, long total) +file_progress_show_bytes (double done, double total) { if (!total) gtk_progress_bar_update (GTK_PROGRESS_BAR (byte_prog), 0.0); diff --git a/gnome/gdnd.c b/gnome/gdnd.c index d06838f3b..ed2f34847 100644 --- a/gnome/gdnd.c +++ b/gnome/gdnd.c @@ -91,8 +91,20 @@ find_panel_owning_window (GdkDragContext *context) panel_toplevel_widget = panel->xwindow; - if (panel->xwindow == source_widget) + if (panel->xwindow == source_widget){ + + /* + * Now a WPanel actually contains a number of + * drag sources. If the drag source is the + * Tree, we must report that it was not the + * contents of the WPanel + */ + + if (source_widget == panel->tree) + return NULL; + return panel; + } } return NULL; @@ -190,16 +202,30 @@ perform_action (GList *names, GdkDragAction action, char *destdir) if (file_error (_("Could not stat %s\n%s"), dest_name) != FILE_RETRY) result = 0; else { + long count = 0; + double bytes = 0; + if (S_ISDIR (s.st_mode)) { if (action == GDK_ACTION_COPY) - copy_dir_dir (name, dest_name, TRUE, FALSE, FALSE, FALSE); + copy_dir_dir ( + name, dest_name, + TRUE, FALSE, + FALSE, FALSE, + &count, &bytes); else - move_dir_dir (name, dest_name); + move_dir_dir ( + name, dest_name, + &count, &bytes); } else { if (action == GDK_ACTION_COPY) - copy_file_file (name, dest_name, TRUE); + copy_file_file ( + name, dest_name, + TRUE, + &count, &bytes); else - move_file_file (name, dest_name); + move_file_file ( + name, dest_name, + &count, &bytes); } } } diff --git a/gnome/gpageprop.c b/gnome/gpageprop.c index b3aebc3cd..2565080a4 100644 --- a/gnome/gpageprop.c +++ b/gnome/gpageprop.c @@ -200,9 +200,11 @@ item_properties (GtkWidget *parent, char *fname, desktop_icon_t *di) if (strchr (new_name, '/')) message (1, "Error", "The new name includes the `/' character"); else if (strcmp (new_name, base) != 0) { - char *base = x_basename (fname); - char save = *base; - char *full_target; + char *base = x_basename (fname); + char save = *base; + char *full_target; + long count = 0; + double bytes = 0; *base = 0; full_target = concat_dir_and_file (fname, new_name); @@ -210,7 +212,7 @@ item_properties (GtkWidget *parent, char *fname, desktop_icon_t *di) create_op_win (OP_MOVE, 0); file_mask_defaults (); - move_file_file (fname, full_target); + move_file_file (fname, full_target, &count, &bytes); destroy_op_win (); if (di) { diff --git a/src/ChangeLog b/src/ChangeLog index f2bfc3286..c21062ce0 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,17 @@ +1998-12-04 Miguel de Icaza + + * cmd.c, tree.c: Updated to the new file.c api. + + * file.c: (copy_file_file, copy_dir_dir, move_file_file, + move_dir_dir): Updated to work with the new updating stuff. + + * setup.c: New configuration option to compute the totals to be + transfered. + + * file.c (compute_dir_size, panel_compute_totals): New routines to + compute the total ammount of information that is going to be + transfered. + 1998-12-03 Miguel de Icaza * ext.h: GNOME edition uses a different set of .ext files. diff --git a/src/cmd.c b/src/cmd.c index 91ce089eb..5d20e703b 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -622,13 +622,16 @@ void unselect_cmd (void) static int check_for_default(char *default_file, char *file) { struct stat s; + long count = 0; + double bytes = 0; + if (mc_stat (file, &s)){ if (mc_stat (default_file, &s)){ return -1; } create_op_win (OP_COPY, 0); file_mask_defaults (); - copy_file_file (default_file, file, 1); + copy_file_file (default_file, file, 1, &count, &bytes); destroy_op_win (); } return 0; diff --git a/src/file.c b/src/file.c index 651e36fbf..53292dee1 100644 --- a/src/file.c +++ b/src/file.c @@ -134,6 +134,13 @@ int erase_at_end = 1; */ int file_mask_preserve; +/* + * Whether the Midnight Commander tries to provide more + * information about copy/move sizes and bytes transfered + * at the expense of some speed + */ +int file_op_compute_totals = 1; + /* * If running as root, preserve the original uid/gid * (we don't want to try chwon for non root) @@ -161,6 +168,10 @@ double file_progress_eta_secs; /* The reget flag */ int file_progress_do_reget = 1; +/* Status reporting flags */ +long file_progress_count; +double file_progress_bytes; + /* mapping operations into names */ char *operation_names [] = { "Copy", "Move", "Delete" }; @@ -502,9 +513,28 @@ make_symlink (char *src_path, char *dst_path) return return_status; } +static int +progress_update_one (long *progress_count, double *progress_bytes, int add) +{ + int ret; + + (*progress_count)++; + (*progress_bytes) += add; + + /* Apply some heuristic here to not call the update stuff very often */ + ret = file_progress_show_count (*progress_count, file_progress_count); + + if (ret != FILE_CONT) + return ret; + + ret = file_progress_show_bytes (*progress_bytes, file_progress_bytes); + + return ret; +} int -copy_file_file (char *src_path, char *dst_path, int ask_overwrite) +copy_file_file (char *src_path, char *dst_path, int ask_overwrite, + long *progress_count, double *progress_bytes) { #ifndef OS2_NT uid_t src_uid; @@ -705,8 +735,11 @@ copy_file_file (char *src_path, char *dst_path, int ask_overwrite) file_progress_eta_secs = 0.0; file_progress_bps = 0; + return_status = file_progress_show (0, file_size); + mc_refresh (); + if (return_status != FILE_CONT) goto ret; @@ -849,7 +882,8 @@ ret: } #endif - /* .ado: according to the XPG4 standard, the file must be closed before + /* + * .ado: according to the XPG4 standard, the file must be closed before * chmod can be invoked */ retry_dst_chmod: @@ -864,6 +898,10 @@ ret: if (!appending && file_mask_preserve) mc_utime (dst_path, &utb); } + + if (return_status == FILE_CONT) + return_status = progress_update_one (progress_count, progress_bytes, file_size); + return return_status; } @@ -874,8 +912,11 @@ ret: /* FIXME: This function needs to check the return values of the function calls */ int -copy_dir_dir (char *s, char *d, int toplevel, int move_over, int delete, - struct link *parent_dirs) +copy_dir_dir (char *s, char *d, int toplevel, + int move_over, int delete, + struct link *parent_dirs, + long *progress_count, + double *progress_bytes) { #ifdef __os2__ DIR *next; @@ -1030,11 +1071,15 @@ copy_dir_dir (char *s, char *d, int toplevel, int move_over, int delete, * dir already exists. So, we give the recursive call the flag 0 * meaning no toplevel. */ - return_status = copy_dir_dir (path, mdpath, 0, 0, delete, parent_dirs); + return_status = copy_dir_dir ( + path, mdpath, 0, 0, delete, parent_dirs, + progress_count, progress_bytes); free (mdpath); } else { dest_file = concat_dir_and_file (dest_dir, x_basename (path)); - return_status = copy_file_file (path, dest_file, 1); + return_status = copy_file_file ( + path, dest_file, 1, + progress_count, progress_bytes); free (dest_file); } if (delete && return_status == FILE_CONT){ @@ -1089,7 +1134,7 @@ ret: /* {{{ Move routines */ int -move_file_file (char *s, char *d) +move_file_file (char *s, char *d, long *progress_count, double *progress_bytes) { struct stat src_stats, dst_stats; int return_status = FILE_CONT; @@ -1175,8 +1220,10 @@ move_file_file (char *s, char *d) #endif /* Failed because filesystem boundary -> copy the file instead */ - if ((return_status = copy_file_file (s, d, 0)) != FILE_CONT) + return_status = copy_file_file (s, d, 0, progress_count, progress_bytes); + if (return_status != FILE_CONT) return return_status; + if ((return_status = file_progress_show_source (NULL)) != FILE_CONT || (return_status = file_progress_show (0, 0)) != FILE_CONT) return return_status; @@ -1191,11 +1238,14 @@ move_file_file (char *s, char *d) return return_status; } - return FILE_CONT; + if (return_status == FILE_CONT) + return_status = progress_update_one (progress_count, progress_bytes, src_stats.st_size); + + return return_status; } int -move_dir_dir (char *s, char *d) +move_dir_dir (char *s, char *d, long *progress_count, double *progress_bytes) { struct stat sbuf, dbuf, destbuf; struct link *lp; @@ -1222,7 +1272,11 @@ move_dir_dir (char *s, char *d) retry_dst_stat: if (!mc_stat (destdir, &destbuf)){ if (move_over){ - if ((return_status = copy_dir_dir (s, destdir, 0, 1, 1, 0)) != FILE_CONT) + return_status = copy_dir_dir ( + s, destdir, 0, 1, 1, 0, + progress_count, progress_bytes); + + if (return_status != FILE_CONT) goto ret; goto oktoret; } else { @@ -1260,7 +1314,9 @@ move_dir_dir (char *s, char *d) w32try: /* Failed because of filesystem boundary -> copy dir instead */ - if ((return_status = copy_dir_dir (s, destdir, 0, 0, 1, 0)) != FILE_CONT) + return_status = copy_dir_dir (s, destdir, 0, 0, 1, 0, progress_count, progress_bytes); + + if (return_status != FILE_CONT) goto ret; oktoret: if ((return_status = file_progress_show_source (NULL)) != FILE_CONT @@ -1525,8 +1581,106 @@ file_mask_defaults (void) file_mask_preserve_uidgid = (geteuid () == 0) ? 1 : 0; } -/* Returns 1 if did change the directory structure, - Returns 0 if user aborted */ +/** + * compute_dir_size: + * + * Computes the number of bytes used by the files in a directory + */ +static void +compute_dir_size (char *dirname, long *ret_marked, double *ret_total) +{ + DIR *dir; + struct dirent *dirent; + + dir = mc_opendir (dirname); + + if (!dir) + return; + + while ((dirent = mc_readdir (dir)) != NULL){ + struct stat s; + char *fullname; + int res; + + if (strcmp (dirent->d_name, ".") == 0) + continue; + if (strcmp (dirent->d_name, "..") == 0) + continue; + + fullname = concat_dir_and_file (dirname, dirent->d_name); + + res = mc_lstat (fullname, &s); + + if (res != 0){ + free (fullname); + continue; + } + + if (S_ISDIR (s.st_mode)){ + long subdir_count = 0; + double subdir_bytes = 0; + + compute_dir_size (fullname, &subdir_count, &subdir_bytes); + + *ret_marked += subdir_count; + *ret_total += subdir_bytes; + } else { + (*ret_marked)++; + *ret_total += s.st_size; + } + free (fullname); + } + + mc_closedir (dir); +} + +/** + * panel_compute_totals: + * + * compute the number of files and the number of bytes + * used up by the whole selection, recursing directories + * as required. + */ +static void +panel_compute_totals (WPanel *panel, long *ret_marked, double *ret_total) +{ + int i; + + for (i = 0; i < panel->count; i++){ + struct stat *s; + + if (!panel->dir.list [i].f.marked) + continue; + + s = &panel->dir.list [i].buf; + + if (S_ISDIR (s->st_mode)){ + char *dir_name; + long subdir_count = 0; + double subdir_bytes = 0; + + dir_name = concat_dir_and_file (panel->cwd, panel->dir.list [i].fname); + compute_dir_size (dir_name, &subdir_count, &subdir_bytes); + + *ret_marked += subdir_count; + *ret_total += subdir_bytes; + free (dir_name); + } else { + (*ret_marked)++; + *ret_total += s->st_size; + } + } +} + +/** + * panel_operate: + * + * Performs one of the operations on the selection on the source_panel + * (copy, delete, move). + * + * Returns 1 if did change the directory + * structure, Returns 0 if user aborted + */ int panel_operate (void *source_panel, FileOperation operation, char *thedefault) { @@ -1542,8 +1696,10 @@ panel_operate (void *source_panel, FileOperation operation, char *thedefault) int only_one = (get_current_type () == view_tree) || (panel->marked <= 1); struct stat src_stat, dst_stat; int i, value; - long marked, total; - long count = 0, bytes = 0; + + long count = 0; + double bytes = 0; + int dst_result; int do_bg; /* do background operation? */ @@ -1614,17 +1770,22 @@ panel_operate (void *source_panel, FileOperation operation, char *thedefault) } } #endif + /* Initialize things */ /* We now have ETA in all cases */ create_op_win (operation, 1); - /* We do not want to trash cache every time file is - created/touched. However, this will make our cache contain - invalid data. */ + + /* + * We do not want to trash cache every time file is + * created/touched. However, this will make our cache contain + * invalid data. + */ if (dest) mc_setctl (dest, MCCTL_WANT_STALE_DATA, NULL); ftpfs_hint_reread (0); /* Now, let's do the job */ + /* This code is only called by the tree and panel code */ if (only_one){ /* One file: FIXME mc_chdir will take user out of any vfs */ @@ -1636,18 +1797,22 @@ panel_operate (void *source_panel, FileOperation operation, char *thedefault) source_with_path = concat_dir_and_file (panel->cwd, source); #endif - if (operation == OP_DELETE){ - /* Delete operation */ + if (operation == OP_DELETE) + { if (S_ISDIR (src_stat.st_mode)) value = erase_dir (source_with_path); else value = erase_file (source_with_path); - } else { - /* Copy or move operation */ + } + else + { temp = transform_source (source_with_path); + if (temp == NULL){ value = transform_error; - } else { + } + else + { temp = get_full_name (dest, temp); free (dest); dest = temp; @@ -1655,20 +1820,28 @@ panel_operate (void *source_panel, FileOperation operation, char *thedefault) switch (operation){ case OP_COPY: - /* we use file_mask_op_follow_links only with OP_COPY, + /* + * we use file_mask_op_follow_links only with OP_COPY, */ (*file_mask_xstat) (source_with_path, &src_stat); + if (S_ISDIR (src_stat.st_mode)) - value = copy_dir_dir (source_with_path, dest, 1, 0, 0, 0); + value = copy_dir_dir ( + source_with_path, dest, 1, 0, 0, 0, &count, &bytes); else - value = copy_file_file (source_with_path, dest, 1); + value = copy_file_file ( + source_with_path, dest, 1, &count, &bytes); break; + case OP_MOVE: if (S_ISDIR (src_stat.st_mode)) - value = move_dir_dir (source_with_path, dest); + value = move_dir_dir ( + source_with_path, dest, &count, &bytes); else - value = move_file_file (source_with_path, dest); + value = move_file_file ( + source_with_path, dest, &count, &bytes); break; + default: value = FILE_CONT; message_1s (1, _(" Internal failure "), _(" Unknown file operation ")); @@ -1682,8 +1855,8 @@ panel_operate (void *source_panel, FileOperation operation, char *thedefault) } else { /* Many files */ + /* Check destination for copy or move operation */ if (operation != OP_DELETE){ - /* Check destination for copy or move operation */ retry_many_dst_stat: dst_result = mc_stat (dest, &dst_stat); if (dst_result == 0 && !S_ISDIR (dst_stat.st_mode)){ @@ -1694,75 +1867,104 @@ panel_operate (void *source_panel, FileOperation operation, char *thedefault) } /* Initialize variables for progress bars */ - marked = panel->marked; - total = panel->total; + if (file_op_compute_totals) + panel_compute_totals ( + panel, &file_progress_count, &file_progress_bytes); + else { + file_progress_count = panel->marked; + file_progress_bytes = panel->total; + } - /* Loop for every file */ + /* Loop for every file, perform the actual copy operation */ for (i = 0; i < panel->count; i++){ + if (!panel->dir.list [i].f.marked) continue; /* Skip the unmarked ones */ + source = panel->dir.list [i].fname; src_stat = panel->dir.list [i].buf; /* Inefficient, should we use pointers? */ + #ifdef WITH_FULL_PATHS if (source_with_path) free (source_with_path); source_with_path = concat_dir_and_file (panel->cwd, source); #endif + if (operation == OP_DELETE){ - /* Delete operation */ if (S_ISDIR (src_stat.st_mode)) value = erase_dir (source_with_path); else value = erase_file (source_with_path); - } else { - /* Copy or move operation */ + } + else + { if (temp) free (temp); + temp = transform_source (source_with_path); - if (temp == NULL){ + if (temp == NULL) value = transform_error; - } else { + else + { temp = get_full_name (dest, temp); + switch (operation){ case OP_COPY: - /* we use file_mask_op_follow_links only with OP_COPY, + /* + * we use file_mask_op_follow_links only with OP_COPY, */ (*file_mask_xstat) (source_with_path, &src_stat); if (S_ISDIR (src_stat.st_mode)) - value = copy_dir_dir (source_with_path, temp, 1, 0, 0, 0); + value = copy_dir_dir ( + source_with_path, temp, 1, 0, 0, 0, + &count, &bytes); else - value = copy_file_file (source_with_path, temp, 1); + value = copy_file_file ( + source_with_path, temp, 1, + &count, &bytes); free_linklist (&dest_dirs); break; + case OP_MOVE: if (S_ISDIR (src_stat.st_mode)) - value = move_dir_dir (source_with_path, temp); + value = move_dir_dir ( + source_with_path, temp, + &count, &bytes); else - value = move_file_file (source_with_path, temp); + value = move_file_file ( + source_with_path, temp, + &count, &bytes); break; + default: message_1s (1, _(" Internal failure "), _(" Unknown file operation ")); goto clean_up; } } + } /* Copy or move operation */ if (value == FILE_ABORT) goto clean_up; - if (value == FILE_CONT){ + + if (value == FILE_CONT) do_file_mark (panel, i, 0); - } - count ++; - if (file_progress_show_count (count, marked) == FILE_ABORT) + + count++; + + if (file_progress_show_count (count, file_progress_count) == FILE_ABORT) goto clean_up; + bytes += src_stat.st_size; if (verbose && - file_progress_show_bytes (bytes, total) == FILE_ABORT) + file_progress_show_bytes (bytes, file_progress_bytes) == FILE_ABORT) goto clean_up; + if (operation != OP_DELETE && verbose && file_progress_show (0, 0) == FILE_ABORT) goto clean_up; + mc_refresh (); } /* Loop for every file */ } /* Many files */ @@ -1770,23 +1972,30 @@ panel_operate (void *source_panel, FileOperation operation, char *thedefault) clean_up: /* Clean up */ destroy_op_win (); + if (dest) mc_setctl (dest, MCCTL_NO_STALE_DATA, NULL); + ftpfs_hint_reread (1); + free_linklist (&linklist); free_linklist (&dest_dirs); #if WITH_FULL_PATHS if (source_with_path) free (source_with_path); #endif + if (dest) free (dest); + if (temp) free (temp); + if (file_mask_rx.buffer){ free (file_mask_rx.buffer); file_mask_rx.buffer = NULL; } + if (file_mask_dest_mask){ free (file_mask_dest_mask); file_mask_dest_mask = NULL; @@ -1820,9 +2029,11 @@ real_do_file_error (enum OperationMode mode, char *error) case 0: do_refresh (); return FILE_SKIP; + case 1: do_refresh (); return FILE_RETRY; + case 2: default: return FILE_ABORT; @@ -1835,6 +2046,7 @@ file_error (char *format, char *file) { sprintf (cmd_buf, format, name_trunc (file, 30), unix_error_string (errno)); + return do_file_error (cmd_buf); } @@ -1849,6 +2061,7 @@ files_error (char *format, char *file1, char *file2) strcpy (nfile2, name_trunc (file2, 15)); sprintf (cmd_buf, format, nfile1, nfile2, unix_error_string (errno)); + return do_file_error (cmd_buf); } diff --git a/src/file.h b/src/file.h index bd78bc64a..3bc83c022 100644 --- a/src/file.h +++ b/src/file.h @@ -30,13 +30,17 @@ extern int know_not_what_am_i_doing; struct link; -int copy_file_file (char *s, char *d, int ask_overwrite); -int move_file_file (char *s, char *d); +int copy_file_file (char *s, char *d, int ask_overwrite, + long *progres_count, double *progress_bytes); +int move_file_file (char *s, char *d, + long *progres_count, double *progress_bytes); +int move_dir_dir (char *s, char *d, + long *progres_count, double *progress_bytes); +int copy_dir_dir (char *s, char *d, int toplevel, int move_over, + int delete, struct link *parent_dirs, + long *progres_count, double *progress_bytes); int erase_dir (char *s); int erase_dir_iff_empty (char *s); -int move_dir_dir (char *s, char *d); -int copy_dir_dir (char *s, char *d, int toplevel, int move_over, - int delete, struct link *parent_dirs); /* * Manually creating the copy/move/delte dialogs @@ -57,6 +61,7 @@ char *panel_operate_generate_prompt (char* cmd_buf, #endif extern int dive_into_subdirs; +extern int file_op_compute_totals; /* Error reporting routines */ /* Skip/Retry/Abort routine */ @@ -80,6 +85,7 @@ extern int dive_into_subdirs; /* Callback routine for background activity */ int background_attention (int fd, void *info); + extern int background_wait; int is_wildcarded (char *p); diff --git a/src/filegui.c b/src/filegui.c index c19d4354a..7da0883e6 100644 --- a/src/filegui.c +++ b/src/filegui.c @@ -379,7 +379,7 @@ file_progress_show_count (long done, long total) } FileProgressStatus -file_progress_show_bytes (long done, long total) +file_progress_show_bytes (double done, double total) { if (!verbose) return file_progress_check_buttons (); diff --git a/src/filegui.h b/src/filegui.h index 91dff1c87..fa6bad36c 100644 --- a/src/filegui.h +++ b/src/filegui.h @@ -7,7 +7,7 @@ FileProgressStatus file_progress_check_buttons (void); FileProgressStatus file_progress_show (long done, long total); FileProgressStatus file_progress_show_count (long done, long total); -FileProgressStatus file_progress_show_bytes (long done, long total); +FileProgressStatus file_progress_show_bytes (double done, double total); FileProgressStatus file_progress_show_source (char *path); FileProgressStatus file_progress_show_target (char *path); FileProgressStatus file_progress_show_deleting (char *path); diff --git a/src/setup.c b/src/setup.c index fb3222da4..c8e7ab030 100644 --- a/src/setup.c +++ b/src/setup.c @@ -209,6 +209,7 @@ static struct { { "panel_scroll_pages", &panel_scroll_pages }, { "xtree_mode", &xtree_mode }, { "num_history_items_recorded", &num_history_items_recorded }, + { "file_op_compute_totals", &file_op_compute_totals }, #ifdef SAVE_CHANGES_OUTSIDE_OPTIONS_MENU { "dive_into_subdirs", &dive_into_subdirs }, { "preserve_uidgid", &preserve_uidgid }, diff --git a/src/tree.c b/src/tree.c index 66f2fadb0..b1b6741ff 100644 --- a/src/tree.c +++ b/src/tree.c @@ -1093,8 +1093,10 @@ static int toggle_nav_mode (void) void tree_copy (WTree *tree, char *default_dest) { - char *dest; - + char *dest; + long count = 0; + double bytes = 0; + if (!tree->selected_ptr) return; sprintf (cmd_buf, _("Copy \"%s\" directory to:"), @@ -1105,7 +1107,8 @@ void tree_copy (WTree *tree, char *default_dest) } create_op_win (OP_COPY, 0); file_mask_defaults (); - copy_dir_dir (tree->selected_ptr->name, dest, 1, 0, 0, 0); + + copy_dir_dir (tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes); destroy_op_win (); free (dest); } @@ -1125,9 +1128,11 @@ static int tree_copy_cmd (WTree *tree) void tree_move (WTree *tree, char *default_dest) { - char *dest; + char *dest; struct stat buf; - + double bytes = 0; + long count = 0; + if (!tree->selected_ptr) return; sprintf (cmd_buf, _("Move \"%s\" directory to:"), @@ -1149,7 +1154,7 @@ void tree_move (WTree *tree, char *default_dest) } create_op_win (OP_MOVE, 0); file_mask_defaults (); - move_dir_dir (tree->selected_ptr->name, dest); + move_dir_dir (tree->selected_ptr->name, dest, &count, &bytes); destroy_op_win (); free (dest); }