Coverage Report

Created: 2026-10-22 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/ftplistparser.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#ifndef CURL_DISABLE_FTP
27
28
/**
29
 * Now implemented:
30
 *
31
 * 1) Unix version 1
32
 * drwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog
33
 * 2) Unix version 2
34
 * drwxr-xr-x 1 user01 ftp  512 Jan 29 1997  prog
35
 * 3) Unix version 3
36
 * drwxr-xr-x 1      1   1  512 Jan 29 23:32 prog
37
 * 4) Unix symlink
38
 * lrwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog -> prog2000
39
 * 5) DOS style
40
 * 01-29-97 11:32PM <DIR> prog
41
 */
42
43
#include "urldata.h"
44
#include "fileinfo.h"
45
#include "llist.h"
46
#include "ftp.h"
47
#include "ftp-int.h"
48
#include "ftplistparser.h"
49
#include "curl_fnmatch.h"
50
#include "multiif.h"
51
#include "curlx/strparse.h"
52
53
typedef enum {
54
  PL_UNIX_TOTALSIZE = 0,
55
  PL_UNIX_FILETYPE,
56
  PL_UNIX_PERMISSION,
57
  PL_UNIX_HLINKS,
58
  PL_UNIX_USER,
59
  PL_UNIX_GROUP,
60
  PL_UNIX_SIZE,
61
  PL_UNIX_TIME,
62
  PL_UNIX_FILENAME,
63
  PL_UNIX_SYMLINK
64
} pl_unix_mainstate;
65
66
typedef union {
67
  enum {
68
    PL_UNIX_TOTALSIZE_INIT = 0,
69
    PL_UNIX_TOTALSIZE_READING
70
  } total_dirsize;
71
72
  enum {
73
    PL_UNIX_HLINKS_PRESPACE = 0,
74
    PL_UNIX_HLINKS_NUMBER
75
  } hlinks;
76
77
  enum {
78
    PL_UNIX_USER_PRESPACE = 0,
79
    PL_UNIX_USER_PARSING
80
  } user;
81
82
  enum {
83
    PL_UNIX_GROUP_PRESPACE = 0,
84
    PL_UNIX_GROUP_NAME
85
  } group;
86
87
  enum {
88
    PL_UNIX_SIZE_PRESPACE = 0,
89
    PL_UNIX_SIZE_NUMBER
90
  } size;
91
92
  enum {
93
    PL_UNIX_TIME_PREPART1 = 0,
94
    PL_UNIX_TIME_PART1,
95
    PL_UNIX_TIME_PREPART2,
96
    PL_UNIX_TIME_PART2,
97
    PL_UNIX_TIME_PREPART3,
98
    PL_UNIX_TIME_PART3
99
  } time;
100
101
  enum {
102
    PL_UNIX_FILENAME_PRESPACE = 0,
103
    PL_UNIX_FILENAME_NAME,
104
    PL_UNIX_FILENAME_WINDOWSEOL
105
  } filename;
106
107
  enum {
108
    PL_UNIX_SYMLINK_PRESPACE = 0,
109
    PL_UNIX_SYMLINK_NAME,
110
    PL_UNIX_SYMLINK_PRETARGET1,
111
    PL_UNIX_SYMLINK_PRETARGET2,
112
    PL_UNIX_SYMLINK_PRETARGET3,
113
    PL_UNIX_SYMLINK_PRETARGET4,
114
    PL_UNIX_SYMLINK_TARGET,
115
    PL_UNIX_SYMLINK_WINDOWSEOL
116
  } symlink;
117
} pl_unix_substate;
118
119
typedef enum {
120
  PL_WINNT_DATE = 0,
121
  PL_WINNT_TIME,
122
  PL_WINNT_DIRORSIZE,
123
  PL_WINNT_FILENAME
124
} pl_winNT_mainstate;
125
126
typedef union {
127
  enum {
128
    PL_WINNT_TIME_PRESPACE = 0,
129
    PL_WINNT_TIME_TIME
130
  } time;
131
  enum {
132
    PL_WINNT_DIRORSIZE_PRESPACE = 0,
133
    PL_WINNT_DIRORSIZE_CONTENT
134
  } dirorsize;
135
  enum {
136
    PL_WINNT_FILENAME_PRESPACE = 0,
137
    PL_WINNT_FILENAME_CONTENT,
138
    PL_WINNT_FILENAME_WINEOL
139
  } filename;
140
} pl_winNT_substate;
141
142
/* This struct is used in wildcard downloading - for parsing LIST response */
143
struct ftp_parselist_data {
144
  enum {
145
    OS_TYPE_UNKNOWN = 0,
146
    OS_TYPE_UNIX,
147
    OS_TYPE_WIN_NT
148
  } os_type;
149
150
  union {
151
    struct {
152
      pl_unix_mainstate main;
153
      pl_unix_substate sub;
154
    } UNIX;
155
156
    struct {
157
      pl_winNT_mainstate main;
158
      pl_winNT_substate sub;
159
    } NT;
160
  } state;
161
162
  CURLcode error;
163
  struct fileinfo *file_data;
164
  unsigned int item_length;
165
  size_t item_offset;
166
  struct {
167
    size_t filename;
168
    size_t user;
169
    size_t group;
170
    size_t time;
171
    size_t perm;
172
    size_t symlink_target;
173
  } offsets;
174
};
175
176
static void fileinfo_dtor(void *user, void *element)
177
2.11k
{
178
2.11k
  (void)user;
179
2.11k
  Curl_fileinfo_cleanup(element);
180
2.11k
}
181
182
void Curl_wildcard_init(struct WildcardData *wc)
183
3.28k
{
184
3.28k
  Curl_llist_init(&wc->filelist, fileinfo_dtor);
185
3.28k
  wc->state = CURLWC_INIT;
186
3.28k
}
187
188
void Curl_wildcard_dtor(struct WildcardData **wcp)
189
1.93M
{
190
1.93M
  struct WildcardData *wc = *wcp;
191
1.93M
  if(!wc)
192
1.93M
    return;
193
194
3.28k
  if(wc->dtor) {
195
2.32k
    wc->dtor(wc->ftpwc);
196
2.32k
    wc->dtor = ZERO_NULL;
197
2.32k
    wc->ftpwc = NULL;
198
2.32k
  }
199
3.28k
  DEBUGASSERT(!wc->ftpwc);
200
201
3.28k
  Curl_llist_destroy(&wc->filelist, NULL);
202
3.28k
  curlx_safefree(wc->path);
203
3.28k
  curlx_safefree(wc->pattern);
204
3.28k
  wc->state = CURLWC_INIT;
205
3.28k
  curlx_free(wc);
206
3.28k
  *wcp = NULL;
207
3.28k
}
208
209
struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
210
2.33k
{
211
2.33k
  return curlx_calloc(1, sizeof(struct ftp_parselist_data));
212
2.33k
}
213
214
void Curl_ftp_parselist_data_free(struct ftp_parselist_data **parserp)
215
2.33k
{
216
2.33k
  struct ftp_parselist_data *parser = *parserp;
217
2.33k
  if(parser)
218
2.33k
    Curl_fileinfo_cleanup(parser->file_data);
219
2.33k
  curlx_free(parser);
220
2.33k
  *parserp = NULL;
221
2.33k
}
222
223
CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
224
2.04k
{
225
2.04k
  return pl_data->error;
226
2.04k
}
227
228
4.62k
#define FTP_LP_MALFORMATED_PERM 0x01000000
229
230
static unsigned int ftp_pl_get_permission(const char *str)
231
4.51k
{
232
4.51k
  unsigned int permissions = 0;
233
  /* USER */
234
4.51k
  if(str[0] == 'r')
235
4.44k
    permissions |= 1 << 8;
236
66
  else if(str[0] != '-')
237
6
    permissions |= FTP_LP_MALFORMATED_PERM;
238
4.51k
  if(str[1] == 'w')
239
3.85k
    permissions |= 1 << 7;
240
655
  else if(str[1] != '-')
241
16
    permissions |= FTP_LP_MALFORMATED_PERM;
242
243
4.51k
  if(str[2] == 'x')
244
1.85k
    permissions |= 1 << 6;
245
2.66k
  else if(str[2] == 's') {
246
77
    permissions |= 1 << 6;
247
77
    permissions |= 1 << 11;
248
77
  }
249
2.58k
  else if(str[2] == 'S')
250
237
    permissions |= 1 << 11;
251
2.34k
  else if(str[2] != '-')
252
12
    permissions |= FTP_LP_MALFORMATED_PERM;
253
  /* GROUP */
254
4.51k
  if(str[3] == 'r')
255
4.21k
    permissions |= 1 << 5;
256
300
  else if(str[3] != '-')
257
13
    permissions |= FTP_LP_MALFORMATED_PERM;
258
4.51k
  if(str[4] == 'w')
259
138
    permissions |= 1 << 4;
260
4.37k
  else if(str[4] != '-')
261
18
    permissions |= FTP_LP_MALFORMATED_PERM;
262
4.51k
  if(str[5] == 'x')
263
1.58k
    permissions |= 1 << 3;
264
2.92k
  else if(str[5] == 's') {
265
288
    permissions |= 1 << 3;
266
288
    permissions |= 1 << 10;
267
288
  }
268
2.63k
  else if(str[5] == 'S')
269
52
    permissions |= 1 << 10;
270
2.58k
  else if(str[5] != '-')
271
13
    permissions |= FTP_LP_MALFORMATED_PERM;
272
  /* others */
273
4.51k
  if(str[6] == 'r')
274
4.15k
    permissions |= 1 << 2;
275
361
  else if(str[6] != '-')
276
13
    permissions |= FTP_LP_MALFORMATED_PERM;
277
4.51k
  if(str[7] == 'w')
278
117
    permissions |= 1 << 1;
279
4.39k
  else if(str[7] != '-')
280
12
    permissions |= FTP_LP_MALFORMATED_PERM;
281
4.51k
  if(str[8] == 'x')
282
1.54k
    permissions |= 1;
283
2.97k
  else if(str[8] == 't') {
284
235
    permissions |= 1;
285
235
    permissions |= 1 << 9;
286
235
  }
287
2.73k
  else if(str[8] == 'T')
288
48
    permissions |= 1 << 9;
289
2.68k
  else if(str[8] != '-')
290
12
    permissions |= FTP_LP_MALFORMATED_PERM;
291
292
4.51k
  return permissions;
293
4.51k
}
294
295
static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
296
                                    struct fileinfo *infop)
