vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / tty / line_buffer.cpp
blobd051fd3bb323ad9bb07bb1173eb71a5808c61a07
1 /*
2 * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "line_buffer.h"
9 #include <KernelExport.h>
10 #include <stdlib.h>
13 status_t
14 clear_line_buffer(struct line_buffer &buffer)
16 buffer.in = 0;
17 buffer.first = 0;
18 return B_OK;
22 status_t
23 init_line_buffer(struct line_buffer &buffer, size_t size)
25 clear_line_buffer(buffer);
27 buffer.buffer = (char *)malloc(size);
28 if (buffer.buffer == NULL)
29 return B_NO_MEMORY;
31 buffer.size = size;
33 return B_OK;
37 status_t
38 uninit_line_buffer(struct line_buffer &buffer)
40 free(buffer.buffer);
41 return B_OK;
45 int32
46 line_buffer_readable(struct line_buffer &buffer)
48 return buffer.in;
52 int32
53 line_buffer_readable_line(struct line_buffer &buffer, char eol, char eof)
55 size_t size = buffer.in;
56 if (size == 0)
57 return 0;
59 // find EOL or EOF char
60 for (size_t i = 0; i < size; i++) {
61 char c = buffer.buffer[(buffer.first + i) % buffer.size];
62 if (c == eol || c == '\n' || c == '\r' || c == eof)
63 return i + 1;
66 // If the buffer is full, but doesn't contain a EOL or EOF, we report the
67 // full size anyway, since otherwise the reader would wait forever.
68 return buffer.in == buffer.size ? buffer.in : 0;
72 int32
73 line_buffer_writable(struct line_buffer &buffer)
75 return buffer.size - buffer.in;
79 ssize_t
80 line_buffer_user_read(struct line_buffer &buffer, char *data, size_t length,
81 char eof, bool* hitEOF)
83 size_t available = buffer.in;
85 if (length > available)
86 length = available;
88 if (length == 0)
89 return 0;
91 // check for EOF, if the caller asked us to
92 if (hitEOF) {
93 *hitEOF = false;
94 for (size_t i = 0; i < available; i++) {
95 char c = buffer.buffer[(buffer.first + i) % buffer.size];
96 if (c == eof) {
97 *hitEOF = true;
98 length = i;
99 break;
104 ssize_t bytesRead = length;
106 if (buffer.first + length < buffer.size) {
107 // simple copy
108 if (user_memcpy(data, buffer.buffer + buffer.first, length) != B_OK)
109 bytesRead = B_BAD_ADDRESS;
110 } else {
111 // need to copy both ends
112 size_t upper = buffer.size - buffer.first;
113 size_t lower = length - upper;
115 if (user_memcpy(data, buffer.buffer + buffer.first, upper) != B_OK
116 || user_memcpy(data + upper, buffer.buffer, lower) != B_OK)
117 bytesRead = B_BAD_ADDRESS;
120 if (bytesRead > 0) {
121 buffer.first = (buffer.first + bytesRead) % buffer.size;
122 buffer.in -= bytesRead;
125 // dispose of EOF char
126 if (hitEOF && *hitEOF) {
127 buffer.first = (buffer.first + 1) % buffer.size;
128 buffer.in--;
131 return bytesRead;
135 status_t
136 line_buffer_putc(struct line_buffer &buffer, char c)
138 if (buffer.in == buffer.size)
139 return B_NO_MEMORY;
141 buffer.buffer[(buffer.first + buffer.in++) % buffer.size] = c;
142 return B_OK;
146 #if 0
147 status_t
148 line_buffer_getc(struct line_buffer &buffer, char *_c)
153 status_t
154 line_buffer_ungetc(struct line_buffer &buffer, char *c)
158 #endif
161 bool
162 line_buffer_tail_getc(struct line_buffer &buffer, char *c)
164 if (buffer.in == 0)
165 return false;
167 *c = buffer.buffer[(buffer.first + --buffer.in) % buffer.size];
168 return true;