File: | obj-scan-build/libftpconn/../../libftpconn/reply.c |
Location: | line 235, column 18 |
Description: | The left operand of '==' is a garbage value |
1 | /* Parse ftp server replies | |||
2 | ||||
3 | Copyright (C) 1997 Free Software Foundation, Inc. | |||
4 | ||||
5 | Written by Miles Bader <miles@gnu.ai.mit.edu> | |||
6 | ||||
7 | This program is free software; you can redistribute it and/or | |||
8 | modify it under the terms of the GNU General Public License as | |||
9 | published by the Free Software Foundation; either version 2, or (at | |||
10 | your option) any later version. | |||
11 | ||||
12 | This program is distributed in the hope that it will be useful, but | |||
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
15 | General Public License for more details. | |||
16 | ||||
17 | You should have received a copy of the GNU General Public License | |||
18 | along with this program; if not, write to the Free Software | |||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
20 | ||||
21 | #include <unistd.h> | |||
22 | #include <errno(*__errno_location ()).h> | |||
23 | #include <string.h> | |||
24 | #include <ctype.h> | |||
25 | ||||
26 | #include <ftpconn.h> | |||
27 | #include "priv.h" | |||
28 | ||||
29 | /* Add STR (of size LEN) to CONN's reply_txt buffer, at offset *OFFS, | |||
30 | updating *OFFS. */ | |||
31 | static inline error_t | |||
32 | ftp_conn_add_reply_txt (struct ftp_conn *conn, size_t *offs, | |||
33 | const char *str, size_t len) | |||
34 | { | |||
35 | if (*offs + len + 1 > conn->reply_txt_sz) | |||
36 | { | |||
37 | size_t new_sz = *offs + len + 50; | |||
38 | char *new = realloc (conn->reply_txt, new_sz); | |||
39 | if (! new) | |||
40 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
41 | conn->reply_txt = new; | |||
42 | conn->reply_txt_sz = new_sz; | |||
43 | } | |||
44 | ||||
45 | bcopy (str, conn->reply_txt + *offs, len); | |||
46 | conn->reply_txt[*offs + len] = '\0'; /* Make sure nul terminated. */ | |||
47 | ||||
48 | *offs += len; | |||
49 | ||||
50 | return 0; | |||
51 | } | |||
52 | ||||
53 | /* Return a new line read from CONN's control connection in LINE & LINE_LEN; | |||
54 | LINE points into storage allocated in CONN, and is only valid until the | |||
55 | next call to this function, or return an error code. (we used to just use | |||
56 | the stdio getline function, and keep a stdio stream for the control | |||
57 | connection, but interleaved I/O didn't work correctly.) */ | |||
58 | static inline error_t | |||
59 | ftp_conn_getline (struct ftp_conn *conn, const char **line, size_t *line_len) | |||
60 | { | |||
61 | char *l = conn->line; | |||
62 | size_t offs = conn->line_offs, len = conn->line_len, sz = conn->line_sz; | |||
63 | int (*icheck) (struct ftp_conn *conn) = conn->hooks->interrupt_check; | |||
64 | ||||
65 | for (;;) | |||
66 | { | |||
67 | int rd; | |||
68 | ||||
69 | if (offs < len) | |||
70 | /* See if there's a newline in the active part of the line buffer. */ | |||
71 | { | |||
72 | char *nl = memchr (l + offs, '\n', len - offs); | |||
73 | if (nl) | |||
74 | /* There is! Consume and return the whole line we found. */ | |||
75 | { | |||
76 | *line = l + offs; | |||
77 | ||||
78 | offs = nl + 1 - l; /* Consume the line */ | |||
79 | ||||
80 | /* Null terminate the result by overwriting the newline; if | |||
81 | there's a CR preceding it, get rid of that too. */ | |||
82 | if (nl > *line && nl[-1] == '\r') | |||
83 | nl--; | |||
84 | *nl = '\0'; | |||
85 | ||||
86 | *line_len = nl - *line; | |||
87 | ||||
88 | if (offs == len) | |||
89 | conn->line_offs = conn->line_len = 0; | |||
90 | else | |||
91 | conn->line_offs = offs; | |||
92 | ||||
93 | return 0; | |||
94 | } | |||
95 | } | |||
96 | ||||
97 | /* No newline yet, so read some more! */ | |||
98 | ||||
99 | if (offs > (len << 2) && offs < len) | |||
100 | /* Relocate the current contents of the buffer to the beginning. */ | |||
101 | { | |||
102 | len -= offs; | |||
103 | bcopy (l + offs, l, len - offs); | |||
104 | offs = conn->line_offs = 0; | |||
105 | conn->line_len = len; | |||
106 | } | |||
107 | if (len == sz) | |||
108 | /* Grow the line buffer; there's no space left. */ | |||
109 | { | |||
110 | sz = sz + len ?: 50; | |||
111 | l = realloc (l, sz); | |||
112 | if (! l) | |||
113 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
114 | conn->line = l; | |||
115 | conn->line_sz = sz; | |||
116 | } | |||
117 | ||||
118 | /* Actually read something. */ | |||
119 | rd = read (conn->control, l + len, sz - len); | |||
120 | if (rd < 0) | |||
121 | return errno(*__errno_location ()); | |||
122 | else if (rd == 0) | |||
123 | { | |||
124 | *line = l + offs; | |||
125 | *line_len = 0; | |||
126 | return 0; | |||
127 | } | |||
128 | ||||
129 | len += rd; | |||
130 | conn->line_len = len; | |||
131 | ||||
132 | if (icheck && (*icheck) (conn)) | |||
133 | return EINTR((0x10 << 26) | ((4) & 0x3fff)); | |||
134 | } | |||
135 | } | |||
136 | ||||
137 | /* Get the next reply from CONN's ftp server, returning the reply code in | |||
138 | REPLY, if REPLY is non-zero, and the text of the reply (not including the | |||
139 | reply code) in REPLY_TXT (if it isn't zero), or return an error code. If | |||
140 | the reply is multiple lines, all of them are included in REPLY_TXT, | |||
141 | separated by newlines. */ | |||
142 | inline error_t | |||
143 | ftp_conn_get_raw_reply (struct ftp_conn *conn, int *reply, | |||
144 | const char **reply_txt) | |||
145 | { | |||
146 | size_t reply_txt_offs = 0; /* End of a multi-line reply in accum buf. */ | |||
147 | int multi = 0; /* If a multi-line reply, the reply code. */ | |||
148 | ||||
149 | if (!reply && !reply_txt) | |||
150 | return 0; /* nop */ | |||
151 | ||||
152 | do | |||
153 | { | |||
154 | const char *l; | |||
155 | size_t len; | |||
156 | error_t err = ftp_conn_getline (conn, &l, &len); | |||
157 | ||||
158 | if (err) | |||
159 | return err; | |||
160 | if (!multi && len == 0) | |||
161 | return EPIPE((0x10 << 26) | ((32) & 0x3fff)); | |||
162 | ||||
163 | #define ACCUM(txt, len)do { if (reply_txt) { error_t err = ftp_conn_add_reply_txt (conn , &reply_txt_offs, txt, len); if (err) return err; } } while (0) \ | |||
164 | do { \ | |||
165 | if (reply_txt) /* Only accumulate if wanted. */ \ | |||
166 | { \ | |||
167 | error_t err = \ | |||
168 | ftp_conn_add_reply_txt (conn, &reply_txt_offs, txt, len); \ | |||
169 | if (err) \ | |||
170 | return err; \ | |||
171 | } \ | |||
172 | } while (0) | |||
173 | ||||
174 | if (conn->hooks && conn->hooks->cntl_debug) | |||
175 | (*conn->hooks->cntl_debug) (conn, FTP_CONN_CNTL_DEBUG_REPLY2, l); | |||
176 | ||||
177 | if (isdigit (l[0])((*__ctype_b_loc ())[(int) ((l[0]))] & (unsigned short int ) _ISdigit) && isdigit (l[1])((*__ctype_b_loc ())[(int) ((l[1]))] & (unsigned short int ) _ISdigit) && isdigit (l[2])((*__ctype_b_loc ())[(int) ((l[2]))] & (unsigned short int ) _ISdigit)) | |||
178 | /* A reply code. */ | |||
179 | { | |||
180 | int code = (l[0] - '0')*100 + (l[1] - '0')*10 + (l[2] - '0'); | |||
181 | ||||
182 | if (multi && code != multi) | |||
183 | /* Two codes in a multi-line reply don't match. */ | |||
184 | return EGRATUITOUS((0x10 << 26) | ((105) & 0x3fff)); | |||
185 | ||||
186 | if (l[3] == '-') | |||
187 | /* The non-terminal line of a multi-line reply. RFC959 actually | |||
188 | claims there shouldn't be more than one multi-line code (other | |||
189 | lines in between the two shouldn't have a numeric code at | |||
190 | all), but real ftp servers don't obey this rule. */ | |||
191 | multi = code; | |||
192 | else if (l[3] != ' ') | |||
193 | /* Some syntax error. */ | |||
194 | return EGRATUITOUS((0x10 << 26) | ((105) & 0x3fff)); | |||
195 | else | |||
196 | /* The end of the reply (and perhaps the only line). */ | |||
197 | { | |||
198 | multi = 0; | |||
199 | if (reply) | |||
200 | *reply = code; | |||
201 | } | |||
202 | ||||
203 | ACCUM (l + 4, len - 4)do { if (reply_txt) { error_t err = ftp_conn_add_reply_txt (conn , &reply_txt_offs, l + 4, len - 4); if (err) return err; } } while (0); | |||
204 | } | |||
205 | else if (multi) | |||
206 | /* The lines between the first and last in a multi-line reply may be | |||
207 | anything as long as they don't start with a digit. */ | |||
208 | ACCUM (l, len)do { if (reply_txt) { error_t err = ftp_conn_add_reply_txt (conn , &reply_txt_offs, l, len); if (err) return err; } } while (0); | |||
209 | else | |||
210 | return EGRATUITOUS((0x10 << 26) | ((105) & 0x3fff)); | |||
211 | } | |||
212 | while (multi); | |||
213 | ||||
214 | if (reply_txt) | |||
215 | *reply_txt = conn->reply_txt; | |||
216 | ||||
217 | return 0; | |||
218 | } | |||
219 | ||||
220 | /* Get the next reply from CONN's ftp server, returning the reply code in | |||
221 | REPLY, if REPLY is non-zero, and the text of the reply (not including the | |||
222 | reply code) in REPLY_TXT (if it isn't zero), or return an error code. If | |||
223 | the reply is multiple lines, all of them are included in REPLY_TXT, | |||
224 | separated by newlines. This differs from ftp_conn_get_raw_reply in that | |||
225 | it eats REPLY_ABORT_OK replies on the assumption that they're junk left | |||
226 | over from the last abort command. */ | |||
227 | error_t | |||
228 | ftp_conn_get_reply (struct ftp_conn *conn, int *reply, const char **reply_txt) | |||
229 | { | |||
230 | int code; | |||
| ||||
231 | error_t err; | |||
232 | ||||
233 | do | |||
234 | err = ftp_conn_get_raw_reply (conn, &code, reply_txt); | |||
235 | while (!err && code == REPLY_ABORT_OK225); | |||
| ||||
236 | ||||
237 | if (!err && reply) | |||
238 | *reply = code; | |||
239 | ||||
240 | return err; | |||
241 | } |