vfs.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899
  1. /* Virtual File System switch code
  2. Copyright (C) 1995 The Free Software Foundation
  3. Written by: 1995 Miguel de Icaza
  4. 1995 Jakub Jelinek
  5. 1998 Pavel Machek
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Library General Public License
  8. as published by the Free Software Foundation; either version 2 of
  9. the License, or (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public
  15. License along with this program; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  17. /* Warning: funtions like extfs_lstat() have right to destroy any
  18. * strings you pass to them. This is acutally ok as you g_strdup what
  19. * you are passing to them, anyway; still, beware. */
  20. /* Namespace: exports *many* functions with vfs_ prefix; exports
  21. parse_ls_lga and friends which do not have that prefix. */
  22. #include <config.h>
  23. #ifndef NO_SYSLOG_H
  24. # include <syslog.h>
  25. #endif
  26. #include <stdio.h>
  27. #include <stdlib.h> /* For atol() */
  28. #include <stdarg.h>
  29. #include <string.h>
  30. #include <errno.h>
  31. #include <sys/types.h>
  32. #include <signal.h>
  33. #include "utilvfs.h"
  34. #include "../src/dir.h"
  35. #include "../src/main.h"
  36. #include "../src/panel.h"
  37. #include "../src/key.h" /* Required for the async alarm handler */
  38. #include "../src/layout.h" /* For get_panel_widget and get_other_index */
  39. #include "../src/wtools.h" /* input_dialog() */
  40. #include "xdirentry.h"
  41. #include "vfs.h"
  42. #include "extfs.h" /* FIXME: we should not know anything about our modules */
  43. #include "names.h"
  44. #ifdef USE_NETCODE
  45. # include "tcputil.h"
  46. #endif
  47. extern int get_other_type (void);
  48. int vfs_timeout = 60; /* VFS timeout in seconds */
  49. int vfs_flags = 0; /* Flags */
  50. extern int cd_symlinks; /* Defined in main.c */
  51. /* They keep track of the current directory */
  52. static vfs *current_vfs = &vfs_local_ops;
  53. static char *current_dir = NULL;
  54. /*
  55. * FIXME: this is broken. It depends on mc not crossing border on month!
  56. */
  57. static int current_mday;
  58. static int current_mon;
  59. static int current_year;
  60. uid_t vfs_uid = 0;
  61. gid_t vfs_gid = 0;
  62. /* FIXME: Open files managed by the vfs layer, should be dynamical */
  63. #define MAX_VFS_FILES 100
  64. static struct {
  65. void *fs_info;
  66. vfs *operations;
  67. } vfs_file_table [MAX_VFS_FILES];
  68. static int
  69. get_bucket (void)
  70. {
  71. int i;
  72. /* 0, 1, 2 are reserved file descriptors, while (DIR *) 0 means error */
  73. for (i = 3; i < MAX_VFS_FILES; i++){
  74. if (!vfs_file_table [i].fs_info)
  75. return i;
  76. }
  77. vfs_die ("No more virtual file handles");
  78. return 0;
  79. }
  80. /* vfs_local_ops needs to be the first one */
  81. static vfs *vfs_list = &vfs_local_ops;
  82. static int
  83. vfs_register (vfs *vfs)
  84. {
  85. if (!vfs)
  86. vfs_die("You can not register NULL.");
  87. if (vfs->init) /* vfs has own initialization function */
  88. if (!(*vfs->init)(vfs)) /* but it failed */
  89. return 0;
  90. vfs->next = vfs_list;
  91. vfs_list = vfs;
  92. return 1;
  93. }
  94. static vfs *
  95. vfs_type_from_op (char *path)
  96. {
  97. vfs *vfs;
  98. if (!path)
  99. vfs_die ("vfs_type_from_op got NULL: impossible");
  100. for (vfs = vfs_list; vfs != &vfs_local_ops; vfs = vfs->next){
  101. if (vfs->which) {
  102. if ((*vfs->which) (vfs, path) == -1)
  103. continue;
  104. return vfs;
  105. }
  106. if (!strncmp (path, vfs->prefix, strlen (vfs->prefix)))
  107. return vfs;
  108. }
  109. return NULL; /* shut up stupid gcc */
  110. }
  111. /* Strip known vfs suffixes from a filename (possible improvement: strip
  112. suffix from last path component).
  113. Returns a malloced string which has to be freed. */
  114. char *
  115. vfs_strip_suffix_from_filename (const char *filename)
  116. {
  117. vfs *vfs;
  118. char *semi;
  119. char *p;
  120. if (!filename)
  121. vfs_die("vfs_strip_suffix_from_path got NULL: impossible");
  122. p = g_strdup (filename);
  123. if (!(semi = strrchr (p, '#')))
  124. return p;
  125. for (vfs = vfs_list; vfs != &vfs_local_ops; vfs = vfs->next){
  126. if (vfs->which){
  127. if ((*vfs->which) (vfs, semi + 1) == -1)
  128. continue;
  129. *semi = '\0'; /* Found valid suffix */
  130. return p;
  131. }
  132. if (!strncmp (semi + 1, vfs->prefix, strlen (vfs->prefix))) {
  133. *semi = '\0'; /* Found valid suffix */
  134. return p;
  135. }
  136. }
  137. return p;
  138. }
  139. static int
  140. path_magic (const char *path)
  141. {
  142. struct stat buf;
  143. if (vfs_flags & FL_ALWAYS_MAGIC)
  144. return 1;
  145. if (!stat(path, &buf))
  146. return 0;
  147. return 1;
  148. }
  149. /*
  150. * Splits path '/p1#op/inpath' into inpath,op; returns which vfs it is.
  151. * What is left in path is p1. You still want to g_free(path), you DON'T
  152. * want to free neither *inpath nor *op
  153. */
  154. vfs *
  155. vfs_split (char *path, char **inpath, char **op)
  156. {
  157. char *semi;
  158. char *slash;
  159. vfs *ret;
  160. if (!path)
  161. vfs_die("Can not split NULL");
  162. semi = strrchr (path, '#');
  163. if (!semi || !path_magic(path))
  164. return NULL;
  165. slash = strchr (semi, PATH_SEP);
  166. *semi = 0;
  167. if (op)
  168. *op = NULL;
  169. if (inpath)
  170. *inpath = NULL;
  171. if (slash)
  172. *slash = 0;
  173. if ((ret = vfs_type_from_op (semi+1))){
  174. if (op)
  175. *op = semi + 1;
  176. if (inpath)
  177. *inpath = slash ? slash + 1 : NULL;
  178. return ret;
  179. }
  180. if (slash)
  181. *slash = PATH_SEP;
  182. ret = vfs_split (path, inpath, op);
  183. *semi = '#';
  184. return ret;
  185. }
  186. static vfs *
  187. vfs_rosplit (char *path)
  188. {
  189. char *semi;
  190. char *slash;
  191. vfs *ret;
  192. g_return_val_if_fail(path, NULL);
  193. semi = strrchr (path, '#');
  194. if (!semi || !path_magic (path))
  195. return NULL;
  196. slash = strchr (semi, PATH_SEP);
  197. *semi = 0;
  198. if (slash)
  199. *slash = 0;
  200. ret = vfs_type_from_op (semi+1);
  201. if (!ret && (vfs_flags & FL_NO_LOCALHASH))
  202. return &vfs_nil_ops;
  203. if (slash)
  204. *slash = PATH_SEP;
  205. if (!ret)
  206. ret = vfs_rosplit (path);
  207. *semi = '#';
  208. return ret;
  209. }
  210. vfs *
  211. vfs_type (char *path)
  212. {
  213. vfs *vfs;
  214. vfs = vfs_rosplit(path);
  215. if (!vfs)
  216. vfs = &vfs_local_ops;
  217. return vfs;
  218. }
  219. static struct vfs_stamping *stamps;
  220. /*
  221. * Returns the number of seconds remaining to the vfs timeout
  222. *
  223. * FIXME: currently this is set to 10 seconds. We should compute this.
  224. */
  225. int
  226. vfs_timeouts ()
  227. {
  228. return stamps ? 10 : 0;
  229. }
  230. void
  231. vfs_addstamp (vfs *v, vfsid id, struct vfs_stamping *parent)
  232. {
  233. if (v != &vfs_local_ops && id != (vfsid)-1){
  234. struct vfs_stamping *stamp;
  235. struct vfs_stamping *last_stamp = NULL;
  236. for (stamp = stamps; stamp != NULL; stamp = stamp->next) {
  237. if (stamp->v == v && stamp->id == id){
  238. gettimeofday(&(stamp->time), NULL);
  239. return;
  240. }
  241. last_stamp = stamp;
  242. }
  243. stamp = g_new (struct vfs_stamping, 1);
  244. stamp->v = v;
  245. stamp->id = id;
  246. if (parent){
  247. struct vfs_stamping *st = stamp;
  248. while (parent){
  249. st->parent = g_new (struct vfs_stamping, 1);
  250. *st->parent = *parent;
  251. parent = parent->parent;
  252. st = st->parent;
  253. }
  254. st->parent = 0;
  255. }
  256. else
  257. stamp->parent = 0;
  258. gettimeofday (&(stamp->time), NULL);
  259. stamp->next = 0;
  260. if (stamps) {
  261. /* Add to the end */
  262. last_stamp->next = stamp;
  263. } else {
  264. /* Add first element */
  265. stamps = stamp;
  266. }
  267. }
  268. }
  269. void
  270. vfs_stamp (vfs *v, vfsid id)
  271. {
  272. struct vfs_stamping *stamp;
  273. for (stamp = stamps; stamp != NULL; stamp = stamp->next)
  274. if (stamp->v == v && stamp->id == id){
  275. gettimeofday (&(stamp->time), NULL);
  276. if (stamp->parent != NULL)
  277. vfs_stamp (stamp->parent->v, stamp->parent->id);
  278. return;
  279. }
  280. }
  281. void
  282. vfs_rm_parents (struct vfs_stamping *stamp)
  283. {
  284. struct vfs_stamping *parent;
  285. while (stamp) {
  286. parent = stamp->parent;
  287. g_free (stamp);
  288. stamp = parent;
  289. }
  290. }
  291. void
  292. vfs_rmstamp (vfs *v, vfsid id, int removeparents)
  293. {
  294. struct vfs_stamping *stamp, *st1;
  295. for (stamp = stamps, st1 = NULL; stamp != NULL; st1 = stamp, stamp = stamp->next)
  296. if (stamp->v == v && stamp->id == id){
  297. if (stamp->parent != NULL){
  298. if (removeparents)
  299. vfs_rmstamp (stamp->parent->v, stamp->parent->id, 1);
  300. vfs_rm_parents (stamp->parent);
  301. }
  302. if (st1 == NULL){
  303. stamps = stamp->next;
  304. } else {
  305. st1->next = stamp->next;
  306. }
  307. g_free (stamp);
  308. return;
  309. }
  310. }
  311. static int
  312. ferrno (vfs *vfs)
  313. {
  314. return vfs->ferrno ? (*vfs->ferrno)(vfs) : E_UNKNOWN;
  315. /* Hope that error message is obscure enough ;-) */
  316. }
  317. int
  318. mc_open (const char *filename, int flags, ...)
  319. {
  320. int handle;
  321. int mode;
  322. void *info;
  323. va_list ap;
  324. char *file = vfs_canon (filename);
  325. vfs *vfs = vfs_type (file);
  326. /* Get the mode flag */ /* FIXME: should look if O_CREAT is present */
  327. va_start (ap, flags);
  328. mode = va_arg (ap, int);
  329. va_end (ap);
  330. if (!vfs->open) {
  331. errno = -EOPNOTSUPP;
  332. return -1;
  333. }
  334. info = (*vfs->open) (vfs, file, flags, mode); /* open must be supported */
  335. g_free (file);
  336. if (!info){
  337. errno = ferrno (vfs);
  338. return -1;
  339. }
  340. handle = get_bucket ();
  341. vfs_file_table [handle].fs_info = info;
  342. vfs_file_table [handle].operations = vfs;
  343. return handle;
  344. }
  345. #define vfs_op(handle) vfs_file_table [handle].operations
  346. #define vfs_info(handle) vfs_file_table [handle].fs_info
  347. #define vfs_free_bucket(handle) vfs_info(handle) = 0;
  348. #define MC_OP(name, inarg, callarg, pre, post) \
  349. int mc_##name inarg \
  350. { \
  351. vfs *vfs; \
  352. int result; \
  353. \
  354. pre \
  355. result = vfs->name ? (*vfs->name)callarg : -1; \
  356. post \
  357. if (result == -1) \
  358. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
  359. return result; \
  360. }
  361. #define MC_NAMEOP(name, inarg, callarg) \
  362. MC_OP (name, inarg, callarg, path = vfs_canon (path); vfs = vfs_type (path);, g_free (path); )
  363. #define MC_HANDLEOP(name, inarg, callarg) \
  364. MC_OP (name, inarg, callarg, if (handle == -1) return -1; vfs = vfs_op (handle);, )
  365. MC_HANDLEOP(read, (int handle, char *buffer, int count), (vfs_info (handle), buffer, count) )
  366. int
  367. mc_ctl (int handle, int ctlop, int arg)
  368. {
  369. vfs *vfs = vfs_op (handle);
  370. return vfs->ctl ? (*vfs->ctl)(vfs_info (handle), ctlop, arg) : 0;
  371. }
  372. int
  373. mc_setctl (char *path, int ctlop, char *arg)
  374. {
  375. vfs *vfs;
  376. int result;
  377. if (!path)
  378. vfs_die("You don't want to pass NULL to mc_setctl.");
  379. path = vfs_canon (path);
  380. vfs = vfs_type (path);
  381. result = vfs->setctl ? (*vfs->setctl)(vfs, path, ctlop, arg) : 0;
  382. g_free (path);
  383. return result;
  384. }
  385. int
  386. mc_close (int handle)
  387. {
  388. vfs *vfs;
  389. int result;
  390. if (handle == -1 || !vfs_info (handle))
  391. return -1;
  392. vfs = vfs_op (handle);
  393. if (handle < 3)
  394. return close (handle);
  395. if (!vfs->close)
  396. vfs_die ("VFS must support close.\n");
  397. result = (*vfs->close)(vfs_info (handle));
  398. vfs_free_bucket (handle);
  399. if (result == -1)
  400. errno = ferrno (vfs);
  401. return result;
  402. }
  403. DIR *
  404. mc_opendir (char *dirname)
  405. {
  406. int handle, *handlep;
  407. void *info;
  408. vfs *vfs;
  409. dirname = vfs_canon (dirname);
  410. vfs = vfs_type (dirname);
  411. info = vfs->opendir ? (*vfs->opendir)(vfs, dirname) : NULL;
  412. g_free (dirname);
  413. if (!info){
  414. errno = vfs->opendir ? ferrno (vfs) : E_NOTSUPP;
  415. return NULL;
  416. }
  417. handle = get_bucket ();
  418. vfs_file_table [handle].fs_info = info;
  419. vfs_file_table [handle].operations = vfs;
  420. handlep = g_new (int, 1);
  421. *handlep = handle;
  422. return (DIR *) handlep;
  423. }
  424. /* This should strip the non needed part of a path name */
  425. #define vfs_name(x) x
  426. void
  427. mc_seekdir (DIR *dirp, int offset)
  428. {
  429. int handle;
  430. vfs *vfs;
  431. if (!dirp){
  432. errno = EFAULT;
  433. return;
  434. }
  435. handle = *(int *) dirp;
  436. vfs = vfs_op (handle);
  437. if (vfs->seekdir)
  438. (*vfs->seekdir) (vfs_info (handle), offset);
  439. else
  440. errno = E_NOTSUPP;
  441. }
  442. #define MC_DIROP(name, type, onerr ) \
  443. type mc_##name (DIR *dirp) \
  444. { \
  445. int handle; \
  446. vfs *vfs; \
  447. type result; \
  448. \
  449. if (!dirp){ \
  450. errno = EFAULT; \
  451. return onerr; \
  452. } \
  453. handle = *(int *) dirp; \
  454. vfs = vfs_op (handle); \
  455. result = vfs->name ? (*vfs->name) (vfs_info (handle)) : onerr; \
  456. if (result == onerr) \
  457. errno = vfs->name ? ferrno(vfs) : E_NOTSUPP; \
  458. return result; \
  459. }
  460. MC_DIROP (readdir, struct dirent *, NULL)
  461. MC_DIROP (telldir, int, -1)
  462. int
  463. mc_closedir (DIR *dirp)
  464. {
  465. int handle = *(int *) dirp;
  466. vfs *vfs = vfs_op (handle);
  467. int result;
  468. result = vfs->closedir ? (*vfs->closedir)(vfs_info (handle)) : -1;
  469. vfs_free_bucket (handle);
  470. g_free (dirp);
  471. return result;
  472. }
  473. int mc_stat (char *path, struct stat *buf) {
  474. vfs *vfs;
  475. int result;
  476. path = vfs_canon (path); vfs = vfs_type (path);
  477. result = vfs->stat ? (*vfs->stat) (vfs, vfs_name (path), buf) : -1;
  478. g_free (path);
  479. if (result == -1)
  480. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  481. return result;
  482. }
  483. int mc_lstat (char *path, struct stat *buf) {
  484. vfs *vfs;
  485. int result;
  486. path = vfs_canon (path); vfs = vfs_type (path);
  487. result = vfs->lstat ? (*vfs->lstat) (vfs, vfs_name (path), buf) : -1;
  488. g_free (path);
  489. if (result == -1)
  490. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  491. return result;
  492. }
  493. int mc_fstat (int handle, struct stat *buf) {
  494. vfs *vfs;
  495. int result;
  496. if (handle == -1)
  497. return -1;
  498. vfs = vfs_op (handle);
  499. result = vfs->fstat ? (*vfs->fstat) (vfs_info (handle), buf) : -1;
  500. if (result == -1)
  501. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  502. return result;
  503. }
  504. /*
  505. * You must g_strdup whatever this function returns.
  506. */
  507. static const char *
  508. mc_return_cwd (void)
  509. {
  510. char *p;
  511. struct stat my_stat, my_stat2;
  512. if (!vfs_rosplit (current_dir)){
  513. p = g_get_current_dir ();
  514. if (!p) /* One of the directories in the path is not readable */
  515. return current_dir;
  516. /* Otherwise check if it is O.K. to use the current_dir */
  517. if (!cd_symlinks ||
  518. mc_stat (p, &my_stat) ||
  519. mc_stat (current_dir, &my_stat2) ||
  520. my_stat.st_ino != my_stat2.st_ino ||
  521. my_stat.st_dev != my_stat2.st_dev){
  522. g_free (current_dir);
  523. current_dir = p;
  524. return p;
  525. } /* Otherwise we return current_dir below */
  526. g_free (p);
  527. }
  528. return current_dir;
  529. }
  530. char *
  531. mc_get_current_wd (char *buffer, int size)
  532. {
  533. const char *cwd = mc_return_cwd();
  534. strncpy (buffer, cwd, size);
  535. return buffer;
  536. }
  537. MC_NAMEOP (chmod, (char *path, int mode), (vfs, vfs_name (path), mode))
  538. MC_NAMEOP (chown, (char *path, int owner, int group), (vfs, vfs_name (path), owner, group))
  539. MC_NAMEOP (utime, (char *path, struct utimbuf *times), (vfs, vfs_name (path), times))
  540. MC_NAMEOP (readlink, (char *path, char *buf, int bufsiz), (vfs, vfs_name (path), buf, bufsiz))
  541. MC_NAMEOP (unlink, (char *path), (vfs, vfs_name (path)))
  542. MC_NAMEOP (symlink, (char *name1, char *path), (vfs, vfs_name (name1), vfs_name (path)))
  543. #define MC_RENAMEOP(name) \
  544. int mc_##name (const char *fname1, const char *fname2) \
  545. { \
  546. vfs *vfs; \
  547. int result; \
  548. \
  549. char *name2, *name1 = vfs_canon (fname1); \
  550. vfs = vfs_type (name1); \
  551. name2 = vfs_canon (fname2); \
  552. if (vfs != vfs_type (name2)){ \
  553. errno = EXDEV; \
  554. g_free (name1); \
  555. g_free (name2); \
  556. return -1; \
  557. } \
  558. \
  559. result = vfs->name ? (*vfs->name)(vfs, vfs_name (name1), vfs_name (name2)) : -1; \
  560. g_free (name1); \
  561. g_free (name2); \
  562. if (result == -1) \
  563. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
  564. return result; \
  565. }
  566. MC_RENAMEOP (link)
  567. MC_RENAMEOP (rename)
  568. MC_HANDLEOP (write, (int handle, char *buf, int nbyte), (vfs_info (handle), buf, nbyte))
  569. off_t mc_lseek (int fd, off_t offset, int whence)
  570. {
  571. vfs *vfs;
  572. int result;
  573. if (fd == -1)
  574. return -1;
  575. vfs = vfs_op (fd);
  576. result = vfs->lseek ? (*vfs->lseek)(vfs_info (fd), offset, whence) : -1;
  577. if (result == -1)
  578. errno = vfs->lseek ? ferrno (vfs) : E_NOTSUPP;
  579. return result;
  580. }
  581. /*
  582. * remove //, /./ and /../, local should point to big enough buffer
  583. */
  584. #define ISSLASH(a) (!a || (a == '/'))
  585. char *
  586. vfs_canon (const char *path)
  587. {
  588. if (!path)
  589. vfs_die("Cannot canonicalize NULL");
  590. /* Tilde expansion */
  591. if (*path == '~'){
  592. char *local, *result;
  593. local = tilde_expand (path);
  594. if (local){
  595. result = vfs_canon (local);
  596. g_free (local);
  597. return result;
  598. }
  599. }
  600. /* Relative to current directory */
  601. if (*path != PATH_SEP){
  602. char *local, *result;
  603. local = concat_dir_and_file (current_dir, path);
  604. result = vfs_canon (local);
  605. g_free (local);
  606. return result;
  607. }
  608. /*
  609. * So we have path of following form:
  610. * /p1/p2#op/.././././p3#op/p4. Good luck.
  611. */
  612. {
  613. char *result = g_strdup (path);
  614. canonicalize_pathname (result);
  615. return result;
  616. }
  617. }
  618. vfsid
  619. vfs_ncs_getid (vfs *nvfs, char *dir, struct vfs_stamping **par)
  620. {
  621. vfsid nvfsid;
  622. dir = concat_dir_and_file (dir, "");
  623. nvfsid = (*nvfs->getid)(nvfs, dir, par);
  624. g_free (dir);
  625. return nvfsid;
  626. }
  627. static int
  628. is_parent (vfs * nvfs, vfsid nvfsid, struct vfs_stamping *parent)
  629. {
  630. struct vfs_stamping *stamp;
  631. for (stamp = parent; stamp; stamp = stamp->parent)
  632. if (stamp->v == nvfs && stamp->id == nvfsid)
  633. break;
  634. return (stamp ? 1 : 0);
  635. }
  636. void
  637. vfs_add_noncurrent_stamps (vfs * oldvfs, vfsid oldvfsid, struct vfs_stamping *parent)
  638. {
  639. vfs *nvfs, *n2vfs, *n3vfs;
  640. vfsid nvfsid, n2vfsid, n3vfsid;
  641. struct vfs_stamping *par, *stamp;
  642. int f;
  643. /* FIXME: As soon as we convert to multiple panels, this stuff
  644. has to change. It works like this: We do not time out the
  645. vfs's which are current in any panel and on the other
  646. side we add the old directory with all its parents which
  647. are not in any panel (if we find such one, we stop adding
  648. parents to the time-outing structure. */
  649. /* There are three directories we have to take care of: current_dir,
  650. cpanel->cwd and opanel->cwd. Athough most of the time either
  651. current_dir and cpanel->cwd or current_dir and opanel->cwd are the
  652. same, it's possible that all three are different -- Norbert */
  653. if (!cpanel)
  654. return;
  655. nvfs = vfs_type (current_dir);
  656. nvfsid = vfs_ncs_getid (nvfs, current_dir, &par);
  657. vfs_rmstamp (nvfs, nvfsid, 1);
  658. f = is_parent (oldvfs, oldvfsid, par);
  659. vfs_rm_parents (par);
  660. if ((nvfs == oldvfs && nvfsid == oldvfsid) || oldvfsid == (vfsid *)-1 || f){
  661. return;
  662. }
  663. if (get_current_type () == view_listing){
  664. n2vfs = vfs_type (cpanel->cwd);
  665. n2vfsid = vfs_ncs_getid (n2vfs, cpanel->cwd, &par);
  666. f = is_parent (oldvfs, oldvfsid, par);
  667. vfs_rm_parents (par);
  668. if ((n2vfs == oldvfs && n2vfsid == oldvfsid) || f)
  669. return;
  670. } else {
  671. n2vfs = (vfs *) -1;
  672. n2vfsid = (vfs *) -1;
  673. }
  674. if (get_other_type () == view_listing){
  675. n3vfs = vfs_type (opanel->cwd);
  676. n3vfsid = vfs_ncs_getid (n3vfs, opanel->cwd, &par);
  677. f = is_parent (oldvfs, oldvfsid, par);
  678. vfs_rm_parents (par);
  679. if ((n3vfs == oldvfs && n3vfsid == oldvfsid) || f)
  680. return;
  681. } else {
  682. n3vfs = (vfs *)-1;
  683. n3vfsid = (vfs *)-1;
  684. }
  685. if ((*oldvfs->nothingisopen) (oldvfsid)){
  686. if (oldvfs == &vfs_extfs_ops && ((extfs_archive *) oldvfsid)->name == 0){
  687. /* Free the resources immediatly when we leave a mtools fs
  688. ('cd a:') instead of waiting for the vfs-timeout */
  689. (oldvfs->free) (oldvfsid);
  690. } else
  691. vfs_addstamp (oldvfs, oldvfsid, parent);
  692. for (stamp = parent; stamp != NULL; stamp = stamp->parent){
  693. if ((stamp->v == nvfs && stamp->id == nvfsid) ||
  694. (stamp->v == n2vfs && stamp->id == n2vfsid) ||
  695. (stamp->v == n3vfs && stamp->id == n3vfsid) ||
  696. stamp->id == (vfsid) - 1 ||
  697. !(*stamp->v->nothingisopen) (stamp->id))
  698. break;
  699. if (stamp->v == &vfs_extfs_ops && ((extfs_archive *) stamp->id)->name == 0){
  700. (stamp->v->free) (stamp->id);
  701. vfs_rmstamp (stamp->v, stamp->id, 0);
  702. } else
  703. vfs_addstamp (stamp->v, stamp->id, stamp->parent);
  704. }
  705. }
  706. }
  707. static void
  708. vfs_stamp_path (char *path)
  709. {
  710. vfs *vfs;
  711. vfsid id;
  712. struct vfs_stamping *par, *stamp;
  713. vfs = vfs_type (path);
  714. id = vfs_ncs_getid (vfs, path, &par);
  715. vfs_addstamp (vfs, id, par);
  716. for (stamp = par; stamp != NULL; stamp = stamp->parent)
  717. vfs_addstamp (stamp->v, stamp->id, stamp->parent);
  718. vfs_rm_parents (par);
  719. }
  720. void
  721. vfs_add_current_stamps (void)
  722. {
  723. vfs_stamp_path (current_dir);
  724. if (cpanel) {
  725. if (get_current_type () == view_listing)
  726. vfs_stamp_path (cpanel->cwd);
  727. }
  728. if (opanel) {
  729. if (get_other_type () == view_listing)
  730. vfs_stamp_path (opanel->cwd);
  731. }
  732. }
  733. /* This function is really broken */
  734. int
  735. mc_chdir (char *path)
  736. {
  737. char *a, *b;
  738. int result;
  739. char *p = NULL;
  740. vfs *oldvfs;
  741. vfsid oldvfsid;
  742. struct vfs_stamping *parent;
  743. a = current_dir; /* Save a copy for case of failure */
  744. current_dir = vfs_canon (path);
  745. current_vfs = vfs_type (current_dir);
  746. b = g_strdup (current_dir);
  747. result = (*current_vfs->chdir) ? (*current_vfs->chdir)(current_vfs, vfs_name (b)) : -1;
  748. g_free (b);
  749. if (result == -1){
  750. errno = ferrno (current_vfs);
  751. g_free (current_dir);
  752. current_vfs = vfs_type (a);
  753. current_dir = a;
  754. } else {
  755. oldvfs = vfs_type (a);
  756. oldvfsid = vfs_ncs_getid (oldvfs, a, &parent);
  757. g_free (a);
  758. vfs_add_noncurrent_stamps (oldvfs, oldvfsid, parent);
  759. vfs_rm_parents (parent);
  760. }
  761. if (*current_dir){
  762. p = strchr (current_dir, 0) - 1;
  763. if (*p == PATH_SEP && p > current_dir)
  764. *p = 0; /* Sometimes we assume no trailing slash on cwd */
  765. }
  766. return result;
  767. }
  768. int
  769. vfs_current_is_local (void)
  770. {
  771. return current_vfs == &vfs_local_ops;
  772. }
  773. #if 0
  774. /* External world should not do differences between VFS-s */
  775. int
  776. vfs_current_is_extfs (void)
  777. {
  778. return current_vfs == &vfs_extfs_ops;
  779. }
  780. int
  781. vfs_current_is_tarfs (void)
  782. {
  783. return current_vfs == &vfs_tarfs_ops;
  784. }
  785. int
  786. vfs_current_is_cpiofs (void)
  787. {
  788. return current_vfs == &vfs_cpiofs_ops;
  789. }
  790. #endif
  791. int
  792. vfs_file_is_local (const char *file)
  793. {
  794. char *filename = vfs_canon (file);
  795. vfs *vfs = vfs_type (filename);
  796. g_free (filename);
  797. return vfs == &vfs_local_ops;
  798. }
  799. int
  800. vfs_file_is_ftp (char *filename)
  801. {
  802. #ifdef USE_NETCODE
  803. vfs *vfs;
  804. filename = vfs_canon (filename);
  805. vfs = vfs_type (filename);
  806. g_free (filename);
  807. return vfs == &vfs_ftpfs_ops;
  808. #else
  809. return 0;
  810. #endif
  811. }
  812. int
  813. vfs_file_is_smb (char *filename)
  814. {
  815. #ifdef WITH_SMBFS
  816. #ifdef USE_NETCODE
  817. vfs *vfs;
  818. filename = vfs_canon (filename);
  819. vfs = vfs_type (filename);
  820. g_free (filename);
  821. return vfs == &vfs_smbfs_ops;
  822. #endif /* USE_NETCODE */
  823. #endif /* WITH_SMBFS */
  824. return 0;
  825. }
  826. char *vfs_get_current_dir (void)
  827. {
  828. return current_dir;
  829. }
  830. static void vfs_setup_wd (void)
  831. {
  832. current_dir = g_strdup (PATH_SEP_STR);
  833. if (!(vfs_flags & FL_NO_CWDSETUP))
  834. mc_return_cwd();
  835. if (strlen(current_dir)>MC_MAXPATHLEN-2)
  836. vfs_die ("Current dir too long.\n");
  837. }
  838. MC_NAMEOP (mkdir, (char *path, mode_t mode), (vfs, vfs_name (path), mode))
  839. MC_NAMEOP (rmdir, (char *path), (vfs, vfs_name (path)))
  840. MC_NAMEOP (mknod, (char *path, int mode, int dev), (vfs, vfs_name (path), mode, dev))
  841. #ifdef HAVE_MMAP
  842. static struct mc_mmapping {
  843. caddr_t addr;
  844. void *vfs_info;
  845. vfs *vfs;
  846. struct mc_mmapping *next;
  847. } *mc_mmaparray = NULL;
  848. caddr_t
  849. mc_mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
  850. {
  851. vfs *vfs;
  852. caddr_t result;
  853. struct mc_mmapping *mcm;
  854. if (fd == -1)
  855. return (caddr_t) -1;
  856. vfs = vfs_op (fd);
  857. result = vfs->mmap ? (*vfs->mmap)(vfs, addr, len, prot, flags, vfs_info (fd), offset) : (caddr_t)-1;
  858. if (result == (caddr_t)-1){
  859. errno = ferrno (vfs);
  860. return (caddr_t)-1;
  861. }
  862. mcm =g_new (struct mc_mmapping, 1);
  863. mcm->addr = result;
  864. mcm->vfs_info = vfs_info (fd);
  865. mcm->vfs = vfs;
  866. mcm->next = mc_mmaparray;
  867. mc_mmaparray = mcm;
  868. return result;
  869. }
  870. int
  871. mc_munmap (caddr_t addr, size_t len)
  872. {
  873. struct mc_mmapping *mcm, *mcm2 = NULL;
  874. for (mcm = mc_mmaparray; mcm != NULL; mcm2 = mcm, mcm = mcm->next){
  875. if (mcm->addr == addr){
  876. if (mcm2 == NULL)
  877. mc_mmaparray = mcm->next;
  878. else
  879. mcm2->next = mcm->next;
  880. if (mcm->vfs->munmap)
  881. (*mcm->vfs->munmap)(mcm->vfs, addr, len, mcm->vfs_info);
  882. g_free (mcm);
  883. return 0;
  884. }
  885. }
  886. return -1;
  887. }
  888. #endif
  889. char *
  890. mc_def_getlocalcopy (vfs *vfs, char *filename)
  891. {
  892. char *tmp;
  893. int fdin, fdout, i;
  894. char buffer[8192];
  895. struct stat mystat;
  896. char *ext = NULL;
  897. char *ptr;
  898. fdin = mc_open (filename, O_RDONLY);
  899. if (fdin == -1)
  900. return NULL;
  901. /* Try to preserve existing extension */
  902. for (ptr = filename + strlen(filename) - 1; ptr >= filename; ptr--) {
  903. if (*ptr == '.') {
  904. ext = ptr;
  905. break;
  906. }
  907. if (!isalnum((unsigned char) *ptr))
  908. break;
  909. }
  910. fdout = mc_mkstemps (&tmp, "mclocalcopy", ext);
  911. if (fdout == -1)
  912. goto fail;
  913. while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0){
  914. if (write (fdout, buffer, i) != i)
  915. goto fail;
  916. }
  917. if (i == -1)
  918. goto fail;
  919. i = mc_close (fdin);
  920. fdin = -1;
  921. if (i==-1)
  922. goto fail;
  923. if (close (fdout)==-1)
  924. goto fail;
  925. if (mc_stat (filename, &mystat) != -1){
  926. chmod (tmp, mystat.st_mode);
  927. }
  928. return tmp;
  929. fail:
  930. if (fdout) close(fdout);
  931. if (fdin) mc_close (fdin);
  932. g_free (tmp);
  933. return NULL;
  934. }
  935. char *
  936. mc_getlocalcopy (const char *pathname)
  937. {
  938. char *result;
  939. char *path = vfs_canon (pathname);
  940. vfs *vfs = vfs_type (path);
  941. result = vfs->getlocalcopy ? (*vfs->getlocalcopy)(vfs, vfs_name (path)) :
  942. mc_def_getlocalcopy (vfs, vfs_name (path));
  943. g_free (path);
  944. if (!result)
  945. errno = ferrno (vfs);
  946. return result;
  947. }
  948. int
  949. mc_def_ungetlocalcopy (vfs *vfs, char *filename, char *local, int has_changed)
  950. { /* Dijkstra probably hates me... But he should teach me how to do this nicely. */
  951. int fdin = -1, fdout = -1, i;
  952. if (has_changed){
  953. char buffer [8192];
  954. fdin = open (local, O_RDONLY);
  955. if (fdin == -1)
  956. goto failed;
  957. fdout = mc_open (filename, O_WRONLY | O_TRUNC);
  958. if (fdout == -1)
  959. goto failed;
  960. while ((i = read (fdin, buffer, sizeof (buffer))) > 0){
  961. if (mc_write (fdout, buffer, i) != i)
  962. goto failed;
  963. }
  964. if (i == -1)
  965. goto failed;
  966. if (close (fdin)==-1) {
  967. fdin = -1;
  968. goto failed;
  969. }
  970. fdin = -1;
  971. if (mc_close (fdout)==-1) {
  972. fdout = -1;
  973. goto failed;
  974. }
  975. }
  976. unlink (local);
  977. g_free (local);
  978. return 0;
  979. failed:
  980. message_1s (1, _("Changes to file lost"), filename);
  981. if (fdout!=-1) mc_close(fdout);
  982. if (fdin!=-1) close(fdin);
  983. unlink (local);
  984. g_free (local);
  985. return -1;
  986. }
  987. int
  988. mc_ungetlocalcopy (const char *pathname, char *local, int has_changed)
  989. {
  990. int return_value = 0;
  991. char *path = vfs_canon (pathname);
  992. vfs *vfs = vfs_type (path);
  993. return_value = vfs->ungetlocalcopy ?
  994. (*vfs->ungetlocalcopy)(vfs, vfs_name (path), local, has_changed) :
  995. mc_def_ungetlocalcopy (vfs, vfs_name (path), local, has_changed);
  996. g_free (path);
  997. return return_value;
  998. }
  999. /*
  1000. * Hmm, as timeout is minute or so, do we need to care about usecs?
  1001. */
  1002. static inline int
  1003. timeoutcmp (struct timeval *t1, struct timeval *t2)
  1004. {
  1005. return ((t1->tv_sec < t2->tv_sec)
  1006. || ((t1->tv_sec == t2->tv_sec) && (t1->tv_usec <= t2->tv_usec)));
  1007. }
  1008. /* This is called from timeout handler with now = 0, or can be called
  1009. with now = 1 to force freeing all filesystems that are not in use */
  1010. void
  1011. vfs_expire (int now)
  1012. {
  1013. static int locked = 0;
  1014. struct timeval time;
  1015. struct vfs_stamping *stamp, *st;
  1016. /* Avoid recursive invocation, e.g. when one of the free functions
  1017. calls message_1s */
  1018. if (locked)
  1019. return;
  1020. locked = 1;
  1021. gettimeofday (&time, NULL);
  1022. time.tv_sec -= vfs_timeout;
  1023. for (stamp = stamps; stamp != NULL;){
  1024. if (now || (timeoutcmp (&stamp->time, &time))){
  1025. st = stamp->next;
  1026. (*stamp->v->free) (stamp->id);
  1027. vfs_rmstamp (stamp->v, stamp->id, 0);
  1028. stamp = st;
  1029. } else
  1030. stamp = stamp->next;
  1031. }
  1032. locked = 0;
  1033. }
  1034. void
  1035. vfs_timeout_handler (void)
  1036. {
  1037. vfs_expire (0);
  1038. }
  1039. void
  1040. vfs_init (void)
  1041. {
  1042. time_t current_time;
  1043. struct tm *t;
  1044. memset (vfs_file_table, 0, sizeof (vfs_file_table));
  1045. current_time = time (NULL);
  1046. t = localtime (&current_time);
  1047. current_mday = t->tm_mday;
  1048. current_mon = t->tm_mon;
  1049. current_year = t->tm_year;
  1050. /* We do not want to register vfs_local_ops */
  1051. #ifdef USE_NETCODE
  1052. tcp_init();
  1053. vfs_register (&vfs_ftpfs_ops);
  1054. vfs_register (&vfs_fish_ops);
  1055. #ifdef WITH_SMBFS
  1056. vfs_register (&vfs_smbfs_ops);
  1057. #endif /* WITH_SMBFS */
  1058. #ifdef WITH_MCFS
  1059. vfs_register (&vfs_mcfs_ops);
  1060. #endif /* WITH_SMBFS */
  1061. #endif /* USE_NETCODE */
  1062. vfs_register (&vfs_extfs_ops);
  1063. vfs_register (&vfs_sfs_ops);
  1064. vfs_register (&vfs_tarfs_ops);
  1065. vfs_register (&vfs_cpiofs_ops);
  1066. #ifdef USE_EXT2FSLIB
  1067. vfs_register (&vfs_undelfs_ops);
  1068. #endif /* USE_EXT2FSLIB */
  1069. vfs_setup_wd ();
  1070. }
  1071. void
  1072. vfs_free_resources (char *path)
  1073. {
  1074. vfs *vfs;
  1075. vfsid vid;
  1076. struct vfs_stamping *parent;
  1077. vfs = vfs_type (path);
  1078. vid = vfs_ncs_getid (vfs, path, &parent);
  1079. if (vid != (vfsid) -1)
  1080. (*vfs->free)(vid);
  1081. vfs_rm_parents (parent);
  1082. }
  1083. #if 0
  1084. /* Shutdown a vfs given a path name */
  1085. void
  1086. vfs_shut_path (char *p)
  1087. {
  1088. vfs *the_vfs;
  1089. struct vfs_stamping *par;
  1090. the_vfs = vfs_type (p);
  1091. vfs_ncs_getid (the_vfs, p, &par);
  1092. (*par->v->free)(par->id);
  1093. vfs_rm_parents (par);
  1094. }
  1095. #endif
  1096. void
  1097. vfs_shut (void)
  1098. {
  1099. struct vfs_stamping *stamp, *st;
  1100. vfs *vfs;
  1101. for (stamp = stamps, stamps = 0; stamp != NULL;){
  1102. (*stamp->v->free)(stamp->id);
  1103. st = stamp->next;
  1104. g_free (stamp);
  1105. stamp = st;
  1106. }
  1107. if (stamps)
  1108. vfs_rmstamp (stamps->v, stamps->id, 1);
  1109. if (current_dir)
  1110. g_free (current_dir);
  1111. for (vfs=vfs_list; vfs; vfs=vfs->next)
  1112. if (vfs->done)
  1113. (*vfs->done) (vfs);
  1114. }
  1115. /*
  1116. * These ones grab information from the VFS
  1117. * and handles them to an upper layer
  1118. */
  1119. void
  1120. vfs_fill_names (void (*func)(char *))
  1121. {
  1122. vfs *vfs;
  1123. for (vfs=vfs_list; vfs; vfs=vfs->next)
  1124. if (vfs->fill_names)
  1125. (*vfs->fill_names) (vfs, func);
  1126. }
  1127. /* Following stuff (parse_ls_lga) is used by ftpfs and extfs */
  1128. #define MAXCOLS 30
  1129. static char *columns [MAXCOLS]; /* Points to the string in column n */
  1130. static int column_ptr [MAXCOLS]; /* Index from 0 to the starting positions of the columns */
  1131. int
  1132. vfs_split_text (char *p)
  1133. {
  1134. char *original = p;
  1135. int numcols;
  1136. memset (columns, 0, sizeof (columns));
  1137. for (numcols = 0; *p && numcols < MAXCOLS; numcols++){
  1138. while (*p == ' ' || *p == '\r' || *p == '\n'){
  1139. *p = 0;
  1140. p++;
  1141. }
  1142. columns [numcols] = p;
  1143. column_ptr [numcols] = p - original;
  1144. while (*p && *p != ' ' && *p != '\r' && *p != '\n')
  1145. p++;
  1146. }
  1147. return numcols;
  1148. }
  1149. static int
  1150. is_num (int idx)
  1151. {
  1152. char *column = columns[idx];
  1153. if (!column || column[0] < '0' || column[0] > '9')
  1154. return 0;
  1155. return 1;
  1156. }
  1157. static int
  1158. is_dos_date (char *str)
  1159. {
  1160. if (!str)
  1161. return 0;
  1162. if (strlen (str) == 8 && str[2] == str[5]
  1163. && strchr ("\\-/", (int) str[2]) != NULL)
  1164. return 1;
  1165. return 0;
  1166. }
  1167. static int
  1168. is_week (char *str, struct tm *tim)
  1169. {
  1170. static const char *week = "SunMonTueWedThuFriSat";
  1171. char *pos;
  1172. if (!str)
  1173. return 0;
  1174. if ((pos = strstr (week, str)) != NULL) {
  1175. if (tim != NULL)
  1176. tim->tm_wday = (pos - week) / 3;
  1177. return 1;
  1178. }
  1179. return 0;
  1180. }
  1181. static int
  1182. is_month (char *str, struct tm *tim)
  1183. {
  1184. static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
  1185. char *pos;
  1186. if (!str)
  1187. return 0;
  1188. if ((pos = strstr (month, str)) != NULL) {
  1189. if (tim != NULL)
  1190. tim->tm_mon = (pos - month) / 3;
  1191. return 1;
  1192. }
  1193. return 0;
  1194. }
  1195. static int
  1196. is_time (char *str, struct tm *tim)
  1197. {
  1198. char *p, *p2;
  1199. if (!str)
  1200. return 0;
  1201. if ((p = strchr (str, ':')) && (p2 = strrchr (str, ':'))) {
  1202. if (p != p2) {
  1203. if (sscanf
  1204. (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min,
  1205. &tim->tm_sec) != 3)
  1206. return 0;
  1207. } else {
  1208. if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
  1209. return 0;
  1210. }
  1211. } else
  1212. return 0;
  1213. return 1;
  1214. }
  1215. static int is_year (char *str, struct tm *tim)
  1216. {
  1217. long year;
  1218. if (!str)
  1219. return 0;
  1220. if (strchr (str, ':'))
  1221. return 0;
  1222. if (strlen (str) != 4)
  1223. return 0;
  1224. if (sscanf (str, "%ld", &year) != 1)
  1225. return 0;
  1226. if (year < 1900 || year > 3000)
  1227. return 0;
  1228. tim->tm_year = (int) (year - 1900);
  1229. return 1;
  1230. }
  1231. /*
  1232. * FIXME: this is broken. Consider following entry:
  1233. * -rwx------ 1 root root 1 Aug 31 10:04 2904 1234
  1234. * where "2904 1234" is filename. Well, this code decodes it as year :-(.
  1235. */
  1236. int
  1237. vfs_parse_filetype (char c)
  1238. {
  1239. switch (c) {
  1240. case 'd': return S_IFDIR;
  1241. case 'b': return S_IFBLK;
  1242. case 'c': return S_IFCHR;
  1243. case 'l': return S_IFLNK;
  1244. case 's': /* Socket */
  1245. #ifdef S_IFSOCK
  1246. return S_IFSOCK;
  1247. #else
  1248. /* If not supported, we fall through to IFIFO */
  1249. return S_IFIFO;
  1250. #endif
  1251. case 'D': /* Solaris door */
  1252. #ifdef S_IFDOOR
  1253. return S_IFDOOR;
  1254. #else
  1255. return S_IFIFO;
  1256. #endif
  1257. case 'p': return S_IFIFO;
  1258. case 'm': case 'n': /* Don't know what these are :-) */
  1259. case '-': case '?': return S_IFREG;
  1260. default: return -1;
  1261. }
  1262. }
  1263. int vfs_parse_filemode (const char *p)
  1264. { /* converts rw-rw-rw- into 0666 */
  1265. int res = 0;
  1266. switch (*(p++)){
  1267. case 'r': res |= 0400; break;
  1268. case '-': break;
  1269. default: return -1;
  1270. }
  1271. switch (*(p++)){
  1272. case 'w': res |= 0200; break;
  1273. case '-': break;
  1274. default: return -1;
  1275. }
  1276. switch (*(p++)){
  1277. case 'x': res |= 0100; break;
  1278. case 's': res |= 0100 | S_ISUID; break;
  1279. case 'S': res |= S_ISUID; break;
  1280. case '-': break;
  1281. default: return -1;
  1282. }
  1283. switch (*(p++)){
  1284. case 'r': res |= 0040; break;
  1285. case '-': break;
  1286. default: return -1;
  1287. }
  1288. switch (*(p++)){
  1289. case 'w': res |= 0020; break;
  1290. case '-': break;
  1291. default: return -1;
  1292. }
  1293. switch (*(p++)){
  1294. case 'x': res |= 0010; break;
  1295. case 's': res |= 0010 | S_ISGID; break;
  1296. case 'l': /* Solaris produces these */
  1297. case 'S': res |= S_ISGID; break;
  1298. case '-': break;
  1299. default: return -1;
  1300. }
  1301. switch (*(p++)){
  1302. case 'r': res |= 0004; break;
  1303. case '-': break;
  1304. default: return -1;
  1305. }
  1306. switch (*(p++)){
  1307. case 'w': res |= 0002; break;
  1308. case '-': break;
  1309. default: return -1;
  1310. }
  1311. switch (*(p++)){
  1312. case 'x': res |= 0001; break;
  1313. case 't': res |= 0001 | S_ISVTX; break;
  1314. case 'T': res |= S_ISVTX; break;
  1315. case '-': break;
  1316. default: return -1;
  1317. }
  1318. return res;
  1319. }
  1320. /* This function parses from idx in the columns[] array */
  1321. int
  1322. vfs_parse_filedate (int idx, time_t *t)
  1323. {
  1324. char *p;
  1325. struct tm tim;
  1326. int d[3];
  1327. int got_year = 0;
  1328. /* Let's setup default time values */
  1329. tim.tm_year = current_year;
  1330. tim.tm_mon = current_mon;
  1331. tim.tm_mday = current_mday;
  1332. tim.tm_hour = 0;
  1333. tim.tm_min = 0;
  1334. tim.tm_sec = 0;
  1335. tim.tm_isdst = -1; /* Let mktime() try to guess correct dst offset */
  1336. p = columns[idx++];
  1337. /* We eat weekday name in case of extfs */
  1338. if (is_week (p, &tim))
  1339. p = columns[idx++];
  1340. /* Month name */
  1341. if (is_month (p, &tim)) {
  1342. /* And we expect, it followed by day number */
  1343. if (is_num (idx))
  1344. tim.tm_mday = (int) atol (columns[idx++]);
  1345. else
  1346. return 0; /* No day */
  1347. } else {
  1348. /* We usually expect:
  1349. Mon DD hh:mm
  1350. Mon DD YYYY
  1351. But in case of extfs we allow these date formats:
  1352. Mon DD YYYY hh:mm
  1353. Mon DD hh:mm YYYY
  1354. Wek Mon DD hh:mm:ss YYYY
  1355. MM-DD-YY hh:mm
  1356. where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
  1357. YYYY four digit year, hh, mm, ss two digit hour, minute or second. */
  1358. /* Here just this special case with MM-DD-YY */
  1359. if (is_dos_date (p)) {
  1360. p[2] = p[5] = '-';
  1361. if (sscanf (p, "%2d-%2d-%2d", &d[0], &d[1], &d[2]) == 3) {
  1362. /* We expect to get:
  1363. 1. MM-DD-YY
  1364. 2. DD-MM-YY
  1365. 3. YY-MM-DD
  1366. 4. YY-DD-MM */
  1367. /* Hmm... maybe, next time :) */
  1368. /* At last, MM-DD-YY */
  1369. d[0]--; /* Months are zerobased */
  1370. /* Y2K madness */
  1371. if (d[2] < 70)
  1372. d[2] += 100;
  1373. tim.tm_mon = d[0];
  1374. tim.tm_mday = d[1];
  1375. tim.tm_year = d[2];
  1376. got_year = 1;
  1377. } else
  1378. return 0; /* sscanf failed */
  1379. } else
  1380. return 0; /* unsupported format */
  1381. }
  1382. /* Here we expect to find time and/or year */
  1383. if (is_num (idx)) {
  1384. if (is_time (columns[idx], &tim)
  1385. || (got_year = is_year (columns[idx], &tim))) {
  1386. idx++;
  1387. /* This is a special case for ctime() or Mon DD YYYY hh:mm */
  1388. if (is_num (idx) && (columns[idx + 1][0])) {
  1389. if (got_year) {
  1390. if (is_time (columns[idx], &tim))
  1391. idx++; /* time also */
  1392. } else {
  1393. if ((got_year = is_year (columns[idx], &tim)))
  1394. idx++; /* year also */
  1395. }
  1396. }
  1397. } /* only time or date */
  1398. } else
  1399. return 0; /* Nor time or date */
  1400. /*
  1401. * If the date is less than 6 months in the past, it is shown without year
  1402. * other dates in the past or future are shown with year but without time
  1403. * This does not check for years before 1900 ... I don't know, how
  1404. * to represent them at all
  1405. */
  1406. if (!got_year && current_mon < 6 && current_mon < tim.tm_mon
  1407. && tim.tm_mon - current_mon >= 6)
  1408. tim.tm_year--;
  1409. if ((*t = mktime (&tim)) < 0)
  1410. *t = 0;
  1411. return idx;
  1412. }
  1413. int
  1414. vfs_parse_ls_lga (const char *p, struct stat *s, char **filename, char **linkname)
  1415. {
  1416. int idx, idx2, num_cols;
  1417. int i;
  1418. char *p_copy = NULL;
  1419. char *t = NULL;
  1420. const char *line = p;
  1421. if (strncmp (p, "total", 5) == 0)
  1422. return 0;
  1423. if ((i = vfs_parse_filetype(*(p++))) == -1)
  1424. goto error;
  1425. s->st_mode = i;
  1426. if (*p == ' ') /* Notwell 4 */
  1427. p++;
  1428. if (*p == '['){
  1429. if (strlen (p) <= 8 || p [8] != ']')
  1430. goto error;
  1431. /* Should parse here the Notwell permissions :) */
  1432. if (S_ISDIR (s->st_mode))
  1433. s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
  1434. else
  1435. s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
  1436. p += 9;
  1437. } else {
  1438. if ((i = vfs_parse_filemode(p)) == -1)
  1439. goto error;
  1440. s->st_mode |= i;
  1441. p += 9;
  1442. /* This is for an extra ACL attribute (HP-UX) */
  1443. if (*p == '+')
  1444. p++;
  1445. }
  1446. p_copy = g_strdup(p);
  1447. num_cols = vfs_split_text (p_copy);
  1448. s->st_nlink = atol (columns [0]);
  1449. if (s->st_nlink <= 0)
  1450. goto error;
  1451. if (!is_num (1))
  1452. s->st_uid = finduid (columns [1]);
  1453. else
  1454. s->st_uid = (uid_t) atol (columns [1]);
  1455. /* Mhm, the ls -lg did not produce a group field */
  1456. for (idx = 3; idx <= 5; idx++)
  1457. if (is_month(columns [idx], NULL) || is_week(columns [idx], NULL) || is_dos_date(columns[idx]))
  1458. break;
  1459. if (idx == 6 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode)))
  1460. goto error;
  1461. /* We don't have gid */
  1462. if (idx == 3 || (idx == 4 && (S_ISCHR(s->st_mode) || S_ISBLK (s->st_mode))))
  1463. idx2 = 2;
  1464. else {
  1465. /* We have gid field */
  1466. if (is_num (2))
  1467. s->st_gid = (gid_t) atol (columns [2]);
  1468. else
  1469. s->st_gid = findgid (columns [2]);
  1470. idx2 = 3;
  1471. }
  1472. /* This is device */
  1473. if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode)){
  1474. int maj, min;
  1475. if (!is_num (idx2) || sscanf(columns [idx2], " %d,", &maj) != 1)
  1476. goto error;
  1477. if (!is_num (++idx2) || sscanf(columns [idx2], " %d", &min) != 1)
  1478. goto error;
  1479. #ifdef HAVE_ST_RDEV
  1480. s->st_rdev = ((maj & 0xff) << 8) | (min & 0xffff00ff);
  1481. #endif
  1482. s->st_size = 0;
  1483. } else {
  1484. /* Common file size */
  1485. if (!is_num (idx2))
  1486. goto error;
  1487. s->st_size = (size_t) atol (columns [idx2]);
  1488. #ifdef HAVE_ST_RDEV
  1489. s->st_rdev = 0;
  1490. #endif
  1491. }
  1492. idx = vfs_parse_filedate(idx, &s->st_mtime);
  1493. if (!idx)
  1494. goto error;
  1495. /* Use resulting time value */
  1496. s->st_atime = s->st_ctime = s->st_mtime;
  1497. #if 0
  1498. /* These variables must be initialized by vfs_s_new_inode () */
  1499. s->st_dev = 0;
  1500. s->st_ino = 0;
  1501. #endif
  1502. #ifdef HAVE_ST_BLKSIZE
  1503. s->st_blksize = 512;
  1504. #endif
  1505. #ifdef HAVE_ST_BLOCKS
  1506. s->st_blocks = (s->st_size + 511) / 512;
  1507. #endif
  1508. for (i = idx + 1, idx2 = 0; i < num_cols; i++ )
  1509. if (strcmp (columns [i], "->") == 0){
  1510. idx2 = i;
  1511. break;
  1512. }
  1513. if (((S_ISLNK (s->st_mode) ||
  1514. (num_cols == idx + 3 && s->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */
  1515. && idx2){
  1516. if (filename){
  1517. *filename = g_strndup (p + column_ptr [idx], column_ptr [idx2] - column_ptr [idx] - 1);
  1518. }
  1519. if (linkname){
  1520. t = g_strdup (p + column_ptr [idx2+1]);
  1521. *linkname = t;
  1522. }
  1523. } else {
  1524. /* Extract the filename from the string copy, not from the columns
  1525. * this way we have a chance of entering hidden directories like ". ."
  1526. */
  1527. if (filename){
  1528. /*
  1529. *filename = g_strdup (columns [idx++]);
  1530. */
  1531. t = g_strdup (p + column_ptr [idx]);
  1532. *filename = t;
  1533. }
  1534. if (linkname)
  1535. *linkname = NULL;
  1536. }
  1537. if (t) {
  1538. int p = strlen (t);
  1539. if ((--p > 0) && (t [p] == '\r' || t [p] == '\n'))
  1540. t [p] = 0;
  1541. if ((--p > 0) && (t [p] == '\r' || t [p] == '\n'))
  1542. t [p] = 0;
  1543. }
  1544. g_free (p_copy);
  1545. return 1;
  1546. error:
  1547. {
  1548. static int errorcount = 0;
  1549. if (++errorcount < 5) {
  1550. message_1s (1, _("Could not parse:"), (p_copy && *p_copy) ? p_copy : line);
  1551. } else if (errorcount == 5)
  1552. message_1s (1, _("Error"), _("More parsing errors will be ignored."));
  1553. }
  1554. g_free (p_copy);
  1555. return 0;
  1556. }
  1557. void
  1558. vfs_die (char *m)
  1559. {
  1560. message_1s (1, _("Internal error:"), m);
  1561. exit (1);
  1562. }
  1563. void
  1564. vfs_print_stats (const char *fs_name, const char *action, const char *file_name, off_t have, off_t need)
  1565. {
  1566. static char *i18n_percent_transf_format = NULL, *i18n_transf_format = NULL;
  1567. if (i18n_percent_transf_format == NULL) {
  1568. i18n_percent_transf_format = _("%s: %s: %s %3d%% (%lu bytes transferred)");
  1569. i18n_transf_format = _("%s: %s: %s %lu bytes transferred");
  1570. }
  1571. if (need)
  1572. print_vfs_message (i18n_percent_transf_format, fs_name, action,
  1573. file_name, (int)((double)have*100/need), (unsigned long) have);
  1574. else
  1575. print_vfs_message (i18n_transf_format,
  1576. fs_name, action, file_name, (unsigned long) have);
  1577. }
  1578. char *
  1579. vfs_get_password (char *msg)
  1580. {
  1581. return (char *) input_dialog (msg, _("Password:"), INPUT_PASSWORD);
  1582. }
  1583. /*
  1584. * Returns vfs path corresponding to given url. If passed string is
  1585. * not recognized as url, g_strdup(url) is returned.
  1586. */
  1587. char *
  1588. vfs_translate_url (char *url)
  1589. {
  1590. if (strncmp (url, "ftp://", 6) == 0)
  1591. return g_strconcat ("/#ftp:", url + 6, NULL);
  1592. else if (strncmp (url, "a:", 2) == 0)
  1593. return g_strdup ("/#a");
  1594. else
  1595. return g_strdup (url);
  1596. }