297
3.84k
{
298
3.84k
  curl_fnmatch_callback compare;
299
3.84k
  struct WildcardData *wc = data->wildcard;
300
3.84k
  struct ftp_wc *ftpwc = wc->ftpwc;
301
3.84k
  struct Curl_llist *llist = &wc->filelist;
302
3.84k
  struct ftp_parselist_data *parser = ftpwc->parser;
303
3.84k
  bool add = TRUE;
304
3.84k
  struct curl_fileinfo *finfo = &infop->info;
305
306
  /* set the finfo pointers */
307
3.84k
  char *str = curlx_dyn_ptr(&infop->buf);
308
3.84k
  finfo->filename       = str + parser->offsets.filename;
309
3.84k
  finfo->strings.group  = parser->offsets.group ?
310
3.84k
                          str + parser->offsets.group : NULL;
311
3.84k
  finfo->strings.perm   = parser->offsets.perm ?
312
3.84k
                          str + parser->offsets.perm : NULL;
313
3.84k
  finfo->strings.target = parser->offsets.symlink_target &&
314
369
    (finfo->filetype == CURLFILETYPE_SYMLINK) ?
315
3.84k
    str + parser->offsets.symlink_target : NULL;
316
3.84k
  finfo->strings.time   = str + parser->offsets.time;
317
3.84k
  finfo->strings.user   = parser->offsets.user ?
318
3.84k
                          str + parser->offsets.user : NULL;
319
320
  /* get correct fnmatch callback */
321
3.84k
  compare = data->set.fnmatch;
322
3.84k
  if(!compare)
323
3.84k
    compare = Curl_fnmatch;
324
325
  /* filter pattern-corresponding filenames */
326
3.84k
  if(strchr(finfo->filename, '/'))
327
66
    add = FALSE;
328
3.77k
  else {
329
    /* a real file name cannot contain a slash */
330
3.77k
    struct Curl_mapi_guard guard;
331
3.77k
    CURL_CBAPI_START(&guard, data, easy_fnmatch_data);
332
3.77k
    if(compare(data->set.fnmatch_data, wc->pattern, finfo->filename) == 0) {
333
      /* discard symlink which is containing multiple " -> " */
334
2.18k
      if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
335
159
         strstr(finfo->strings.target, " -> ")) {
336
62
        add = FALSE;
337
62
      }
338
2.18k
    }
339
1.59k
    else {
340
1.59k
      add = FALSE;
341
1.59k
    }
342
3.77k
    CURL_CBAPI_END(&guard);
343
3.77k
  }
