xaizek / vifm (License: GPLv2+) (since 2018-12-07)
Vifm is a file manager with curses interface, which provides Vi[m]-like environment for managing objects within file systems, extended with some useful ideas from mutt.
Commit 84ae913e97959595e8e32410539e71c0d7bd560f

Fix unlimited growth of directory histories
Directory history is filled with data read from the state before its
size limit is known. For this reason it's allowed to grow unlimited and
diverge from the size limit imposed by the 'history' option. Setting an
option in the configuration to the default value of 15 or not setting it
there at all leaves the directory history size larger than it should be.
Enforce the expected size after processing configuration to avoid the
history growing unbounded.

Fixes the cause of #1075 on GitHub.

Thanks to zoj613.
Author: xaizek
Author date (UTC): 2025-05-23 09:23
Committer name: xaizek
Committer date (UTC): 2025-05-24 14:15
Parent(s): b140805559b623aef411bf2d3e0d9a69789179d6
Signing key: 99DC5E4DB05F6BE2
Tree: 58d8a8d44732f993ed0ec468170f00ab12b7c09e
File Lines added Lines deleted
ChangeLog 3 0
THANKS 1 0
src/instance.c 19 1
src/instance.h 4 0
src/vifm.c 2 1
tests/commands/sessions.c 7 2
tests/misc/vifminfo.c 35 0
tests/test-support/test-utils.c 4 0
File ChangeLog changed (mode: 100644) (index 33e598d30..95a2e7f24)
5 5 Fixed picking trash directory when rooted trash is included in 'trashdir' Fixed picking trash directory when rooted trash is included in 'trashdir'
6 6 and root is writable. Regression in v0.14.2. and root is writable. Regression in v0.14.2.
7 7
8 Fixed unlimited growth of directory histories when 'history' is set to its
9 default value or not set at all in vifmrc. Thanks to zoj613.
10
8 11 0.14.1 to 0.14.2 (2025-05-07) 0.14.1 to 0.14.2 (2025-05-07)
9 12
10 13 Fixed build issue with musl due to use of non-standard LONG_LONG_MAX. Fixed build issue with musl due to use of non-standard LONG_LONG_MAX.
File THANKS changed (mode: 100644) (index 58738abae..58c8917a3)
... ... yanzhang0219
363 363 Yuriy Artemyev (anuvyklack) Yuriy Artemyev (anuvyklack)
364 364 Yusuf Aktepe Yusuf Aktepe
365 365 Zeng (Bekaboo) Zeng (Bekaboo)
366 zoj613
366 367 zpxue zpxue
367 368 Zsolt Udvari (uzsolt) Zsolt Udvari (uzsolt)
368 369 zsugabubus zsugabubus
File src/instance.c changed (mode: 100644) (index 971abd5c6..1e3ef247d)
19 19
20 20 #include "instance.h" #include "instance.h"
21 21
22 #include <assert.h> /* assert() */
23
22 24 #include "cfg/config.h" #include "cfg/config.h"
23 25 #include "engine/abbrevs.h" #include "engine/abbrevs.h"
24 26 #include "engine/autocmds.h" #include "engine/autocmds.h"
 
... ... instance_finish_restart(void)
140 142 } }
141 143 cs_load_pairs(); cs_load_pairs();
142 144
143 cfg_load();
145 instance_load_config();
144 146 plugs_load(curr_stats.plugs, curr_stats.plugins_dirs); plugs_load(curr_stats.plugs, curr_stats.plugins_dirs);
145 147
146 148 vifm_reexec_startup_commands(); vifm_reexec_startup_commands();
 
