ftplistparser.c 31 KB

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