344
345
3.84k
  if(add) {
346
2.11k
    Curl_llist_append(llist, finfo, &infop->list);
347
2.11k
  }
348
1.72k
  else {
349
1.72k
    Curl_fileinfo_cleanup(infop);
350
1.72k
  }
351
352
3.84k
  ftpwc->parser->file_data = NULL;
353
3.84k
  return CURLE_OK;
354
3.84k
}
355
356
5.48k
#define MAX_FTPLIST_BUFFER 10000 /* arbitrarily set */
357
358
static CURLcode unix_filetype(const char c, curlfiletype *t)
359
4.73k
{
360
4.73k
  switch(c) {
361
1.65k
  case '-':
362
1.65k
    *t = CURLFILETYPE_FILE;
363
1.65k
    break;
364
1.41k
  case 'd':
365
1.41k
    *t = CURLFILETYPE_DIRECTORY;
366
1.41k
    break;
367
550
  case 'l':
368
550
    *t = CURLFILETYPE_SYMLINK;
369
550
    break;
370
95
  case 'p':
371
95
    *t = CURLFILETYPE_NAMEDPIPE;
372
95
    break;
373
90
  case 's':
374
90
    *t = CURLFILETYPE_SOCKET;
375
90
    break;
376
286
  case 'c':
377
286
    *t = CURLFILETYPE_DEVICE_CHAR;
378
286
    break;
379
497
  case 'b':
380
497
    *t = CURLFILETYPE_DEVICE_BLOCK;
381
497
    break;
382
33
  case 'D':
383
33
    *t = CURLFILETYPE_DOOR;
384
33
    break;
385
107
  default:
386
107
    return CURLE_FTP_BAD_FILE_LIST;
387
4.73k
  }
388
4.62k
  return CURLE_OK;
389
4.73k
}
390
391
static CURLcode parse_unix_totalsize(struct ftp_parselist_data *parser,
392
                                     struct fileinfo *infop,
393
                                     const char c)
394
5.86k
{
395
5.86k
  size_t len = curlx_dyn_len(&infop->buf);
396
5.86k
  char *mem = curlx_dyn_ptr(&infop->buf);
397
5.86k
  switch(parser->state.UNIX.sub.total_dirsize) {
398
1.71k
  case PL_UNIX_TOTALSIZE_INIT:
399
1.71k
    if(c == 't') {
400
128
      parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
401
128
      parser->item_length++;
402
128
    }
403
1.59k
    else {
404
1.59k
      parser->state.UNIX.main = PL_UNIX_FILETYPE;
405
      /* continue to fall through */
406
1.59k
    }
407
1.71k
    break;
408
4.14k
  case PL_UNIX_TOTALSIZE_READING:
409
4.14k
    parser->item_length++;
410
4.14k
    if(c == '\r') {
411
1
      parser->item_length--;
412
1
      if(len)
413
1
        curlx_dyn_setlen(&infop->buf, --len);
414
1
    }
415
4.14k
    else if(c == '\n') {
416
107
      mem[parser->item_length - 1] = 0;
417
107
      if(!strncmp("total ", mem, 6)) {
418
51
        const char *endptr = mem + 6;
419
        /* here we can deal with directory size, pass the leading
420
           whitespace and then the digits */
421
51
        curlx_str_passblanks(&endptr);
422
602
        while(ISDIGIT(*endptr))
423
551
          endptr++;
424
51
        if(*endptr) {
425
24
          return CURLE_FTP_BAD_FILE_LIST;
426
24
        }
427
27
        parser->state.UNIX.main = PL_UNIX_FILETYPE;
428
27
        curlx_dyn_reset(&infop->buf);
429
27
      }
430
56
      else
431
56
        return CURLE_FTP_BAD_FILE_LIST;
432
107
    }
433
4.06k
    break;
434
5.86k
  }
435
5.78k
  return CURLE_OK;
436
5.86k
}
437
438
static CURLcode parse_unix_permission(struct ftp_parselist_data *parser,
439
                                      struct fileinfo *infop,
440
                                      const char c)
