1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | #include <unistd.h> |
22 | #include <string.h> |
23 | #include <errno(*__errno_location ()).h> |
24 | |
25 | #include <ftpconn.h> |
26 |
|
27 | struct get_names_state |
28 | { |
29 | char *name; |
30 | size_t name_len; |
31 | size_t name_alloced; |
32 | int name_partial; |
33 | |
34 | size_t buf_len; |
35 | char buf[7000]; |
36 | }; |
37 | |
38 | |
39 | |
40 | |
41 | error_t |
42 | ftp_conn_start_get_names (struct ftp_conn *conn, |
43 | const char *name, int *fd, void **state) |
44 | { |
45 | error_t err; |
46 | struct get_names_state *s = malloc (sizeof (struct get_names_state)); |
47 | |
48 | if (! s) |
49 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); |
50 | |
51 | err = ftp_conn_start_list (conn, name, fd); |
52 | |
53 | if (err) |
54 | free (s); |
55 | else |
56 | { |
57 | s->name = 0; |
58 | s->name_len = s->name_alloced = 0; |
59 | s->name_partial = 0; |
60 | s->buf_len = 0; |
61 | *state = s; |
62 | } |
63 | |
64 | return err; |
65 | } |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | error_t |
73 | ftp_conn_cont_get_names (struct ftp_conn *conn, int fd, void *state, |
74 | ftp_conn_add_name_fun_t add_name, void *hook) |
75 | { |
76 | char *p, *nl; |
77 | ssize_t rd; |
78 | size_t name_len; |
79 | error_t err = 0; |
80 | struct get_names_state *s = state; |
81 | int (*icheck) (struct ftp_conn *conn) = conn->hooks->interrupt_check; |
82 | |
83 | |
84 | |
85 | rd = read (fd, s->buf + s->buf_len, sizeof (s->buf) - s->buf_len); |
86 | if (rd < 0) |
| |
| |
87 | { |
88 | err = errno(*__errno_location ()); |
89 | goto finished; |
90 | } |
91 | |
92 | if (icheck && (*icheck) (conn)) |
93 | { |
94 | err = EINTR((0x10 << 26) | ((4) & 0x3fff)); |
95 | goto finished; |
96 | } |
97 | |
98 | if (rd == 0) |
| 5 | | Assuming 'rd' is not equal to 0 | |
|
| |
99 | |
100 | if (s->buf_len == 0) |
101 | |
102 | goto finished; |
103 | else |
104 | |
105 | nl = s->buf + s->buf_len; |
106 | else |
107 | |
108 | |
109 | { |
110 | nl = memchr (s->buf + s->buf_len, '\n', rd); |
111 | s->buf_len += rd; |
112 | } |
113 | |
114 | if (!nl && s->buf_len < sizeof (s->buf)) |
| 7 | | Assuming 'nl' is non-null | |
|
115 | |
116 | |
117 | |
118 | return EAGAIN((0x10 << 26) | ((35) & 0x3fff)); |
119 | |
120 | |
121 | p = s->buf; |
122 | |
123 | do |
| 17 | | Loop condition is true. Execution continues on line 126 | |
|
124 | { |
125 | |
126 | name_len = (nl ? nl - p : s->buf + s->buf_len - p); |
| |
| |
127 | if (name_len > 0 && p[name_len - 1] == '\r') |
| 9 | | Assuming 'name_len' is <= 0 | |
|
| 19 | | Assuming 'name_len' is > 0 | |
|
| |
128 | name_len--; |
129 | if (name_len > 0) |
| |
| |
130 | |
131 | { |
132 | size_t old_len = s->name_len; |
133 | size_t total_len = old_len + name_len + 1; |
134 | |
135 | if (total_len > s->name_alloced) |
| |
136 | { |
137 | char *new_name = realloc (s->name, total_len); |
138 | if (! new_name) |
139 | goto enomem; |
140 | s->name = new_name; |
141 | s->name_alloced = total_len; |
142 | } |
143 | |
144 | strncpy (s->name + old_len, p, name_len); |
| 23 | | Use of memory after it is freed |
|
145 | s->name[old_len + name_len] = '\0'; |
146 | s->name_len = total_len - 1; |
147 | } |
148 | |
149 | if (nl) |
| |
150 | { |
151 | char *name = s->name; |
152 | |
153 | if (conn->syshooks.basename) |
| |
154 | |
155 | { |
156 | err = (*conn->syshooks.basename) (conn, &name); |
157 | if (err) |
158 | goto finished; |
159 | } |
160 | |
161 | |
162 | err = (*add_name) (name, hook); |
163 | |
164 | if (name < s->name || name > s->name + s->name_len) |
| |
165 | |
166 | free (name); |
| |
167 | |
168 | if (err) |
| |
| |
169 | goto finished; |
170 | |
171 | s->name_len = 0; |
172 | s->name_partial = 0; |
173 | |
174 | p = nl + 1; |
175 | nl = memchr (p, '\n', s->buf + s->buf_len - p); |
176 | } |
177 | else |
178 | |
179 | |
180 | { |
181 | s->name_partial = 1; |
182 | |
183 | p += name_len; |
184 | } |
185 | } |
186 | while (nl); |
187 | |
188 | |
189 | |
190 | s->buf_len -= (p - s->buf); |
191 | if (s->buf_len > 0) |
192 | memmove (s->buf, p, s->buf_len); |
193 | |
194 | |
195 | return EAGAIN((0x10 << 26) | ((35) & 0x3fff)); |
196 | |
197 | enomem: |
198 | |
199 | err = ENOMEM((0x10 << 26) | ((12) & 0x3fff)); |
200 | |
201 | finished: |
202 | |
203 | |
204 | if (s->name) |
205 | free (s->name); |
206 | free (s); |
207 | close (fd); |
208 | |
209 | if (err && rd > 0) |
210 | ftp_conn_abort (conn); |
211 | else if (err) |
212 | ftp_conn_finish_transfer (conn); |
213 | else |
214 | err = ftp_conn_finish_transfer (conn); |
215 | |
216 | return err; |
217 | } |
218 | |
219 | |
220 | |
221 | error_t |
222 | ftp_conn_get_names (struct ftp_conn *conn, const char *name, |
223 | ftp_conn_add_name_fun_t add_name, void *hook) |
224 | { |
225 | int fd; |
226 | void *state; |
227 | error_t err = ftp_conn_start_get_names (conn, name, &fd, &state); |
228 | |
229 | if (err) |
| |
230 | return err; |
231 | |
232 | do |
233 | err = ftp_conn_cont_get_names (conn, fd, state, add_name, hook); |
| 2 | | Calling 'ftp_conn_cont_get_names' | |
|
234 | while (err == EAGAIN((0x10 << 26) | ((35) & 0x3fff))); |
235 | |
236 | return err; |
237 | } |