parse_ls_vga.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. /*
  2. Routines for parsing output from the 'ls' command.
  3. Copyright (C) 1988, 1992, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
  4. 2005, 2006, 2007, 2011
  5. The Free Software Foundation, Inc.
  6. Copyright (C) 1995, 1996 Miguel de Icaza
  7. Written by:
  8. Miguel de Icaza, 1995, 1996
  9. Slava Zanko <slavazanko@gmail.com>, 2011
  10. This file is part of the Midnight Commander.
  11. The Midnight Commander is free software: you can redistribute it
  12. and/or modify it under the terms of the GNU General Public License as
  13. published by the Free Software Foundation, either version 3 of the License,
  14. or (at your option) any later version.
  15. The Midnight Commander is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU General Public License for more details.
  19. You should have received a copy of the GNU General Public License
  20. along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * \file
  24. * \brief Source: Utilities for VFS modules
  25. * \author Miguel de Icaza
  26. * \date 1995, 1996
  27. */
  28. #include <config.h>
  29. #include <ctype.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include "lib/global.h"
  33. #include "lib/unixcompat.h" /* makedev */
  34. #include "lib/widget.h" /* message() */
  35. #include "utilvfs.h"
  36. /*** global variables ****************************************************************************/
  37. /*** file scope macro definitions ****************************************************************/
  38. /* Parsing code is used by ftpfs, fish and extfs */
  39. #define MAXCOLS 30
  40. /*** file scope type declarations ****************************************************************/
  41. /*** file scope variables ************************************************************************/
  42. static char *columns[MAXCOLS]; /* Points to the string in column n */
  43. static int column_ptr[MAXCOLS]; /* Index from 0 to the starting positions of the columns */
  44. static size_t vfs_parce_ls_final_num_spaces = 0;
  45. /*** file scope functions ************************************************************************/
  46. /* --------------------------------------------------------------------------------------------- */
  47. static int
  48. is_num (int idx)
  49. {
  50. char *column = columns[idx];
  51. if (!column || column[0] < '0' || column[0] > '9')
  52. return 0;
  53. return 1;
  54. }
  55. /* --------------------------------------------------------------------------------------------- */
  56. /* Return 1 for MM-DD-YY and MM-DD-YYYY */
  57. static int
  58. is_dos_date (const char *str)
  59. {
  60. int len;
  61. if (!str)
  62. return 0;
  63. len = strlen (str);
  64. if (len != 8 && len != 10)
  65. return 0;
  66. if (str[2] != str[5])
  67. return 0;
  68. if (!strchr ("\\-/", (int) str[2]))
  69. return 0;
  70. return 1;
  71. }
  72. /* --------------------------------------------------------------------------------------------- */
  73. static int
  74. is_week (const char *str, struct tm *tim)
  75. {
  76. static const char *week = "SunMonTueWedThuFriSat";
  77. const char *pos;
  78. if (!str)
  79. return 0;
  80. pos = strstr (week, str);
  81. if (pos != NULL)
  82. {
  83. if (tim != NULL)
  84. tim->tm_wday = (pos - week) / 3;
  85. return 1;
  86. }
  87. return 0;
  88. }
  89. /* --------------------------------------------------------------------------------------------- */
  90. static int
  91. is_month (const char *str, struct tm *tim)
  92. {
  93. static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
  94. const char *pos;
  95. if (!str)
  96. return 0;
  97. pos = strstr (month, str);
  98. if (pos != NULL)
  99. {
  100. if (tim != NULL)
  101. tim->tm_mon = (pos - month) / 3;
  102. return 1;
  103. }
  104. return 0;
  105. }
  106. /* --------------------------------------------------------------------------------------------- */
  107. /**
  108. * Check for possible locale's abbreviated month name (Jan..Dec).
  109. * Any 3 bytes long string without digit, control and punctuation characters.
  110. * isalpha() is locale specific, so it cannot be used if current
  111. * locale is "C" and ftp server use Cyrillic.
  112. * NB: It is assumed there are no whitespaces in month.
  113. */
  114. static int
  115. is_localized_month (const char *month)
  116. {
  117. int i = 0;
  118. if (!month)
  119. return 0;
  120. while ((i < 3) && *month && !isdigit ((unsigned char) *month)
  121. && !iscntrl ((unsigned char) *month) && !ispunct ((unsigned char) *month))
  122. {
  123. i++;
  124. month++;
  125. }
  126. return ((i == 3) && (*month == 0));
  127. }
  128. /* --------------------------------------------------------------------------------------------- */
  129. static int
  130. is_time (const char *str, struct tm *tim)
  131. {
  132. const char *p, *p2;
  133. if (str == NULL)
  134. return 0;
  135. p = strchr (str, ':');
  136. p2 = strrchr (str, ':');
  137. if (p != NULL && p2 != NULL)
  138. {
  139. if (p != p2)
  140. {
  141. if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
  142. return 0;
  143. }
  144. else
  145. {
  146. if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
  147. return 0;
  148. }
  149. }
  150. else
  151. return 0;
  152. return 1;
  153. }
  154. /* --------------------------------------------------------------------------------------------- */
  155. static int
  156. is_year (char *str, struct tm *tim)
  157. {
  158. long year;
  159. if (!str)
  160. return 0;
  161. if (strchr (str, ':'))
  162. return 0;
  163. if (strlen (str) != 4)
  164. return 0;
  165. /* cppcheck-suppress invalidscanf */
  166. if (sscanf (str, "%ld", &year) != 1)
  167. return 0;
  168. if (year < 1900 || year > 3000)
  169. return 0;
  170. tim->tm_year = (int) (year - 1900);
  171. return 1;
  172. }
  173. /* --------------------------------------------------------------------------------------------- */
  174. /*** public functions ****************************************************************************/
  175. /* --------------------------------------------------------------------------------------------- */
  176. gboolean
  177. vfs_parse_filetype (const char *s, size_t * ret_skipped, mode_t * ret_type)
  178. {
  179. mode_t type;
  180. switch (*s)
  181. {
  182. case 'd':
  183. type = S_IFDIR;
  184. break;
  185. case 'b':
  186. type = S_IFBLK;
  187. break;
  188. case 'c':
  189. type = S_IFCHR;
  190. break;
  191. case 'l':
  192. type = S_IFLNK;
  193. break;
  194. #ifdef S_IFSOCK
  195. case 's':
  196. type = S_IFSOCK;
  197. break;
  198. #else
  199. case 's':
  200. type = S_IFIFO;
  201. break;
  202. #endif
  203. #ifdef S_IFDOOR /* Solaris door */
  204. case 'D':
  205. type = S_IFDOOR;
  206. break;
  207. #else
  208. case 'D':
  209. type = S_IFIFO;
  210. break;
  211. #endif
  212. case 'p':
  213. type = S_IFIFO;
  214. break;
  215. #ifdef S_IFNAM /* Special named files */
  216. case 'n':
  217. type = S_IFNAM;
  218. break;
  219. #else
  220. case 'n':
  221. type = S_IFREG;
  222. break;
  223. #endif
  224. case 'm': /* Don't know what these are :-) */
  225. case '-':
  226. case '?':
  227. type = S_IFREG;
  228. break;
  229. default:
  230. return FALSE;
  231. }
  232. *ret_type = type;
  233. *ret_skipped = 1;
  234. return TRUE;
  235. }
  236. /* --------------------------------------------------------------------------------------------- */
  237. gboolean
  238. vfs_parse_fileperms (const char *s, size_t * ret_skipped, mode_t * ret_perms)
  239. {
  240. const char *p;
  241. mode_t perms;
  242. p = s;
  243. perms = 0;
  244. switch (*p++)
  245. {
  246. case '-':
  247. break;
  248. case 'r':
  249. perms |= S_IRUSR;
  250. break;
  251. default:
  252. return FALSE;
  253. }
  254. switch (*p++)
  255. {
  256. case '-':
  257. break;
  258. case 'w':
  259. perms |= S_IWUSR;
  260. break;
  261. default:
  262. return FALSE;
  263. }
  264. switch (*p++)
  265. {
  266. case '-':
  267. break;
  268. case 'S':
  269. perms |= S_ISUID;
  270. break;
  271. case 's':
  272. perms |= S_IXUSR | S_ISUID;
  273. break;
  274. case 'x':
  275. perms |= S_IXUSR;
  276. break;
  277. default:
  278. return FALSE;
  279. }
  280. switch (*p++)
  281. {
  282. case '-':
  283. break;
  284. case 'r':
  285. perms |= S_IRGRP;
  286. break;
  287. default:
  288. return FALSE;
  289. }
  290. switch (*p++)
  291. {
  292. case '-':
  293. break;
  294. case 'w':
  295. perms |= S_IWGRP;
  296. break;
  297. default:
  298. return FALSE;
  299. }
  300. switch (*p++)
  301. {
  302. case '-':
  303. break;
  304. case 'S':
  305. perms |= S_ISGID;
  306. break;
  307. case 'l':
  308. perms |= S_ISGID;
  309. break; /* found on Solaris */
  310. case 's':
  311. perms |= S_IXGRP | S_ISGID;
  312. break;
  313. case 'x':
  314. perms |= S_IXGRP;
  315. break;
  316. default:
  317. return FALSE;
  318. }
  319. switch (*p++)
  320. {
  321. case '-':
  322. break;
  323. case 'r':
  324. perms |= S_IROTH;
  325. break;
  326. default:
  327. return FALSE;
  328. }
  329. switch (*p++)
  330. {
  331. case '-':
  332. break;
  333. case 'w':
  334. perms |= S_IWOTH;
  335. break;
  336. default:
  337. return FALSE;
  338. }
  339. switch (*p++)
  340. {
  341. case '-':
  342. break;
  343. case 'T':
  344. perms |= S_ISVTX;
  345. break;
  346. case 't':
  347. perms |= S_IXOTH | S_ISVTX;
  348. break;
  349. case 'x':
  350. perms |= S_IXOTH;
  351. break;
  352. default:
  353. return FALSE;
  354. }
  355. if (*p == '+')
  356. { /* ACLs on Solaris, HP-UX and others */
  357. p++;
  358. }
  359. *ret_skipped = p - s;
  360. *ret_perms = perms;
  361. return TRUE;
  362. }
  363. /* --------------------------------------------------------------------------------------------- */
  364. gboolean
  365. vfs_parse_filemode (const char *s, size_t * ret_skipped, mode_t * ret_mode)
  366. {
  367. const char *p;
  368. mode_t type, perms;
  369. size_t skipped;
  370. p = s;
  371. if (!vfs_parse_filetype (p, &skipped, &type))
  372. return FALSE;
  373. p += skipped;
  374. if (!vfs_parse_fileperms (p, &skipped, &perms))
  375. return FALSE;
  376. p += skipped;
  377. *ret_skipped = p - s;
  378. *ret_mode = type | perms;
  379. return TRUE;
  380. }
  381. /* --------------------------------------------------------------------------------------------- */
  382. gboolean
  383. vfs_parse_raw_filemode (const char *s, size_t * ret_skipped, mode_t * ret_mode)
  384. {
  385. const char *p;
  386. mode_t remote_type = 0, local_type, perms = 0;
  387. p = s;
  388. /* isoctal */
  389. while (*p >= '0' && *p <= '7')
  390. {
  391. perms *= 010;
  392. perms += (*p - '0');
  393. ++p;
  394. }
  395. if (*p++ != ' ')
  396. return FALSE;
  397. while (*p >= '0' && *p <= '7')
  398. {
  399. remote_type *= 010;
  400. remote_type += (*p - '0');
  401. ++p;
  402. }
  403. if (*p++ != ' ')
  404. return FALSE;
  405. /* generated with:
  406. $ perl -e 'use Fcntl ":mode";
  407. my @modes = (S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFREG);
  408. foreach $t (@modes) { printf ("%o\n", $t); };'
  409. TODO: S_IFDOOR, S_IFIFO, S_IFSOCK (if supported by os)
  410. (see vfs_parse_filetype)
  411. */
  412. switch (remote_type)
  413. {
  414. case 020000:
  415. local_type = S_IFCHR;
  416. break;
  417. case 040000:
  418. local_type = S_IFDIR;
  419. break;
  420. case 060000:
  421. local_type = S_IFBLK;
  422. break;
  423. case 0120000:
  424. local_type = S_IFLNK;
  425. break;
  426. case 0100000:
  427. default: /* don't know what is it */
  428. local_type = S_IFREG;
  429. break;
  430. }
  431. *ret_skipped = p - s;
  432. *ret_mode = local_type | perms;
  433. return TRUE;
  434. }
  435. /* --------------------------------------------------------------------------------------------- */
  436. /** This function parses from idx in the columns[] array */
  437. int
  438. vfs_parse_filedate (int idx, time_t * t)
  439. {
  440. char *p;
  441. struct tm tim;
  442. int d[3];
  443. int got_year = 0;
  444. int l10n = 0; /* Locale's abbreviated month name */
  445. time_t current_time;
  446. struct tm *local_time;
  447. /* Let's setup default time values */
  448. current_time = time (NULL);
  449. local_time = localtime (&current_time);
  450. tim.tm_mday = local_time->tm_mday;
  451. tim.tm_mon = local_time->tm_mon;
  452. tim.tm_year = local_time->tm_year;
  453. tim.tm_hour = 0;
  454. tim.tm_min = 0;
  455. tim.tm_sec = 0;
  456. tim.tm_isdst = -1; /* Let mktime() try to guess correct dst offset */
  457. p = columns[idx++];
  458. /* We eat weekday name in case of extfs */
  459. if (is_week (p, &tim))
  460. p = columns[idx++];
  461. /* Month name */
  462. if (is_month (p, &tim))
  463. {
  464. /* And we expect, it followed by day number */
  465. if (is_num (idx))
  466. tim.tm_mday = (int) atol (columns[idx++]);
  467. else
  468. return 0; /* No day */
  469. }
  470. else
  471. {
  472. /* We expect:
  473. 3 fields max or we'll see oddities with certain file names.
  474. So both year and time is not allowed.
  475. Mon DD hh:mm[:ss]
  476. Mon DD YYYY
  477. But in case of extfs we allow these date formats:
  478. MM-DD-YY hh:mm[:ss]
  479. where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
  480. YYYY four digit year, hh, mm, ss two digit hour, minute or second. */
  481. /* Special case with MM-DD-YY or MM-DD-YYYY */
  482. if (is_dos_date (p))
  483. {
  484. p[2] = p[5] = '-';
  485. /* cppcheck-suppress invalidscanf */
  486. if (sscanf (p, "%2d-%2d-%d", &d[0], &d[1], &d[2]) == 3)
  487. {
  488. /* Months are zero based */
  489. if (d[0] > 0)
  490. d[0]--;
  491. if (d[2] > 1900)
  492. {
  493. d[2] -= 1900;
  494. }
  495. else
  496. {
  497. /* Y2K madness */
  498. if (d[2] < 70)
  499. d[2] += 100;
  500. }
  501. tim.tm_mon = d[0];
  502. tim.tm_mday = d[1];
  503. tim.tm_year = d[2];
  504. got_year = 1;
  505. }
  506. else
  507. return 0; /* sscanf failed */
  508. }
  509. else
  510. {
  511. /* Locale's abbreviated month name followed by day number */
  512. if (is_localized_month (p) && (is_num (idx++)))
  513. l10n = 1;
  514. else
  515. return 0; /* unsupported format */
  516. }
  517. }
  518. /* Here we expect to find time or year */
  519. if (is_num (idx) && (is_time (columns[idx], &tim) || (got_year = is_year (columns[idx], &tim))))
  520. idx++;
  521. else
  522. return 0; /* Neither time nor date */
  523. /*
  524. * If the date is less than 6 months in the past, it is shown without year
  525. * other dates in the past or future are shown with year but without time
  526. * This does not check for years before 1900 ... I don't know, how
  527. * to represent them at all
  528. */
  529. if (!got_year && local_time->tm_mon < 6
  530. && local_time->tm_mon < tim.tm_mon && tim.tm_mon - local_time->tm_mon >= 6)
  531. tim.tm_year--;
  532. *t = mktime (&tim);
  533. if (l10n || (*t < 0))
  534. *t = 0;
  535. return idx;
  536. }
  537. /* --------------------------------------------------------------------------------------------- */
  538. int
  539. vfs_split_text (char *p)
  540. {
  541. char *original = p;
  542. int numcols;
  543. memset (columns, 0, sizeof (columns));
  544. for (numcols = 0; *p && numcols < MAXCOLS; numcols++)
  545. {
  546. while (*p == ' ' || *p == '\r' || *p == '\n')
  547. {
  548. *p = 0;
  549. p++;
  550. }
  551. columns[numcols] = p;
  552. column_ptr[numcols] = p - original;
  553. while (*p && *p != ' ' && *p != '\r' && *p != '\n')
  554. p++;
  555. }
  556. return numcols;
  557. }
  558. /* --------------------------------------------------------------------------------------------- */
  559. void
  560. vfs_parse_ls_lga_init (void)
  561. {
  562. vfs_parce_ls_final_num_spaces = 1;
  563. }
  564. /* --------------------------------------------------------------------------------------------- */
  565. size_t
  566. vfs_parse_ls_lga_get_final_spaces (void)
  567. {
  568. return vfs_parce_ls_final_num_spaces;
  569. }
  570. /* --------------------------------------------------------------------------------------------- */
  571. gboolean
  572. vfs_parse_ls_lga (const char *p, struct stat * s, char **filename, char **linkname,
  573. size_t * num_spaces)
  574. {
  575. int idx, idx2, num_cols;
  576. int i;
  577. char *p_copy = NULL;
  578. char *t = NULL;
  579. const char *line = p;
  580. size_t skipped;
  581. if (strncmp (p, "total", 5) == 0)
  582. return FALSE;
  583. if (!vfs_parse_filetype (p, &skipped, &s->st_mode))
  584. goto error;
  585. p += skipped;
  586. if (*p == ' ') /* Notwell 4 */
  587. p++;
  588. if (*p == '[')
  589. {
  590. if (strlen (p) <= 8 || p[8] != ']')
  591. goto error;
  592. /* Should parse here the Notwell permissions :) */
  593. if (S_ISDIR (s->st_mode))
  594. s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
  595. else
  596. s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
  597. p += 9;
  598. }
  599. else
  600. {
  601. size_t lc_skipped;
  602. mode_t perms;
  603. if (!vfs_parse_fileperms (p, &lc_skipped, &perms))
  604. goto error;
  605. p += lc_skipped;
  606. s->st_mode |= perms;
  607. }
  608. p_copy = g_strdup (p);
  609. num_cols = vfs_split_text (p_copy);
  610. s->st_nlink = atol (columns[0]);
  611. if (s->st_nlink <= 0)
  612. goto error;
  613. if (!is_num (1))
  614. s->st_uid = vfs_finduid (columns[1]);
  615. else
  616. s->st_uid = (uid_t) atol (columns[1]);
  617. /* Mhm, the ls -lg did not produce a group field */
  618. for (idx = 3; idx <= 5; idx++)
  619. if (is_month (columns[idx], NULL) || is_week (columns[idx], NULL)
  620. || is_dos_date (columns[idx]) || is_localized_month (columns[idx]))
  621. break;
  622. if (idx == 6 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode)))
  623. goto error;
  624. /* We don't have gid */
  625. if (idx == 3 || (idx == 4 && (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))))
  626. idx2 = 2;
  627. else
  628. {
  629. /* We have gid field */
  630. if (is_num (2))
  631. s->st_gid = (gid_t) atol (columns[2]);
  632. else
  633. s->st_gid = vfs_findgid (columns[2]);
  634. idx2 = 3;
  635. }
  636. /* This is device */
  637. if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))
  638. {
  639. int maj, min;
  640. /* Corner case: there is no whitespace(s) between maj & min */
  641. if (!is_num (idx2) && idx2 == 2)
  642. {
  643. /* cppcheck-suppress invalidscanf */
  644. if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &maj, &min) != 2)
  645. goto error;
  646. }
  647. else
  648. {
  649. /* cppcheck-suppress invalidscanf */
  650. if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1)
  651. goto error;
  652. /* cppcheck-suppress invalidscanf */
  653. if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1)
  654. goto error;
  655. }
  656. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  657. s->st_rdev = makedev (maj, min);
  658. #endif
  659. s->st_size = 0;
  660. }
  661. else
  662. {
  663. /* Common file size */
  664. if (!is_num (idx2))
  665. goto error;
  666. s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10);
  667. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  668. s->st_rdev = 0;
  669. #endif
  670. }
  671. idx = vfs_parse_filedate (idx, &s->st_mtime);
  672. if (!idx)
  673. goto error;
  674. /* Use resulting time value */
  675. s->st_atime = s->st_ctime = s->st_mtime;
  676. /* s->st_dev and s->st_ino must be initialized by vfs_s_new_inode () */
  677. #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
  678. s->st_blksize = 512;
  679. #endif
  680. #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
  681. s->st_blocks = (s->st_size + 511) / 512;
  682. #endif
  683. if (num_spaces != NULL)
  684. {
  685. *num_spaces = column_ptr[idx] - column_ptr[idx - 1] - strlen (columns[idx - 1]);
  686. if (DIR_IS_DOTDOT (columns[idx]))
  687. vfs_parce_ls_final_num_spaces = *num_spaces;
  688. }
  689. for (i = idx + 1, idx2 = 0; i < num_cols; i++)
  690. if (strcmp (columns[i], "->") == 0)
  691. {
  692. idx2 = i;
  693. break;
  694. }
  695. if (((S_ISLNK (s->st_mode) || (num_cols == idx + 3 && s->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */
  696. && idx2)
  697. {
  698. if (filename)
  699. {
  700. *filename = g_strndup (p + column_ptr[idx], column_ptr[idx2] - column_ptr[idx] - 1);
  701. }
  702. if (linkname)
  703. {
  704. t = g_strdup (p + column_ptr[idx2 + 1]);
  705. *linkname = t;
  706. }
  707. }
  708. else
  709. {
  710. /* Extract the filename from the string copy, not from the columns
  711. * this way we have a chance of entering hidden directories like ". ."
  712. */
  713. if (filename)
  714. {
  715. /*
  716. * filename = g_strdup (columns [idx++]);
  717. */
  718. t = g_strdup (p + column_ptr[idx]);
  719. *filename = t;
  720. }
  721. if (linkname)
  722. *linkname = NULL;
  723. }
  724. if (t)
  725. {
  726. int p2 = strlen (t);
  727. if ((--p2 > 0) && (t[p2] == '\r' || t[p2] == '\n'))
  728. t[p2] = 0;
  729. if ((--p2 > 0) && (t[p2] == '\r' || t[p2] == '\n'))
  730. t[p2] = 0;
  731. }
  732. g_free (p_copy);
  733. return TRUE;
  734. error:
  735. {
  736. static int errorcount = 0;
  737. if (++errorcount < 5)
  738. {
  739. message (D_ERROR, _("Cannot parse:"), "%s", (p_copy && *p_copy) ? p_copy : line);
  740. }
  741. else if (errorcount == 5)
  742. message (D_ERROR, MSG_ERROR, _("More parsing errors will be ignored."));
  743. }
  744. g_free (p_copy);
  745. return FALSE;
  746. }
  747. /* --------------------------------------------------------------------------------------------- */