... ... instance_finish_restart(void)
161 163 update_screen(UT_REDRAW); update_screen(UT_REDRAW);
162 164 } }
163 165
166 void
167 instance_load_config(void)
168 {
169 cfg_load();
170
171 /* Directory history is filled with data read from the state before its size
172 * limit is known. For this reason it's allowed to grow unlimited and
173 * diverge from the size limit imposed by the 'history' option. Setting an
174 * option in the configuration to the default value of 15 or not setting it
175 * there at all leaves the directory history size larger than it should be.
176 * Enforce the expected size here to avoid the history growing unbounded. */
177 opt_t *history_opt = vle_opts_find("history", OPT_GLOBAL);
178 assert(history_opt != NULL && "'history' option must be there.");
179 cfg_resize_histories(history_opt->val.int_val);
180 }
181
164 182 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
165 183 /* vim: set cinoptions+=t0 : */ /* vim: set cinoptions+=t0 : */
File src/instance.h changed (mode: 100644) (index a2316ebae..e235dd5f2)
... ... void instance_start_restart(RestartType type);
32 32 * calls to instance_start_restart() and this function. */ * calls to instance_start_restart() and this function. */
33 33 void instance_finish_restart(void); void instance_finish_restart(void);
34 34
35 /* Loads configuration file taking care of anything that needs to be done before
36 * or after it. */
37 void instance_load_config(void);
38
35 39 #endif /* VIFM__INSTANCE_H__ */ #endif /* VIFM__INSTANCE_H__ */
36 40
37 41 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
File src/vifm.c changed (mode: 100644) (index 77f0d993d..dcf1cf272)
81 81 #include "flist_hist.h" #include "flist_hist.h"
82 82 #include "flist_pos.h" #include "flist_pos.h"
83 83 #include "fops_common.h" #include "fops_common.h"
84 #include "instance.h"
84 85 #include "ipc.h" #include "ipc.h"
85 86 #include "marks.h" #include "marks.h"
86 87 #include "ops.h" #include "ops.h"
 
... ... vifm_main(int argc, char *argv[])
313 314 if(!vifm_args.no_configs) if(!vifm_args.no_configs)
314 315 { {
315 316 load_scheme(); load_scheme();
316 cfg_load();
317 instance_load_config();
317 318 } }
318 319
319 320 if(lwin_cv || rwin_cv) if(lwin_cv || rwin_cv)
File tests/commands/sessions.c changed (mode: 100644) (index 6cdff83a6..7ceceea1d)
... ... SETUP()
41 41 columns_setup_column(SK_BY_NAME); columns_setup_column(SK_BY_NAME);
42 42 columns_setup_column(SK_BY_SIZE); columns_setup_column(SK_BY_SIZE);
43 43
44 /* Test a realistic configuration. */
45 cfg_init();
46 histories_init(cfg.history_len);
47
44 48 cmds_init(); cmds_init();
45 49 opt_handlers_setup(); opt_handlers_setup();
46 50 } }
 
... ... TEARDOWN()
53 57 cfg.session_options = 0; cfg.session_options = 0;
54 58
55 59 opt_handlers_teardown(); opt_handlers_teardown();
60 conf_teardown();
56 61 vle_keys_reset(); vle_keys_reset();
57 62
63 histories_init(0);
64
58 65 view_teardown(&lwin); view_teardown(&lwin);
59 66 view_teardown(&rwin); view_teardown(&rwin);
60 67
 
... ... TEST(can_load_a_session)
166 173 remove_file(SANDBOX_PATH "/sessions/sess.json"); remove_file(SANDBOX_PATH "/sessions/sess.json");
167 174 remove_dir(SANDBOX_PATH "/sessions"); remove_dir(SANDBOX_PATH "/sessions");
168 175 remove_file(SANDBOX_PATH "/vifminfo.json"); remove_file(SANDBOX_PATH "/vifminfo.json");
169
170 histories_init(0);
171 176 } }
172 177
173 178 TEST(can_delete_a_session) TEST(can_delete_a_session)
File tests/misc/vifminfo.c changed (mode: 100644) (index d5a2b51ae..bd9d8987e)
11 11 #include "../../src/cfg/config.h" #include "../../src/cfg/config.h"
12 12 #include "../../src/cfg/info.h" #include "../../src/cfg/info.h"
13 13 #include "../../src/cfg/info_chars.h" #include "../../src/cfg/info_chars.h"
14 #include "../../src/engine/keys.h"
14 15 #include "../../src/ui/column_view.h" #include "../../src/ui/column_view.h"
15 16 #include "../../src/ui/ui.h" #include "../../src/ui/ui.h"
16 17 #include "../../src/utils/matcher.h" #include "../../src/utils/matcher.h"
 
