diff options
Diffstat (limited to 'plugins/FTPFileYM/curl-7.29.0/lib/ftplistparser.c')
| -rw-r--r-- | plugins/FTPFileYM/curl-7.29.0/lib/ftplistparser.c | 1050 | 
1 files changed, 1050 insertions, 0 deletions
diff --git a/plugins/FTPFileYM/curl-7.29.0/lib/ftplistparser.c b/plugins/FTPFileYM/curl-7.29.0/lib/ftplistparser.c new file mode 100644 index 0000000000..cb3601f58d --- /dev/null +++ b/plugins/FTPFileYM/curl-7.29.0/lib/ftplistparser.c @@ -0,0 +1,1050 @@ +/*************************************************************************** + *                                  _   _ ____  _ + *  Project                     ___| | | |  _ \| | + *                             / __| | | | |_) | | + *                            | (__| |_| |  _ <| |___ + *                             \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/** + * Now implemented: + * + * 1) UNIX version 1 + * drwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog + * 2) UNIX version 2 + * drwxr-xr-x 1 user01 ftp  512 Jan 29 1997  prog + * 3) UNIX version 3 + * drwxr-xr-x 1      1   1  512 Jan 29 23:32 prog + * 4) UNIX symlink + * lrwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog -> prog2000 + * 5) DOS style + * 01-29-97 11:32PM <DIR> prog + */ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_FTP + +#include <curl/curl.h> + +#include "urldata.h" +#include "fileinfo.h" +#include "llist.h" +#include "strtoofft.h" +#include "rawstr.h" +#include "ftp.h" +#include "ftplistparser.h" +#include "curl_fnmatch.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* allocs buffer which will contain one line of LIST command response */ +#define FTP_BUFFER_ALLOCSIZE 160 + +typedef enum { +  PL_UNIX_TOTALSIZE = 0, +  PL_UNIX_FILETYPE, +  PL_UNIX_PERMISSION, +  PL_UNIX_HLINKS, +  PL_UNIX_USER, +  PL_UNIX_GROUP, +  PL_UNIX_SIZE, +  PL_UNIX_TIME, +  PL_UNIX_FILENAME, +  PL_UNIX_SYMLINK +} pl_unix_mainstate; + +typedef union { +  enum { +    PL_UNIX_TOTALSIZE_INIT = 0, +    PL_UNIX_TOTALSIZE_READING +  } total_dirsize; + +  enum { +    PL_UNIX_HLINKS_PRESPACE = 0, +    PL_UNIX_HLINKS_NUMBER +  } hlinks; + +  enum { +    PL_UNIX_USER_PRESPACE = 0, +    PL_UNIX_USER_PARSING +  } user; + +  enum { +    PL_UNIX_GROUP_PRESPACE = 0, +    PL_UNIX_GROUP_NAME +  } group; + +  enum { +    PL_UNIX_SIZE_PRESPACE = 0, +    PL_UNIX_SIZE_NUMBER +  } size; + +  enum { +    PL_UNIX_TIME_PREPART1 = 0, +    PL_UNIX_TIME_PART1, +    PL_UNIX_TIME_PREPART2, +    PL_UNIX_TIME_PART2, +    PL_UNIX_TIME_PREPART3, +    PL_UNIX_TIME_PART3 +  } time; + +  enum { +    PL_UNIX_FILENAME_PRESPACE = 0, +    PL_UNIX_FILENAME_NAME, +    PL_UNIX_FILENAME_WINDOWSEOL +  } filename; + +  enum { +    PL_UNIX_SYMLINK_PRESPACE = 0, +    PL_UNIX_SYMLINK_NAME, +    PL_UNIX_SYMLINK_PRETARGET1, +    PL_UNIX_SYMLINK_PRETARGET2, +    PL_UNIX_SYMLINK_PRETARGET3, +    PL_UNIX_SYMLINK_PRETARGET4, +    PL_UNIX_SYMLINK_TARGET, +    PL_UNIX_SYMLINK_WINDOWSEOL +  } symlink; +} pl_unix_substate; + +typedef enum { +  PL_WINNT_DATE = 0, +  PL_WINNT_TIME, +  PL_WINNT_DIRORSIZE, +  PL_WINNT_FILENAME +} pl_winNT_mainstate; + +typedef union { +  enum { +    PL_WINNT_TIME_PRESPACE = 0, +    PL_WINNT_TIME_TIME +  } time; +  enum { +    PL_WINNT_DIRORSIZE_PRESPACE = 0, +    PL_WINNT_DIRORSIZE_CONTENT +  } dirorsize; +  enum { +    PL_WINNT_FILENAME_PRESPACE = 0, +    PL_WINNT_FILENAME_CONTENT, +    PL_WINNT_FILENAME_WINEOL +  } filename; +} pl_winNT_substate; + +/* This struct is used in wildcard downloading - for parsing LIST response */ +struct ftp_parselist_data { +  enum { +    OS_TYPE_UNKNOWN = 0, +    OS_TYPE_UNIX, +    OS_TYPE_WIN_NT +  } os_type; + +  union { +    struct { +      pl_unix_mainstate main; +      pl_unix_substate sub; +    } UNIX; + +    struct { +      pl_winNT_mainstate main; +      pl_winNT_substate sub; +    } NT; +  } state; + +  CURLcode error; +  struct curl_fileinfo *file_data; +  unsigned int item_length; +  size_t item_offset; +  struct { +    size_t filename; +    size_t user; +    size_t group; +    size_t time; +    size_t perm; +    size_t symlink_target; +  } offsets; +}; + +struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void) +{ +  return calloc(1, sizeof(struct ftp_parselist_data)); +} + + +void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data) +{ +  if(*pl_data) +    free(*pl_data); +  *pl_data = NULL; +} + + +CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data) +{ +  return pl_data->error; +} + + +#define FTP_LP_MALFORMATED_PERM 0x01000000 + +static int ftp_pl_get_permission(const char *str) +{ +  int permissions = 0; +  /* USER */ +  if(str[0] == 'r') +    permissions |= 1 << 8; +  else if(str[0] != '-') +    permissions |= FTP_LP_MALFORMATED_PERM; +  if(str[1] == 'w') +    permissions |= 1 << 7; +  else if(str[1] != '-') +    permissions |= FTP_LP_MALFORMATED_PERM; + +  if(str[2] == 'x') +    permissions |= 1 << 6; +  else if(str[2] == 's') { +    permissions |= 1 << 6; +    permissions |= 1 << 11; +  } +  else if(str[2] == 'S') +    permissions |= 1 << 11; +  else if(str[2] != '-') +    permissions |= FTP_LP_MALFORMATED_PERM; +  /* GROUP */ +  if(str[3] == 'r') +    permissions |= 1 << 5; +  else if(str[3] != '-') +    permissions |= FTP_LP_MALFORMATED_PERM; +  if(str[4] == 'w') +    permissions |= 1 << 4; +  else if(str[4] != '-') +    permissions |= FTP_LP_MALFORMATED_PERM; +  if(str[5] == 'x') +    permissions |= 1 << 3; +  else if(str[5] == 's') { +    permissions |= 1 << 3; +    permissions |= 1 << 10; +  } +  else if(str[5] == 'S') +    permissions |= 1 << 10; +  else if(str[5] != '-') +    permissions |= FTP_LP_MALFORMATED_PERM; +  /* others */ +  if(str[6] == 'r') +    permissions |= 1 << 2; +  else if(str[6] != '-') +    permissions |= FTP_LP_MALFORMATED_PERM; +  if(str[7] == 'w') +    permissions |= 1 << 1; +  else if(str[7] != '-') +      permissions |= FTP_LP_MALFORMATED_PERM; +  if(str[8] == 'x') +    permissions |= 1; +  else if(str[8] == 't') { +    permissions |= 1; +    permissions |= 1 << 9; +  } +  else if(str[8] == 'T') +    permissions |= 1 << 9; +  else if(str[8] != '-') +    permissions |= FTP_LP_MALFORMATED_PERM; + +  return permissions; +} + +static void PL_ERROR(struct connectdata *conn, CURLcode err) +{ +  struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp; +  struct ftp_parselist_data *parser = tmpdata->parser; +  if(parser->file_data) +    Curl_fileinfo_dtor(NULL, parser->file_data); +  parser->file_data = NULL; +  parser->error = err; +} + +static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string) +{ +  (void)parser; +  (void)string; +  /* TODO +   * There could be possible parse timestamp from server. Leaving unimplemented +   * for now. +   * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to +   * parser->file_data->flags +   * +   * Ftp servers are giving usually these formats: +   *  Apr 11  1998 (unknown time.. set it to 00:00:00?) +   *  Apr 11 12:21 (unknown year -> set it to NOW() time?) +   *  08-05-09  02:49PM  (ms-dos format) +   *  20100421092538 -> for MLST/MLSD response +   */ + +  return FALSE; +} + +static CURLcode ftp_pl_insert_finfo(struct connectdata *conn, +                                    struct curl_fileinfo *finfo) +{ +  curl_fnmatch_callback compare; +  struct WildcardData *wc = &conn->data->wildcard; +  struct ftp_wc_tmpdata *tmpdata = wc->tmp; +  struct curl_llist *llist = wc->filelist; +  struct ftp_parselist_data *parser = tmpdata->parser; +  bool add = TRUE; + +  /* move finfo pointers to b_data */ +  char *str = finfo->b_data; +  finfo->filename       = str + parser->offsets.filename; +  finfo->strings.group  = parser->offsets.group ? +                          str + parser->offsets.group : NULL; +  finfo->strings.perm   = parser->offsets.perm ? +                          str + parser->offsets.perm : NULL; +  finfo->strings.target = parser->offsets.symlink_target ? +                          str + parser->offsets.symlink_target : NULL; +  finfo->strings.time   = str + parser->offsets.time; +  finfo->strings.user   = parser->offsets.user ? +                          str + parser->offsets.user : NULL; + +  /* get correct fnmatch callback */ +  compare = conn->data->set.fnmatch; +  if(!compare) +    compare = Curl_fnmatch; + +  /* filter pattern-corresponding filenames */ +  if(compare(conn->data->set.fnmatch_data, wc->pattern, +             finfo->filename) == 0) { +    /* discard symlink which is containing multiple " -> " */ +    if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target && +       (strstr(finfo->strings.target, " -> "))) { +      add = FALSE; +    } +  } +  else { +    add = FALSE; +  } + +  if(add) { +    if(!Curl_llist_insert_next(llist, llist->tail, finfo)) { +      Curl_fileinfo_dtor(NULL, finfo); +      tmpdata->parser->file_data = NULL; +      return CURLE_OUT_OF_MEMORY; +    } +  } +  else { +    Curl_fileinfo_dtor(NULL, finfo); +  } + +  tmpdata->parser->file_data = NULL; +  return CURLE_OK; +} + +size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, +                          void *connptr) +{ +  size_t bufflen = size*nmemb; +  struct connectdata *conn = (struct connectdata *)connptr; +  struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp; +  struct ftp_parselist_data *parser = tmpdata->parser; +  struct curl_fileinfo *finfo; +  unsigned long i = 0; +  CURLcode rc; + +  if(parser->error) { /* error in previous call */ +    /* scenario: +     * 1. call => OK.. +     * 2. call => OUT_OF_MEMORY (or other error) +     * 3. (last) call => is skipped RIGHT HERE and the error is hadled later +     *    in wc_statemach() +     */ +    return bufflen; +  } + +  if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) { +    /* considering info about FILE response format */ +    parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ? +                       OS_TYPE_WIN_NT : OS_TYPE_UNIX; +  } + +  while(i < bufflen) { /* FSM */ + +    char c = buffer[i]; +    if(!parser->file_data) { /* tmp file data is not allocated yet */ +      parser->file_data = Curl_fileinfo_alloc(); +      if(!parser->file_data) { +        parser->error = CURLE_OUT_OF_MEMORY; +        return bufflen; +      } +      parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE); +      if(!parser->file_data->b_data) { +        PL_ERROR(conn, CURLE_OUT_OF_MEMORY); +        return bufflen; +      } +      parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE; +      parser->item_offset = 0; +      parser->item_length = 0; +    } + +    finfo = parser->file_data; +    finfo->b_data[finfo->b_used++] = c; + +    if(finfo->b_used >= finfo->b_size - 1) { +      /* if it is important, extend buffer space for file data */ +      char *tmp = realloc(finfo->b_data, +                          finfo->b_size + FTP_BUFFER_ALLOCSIZE); +      if(tmp) { +        finfo->b_size += FTP_BUFFER_ALLOCSIZE; +        finfo->b_data = tmp; +      } +      else { +        Curl_fileinfo_dtor(NULL, parser->file_data); +        parser->file_data = NULL; +        parser->error = CURLE_OUT_OF_MEMORY; +        PL_ERROR(conn, CURLE_OUT_OF_MEMORY); +        return bufflen; +      } +    } + +    switch (parser->os_type) { +    case OS_TYPE_UNIX: +      switch (parser->state.UNIX.main) { +      case PL_UNIX_TOTALSIZE: +        switch(parser->state.UNIX.sub.total_dirsize) { +        case PL_UNIX_TOTALSIZE_INIT: +          if(c == 't') { +            parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING; +            parser->item_length++; +          } +          else { +            parser->state.UNIX.main = PL_UNIX_FILETYPE; +            /* start FSM again not considering size of directory */ +            finfo->b_used = 0; +            i--; +          } +          break; +        case PL_UNIX_TOTALSIZE_READING: +          parser->item_length++; +          if(c == '\r') { +            parser->item_length--; +            finfo->b_used--; +          } +          else if(c == '\n') { +            finfo->b_data[parser->item_length - 1] = 0; +            if(strncmp("total ", finfo->b_data, 6) == 0) { +              char *endptr = finfo->b_data+6; +              /* here we can deal with directory size */ +              while(ISSPACE(*endptr)) +                endptr++; +              if(*endptr != 0) { +                PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +                return bufflen; +              } +              else { +                parser->state.UNIX.main = PL_UNIX_FILETYPE; +                finfo->b_used = 0; +              } +            } +            else { +              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +              return bufflen; +            } +          } +          break; +        } +        break; +      case PL_UNIX_FILETYPE: +        switch (c) { +        case '-': +          finfo->filetype = CURLFILETYPE_FILE; +          break; +        case 'd': +          finfo->filetype = CURLFILETYPE_DIRECTORY; +          break; +        case 'l': +          finfo->filetype = CURLFILETYPE_SYMLINK; +          break; +        case 'p': +          finfo->filetype = CURLFILETYPE_NAMEDPIPE; +          break; +        case 's': +          finfo->filetype = CURLFILETYPE_SOCKET; +          break; +        case 'c': +          finfo->filetype = CURLFILETYPE_DEVICE_CHAR; +          break; +        case 'b': +          finfo->filetype = CURLFILETYPE_DEVICE_BLOCK; +          break; +        case 'D': +          finfo->filetype = CURLFILETYPE_DOOR; +          break; +        default: +          PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +          return bufflen; +        } +        parser->state.UNIX.main = PL_UNIX_PERMISSION; +        parser->item_length = 0; +        parser->item_offset = 1; +        break; +      case PL_UNIX_PERMISSION: +        parser->item_length++; +        if(parser->item_length <= 9) { +          if(!strchr("rwx-tTsS", c)) { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +        } +        else if(parser->item_length == 10) { +          unsigned int perm; +          if(c != ' ') { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          finfo->b_data[10] = 0; /* terminate permissions */ +          perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset); +          if(perm & FTP_LP_MALFORMATED_PERM) { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM; +          parser->file_data->perm = perm; +          parser->offsets.perm = parser->item_offset; + +          parser->item_length = 0; +          parser->state.UNIX.main = PL_UNIX_HLINKS; +          parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE; +        } +        break; +      case PL_UNIX_HLINKS: +        switch(parser->state.UNIX.sub.hlinks) { +        case PL_UNIX_HLINKS_PRESPACE: +          if(c != ' ') { +            if(c >= '0' && c <= '9') { +              parser->item_offset = finfo->b_used - 1; +              parser->item_length = 1; +              parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER; +            } +            else { +              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +              return bufflen; +            } +          } +          break; +        case PL_UNIX_HLINKS_NUMBER: +          parser->item_length ++; +          if(c == ' ') { +            char *p; +            long int hlinks; +            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; +            hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10); +            if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) { +              parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; +              parser->file_data->hardlinks = hlinks; +            } +            parser->item_length = 0; +            parser->item_offset = 0; +            parser->state.UNIX.main = PL_UNIX_USER; +            parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE; +          } +          else if(c < '0' || c > '9') { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        } +        break; +      case PL_UNIX_USER: +        switch(parser->state.UNIX.sub.user) { +        case PL_UNIX_USER_PRESPACE: +          if(c != ' ') { +            parser->item_offset = finfo->b_used - 1; +            parser->item_length = 1; +            parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING; +          } +          break; +        case PL_UNIX_USER_PARSING: +          parser->item_length++; +          if(c == ' ') { +            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; +            parser->offsets.user = parser->item_offset; +            parser->state.UNIX.main = PL_UNIX_GROUP; +            parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE; +            parser->item_offset = 0; +            parser->item_length = 0; +          } +          break; +        } +        break; +      case PL_UNIX_GROUP: +        switch(parser->state.UNIX.sub.group) { +        case PL_UNIX_GROUP_PRESPACE: +          if(c != ' ') { +            parser->item_offset = finfo->b_used - 1; +            parser->item_length = 1; +            parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME; +          } +          break; +        case PL_UNIX_GROUP_NAME: +          parser->item_length++; +          if(c == ' ') { +            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; +            parser->offsets.group = parser->item_offset; +            parser->state.UNIX.main = PL_UNIX_SIZE; +            parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE; +            parser->item_offset = 0; +            parser->item_length = 0; +          } +          break; +        } +        break; +      case PL_UNIX_SIZE: +        switch(parser->state.UNIX.sub.size) { +        case PL_UNIX_SIZE_PRESPACE: +          if(c != ' ') { +            if(c >= '0' && c <= '9') { +              parser->item_offset = finfo->b_used - 1; +              parser->item_length = 1; +              parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER; +            } +            else { +              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +              return bufflen; +            } +          } +          break; +        case PL_UNIX_SIZE_NUMBER: +          parser->item_length++; +          if(c == ' ') { +            char *p; +            curl_off_t fsize; +            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; +            fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10); +            if(p[0] == '\0' && fsize != CURL_OFF_T_MAX && +                               fsize != CURL_OFF_T_MIN) { +              parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE; +              parser->file_data->size = fsize; +            } +            parser->item_length = 0; +            parser->item_offset = 0; +            parser->state.UNIX.main = PL_UNIX_TIME; +            parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; +          } +          else if(!ISDIGIT(c)) { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        } +        break; +      case PL_UNIX_TIME: +        switch(parser->state.UNIX.sub.time) { +        case PL_UNIX_TIME_PREPART1: +          if(c != ' ') { +            if(ISALNUM(c)) { +              parser->item_offset = finfo->b_used -1; +              parser->item_length = 1; +              parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1; +            } +            else { +              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +              return bufflen; +            } +          } +          break; +        case PL_UNIX_TIME_PART1: +          parser->item_length++; +          if(c == ' ') { +            parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2; +          } +          else if(!ISALNUM(c) && c != '.') { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        case PL_UNIX_TIME_PREPART2: +          parser->item_length++; +          if(c != ' ') { +            if(ISALNUM(c)) { +              parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2; +            } +            else { +              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +              return bufflen; +            } +          } +          break; +        case PL_UNIX_TIME_PART2: +          parser->item_length++; +          if(c == ' ') { +            parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3; +          } +          else if(!ISALNUM(c) && c != '.') { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        case PL_UNIX_TIME_PREPART3: +          parser->item_length++; +          if(c != ' ') { +            if(ISALNUM(c)) { +              parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3; +            } +            else { +              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +              return bufflen; +            } +          } +          break; +        case PL_UNIX_TIME_PART3: +          parser->item_length++; +          if(c == ' ') { +            finfo->b_data[parser->item_offset + parser->item_length -1] = 0; +            parser->offsets.time = parser->item_offset; +            if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) { +              parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME; +            } +            if(finfo->filetype == CURLFILETYPE_SYMLINK) { +              parser->state.UNIX.main = PL_UNIX_SYMLINK; +              parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE; +            } +            else { +              parser->state.UNIX.main = PL_UNIX_FILENAME; +              parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE; +            } +          } +          else if(!ISALNUM(c) && c != '.' && c != ':') { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        } +        break; +      case PL_UNIX_FILENAME: +        switch(parser->state.UNIX.sub.filename) { +        case PL_UNIX_FILENAME_PRESPACE: +          if(c != ' ') { +            parser->item_offset = finfo->b_used - 1; +            parser->item_length = 1; +            parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME; +          } +          break; +        case PL_UNIX_FILENAME_NAME: +          parser->item_length++; +          if(c == '\r') { +            parser->item_length--; +            parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; +          } +          else if(c == '\n') { +            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; +            parser->offsets.filename = parser->item_offset; +            parser->state.UNIX.main = PL_UNIX_FILETYPE; +            rc = ftp_pl_insert_finfo(conn, finfo); +            if(rc) { +              PL_ERROR(conn, rc); +              return bufflen; +            } +          } +          break; +        case PL_UNIX_FILENAME_WINDOWSEOL: +          if(c == '\n') { +            finfo->b_data[parser->item_offset + parser->item_length] = 0; +            parser->offsets.filename = parser->item_offset; +            parser->state.UNIX.main = PL_UNIX_FILETYPE; +            rc = ftp_pl_insert_finfo(conn, finfo); +            if(rc) { +              PL_ERROR(conn, rc); +              return bufflen; +            } +          } +          else { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        } +        break; +      case PL_UNIX_SYMLINK: +        switch(parser->state.UNIX.sub.symlink) { +        case PL_UNIX_SYMLINK_PRESPACE: +          if(c != ' ') { +            parser->item_offset = finfo->b_used - 1; +            parser->item_length = 1; +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; +          } +          break; +        case PL_UNIX_SYMLINK_NAME: +          parser->item_length++; +          if(c == ' ') { +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1; +          } +          else if(c == '\r' || c == '\n') { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        case PL_UNIX_SYMLINK_PRETARGET1: +          parser->item_length++; +          if(c == '-') { +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2; +          } +          else if(c == '\r' || c == '\n') { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          else { +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; +          } +          break; +        case PL_UNIX_SYMLINK_PRETARGET2: +          parser->item_length++; +          if(c == '>') { +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3; +          } +          else if(c == '\r' || c == '\n') { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          else { +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; +          } +          break; +        case PL_UNIX_SYMLINK_PRETARGET3: +          parser->item_length++; +          if(c == ' ') { +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4; +            /* now place where is symlink following */ +            finfo->b_data[parser->item_offset + parser->item_length - 4] = 0; +            parser->offsets.filename = parser->item_offset; +            parser->item_length = 0; +            parser->item_offset = 0; +          } +          else if(c == '\r' || c == '\n') { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          else { +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; +          } +          break; +        case PL_UNIX_SYMLINK_PRETARGET4: +          if(c != '\r' && c != '\n') { +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET; +            parser->item_offset = finfo->b_used - 1; +            parser->item_length = 1; +          } +          else { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        case PL_UNIX_SYMLINK_TARGET: +          parser->item_length ++; +          if(c == '\r') { +            parser->item_length --; +            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; +          } +          else if(c == '\n') { +            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; +            parser->offsets.symlink_target = parser->item_offset; +            rc = ftp_pl_insert_finfo(conn, finfo); +            if(rc) { +              PL_ERROR(conn, rc); +              return bufflen; +            } +            parser->state.UNIX.main = PL_UNIX_FILETYPE; +          } +          break; +        case PL_UNIX_SYMLINK_WINDOWSEOL: +          if(c == '\n') { +            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; +            parser->offsets.symlink_target = parser->item_offset; +            rc = ftp_pl_insert_finfo(conn, finfo); +            if(rc) { +              PL_ERROR(conn, rc); +              return bufflen; +            } +            parser->state.UNIX.main = PL_UNIX_FILETYPE; +          } +          else { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        } +        break; +      } +      break; +    case OS_TYPE_WIN_NT: +      switch(parser->state.NT.main) { +      case PL_WINNT_DATE: +        parser->item_length++; +        if(parser->item_length < 9) { +          if(!strchr("0123456789-", c)) { /* only simple control */ +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +        } +        else if(parser->item_length == 9) { +          if(c == ' ') { +            parser->state.NT.main = PL_WINNT_TIME; +            parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE; +          } +          else { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +        } +        else { +          PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +          return bufflen; +        } +        break; +      case PL_WINNT_TIME: +        parser->item_length++; +        switch(parser->state.NT.sub.time) { +        case PL_WINNT_TIME_PRESPACE: +          if(!ISSPACE(c)) { +            parser->state.NT.sub.time = PL_WINNT_TIME_TIME; +          } +          break; +        case PL_WINNT_TIME_TIME: +          if(c == ' ') { +            parser->offsets.time = parser->item_offset; +            finfo->b_data[parser->item_offset + parser->item_length -1] = 0; +            parser->state.NT.main = PL_WINNT_DIRORSIZE; +            parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE; +            parser->item_length = 0; +          } +          else if(!strchr("APM0123456789:", c)) { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        } +        break; +      case PL_WINNT_DIRORSIZE: +        switch(parser->state.NT.sub.dirorsize) { +        case PL_WINNT_DIRORSIZE_PRESPACE: +          if(c == ' ') { + +          } +          else { +            parser->item_offset = finfo->b_used - 1; +            parser->item_length = 1; +            parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT; +          } +          break; +        case PL_WINNT_DIRORSIZE_CONTENT: +          parser->item_length ++; +          if(c == ' ') { +            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; +            if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) { +              finfo->filetype = CURLFILETYPE_DIRECTORY; +              finfo->size = 0; +            } +            else { +              char *endptr; +              finfo->size = curlx_strtoofft(finfo->b_data + +                                            parser->item_offset, +                                            &endptr, 10); +              if(!*endptr) { +                if(finfo->size == CURL_OFF_T_MAX || +                   finfo->size == CURL_OFF_T_MIN) { +                  if(errno == ERANGE) { +                    PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +                    return bufflen; +                  } +                } +              } +              else { +                PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +                return bufflen; +              } +              /* correct file type */ +              parser->file_data->filetype = CURLFILETYPE_FILE; +            } + +            parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE; +            parser->item_length = 0; +            parser->state.NT.main = PL_WINNT_FILENAME; +            parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; +          } +          break; +        } +        break; +      case PL_WINNT_FILENAME: +        switch (parser->state.NT.sub.filename) { +        case PL_WINNT_FILENAME_PRESPACE: +          if(c != ' ') { +            parser->item_offset = finfo->b_used -1; +            parser->item_length = 1; +            parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT; +          } +          break; +        case PL_WINNT_FILENAME_CONTENT: +          parser->item_length++; +          if(c == '\r') { +            parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL; +            finfo->b_data[finfo->b_used - 1] = 0; +          } +          else if(c == '\n') { +            parser->offsets.filename = parser->item_offset; +            finfo->b_data[finfo->b_used - 1] = 0; +            parser->offsets.filename = parser->item_offset; +            rc = ftp_pl_insert_finfo(conn, finfo); +            if(rc) { +              PL_ERROR(conn, rc); +              return bufflen; +            } +            parser->state.NT.main = PL_WINNT_DATE; +            parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; +          } +          break; +        case PL_WINNT_FILENAME_WINEOL: +          if(c == '\n') { +            parser->offsets.filename = parser->item_offset; +            rc = ftp_pl_insert_finfo(conn, finfo); +            if(rc) { +              PL_ERROR(conn, rc); +              return bufflen; +            } +            parser->state.NT.main = PL_WINNT_DATE; +            parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; +          } +          else { +            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); +            return bufflen; +          } +          break; +        } +        break; +      } +      break; +    default: +      return bufflen+1; +    } + +    i++; +  } + +  return bufflen; +} + +#endif /* CURL_DISABLE_FTP */  | 
