utilvfs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. /* Utilities for VFS modules.
  2. Copyright (C) 1988, 1992 Free Software Foundation
  3. Copyright (C) 1995, 1996 Miguel de Icaza
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License
  6. as published by the Free Software Foundation; either version 2 of
  7. the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  15. #include <config.h>
  16. #include <ctype.h>
  17. #include "../src/global.h"
  18. #include "../src/tty.h" /* enable/disable interrupt key */
  19. #include "../src/wtools.h" /* message() */
  20. #include "../src/main.h" /* print_vfs_message */
  21. #include "utilvfs.h"
  22. #include "vfs.h"
  23. #include "../src/unixcompat.h"
  24. /* Extract the hostname and username from the path */
  25. /* path is in the form: [user@]hostname:port/remote-dir, e.g.:
  26. *
  27. * ftp://sunsite.unc.edu/pub/linux
  28. * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
  29. * ftp://tsx-11.mit.edu:8192/
  30. * ftp://joe@foo.edu:11321/private
  31. * ftp://joe:password@foo.se
  32. *
  33. * Returns g_malloc()ed host, user and pass they are present.
  34. * If the user is empty, e.g. ftp://@roxanne/private, and URL_ALLOW_ANON
  35. * is not set, then the current login name is supplied.
  36. *
  37. * Return value is a g_malloc()ed string with the pathname relative to the
  38. * host.
  39. */
  40. #ifdef USE_NETCODE
  41. char *
  42. vfs_split_url (const char *path, char **host, char **user, int *port,
  43. char **pass, int default_port, int flags)
  44. {
  45. struct passwd *passwd_info;
  46. char *dir, *colon, *inner_colon, *at, *rest;
  47. char *retval;
  48. char * const pcopy = g_strdup (path);
  49. const char *pend = pcopy + strlen (pcopy);
  50. if (pass)
  51. *pass = NULL;
  52. *port = default_port;
  53. *user = NULL;
  54. retval = NULL;
  55. dir = pcopy;
  56. if (!(flags & URL_NOSLASH)) {
  57. /* locate path component */
  58. while (*dir != PATH_SEP && *dir)
  59. dir++;
  60. if (*dir) {
  61. retval = g_strdup (dir);
  62. *dir = 0;
  63. } else
  64. retval = g_strdup (PATH_SEP_STR);
  65. }
  66. /* search for any possible user */
  67. at = strrchr (pcopy, '@');
  68. /* We have a username */
  69. if (at) {
  70. *at = 0;
  71. inner_colon = strchr (pcopy, ':');
  72. if (inner_colon) {
  73. *inner_colon = 0;
  74. inner_colon++;
  75. if (pass)
  76. *pass = g_strdup (inner_colon);
  77. }
  78. if (*pcopy != 0)
  79. *user = g_strdup (pcopy);
  80. if (pend == at + 1)
  81. rest = at;
  82. else
  83. rest = at + 1;
  84. } else
  85. rest = pcopy;
  86. if (!*user && !(flags & URL_ALLOW_ANON)) {
  87. passwd_info = getpwuid (geteuid ());
  88. if (passwd_info && passwd_info->pw_name)
  89. *user = g_strdup (passwd_info->pw_name);
  90. else {
  91. /* This is very unlikely to happen */
  92. *user = g_strdup ("anonymous");
  93. }
  94. endpwent ();
  95. }
  96. /* Check if the host comes with a port spec, if so, chop it */
  97. colon = strchr (rest, ':');
  98. if (colon) {
  99. *colon = 0;
  100. if (sscanf (colon + 1, "%d", port) == 1) {
  101. if (*port <= 0 || *port >= 65536)
  102. *port = default_port;
  103. } else {
  104. while (*(++colon)) {
  105. switch (*colon) {
  106. case 'C':
  107. *port = 1;
  108. break;
  109. case 'r':
  110. *port = 2;
  111. break;
  112. }
  113. }
  114. }
  115. }
  116. if (host)
  117. *host = g_strdup (rest);
  118. g_free (pcopy);
  119. return retval;
  120. }
  121. #endif /* USE_NETCODE */
  122. /*
  123. * Look up a user or group name from a uid/gid, maintaining a cache.
  124. * FIXME, for now it's a one-entry cache.
  125. * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
  126. * This file should be modified for non-unix systems to do something
  127. * reasonable.
  128. */
  129. #ifndef TUNMLEN
  130. #define TUNMLEN 256
  131. #endif
  132. #ifndef TGNMLEN
  133. #define TGNMLEN 256
  134. #endif
  135. #define myuid ( my_uid < 0? (my_uid = getuid()): my_uid )
  136. #define mygid ( my_gid < 0? (my_gid = getgid()): my_gid )
  137. int
  138. vfs_finduid (const char *uname)
  139. {
  140. static int saveuid = -993;
  141. static char saveuname[TUNMLEN];
  142. static int my_uid = -993;
  143. struct passwd *pw;
  144. if (uname[0] != saveuname[0] /* Quick test w/o proc call */
  145. ||0 != strncmp (uname, saveuname, TUNMLEN)) {
  146. g_strlcpy (saveuname, uname, TUNMLEN);
  147. pw = getpwnam (uname);
  148. if (pw) {
  149. saveuid = pw->pw_uid;
  150. } else {
  151. saveuid = myuid;
  152. }
  153. }
  154. return saveuid;
  155. }
  156. int
  157. vfs_findgid (const char *gname)
  158. {
  159. static int savegid = -993;
  160. static char savegname[TGNMLEN];
  161. static int my_gid = -993;
  162. struct group *gr;
  163. if (gname[0] != savegname[0] /* Quick test w/o proc call */
  164. ||0 != strncmp (gname, savegname, TUNMLEN)) {
  165. g_strlcpy (savegname, gname, TUNMLEN);
  166. gr = getgrnam (gname);
  167. if (gr) {
  168. savegid = gr->gr_gid;
  169. } else {
  170. savegid = mygid;
  171. }
  172. }
  173. return savegid;
  174. }
  175. /*
  176. * Create a temporary file with a name resembling the original.
  177. * This is needed e.g. for local copies requested by extfs.
  178. * Some extfs scripts may look at the extension.
  179. * We also protect stupid scripts agains dangerous names.
  180. */
  181. int
  182. vfs_mkstemps (char **pname, const char *prefix, const char *basename)
  183. {
  184. const unsigned char *p;
  185. char *suffix, *q;
  186. int shift;
  187. int fd;
  188. /* Strip directories */
  189. p = strrchr (basename, PATH_SEP);
  190. if (!p)
  191. p = basename;
  192. else
  193. p++;
  194. /* Protection against very long names */
  195. shift = strlen (p) - (MC_MAXPATHLEN - 16);
  196. if (shift > 0)
  197. p += shift;
  198. suffix = g_malloc (MC_MAXPATHLEN);
  199. /* Protection against unusual characters */
  200. q = suffix;
  201. while (*p && (*p != '#')) {
  202. if (strchr (".-_@", *p) || isalnum (*p))
  203. *q++ = *p;
  204. p++;
  205. }
  206. *q = 0;
  207. fd = mc_mkstemps (pname, prefix, suffix);
  208. g_free (suffix);
  209. return fd;
  210. }
  211. /* Parsing code is used by ftpfs, fish and extfs */
  212. #define MAXCOLS 30
  213. static char *columns[MAXCOLS]; /* Points to the string in column n */
  214. static int column_ptr[MAXCOLS]; /* Index from 0 to the starting positions of the columns */
  215. int
  216. vfs_split_text (char *p)
  217. {
  218. char *original = p;
  219. int numcols;
  220. memset (columns, 0, sizeof (columns));
  221. for (numcols = 0; *p && numcols < MAXCOLS; numcols++) {
  222. while (*p == ' ' || *p == '\r' || *p == '\n') {
  223. *p = 0;
  224. p++;
  225. }
  226. columns[numcols] = p;
  227. column_ptr[numcols] = p - original;
  228. while (*p && *p != ' ' && *p != '\r' && *p != '\n')
  229. p++;
  230. }
  231. return numcols;
  232. }
  233. static int
  234. is_num (int idx)
  235. {
  236. char *column = columns[idx];
  237. if (!column || column[0] < '0' || column[0] > '9')
  238. return 0;
  239. return 1;
  240. }
  241. /* Return 1 for MM-DD-YY and MM-DD-YYYY */
  242. static int
  243. is_dos_date (const char *str)
  244. {
  245. int len;
  246. if (!str)
  247. return 0;
  248. len = strlen (str);
  249. if (len != 8 && len != 10)
  250. return 0;
  251. if (str[2] != str[5])
  252. return 0;
  253. if (!strchr ("\\-/", (int) str[2]))
  254. return 0;
  255. return 1;
  256. }
  257. static int
  258. is_week (const char *str, struct tm *tim)
  259. {
  260. static const char *week = "SunMonTueWedThuFriSat";
  261. const char *pos;
  262. if (!str)
  263. return 0;
  264. if ((pos = strstr (week, str)) != NULL) {
  265. if (tim != NULL)
  266. tim->tm_wday = (pos - week) / 3;
  267. return 1;
  268. }
  269. return 0;
  270. }
  271. static int
  272. is_month (const char *str, struct tm *tim)
  273. {
  274. static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
  275. const char *pos;
  276. if (!str)
  277. return 0;
  278. if ((pos = strstr (month, str)) != NULL) {
  279. if (tim != NULL)
  280. tim->tm_mon = (pos - month) / 3;
  281. return 1;
  282. }
  283. return 0;
  284. }
  285. /*
  286. * Check for possible locale's abbreviated month name (Jan..Dec).
  287. * Any 3 bytes long string without digit, control and punctuation characters.
  288. * isalpha() is locale specific, so it cannot be used if current
  289. * locale is "C" and ftp server use Cyrillic.
  290. * NB: It is assumed there are no whitespaces in month.
  291. */
  292. static int
  293. is_localized_month (const unsigned char *month)
  294. {
  295. int i = 0;
  296. if (!month)
  297. return 0;
  298. while ((i < 3) && *month && !isdigit (*month) && !iscntrl (*month)
  299. && !ispunct (*month)) {
  300. i++;
  301. month++;
  302. }
  303. return ((i == 3) && (*month == 0));
  304. }
  305. static int
  306. is_time (const char *str, struct tm *tim)
  307. {
  308. const char *p, *p2;
  309. if (!str)
  310. return 0;
  311. if ((p = strchr (str, ':')) && (p2 = strrchr (str, ':'))) {
  312. if (p != p2) {
  313. if (sscanf
  314. (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min,
  315. &tim->tm_sec) != 3)
  316. return 0;
  317. } else {
  318. if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
  319. return 0;
  320. }
  321. } else
  322. return 0;
  323. return 1;
  324. }
  325. static int
  326. is_year (char *str, struct tm *tim)
  327. {
  328. long year;
  329. if (!str)
  330. return 0;
  331. if (strchr (str, ':'))
  332. return 0;
  333. if (strlen (str) != 4)
  334. return 0;
  335. if (sscanf (str, "%ld", &year) != 1)
  336. return 0;
  337. if (year < 1900 || year > 3000)
  338. return 0;
  339. tim->tm_year = (int) (year - 1900);
  340. return 1;
  341. }
  342. /*
  343. * FIXME: this is broken. Consider following entry:
  344. * -rwx------ 1 root root 1 Aug 31 10:04 2904 1234
  345. * where "2904 1234" is filename. Well, this code decodes it as year :-(.
  346. */
  347. int
  348. vfs_parse_filetype (char c)
  349. {
  350. switch (c) {
  351. case 'd':
  352. return S_IFDIR;
  353. case 'b':
  354. return S_IFBLK;
  355. case 'c':
  356. return S_IFCHR;
  357. case 'l':
  358. return S_IFLNK;
  359. case 's': /* Socket */
  360. #ifdef S_IFSOCK
  361. return S_IFSOCK;
  362. #else
  363. /* If not supported, we fall through to IFIFO */
  364. return S_IFIFO;
  365. #endif
  366. case 'D': /* Solaris door */
  367. #ifdef S_IFDOOR
  368. return S_IFDOOR;
  369. #else
  370. return S_IFIFO;
  371. #endif
  372. case 'p':
  373. return S_IFIFO;
  374. case 'n': /* Special named files */
  375. #ifdef S_IFNAM
  376. return S_IFNAM;
  377. #endif /* S_IFNAM */
  378. case 'm': /* Don't know what these are :-) */
  379. case '-':
  380. case '?':
  381. return S_IFREG;
  382. default:
  383. return -1;
  384. }
  385. }
  386. int
  387. vfs_parse_filemode (const char *p)
  388. { /* converts rw-rw-rw- into 0666 */
  389. int res = 0;
  390. switch (*(p++)) {
  391. case 'r':
  392. res |= 0400;
  393. break;
  394. case '-':
  395. break;
  396. default:
  397. return -1;
  398. }
  399. switch (*(p++)) {
  400. case 'w':
  401. res |= 0200;
  402. break;
  403. case '-':
  404. break;
  405. default:
  406. return -1;
  407. }
  408. switch (*(p++)) {
  409. case 'x':
  410. res |= 0100;
  411. break;
  412. case 's':
  413. res |= 0100 | S_ISUID;
  414. break;
  415. case 'S':
  416. res |= S_ISUID;
  417. break;
  418. case '-':
  419. break;
  420. default:
  421. return -1;
  422. }
  423. switch (*(p++)) {
  424. case 'r':
  425. res |= 0040;
  426. break;
  427. case '-':
  428. break;
  429. default:
  430. return -1;
  431. }
  432. switch (*(p++)) {
  433. case 'w':
  434. res |= 0020;
  435. break;
  436. case '-':
  437. break;
  438. default:
  439. return -1;
  440. }
  441. switch (*(p++)) {
  442. case 'x':
  443. res |= 0010;
  444. break;
  445. case 's':
  446. res |= 0010 | S_ISGID;
  447. break;
  448. case 'l': /* Solaris produces these */
  449. case 'S':
  450. res |= S_ISGID;
  451. break;
  452. case '-':
  453. break;
  454. default:
  455. return -1;
  456. }
  457. switch (*(p++)) {
  458. case 'r':
  459. res |= 0004;
  460. break;
  461. case '-':
  462. break;
  463. default:
  464. return -1;
  465. }
  466. switch (*(p++)) {
  467. case 'w':
  468. res |= 0002;
  469. break;
  470. case '-':
  471. break;
  472. default:
  473. return -1;
  474. }
  475. switch (*(p++)) {
  476. case 'x':
  477. res |= 0001;
  478. break;
  479. case 't':
  480. res |= 0001 | S_ISVTX;
  481. break;
  482. case 'T':
  483. res |= S_ISVTX;
  484. break;
  485. case '-':
  486. break;
  487. default:
  488. return -1;
  489. }
  490. return res;
  491. }
  492. /* This function parses from idx in the columns[] array */
  493. int
  494. vfs_parse_filedate (int idx, time_t *t)
  495. {
  496. char *p;
  497. struct tm tim;
  498. int d[3];
  499. int got_year = 0;
  500. int l10n = 0; /* Locale's abbreviated month name */
  501. time_t current_time;
  502. struct tm *local_time;
  503. /* Let's setup default time values */
  504. current_time = time (NULL);
  505. local_time = localtime (&current_time);
  506. tim.tm_mday = local_time->tm_mday;
  507. tim.tm_mon = local_time->tm_mon;
  508. tim.tm_year = local_time->tm_year;
  509. tim.tm_hour = 0;
  510. tim.tm_min = 0;
  511. tim.tm_sec = 0;
  512. tim.tm_isdst = -1; /* Let mktime() try to guess correct dst offset */
  513. p = columns[idx++];
  514. /* We eat weekday name in case of extfs */
  515. if (is_week (p, &tim))
  516. p = columns[idx++];
  517. /* Month name */
  518. if (is_month (p, &tim)) {
  519. /* And we expect, it followed by day number */
  520. if (is_num (idx))
  521. tim.tm_mday = (int) atol (columns[idx++]);
  522. else
  523. return 0; /* No day */
  524. } else {
  525. /* We usually expect:
  526. Mon DD hh:mm
  527. Mon DD YYYY
  528. But in case of extfs we allow these date formats:
  529. Mon DD YYYY hh:mm
  530. Mon DD hh:mm YYYY
  531. Wek Mon DD hh:mm:ss YYYY
  532. MM-DD-YY hh:mm
  533. where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
  534. YYYY four digit year, hh, mm, ss two digit hour, minute or second. */
  535. /* Special case with MM-DD-YY or MM-DD-YYYY */
  536. if (is_dos_date (p)) {
  537. p[2] = p[5] = '-';
  538. if (sscanf (p, "%2d-%2d-%d", &d[0], &d[1], &d[2]) == 3) {
  539. /* Months are zero based */
  540. if (d[0] > 0)
  541. d[0]--;
  542. if (d[2] > 1900) {
  543. d[2] -= 1900;
  544. } else {
  545. /* Y2K madness */
  546. if (d[2] < 70)
  547. d[2] += 100;
  548. }
  549. tim.tm_mon = d[0];
  550. tim.tm_mday = d[1];
  551. tim.tm_year = d[2];
  552. got_year = 1;
  553. } else
  554. return 0; /* sscanf failed */
  555. } else {
  556. /* Locale's abbreviated month name followed by day number */
  557. if (is_localized_month (p) && (is_num (idx++)))
  558. l10n = 1;
  559. else
  560. return 0; /* unsupported format */
  561. }
  562. }
  563. /* Here we expect to find time and/or year */
  564. if (is_num (idx)) {
  565. if (is_time (columns[idx], &tim)
  566. || (got_year = is_year (columns[idx], &tim))) {
  567. idx++;
  568. /* This is a special case for ctime() or Mon DD YYYY hh:mm */
  569. if (is_num (idx) && (columns[idx + 1][0])) {
  570. if (got_year) {
  571. if (is_time (columns[idx], &tim))
  572. idx++; /* time also */
  573. } else {
  574. if ((got_year = is_year (columns[idx], &tim)))
  575. idx++; /* year also */
  576. }
  577. }
  578. } /* only time or date */
  579. } else
  580. return 0; /* Nor time or date */
  581. /*
  582. * If the date is less than 6 months in the past, it is shown without year
  583. * other dates in the past or future are shown with year but without time
  584. * This does not check for years before 1900 ... I don't know, how
  585. * to represent them at all
  586. */
  587. if (!got_year && local_time->tm_mon < 6
  588. && local_time->tm_mon < tim.tm_mon
  589. && tim.tm_mon - local_time->tm_mon >= 6)
  590. tim.tm_year--;
  591. if (l10n || (*t = mktime (&tim)) < 0)
  592. *t = 0;
  593. return idx;
  594. }
  595. int
  596. vfs_parse_ls_lga (const char *p, struct stat *s, char **filename,
  597. char **linkname)
  598. {
  599. int idx, idx2, num_cols;
  600. int i;
  601. char *p_copy = NULL;
  602. char *t = NULL;
  603. const char *line = p;
  604. if (strncmp (p, "total", 5) == 0)
  605. return 0;
  606. if ((i = vfs_parse_filetype (*(p++))) == -1)
  607. goto error;
  608. s->st_mode = i;
  609. if (*p == ' ') /* Notwell 4 */
  610. p++;
  611. if (*p == '[') {
  612. if (strlen (p) <= 8 || p[8] != ']')
  613. goto error;
  614. /* Should parse here the Notwell permissions :) */
  615. if (S_ISDIR (s->st_mode))
  616. s->st_mode |=
  617. (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP
  618. | S_IXOTH);
  619. else
  620. s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
  621. p += 9;
  622. } else {
  623. if ((i = vfs_parse_filemode (p)) == -1)
  624. goto error;
  625. s->st_mode |= i;
  626. p += 9;
  627. /* This is for an extra ACL attribute (HP-UX) */
  628. if (*p == '+')
  629. p++;
  630. }
  631. p_copy = g_strdup (p);
  632. num_cols = vfs_split_text (p_copy);
  633. s->st_nlink = atol (columns[0]);
  634. if (s->st_nlink <= 0)
  635. goto error;
  636. if (!is_num (1))
  637. s->st_uid = vfs_finduid (columns[1]);
  638. else
  639. s->st_uid = (uid_t) atol (columns[1]);
  640. /* Mhm, the ls -lg did not produce a group field */
  641. for (idx = 3; idx <= 5; idx++)
  642. if (is_month (columns[idx], NULL) || is_week (columns[idx], NULL)
  643. || is_dos_date (columns[idx])
  644. || is_localized_month (columns[idx]))
  645. break;
  646. if (idx == 6
  647. || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode)))
  648. goto error;
  649. /* We don't have gid */
  650. if (idx == 3
  651. || (idx == 4 && (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))))
  652. idx2 = 2;
  653. else {
  654. /* We have gid field */
  655. if (is_num (2))
  656. s->st_gid = (gid_t) atol (columns[2]);
  657. else
  658. s->st_gid = vfs_findgid (columns[2]);
  659. idx2 = 3;
  660. }
  661. /* This is device */
  662. if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode)) {
  663. int maj, min;
  664. /* Corner case: there is no whitespace(s) between maj & min */
  665. if (!is_num (idx2) && idx2 == 2) {
  666. if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &min, &min) != 2)
  667. goto error;
  668. } else {
  669. if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1)
  670. goto error;
  671. if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1)
  672. goto error;
  673. }
  674. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  675. s->st_rdev = makedev (maj, min);
  676. #endif
  677. s->st_size = 0;
  678. } else {
  679. /* Common file size */
  680. if (!is_num (idx2))
  681. goto error;
  682. #ifdef HAVE_ATOLL
  683. s->st_size = (off_t) atoll (columns[idx2]);
  684. #else
  685. s->st_size = (off_t) atof (columns[idx2]);
  686. #endif
  687. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  688. s->st_rdev = 0;
  689. #endif
  690. }
  691. idx = vfs_parse_filedate (idx, &s->st_mtime);
  692. if (!idx)
  693. goto error;
  694. /* Use resulting time value */
  695. s->st_atime = s->st_ctime = s->st_mtime;
  696. /* s->st_dev and s->st_ino must be initialized by vfs_s_new_inode () */
  697. #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
  698. s->st_blksize = 512;
  699. #endif
  700. #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
  701. s->st_blocks = (s->st_size + 511) / 512;
  702. #endif
  703. for (i = idx + 1, idx2 = 0; i < num_cols; i++)
  704. if (strcmp (columns[i], "->") == 0) {
  705. idx2 = i;
  706. break;
  707. }
  708. if (((S_ISLNK (s->st_mode) || (num_cols == idx + 3 && s->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */
  709. &&idx2) {
  710. if (filename) {
  711. *filename =
  712. g_strndup (p + column_ptr[idx],
  713. column_ptr[idx2] - column_ptr[idx] - 1);
  714. }
  715. if (linkname) {
  716. t = g_strdup (p + column_ptr[idx2 + 1]);
  717. *linkname = t;
  718. }
  719. } else {
  720. /* Extract the filename from the string copy, not from the columns
  721. * this way we have a chance of entering hidden directories like ". ."
  722. */
  723. if (filename) {
  724. /*
  725. * filename = g_strdup (columns [idx++]);
  726. */
  727. t = g_strdup (p + column_ptr[idx]);
  728. *filename = t;
  729. }
  730. if (linkname)
  731. *linkname = NULL;
  732. }
  733. if (t) {
  734. int p = strlen (t);
  735. if ((--p > 0) && (t[p] == '\r' || t[p] == '\n'))
  736. t[p] = 0;
  737. if ((--p > 0) && (t[p] == '\r' || t[p] == '\n'))
  738. t[p] = 0;
  739. }
  740. g_free (p_copy);
  741. return 1;
  742. error:
  743. {
  744. static int errorcount = 0;
  745. if (++errorcount < 5) {
  746. message (1, _("Cannot parse:"), "%s",
  747. (p_copy && *p_copy) ? p_copy : line);
  748. } else if (errorcount == 5)
  749. message (1, MSG_ERROR,
  750. _("More parsing errors will be ignored."));
  751. }
  752. g_free (p_copy);
  753. return 0;
  754. }
  755. void
  756. vfs_die (const char *m)
  757. {
  758. message (1, _("Internal error:"), "%s", m);
  759. exit (1);
  760. }
  761. char *
  762. vfs_get_password (const char *msg)
  763. {
  764. return input_dialog (msg, _("Password:"), INPUT_PASSWORD);
  765. }