Commit 5db0bd5 (Lock history file before reading it, 2024-10-09)
rewrites the history file in place instead of using rename().
By writing to the same file (with the same inode), it corrupts
our memory-mapped snapshot; mmap(3) says:
> It is unspecified whether modifications to the underlying object done
> after the MAP_PRIVATE mapping is established are visible through the
> MAP_PRIVATE mapping.
Revert it (it was misguided anyway).
Closes#10777Closes#10782
We use optimistic concurrency when rewriting the history file to
minimize the lock scope. Unfortunately, old.mtime == new.mtime
does not imply that file is unchanged; we don't have guarantees
on the granularity of the modification time timestamp, see
https://stackoverflow.com/questions/14392975/timestamp-accuracy-on-ext4-sub-millsecond
So let's lock before reading any old contents and use the other
"write-to-tempfile-and-rename" code path only when locking fails.
Potentially fixes#10300
(untested) which probably happens because read_zero_padded() attempts to
read bytes that have not been flushed yet.
When I run a command with leading space, it is not added to the on-disk
history. However we still call History::save(). After 25 of such calls,
we rewrite the history file (even though nothing was written by us).
This is annoying when diagnosing #10300 where the history of the current
shell (but not other shells) is broken; because the history rewrite will
make the problem go away. Let's not save in this case, to make it easier to
run commands to inspect the state of the history file.
We used deque in C++ because this vector may be large, and so it avoids
repeated re-allocations. But VecDeque is different in Rust - it's contiguous -
so there's no benefit. Just use Vec.
This was based on a misunderstanding.
On musl, 64-bit time_t on 32-bit architectures was introduced in version 1.2.0,
by introducing new symbols. The old symbols still exist, to allow programs compiled against older versions
to keep running on 1.2.0+, preserving ABI-compatibility. (see musl commit 38143339646a4ccce8afe298c34467767c899f51)
Programs compiled against 1.2.0+ will get the new symbols, and will therefore think time_t is 64-bit.
Unfortunately, rust's libc crate uses its own definition of these types, and does not check for musl version.
Currently, it includes the pre-1.2.0 32-bit type.
That means:
- If you run on a 32-bit system like i686
- ... and compile against a C-library other than libc
- ... and pass it a time_t-containing struct like timespec or stat
... you need to arrange for that library to be built against musl <1.2.0.
Or, as https://github.com/ericonr/rust-time64 says:
> Therefore, for "old" 32-bit targets (riscv32 is supposed to default to time64),
> any Rust code that interacts with C code built on musl after 1.2.0,
> using types based on time_t (arguably, the main ones are struct timespec and struct stat) in their interface,
> will be completely miscompiled.
However, while fish runs on i686 and compiles against pcre2, we do not pass pcre2 a time_t.
Our only uses of time_t are confined to interactions with libc, in which case with musl we would simply use the legacy ABI.
I have compiled an i686 fish against musl to confirm and can find no issue.
This reverts commit 55196ee2a0430d920ea7a2c89a6e322615f78334.
This reverts commit 4992f8896633fb8ca8d89e09f02330cd49395485.
This reverts commit 46c8ba2c9fec77195091ddcf7ee0bb3d9a6e5f54.
This reverts commit 3a9b4149da7d44b8648702f17d9e9eef651e56f9.
This reverts commit 5f9e9cbe741025231acfb24dc900433e1c6738ac.
This reverts commit 338579b78ca2ba0aab108304bc33a53fddeb11ba.
This reverts commit d19e5508d7b406da6813edb9d0a6909094d20e5a.
This reverts commit b64045dc189ec58b6bd3dea71e1441e00876904c.
Closes#10634
While it does need to store the string, we also need to use the string after
storing it, so we aren't getting any advantage from passing by value. Just pass
by reference to simplify the call sites.
Popular operating systems support shift-delete to delete the selected item
in an autocompletion widgets. We already support this in the history pager.
Let's do the same for up-arrow history search.
Related discussion: https://github.com/fish-shell/fish-shell/pull/9515
More work in prep for having wopen_cloexec() return `File` directly.
This eliminates checking for an invalid fd and makes both ownership and
mutability clear (some more operations that involve changes to the underlying
state of the fd now require `&mut File` instead of just a `RawFd`).
Code that clearly does not use non-blocking IO is ported to use
`Write::write_all()` directly instead of our rusty port of the `write_loop()`
function (which handles EAGAIN/EWOULDBLOCK in addition to EINTR, while
`write_all()` only handles the latter).
This is a step towards converting `wopen_cloexec()` to return `File` instead of
`OwnedFd`/`AutocloseFd`.¹
In addition to letting us use native standard library functions instead of
unsafe libc calls, we gain additional semantic safety because `File` operations
that manipulate the state of the fd (e.g. `File::seek()`) require a `&mut`
reference to the `File`, whereas using `RawFd` or `OwnedFd` everywhere leaves us
in a position where it's not clear whether or not other references to the same
fd will manipulate its underlying state.
¹ We actually wouldn't even need `wopen_cloexec()` at all (just a widechar
wrapper) as Rust's native `File::open()`/`File::create()` functionality uses
`FD_CLOEXEC` internally.
I was able to trigger this by flipping around the history pager.
Since the only applicable caller here already stops if it gets None,
just don't assert.
We still don't support tabs but as of the parent commit, there are no more
weird glitches, so it should be fine to recall those lines?
This reverts commit cc0e366037b9af90015b562e71b660329a9012d2.
The lines of code I commented on in #10254 were meant to serve only as examples
of the changes I was requesting, not the only instances.
Also just use `Mode::from_bits_truncate()` instead of unsafe or unwrapping since
we know the modes are correct.