ftplistparser.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2017, 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.haxx.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. ***************************************************************************/
  22. /**
  23. * Now implemented:
  24. *
  25. * 1) Unix version 1
  26. * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog
  27. * 2) Unix version 2
  28. * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog
  29. * 3) Unix version 3
  30. * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog
  31. * 4) Unix symlink
  32. * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000
  33. * 5) DOS style
  34. * 01-29-97 11:32PM <DIR> prog
  35. */
  36. #include "curl_setup.h"
  37. #ifndef CURL_DISABLE_FTP
  38. #include <curl/curl.h>
  39. #include "urldata.h"
  40. #include "fileinfo.h"
  41. #include "llist.h"
  42. #include "strtoofft.h"
  43. #include "ftp.h"
  44. #include "ftplistparser.h"
  45. #include "curl_fnmatch.h"
  46. #include "curl_memory.h"
  47. /* The last #include file should be: */
  48. #include "memdebug.h"
  49. /* allocs buffer which will contain one line of LIST command response */
  50. #define FTP_BUFFER_ALLOCSIZE 160
  51. typedef enum {
  52. PL_UNIX_TOTALSIZE = 0,
  53. PL_UNIX_FILETYPE,
  54. PL_UNIX_PERMISSION,
  55. PL_UNIX_HLINKS,
  56. PL_UNIX_USER,
  57. PL_UNIX_GROUP,
  58. PL_UNIX_SIZE,
  59. PL_UNIX_TIME,
  60. PL_UNIX_FILENAME,
  61. PL_UNIX_SYMLINK
  62. } pl_unix_mainstate;
  63. typedef union {
  64. enum {
  65. PL_UNIX_TOTALSIZE_INIT = 0,
  66. PL_UNIX_TOTALSIZE_READING
  67. } total_dirsize;
  68. enum {
  69. PL_UNIX_HLINKS_PRESPACE = 0,
  70. PL_UNIX_HLINKS_NUMBER
  71. } hlinks;
  72. enum {
  73. PL_UNIX_USER_PRESPACE = 0,
  74. PL_UNIX_USER_PARSING
  75. } user;
  76. enum {
  77. PL_UNIX_GROUP_PRESPACE = 0,
  78. PL_UNIX_GROUP_NAME
  79. } group;
  80. enum {
  81. PL_UNIX_SIZE_PRESPACE = 0,
  82. PL_UNIX_SIZE_NUMBER
  83. } size;
  84. enum {
  85. PL_UNIX_TIME_PREPART1 = 0,
  86. PL_UNIX_TIME_PART1,
  87. PL_UNIX_TIME_PREPART2,
  88. PL_UNIX_TIME_PART2,
  89. PL_UNIX_TIME_PREPART3,
  90. PL_UNIX_TIME_PART3
  91. } time;
  92. enum {
  93. PL_UNIX_FILENAME_PRESPACE = 0,
  94. PL_UNIX_FILENAME_NAME,
  95. PL_UNIX_FILENAME_WINDOWSEOL
  96. } filename;
  97. enum {
  98. PL_UNIX_SYMLINK_PRESPACE = 0,
  99. PL_UNIX_SYMLINK_NAME,
  100. PL_UNIX_SYMLINK_PRETARGET1,
  101. PL_UNIX_SYMLINK_PRETARGET2,
  102. PL_UNIX_SYMLINK_PRETARGET3,
  103. PL_UNIX_SYMLINK_PRETARGET4,
  104. PL_UNIX_SYMLINK_TARGET,
  105. PL_UNIX_SYMLINK_WINDOWSEOL
  106. } symlink;
  107. } pl_unix_substate;
  108. typedef enum {
  109. PL_WINNT_DATE = 0,
  110. PL_WINNT_TIME,
  111. PL_WINNT_DIRORSIZE,
  112. PL_WINNT_FILENAME
  113. } pl_winNT_mainstate;
  114. typedef union {
  115. enum {
  116. PL_WINNT_TIME_PRESPACE = 0,
  117. PL_WINNT_TIME_TIME
  118. } time;
  119. enum {
  120. PL_WINNT_DIRORSIZE_PRESPACE = 0,
  121. PL_WINNT_DIRORSIZE_CONTENT
  122. } dirorsize;
  123. enum {
  124. PL_WINNT_FILENAME_PRESPACE = 0,
  125. PL_WINNT_FILENAME_CONTENT,
  126. PL_WINNT_FILENAME_WINEOL
  127. } filename;
  128. } pl_winNT_substate;
  129. /* This struct is used in wildcard downloading - for parsing LIST response */
  130. struct ftp_parselist_data {
  131. enum {
  132. OS_TYPE_UNKNOWN = 0,
  133. OS_TYPE_UNIX,
  134. OS_TYPE_WIN_NT
  135. } os_type;
  136. union {
  137. struct {
  138. pl_unix_mainstate main;
  139. pl_unix_substate sub;
  140. } UNIX;
  141. struct {
  142. pl_winNT_mainstate main;
  143. pl_winNT_substate sub;
  144. } NT;
  145. } state;
  146. CURLcode error;
  147. struct fileinfo *file_data;
  148. unsigned int item_length;
  149. size_t item_offset;
  150. struct {
  151. size_t filename;
  152. size_t user;
  153. size_t group;
  154. size_t time;
  155. size_t perm;
  156. size_t symlink_target;
  157. } offsets;
  158. };
  159. struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
  160. {
  161. return calloc(1, sizeof(struct ftp_parselist_data));
  162. }
  163. void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
  164. {
  165. free(*pl_data);
  166. *pl_data = NULL;
  167. }
  168. CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
  169. {
  170. return pl_data->error;
  171. }
  172. #define FTP_LP_MALFORMATED_PERM 0x01000000
  173. static int ftp_pl_get_permission(const char *str)
  174. {
  175. int permissions = 0;
  176. /* USER */
  177. if(str[0] == 'r')
  178. permissions |= 1 << 8;
  179. else if(str[0] != '-')
  180. permissions |= FTP_LP_MALFORMATED_PERM;
  181. if(str[1] == 'w')
  182. permissions |= 1 << 7;
  183. else if(str[1] != '-')
  184. permissions |= FTP_LP_MALFORMATED_PERM;
  185. if(str[2] == 'x')
  186. permissions |= 1 << 6;
  187. else if(str[2] == 's') {
  188. permissions |= 1 << 6;
  189. permissions |= 1 << 11;
  190. }
  191. else if(str[2] == 'S')
  192. permissions |= 1 << 11;
  193. else if(str[2] != '-')
  194. permissions |= FTP_LP_MALFORMATED_PERM;
  195. /* GROUP */
  196. if(str[3] == 'r')
  197. permissions |= 1 << 5;
  198. else if(str[3] != '-')
  199. permissions |= FTP_LP_MALFORMATED_PERM;
  200. if(str[4] == 'w')
  201. permissions |= 1 << 4;
  202. else if(str[4] != '-')
  203. permissions |= FTP_LP_MALFORMATED_PERM;
  204. if(str[5] == 'x')
  205. permissions |= 1 << 3;
  206. else if(str[5] == 's') {
  207. permissions |= 1 << 3;
  208. permissions |= 1 << 10;
  209. }
  210. else if(str[5] == 'S')
  211. permissions |= 1 << 10;
  212. else if(str[5] != '-')
  213. permissions |= FTP_LP_MALFORMATED_PERM;
  214. /* others */
  215. if(str[6] == 'r')
  216. permissions |= 1 << 2;
  217. else if(str[6] != '-')
  218. permissions |= FTP_LP_MALFORMATED_PERM;
  219. if(str[7] == 'w')
  220. permissions |= 1 << 1;
  221. else if(str[7] != '-')
  222. permissions |= FTP_LP_MALFORMATED_PERM;
  223. if(str[8] == 'x')
  224. permissions |= 1;
  225. else if(str[8] == 't') {
  226. permissions |= 1;
  227. permissions |= 1 << 9;
  228. }
  229. else if(str[8] == 'T')
  230. permissions |= 1 << 9;
  231. else if(str[8] != '-')
  232. permissions |= FTP_LP_MALFORMATED_PERM;
  233. return permissions;
  234. }
  235. static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
  236. struct fileinfo *infop)
  237. {
  238. curl_fnmatch_callback compare;
  239. struct WildcardData *wc = &conn->data->wildcard;
  240. struct ftp_wc_tmpdata *tmpdata = wc->tmp;
  241. struct curl_llist *llist = &wc->filelist;
  242. struct ftp_parselist_data *parser = tmpdata->parser;
  243. bool add = TRUE;
  244. struct curl_fileinfo *finfo = &infop->info;
  245. /* move finfo pointers to b_data */
  246. char *str = finfo->b_data;
  247. finfo->filename = str + parser->offsets.filename;
  248. finfo->strings.group = parser->offsets.group ?
  249. str + parser->offsets.group : NULL;
  250. finfo->strings.perm = parser->offsets.perm ?
  251. str + parser->offsets.perm : NULL;
  252. finfo->strings.target = parser->offsets.symlink_target ?
  253. str + parser->offsets.symlink_target : NULL;
  254. finfo->strings.time = str + parser->offsets.time;
  255. finfo->strings.user = parser->offsets.user ?
  256. str + parser->offsets.user : NULL;
  257. /* get correct fnmatch callback */
  258. compare = conn->data->set.fnmatch;
  259. if(!compare)
  260. compare = Curl_fnmatch;
  261. /* filter pattern-corresponding filenames */
  262. if(compare(conn->data->set.fnmatch_data, wc->pattern,
  263. finfo->filename) == 0) {
  264. /* discard symlink which is containing multiple " -> " */
  265. if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
  266. (strstr(finfo->strings.target, " -> "))) {
  267. add = FALSE;
  268. }
  269. }
  270. else {
  271. add = FALSE;
  272. }
  273. if(add) {
  274. Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
  275. }
  276. else {
  277. Curl_fileinfo_dtor(NULL, finfo);
  278. }
  279. tmpdata->parser->file_data = NULL;
  280. return CURLE_OK;
  281. }
  282. size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
  283. void *connptr)
  284. {
  285. size_t bufflen = size*nmemb;
  286. struct connectdata *conn = (struct connectdata *)connptr;
  287. struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
  288. struct ftp_parselist_data *parser = tmpdata->parser;
  289. struct fileinfo *infop;
  290. struct curl_fileinfo *finfo;
  291. unsigned long i = 0;
  292. CURLcode result;
  293. size_t retsize = bufflen;
  294. if(parser->error) { /* error in previous call */
  295. /* scenario:
  296. * 1. call => OK..
  297. * 2. call => OUT_OF_MEMORY (or other error)
  298. * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
  299. * in wc_statemach()
  300. */
  301. goto fail;
  302. }
  303. if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
  304. /* considering info about FILE response format */
  305. parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
  306. OS_TYPE_WIN_NT : OS_TYPE_UNIX;
  307. }
  308. while(i < bufflen) { /* FSM */
  309. char c = buffer[i];
  310. if(!parser->file_data) { /* tmp file data is not allocated yet */
  311. parser->file_data = Curl_fileinfo_alloc();
  312. if(!parser->file_data) {
  313. parser->error = CURLE_OUT_OF_MEMORY;
  314. goto fail;
  315. }
  316. parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
  317. if(!parser->file_data->info.b_data) {
  318. parser->error = CURLE_OUT_OF_MEMORY;
  319. goto fail;
  320. }
  321. parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
  322. parser->item_offset = 0;
  323. parser->item_length = 0;
  324. }
  325. infop = parser->file_data;
  326. finfo = &infop->info;
  327. finfo->b_data[finfo->b_used++] = c;
  328. if(finfo->b_used >= finfo->b_size - 1) {
  329. /* if it is important, extend buffer space for file data */
  330. char *tmp = realloc(finfo->b_data,
  331. finfo->b_size + FTP_BUFFER_ALLOCSIZE);
  332. if(tmp) {
  333. finfo->b_size += FTP_BUFFER_ALLOCSIZE;
  334. finfo->b_data = tmp;
  335. }
  336. else {
  337. Curl_fileinfo_dtor(NULL, parser->file_data);
  338. parser->file_data = NULL;
  339. parser->error = CURLE_OUT_OF_MEMORY;
  340. goto fail;
  341. }
  342. }
  343. switch(parser->os_type) {
  344. case OS_TYPE_UNIX:
  345. switch(parser->state.UNIX.main) {
  346. case PL_UNIX_TOTALSIZE:
  347. switch(parser->state.UNIX.sub.total_dirsize) {
  348. case PL_UNIX_TOTALSIZE_INIT:
  349. if(c == 't') {
  350. parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
  351. parser->item_length++;
  352. }
  353. else {
  354. parser->state.UNIX.main = PL_UNIX_FILETYPE;
  355. /* start FSM again not considering size of directory */
  356. finfo->b_used = 0;
  357. i--;
  358. }
  359. break;
  360. case PL_UNIX_TOTALSIZE_READING:
  361. parser->item_length++;
  362. if(c == '\r') {
  363. parser->item_length--;
  364. finfo->b_used--;
  365. }
  366. else if(c == '\n') {
  367. finfo->b_data[parser->item_length - 1] = 0;
  368. if(strncmp("total ", finfo->b_data, 6) == 0) {
  369. char *endptr = finfo->b_data + 6;
  370. /* here we can deal with directory size, pass the leading white
  371. spaces and then the digits */
  372. while(ISSPACE(*endptr))
  373. endptr++;
  374. while(ISDIGIT(*endptr))
  375. endptr++;
  376. if(*endptr != 0) {
  377. parser->error = CURLE_FTP_BAD_FILE_LIST;
  378. goto fail;
  379. }
  380. parser->state.UNIX.main = PL_UNIX_FILETYPE;
  381. finfo->b_used = 0;
  382. }
  383. else {
  384. parser->error = CURLE_FTP_BAD_FILE_LIST;
  385. goto fail;
  386. }
  387. }
  388. break;
  389. }
  390. break;
  391. case PL_UNIX_FILETYPE:
  392. switch(c) {
  393. case '-':
  394. finfo->filetype = CURLFILETYPE_FILE;
  395. break;
  396. case 'd':
  397. finfo->filetype = CURLFILETYPE_DIRECTORY;
  398. break;
  399. case 'l':
  400. finfo->filetype = CURLFILETYPE_SYMLINK;
  401. break;
  402. case 'p':
  403. finfo->filetype = CURLFILETYPE_NAMEDPIPE;
  404. break;
  405. case 's':
  406. finfo->filetype = CURLFILETYPE_SOCKET;
  407. break;
  408. case 'c':
  409. finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
  410. break;
  411. case 'b':
  412. finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
  413. break;
  414. case 'D':
  415. finfo->filetype = CURLFILETYPE_DOOR;
  416. break;
  417. default:
  418. parser->error = CURLE_FTP_BAD_FILE_LIST;
  419. goto fail;
  420. }
  421. parser->state.UNIX.main = PL_UNIX_PERMISSION;
  422. parser->item_length = 0;
  423. parser->item_offset = 1;
  424. break;
  425. case PL_UNIX_PERMISSION:
  426. parser->item_length++;
  427. if(parser->item_length <= 9) {
  428. if(!strchr("rwx-tTsS", c)) {
  429. parser->error = CURLE_FTP_BAD_FILE_LIST;
  430. goto fail;
  431. }
  432. }
  433. else if(parser->item_length == 10) {
  434. unsigned int perm;
  435. if(c != ' ') {
  436. parser->error = CURLE_FTP_BAD_FILE_LIST;
  437. goto fail;
  438. }
  439. finfo->b_data[10] = 0; /* terminate permissions */
  440. perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
  441. if(perm & FTP_LP_MALFORMATED_PERM) {
  442. parser->error = CURLE_FTP_BAD_FILE_LIST;
  443. goto fail;
  444. }
  445. parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
  446. parser->file_data->info.perm = perm;
  447. parser->offsets.perm = parser->item_offset;
  448. parser->item_length = 0;
  449. parser->state.UNIX.main = PL_UNIX_HLINKS;
  450. parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
  451. }
  452. break;
  453. case PL_UNIX_HLINKS:
  454. switch(parser->state.UNIX.sub.hlinks) {
  455. case PL_UNIX_HLINKS_PRESPACE:
  456. if(c != ' ') {
  457. if(c >= '0' && c <= '9') {
  458. parser->item_offset = finfo->b_used - 1;
  459. parser->item_length = 1;
  460. parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
  461. }
  462. else {
  463. parser->error = CURLE_FTP_BAD_FILE_LIST;
  464. goto fail;
  465. }
  466. }
  467. break;
  468. case PL_UNIX_HLINKS_NUMBER:
  469. parser->item_length ++;
  470. if(c == ' ') {
  471. char *p;
  472. long int hlinks;
  473. finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
  474. hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
  475. if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
  476. parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
  477. parser->file_data->info.hardlinks = hlinks;
  478. }
  479. parser->item_length = 0;
  480. parser->item_offset = 0;
  481. parser->state.UNIX.main = PL_UNIX_USER;
  482. parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
  483. }
  484. else if(c < '0' || c > '9') {
  485. parser->error = CURLE_FTP_BAD_FILE_LIST;
  486. goto fail;
  487. }
  488. break;
  489. }
  490. break;
  491. case PL_UNIX_USER:
  492. switch(parser->state.UNIX.sub.user) {
  493. case PL_UNIX_USER_PRESPACE:
  494. if(c != ' ') {
  495. parser->item_offset = finfo->b_used - 1;
  496. parser->item_length = 1;
  497. parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
  498. }
  499. break;
  500. case PL_UNIX_USER_PARSING:
  501. parser->item_length++;
  502. if(c == ' ') {
  503. finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
  504. parser->offsets.user = parser->item_offset;
  505. parser->state.UNIX.main = PL_UNIX_GROUP;
  506. parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
  507. parser->item_offset = 0;
  508. parser->item_length = 0;
  509. }
  510. break;
  511. }
  512. break;
  513. case PL_UNIX_GROUP:
  514. switch(parser->state.UNIX.sub.group) {
  515. case PL_UNIX_GROUP_PRESPACE:
  516. if(c != ' ') {
  517. parser->item_offset = finfo->b_used - 1;
  518. parser->item_length = 1;
  519. parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
  520. }
  521. break;
  522. case PL_UNIX_GROUP_NAME:
  523. parser->item_length++;
  524. if(c == ' ') {
  525. finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
  526. parser->offsets.group = parser->item_offset;
  527. parser->state.UNIX.main = PL_UNIX_SIZE;
  528. parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
  529. parser->item_offset = 0;
  530. parser->item_length = 0;
  531. }
  532. break;
  533. }
  534. break;
  535. case PL_UNIX_SIZE:
  536. switch(parser->state.UNIX.sub.size) {
  537. case PL_UNIX_SIZE_PRESPACE:
  538. if(c != ' ') {
  539. if(c >= '0' && c <= '9') {
  540. parser->item_offset = finfo->b_used - 1;
  541. parser->item_length = 1;
  542. parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
  543. }
  544. else {
  545. parser->error = CURLE_FTP_BAD_FILE_LIST;
  546. goto fail;
  547. }
  548. }
  549. break;
  550. case PL_UNIX_SIZE_NUMBER:
  551. parser->item_length++;
  552. if(c == ' ') {
  553. char *p;
  554. curl_off_t fsize;
  555. finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
  556. if(!curlx_strtoofft(finfo->b_data + parser->item_offset,
  557. &p, 10, &fsize)) {
  558. if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
  559. fsize != CURL_OFF_T_MIN) {
  560. parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
  561. parser->file_data->info.size = fsize;
  562. }
  563. parser->item_length = 0;
  564. parser->item_offset = 0;
  565. parser->state.UNIX.main = PL_UNIX_TIME;
  566. parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
  567. }
  568. }
  569. else if(!ISDIGIT(c)) {
  570. parser->error = CURLE_FTP_BAD_FILE_LIST;
  571. goto fail;
  572. }
  573. break;
  574. }
  575. break;
  576. case PL_UNIX_TIME:
  577. switch(parser->state.UNIX.sub.time) {
  578. case PL_UNIX_TIME_PREPART1:
  579. if(c != ' ') {
  580. if(ISALNUM(c)) {
  581. parser->item_offset = finfo->b_used -1;
  582. parser->item_length = 1;
  583. parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
  584. }
  585. else {
  586. parser->error = CURLE_FTP_BAD_FILE_LIST;
  587. goto fail;
  588. }
  589. }
  590. break;
  591. case PL_UNIX_TIME_PART1:
  592. parser->item_length++;
  593. if(c == ' ') {
  594. parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
  595. }
  596. else if(!ISALNUM(c) && c != '.') {
  597. parser->error = CURLE_FTP_BAD_FILE_LIST;
  598. goto fail;
  599. }
  600. break;
  601. case PL_UNIX_TIME_PREPART2:
  602. parser->item_length++;
  603. if(c != ' ') {
  604. if(ISALNUM(c)) {
  605. parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
  606. }
  607. else {
  608. parser->error = CURLE_FTP_BAD_FILE_LIST;
  609. goto fail;
  610. }
  611. }
  612. break;
  613. case PL_UNIX_TIME_PART2:
  614. parser->item_length++;
  615. if(c == ' ') {
  616. parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
  617. }
  618. else if(!ISALNUM(c) && c != '.') {
  619. parser->error = CURLE_FTP_BAD_FILE_LIST;
  620. goto fail;
  621. }
  622. break;
  623. case PL_UNIX_TIME_PREPART3:
  624. parser->item_length++;
  625. if(c != ' ') {
  626. if(ISALNUM(c)) {
  627. parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
  628. }
  629. else {
  630. parser->error = CURLE_FTP_BAD_FILE_LIST;
  631. goto fail;
  632. }
  633. }
  634. break;
  635. case PL_UNIX_TIME_PART3:
  636. parser->item_length++;
  637. if(c == ' ') {
  638. finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
  639. parser->offsets.time = parser->item_offset;
  640. /*
  641. if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
  642. parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
  643. }
  644. */
  645. if(finfo->filetype == CURLFILETYPE_SYMLINK) {
  646. parser->state.UNIX.main = PL_UNIX_SYMLINK;
  647. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
  648. }
  649. else {
  650. parser->state.UNIX.main = PL_UNIX_FILENAME;
  651. parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
  652. }
  653. }
  654. else if(!ISALNUM(c) && c != '.' && c != ':') {
  655. parser->error = CURLE_FTP_BAD_FILE_LIST;
  656. goto fail;
  657. }
  658. break;
  659. }
  660. break;
  661. case PL_UNIX_FILENAME:
  662. switch(parser->state.UNIX.sub.filename) {
  663. case PL_UNIX_FILENAME_PRESPACE:
  664. if(c != ' ') {
  665. parser->item_offset = finfo->b_used - 1;
  666. parser->item_length = 1;
  667. parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
  668. }
  669. break;
  670. case PL_UNIX_FILENAME_NAME:
  671. parser->item_length++;
  672. if(c == '\r') {
  673. parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
  674. }
  675. else if(c == '\n') {
  676. finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
  677. parser->offsets.filename = parser->item_offset;
  678. parser->state.UNIX.main = PL_UNIX_FILETYPE;
  679. result = ftp_pl_insert_finfo(conn, infop);
  680. if(result) {
  681. parser->error = result;
  682. goto fail;
  683. }
  684. }
  685. break;
  686. case PL_UNIX_FILENAME_WINDOWSEOL:
  687. if(c == '\n') {
  688. finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
  689. parser->offsets.filename = parser->item_offset;
  690. parser->state.UNIX.main = PL_UNIX_FILETYPE;
  691. result = ftp_pl_insert_finfo(conn, infop);
  692. if(result) {
  693. parser->error = result;
  694. goto fail;
  695. }
  696. }
  697. else {
  698. parser->error = CURLE_FTP_BAD_FILE_LIST;
  699. goto fail;
  700. }
  701. break;
  702. }
  703. break;
  704. case PL_UNIX_SYMLINK:
  705. switch(parser->state.UNIX.sub.symlink) {
  706. case PL_UNIX_SYMLINK_PRESPACE:
  707. if(c != ' ') {
  708. parser->item_offset = finfo->b_used - 1;
  709. parser->item_length = 1;
  710. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
  711. }
  712. break;
  713. case PL_UNIX_SYMLINK_NAME:
  714. parser->item_length++;
  715. if(c == ' ') {
  716. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
  717. }
  718. else if(c == '\r' || c == '\n') {
  719. parser->error = CURLE_FTP_BAD_FILE_LIST;
  720. goto fail;
  721. }
  722. break;
  723. case PL_UNIX_SYMLINK_PRETARGET1:
  724. parser->item_length++;
  725. if(c == '-') {
  726. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
  727. }
  728. else if(c == '\r' || c == '\n') {
  729. parser->error = CURLE_FTP_BAD_FILE_LIST;
  730. goto fail;
  731. }
  732. else {
  733. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
  734. }
  735. break;
  736. case PL_UNIX_SYMLINK_PRETARGET2:
  737. parser->item_length++;
  738. if(c == '>') {
  739. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
  740. }
  741. else if(c == '\r' || c == '\n') {
  742. parser->error = CURLE_FTP_BAD_FILE_LIST;
  743. goto fail;
  744. }
  745. else {
  746. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
  747. }
  748. break;
  749. case PL_UNIX_SYMLINK_PRETARGET3:
  750. parser->item_length++;
  751. if(c == ' ') {
  752. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
  753. /* now place where is symlink following */
  754. finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
  755. parser->offsets.filename = parser->item_offset;
  756. parser->item_length = 0;
  757. parser->item_offset = 0;
  758. }
  759. else if(c == '\r' || c == '\n') {
  760. parser->error = CURLE_FTP_BAD_FILE_LIST;
  761. goto fail;
  762. }
  763. else {
  764. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
  765. }
  766. break;
  767. case PL_UNIX_SYMLINK_PRETARGET4:
  768. if(c != '\r' && c != '\n') {
  769. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
  770. parser->item_offset = finfo->b_used - 1;
  771. parser->item_length = 1;
  772. }
  773. else {
  774. parser->error = CURLE_FTP_BAD_FILE_LIST;
  775. goto fail;
  776. }
  777. break;
  778. case PL_UNIX_SYMLINK_TARGET:
  779. parser->item_length++;
  780. if(c == '\r') {
  781. parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
  782. }
  783. else if(c == '\n') {
  784. finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
  785. parser->offsets.symlink_target = parser->item_offset;
  786. result = ftp_pl_insert_finfo(conn, infop);
  787. if(result) {
  788. parser->error = result;
  789. goto fail;
  790. }
  791. parser->state.UNIX.main = PL_UNIX_FILETYPE;
  792. }
  793. break;
  794. case PL_UNIX_SYMLINK_WINDOWSEOL:
  795. if(c == '\n') {
  796. finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
  797. parser->offsets.symlink_target = parser->item_offset;
  798. result = ftp_pl_insert_finfo(conn, infop);
  799. if(result) {
  800. parser->error = result;
  801. goto fail;
  802. }
  803. parser->state.UNIX.main = PL_UNIX_FILETYPE;
  804. }
  805. else {
  806. parser->error = CURLE_FTP_BAD_FILE_LIST;
  807. goto fail;
  808. }
  809. break;
  810. }
  811. break;
  812. }
  813. break;
  814. case OS_TYPE_WIN_NT:
  815. switch(parser->state.NT.main) {
  816. case PL_WINNT_DATE:
  817. parser->item_length++;
  818. if(parser->item_length < 9) {
  819. if(!strchr("0123456789-", c)) { /* only simple control */
  820. parser->error = CURLE_FTP_BAD_FILE_LIST;
  821. goto fail;
  822. }
  823. }
  824. else if(parser->item_length == 9) {
  825. if(c == ' ') {
  826. parser->state.NT.main = PL_WINNT_TIME;
  827. parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
  828. }
  829. else {
  830. parser->error = CURLE_FTP_BAD_FILE_LIST;
  831. goto fail;
  832. }
  833. }
  834. else {
  835. parser->error = CURLE_FTP_BAD_FILE_LIST;
  836. goto fail;
  837. }
  838. break;
  839. case PL_WINNT_TIME:
  840. parser->item_length++;
  841. switch(parser->state.NT.sub.time) {
  842. case PL_WINNT_TIME_PRESPACE:
  843. if(!ISSPACE(c)) {
  844. parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
  845. }
  846. break;
  847. case PL_WINNT_TIME_TIME:
  848. if(c == ' ') {
  849. parser->offsets.time = parser->item_offset;
  850. finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
  851. parser->state.NT.main = PL_WINNT_DIRORSIZE;
  852. parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
  853. parser->item_length = 0;
  854. }
  855. else if(!strchr("APM0123456789:", c)) {
  856. parser->error = CURLE_FTP_BAD_FILE_LIST;
  857. goto fail;
  858. }
  859. break;
  860. }
  861. break;
  862. case PL_WINNT_DIRORSIZE:
  863. switch(parser->state.NT.sub.dirorsize) {
  864. case PL_WINNT_DIRORSIZE_PRESPACE:
  865. if(c == ' ') {
  866. }
  867. else {
  868. parser->item_offset = finfo->b_used - 1;
  869. parser->item_length = 1;
  870. parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
  871. }
  872. break;
  873. case PL_WINNT_DIRORSIZE_CONTENT:
  874. parser->item_length ++;
  875. if(c == ' ') {
  876. finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
  877. if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
  878. finfo->filetype = CURLFILETYPE_DIRECTORY;
  879. finfo->size = 0;
  880. }
  881. else {
  882. char *endptr;
  883. if(curlx_strtoofft(finfo->b_data +
  884. parser->item_offset,
  885. &endptr, 10, &finfo->size)) {
  886. parser->error = CURLE_FTP_BAD_FILE_LIST;
  887. goto fail;
  888. }
  889. /* correct file type */
  890. parser->file_data->info.filetype = CURLFILETYPE_FILE;
  891. }
  892. parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
  893. parser->item_length = 0;
  894. parser->state.NT.main = PL_WINNT_FILENAME;
  895. parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
  896. }
  897. break;
  898. }
  899. break;
  900. case PL_WINNT_FILENAME:
  901. switch(parser->state.NT.sub.filename) {
  902. case PL_WINNT_FILENAME_PRESPACE:
  903. if(c != ' ') {
  904. parser->item_offset = finfo->b_used -1;
  905. parser->item_length = 1;
  906. parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
  907. }
  908. break;
  909. case PL_WINNT_FILENAME_CONTENT:
  910. parser->item_length++;
  911. if(c == '\r') {
  912. parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
  913. finfo->b_data[finfo->b_used - 1] = 0;
  914. }
  915. else if(c == '\n') {
  916. parser->offsets.filename = parser->item_offset;
  917. finfo->b_data[finfo->b_used - 1] = 0;
  918. parser->offsets.filename = parser->item_offset;
  919. result = ftp_pl_insert_finfo(conn, infop);
  920. if(result) {
  921. parser->error = result;
  922. goto fail;
  923. }
  924. parser->state.NT.main = PL_WINNT_DATE;
  925. parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
  926. }
  927. break;
  928. case PL_WINNT_FILENAME_WINEOL:
  929. if(c == '\n') {
  930. parser->offsets.filename = parser->item_offset;
  931. result = ftp_pl_insert_finfo(conn, infop);
  932. if(result) {
  933. parser->error = result;
  934. goto fail;
  935. }
  936. parser->state.NT.main = PL_WINNT_DATE;
  937. parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
  938. }
  939. else {
  940. parser->error = CURLE_FTP_BAD_FILE_LIST;
  941. goto fail;
  942. }
  943. break;
  944. }
  945. break;
  946. }
  947. break;
  948. default:
  949. retsize = bufflen + 1;
  950. goto fail;
  951. }
  952. i++;
  953. }
  954. fail:
  955. /* Clean up any allocated memory. */
  956. if(parser->file_data) {
  957. Curl_fileinfo_dtor(NULL, parser->file_data);
  958. parser->file_data = NULL;
  959. }
  960. return retsize;
  961. }
  962. #endif /* CURL_DISABLE_FTP */