441
45.4k
{
442
45.4k
  char *mem = curlx_dyn_ptr(&infop->buf);
443
45.4k
  parser->item_length++;
444
45.4k
  if((parser->item_length <= 9) && !strchr("rwx-tTsS", c))
445
61
    return CURLE_FTP_BAD_FILE_LIST;
446
447
45.3k
  else if(parser->item_length == 10) {
448
4.52k
    unsigned int perm;
449
4.52k
    if(c != ' ')
450
10
      return CURLE_FTP_BAD_FILE_LIST;
451
452
4.51k
    mem[10] = 0; /* terminate permissions */
453
4.51k
    perm = ftp_pl_get_permission(mem + parser->item_offset);
454
4.51k
    if(perm & FTP_LP_MALFORMATED_PERM)
455
48
      return CURLE_FTP_BAD_FILE_LIST;
456
457
4.46k
    parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
458
4.46k
    parser->file_data->info.perm = perm;
459
4.46k
    parser->offsets.perm = parser->item_offset;
460
461
4.46k
    parser->item_length = 0;
462
4.46k
    parser->state.UNIX.main = PL_UNIX_HLINKS;
463
4.46k
    parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
464
4.46k
  }
465
45.3k
  return CURLE_OK;
466
45.4k
}
467
468
static CURLcode parse_unix_hlinks(struct ftp_parselist_data *parser,
469
                                  struct fileinfo *infop,
470
                                  const char c)
471
17.2k
{
472
17.2k
  size_t len = curlx_dyn_len(&infop->buf);
473
17.2k
  char *mem = curlx_dyn_ptr(&infop->buf);
474
475
17.2k
  switch(parser->state.UNIX.sub.hlinks) {
476
9.99k
  case PL_UNIX_HLINKS_PRESPACE:
477
9.99k
    if(c != ' ') {
478
4.44k
      if(ISDIGIT(c) && len) {
479
4.40k
        parser->item_offset = len - 1;
480
4.40k
        parser->item_length = 1;
481
4.40k
        parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
482
4.40k
      }
483
47
      else
484
47
        return CURLE_FTP_BAD_FILE_LIST;
485
4.44k
    }
486
9.94k
    break;
487
9.94k
  case PL_UNIX_HLINKS_NUMBER:
488
7.26k
    parser->item_length++;
489
7.26k
    if(c == ' ') {
490
4.37k
      const char *p = &mem[parser->item_offset];
491
4.37k
      curl_off_t hlinks;
492
4.37k
      mem[parser->item_offset + parser->item_length - 1] = 0;
493
494
4.37k
      if(!curlx_str_number(&p, &hlinks, LONG_MAX)) {
495
4.33k
        parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
496
4.33k
        parser->file_data->info.hardlinks = (long)hlinks;
497
4.33k
      }
498
4.37k
      parser->item_length = 0;
499
4.37k
      parser->item_offset = 0;
500
4.37k
      parser->state.UNIX.main = PL_UNIX_USER;
501
4.37k
      parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
502
4.37k
    }
503
2.88k
    else if(!ISDIGIT(c))
504
22
      return CURLE_FTP_BAD_FILE_LIST;
505
506
7.23k
    break;
507
17.2k
  }
508
17.1k
  return CURLE_OK;
509
17.2k
}
510
511
static CURLcode parse_unix_user(struct ftp_parselist_data *parser,
512
                                struct fileinfo *infop,
513
                                const char c)
514
72.4k
{
515
72.4k
  size_t len = curlx_dyn_len(&infop->buf);
516
72.4k
  char *mem = curlx_dyn_ptr(&infop->buf);
517
72.4k
  switch(parser->state.UNIX.sub.user) {
518
6.50k
  case PL_UNIX_USER_PRESPACE:
519
6.50k
    if(c != ' ' && len) {
520
4.36k
      parser->item_offset = len - 1;
521
4.36k
      parser->item_length = 1;
522
4.36k
      parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
523
4.36k
    }
524
6.50k
    break;
525
65.9k
  case PL_UNIX_USER_PARSING:
526
65.9k
    parser->item_length++;
527
65.9k
    if(c == ' ') {
528
4.31k
      mem[parser->item_offset + parser->item_length - 1] = 0;
529
4.31k
      parser->offsets.user = parser->item_offset;
530
4.31k
      parser->state.UNIX.main = PL_UNIX_GROUP;
531
4.31k
      parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
532
4.31k
      parser->item_offset = 0;
533
4.31k
      parser->item_length = 0;
534
4.31k
    }
535
65.9k
    break;
536
72.4k
  }
537
72.4k
  return CURLE_OK;
538
72.4k
}
539
540
static CURLcode parse_unix_group(struct ftp_parselist_data *parser,
541
                                 struct fileinfo *infop,
542
                                 const char c)
543
28.2k
{
544
28.2k
  size_t len = curlx_dyn_len(&infop->buf);
545
28.2k
  char *mem = curlx_dyn_ptr(&infop->buf);
546
28.2k
  switch(parser->state.UNIX.sub.group) {
547
10.0k
  case PL_UNIX_GROUP_PRESPACE:
548
10.0k
    if(c != ' ' && len) {
549
4.30k
      parser->item_offset = len - 1;
550
4.30k
      parser->item_length = 1;
551
4.30k
      parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
552
4.30k
    }
553
10.0k
    break;
554
18.2k
  case PL_UNIX_GROUP_NAME:
555
18.2k
    parser->item_length++;
556
18.2k
    if(c == ' ') {
557
4.26k
      mem[parser->item_offset + parser->item_length - 1] = 0;
558
4.26k
      parser->offsets.group = parser->item_offset;
559
4.26k
      parser->state.UNIX.main = PL_UNIX_SIZE;
560
4.26k
      parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
561
4.26k
      parser->item_offset = 0;
562
4.26k
      parser->item_length = 0;
563
4.26k
    }
564
18.2k
    break;
565
28.2k
  }
566
28.2k
  return CURLE_OK;
567
28.2k
}
568
569
static CURLcode parse_unix_size(struct ftp_parselist_data *parser,
570
                                struct fileinfo *infop,
571
                                const char c)
