113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci/**
2613498266Sopenharmony_ci * Now implemented:
2713498266Sopenharmony_ci *
2813498266Sopenharmony_ci * 1) Unix version 1
2913498266Sopenharmony_ci * drwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog
3013498266Sopenharmony_ci * 2) Unix version 2
3113498266Sopenharmony_ci * drwxr-xr-x 1 user01 ftp  512 Jan 29 1997  prog
3213498266Sopenharmony_ci * 3) Unix version 3
3313498266Sopenharmony_ci * drwxr-xr-x 1      1   1  512 Jan 29 23:32 prog
3413498266Sopenharmony_ci * 4) Unix symlink
3513498266Sopenharmony_ci * lrwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog -> prog2000
3613498266Sopenharmony_ci * 5) DOS style
3713498266Sopenharmony_ci * 01-29-97 11:32PM <DIR> prog
3813498266Sopenharmony_ci */
3913498266Sopenharmony_ci
4013498266Sopenharmony_ci#include "curl_setup.h"
4113498266Sopenharmony_ci
4213498266Sopenharmony_ci#ifndef CURL_DISABLE_FTP
4313498266Sopenharmony_ci
4413498266Sopenharmony_ci#include <curl/curl.h>
4513498266Sopenharmony_ci
4613498266Sopenharmony_ci#include "urldata.h"
4713498266Sopenharmony_ci#include "fileinfo.h"
4813498266Sopenharmony_ci#include "llist.h"
4913498266Sopenharmony_ci#include "strtoofft.h"
5013498266Sopenharmony_ci#include "ftp.h"
5113498266Sopenharmony_ci#include "ftplistparser.h"
5213498266Sopenharmony_ci#include "curl_fnmatch.h"
5313498266Sopenharmony_ci#include "curl_memory.h"
5413498266Sopenharmony_ci#include "multiif.h"
5513498266Sopenharmony_ci/* The last #include file should be: */
5613498266Sopenharmony_ci#include "memdebug.h"
5713498266Sopenharmony_ci
5813498266Sopenharmony_citypedef enum {
5913498266Sopenharmony_ci  PL_UNIX_TOTALSIZE = 0,
6013498266Sopenharmony_ci  PL_UNIX_FILETYPE,
6113498266Sopenharmony_ci  PL_UNIX_PERMISSION,
6213498266Sopenharmony_ci  PL_UNIX_HLINKS,
6313498266Sopenharmony_ci  PL_UNIX_USER,
6413498266Sopenharmony_ci  PL_UNIX_GROUP,
6513498266Sopenharmony_ci  PL_UNIX_SIZE,
6613498266Sopenharmony_ci  PL_UNIX_TIME,
6713498266Sopenharmony_ci  PL_UNIX_FILENAME,
6813498266Sopenharmony_ci  PL_UNIX_SYMLINK
6913498266Sopenharmony_ci} pl_unix_mainstate;
7013498266Sopenharmony_ci
7113498266Sopenharmony_citypedef union {
7213498266Sopenharmony_ci  enum {
7313498266Sopenharmony_ci    PL_UNIX_TOTALSIZE_INIT = 0,
7413498266Sopenharmony_ci    PL_UNIX_TOTALSIZE_READING
7513498266Sopenharmony_ci  } total_dirsize;
7613498266Sopenharmony_ci
7713498266Sopenharmony_ci  enum {
7813498266Sopenharmony_ci    PL_UNIX_HLINKS_PRESPACE = 0,
7913498266Sopenharmony_ci    PL_UNIX_HLINKS_NUMBER
8013498266Sopenharmony_ci  } hlinks;
8113498266Sopenharmony_ci
8213498266Sopenharmony_ci  enum {
8313498266Sopenharmony_ci    PL_UNIX_USER_PRESPACE = 0,
8413498266Sopenharmony_ci    PL_UNIX_USER_PARSING
8513498266Sopenharmony_ci  } user;
8613498266Sopenharmony_ci
8713498266Sopenharmony_ci  enum {
8813498266Sopenharmony_ci    PL_UNIX_GROUP_PRESPACE = 0,
8913498266Sopenharmony_ci    PL_UNIX_GROUP_NAME
9013498266Sopenharmony_ci  } group;
9113498266Sopenharmony_ci
9213498266Sopenharmony_ci  enum {
9313498266Sopenharmony_ci    PL_UNIX_SIZE_PRESPACE = 0,
9413498266Sopenharmony_ci    PL_UNIX_SIZE_NUMBER
9513498266Sopenharmony_ci  } size;
9613498266Sopenharmony_ci
9713498266Sopenharmony_ci  enum {
9813498266Sopenharmony_ci    PL_UNIX_TIME_PREPART1 = 0,
9913498266Sopenharmony_ci    PL_UNIX_TIME_PART1,
10013498266Sopenharmony_ci    PL_UNIX_TIME_PREPART2,
10113498266Sopenharmony_ci    PL_UNIX_TIME_PART2,
10213498266Sopenharmony_ci    PL_UNIX_TIME_PREPART3,
10313498266Sopenharmony_ci    PL_UNIX_TIME_PART3
10413498266Sopenharmony_ci  } time;
10513498266Sopenharmony_ci
10613498266Sopenharmony_ci  enum {
10713498266Sopenharmony_ci    PL_UNIX_FILENAME_PRESPACE = 0,
10813498266Sopenharmony_ci    PL_UNIX_FILENAME_NAME,
10913498266Sopenharmony_ci    PL_UNIX_FILENAME_WINDOWSEOL
11013498266Sopenharmony_ci  } filename;
11113498266Sopenharmony_ci
11213498266Sopenharmony_ci  enum {
11313498266Sopenharmony_ci    PL_UNIX_SYMLINK_PRESPACE = 0,
11413498266Sopenharmony_ci    PL_UNIX_SYMLINK_NAME,
11513498266Sopenharmony_ci    PL_UNIX_SYMLINK_PRETARGET1,
11613498266Sopenharmony_ci    PL_UNIX_SYMLINK_PRETARGET2,
11713498266Sopenharmony_ci    PL_UNIX_SYMLINK_PRETARGET3,
11813498266Sopenharmony_ci    PL_UNIX_SYMLINK_PRETARGET4,
11913498266Sopenharmony_ci    PL_UNIX_SYMLINK_TARGET,
12013498266Sopenharmony_ci    PL_UNIX_SYMLINK_WINDOWSEOL
12113498266Sopenharmony_ci  } symlink;
12213498266Sopenharmony_ci} pl_unix_substate;
12313498266Sopenharmony_ci
12413498266Sopenharmony_citypedef enum {
12513498266Sopenharmony_ci  PL_WINNT_DATE = 0,
12613498266Sopenharmony_ci  PL_WINNT_TIME,
12713498266Sopenharmony_ci  PL_WINNT_DIRORSIZE,
12813498266Sopenharmony_ci  PL_WINNT_FILENAME
12913498266Sopenharmony_ci} pl_winNT_mainstate;
13013498266Sopenharmony_ci
13113498266Sopenharmony_citypedef union {
13213498266Sopenharmony_ci  enum {
13313498266Sopenharmony_ci    PL_WINNT_TIME_PRESPACE = 0,
13413498266Sopenharmony_ci    PL_WINNT_TIME_TIME
13513498266Sopenharmony_ci  } time;
13613498266Sopenharmony_ci  enum {
13713498266Sopenharmony_ci    PL_WINNT_DIRORSIZE_PRESPACE = 0,
13813498266Sopenharmony_ci    PL_WINNT_DIRORSIZE_CONTENT
13913498266Sopenharmony_ci  } dirorsize;
14013498266Sopenharmony_ci  enum {
14113498266Sopenharmony_ci    PL_WINNT_FILENAME_PRESPACE = 0,
14213498266Sopenharmony_ci    PL_WINNT_FILENAME_CONTENT,
14313498266Sopenharmony_ci    PL_WINNT_FILENAME_WINEOL
14413498266Sopenharmony_ci  } filename;
14513498266Sopenharmony_ci} pl_winNT_substate;
14613498266Sopenharmony_ci
14713498266Sopenharmony_ci/* This struct is used in wildcard downloading - for parsing LIST response */
14813498266Sopenharmony_cistruct ftp_parselist_data {
14913498266Sopenharmony_ci  enum {
15013498266Sopenharmony_ci    OS_TYPE_UNKNOWN = 0,
15113498266Sopenharmony_ci    OS_TYPE_UNIX,
15213498266Sopenharmony_ci    OS_TYPE_WIN_NT
15313498266Sopenharmony_ci  } os_type;
15413498266Sopenharmony_ci
15513498266Sopenharmony_ci  union {
15613498266Sopenharmony_ci    struct {
15713498266Sopenharmony_ci      pl_unix_mainstate main;
15813498266Sopenharmony_ci      pl_unix_substate sub;
15913498266Sopenharmony_ci    } UNIX;
16013498266Sopenharmony_ci
16113498266Sopenharmony_ci    struct {
16213498266Sopenharmony_ci      pl_winNT_mainstate main;
16313498266Sopenharmony_ci      pl_winNT_substate sub;
16413498266Sopenharmony_ci    } NT;
16513498266Sopenharmony_ci  } state;
16613498266Sopenharmony_ci
16713498266Sopenharmony_ci  CURLcode error;
16813498266Sopenharmony_ci  struct fileinfo *file_data;
16913498266Sopenharmony_ci  unsigned int item_length;
17013498266Sopenharmony_ci  size_t item_offset;
17113498266Sopenharmony_ci  struct {
17213498266Sopenharmony_ci    size_t filename;
17313498266Sopenharmony_ci    size_t user;
17413498266Sopenharmony_ci    size_t group;
17513498266Sopenharmony_ci    size_t time;
17613498266Sopenharmony_ci    size_t perm;
17713498266Sopenharmony_ci    size_t symlink_target;
17813498266Sopenharmony_ci  } offsets;
17913498266Sopenharmony_ci};
18013498266Sopenharmony_ci
18113498266Sopenharmony_cistatic void fileinfo_dtor(void *user, void *element)
18213498266Sopenharmony_ci{
18313498266Sopenharmony_ci  (void)user;
18413498266Sopenharmony_ci  Curl_fileinfo_cleanup(element);
18513498266Sopenharmony_ci}
18613498266Sopenharmony_ci
18713498266Sopenharmony_ciCURLcode Curl_wildcard_init(struct WildcardData *wc)
18813498266Sopenharmony_ci{
18913498266Sopenharmony_ci  Curl_llist_init(&wc->filelist, fileinfo_dtor);
19013498266Sopenharmony_ci  wc->state = CURLWC_INIT;
19113498266Sopenharmony_ci
19213498266Sopenharmony_ci  return CURLE_OK;
19313498266Sopenharmony_ci}
19413498266Sopenharmony_ci
19513498266Sopenharmony_civoid Curl_wildcard_dtor(struct WildcardData **wcp)
19613498266Sopenharmony_ci{
19713498266Sopenharmony_ci  struct WildcardData *wc = *wcp;
19813498266Sopenharmony_ci  if(!wc)
19913498266Sopenharmony_ci    return;
20013498266Sopenharmony_ci
20113498266Sopenharmony_ci  if(wc->dtor) {
20213498266Sopenharmony_ci    wc->dtor(wc->ftpwc);
20313498266Sopenharmony_ci    wc->dtor = ZERO_NULL;
20413498266Sopenharmony_ci    wc->ftpwc = NULL;
20513498266Sopenharmony_ci  }
20613498266Sopenharmony_ci  DEBUGASSERT(wc->ftpwc == NULL);
20713498266Sopenharmony_ci
20813498266Sopenharmony_ci  Curl_llist_destroy(&wc->filelist, NULL);
20913498266Sopenharmony_ci  free(wc->path);
21013498266Sopenharmony_ci  wc->path = NULL;
21113498266Sopenharmony_ci  free(wc->pattern);
21213498266Sopenharmony_ci  wc->pattern = NULL;
21313498266Sopenharmony_ci  wc->state = CURLWC_INIT;
21413498266Sopenharmony_ci  free(wc);
21513498266Sopenharmony_ci  *wcp = NULL;
21613498266Sopenharmony_ci}
21713498266Sopenharmony_ci
21813498266Sopenharmony_cistruct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
21913498266Sopenharmony_ci{
22013498266Sopenharmony_ci  return calloc(1, sizeof(struct ftp_parselist_data));
22113498266Sopenharmony_ci}
22213498266Sopenharmony_ci
22313498266Sopenharmony_ci
22413498266Sopenharmony_civoid Curl_ftp_parselist_data_free(struct ftp_parselist_data **parserp)
22513498266Sopenharmony_ci{
22613498266Sopenharmony_ci  struct ftp_parselist_data *parser = *parserp;
22713498266Sopenharmony_ci  if(parser)
22813498266Sopenharmony_ci    Curl_fileinfo_cleanup(parser->file_data);
22913498266Sopenharmony_ci  free(parser);
23013498266Sopenharmony_ci  *parserp = NULL;
23113498266Sopenharmony_ci}
23213498266Sopenharmony_ci
23313498266Sopenharmony_ci
23413498266Sopenharmony_ciCURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
23513498266Sopenharmony_ci{
23613498266Sopenharmony_ci  return pl_data->error;
23713498266Sopenharmony_ci}
23813498266Sopenharmony_ci
23913498266Sopenharmony_ci
24013498266Sopenharmony_ci#define FTP_LP_MALFORMATED_PERM 0x01000000
24113498266Sopenharmony_ci
24213498266Sopenharmony_cistatic unsigned int ftp_pl_get_permission(const char *str)
24313498266Sopenharmony_ci{
24413498266Sopenharmony_ci  unsigned int permissions = 0;
24513498266Sopenharmony_ci  /* USER */
24613498266Sopenharmony_ci  if(str[0] == 'r')
24713498266Sopenharmony_ci    permissions |= 1 << 8;
24813498266Sopenharmony_ci  else if(str[0] != '-')
24913498266Sopenharmony_ci    permissions |= FTP_LP_MALFORMATED_PERM;
25013498266Sopenharmony_ci  if(str[1] == 'w')
25113498266Sopenharmony_ci    permissions |= 1 << 7;
25213498266Sopenharmony_ci  else if(str[1] != '-')
25313498266Sopenharmony_ci    permissions |= FTP_LP_MALFORMATED_PERM;
25413498266Sopenharmony_ci
25513498266Sopenharmony_ci  if(str[2] == 'x')
25613498266Sopenharmony_ci    permissions |= 1 << 6;
25713498266Sopenharmony_ci  else if(str[2] == 's') {
25813498266Sopenharmony_ci    permissions |= 1 << 6;
25913498266Sopenharmony_ci    permissions |= 1 << 11;
26013498266Sopenharmony_ci  }
26113498266Sopenharmony_ci  else if(str[2] == 'S')
26213498266Sopenharmony_ci    permissions |= 1 << 11;
26313498266Sopenharmony_ci  else if(str[2] != '-')
26413498266Sopenharmony_ci    permissions |= FTP_LP_MALFORMATED_PERM;
26513498266Sopenharmony_ci  /* GROUP */
26613498266Sopenharmony_ci  if(str[3] == 'r')
26713498266Sopenharmony_ci    permissions |= 1 << 5;
26813498266Sopenharmony_ci  else if(str[3] != '-')
26913498266Sopenharmony_ci    permissions |= FTP_LP_MALFORMATED_PERM;
27013498266Sopenharmony_ci  if(str[4] == 'w')
27113498266Sopenharmony_ci    permissions |= 1 << 4;
27213498266Sopenharmony_ci  else if(str[4] != '-')
27313498266Sopenharmony_ci    permissions |= FTP_LP_MALFORMATED_PERM;
27413498266Sopenharmony_ci  if(str[5] == 'x')
27513498266Sopenharmony_ci    permissions |= 1 << 3;
27613498266Sopenharmony_ci  else if(str[5] == 's') {
27713498266Sopenharmony_ci    permissions |= 1 << 3;
27813498266Sopenharmony_ci    permissions |= 1 << 10;
27913498266Sopenharmony_ci  }
28013498266Sopenharmony_ci  else if(str[5] == 'S')
28113498266Sopenharmony_ci    permissions |= 1 << 10;
28213498266Sopenharmony_ci  else if(str[5] != '-')
28313498266Sopenharmony_ci    permissions |= FTP_LP_MALFORMATED_PERM;
28413498266Sopenharmony_ci  /* others */
28513498266Sopenharmony_ci  if(str[6] == 'r')
28613498266Sopenharmony_ci    permissions |= 1 << 2;
28713498266Sopenharmony_ci  else if(str[6] != '-')
28813498266Sopenharmony_ci    permissions |= FTP_LP_MALFORMATED_PERM;
28913498266Sopenharmony_ci  if(str[7] == 'w')
29013498266Sopenharmony_ci    permissions |= 1 << 1;
29113498266Sopenharmony_ci  else if(str[7] != '-')
29213498266Sopenharmony_ci      permissions |= FTP_LP_MALFORMATED_PERM;
29313498266Sopenharmony_ci  if(str[8] == 'x')
29413498266Sopenharmony_ci    permissions |= 1;
29513498266Sopenharmony_ci  else if(str[8] == 't') {
29613498266Sopenharmony_ci    permissions |= 1;
29713498266Sopenharmony_ci    permissions |= 1 << 9;
29813498266Sopenharmony_ci  }
29913498266Sopenharmony_ci  else if(str[8] == 'T')
30013498266Sopenharmony_ci    permissions |= 1 << 9;
30113498266Sopenharmony_ci  else if(str[8] != '-')
30213498266Sopenharmony_ci    permissions |= FTP_LP_MALFORMATED_PERM;
30313498266Sopenharmony_ci
30413498266Sopenharmony_ci  return permissions;
30513498266Sopenharmony_ci}
30613498266Sopenharmony_ci
30713498266Sopenharmony_cistatic CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
30813498266Sopenharmony_ci                                    struct fileinfo *infop)
30913498266Sopenharmony_ci{
31013498266Sopenharmony_ci  curl_fnmatch_callback compare;
31113498266Sopenharmony_ci  struct WildcardData *wc = data->wildcard;
31213498266Sopenharmony_ci  struct ftp_wc *ftpwc = wc->ftpwc;
31313498266Sopenharmony_ci  struct Curl_llist *llist = &wc->filelist;
31413498266Sopenharmony_ci  struct ftp_parselist_data *parser = ftpwc->parser;
31513498266Sopenharmony_ci  bool add = TRUE;
31613498266Sopenharmony_ci  struct curl_fileinfo *finfo = &infop->info;
31713498266Sopenharmony_ci
31813498266Sopenharmony_ci  /* set the finfo pointers */
31913498266Sopenharmony_ci  char *str = Curl_dyn_ptr(&infop->buf);
32013498266Sopenharmony_ci  finfo->filename       = str + parser->offsets.filename;
32113498266Sopenharmony_ci  finfo->strings.group  = parser->offsets.group ?
32213498266Sopenharmony_ci                          str + parser->offsets.group : NULL;
32313498266Sopenharmony_ci  finfo->strings.perm   = parser->offsets.perm ?
32413498266Sopenharmony_ci                          str + parser->offsets.perm : NULL;
32513498266Sopenharmony_ci  finfo->strings.target = parser->offsets.symlink_target ?
32613498266Sopenharmony_ci                          str + parser->offsets.symlink_target : NULL;
32713498266Sopenharmony_ci  finfo->strings.time   = str + parser->offsets.time;
32813498266Sopenharmony_ci  finfo->strings.user   = parser->offsets.user ?
32913498266Sopenharmony_ci                          str + parser->offsets.user : NULL;
33013498266Sopenharmony_ci
33113498266Sopenharmony_ci  /* get correct fnmatch callback */
33213498266Sopenharmony_ci  compare = data->set.fnmatch;
33313498266Sopenharmony_ci  if(!compare)
33413498266Sopenharmony_ci    compare = Curl_fnmatch;
33513498266Sopenharmony_ci
33613498266Sopenharmony_ci  /* filter pattern-corresponding filenames */
33713498266Sopenharmony_ci  Curl_set_in_callback(data, true);
33813498266Sopenharmony_ci  if(compare(data->set.fnmatch_data, wc->pattern,
33913498266Sopenharmony_ci             finfo->filename) == 0) {
34013498266Sopenharmony_ci    /* discard symlink which is containing multiple " -> " */
34113498266Sopenharmony_ci    if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
34213498266Sopenharmony_ci       (strstr(finfo->strings.target, " -> "))) {
34313498266Sopenharmony_ci      add = FALSE;
34413498266Sopenharmony_ci    }
34513498266Sopenharmony_ci  }
34613498266Sopenharmony_ci  else {
34713498266Sopenharmony_ci    add = FALSE;
34813498266Sopenharmony_ci  }
34913498266Sopenharmony_ci  Curl_set_in_callback(data, false);
35013498266Sopenharmony_ci
35113498266Sopenharmony_ci  if(add) {
35213498266Sopenharmony_ci    Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
35313498266Sopenharmony_ci  }
35413498266Sopenharmony_ci  else {
35513498266Sopenharmony_ci    Curl_fileinfo_cleanup(infop);
35613498266Sopenharmony_ci  }
35713498266Sopenharmony_ci
35813498266Sopenharmony_ci  ftpwc->parser->file_data = NULL;
35913498266Sopenharmony_ci  return CURLE_OK;
36013498266Sopenharmony_ci}
36113498266Sopenharmony_ci
36213498266Sopenharmony_ci#define MAX_FTPLIST_BUFFER 10000 /* arbitrarily set */
36313498266Sopenharmony_ci
36413498266Sopenharmony_cisize_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
36513498266Sopenharmony_ci                          void *connptr)
36613498266Sopenharmony_ci{
36713498266Sopenharmony_ci  size_t bufflen = size*nmemb;
36813498266Sopenharmony_ci  struct Curl_easy *data = (struct Curl_easy *)connptr;
36913498266Sopenharmony_ci  struct ftp_wc *ftpwc = data->wildcard->ftpwc;
37013498266Sopenharmony_ci  struct ftp_parselist_data *parser = ftpwc->parser;
37113498266Sopenharmony_ci  size_t i = 0;
37213498266Sopenharmony_ci  CURLcode result;
37313498266Sopenharmony_ci  size_t retsize = bufflen;
37413498266Sopenharmony_ci
37513498266Sopenharmony_ci  if(parser->error) { /* error in previous call */
37613498266Sopenharmony_ci    /* scenario:
37713498266Sopenharmony_ci     * 1. call => OK..
37813498266Sopenharmony_ci     * 2. call => OUT_OF_MEMORY (or other error)
37913498266Sopenharmony_ci     * 3. (last) call => is skipped RIGHT HERE and the error is handled later
38013498266Sopenharmony_ci     *    in wc_statemach()
38113498266Sopenharmony_ci     */
38213498266Sopenharmony_ci    goto fail;
38313498266Sopenharmony_ci  }
38413498266Sopenharmony_ci
38513498266Sopenharmony_ci  if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
38613498266Sopenharmony_ci    /* considering info about FILE response format */
38713498266Sopenharmony_ci    parser->os_type = ISDIGIT(buffer[0]) ? OS_TYPE_WIN_NT : OS_TYPE_UNIX;
38813498266Sopenharmony_ci  }
38913498266Sopenharmony_ci
39013498266Sopenharmony_ci  while(i < bufflen) { /* FSM */
39113498266Sopenharmony_ci    char *mem;
39213498266Sopenharmony_ci    size_t len; /* number of bytes of data in the dynbuf */
39313498266Sopenharmony_ci    char c = buffer[i];
39413498266Sopenharmony_ci    struct fileinfo *infop;
39513498266Sopenharmony_ci    struct curl_fileinfo *finfo;
39613498266Sopenharmony_ci    if(!parser->file_data) { /* tmp file data is not allocated yet */
39713498266Sopenharmony_ci      parser->file_data = Curl_fileinfo_alloc();
39813498266Sopenharmony_ci      if(!parser->file_data) {
39913498266Sopenharmony_ci        parser->error = CURLE_OUT_OF_MEMORY;
40013498266Sopenharmony_ci        goto fail;
40113498266Sopenharmony_ci      }
40213498266Sopenharmony_ci      parser->item_offset = 0;
40313498266Sopenharmony_ci      parser->item_length = 0;
40413498266Sopenharmony_ci      Curl_dyn_init(&parser->file_data->buf, MAX_FTPLIST_BUFFER);
40513498266Sopenharmony_ci    }
40613498266Sopenharmony_ci
40713498266Sopenharmony_ci    infop = parser->file_data;
40813498266Sopenharmony_ci    finfo = &infop->info;
40913498266Sopenharmony_ci
41013498266Sopenharmony_ci    if(Curl_dyn_addn(&infop->buf, &c, 1)) {
41113498266Sopenharmony_ci      parser->error = CURLE_OUT_OF_MEMORY;
41213498266Sopenharmony_ci      goto fail;
41313498266Sopenharmony_ci    }
41413498266Sopenharmony_ci    len = Curl_dyn_len(&infop->buf);
41513498266Sopenharmony_ci    mem = Curl_dyn_ptr(&infop->buf);
41613498266Sopenharmony_ci
41713498266Sopenharmony_ci    switch(parser->os_type) {
41813498266Sopenharmony_ci    case OS_TYPE_UNIX:
41913498266Sopenharmony_ci      switch(parser->state.UNIX.main) {
42013498266Sopenharmony_ci      case PL_UNIX_TOTALSIZE:
42113498266Sopenharmony_ci        switch(parser->state.UNIX.sub.total_dirsize) {
42213498266Sopenharmony_ci        case PL_UNIX_TOTALSIZE_INIT:
42313498266Sopenharmony_ci          if(c == 't') {
42413498266Sopenharmony_ci            parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
42513498266Sopenharmony_ci            parser->item_length++;
42613498266Sopenharmony_ci          }
42713498266Sopenharmony_ci          else {
42813498266Sopenharmony_ci            parser->state.UNIX.main = PL_UNIX_FILETYPE;
42913498266Sopenharmony_ci            /* start FSM again not considering size of directory */
43013498266Sopenharmony_ci            Curl_dyn_reset(&infop->buf);
43113498266Sopenharmony_ci            continue;
43213498266Sopenharmony_ci          }
43313498266Sopenharmony_ci          break;
43413498266Sopenharmony_ci        case PL_UNIX_TOTALSIZE_READING:
43513498266Sopenharmony_ci          parser->item_length++;
43613498266Sopenharmony_ci          if(c == '\r') {
43713498266Sopenharmony_ci            parser->item_length--;
43813498266Sopenharmony_ci            Curl_dyn_setlen(&infop->buf, --len);
43913498266Sopenharmony_ci          }
44013498266Sopenharmony_ci          else if(c == '\n') {
44113498266Sopenharmony_ci            mem[parser->item_length - 1] = 0;
44213498266Sopenharmony_ci            if(!strncmp("total ", mem, 6)) {
44313498266Sopenharmony_ci              char *endptr = mem + 6;
44413498266Sopenharmony_ci              /* here we can deal with directory size, pass the leading
44513498266Sopenharmony_ci                 whitespace and then the digits */
44613498266Sopenharmony_ci              while(ISBLANK(*endptr))
44713498266Sopenharmony_ci                endptr++;
44813498266Sopenharmony_ci              while(ISDIGIT(*endptr))
44913498266Sopenharmony_ci                endptr++;
45013498266Sopenharmony_ci              if(*endptr) {
45113498266Sopenharmony_ci                parser->error = CURLE_FTP_BAD_FILE_LIST;
45213498266Sopenharmony_ci                goto fail;
45313498266Sopenharmony_ci              }
45413498266Sopenharmony_ci              parser->state.UNIX.main = PL_UNIX_FILETYPE;
45513498266Sopenharmony_ci              Curl_dyn_reset(&infop->buf);
45613498266Sopenharmony_ci            }
45713498266Sopenharmony_ci            else {
45813498266Sopenharmony_ci              parser->error = CURLE_FTP_BAD_FILE_LIST;
45913498266Sopenharmony_ci              goto fail;
46013498266Sopenharmony_ci            }
46113498266Sopenharmony_ci          }
46213498266Sopenharmony_ci          break;
46313498266Sopenharmony_ci        }
46413498266Sopenharmony_ci        break;
46513498266Sopenharmony_ci      case PL_UNIX_FILETYPE:
46613498266Sopenharmony_ci        switch(c) {
46713498266Sopenharmony_ci        case '-':
46813498266Sopenharmony_ci          finfo->filetype = CURLFILETYPE_FILE;
46913498266Sopenharmony_ci          break;
47013498266Sopenharmony_ci        case 'd':
47113498266Sopenharmony_ci          finfo->filetype = CURLFILETYPE_DIRECTORY;
47213498266Sopenharmony_ci          break;
47313498266Sopenharmony_ci        case 'l':
47413498266Sopenharmony_ci          finfo->filetype = CURLFILETYPE_SYMLINK;
47513498266Sopenharmony_ci          break;
47613498266Sopenharmony_ci        case 'p':
47713498266Sopenharmony_ci          finfo->filetype = CURLFILETYPE_NAMEDPIPE;
47813498266Sopenharmony_ci          break;
47913498266Sopenharmony_ci        case 's':
48013498266Sopenharmony_ci          finfo->filetype = CURLFILETYPE_SOCKET;
48113498266Sopenharmony_ci          break;
48213498266Sopenharmony_ci        case 'c':
48313498266Sopenharmony_ci          finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
48413498266Sopenharmony_ci          break;
48513498266Sopenharmony_ci        case 'b':
48613498266Sopenharmony_ci          finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
48713498266Sopenharmony_ci          break;
48813498266Sopenharmony_ci        case 'D':
48913498266Sopenharmony_ci          finfo->filetype = CURLFILETYPE_DOOR;
49013498266Sopenharmony_ci          break;
49113498266Sopenharmony_ci        default:
49213498266Sopenharmony_ci          parser->error = CURLE_FTP_BAD_FILE_LIST;
49313498266Sopenharmony_ci          goto fail;
49413498266Sopenharmony_ci        }
49513498266Sopenharmony_ci        parser->state.UNIX.main = PL_UNIX_PERMISSION;
49613498266Sopenharmony_ci        parser->item_length = 0;
49713498266Sopenharmony_ci        parser->item_offset = 1;
49813498266Sopenharmony_ci        break;
49913498266Sopenharmony_ci      case PL_UNIX_PERMISSION:
50013498266Sopenharmony_ci        parser->item_length++;
50113498266Sopenharmony_ci        if(parser->item_length <= 9) {
50213498266Sopenharmony_ci          if(!strchr("rwx-tTsS", c)) {
50313498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
50413498266Sopenharmony_ci            goto fail;
50513498266Sopenharmony_ci          }
50613498266Sopenharmony_ci        }
50713498266Sopenharmony_ci        else if(parser->item_length == 10) {
50813498266Sopenharmony_ci          unsigned int perm;
50913498266Sopenharmony_ci          if(c != ' ') {
51013498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
51113498266Sopenharmony_ci            goto fail;
51213498266Sopenharmony_ci          }
51313498266Sopenharmony_ci          mem[10] = 0; /* terminate permissions */
51413498266Sopenharmony_ci          perm = ftp_pl_get_permission(mem + parser->item_offset);
51513498266Sopenharmony_ci          if(perm & FTP_LP_MALFORMATED_PERM) {
51613498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
51713498266Sopenharmony_ci            goto fail;
51813498266Sopenharmony_ci          }
51913498266Sopenharmony_ci          parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
52013498266Sopenharmony_ci          parser->file_data->info.perm = perm;
52113498266Sopenharmony_ci          parser->offsets.perm = parser->item_offset;
52213498266Sopenharmony_ci
52313498266Sopenharmony_ci          parser->item_length = 0;
52413498266Sopenharmony_ci          parser->state.UNIX.main = PL_UNIX_HLINKS;
52513498266Sopenharmony_ci          parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
52613498266Sopenharmony_ci        }
52713498266Sopenharmony_ci        break;
52813498266Sopenharmony_ci      case PL_UNIX_HLINKS:
52913498266Sopenharmony_ci        switch(parser->state.UNIX.sub.hlinks) {
53013498266Sopenharmony_ci        case PL_UNIX_HLINKS_PRESPACE:
53113498266Sopenharmony_ci          if(c != ' ') {
53213498266Sopenharmony_ci            if(ISDIGIT(c)) {
53313498266Sopenharmony_ci              parser->item_offset = len - 1;
53413498266Sopenharmony_ci              parser->item_length = 1;
53513498266Sopenharmony_ci              parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
53613498266Sopenharmony_ci            }
53713498266Sopenharmony_ci            else {
53813498266Sopenharmony_ci              parser->error = CURLE_FTP_BAD_FILE_LIST;
53913498266Sopenharmony_ci              goto fail;
54013498266Sopenharmony_ci            }
54113498266Sopenharmony_ci          }
54213498266Sopenharmony_ci          break;
54313498266Sopenharmony_ci        case PL_UNIX_HLINKS_NUMBER:
54413498266Sopenharmony_ci          parser->item_length ++;
54513498266Sopenharmony_ci          if(c == ' ') {
54613498266Sopenharmony_ci            char *p;
54713498266Sopenharmony_ci            long int hlinks;
54813498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 1] = 0;
54913498266Sopenharmony_ci            hlinks = strtol(mem + parser->item_offset, &p, 10);
55013498266Sopenharmony_ci            if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
55113498266Sopenharmony_ci              parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
55213498266Sopenharmony_ci              parser->file_data->info.hardlinks = hlinks;
55313498266Sopenharmony_ci            }
55413498266Sopenharmony_ci            parser->item_length = 0;
55513498266Sopenharmony_ci            parser->item_offset = 0;
55613498266Sopenharmony_ci            parser->state.UNIX.main = PL_UNIX_USER;
55713498266Sopenharmony_ci            parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
55813498266Sopenharmony_ci          }
55913498266Sopenharmony_ci          else if(!ISDIGIT(c)) {
56013498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
56113498266Sopenharmony_ci            goto fail;
56213498266Sopenharmony_ci          }
56313498266Sopenharmony_ci          break;
56413498266Sopenharmony_ci        }
56513498266Sopenharmony_ci        break;
56613498266Sopenharmony_ci      case PL_UNIX_USER:
56713498266Sopenharmony_ci        switch(parser->state.UNIX.sub.user) {
56813498266Sopenharmony_ci        case PL_UNIX_USER_PRESPACE:
56913498266Sopenharmony_ci          if(c != ' ') {
57013498266Sopenharmony_ci            parser->item_offset = len - 1;
57113498266Sopenharmony_ci            parser->item_length = 1;
57213498266Sopenharmony_ci            parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
57313498266Sopenharmony_ci          }
57413498266Sopenharmony_ci          break;
57513498266Sopenharmony_ci        case PL_UNIX_USER_PARSING:
57613498266Sopenharmony_ci          parser->item_length++;
57713498266Sopenharmony_ci          if(c == ' ') {
57813498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 1] = 0;
57913498266Sopenharmony_ci            parser->offsets.user = parser->item_offset;
58013498266Sopenharmony_ci            parser->state.UNIX.main = PL_UNIX_GROUP;
58113498266Sopenharmony_ci            parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
58213498266Sopenharmony_ci            parser->item_offset = 0;
58313498266Sopenharmony_ci            parser->item_length = 0;
58413498266Sopenharmony_ci          }
58513498266Sopenharmony_ci          break;
58613498266Sopenharmony_ci        }
58713498266Sopenharmony_ci        break;
58813498266Sopenharmony_ci      case PL_UNIX_GROUP:
58913498266Sopenharmony_ci        switch(parser->state.UNIX.sub.group) {
59013498266Sopenharmony_ci        case PL_UNIX_GROUP_PRESPACE:
59113498266Sopenharmony_ci          if(c != ' ') {
59213498266Sopenharmony_ci            parser->item_offset = len - 1;
59313498266Sopenharmony_ci            parser->item_length = 1;
59413498266Sopenharmony_ci            parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
59513498266Sopenharmony_ci          }
59613498266Sopenharmony_ci          break;
59713498266Sopenharmony_ci        case PL_UNIX_GROUP_NAME:
59813498266Sopenharmony_ci          parser->item_length++;
59913498266Sopenharmony_ci          if(c == ' ') {
60013498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 1] = 0;
60113498266Sopenharmony_ci            parser->offsets.group = parser->item_offset;
60213498266Sopenharmony_ci            parser->state.UNIX.main = PL_UNIX_SIZE;
60313498266Sopenharmony_ci            parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
60413498266Sopenharmony_ci            parser->item_offset = 0;
60513498266Sopenharmony_ci            parser->item_length = 0;
60613498266Sopenharmony_ci          }
60713498266Sopenharmony_ci          break;
60813498266Sopenharmony_ci        }
60913498266Sopenharmony_ci        break;
61013498266Sopenharmony_ci      case PL_UNIX_SIZE:
61113498266Sopenharmony_ci        switch(parser->state.UNIX.sub.size) {
61213498266Sopenharmony_ci        case PL_UNIX_SIZE_PRESPACE:
61313498266Sopenharmony_ci          if(c != ' ') {
61413498266Sopenharmony_ci            if(ISDIGIT(c)) {
61513498266Sopenharmony_ci              parser->item_offset = len - 1;
61613498266Sopenharmony_ci              parser->item_length = 1;
61713498266Sopenharmony_ci              parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
61813498266Sopenharmony_ci            }
61913498266Sopenharmony_ci            else {
62013498266Sopenharmony_ci              parser->error = CURLE_FTP_BAD_FILE_LIST;
62113498266Sopenharmony_ci              goto fail;
62213498266Sopenharmony_ci            }
62313498266Sopenharmony_ci          }
62413498266Sopenharmony_ci          break;
62513498266Sopenharmony_ci        case PL_UNIX_SIZE_NUMBER:
62613498266Sopenharmony_ci          parser->item_length++;
62713498266Sopenharmony_ci          if(c == ' ') {
62813498266Sopenharmony_ci            char *p;
62913498266Sopenharmony_ci            curl_off_t fsize;
63013498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 1] = 0;
63113498266Sopenharmony_ci            if(!curlx_strtoofft(mem + parser->item_offset,
63213498266Sopenharmony_ci                                &p, 10, &fsize)) {
63313498266Sopenharmony_ci              if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
63413498266Sopenharmony_ci                 fsize != CURL_OFF_T_MIN) {
63513498266Sopenharmony_ci                parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
63613498266Sopenharmony_ci                parser->file_data->info.size = fsize;
63713498266Sopenharmony_ci              }
63813498266Sopenharmony_ci              parser->item_length = 0;
63913498266Sopenharmony_ci              parser->item_offset = 0;
64013498266Sopenharmony_ci              parser->state.UNIX.main = PL_UNIX_TIME;
64113498266Sopenharmony_ci              parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
64213498266Sopenharmony_ci            }
64313498266Sopenharmony_ci          }
64413498266Sopenharmony_ci          else if(!ISDIGIT(c)) {
64513498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
64613498266Sopenharmony_ci            goto fail;
64713498266Sopenharmony_ci          }
64813498266Sopenharmony_ci          break;
64913498266Sopenharmony_ci        }
65013498266Sopenharmony_ci        break;
65113498266Sopenharmony_ci      case PL_UNIX_TIME:
65213498266Sopenharmony_ci        switch(parser->state.UNIX.sub.time) {
65313498266Sopenharmony_ci        case PL_UNIX_TIME_PREPART1:
65413498266Sopenharmony_ci          if(c != ' ') {
65513498266Sopenharmony_ci            if(ISALNUM(c)) {
65613498266Sopenharmony_ci              parser->item_offset = len -1;
65713498266Sopenharmony_ci              parser->item_length = 1;
65813498266Sopenharmony_ci              parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
65913498266Sopenharmony_ci            }
66013498266Sopenharmony_ci            else {
66113498266Sopenharmony_ci              parser->error = CURLE_FTP_BAD_FILE_LIST;
66213498266Sopenharmony_ci              goto fail;
66313498266Sopenharmony_ci            }
66413498266Sopenharmony_ci          }
66513498266Sopenharmony_ci          break;
66613498266Sopenharmony_ci        case PL_UNIX_TIME_PART1:
66713498266Sopenharmony_ci          parser->item_length++;
66813498266Sopenharmony_ci          if(c == ' ') {
66913498266Sopenharmony_ci            parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
67013498266Sopenharmony_ci          }
67113498266Sopenharmony_ci          else if(!ISALNUM(c) && c != '.') {
67213498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
67313498266Sopenharmony_ci            goto fail;
67413498266Sopenharmony_ci          }
67513498266Sopenharmony_ci          break;
67613498266Sopenharmony_ci        case PL_UNIX_TIME_PREPART2:
67713498266Sopenharmony_ci          parser->item_length++;
67813498266Sopenharmony_ci          if(c != ' ') {
67913498266Sopenharmony_ci            if(ISALNUM(c)) {
68013498266Sopenharmony_ci              parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
68113498266Sopenharmony_ci            }
68213498266Sopenharmony_ci            else {
68313498266Sopenharmony_ci              parser->error = CURLE_FTP_BAD_FILE_LIST;
68413498266Sopenharmony_ci              goto fail;
68513498266Sopenharmony_ci            }
68613498266Sopenharmony_ci          }
68713498266Sopenharmony_ci          break;
68813498266Sopenharmony_ci        case PL_UNIX_TIME_PART2:
68913498266Sopenharmony_ci          parser->item_length++;
69013498266Sopenharmony_ci          if(c == ' ') {
69113498266Sopenharmony_ci            parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
69213498266Sopenharmony_ci          }
69313498266Sopenharmony_ci          else if(!ISALNUM(c) && c != '.') {
69413498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
69513498266Sopenharmony_ci            goto fail;
69613498266Sopenharmony_ci          }
69713498266Sopenharmony_ci          break;
69813498266Sopenharmony_ci        case PL_UNIX_TIME_PREPART3:
69913498266Sopenharmony_ci          parser->item_length++;
70013498266Sopenharmony_ci          if(c != ' ') {
70113498266Sopenharmony_ci            if(ISALNUM(c)) {
70213498266Sopenharmony_ci              parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
70313498266Sopenharmony_ci            }
70413498266Sopenharmony_ci            else {
70513498266Sopenharmony_ci              parser->error = CURLE_FTP_BAD_FILE_LIST;
70613498266Sopenharmony_ci              goto fail;
70713498266Sopenharmony_ci            }
70813498266Sopenharmony_ci          }
70913498266Sopenharmony_ci          break;
71013498266Sopenharmony_ci        case PL_UNIX_TIME_PART3:
71113498266Sopenharmony_ci          parser->item_length++;
71213498266Sopenharmony_ci          if(c == ' ') {
71313498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length -1] = 0;
71413498266Sopenharmony_ci            parser->offsets.time = parser->item_offset;
71513498266Sopenharmony_ci            /*
71613498266Sopenharmony_ci              if(ftp_pl_gettime(parser, finfo->mem + parser->item_offset)) {
71713498266Sopenharmony_ci                parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
71813498266Sopenharmony_ci              }
71913498266Sopenharmony_ci            */
72013498266Sopenharmony_ci            if(finfo->filetype == CURLFILETYPE_SYMLINK) {
72113498266Sopenharmony_ci              parser->state.UNIX.main = PL_UNIX_SYMLINK;
72213498266Sopenharmony_ci              parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
72313498266Sopenharmony_ci            }
72413498266Sopenharmony_ci            else {
72513498266Sopenharmony_ci              parser->state.UNIX.main = PL_UNIX_FILENAME;
72613498266Sopenharmony_ci              parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
72713498266Sopenharmony_ci            }
72813498266Sopenharmony_ci          }
72913498266Sopenharmony_ci          else if(!ISALNUM(c) && c != '.' && c != ':') {
73013498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
73113498266Sopenharmony_ci            goto fail;
73213498266Sopenharmony_ci          }
73313498266Sopenharmony_ci          break;
73413498266Sopenharmony_ci        }
73513498266Sopenharmony_ci        break;
73613498266Sopenharmony_ci      case PL_UNIX_FILENAME:
73713498266Sopenharmony_ci        switch(parser->state.UNIX.sub.filename) {
73813498266Sopenharmony_ci        case PL_UNIX_FILENAME_PRESPACE:
73913498266Sopenharmony_ci          if(c != ' ') {
74013498266Sopenharmony_ci            parser->item_offset = len - 1;
74113498266Sopenharmony_ci            parser->item_length = 1;
74213498266Sopenharmony_ci            parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
74313498266Sopenharmony_ci          }
74413498266Sopenharmony_ci          break;
74513498266Sopenharmony_ci        case PL_UNIX_FILENAME_NAME:
74613498266Sopenharmony_ci          parser->item_length++;
74713498266Sopenharmony_ci          if(c == '\r') {
74813498266Sopenharmony_ci            parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
74913498266Sopenharmony_ci          }
75013498266Sopenharmony_ci          else if(c == '\n') {
75113498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 1] = 0;
75213498266Sopenharmony_ci            parser->offsets.filename = parser->item_offset;
75313498266Sopenharmony_ci            parser->state.UNIX.main = PL_UNIX_FILETYPE;
75413498266Sopenharmony_ci            result = ftp_pl_insert_finfo(data, infop);
75513498266Sopenharmony_ci            if(result) {
75613498266Sopenharmony_ci              parser->error = result;
75713498266Sopenharmony_ci              goto fail;
75813498266Sopenharmony_ci            }
75913498266Sopenharmony_ci          }
76013498266Sopenharmony_ci          break;
76113498266Sopenharmony_ci        case PL_UNIX_FILENAME_WINDOWSEOL:
76213498266Sopenharmony_ci          if(c == '\n') {
76313498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 1] = 0;
76413498266Sopenharmony_ci            parser->offsets.filename = parser->item_offset;
76513498266Sopenharmony_ci            parser->state.UNIX.main = PL_UNIX_FILETYPE;
76613498266Sopenharmony_ci            result = ftp_pl_insert_finfo(data, infop);
76713498266Sopenharmony_ci            if(result) {
76813498266Sopenharmony_ci              parser->error = result;
76913498266Sopenharmony_ci              goto fail;
77013498266Sopenharmony_ci            }
77113498266Sopenharmony_ci          }
77213498266Sopenharmony_ci          else {
77313498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
77413498266Sopenharmony_ci            goto fail;
77513498266Sopenharmony_ci          }
77613498266Sopenharmony_ci          break;
77713498266Sopenharmony_ci        }
77813498266Sopenharmony_ci        break;
77913498266Sopenharmony_ci      case PL_UNIX_SYMLINK:
78013498266Sopenharmony_ci        switch(parser->state.UNIX.sub.symlink) {
78113498266Sopenharmony_ci        case PL_UNIX_SYMLINK_PRESPACE:
78213498266Sopenharmony_ci          if(c != ' ') {
78313498266Sopenharmony_ci            parser->item_offset = len - 1;
78413498266Sopenharmony_ci            parser->item_length = 1;
78513498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
78613498266Sopenharmony_ci          }
78713498266Sopenharmony_ci          break;
78813498266Sopenharmony_ci        case PL_UNIX_SYMLINK_NAME:
78913498266Sopenharmony_ci          parser->item_length++;
79013498266Sopenharmony_ci          if(c == ' ') {
79113498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
79213498266Sopenharmony_ci          }
79313498266Sopenharmony_ci          else if(c == '\r' || c == '\n') {
79413498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
79513498266Sopenharmony_ci            goto fail;
79613498266Sopenharmony_ci          }
79713498266Sopenharmony_ci          break;
79813498266Sopenharmony_ci        case PL_UNIX_SYMLINK_PRETARGET1:
79913498266Sopenharmony_ci          parser->item_length++;
80013498266Sopenharmony_ci          if(c == '-') {
80113498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
80213498266Sopenharmony_ci          }
80313498266Sopenharmony_ci          else if(c == '\r' || c == '\n') {
80413498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
80513498266Sopenharmony_ci            goto fail;
80613498266Sopenharmony_ci          }
80713498266Sopenharmony_ci          else {
80813498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
80913498266Sopenharmony_ci          }
81013498266Sopenharmony_ci          break;
81113498266Sopenharmony_ci        case PL_UNIX_SYMLINK_PRETARGET2:
81213498266Sopenharmony_ci          parser->item_length++;
81313498266Sopenharmony_ci          if(c == '>') {
81413498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
81513498266Sopenharmony_ci          }
81613498266Sopenharmony_ci          else if(c == '\r' || c == '\n') {
81713498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
81813498266Sopenharmony_ci            goto fail;
81913498266Sopenharmony_ci          }
82013498266Sopenharmony_ci          else {
82113498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
82213498266Sopenharmony_ci          }
82313498266Sopenharmony_ci          break;
82413498266Sopenharmony_ci        case PL_UNIX_SYMLINK_PRETARGET3:
82513498266Sopenharmony_ci          parser->item_length++;
82613498266Sopenharmony_ci          if(c == ' ') {
82713498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
82813498266Sopenharmony_ci            /* now place where is symlink following */
82913498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 4] = 0;
83013498266Sopenharmony_ci            parser->offsets.filename = parser->item_offset;
83113498266Sopenharmony_ci            parser->item_length = 0;
83213498266Sopenharmony_ci            parser->item_offset = 0;
83313498266Sopenharmony_ci          }
83413498266Sopenharmony_ci          else if(c == '\r' || c == '\n') {
83513498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
83613498266Sopenharmony_ci            goto fail;
83713498266Sopenharmony_ci          }
83813498266Sopenharmony_ci          else {
83913498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
84013498266Sopenharmony_ci          }
84113498266Sopenharmony_ci          break;
84213498266Sopenharmony_ci        case PL_UNIX_SYMLINK_PRETARGET4:
84313498266Sopenharmony_ci          if(c != '\r' && c != '\n') {
84413498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
84513498266Sopenharmony_ci            parser->item_offset = len - 1;
84613498266Sopenharmony_ci            parser->item_length = 1;
84713498266Sopenharmony_ci          }
84813498266Sopenharmony_ci          else {
84913498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
85013498266Sopenharmony_ci            goto fail;
85113498266Sopenharmony_ci          }
85213498266Sopenharmony_ci          break;
85313498266Sopenharmony_ci        case PL_UNIX_SYMLINK_TARGET:
85413498266Sopenharmony_ci          parser->item_length++;
85513498266Sopenharmony_ci          if(c == '\r') {
85613498266Sopenharmony_ci            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
85713498266Sopenharmony_ci          }
85813498266Sopenharmony_ci          else if(c == '\n') {
85913498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 1] = 0;
86013498266Sopenharmony_ci            parser->offsets.symlink_target = parser->item_offset;
86113498266Sopenharmony_ci            result = ftp_pl_insert_finfo(data, infop);
86213498266Sopenharmony_ci            if(result) {
86313498266Sopenharmony_ci              parser->error = result;
86413498266Sopenharmony_ci              goto fail;
86513498266Sopenharmony_ci            }
86613498266Sopenharmony_ci            parser->state.UNIX.main = PL_UNIX_FILETYPE;
86713498266Sopenharmony_ci          }
86813498266Sopenharmony_ci          break;
86913498266Sopenharmony_ci        case PL_UNIX_SYMLINK_WINDOWSEOL:
87013498266Sopenharmony_ci          if(c == '\n') {
87113498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 1] = 0;
87213498266Sopenharmony_ci            parser->offsets.symlink_target = parser->item_offset;
87313498266Sopenharmony_ci            result = ftp_pl_insert_finfo(data, infop);
87413498266Sopenharmony_ci            if(result) {
87513498266Sopenharmony_ci              parser->error = result;
87613498266Sopenharmony_ci              goto fail;
87713498266Sopenharmony_ci            }
87813498266Sopenharmony_ci            parser->state.UNIX.main = PL_UNIX_FILETYPE;
87913498266Sopenharmony_ci          }
88013498266Sopenharmony_ci          else {
88113498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
88213498266Sopenharmony_ci            goto fail;
88313498266Sopenharmony_ci          }
88413498266Sopenharmony_ci          break;
88513498266Sopenharmony_ci        }
88613498266Sopenharmony_ci        break;
88713498266Sopenharmony_ci      }
88813498266Sopenharmony_ci      break;
88913498266Sopenharmony_ci    case OS_TYPE_WIN_NT:
89013498266Sopenharmony_ci      switch(parser->state.NT.main) {
89113498266Sopenharmony_ci      case PL_WINNT_DATE:
89213498266Sopenharmony_ci        parser->item_length++;
89313498266Sopenharmony_ci        if(parser->item_length < 9) {
89413498266Sopenharmony_ci          if(!strchr("0123456789-", c)) { /* only simple control */
89513498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
89613498266Sopenharmony_ci            goto fail;
89713498266Sopenharmony_ci          }
89813498266Sopenharmony_ci        }
89913498266Sopenharmony_ci        else if(parser->item_length == 9) {
90013498266Sopenharmony_ci          if(c == ' ') {
90113498266Sopenharmony_ci            parser->state.NT.main = PL_WINNT_TIME;
90213498266Sopenharmony_ci            parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
90313498266Sopenharmony_ci          }
90413498266Sopenharmony_ci          else {
90513498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
90613498266Sopenharmony_ci            goto fail;
90713498266Sopenharmony_ci          }
90813498266Sopenharmony_ci        }
90913498266Sopenharmony_ci        else {
91013498266Sopenharmony_ci          parser->error = CURLE_FTP_BAD_FILE_LIST;
91113498266Sopenharmony_ci          goto fail;
91213498266Sopenharmony_ci        }
91313498266Sopenharmony_ci        break;
91413498266Sopenharmony_ci      case PL_WINNT_TIME:
91513498266Sopenharmony_ci        parser->item_length++;
91613498266Sopenharmony_ci        switch(parser->state.NT.sub.time) {
91713498266Sopenharmony_ci        case PL_WINNT_TIME_PRESPACE:
91813498266Sopenharmony_ci          if(!ISBLANK(c)) {
91913498266Sopenharmony_ci            parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
92013498266Sopenharmony_ci          }
92113498266Sopenharmony_ci          break;
92213498266Sopenharmony_ci        case PL_WINNT_TIME_TIME:
92313498266Sopenharmony_ci          if(c == ' ') {
92413498266Sopenharmony_ci            parser->offsets.time = parser->item_offset;
92513498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length -1] = 0;
92613498266Sopenharmony_ci            parser->state.NT.main = PL_WINNT_DIRORSIZE;
92713498266Sopenharmony_ci            parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
92813498266Sopenharmony_ci            parser->item_length = 0;
92913498266Sopenharmony_ci          }
93013498266Sopenharmony_ci          else if(!strchr("APM0123456789:", c)) {
93113498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
93213498266Sopenharmony_ci            goto fail;
93313498266Sopenharmony_ci          }
93413498266Sopenharmony_ci          break;
93513498266Sopenharmony_ci        }
93613498266Sopenharmony_ci        break;
93713498266Sopenharmony_ci      case PL_WINNT_DIRORSIZE:
93813498266Sopenharmony_ci        switch(parser->state.NT.sub.dirorsize) {
93913498266Sopenharmony_ci        case PL_WINNT_DIRORSIZE_PRESPACE:
94013498266Sopenharmony_ci          if(c != ' ') {
94113498266Sopenharmony_ci            parser->item_offset = len - 1;
94213498266Sopenharmony_ci            parser->item_length = 1;
94313498266Sopenharmony_ci            parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
94413498266Sopenharmony_ci          }
94513498266Sopenharmony_ci          break;
94613498266Sopenharmony_ci        case PL_WINNT_DIRORSIZE_CONTENT:
94713498266Sopenharmony_ci          parser->item_length ++;
94813498266Sopenharmony_ci          if(c == ' ') {
94913498266Sopenharmony_ci            mem[parser->item_offset + parser->item_length - 1] = 0;
95013498266Sopenharmony_ci            if(strcmp("<DIR>", mem + parser->item_offset) == 0) {
95113498266Sopenharmony_ci              finfo->filetype = CURLFILETYPE_DIRECTORY;
95213498266Sopenharmony_ci              finfo->size = 0;
95313498266Sopenharmony_ci            }
95413498266Sopenharmony_ci            else {
95513498266Sopenharmony_ci              char *endptr;
95613498266Sopenharmony_ci              if(curlx_strtoofft(mem +
95713498266Sopenharmony_ci                                 parser->item_offset,
95813498266Sopenharmony_ci                                 &endptr, 10, &finfo->size)) {
95913498266Sopenharmony_ci                parser->error = CURLE_FTP_BAD_FILE_LIST;
96013498266Sopenharmony_ci                goto fail;
96113498266Sopenharmony_ci              }
96213498266Sopenharmony_ci              /* correct file type */
96313498266Sopenharmony_ci              parser->file_data->info.filetype = CURLFILETYPE_FILE;
96413498266Sopenharmony_ci            }
96513498266Sopenharmony_ci
96613498266Sopenharmony_ci            parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
96713498266Sopenharmony_ci            parser->item_length = 0;
96813498266Sopenharmony_ci            parser->state.NT.main = PL_WINNT_FILENAME;
96913498266Sopenharmony_ci            parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
97013498266Sopenharmony_ci          }
97113498266Sopenharmony_ci          break;
97213498266Sopenharmony_ci        }
97313498266Sopenharmony_ci        break;
97413498266Sopenharmony_ci      case PL_WINNT_FILENAME:
97513498266Sopenharmony_ci        switch(parser->state.NT.sub.filename) {
97613498266Sopenharmony_ci        case PL_WINNT_FILENAME_PRESPACE:
97713498266Sopenharmony_ci          if(c != ' ') {
97813498266Sopenharmony_ci            parser->item_offset = len -1;
97913498266Sopenharmony_ci            parser->item_length = 1;
98013498266Sopenharmony_ci            parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
98113498266Sopenharmony_ci          }
98213498266Sopenharmony_ci          break;
98313498266Sopenharmony_ci        case PL_WINNT_FILENAME_CONTENT:
98413498266Sopenharmony_ci          parser->item_length++;
98513498266Sopenharmony_ci          if(c == '\r') {
98613498266Sopenharmony_ci            parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
98713498266Sopenharmony_ci            mem[len - 1] = 0;
98813498266Sopenharmony_ci          }
98913498266Sopenharmony_ci          else if(c == '\n') {
99013498266Sopenharmony_ci            parser->offsets.filename = parser->item_offset;
99113498266Sopenharmony_ci            mem[len - 1] = 0;
99213498266Sopenharmony_ci            result = ftp_pl_insert_finfo(data, infop);
99313498266Sopenharmony_ci            if(result) {
99413498266Sopenharmony_ci              parser->error = result;
99513498266Sopenharmony_ci              goto fail;
99613498266Sopenharmony_ci            }
99713498266Sopenharmony_ci            parser->state.NT.main = PL_WINNT_DATE;
99813498266Sopenharmony_ci            parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
99913498266Sopenharmony_ci          }
100013498266Sopenharmony_ci          break;
100113498266Sopenharmony_ci        case PL_WINNT_FILENAME_WINEOL:
100213498266Sopenharmony_ci          if(c == '\n') {
100313498266Sopenharmony_ci            parser->offsets.filename = parser->item_offset;
100413498266Sopenharmony_ci            result = ftp_pl_insert_finfo(data, infop);
100513498266Sopenharmony_ci            if(result) {
100613498266Sopenharmony_ci              parser->error = result;
100713498266Sopenharmony_ci              goto fail;
100813498266Sopenharmony_ci            }
100913498266Sopenharmony_ci            parser->state.NT.main = PL_WINNT_DATE;
101013498266Sopenharmony_ci            parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
101113498266Sopenharmony_ci          }
101213498266Sopenharmony_ci          else {
101313498266Sopenharmony_ci            parser->error = CURLE_FTP_BAD_FILE_LIST;
101413498266Sopenharmony_ci            goto fail;
101513498266Sopenharmony_ci          }
101613498266Sopenharmony_ci          break;
101713498266Sopenharmony_ci        }
101813498266Sopenharmony_ci        break;
101913498266Sopenharmony_ci      }
102013498266Sopenharmony_ci      break;
102113498266Sopenharmony_ci    default:
102213498266Sopenharmony_ci      retsize = bufflen + 1;
102313498266Sopenharmony_ci      goto fail;
102413498266Sopenharmony_ci    }
102513498266Sopenharmony_ci
102613498266Sopenharmony_ci    i++;
102713498266Sopenharmony_ci  }
102813498266Sopenharmony_ci  return retsize;
102913498266Sopenharmony_ci
103013498266Sopenharmony_cifail:
103113498266Sopenharmony_ci
103213498266Sopenharmony_ci  /* Clean up any allocated memory. */
103313498266Sopenharmony_ci  if(parser->file_data) {
103413498266Sopenharmony_ci    Curl_fileinfo_cleanup(parser->file_data);
103513498266Sopenharmony_ci    parser->file_data = NULL;
103613498266Sopenharmony_ci  }
103713498266Sopenharmony_ci
103813498266Sopenharmony_ci  return retsize;
103913498266Sopenharmony_ci}
104013498266Sopenharmony_ci
104113498266Sopenharmony_ci#endif /* CURL_DISABLE_FTP */
1042