utilvfs.c 18 KB

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