572
23.0k
{
573
23.0k
  size_t len = curlx_dyn_len(&infop->buf);
574
23.0k
  char *mem = curlx_dyn_ptr(&infop->buf);
575
23.0k
  switch(parser->state.UNIX.sub.size) {
576
12.9k
  case PL_UNIX_SIZE_PRESPACE:
577
12.9k
    if(c != ' ') {
578
4.25k
      if(ISDIGIT(c) && len) {
579
4.19k
        parser->item_offset = len - 1;
580
4.19k
        parser->item_length = 1;
581
4.19k
        parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
582
4.19k
      }
583
63
      else
584
63
        return CURLE_FTP_BAD_FILE_LIST;
585
4.25k
    }
586
12.8k
    break;
587
12.8k
  case PL_UNIX_SIZE_NUMBER:
588
10.0k
    parser->item_length++;
589
10.0k
    if(c == ' ') {
590
4.76k
      const char *p = mem + parser->item_offset;
591
4.76k
      curl_off_t fsize;
592
4.76k
      mem[parser->item_offset + parser->item_length - 1] = 0;
593
4.76k
      if(!curlx_str_numblanks(&p, &fsize)) {
594
4.11k
        if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) {
595
4.10k
          parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
596
4.10k
          parser->file_data->info.size = fsize;
597
4.10k
        }
598
4.11k
        parser->item_length = 0;
599
4.11k
        parser->item_offset = 0;
600
4.11k
        parser->state.UNIX.main = PL_UNIX_TIME;
601
4.11k
        parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
602
4.11k
      }
603
4.76k
    }
604
5.33k
    else if(!ISDIGIT(c))
605
60
      return CURLE_FTP_BAD_FILE_LIST;
606
607
10.0k
    break;
608
23.0k
  }
609
22.8k
  return CURLE_OK;
610
23.0k
}
611
612
static CURLcode parse_unix_time(struct ftp_parselist_data *parser,
613
                                struct fileinfo *infop,
614
                                const char c)
615
67.2k
{
616
67.2k
  size_t len = curlx_dyn_len(&infop->buf);
617
67.2k
  char *mem = curlx_dyn_ptr(&infop->buf);
618
67.2k
  struct curl_fileinfo *finfo = &infop->info;
619
620
67.2k
  switch(parser->state.UNIX.sub.time) {
621
13.5k
  case PL_UNIX_TIME_PREPART1:
622
13.5k
    if(c != ' ') {
623
4.09k
      if(ISALNUM(c) && len) {
624
4.04k
        parser->item_offset = len - 1;
625
4.04k
        parser->item_length = 1;
626
4.04k
        parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
627
4.04k
      }
628
48
      else
629
48
        return CURLE_FTP_BAD_FILE_LIST;
630
4.09k
    }
631
13.5k
    break;
632
13.8k
  case PL_UNIX_TIME_PART1:
633
13.8k
    parser->item_length++;
634
13.8k
    if(c == ' ')
635
3.92k
      parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
636
637
9.88k
    else if(!ISALNUM(c) && c != '.')
638
87
      return CURLE_FTP_BAD_FILE_LIST;
639
640
13.7k
    break;
641
13.7k
  case PL_UNIX_TIME_PREPART2:
642
7.52k
    parser->item_length++;
643
7.52k
    if(c != ' ') {
644
3.90k
      if(ISALNUM(c))
645
3.87k
        parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
646
36
      else
647
36
        return CURLE_FTP_BAD_FILE_LIST;
648
3.90k
    }
649
7.48k
    break;
650
11.7k
  case PL_UNIX_TIME_PART2:
651
11.7k
    parser->item_length++;
652
11.7k
    if(c == ' ')
653
3.78k
      parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
654
7.92k
    else if(!ISALNUM(c) && c != '.')
655
53
      return CURLE_FTP_BAD_FILE_LIST;
656
11.6k
    break;
657
11.6k
  case PL_UNIX_TIME_PREPART3:
658
5.95k
    parser->item_length++;
659
5.95k
    if(c != ' ') {
660
3.76k
      if(ISALNUM(c))
661
3.73k
        parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
662
29
      else
663
29
        return CURLE_FTP_BAD_FILE_LIST;
664
3.76k
    }
665
5.92k
    break;
666
14.7k
  case PL_UNIX_TIME_PART3:
667
14.7k
    parser->item_length++;
668
14.7k
    if(c == ' ') {
669
3.63k
      mem[parser->item_offset + parser->item_length - 1] = 0;
670
3.63k
      parser->offsets.time = parser->item_offset;
671
3.63k
      if(finfo->filetype == CURLFILETYPE_SYMLINK) {
672
395
        parser->state.UNIX.main = PL_UNIX_SYMLINK;
673
395
        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
674
395
      }
675
3.24k
      else {
676
3.24k
        parser->state.UNIX.main = PL_UNIX_FILENAME;
677
3.24k
        parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
678
3.24k
      }
679
3.63k
    }
680
11.1k
    else if(!ISALNUM(c) && c != '.' && c != ':')
681
53
      return CURLE_FTP_BAD_FILE_LIST;
682
14.6k
    break;
683
67.2k
  }
684
66.9k
  return CURLE_OK;
685
67.2k
}
686
687
static CURLcode parse_unix_filename(struct Curl_easy *data,
688
                                    struct ftp_parselist_data *parser,
689
                                    struct fileinfo *infop,
690
                                    const char c)
