LINUX.ORG.RU

Просмотр кода

Фича «переименование» реализована в файле tree.c (функция tree_move). Судя по коду, рассчитана на перемещение каталога в другой раздел диска или перезаписи существующего каталога. Поэтому фактически выполняется аналогично копированию: сначала все файлы каталога сканируются, а уж потом он переименовывается.

seyko2
()
Ответ на: комментарий от x905

Условие

По сравнению с 4.7.0 в 4.8.12 добавился параметр конфигурации «Подсчитывать общий размер». Так что первое решение: выключить этот параметр. Но это не очень кузяво. Поэтому второе решение: для случая переименования каталога не выполнять подсчёт общего размера заранее, а перенести его в функцию move_dir_dir.

diff -urN mc-4.8.12.old/src/filemanager/file.c mc-4.8.12/src/filemanager/file.c
--- mc-4.8.12.old/src/filemanager/file.c	2014-06-26 09:23:06.000000000 +0400
+++ mc-4.8.12/src/filemanager/file.c	2014-06-26 09:25:47.000000000 +0400
@@ -2249,7 +2249,7 @@
 /* {{{ Move routines */
 
 FileProgressStatus
-move_dir_dir (FileOpTotalContext * tctx, file_op_context_t * ctx, const char *s, const char *d)
+move_dir_dir (FileOpTotalContext * tctx, file_op_context_t * ctx, const char *s, const char *d, WPanel *panel)
 {
     struct stat sbuf, dbuf;
     FileProgressStatus return_status;
@@ -2260,17 +2260,6 @@
     src_vpath = vfs_path_from_str (s);
     dst_vpath = vfs_path_from_str (d);
 
-    file_progress_show_source (ctx, src_vpath);
-    file_progress_show_target (ctx, dst_vpath);
-
-    if (check_progress_buttons (ctx) == FILE_ABORT)
-    {
-        return_status = FILE_ABORT;
-        goto ret_fast;
-    }
-
-    mc_refresh ();
-
     mc_stat (src_vpath, &sbuf);
 
     dstat_ok = (mc_stat (dst_vpath, &dbuf) == 0);
@@ -2294,6 +2283,45 @@
     }
 
     d = vfs_path_as_str (dst_vpath);
+    if (mc_stat (dst_vpath, &dbuf) == 0)
+	goto init_total;
+
+  retry_rename:
+    if (mc_rename (src_vpath, dst_vpath) == 0)
+    {
+        return_status = FILE_CONT;
+        goto ret;
+    }
+
+    if (errno != EXDEV)
+    {
+        if (!ctx->skip_all)
+        {
+            return_status = files_error (_("Cannot move directory \"%s\" to \"%s\"\n%s"), s, d);
+            if (return_status == FILE_SKIPALL)
+                ctx->skip_all = TRUE;
+            if (return_status == FILE_RETRY)
+                goto retry_rename;
+        }
+        goto ret;
+    }
+
+  init_total:
+    if (panel) {
+	return_status = panel_operate_init_totals (panel, vfs_path_as_str (src_vpath), ctx, FILEGUI_DIALOG_MULTI_ITEM);
+	if (return_status != FILE_CONT)
+    	    goto ret;
+    }
+
+    file_progress_show_source (ctx, src_vpath);
+    file_progress_show_target (ctx, dst_vpath);
+    if (check_progress_buttons (ctx) == FILE_ABORT)
+    {
+        return_status = FILE_ABORT;
+        goto ret_fast;
+    }
+    mc_refresh ();
+
 
     /* Check if the user inputted an existing dir */
   retry_dst_stat:
@@ -2324,25 +2352,6 @@
         goto ret_fast;
     }
 
-  retry_rename:
-    if (mc_rename (src_vpath, dst_vpath) == 0)
-    {
-        return_status = FILE_CONT;
-        goto ret;
-    }
-
-    if (errno != EXDEV)
-    {
-        if (!ctx->skip_all)
-        {
-            return_status = files_error (_("Cannot move directory \"%s\" to \"%s\"\n%s"), s, d);
-            if (return_status == FILE_SKIPALL)
-                ctx->skip_all = TRUE;
-            if (return_status == FILE_RETRY)
-                goto retry_rename;
-        }
-        goto ret;
-    }
     /* Failed because of filesystem boundary -> copy dir instead */
     return_status = copy_dir_dir (tctx, ctx, s, d, FALSE, FALSE, TRUE, NULL);
 
