ctdb-common: Fix the TCP packet length check
[vlendec/samba-autobuild/.git] / ctdb / common / line.c
1 /*
2    Line based I/O over fds
3
4    Copyright (C) Amitay Isaacs  2018
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21
22 #include <talloc.h>
23
24 #include "lib/util/sys_rw.h"
25
26 #include "common/line.h"
27
28 struct line_read_state {
29         line_process_fn_t callback;
30         void *private_data;
31         char *buf;
32         size_t hint, len, offset;
33         int num_lines;
34 };
35
36 static bool line_read_one(char *buf, size_t start, size_t len, size_t *pos)
37 {
38         size_t i;
39
40         for (i=start; i<len; i++) {
41                 if (buf[i] == '\n' || buf[i] == '\0') {
42                         *pos = i;
43                         return true;
44                 }
45         }
46
47         return false;
48 }
49
50 static int line_read_process(struct line_read_state *state)
51 {
52         size_t start = 0;
53         size_t pos = 0;
54
55         while (1) {
56                 int ret;
57                 bool ok;
58
59                 ok = line_read_one(state->buf, start, state->offset, &pos);
60                 if (! ok) {
61                         break;
62                 }
63
64                 state->buf[pos] = '\0';
65                 state->num_lines += 1;
66
67                 ret = state->callback(state->buf + start, state->private_data);
68                 if (ret != 0) {
69                         return ret;
70                 }
71
72                 start = pos+1;
73         }
74
75         if (pos > 0) {
76                 if (pos+1 < state->offset) {
77                         memmove(state->buf,
78                                 state->buf + pos+1,
79                                 state->offset - (pos+1));
80                 }
81                 state->offset -= (pos+1);
82         }
83
84         return 0;
85 }
86
87 int line_read(int fd,
88               size_t length,
89               TALLOC_CTX *mem_ctx,
90               line_process_fn_t callback,
91               void *private_data,
92               int *num_lines)
93 {
94         struct line_read_state state;
95
96         if (length < 32) {
97                 length = 32;
98         }
99
100         state = (struct line_read_state) {
101                 .callback = callback,
102                 .private_data = private_data,
103                 .hint = length,
104         };
105
106         while (1) {
107                 ssize_t n;
108                 int ret;
109
110                 if (state.offset == state.len) {
111                         state.len += state.hint;
112                         state.buf = talloc_realloc_size(mem_ctx,
113                                                         state.buf,
114                                                         state.len);
115                         if (state.buf == NULL) {
116                                 return ENOMEM;
117                         }
118                 }
119
120                 n = sys_read(fd,
121                              state.buf + state.offset,
122                              state.len - state.offset);
123                 if (n < 0) {
124                         return errno;
125                 }
126                 if (n == 0) {
127                         break;
128                 }
129
130                 state.offset += n;
131
132                 ret = line_read_process(&state);
133                 if (ret != 0) {
134                         if (num_lines != NULL) {
135                                 *num_lines = state.num_lines;
136                         }
137                         return ret;
138                 }
139         }
140
141         if (num_lines != NULL) {
142                 *num_lines = state.num_lines;
143         }
144         return 0;
145 }