691
65.4k
{
692
65.4k
  size_t len = curlx_dyn_len(&infop->buf);
693
65.4k
  char *mem = curlx_dyn_ptr(&infop->buf);
694
65.4k
  CURLcode result = CURLE_OK;
695
696
65.4k
  switch(parser->state.UNIX.sub.filename) {
697
4.74k
  case PL_UNIX_FILENAME_PRESPACE:
698
4.74k
    if(c != ' ' && len) {
699
3.23k
      parser->item_offset = len - 1;
700
3.23k
      parser->item_length = 1;
701
3.23k
      parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
702
3.23k
    }
703
4.74k
    break;
704
60.6k
  case PL_UNIX_FILENAME_NAME:
705
60.6k
    parser->item_length++;
706
60.6k
    if(c == '\r')
707
0
      parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
708
709
60.6k
    else if(c == '\n') {
710
3.18k
      mem[parser->item_offset + parser->item_length - 1] = 0;
711
3.18k
      parser->offsets.filename = parser->item_offset;
712
3.18k
      parser->state.UNIX.main = PL_UNIX_FILETYPE;
713
3.18k
      result = ftp_pl_insert_finfo(data, infop);
714
3.18k
    }
715
60.6k
    break;
716
0
  case PL_UNIX_FILENAME_WINDOWSEOL:
717
0
    if(c == '\n') {
718
0
      mem[parser->item_offset + parser->item_length - 1] = 0;
719
0
      parser->offsets.filename = parser->item_offset;
720
0
      parser->state.UNIX.main = PL_UNIX_FILETYPE;
721
0
      result = ftp_pl_insert_finfo(data, infop);
722
0
    }
723
0
    else
724
0
      result = CURLE_FTP_BAD_FILE_LIST;
725
0
    break;
726
65.4k
  }
727
65.4k
  return result;
728
65.4k
}
729
730
static CURLcode parse_unix_symlink(struct Curl_easy *data,
731
                                   struct ftp_parselist_data *parser,
732
                                   struct fileinfo *infop,
733
                                   const char c)
734
29.8k
{
735
29.8k
  size_t len = curlx_dyn_len(&infop->buf);
736
29.8k
  char *mem = curlx_dyn_ptr(&infop->buf);
737
29.8k
  CURLcode result = CURLE_OK;
738
739
29.8k
  switch(parser->state.UNIX.sub.symlink) {
740
1.33k
  case PL_UNIX_SYMLINK_PRESPACE:
741
1.33k
    if(c != ' ' && len) {
742
390
      parser->item_offset = len - 1;
743
390
      parser->item_length = 1;
744
390
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
745
390
    }
746
1.33k
    break;
747
16.4k
  case PL_UNIX_SYMLINK_NAME:
748
16.4k
    parser->item_length++;
749
16.4k
    if(c == ' ')
750
3.14k
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
751
752
13.3k
    else if(c == '\r' || c == '\n')
753
22
      return CURLE_FTP_BAD_FILE_LIST;
754
755
16.4k
    break;
756
16.4k
  case PL_UNIX_SYMLINK_PRETARGET1:
757
3.13k
    parser->item_length++;
758
3.13k
    if(c == '-')
759
705
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
760
761
2.43k
    else if(c == '\r' || c == '\n')
762
3
      return CURLE_FTP_BAD_FILE_LIST;
763
2.42k
    else
764
2.42k
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
765
3.13k
    break;
766
3.13k
  case PL_UNIX_SYMLINK_PRETARGET2:
767
704
    parser->item_length++;
768
704
    if(c == '>')
769
488
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
770
216
    else if(c == '\r' || c == '\n')
771
3
      return CURLE_FTP_BAD_FILE_LIST;
772
213
    else
773
213
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
774
775
701
    break;
776
701
  case PL_UNIX_SYMLINK_PRETARGET3:
777
488
    parser->item_length++;
778
488
    if(c == ' ') {
779
288
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
780
      /* now place where is symlink following */
781
288
      mem[parser->item_offset + parser->item_length - 4] = 0;
782
288
      parser->offsets.filename = parser->item_offset;
783
288
      parser->item_length = 0;
784
288
      parser->item_offset = 0;
785
288
    }
786
200
    else if(c == '\r' || c == '\n')
787
3
      return CURLE_FTP_BAD_FILE_LIST;
788
197
    else
789
197
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
790
485
    break;
791
485
  case PL_UNIX_SYMLINK_PRETARGET4:
792
288
    if(c != '\r' && c != '\n' && len) {
793
285
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
794
285
      parser->item_offset = len - 1;
795
285
      parser->item_length = 1;
796
285
    }
797
3
    else
798
3
      return CURLE_FTP_BAD_FILE_LIST;
799
800
285
    break;
801
7.46k
  case PL_UNIX_SYMLINK_TARGET:
802
7.46k
    parser->item_length++;
803
7.46k
    if(c == '\r')
804
0
      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
805
806
7.46k
    else if(c == '\n') {
807
271
      mem[parser->item_offset + parser->item_length - 1] = 0;
808
271
      parser->offsets.symlink_target = parser->item_offset;
809
271
      result = ftp_pl_insert_finfo(data, infop);
810
271
      if(result)
811
0
        break;
812
813
271
      parser->state.UNIX.main = PL_UNIX_FILETYPE;
814
271
    }
815
7.46k
    break;
816
7.46k
  case PL_UNIX_SYMLINK_WINDOWSEOL:
817
0
    if(c == '\n') {
818
0
      mem[parser->item_offset + parser->item_length - 1] = 0;
819
0
      parser->offsets.symlink_target = parser->item_offset;
820
0
      result = ftp_pl_insert_finfo(data, infop);
821
0
      if(result)
822
0
        break;
823
824
0
      parser->state.UNIX.main = PL_UNIX_FILETYPE;
825
0
    }
826
0
    else
827
0
      result = CURLE_FTP_BAD_FILE_LIST;
828
829
0
    break;
830
29.8k
  }
831
29.8k
  return result;
832
29.8k
}
833
834
static CURLcode parse_unix(struct Curl_easy *data,
835
                           struct ftp_parselist_data *parser,
836
                           struct fileinfo *infop,
837
                           const char c)