@@ -2790,6 +2799,7 @@
     /* This code is only called by the tree and panel code */
     if (single_entry)
     {
+	FileProgressStatus res;
         /* We now have ETA in all cases */
 
         /* One file: FIXME mc_chdir will take user out of any vfs */
@@ -2815,8 +2825,12 @@
         else
             source_with_vpath = vfs_path_append_new (panel->cwd_vpath, source, (char *) NULL);
 #endif /* WITH_FULL_PATHS */
-        if (panel_operate_init_totals (panel, vfs_path_as_str (source_with_vpath), ctx, dialog_type)
-            == FILE_CONT)
+
+	res = FILE_CONT;
+        if (operation != OP_MOVE || !S_ISDIR (src_stat.st_mode))
+    	    res = panel_operate_init_totals (panel, vfs_path_as_str (source_with_vpath), ctx, dialog_type);
+
+	if (res == FILE_CONT)
         {
             if (operation == OP_DELETE)
             {
@@ -2869,7 +2883,7 @@
                     case OP_MOVE:
                         if (S_ISDIR (src_stat.st_mode))
                             value =
-                                move_dir_dir (tctx, ctx, vfs_path_as_str (source_with_vpath), dest);
+                                move_dir_dir (tctx, ctx, vfs_path_as_str (source_with_vpath), dest, panel);
                         else
                             value =
                                 move_file_file (tctx, ctx, vfs_path_as_str (source_with_vpath),
@@ -2982,7 +2996,7 @@
 
                         case OP_MOVE:
                             if (S_ISDIR (src_stat.st_mode))
-                                value = move_dir_dir (tctx, ctx, source_with_path_str, temp);
+                                value = move_dir_dir (tctx, ctx, source_with_path_str, temp, NULL);
                             else
                                 value = move_file_file (tctx, ctx, source_with_path_str, temp);
                             break;
diff -urN mc-4.8.12.old/src/filemanager/file.h mc-4.8.12/src/filemanager/file.h
--- mc-4.8.12.old/src/filemanager/file.h	2014-06-26 09:23:06.000000000 +0400
+++ mc-4.8.12/src/filemanager/file.h	2014-06-26 09:22:21.000000000 +0400
@@ -11,6 +11,7 @@
 #include "lib/widget.h"
 
 #include "fileopctx.h"
+#include "panel.h"		/* WPanel */
 
 /*** typedefs(not structures) and defined constants **********************************************/
 
@@ -37,7 +38,7 @@
 FileProgressStatus copy_file_file (FileOpTotalContext * tctx, file_op_context_t * ctx,
                                    const char *src_path, const char *dst_path);
 FileProgressStatus move_dir_dir (FileOpTotalContext * tctx, file_op_context_t * ctx,
-                                 const char *s, const char *d);
+                                 const char *s, const char *d, WPanel *panel);
 FileProgressStatus copy_dir_dir (FileOpTotalContext * tctx, file_op_context_t * ctx,
                                  const char *s, const char *d,
                                  gboolean toplevel, gboolean move_over, gboolean do_delete,
diff -urN mc-4.8.12.old/src/filemanager/tree.c mc-4.8.12/src/filemanager/tree.c
--- mc-4.8.12.old/src/filemanager/tree.c	2014-06-26 09:23:06.000000000 +0400
+++ mc-4.8.12/src/filemanager/tree.c	2014-06-26 09:22:21.000000000 +0400
@@ -830,7 +830,7 @@
     ctx = file_op_context_new (OP_MOVE);
     tctx = file_op_total_context_new ();
     file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
-    move_dir_dir (tctx, ctx, vfs_path_as_str (tree->selected_ptr->name), dest);
+    move_dir_dir (tctx, ctx, vfs_path_as_str (tree->selected_ptr->name), dest, NULL);
     file_op_total_context_destroy (tctx);
     file_op_context_destroy (ctx);
 

seyko2
()
Ответ на: Условие от seyko2

Поэтому второе решение: для случая переименования каталога не выполнять подсчёт общего размера заранее, а перенести его в функцию move_dir_dir.

Это плохое решение. move_dir_dir ничего ни про какую панель не знает и знать не должна.

akk ★★★★★
()
Ответ на: комментарий от akk

это точно

А ещё она не должна всякими прогресс-барами заниматься и диалоги выдавать. Ибо нормально интерфейс и функциональность должны быть разделены.

Подвариант: разбить move_dir_dir на две части: одна пытается переименовать на месте и возвращает ошибку, другая обслуживает ситуацию, когда первая часть не справляется. move_dir_dir функционирует по-прежнему, а при переименовании каталога использовать две новые составляющие (между ними вызов init_totals)

seyko2
()
Ответ на: комментарий от akk

move_dir_dir

При переименовании группы каталогов (перемещение вверх, напрмер) MC тоже сначала сканирует. Так что нужно и случай для не single-переименования править. Попробую новый патч сочинить...

seyko2
()
Ответ на: комментарий от akk

Переделанный вариант

move_dir_dir оставлена неизменной. Добавлена функция move_dir_dir_in_place. Если она не может переименовать, то вызывается старая move_dir_dir. Перед ёё вызовом выполняется init_totals, если ещё это не сделано. Добавлена обработка множественного переименования.

PS: Не знаю, подходящее или это место для обсуждения патчей. Может есть другое место?

diff -urN mc-4.8.12.old/src/filemanager/file.c mc-4.8.12/src/filemanager/file.c
--- mc-4.8.12.old/src/filemanager/file.c	2014-06-28 13:17:53.000000000 +0400
+++ mc-4.8.12/src/filemanager/file.c	2014-06-28 13:19:32.000000000 +0400
@@ -2248,6 +2248,72 @@
 /* --------------------------------------------------------------------------------------------- */
 /* {{{ Move routines */
 
+/* try to rename directory */
+/* return FILE_RETRY if job is not done (there is a need to copy directory) */
+
+FileProgressStatus move_dir_dir_in_place (FileOpTotalContext * tctx, file_op_context_t * ctx,
+                                 const char *s, const char *d)
+{
+    struct stat sbuf, dbuf;
+    FileProgressStatus return_status;
+    gboolean dstat_ok;
+    vfs_path_t *src_vpath, *dst_vpath;
+
+    src_vpath = vfs_path_from_str (s);
+    dst_vpath = vfs_path_from_str (d);
+
+    mc_stat (src_vpath, &sbuf);
+
+    dstat_ok = (mc_stat (dst_vpath, &dbuf) == 0);
+    if (dstat_ok && sbuf.st_dev == dbuf.st_dev && sbuf.st_ino == dbuf.st_ino)
+    {
+        return_status = warn_same_file (_("\"%s\"\nand\n\"%s\"\nare the same directory"), s, d);
+        goto ret_fast;
+    }
+    
+    if (dstat_ok && ctx->dive_into_subdirs)
+    {
+        vfs_path_t *tmp;
+
+        tmp = dst_vpath;
+        dst_vpath = vfs_path_append_new (dst_vpath, x_basename (s), NULL);
+        vfs_path_free (tmp);
+    }
+
+    if (mc_stat (dst_vpath, &dbuf) == 0)
+    {
+	return_status = FILE_RETRY;
+	goto ret_fast;
+    }
+
+  retry_rename:
+    if (mc_rename (src_vpath, dst_vpath) == 0)
+    {
+        return_status = FILE_CONT;
+        goto ret;
+    }
+
+    if (errno != EXDEV)
+    {
+        if (!ctx->skip_all)
+        {
+            return_status = files_error (_("Cannot move directory \"%s\" to \"%s\"\n%s"), s, d);
+            if (return_status == FILE_SKIPALL)
+                ctx->skip_all = TRUE;
+            if (return_status == FILE_RETRY)
+                goto retry_rename;
+        }
+        goto ret;
+    }
+
+  ret:
+    erase_list = free_linklist (erase_list);
+  ret_fast:
+    vfs_path_free (src_vpath);
+    vfs_path_free (dst_vpath);
+    return return_status;
+}
+
 FileProgressStatus
 move_dir_dir (FileOpTotalContext * tctx, file_op_context_t * ctx, const char *s, const char *d)
 {
@@ -2595,6 +2661,9 @@
 
     gboolean do_bg = FALSE;     /* do background operation? */
 
+    gboolean totals_inited = TRUE;
+    FileProgressStatus res;
+
     static gboolean i18n_flag = FALSE;
     if (!i18n_flag)
     {
@@ -2815,8 +2884,17 @@
         else
             source_with_vpath = vfs_path_append_new (panel->cwd_vpath, source, (char *) NULL);
 #endif /* WITH_FULL_PATHS */
-        if (panel_operate_init_totals (panel, vfs_path_as_str (source_with_vpath), ctx, dialog_type)
-            == FILE_CONT)
+
+        if (operation == OP_MOVE && S_ISDIR (src_stat.st_mode)) {
+    	    /* rename/move a directory */
+    	    /* init_totals will be called if dir can not be renamed in place */
+	    res = FILE_CONT;
+	    totals_inited = FALSE;
+	}
+        else
+    	    res = panel_operate_init_totals (panel, vfs_path_as_str (source_with_vpath), ctx, dialog_type);
+
+	if (res == FILE_CONT)
         {
             if (operation == OP_DELETE)
             {
@@ -2867,9 +2945,18 @@
                         break;
 
                     case OP_MOVE:
-                        if (S_ISDIR (src_stat.st_mode))
-                            value =
-                                move_dir_dir (tctx, ctx, vfs_path_as_str (source_with_vpath), dest);
+                        if (S_ISDIR (src_stat.st_mode)) {
+                            value = move_dir_dir_in_place (tctx, ctx, vfs_path_as_str (source_with_vpath), dest);
+                    	    if (value == FILE_RETRY) {
+                        	res = FILE_CONT;
+                        	if (totals_inited == FALSE) {
+				    totals_inited = TRUE;
+				    res = panel_operate_init_totals (panel, vfs_path_as_str (source_with_vpath), ctx, dialog_type);
+				}
+				if (res == FILE_CONT)
+                            	    value = move_dir_dir (tctx, ctx, vfs_path_as_str (source_with_vpath), dest);
+                            }
+                        }
                         else
                             value =
                                 move_file_file (tctx, ctx, vfs_path_as_str (source_with_vpath),
@@ -2907,7 +2994,15 @@
                 goto clean_up;
         }
 
-        if (panel_operate_init_totals (panel, NULL, ctx, dialog_type) == FILE_CONT)
+        if (operation == OP_MOVE) {
+    	    /* rename/move a directories */
+    	    /* init_totals will be called if dirs can not be renamed in place */
+	    res = FILE_CONT;
+	}
+        else
+    	    res = panel_operate_init_totals (panel, NULL, ctx, dialog_type);
+
+	if (res == FILE_CONT)
         {
             /* Loop for every file, perform the actual copy operation */
             for (i = 0; i < panel->dir.len; i++)
@@ -2981,8 +3076,18 @@
                             break;
 
                         case OP_MOVE:
-                            if (S_ISDIR (src_stat.st_mode))
-                                value = move_dir_dir (tctx, ctx, source_with_path_str, temp);
+                            if (S_ISDIR (src_stat.st_mode)) {
+                                value = move_dir_dir_in_place (tctx, ctx, source_with_path_str, temp);
+                        	if (value == FILE_RETRY) {
+                        	    res = FILE_CONT;
+                        	    if (totals_inited == FALSE) {
+					totals_inited = TRUE;
+					res = panel_operate_init_totals (panel, NULL, ctx, dialog_type);
+                        	    }
+				    if (res == FILE_CONT)
+                            		value = move_dir_dir (tctx, ctx, source_with_path_str, temp);
+                            	}
+                            }
                             else
                                 value = move_file_file (tctx, ctx, source_with_path_str, temp);
                             break;
diff -urN mc-4.8.12.old/src/filemanager/file.h mc-4.8.12/src/filemanager/file.h
--- mc-4.8.12.old/src/filemanager/file.h	2014-06-28 13:17:53.000000000 +0400
+++ mc-4.8.12/src/filemanager/file.h	2014-06-28 13:17:30.000000000 +0400
@@ -36,6 +36,8 @@
 
 FileProgressStatus copy_file_file (FileOpTotalContext * tctx, file_op_context_t * ctx,
                                    const char *src_path, const char *dst_path);
+FileProgressStatus move_dir_dir_in_place (FileOpTotalContext * tctx, file_op_context_t * ctx,
+                                 const char *s, const char *d);
 FileProgressStatus move_dir_dir (FileOpTotalContext * tctx, file_op_context_t * ctx,
                                  const char *s, const char *d);
 FileProgressStatus copy_dir_dir (FileOpTotalContext * tctx, file_op_context_t * ctx,

seyko2
()
Ответ на: Переделанный вариант от seyko2

Поправка

В функции move_dir_dir_in_place кусок кода

+    if (errno != EXDEV)
+    {
+        if (!ctx->skip_all)
+        {
+            return_status = files_error (_("Cannot move directory \"%s\" to \"%s\"\n%s"), s, d);
+            if (return_status == FILE_SKIPALL)
+                ctx->skip_all = TRUE;
+            if (return_status == FILE_RETRY)
+                goto retry_rename;
+        }
+        goto ret;
+    }
надо заменить на
+    if (errno == EXDEV)
+    {
+       return_status = FILE_RETRY;
+       goto ret_fast;
+    }
+
+    if (!ctx->skip_all)
+    {
+       return_status = files_error (_("Cannot move directory \"%s\" to \"%s\"\n%s"), s, d);
+        if (return_status == FILE_RETRY)
+            goto retry_rename;
+        if (return_status == FILE_SKIPALL)
+            ctx->skip_all = TRUE;
+    }

А то не переименовывает (не копирует) при перемещении между устройствами. Пока замечаний больше нет.

seyko2
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.