diff options
author | Sahan Fernando <sahan.h.fernando@gmail.com> | 2021-05-18 19:06:33 +1000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-18 16:47:26 +0200 |
commit | c3b670c09213107ce52990e1d897aa3a68ad5851 (patch) | |
tree | 78e711e52028432991f12380f54ff07890ebc2c6 /Kernel | |
parent | fe2d4d85c429d972e17038c9e78795c2a2ead2ff (diff) | |
download | serenity-c3b670c09213107ce52990e1d897aa3a68ad5851.zip |
Kernel: Acknowledge partial writes from TTYs
Fixes a bug where TTY::write will attempt to write into the underlying
device but will not acknowledge the result of that write, instead
assuming that the write fully completed.
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/TTY/TTY.cpp | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/Kernel/TTY/TTY.cpp b/Kernel/TTY/TTY.cpp index 353ad45582..ce7c21a678 100644 --- a/Kernel/TTY/TTY.cpp +++ b/Kernel/TTY/TTY.cpp @@ -97,8 +97,29 @@ KResultOr<size_t> TTY::write(FileDescription&, u64, const UserOrKernelBuffer& bu } modified_data[i + extra_chars] = ch; } - on_tty_write(UserOrKernelBuffer::for_kernel_buffer(modified_data), buffer_bytes + extra_chars); - return buffer_bytes; + ssize_t bytes_written = on_tty_write(UserOrKernelBuffer::for_kernel_buffer(modified_data), buffer_bytes + extra_chars); + VERIFY(bytes_written != 0); + if (bytes_written < 0 || !(m_termios.c_oflag & OPOST) || !(m_termios.c_oflag & ONLCR)) + return bytes_written; + if ((size_t)bytes_written == buffer_bytes + extra_chars) + return (ssize_t)buffer_bytes; + + // Degenerate case where we converted some newlines and encountered a partial write + + // Calculate where in the input buffer the last character would have been + size_t pos_data = 0; + for (ssize_t pos_modified_data = 0; pos_modified_data < bytes_written; ++pos_data) { + if (data[pos_data] == '\n') + pos_modified_data += 2; + else + pos_modified_data += 1; + + // Handle case where the '\r' got written but not the '\n' + // FIXME: Our strategy is to retry writing both. We should really be queuing a write for the corresponding '\n' + if (pos_modified_data > bytes_written) + --pos_data; + } + return (ssize_t)pos_data; }); } |