838
357k
{
839
357k
  struct curl_fileinfo *finfo = &infop->info;
840
357k
  CURLcode result = CURLE_OK;
841
842
357k
  switch(parser->state.UNIX.main) {
843
5.86k
  case PL_UNIX_TOTALSIZE:
844
5.86k
    result = parse_unix_totalsize(parser, infop, c);
845
5.86k
    if(result)
846
80
      break;
847
5.78k
    if(parser->state.UNIX.main != PL_UNIX_FILETYPE)
848
4.16k
      break;
849
1.61k
    FALLTHROUGH();
850
4.73k
  case PL_UNIX_FILETYPE:
851
4.73k
    result = unix_filetype(c, &finfo->filetype);
852
4.73k
    if(!result) {
853
4.62k
      parser->state.UNIX.main = PL_UNIX_PERMISSION;
854
4.62k
      parser->item_length = 0;
855
4.62k
      parser->item_offset = 1;
856
4.62k
    }
857
4.73k
    break;
858
45.4k
  case PL_UNIX_PERMISSION:
859
45.4k
    result = parse_unix_permission(parser, infop, c);
860
45.4k
    break;
861
17.2k
  case PL_UNIX_HLINKS:
862
17.2k
    result = parse_unix_hlinks(parser, infop, c);
863
17.2k
    break;
864
72.4k
  case PL_UNIX_USER:
865
72.4k
    result = parse_unix_user(parser, infop, c);
866
72.4k
    break;
867
28.2k
  case PL_UNIX_GROUP:
868
28.2k
    result = parse_unix_group(parser, infop, c);
869
28.2k
    break;
870
23.0k
  case PL_UNIX_SIZE:
871
23.0k
    result = parse_unix_size(parser, infop, c);
872
23.0k
    break;
873
67.2k
  case PL_UNIX_TIME:
874
67.2k
    result = parse_unix_time(parser, infop, c);
875
67.2k
    break;
876
65.4k
  case PL_UNIX_FILENAME:
877
65.4k
    result = parse_unix_filename(data, parser, infop, c);
878
65.4k
    break;
879
29.8k
  case PL_UNIX_SYMLINK:
880
29.8k
    result = parse_unix_symlink(data, parser, infop, c);
881
29.8k
    break;
882
357k
  }
883
357k
  return result;
884
357k
}
885
886
static CURLcode parse_winnt(struct Curl_easy *data,
887
                            struct ftp_parselist_data *parser,
888
                            struct fileinfo *infop,
889
                            const char c)
890
58.9k
{
891
58.9k
  struct curl_fileinfo *finfo = &infop->info;
892
58.9k
  size_t len = curlx_dyn_len(&infop->buf);
893
58.9k
  char *mem = curlx_dyn_ptr(&infop->buf);
894
58.9k
  CURLcode result = CURLE_OK;
895
896
58.9k
  switch(parser->state.NT.main) {
897
5.45k
  case PL_WINNT_DATE:
898
5.45k
    parser->item_length++;
899
5.45k
    if(parser->item_length < 9) {
900
4.86k
      if(!strchr("0123456789-", c)) { /* only simple control */
901
41
        return CURLE_FTP_BAD_FILE_LIST;
902
41
      }
903
4.86k
    }
904
588
    else if(parser->item_length == 9) {
905
588
      if(c == ' ') {
906
582
        parser->state.NT.main = PL_WINNT_TIME;
907
582
        parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
908
582
      }
909
6
      else
910
6
        return CURLE_FTP_BAD_FILE_LIST;
911
588
    }
912
0
    else
913
0
      return CURLE_FTP_BAD_FILE_LIST;
914
5.40k
    break;
915
5.40k
  case PL_WINNT_TIME:
916
4.64k
    parser->item_length++;
917
4.64k
    switch(parser->state.NT.sub.time) {
918
3.21k
    case PL_WINNT_TIME_PRESPACE:
919
3.21k
      if(!ISBLANK(c))
920
566
        parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
921
3.21k
      break;
922
1.42k
    case PL_WINNT_TIME_TIME:
923
1.42k
      if(c == ' ') {
924
524
        parser->offsets.time = parser->item_offset;
925
524
        mem[parser->item_offset + parser->item_length - 1] = 0;
926
524
        parser->state.NT.main = PL_WINNT_DIRORSIZE;
927
524
        parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
928
524
        parser->item_length = 0;
929
524
      }
930
905
      else if(!strchr("APM0123456789:", c))
931
31
        return CURLE_FTP_BAD_FILE_LIST;
932
1.39k
      break;
933
4.64k
    }
934
4.61k
    break;
935
36.8k
  case PL_WINNT_DIRORSIZE:
936
36.8k
    switch(parser->state.NT.sub.dirorsize) {
937
1.55k
    case PL_WINNT_DIRORSIZE_PRESPACE:
938
1.55k
      if(c != ' ' && len) {
939
508
        parser->item_offset = len - 1;
940
508
        parser->item_length = 1;
941
508
        parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
942
508
      }
943
1.55k
      break;
944
35.3k
    case PL_WINNT_DIRORSIZE_CONTENT:
945
35.3k
      parser->item_length++;
946
35.3k
      if(c == ' ') {
947
480
        mem[parser->item_offset + parser->item_length - 1] = 0;
948
480
        if(!strcmp("<DIR>", mem + parser->item_offset)) {
949
11
          finfo->filetype = CURLFILETYPE_DIRECTORY;
950
11
          finfo->size = 0;
951
11
        }
952
469
        else {
953
469
          const char *p = mem + parser->item_offset;
954
469
          if(curlx_str_numblanks(&p, &finfo->size)) {
955
57
            return CURLE_FTP_BAD_FILE_LIST;
956
57
          }
957
          /* correct file type */
958
412
          parser->file_data->info.filetype = CURLFILETYPE_FILE;
959
412
        }
960
961
423
        parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
962
423
        parser->item_length = 0;
963
423
        parser->state.NT.main = PL_WINNT_FILENAME;
964
423
        parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
965
423
      }
966
35.2k
      break;
967
36.8k
    }
968
36.8k
    break;
969
36.8k
  case PL_WINNT_FILENAME:
970
11.9k
    switch(parser->state.NT.sub.filename) {
971
1.62k
    case PL_WINNT_FILENAME_PRESPACE:
972
1.62k
      if(c != ' ' && len) {
973
409
        parser->item_offset = len - 1;
974
409
        parser->item_length = 1;
975
409
        parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
976
409
      }
977
1.62k
      break;
978
10.2k
    case PL_WINNT_FILENAME_CONTENT:
979
10.2k
      parser->item_length++;
980
10.2k
      if(!len)
981
0
        return CURLE_FTP_BAD_FILE_LIST;
982
10.2k
      if(c == '\r') {
983
0
        parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
984
0
        mem[len - 1] = 0;
985
0
      }
986
10.2k
      else if(c == '\n') {
987
386
        parser->offsets.filename = parser->item_offset;
988
386
        mem[len - 1] = 0;
989
386
        result = ftp_pl_insert_finfo(data, infop);
990
386
        if(result)
991
0
          return result;
992
993
386
        parser->state.NT.main = PL_WINNT_DATE;
994
386
        parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
995
386
      }
996
10.2k
      break;
997
10.2k
    case PL_WINNT_FILENAME_WINEOL:
998
0
      if(c == '\n') {
999
0
        parser->offsets.filename = parser->item_offset;
1000
0
        result = ftp_pl_insert_finfo(data, infop);
1001
0
        if(result)
1002
0
          return result;
1003
1004
0
        parser->state.NT.main = PL_WINNT_DATE;
1005
0
        parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
1006
0
      }
1007
0
      else
1008
0
        return CURLE_FTP_BAD_FILE_LIST;
1009
1010
0
      break;
1011
11.9k
    }
1012
11.9k
    break;
1013
58.9k
  }
1014
1015
58.7k
  return CURLE_OK;
1016
58.9k
}
1017
1018
/* returns TRUE if in wildcard listing mode */
1019
bool Curl_ftp_listmode(struct Curl_easy *data)
1020
16.7M
{
1021
16.7M
  if(data->state.wildcardmatch) {
1022
54.8k
    struct WildcardData * const wildcard = data->wildcard;
1023
54.8k
    return wildcard && (wildcard->state == CURLWC_MATCHING);
1024
54.8k
  }
1025
16.6M
  return FALSE;
1026
16.7M
}
1027
1028
size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
1029
                          void *connptr)
