summaryrefslogtreecommitdiff
path: root/src/file.cc
AgeCommit message (Collapse)Author
2025-07-08Replace on_scope_end with CTAD with OnScopeEnd directlyMaxime Coste
2025-02-19Move command/filename completion logic to completion.ccMaxime Coste
Refactor list_files to use a callback instead of returning a vector, file.cc/hh should not know about completion logic.
2025-02-19Cleanup file.cc/hh dependenciesMaxime Coste
file.cc/hh should not know about Context, Buffer, etc... It should be a pretty low level set of helper functions. Move buffer related functions to buffer_utils and extract busy indicators to callers.
2024-12-09Print elapsed time when blocked on opening file for writingJohannes Altmanninger
Extract the logic for "waiting for shell to finish" and reuse it for potentially blocking calls to open() that use the O_WRONLY flags.
2024-12-09Allow cancelling "write fifo" with <c-g>Johannes Altmanninger
Just like "echo -to-file fifo".
2024-11-22Take a timeout argument in EventManager::handle_next_eventsMaxime Coste
When provided, this gives the maximal time to wait before exiting handle_next_events. If not given handle_next_events will block, this provides a more flexible approach than the previous "block" boolean. Use this to wait for a millisecond between each try to open a fifo for writing. Fixes the 100% cpu usage discussed in github on commit e74a3ac6a3bad1b74af71aa0bfdacb41ffcb7355
2024-11-16Run urgent event loop when blocking on opening a file for writingMaxime Coste
This makes <c-g> cancel the writing operation if we block on trying to open a fifo with no reader. Fixes #5256
2024-08-16include headers cleanupAdriĆ  Arrufat
2024-05-12Handle binary path detection errors on non-/proc platformsChris Webb
On FreeBSD and NetBSD, sysctl() can return -1 when the path is too long, leaving the buffer unitialised. On macOS, both _NSGetExecutablePath() and realpath() can fail with pathological paths or if memory is exhausted. On Haiku, the kak_assert(status == B_OK) check will be compiled out in non-debug builds. Detect all of these cases and error out, reshaping get_kak_binary_path() to avoid multiple repetitions of the same fatal error message.
2024-05-12Fix error handling when reading binary path from /procChris Webb
On Linux, Hurd, Cygwin, DragonFly BSD and Solaris/Illumos, Kakoune obtains a path to its binary by reading the appropriate /proc symlink target. readlink() can fail or it can fill the entire buffer, silently truncating the path if the buffer is too small. kak_assert() is compiled out in non-debug builds so we ignore a readlink() failure, corrupt the stack by writing to buffer[-1] then return a string from the uninitialised buffer. If readlink() succeeds and the binary path is sizeof(buffer) long, we write a \0 terminator beyond its end. If it is longer, we also truncate the path. Throw a fatal error on startup in all these unlikely failure cases.
2024-05-12Fix tests for OpenBSDMaxime Coste
Using the diff provided by @krobelus on #5173 Close #5173
2024-02-28Fix shell command completion fallback to filenameMaxime Coste
2024-02-06Use different hash algorithms for strings and file hashingMaxime Coste
For hash map, using fnv1a is faster as it is a much simpler algorithm we can afford to inline. For files murmur3 should win as it processes bytes 4 by 4.
2023-11-28Set replacement file permissions before moving into placeChris Webb
When doing :write -method replace, make sure we've set the correct mode, uid and gid on the replacement file before attempting to rename it on top of the original. This means that the original file is left in place with correct permissions if anything fails, rather than ending up with 0700 permissions from mkstemp().
2023-11-26Restore file ownership when editing with root privilegeChris Webb
When a privileged :write is used with -method replace, it silently resets the ownership of files to root:root. Restore the original owner and group in the same way we restore the original permissions. Ownership needs to be restored before permissions to avoid setuid and setgid bits being set while the file is still owned by root, and to avoid them being subsequently lost again on chmod(2).
2023-11-26Fix crash when ':write -method replace' fails to create tempfileChris Webb
If a user attempts to save a file without write permission for the containing directory, with writemethod set as 'replace' or an explicit ':write -method replace' command, kak crashes with "terminating due to uncaught exception of type Kakoune:runtime_error". (Note this doesn't happen with a forced write, which fails earlier when it tries to enable u+w permission.) Don't raise another exception when already bailing out with a runtime error for failing to create a temporary file or open the existing file. Instead, make a best-efforts attempt to restore the file permissions before raising the first exception, and only report the runtime chmod exception if that step fails on the non-error path.
2023-04-24Fix crash after multiple terminal resizesJohannes Altmanninger
When Kakoune's terminal is shown on my laptop monitor and I plug in my external monitor, the terminal's workspace will move to that external monitor. When this happens, Kakoune may segfault. There are multiple resize events (SIGWINCH) in quick succession; it crashes because we handle SIGWINCH during rendering. The problem happens during execution of "TerminalUI::Screen::output" (frame #18). When we receive SIGWINCH while writing to stdout, write(2) fails with EAGAIN, prompting us to handle pending events (See ae001a1f9 (Run EventManager whenever writing to a file descriptor would block, 2022-05-10)). We update the screen size in check_resize() here: #4 Kakoune::TerminalUI::check_resize (force=<optimized out>) at terminal_ui.cc:683 #5 Kakoune::TerminalUI::get_next_key () at terminal_ui.cc:719 #6 operator() (__closure=0x555555984198) at terminal_ui.cc:484 #7 std::__invoke_impl<void, Kakoune::TerminalUI::TerminalUI()::<lambda(Kakoune::FDWatcher&, Kakoune::FdEvents, Kakoune::EventMode)>&, Kakoune::FDWatcher&, Kakoune::FdEvents, Kakoune::EventMode> (__f=...) at /usr/include/c++/12.2.1/bits/invoke.h:61 #8 std::__invoke_r<void, Kakoune::TerminalUI::TerminalUI()::<lambda(Kakoune::FDWatcher&, Kakoune::FdEvents, Kakoune::EventMode)>&, Kakoune::FDWatcher&, Kakoune::FdEvents, Kakoune::EventMode> (__fn=...) at /usr/include/c++/12.2.1/bits/invoke.h:111 #9 std::_Function_handler<void(Kakoune::FDWatcher&, Kakoune::FdEvents, Kakoune::EventMode), Kakoune::TerminalUI::TerminalUI()::<lambda(Kakoune::FDWatcher&, Kakoune::FdEvents, Kakoune::EventMode)> >::_M_invoke(const std::_Any_data &, Kakoune::FDWatcher &, Kakoune::FdEvents &&, Kakoune::EventMode &&) (__functor=..., __args#0=..., __args#1=<optimized out>, __args#2=<optimized out>) at /usr/include/c++/12.2.1/bits/std_function.h:290 #10 std::function<void (Kakoune::FDWatcher&, Kakoune::FdEvents, Kakoune::EventMode)>::operator()(Kakoune::FDWatcher&, Kakoune::FdEvents, Kakoune::EventMode) const (__args#2=<optimized out>, __args#1=<optimized out>, __args#0=...) at /usr/include/c++/12.2.1/bits/std_function.h:591 #11 Kakoune::FDWatcher::run (mode=Kakoune::EventMode::Urgent, events=<optimized out>) at event_manager.cc:28 #12 Kakoune::EventManager::handle_next_events (mode=mode@entry=Kakoune::EventMode::Urgent, sigmask=sigmask@entry=0x0, block=<optimized out>, block@entry=false) at event_manager.cc:143 #13 Kakoune::write (fd=1, data=...) at file.cc:273 #14 Kakoune::BufferedWriter<4096>::flush () at string.hh:236 #15 Kakoune::BufferedWriter<4096>::write (data="t file.hh:145 #16 Kakoune::TerminalUI::Screen::set_face (face=..., writer=...) at terminal_ui.cc:255 #17 operator() (line=..., __closure=<synthetic pointer>) at terminal_ui.cc:326 #18 Kakoune::TerminalUI::Screen::output (force=force@entry=true, synchronized=<optimized out>, writer=...) at terminal_ui.cc:402 #19 Kakoune::TerminalUI::redraw (force=force@entry=true) at terminal_ui.cc:571 #20 Kakoune::TerminalUI::refresh (force=<optimized out>) at terminal_ui.cc:592 #21 Kakoune::Client::redraw_ifn () at client.cc:282 #22 Kakoune::ClientManager::redraw_clients () at client_manager.cc:232 #23 Kakoune::run_server (session=..., server_init=..., client_init=..., init_buffer="fish-rust/src/ast.rs", init_coord=..., flags=Kakoune::ServerFlags::None, ui_type=Kakoune::UIType::Terminal, debug_flags=<optimized out>, files=ArrayView<Kakoune::StringView> = {...}) at main.cc:893 #24 main (argc=<optimized out>, argv=<optimized out>) at main.cc:1243 Thereafter, "TerminalUI::Screen::output" resumes and crashes due to a buffer overflow in "lines" which has been resized.
2023-03-13Merge remote-tracking branch 'krobelus/perror-on-chmod-failure'Maxime Coste
2022-11-19Print OS error when ":write -force" fails to change permissionsJohannes Altmanninger
When the file system runs out of space, "write -force" will fail but doesn't print "No space left on device". Let's fix this by including such an underlying error. Untested. Backstory: I alias "w" to a command that runs "write -force %arg{@}". so I can overwrite files that already exist outside the editor (I should probably get used to the new behavior).
2022-11-19Accept "cd dir/" again instead of using a subdirectoryJohannes Altmanninger
Commit 69053d962 (Use menu behavior when completing change-directory, 2022-07-19) made ":cd dir/" actually run ":cd dir/first-subdir", which can be surprising. This is usually irrelevant because you rarely type the trailing slash. However it does happen after correcting an error with `<backspace>` and friends. For for example, :cd d<tab>/f<backspace> results in :cd dir/ We should probably fix user expectations here. Do this by adding "dir/" as valid completion. This requires us to allow empty candidates in "RankedMatch" but there's no harm in that. This means we need to filter out empty completions from shell-script-candidates elsewhere. Alternative fix: we could revert 69053d962. This would remove the convenient menu behavior but that wouldn't be a huge deal. Fixes #4775
2022-10-29Fix memory domain for cached command completionMaxime Coste
2022-06-03Only set fd to non-block if there is an EventManagerMaxime Coste
Fixes #4630
2022-05-10Run EventManager whenever writing to a file descriptor would blockMaxime Coste
This approach is not very elegant as it hooks into the event manager deep inside the call graph, but solves the exiting issue and is an okay stop gap solution until a better design comes up. Fixes #4605
2022-03-06Close MappedFile fd using on_scope_end to handle all return pathsMaxime Coste
2022-02-18Do not keep MappedFile fd openedMaxime Coste
According to the mmap man page this is not necessary, and this avoids exposing the fd.
2021-08-21Find the executable path on the GNU Hurd, too.Peter Pentchev
2021-07-31Expose BufferedWriterMaxime Coste
2021-07-20Prevent overwriting existing file in :write <explicit filename>Maxime Coste
Add a -force (equivalent to w!) switch that enables overwriting.
2021-05-28Support opening files bigger than 2 GiBMaxime Coste
The real technical limit is with lines bigger than 2 GiB and buffers with more than 2 Gi lines, refactor buffer loading to make it possible to load those files. Fix an overflow with the hash_data function at the same time
2021-03-12Fix typo in file.ccMaxime Coste
2021-03-11Do not use replace write method when writing to a non-regular fileMaxime Coste
Fixes #4098
2021-03-03Re-use the Regex VM when completing filenames to reduce allocationsMaxime Coste
By re-using the VM we avoid re-allocating the threads and saves buffers over and over again. We can just re-use the ones from the previous matching.
2021-01-03Add missing limits includesMaxime Coste
Fixes #4003
2020-09-18Add illumos/Solaris supportluka null
2020-04-23Fix get_kak_binary_path() for NetBSDKamil Rytarowski
Pass correct mib[] to sysctl(3).
2020-03-22|| -> or for consistencynia
2020-03-22Fix build on NetBSDnia
2019-12-19Update fs status post buffer writeMaxime Coste
2019-12-04Merge remote-tracking branch 'lenormf/reload-buffer-hash'Maxime Coste
2019-12-03src: Reload buffers when their contents' hash changesFrank LENORMAND
Instead of triggering a reload event when the timestamp of a buffer's underlying file changes, do so when its contents are actually modified.
2019-11-26src: Check the filesize before calling `mmap()`Frank LENORMAND
2019-07-06Fix build on FreeBSDTobias Kortkamp
file.cc:390:21: error: use of undeclared identifier 'rename'; did you mean 'devname'? if (replace and rename(temp_filename, zfilename) != 0) ^~~~~~ devname /usr/include/stdlib.h:277:7: note: 'devname' declared here char *devname(__dev_t, __mode_t); ^ file.cc:390:28: error: cannot initialize a parameter of type '__dev_t' (aka 'unsigned long') with an lvalue of type 'char [1024]' if (replace and rename(temp_filename, zfilename) != 0) ^~~~~~~~~~~~~ /usr/include/stdlib.h:277:22: note: passing argument to parameter here char *devname(__dev_t, __mode_t); ^ 2 errors generated. --- highlighters.cc:1110:13: error: use of undeclared identifier 'snprintf'; did you mean 'vswprintf'? snprintf(buffer, 16, format, std::abs(line_to_format)); ^~~~~~~~ vswprintf /usr/include/wchar.h:139:5: note: 'vswprintf' declared here int vswprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict, ^ highlighters.cc:1110:22: error: cannot initialize a parameter of type 'wchar_t *' with an lvalue of type 'char [16]' snprintf(buffer, 16, format, std::abs(line_to_format)); ^~~~~~ /usr/include/wchar.h:139:35: note: passing argument to parameter here int vswprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict, ^ 2 errors generated. --- json_ui.cc:60:13: error: use of undeclared identifier 'sprintf'; did you mean 'swprintf'? sprintf(buf, "\\u%04x", *next); ^~~~~~~ swprintf /usr/include/wchar.h:133:5: note: 'swprintf' declared here int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict, ^ json_ui.cc:60:21: error: cannot initialize a parameter of type 'wchar_t *' with an lvalue of type 'char [7]' sprintf(buf, "\\u%04x", *next); ^~~ /usr/include/wchar.h:133:34: note: passing argument to parameter here int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict, ^ json_ui.cc:74:9: error: use of undeclared identifier 'sprintf' sprintf(buffer, R"("#%02x%02x%02x")", color.r, color.g, color.b); ^ 3 errors generated. --- regex_impl.cc:1039:9: error: use of undeclared identifier 'sprintf'; did you mean 'swprintf'? sprintf(buf, " %03d ", count++); ^~~~~~~ swprintf /usr/include/wchar.h:133:5: note: 'swprintf' declared here int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict, ^ regex_impl.cc:1039:17: error: cannot initialize a parameter of type 'wchar_t *' with an lvalue of type 'char [20]' sprintf(buf, " %03d ", count++); ^~~ /usr/include/wchar.h:133:34: note: passing argument to parameter here int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict, ^ regex_impl.cc:1197:17: error: use of undeclared identifier 'puts' { if (dump) puts(dump_regex(*this).c_str()); } ^ regex_impl.cc:1208:18: note: in instantiation of member function 'Kakoune::(anonymous namespace)::TestVM<Kakoune::RegexMode::Forward>::TestVM' requested here TestVM<> vm{R"(a*b)"}; ^ regex_impl.cc:1197:17: error: use of undeclared identifier 'puts' { if (dump) puts(dump_regex(*this).c_str()); } ^ regex_impl.cc:1283:56: note: in instantiation of member function 'Kakoune::(anonymous namespace)::TestVM<5>::TestVM' requested here TestVM<RegexMode::Forward | RegexMode::Search> vm{R"(f.*a(.*o))"}; ^ regex_impl.cc:1197:17: error: use of undeclared identifier 'puts' { if (dump) puts(dump_regex(*this).c_str()); } ^ regex_impl.cc:1423:57: note: in instantiation of member function 'Kakoune::(anonymous namespace)::TestVM<6>::TestVM' requested here TestVM<RegexMode::Backward | RegexMode::Search> vm{R"(fo{1,})"}; ^ 5 errors generated. --- remote.cc:829:9: error: use of undeclared identifier 'rename'; did you mean 'devname'? if (rename(old_socket_file.c_str(), new_socket_file.c_str()) != 0) ^~~~~~ devname /usr/include/stdlib.h:277:7: note: 'devname' declared here char *devname(__dev_t, __mode_t); ^ remote.cc:829:16: error: cannot initialize a parameter of type '__dev_t' (aka 'unsigned long') with an rvalue of type 'const char *' if (rename(old_socket_file.c_str(), new_socket_file.c_str()) != 0) ^~~~~~~~~~~~~~~~~~~~~~~ /usr/include/stdlib.h:277:22: note: passing argument to parameter here char *devname(__dev_t, __mode_t); ^ 2 errors generated. --- string_utils.cc:126:20: error: use of undeclared identifier 'sprintf'; did you mean 'swprintf'? res.m_length = sprintf(res.m_data, "%i", val); ^~~~~~~ swprintf /usr/include/wchar.h:133:5: note: 'swprintf' declared here int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict, ^ string_utils.cc:126:28: error: cannot initialize a parameter of type 'wchar_t *' with an lvalue of type 'char [15]' res.m_length = sprintf(res.m_data, "%i", val); ^~~~~~~~~~ /usr/include/wchar.h:133:34: note: passing argument to parameter here int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict, ^ string_utils.cc:133:20: error: use of undeclared identifier 'sprintf'; did you mean 'swprintf'? res.m_length = sprintf(res.m_data, "%u", val); ^~~~~~~ swprintf [...]
2019-05-29Fix BufferedWriter triggering std::terminate on exception when writingMaxime Coste
Fixes #2932
2019-05-29Fix trailing slash removal code with root directoryMaxime Coste
2019-05-23Do not try to send remaining data on a closed socketMaxime Coste
Fixes #2906
2019-05-19Strip all trailing slashes in real_path and compact_pathRobert Melton
2019-04-07Add a -to-file <filename> switch to the echo commandMaxime Coste
As discussed in #2836
2019-04-01Buffer writes in blocks of 4Kb when writing buffers to filesMaxime Coste
Could make kakoune more compatible with tools looking for file modifications by reducing the amount of writes done. As discussed in #2812
2019-02-12Check the return value of the rename callMaxime Coste
2019-02-12Introduce a writemethod option to either overwrite or replace filesMaxime Coste
This permit to choose if files should be written by overwriting their content (the default), or by writing to a separate temporary file and rename it to the current file. As discussed in #2036