20 21 #include "../../src/cmd_core.h" #include "../../src/cmd_core.h"
21 22 #include "../../src/filetype.h" #include "../../src/filetype.h"
22 23 #include "../../src/flist_hist.h" #include "../../src/flist_hist.h"
24 #include "../../src/instance.h"
23 25 #include "../../src/opt_handlers.h" #include "../../src/opt_handlers.h"
24 26 #include "../../src/status.h" #include "../../src/status.h"
25 27
 
... ... SETUP()
42 44 view_setup(&lwin); view_setup(&lwin);
43 45 view_setup(&rwin); view_setup(&rwin);
44 46 curr_view = &lwin; curr_view = &lwin;
47 other_view = &rwin;
45 48
46 49 cfg_resize_histories(10); cfg_resize_histories(10);
47 50
 
... ... SETUP()
50 53
51 54 TEARDOWN() TEARDOWN()
52 55 { {
56 curr_view = NULL;
57 other_view = NULL;
58
53 59 cfg_resize_histories(0); cfg_resize_histories(0);
54 60
55 61 view_teardown(&lwin); view_teardown(&lwin);
 
... ... TEST(dhistory_is_merged_correctly)
470 476 assert_success(remove(SANDBOX_PATH "/vifminfo.json")); assert_success(remove(SANDBOX_PATH "/vifminfo.json"));
471 477 } }
472 478
479 TEST(size_of_dhistory_is_limited)
480 {
481 cfg.vifm_info = VINFO_DHISTORY;
482
483 /* Short history to fill it easily. */
484 cfg.history_len = 2;
485 opt_handlers_setup();
486 cmds_init();
487
488 /* Adding 3 items to make sure the limit is in effect. */
489 flist_hist_setup(&lwin, "/dir1", "file1", 1, 1);
490 flist_hist_setup(&lwin, "/dir2", "file2", 2, 2);
491 flist_hist_setup(&lwin, "/dir3", "file3", 3, 3);
492 assert_int_equal(2, lwin.history_num);
493
494 /* Write the history to a file. */
495 state_store();
496 /* Reload the state and config (which should be empty in tests). */
497 instance_start_restart(RT_MOST);
498 state_load(0);
499 instance_finish_restart();
500 /* Verify that history was trimmed to the set limit. */
501 assert_int_equal(2, lwin.history_num);
502
503 opt_handlers_teardown();
504 vle_cmds_reset();
505 vle_keys_reset();
506 }
507
473 508 TEST(things_missing_from_vifminfo_option_are_dropped) TEST(things_missing_from_vifminfo_option_are_dropped)
474 509 { {
475 510 cfg.vifm_info = VINFO_CS; cfg.vifm_info = VINFO_CS;
File tests/test-support/test-utils.c changed (mode: 100644) (index 0ebbc7dae..08d0cf3b3)
... ... conf_teardown(void)
160 160 update_string(&cfg.shell, NULL); update_string(&cfg.shell, NULL);
161 161 update_string(&cfg.shell_cmd_flag, NULL); update_string(&cfg.shell_cmd_flag, NULL);
162 162
163 /* Non-zero history size has implications for views and status, so reset
164 * it. */
165 cfg.history_len = 0;
166
163 167 cfg.dot_dirs = 0; cfg.dot_dirs = 0;
164 168
165 169 cfg.sizefmt.base = 0; cfg.sizefmt.base = 0;
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vifm

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vifm

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master