1030
12.1k
{
1031
12.1k
  size_t bufflen = size * nmemb;
1032
12.1k
  struct Curl_easy *data = (struct Curl_easy *)connptr;
1033
12.1k
  struct ftp_wc *ftpwc = data->wildcard->ftpwc;
1034
12.1k
  struct ftp_parselist_data *parser = ftpwc->parser;
1035
12.1k
  size_t i = 0;
1036
12.1k
  CURLcode result;
1037
12.1k
  size_t retsize = bufflen;
1038
1039
12.1k
  if(parser->error) { /* error in previous call */
1040
    /* scenario:
1041
     * 1. call => OK..
1042
     * 2. call => OUT_OF_MEMORY (or other error)
1043
     * 3. (last) call => is skipped RIGHT HERE and the error is handled later
1044
     *    in wc_statemach()
1045
     */
1046
3.29k
    goto fail;
1047
3.29k
  }
1048
1049
8.81k
  if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
1050
    /* considering info about FILE response format */
1051
2.19k
    parser->os_type = ISDIGIT(buffer[0]) ? OS_TYPE_WIN_NT : OS_TYPE_UNIX;
1052
2.19k
  }
1053
1054
424k
  while(i < bufflen) { /* FSM */
1055
416k
    char c = buffer[i];
1056
416k
    struct fileinfo *infop;
1057
416k
    if(!parser->file_data) { /* tmp file data is not allocated yet */
1058
5.48k
      parser->file_data = Curl_fileinfo_alloc();
1059
5.48k
      if(!parser->file_data) {
1060
1
        parser->error = CURLE_OUT_OF_MEMORY;
1061
1
        goto fail;
1062
1
      }
1063
5.48k
      parser->item_offset = 0;
1064
5.48k
      parser->item_length = 0;
1065
5.48k
      curlx_dyn_init(&parser->file_data->buf, MAX_FTPLIST_BUFFER);
1066
5.48k
    }
1067
1068
416k
    infop = parser->file_data;
1069
1070
416k
    if(curlx_dyn_addn(&infop->buf, &c, 1)) {
1071
3
      parser->error = CURLE_OUT_OF_MEMORY;
1072
3
      goto fail;
1073
3
    }
1074
1075
416k
    switch(parser->os_type) {
1076
357k
    case OS_TYPE_UNIX:
1077
357k
      result = parse_unix(data, parser, infop, c);
1078
357k
      break;
1079
58.9k
    case OS_TYPE_WIN_NT:
1080
58.9k
      result = parse_winnt(data, parser, infop, c);
1081
58.9k
      break;
1082
0
    default:
1083
0
      retsize = bufflen + 1;
1084
0
      goto fail;
1085
416k
    }
1086
416k
    if(result) {
1087
973
      parser->error = result;
1088
973
      goto fail;
1089
973
    }
1090
1091
415k
    i++;
1092
415k
  }
1093
7.83k
  return retsize;
1094
1095
4.27k
fail:
1096
1097
  /* Clean up any allocated memory. */
1098
4.27k
  if(parser->file_data) {
1099
976
    Curl_fileinfo_cleanup(parser->file_data);
1100
976
    parser->file_data = NULL;
1101
976
  }
1102
1103
4.27k
  return retsize;
1104
8.81k
}
1105
1106
#endif /* !CURL_DISABLE_FTP */