| 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 | } |