From 7fbdb8780505fc1672d35272a36c3d9e983880ec Mon Sep 17 00:00:00 2001 From: Slava Zanko Date: Tue, 20 Sep 2011 11:41:27 +0300 Subject: [PATCH 1/4] Ticket #2610: Use posix_fallocate() when copying files/moving to a new mount point Added m4 function for check if posix_fallocate() is present. Signed-off-by: Slava Zanko --- m4.include/ac-get-fs-info.m4 | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/m4.include/ac-get-fs-info.m4 b/m4.include/ac-get-fs-info.m4 index b1a65132d..5256f623b 100644 --- a/m4.include/ac-get-fs-info.m4 +++ b/m4.include/ac-get-fs-info.m4 @@ -635,6 +635,27 @@ AC_DEFUN([gl_FSTYPENAME], ]) ]) +dnl +dnl posix_allocate() function detection +dnl + +AC_DEFUN([gl_POSIX_FALLOCATE], [ + dnl * Old glibcs have broken posix_fallocate(). Make sure not to use it. + AC_TRY_COMPILE([ + #define _XOPEN_SOURCE 600 + #include + #if defined(__GLIBC__) && (__GLIBC__ < 2 || __GLIBC_MINOR__ < 7) + possibly broken posix_fallocate + #endif + ], + [posix_fallocate(0, 0, 0);], + [AC_DEFINE( + [HAVE_POSIX_FALLOCATE], + [1], + [Define if you have a working posix_fallocate()]) + ]) +]) + dnl dnl Filesystem information detection dnl @@ -651,4 +672,5 @@ AC_DEFUN([AC_GET_FS_INFO], [ gl_FSUSAGE gl_FSTYPENAME + gl_POSIX_FALLOCATE ]) From 323fedecd73055f3af5395559af132d30b0dbcaf Mon Sep 17 00:00:00 2001 From: Slava Zanko Date: Tue, 20 Sep 2011 12:40:14 +0300 Subject: [PATCH 2/4] Added implementation for files space preallocation Signed-off-by: Slava Zanko --- lib/vfs/vfs.c | 39 +++++++++++++++++++++++++++++++++++++++ lib/vfs/vfs.h | 2 ++ src/filemanager/file.c | 21 +++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/lib/vfs/vfs.c b/lib/vfs/vfs.c index 14a50b75d..39025926a 100644 --- a/lib/vfs/vfs.c +++ b/lib/vfs/vfs.c @@ -594,3 +594,42 @@ vfs_change_encoding (vfs_path_t * vpath, const char *encoding) } /* --------------------------------------------------------------------------------------------- */ + +/** + * Preallocate space for file in new place for ensure that file + * will be fully copied with less fragmentation. + * + * @param dest_desc mc VFS file handler + * @param src_fsize source file size + * @param dest_fsize destination file size (if destination exists, otherwise should be 0) + * + * @return 0 if success and non-zero otherwise. + * Note: function doesn't touch errno global variable. + */ +int +vfs_preallocate (int dest_vfs_fd, off_t src_fsize, off_t dest_fsize) +{ +#ifndef HAVE_POSIX_FALLOCATE + (void) dest_desc; + (void) src_fsize; + (void) dest_fsize; + return 0; + +#else /* HAVE_POSIX_FALLOCATE */ + int *dest_fd; + struct vfs_class *dest_class; + + dest_class = vfs_class_find_by_handle (dest_vfs_fd); + if ((dest_class->flags & VFSF_LOCAL) == 0) + return 0; + + dest_fd = (int *) vfs_class_data_find_by_handle (dest_vfs_fd); + if (dest_fd == NULL) + return 0; + + return posix_fallocate (*dest_fd, dest_fsize, src_fsize - dest_fsize); + +#endif /* HAVE_POSIX_FALLOCATE */ +} + +/* --------------------------------------------------------------------------------------------- */ diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h index 5319711f9..e4892b39d 100644 --- a/lib/vfs/vfs.h +++ b/lib/vfs/vfs.h @@ -268,6 +268,8 @@ char *_vfs_get_cwd (void); vfs_path_t *vfs_change_encoding (vfs_path_t * vpath, const char *encoding); +int vfs_preallocate (int dest_desc, off_t src_fsize, off_t dest_fsize); + /** * Interface functions described in interface.c */ diff --git a/src/filemanager/file.c b/src/filemanager/file.c index c42970d33..dc21ae857 100644 --- a/src/filemanager/file.c +++ b/src/filemanager/file.c @@ -1504,6 +1504,27 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx, ctx->skip_all = TRUE; goto ret; } + while (TRUE) + { + errno = vfs_preallocate (dest_desc, file_size, (ctx->do_append != 0) ? sb.st_size : 0); + if (errno == 0) + break; + + if (!ctx->skip_all) + { + return_status = + file_error (_("Cannot preallocate space for target file \"%s\"\n%s"), dst_path); + if (return_status == FILE_RETRY) + continue; + if (return_status == FILE_SKIPALL) + ctx->skip_all = TRUE; + } + mc_close (dest_desc); + dest_desc = -1; + mc_unlink (dst_path); + dst_status = DEST_NONE; + goto ret; + } ctx->eta_secs = 0.0; ctx->bps = 0; From 41af257135b103f31a3415c775421d9e907bf782 Mon Sep 17 00:00:00 2001 From: Slava Zanko Date: Tue, 20 Sep 2011 13:27:04 +0300 Subject: [PATCH 3/4] Added configuration option 'preallocate_space' for toggle space preallocating behaviour. Signed-off-by: Slava Zanko --- lib/global.c | 3 ++- lib/global.h | 4 +++ lib/vfs/vfs.c | 3 +++ src/filemanager/option.c | 55 +++++++++++++++++++++------------------- src/setup.c | 1 + 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/lib/global.c b/lib/global.c index dadbf390e..60c39f3cd 100644 --- a/lib/global.c +++ b/lib/global.c @@ -107,7 +107,8 @@ mc_global_t mc_global = { .vfs = { - .cd_symlinks = TRUE + .cd_symlinks = TRUE, + .preallocate_space = FALSE, } }; diff --git a/lib/global.h b/lib/global.h index 841a89ae1..a5f20b1ef 100644 --- a/lib/global.h +++ b/lib/global.h @@ -269,6 +269,10 @@ typedef struct { /* Set when cd symlink following is desirable (bash mode) */ gboolean cd_symlinks; + + /* Preallocate space before file copying */ + gboolean preallocate_space; + } vfs; } mc_global_t; diff --git a/lib/vfs/vfs.c b/lib/vfs/vfs.c index 39025926a..a0fb568c9 100644 --- a/lib/vfs/vfs.c +++ b/lib/vfs/vfs.c @@ -619,6 +619,9 @@ vfs_preallocate (int dest_vfs_fd, off_t src_fsize, off_t dest_fsize) int *dest_fd; struct vfs_class *dest_class; + if (!mc_global.vfs.preallocate_space) + return 0; + dest_class = vfs_class_find_by_handle (dest_vfs_fd); if ((dest_class->flags & VFSF_LOCAL) == 0) return 0; diff --git a/src/filemanager/option.c b/src/filemanager/option.c index fb5c594ab..7e754999c 100644 --- a/src/filemanager/option.c +++ b/src/filemanager/option.c @@ -76,7 +76,7 @@ configure_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void { case DLG_ACTION: /* message from "Single press" checkbutton */ - if (sender != NULL && sender->id == 17) + if (sender != NULL && sender->id == 18) { const gboolean not_single = !(((WCheck *) sender)->state & C_BOOL); Widget *w; @@ -125,8 +125,11 @@ configure_box (void) QUICK_BUTTON (38, dlg_width, dlg_height - 3, dlg_height, N_("&Cancel"), B_CANCEL, NULL), QUICK_BUTTON (14, dlg_width, dlg_height - 3, dlg_height, N_("&OK"), B_ENTER, NULL), /* other options */ - QUICK_CHECKBOX (dlg_width / 2 + 2, dlg_width, 12, dlg_height, N_("A&uto save setup"), + QUICK_CHECKBOX (dlg_width / 2 + 2, dlg_width, 13, dlg_height, N_("A&uto save setup"), &auto_save_setup), + QUICK_CHECKBOX (dlg_width / 2 + 2, dlg_width, 12, dlg_height, + N_("Preallocate &space before file copying"), + &mc_global.vfs.preallocate_space), QUICK_CHECKBOX (dlg_width / 2 + 2, dlg_width, 11, dlg_height, N_("Sa&fe delete"), &safe_delete), QUICK_CHECKBOX (dlg_width / 2 + 2, dlg_width, 10, dlg_height, N_("Cd follows lin&ks"), @@ -191,14 +194,14 @@ configure_box (void) /* buttons */ quick_widgets[i].u.button.text = _(quick_widgets[i].u.button.text); break; - case 12: - case 14: - case 18: - case 23: + case 13: + case 15: + case 19: + case 24: /* groupboxes */ quick_widgets[i].u.groupbox.title = _(quick_widgets[i].u.groupbox.title); break; - case 13: + case 14: { /* radio button */ size_t j; @@ -206,10 +209,10 @@ configure_box (void) pause_options[j] = _(pause_options[j]); } break; - case 15: + case 16: /* input line */ break; - case 16: + case 17: /* label */ quick_widgets[i].u.label.text = _(quick_widgets[i].u.label.text); break; @@ -232,20 +235,20 @@ configure_box (void) /* checkboxes within groupboxes */ c_len = 0; - for (i = 2; i < 23; i++) - if ((i < 12) || (i == 17) || (i > 18)) + for (i = 2; i < 24; i++) + if ((i < 13) || (i == 18) || (i > 19)) c_len = max (c_len, str_term_width1 (quick_widgets[i].u.checkbox.text) + 3); /* radiobuttons */ for (i = 0; i < (size_t) pause_options_num; i++) c_len = max (c_len, str_term_width1 (pause_options[i]) + 3); /* label + input */ - l_len = str_term_width1 (quick_widgets[16].u.label.text); + l_len = str_term_width1 (quick_widgets[17].u.label.text); c_len = max (c_len, l_len + 1 + 8); /* groupboxes */ - g_len = max (c_len + 2, str_term_width1 (quick_widgets[23].u.groupbox.title) + 4); - g_len = max (g_len, str_term_width1 (quick_widgets[18].u.groupbox.title) + 4); - g_len = max (g_len, str_term_width1 (quick_widgets[14].u.groupbox.title) + 4); - g_len = max (g_len, str_term_width1 (quick_widgets[12].u.groupbox.title) + 4); + g_len = max (c_len + 2, str_term_width1 (quick_widgets[24].u.groupbox.title) + 4); + g_len = max (g_len, str_term_width1 (quick_widgets[19].u.groupbox.title) + 4); + g_len = max (g_len, str_term_width1 (quick_widgets[15].u.groupbox.title) + 4); + g_len = max (g_len, str_term_width1 (quick_widgets[13].u.groupbox.title) + 4); /* dialog width */ Quick_input.xlen = max (dlg_width, g_len * 2 + 9); Quick_input.xlen = max (Quick_input.xlen, b_len + 2); @@ -257,19 +260,19 @@ configure_box (void) quick_widgets[i].x_divisions = Quick_input.xlen; /* groupboxes */ - quick_widgets[14].u.groupbox.width = - quick_widgets[18].u.groupbox.width = - quick_widgets[23].u.groupbox.width = Quick_input.xlen / 2 - 4; - quick_widgets[12].u.groupbox.width = Quick_input.xlen / 2 - 3; + quick_widgets[15].u.groupbox.width = + quick_widgets[19].u.groupbox.width = + quick_widgets[24].u.groupbox.width = Quick_input.xlen / 2 - 4; + quick_widgets[13].u.groupbox.width = Quick_input.xlen / 2 - 3; /* input */ - quick_widgets[15].relative_x = quick_widgets[16].relative_x + l_len + 1; - quick_widgets[15].u.input.len = quick_widgets[18].u.groupbox.width - l_len - 4; + quick_widgets[16].relative_x = quick_widgets[17].relative_x + l_len + 1; + quick_widgets[16].u.input.len = quick_widgets[19].u.groupbox.width - l_len - 4; /* right column */ - quick_widgets[12].relative_x = Quick_input.xlen / 2; - for (i = 2; i < 12; i++) - quick_widgets[i].relative_x = quick_widgets[12].relative_x + 2; + quick_widgets[13].relative_x = Quick_input.xlen / 2; + for (i = 2; i < 13; i++) + quick_widgets[i].relative_x = quick_widgets[13].relative_x + 2; /* buttons */ quick_widgets[1].relative_x = (Quick_input.xlen - b_len) / 3; @@ -278,7 +281,7 @@ configure_box (void) g_snprintf (time_out, sizeof (time_out), "%d", old_esc_mode_timeout); if (!old_esc_mode) - quick_widgets[15].options = quick_widgets[16].options = W_DISABLED; + quick_widgets[16].options = quick_widgets[17].options = W_DISABLED; if (quick_dialog (&Quick_input) == B_ENTER) old_esc_mode_timeout = atoi (time_out_new); diff --git a/src/setup.c b/src/setup.c index 9069aebe9..7ce9fb348 100644 --- a/src/setup.c +++ b/src/setup.c @@ -238,6 +238,7 @@ static const struct { "pause_after_run", &pause_after_run }, { "shell_patterns", &easy_patterns }, { "auto_save_setup", &auto_save_setup }, + { "preallocate_space", &mc_global.vfs.preallocate_space }, { "auto_menu", &auto_menu }, { "use_internal_view", &use_internal_view }, { "use_internal_edit", &use_internal_edit }, From 9a7d02f4b4a3661feadd9aa6216bd68345d66b5e Mon Sep 17 00:00:00 2001 From: Slava Zanko Date: Tue, 20 Sep 2011 13:57:57 +0300 Subject: [PATCH 4/4] Documentation updated for describe preallocate feature Signed-off-by: Slava Zanko --- doc/man/es/mc.1.in | 4 +++- doc/man/hu/mc.1.in | 4 +++- doc/man/it/mc.1.in | 4 +++- doc/man/mc.1.in | 13 +++++++------ doc/man/pl/mc.1.in | 2 ++ doc/man/ru/mc.1.in | 5 ++++- doc/man/sr/mc.1.in | 4 +++- 7 files changed, 25 insertions(+), 11 deletions(-) diff --git a/doc/man/es/mc.1.in b/doc/man/es/mc.1.in index 07976982e..464f9aa6e 100644 --- a/doc/man/es/mc.1.in +++ b/doc/man/es/mc.1.in @@ -980,7 +980,9 @@ está activada. Sobreimpresiona una ventana de entrada con destino por defecto al directorio del panel no seleccionado y copia el archivo actualmente seleccionado (o los archivos marcados, si hay al menos uno marcado) al directorio especificado -por el usuario en la ventana. Durante este proceso, podemos pulsar +por el usuario en la ventana. Space for destination file may be preallocated +relative to preallocate_space configure option. Durante este proceso, podemos +pulsar .IR Ctrl\-c " o " Esc para anular la operación. Para más detalles sobre la máscara de origen (que será normalmente * o ^\\(.*\\)$ dependiendo diff --git a/doc/man/hu/mc.1.in b/doc/man/hu/mc.1.in index 0c8f5fbac..f6f64c824 100644 --- a/doc/man/hu/mc.1.in +++ b/doc/man/hu/mc.1.in @@ -914,7 +914,9 @@ ha a belső szerkesztő be van kapcsolva. Egy beviteli ablakot jelenít meg, amely alapértelmezésben a nem kiválasztott panel könyvtárát adja meg rendeltetési helyként, majd átmásolja a kiválasztott fájlt (vagy kijelölt fájlokat, ha egynél több -fájlról van szó) a beviteli ablakban megadott könyvtárba. A folyamat +fájlról van szó) a beviteli ablakban megadott könyvtárba. Space for +destination file may be preallocated relative to preallocate_space +configure option. A folyamat futását a C\-c, vagy ESC lenyomásával szakíthatod meg. A forrás maszk beállításairól (ami általában a *, vagy a ^\\(.*\\)$ közül valamelyik. Ezekről a "Shell kifejezések" beállításnál, illetve a diff --git a/doc/man/it/mc.1.in b/doc/man/it/mc.1.in index a9c81e4ce..480017606 100644 --- a/doc/man/it/mc.1.in +++ b/doc/man/it/mc.1.in @@ -938,7 +938,9 @@ se l'opzione, "usa editor interno" è stata impostata. Mostra una finestra di dialogo con destinazione predefinita alla directory del pannello non selezionato, che copia il file selezionato (o i file marcati, se ce n'è almeno uno) sulla directory specificata -dall'utente nella finestra di dialogo. Durante il processo è possibile +dall'utente nella finestra di dialogo. Space for destination +file may be preallocated relative to preallocate_space configure option. +Durante il processo è possibile premere C\-c o ESC per abortire l'operazione. Per maggiori dettagli sulla maschera sorgente (che sarà normalmente * o ^\\(.*\\)$ a seconda dell'impostazione di "modelli della shell") o sui caratteri jolly sulla diff --git a/doc/man/mc.1.in b/doc/man/mc.1.in index 85e00bd6c..a23ff9060 100644 --- a/doc/man/mc.1.in +++ b/doc/man/mc.1.in @@ -1063,12 +1063,13 @@ if the use_internal_edit option is on. .PP Press F5 to pop up an input dialog to copy the currently selected file (or the tagged files, if there is at least one file tagged) to the -directory/filename you specify in the input dialog. The destination -defaults to the directory in the non\-selected panel. During this -process, you can press C\-c or ESC to abort the operation. For details -about source mask (which will be usually either * or ^\\(.*\\)$ depending -on setting of Use shell patterns) and possible wildcards in the destination -see +directory/filename you specify in the input dialog. The destination +defaults to the directory in the non\-selected panel. Space for destination +file may be preallocated relative to preallocate_space configure option. +During this process, you can press C\-c or ESC to abort the operation. +For details about source mask (which will be usually either * or ^\\(.*\\)$ +depending on setting of Use shell patterns) and possible wildcards in the +destination see .\"LINK2" Mask copy/rename\&. .\"Mask Copy/Rename" diff --git a/doc/man/pl/mc.1.in b/doc/man/pl/mc.1.in index 5e7a382ef..b58ff9de0 100644 --- a/doc/man/pl/mc.1.in +++ b/doc/man/pl/mc.1.in @@ -776,6 +776,8 @@ Włącza okno dialogowe, w którym standardowo znajduje się ścieżka do katalogu w nieaktywnym panelu, po czym kopiuje aktualny plik (lub wybrane jeśli wybrano jakiekolwiek) do katalogu, który wybraliśmy w oknie dialogowym. +Space for destination file may be preallocated relative to preallocate_space +configure option. Podczas procesu kopiowania możesz go w każdej chwili przerwać wciskając C\-c lub Esc. Żeby dowiedzieć się czegoś więcej na temat jokerów w ścieżce źródłowej (którymi najczęściej będą * lub ^\\(.*\\)$) i innych możliwych określeń w diff --git a/doc/man/ru/mc.1.in b/doc/man/ru/mc.1.in index 2df666f82..b61bb44bf 100644 --- a/doc/man/ru/mc.1.in +++ b/doc/man/ru/mc.1.in @@ -1055,7 +1055,10 @@ F13, встроенная программа просмотра не выпол подсвеченный файл из каталога, отображаемого в активной панели (или группу отмеченных файлов, если в активной панели отмечен хотя бы один файл) в каталог, отображаемый в пассивной панели. Имя каталога, в -который будет производиться копирование, можно изменить. О том, как +который будет производиться копирование, можно изменить. Можно +предварительно резервировать место под новые файлы в каталоге назначения, +выставив конфигурационную опцию preallocate_space. +О том, как задать шаблон для имен копируемых файлов (обычно это * или ^\\(.*\\)$, в зависимости от установки опции .I Образцы в стиле shell (Shell Patterns), diff --git a/doc/man/sr/mc.1.in b/doc/man/sr/mc.1.in index 16730c517..29ff4090b 100644 --- a/doc/man/sr/mc.1.in +++ b/doc/man/sr/mc.1.in @@ -904,7 +904,9 @@ half name | size:7 | type mode:3 Приказује дијалог за унос са одредиштем које је подразумевано директоријум у неизабраном окну и копира тренутно изабрану датотеку (или означене датотеке, ако је бар једна означена) у директоријум који -је корисник задао у дијалогу за унос. Током овог процеса можете +је корисник задао у дијалогу за унос. Space for destination +file may be preallocated relative to preallocate_space configure option. +Током овог процеса можете притиснути пречицу C\-c или тастер ESC да бисте прекинули операцију. За детаље о изворној масци (која је обично * или ^\\(.*\\)$, у зависности од постављања избора `Користи обрасце љуске') и могућим џокерским