extfs.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472
  1. /* Virtual File System: External file system.
  2. Copyright (C) 1995 The Free Software Foundation
  3. Written by: 1995 Jakub Jelinek
  4. Rewritten by: 1998 Pavel Machek
  5. Additional changes by: 1999 Andrew T. Veliath
  6. $Id$
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public License
  9. as published by the Free Software Foundation; either version 2 of
  10. the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Library General Public License for more details.
  15. You should have received a copy of the GNU Library General Public
  16. License along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  18. /* Namespace: exports only vfs_extfs_ops */
  19. #include <config.h>
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <fcntl.h>
  27. #include <unistd.h>
  28. #include <signal.h>
  29. #ifdef HAVE_SYS_WAIT_H
  30. #include <sys/wait.h>
  31. #endif
  32. #include <errno.h>
  33. #include "utilvfs.h"
  34. #include "../src/dialog.h"
  35. #include "../src/main.h" /* For shell_execute */
  36. #include "xdirentry.h"
  37. #include "vfs.h"
  38. #include "extfs.h"
  39. #undef ERRNOR
  40. #define ERRNOR(x,y) do { my_errno = x; return y; } while(0)
  41. struct inode {
  42. nlink_t nlink;
  43. struct entry *first_in_subdir; /* only used if this is a directory */
  44. struct entry *last_in_subdir;
  45. ino_t inode; /* This is inode # */
  46. dev_t dev; /* This is an internal identification of the extfs archive */
  47. struct archive *archive; /* And this is an archive structure */
  48. dev_t rdev;
  49. mode_t mode;
  50. uid_t uid;
  51. gid_t gid;
  52. int size;
  53. time_t mtime;
  54. char linkflag;
  55. char *linkname;
  56. time_t atime;
  57. time_t ctime;
  58. char *local_filename;
  59. };
  60. struct entry {
  61. struct entry *next_in_dir;
  62. struct entry *dir;
  63. char *name;
  64. struct inode *inode;
  65. };
  66. struct pseudofile {
  67. struct archive *archive;
  68. unsigned int has_changed:1;
  69. int local_handle;
  70. struct entry *entry;
  71. };
  72. static struct entry *
  73. find_entry (struct entry *dir, char *name, int make_dirs, int make_file);
  74. static int extfs_which (vfs *me, char *path);
  75. static void remove_entry (struct entry *e);
  76. static struct archive *first_archive = NULL;
  77. static int my_errno = 0;
  78. static struct stat hstat; /* Stat struct corresponding */
  79. #define MAXEXTFS 32
  80. static char *extfs_prefixes [MAXEXTFS];
  81. static char extfs_need_archive [MAXEXTFS];
  82. static int extfs_no = 0;
  83. static void extfs_fill_names (vfs *me, void (*func)(char *))
  84. {
  85. struct archive *a = first_archive;
  86. char *name;
  87. while (a){
  88. name = g_strconcat (extfs_prefixes [a->fstype], "#",
  89. (a->name ? a->name : ""), "/",
  90. a->current_dir->name, NULL);
  91. (*func)(name);
  92. g_free (name);
  93. a = a->next;
  94. }
  95. }
  96. static void make_dot_doubledot (struct entry *ent)
  97. {
  98. struct entry *entry = g_new (struct entry, 1);
  99. struct entry *parentry = ent->dir;
  100. struct inode *inode = ent->inode, *parent;
  101. parent = (parentry != NULL) ? parentry->inode : NULL;
  102. entry->name = g_strdup (".");
  103. entry->inode = inode;
  104. entry->dir = ent;
  105. inode->local_filename = NULL;
  106. inode->first_in_subdir = entry;
  107. inode->last_in_subdir = entry;
  108. inode->nlink++;
  109. entry->next_in_dir = g_new (struct entry, 1);
  110. entry=entry->next_in_dir;
  111. entry->name = g_strdup ("..");
  112. inode->last_in_subdir = entry;
  113. entry->next_in_dir = NULL;
  114. if (parent != NULL) {
  115. entry->inode = parent;
  116. entry->dir = parentry;
  117. parent->nlink++;
  118. } else {
  119. entry->inode = inode;
  120. entry->dir = ent;
  121. inode->nlink++;
  122. }
  123. }
  124. static struct entry *generate_entry (struct archive *archive,
  125. char *name, struct entry *parentry, mode_t mode)
  126. {
  127. mode_t myumask;
  128. struct inode *inode, *parent;
  129. struct entry *entry;
  130. parent = (parentry != NULL) ? parentry->inode : NULL;
  131. entry = g_new (struct entry, 1);
  132. entry->name = g_strdup (name);
  133. entry->next_in_dir = NULL;
  134. entry->dir = parentry;
  135. if (parent != NULL) {
  136. parent->last_in_subdir->next_in_dir = entry;
  137. parent->last_in_subdir = entry;
  138. }
  139. inode = g_new (struct inode, 1);
  140. entry->inode = inode;
  141. inode->local_filename = NULL;
  142. inode->linkname = 0;
  143. inode->inode = (archive->__inode_counter)++;
  144. inode->dev = archive->rdev;
  145. inode->archive = archive;
  146. myumask = umask (022);
  147. umask (myumask);
  148. inode->mode = mode & ~myumask;
  149. mode = inode->mode;
  150. inode->rdev = 0;
  151. inode->uid = getuid ();
  152. inode->gid = getgid ();
  153. inode->size = 0;
  154. inode->mtime = time (NULL);
  155. inode->atime = inode->mtime;
  156. inode->ctime = inode->mtime;
  157. inode->nlink = 1;
  158. if (S_ISDIR (mode))
  159. make_dot_doubledot (entry);
  160. return entry;
  161. }
  162. static void free_entries (struct entry *entry)
  163. {
  164. return;
  165. }
  166. static void free_archive (struct archive *archive)
  167. {
  168. free_entries (archive->root_entry);
  169. if (archive->local_name != NULL) {
  170. struct stat my;
  171. mc_stat (archive->local_name, &my);
  172. mc_ungetlocalcopy (archive->name, archive->local_name,
  173. archive->local_stat.st_mtime != my.st_mtime);
  174. /* ungetlocalcopy frees local_name for us */
  175. }
  176. if (archive->name)
  177. g_free (archive->name);
  178. g_free (archive);
  179. }
  180. static FILE *open_archive (int fstype, char *name, struct archive **pparc)
  181. {
  182. static dev_t __extfs_no = 0;
  183. FILE *result;
  184. mode_t mode;
  185. char *cmd;
  186. char *mc_extfsdir;
  187. struct stat mystat;
  188. struct archive *current_archive;
  189. struct entry *root_entry;
  190. char *local_name = NULL, *tmp = 0;
  191. int uses_archive = extfs_need_archive [fstype];
  192. if (uses_archive){
  193. if (mc_stat (name, &mystat) == -1)
  194. return NULL;
  195. if (!vfs_file_is_local (name)) {
  196. local_name = mc_getlocalcopy (name);
  197. if (local_name == NULL)
  198. return NULL;
  199. }
  200. tmp = name_quote (name, 0);
  201. }
  202. #if 0
  203. /* Sorry, what is this good for? */
  204. if (uses_archive == EFS_NEED_ARG){
  205. tmp = name_quote (name, 0);
  206. }
  207. #endif
  208. mc_extfsdir = concat_dir_and_file (mc_home, "extfs/");
  209. cmd = g_strconcat (mc_extfsdir, extfs_prefixes [fstype],
  210. " list ", local_name ? local_name : tmp, NULL);
  211. if (tmp)
  212. g_free (tmp);
  213. g_free (mc_extfsdir);
  214. result = popen (cmd, "r");
  215. g_free (cmd);
  216. if (result == NULL) {
  217. if (local_name != NULL && uses_archive)
  218. mc_ungetlocalcopy (name, local_name, 0);
  219. return NULL;
  220. }
  221. current_archive = g_new (struct archive, 1);
  222. current_archive->fstype = fstype;
  223. current_archive->name = name ? g_strdup (name): name;
  224. current_archive->local_name = local_name;
  225. if (local_name != NULL)
  226. mc_stat (local_name, &current_archive->local_stat);
  227. current_archive->__inode_counter = 0;
  228. current_archive->fd_usage = 0;
  229. current_archive->extfsstat = mystat;
  230. current_archive->rdev = __extfs_no++;
  231. current_archive->next = first_archive;
  232. first_archive = current_archive;
  233. mode = current_archive->extfsstat.st_mode & 07777;
  234. if (mode & 0400)
  235. mode |= 0100;
  236. if (mode & 0040)
  237. mode |= 0010;
  238. if (mode & 0004)
  239. mode |= 0001;
  240. mode |= S_IFDIR;
  241. root_entry = generate_entry (current_archive, "/", NULL, mode);
  242. root_entry->inode->uid = current_archive->extfsstat.st_uid;
  243. root_entry->inode->gid = current_archive->extfsstat.st_gid;
  244. root_entry->inode->atime = current_archive->extfsstat.st_atime;
  245. root_entry->inode->ctime = current_archive->extfsstat.st_ctime;
  246. root_entry->inode->mtime = current_archive->extfsstat.st_mtime;
  247. current_archive->root_entry = root_entry;
  248. current_archive->current_dir = root_entry;
  249. *pparc = current_archive;
  250. return result;
  251. }
  252. /*
  253. * Main loop for reading an archive.
  254. * Returns 0 on success, -1 on error.
  255. */
  256. static int read_archive (int fstype, char *name, struct archive **pparc)
  257. {
  258. FILE *extfsd;
  259. char *buffer;
  260. struct archive *current_archive;
  261. char *current_file_name, *current_link_name;
  262. if ((extfsd = open_archive (fstype, name, &current_archive)) == NULL) {
  263. message_3s (1, MSG_ERROR, _("Couldn't open %s archive\n%s"),
  264. extfs_prefixes [fstype], name);
  265. return -1;
  266. }
  267. buffer = g_malloc (4096);
  268. while (fgets (buffer, 4096, extfsd) != NULL) {
  269. current_link_name = NULL;
  270. if (vfs_parse_ls_lga (buffer, &hstat, &current_file_name, &current_link_name)) {
  271. struct entry *entry, *pent;
  272. struct inode *inode;
  273. char *p, *q, *cfn = current_file_name;
  274. if (*cfn) {
  275. if (*cfn == '/')
  276. cfn++;
  277. p = strchr (cfn, 0);
  278. if (p != cfn && *(p - 1) == '/')
  279. *(p - 1) = 0;
  280. p = strrchr (cfn, '/');
  281. if (p == NULL) {
  282. p = cfn;
  283. q = strchr (cfn, 0);
  284. } else {
  285. *(p++) = 0;
  286. q = cfn;
  287. }
  288. if (S_ISDIR (hstat.st_mode) &&
  289. (!strcmp (p, ".") || !strcmp (p, "..")))
  290. goto read_extfs_continue;
  291. pent = find_entry (current_archive->root_entry, q, 1, 0) ;
  292. if (pent == NULL) {
  293. message_1s (1, MSG_ERROR, _("Inconsistent extfs archive"));
  294. /* FIXME: Should clean everything one day */
  295. g_free (buffer);
  296. pclose (extfsd);
  297. return -1;
  298. }
  299. entry = g_new (struct entry, 1);
  300. entry->name = g_strdup (p);
  301. entry->next_in_dir = NULL;
  302. entry->dir = pent;
  303. if (pent != NULL) {
  304. if (pent->inode->last_in_subdir){
  305. pent->inode->last_in_subdir->next_in_dir = entry;
  306. pent->inode->last_in_subdir = entry;
  307. }
  308. }
  309. if (!S_ISLNK (hstat.st_mode) && current_link_name != NULL) {
  310. pent = find_entry (current_archive->root_entry, current_link_name, 0, 0);
  311. if (pent == NULL) {
  312. message_1s (1, MSG_ERROR, _("Inconsistent extfs archive"));
  313. /* FIXME: Should clean everything one day */
  314. g_free (buffer);
  315. pclose (extfsd);
  316. return -1;
  317. } else {
  318. entry->inode = pent->inode;
  319. pent->inode->nlink++;
  320. }
  321. } else {
  322. inode = g_new (struct inode, 1);
  323. entry->inode = inode;
  324. inode->local_filename = NULL;
  325. inode->inode = (current_archive->__inode_counter)++;
  326. inode->nlink = 1;
  327. inode->dev = current_archive->rdev;
  328. inode->archive = current_archive;
  329. inode->mode = hstat.st_mode;
  330. #ifdef HAVE_ST_RDEV
  331. inode->rdev = hstat.st_rdev;
  332. #else
  333. inode->rdev = 0;
  334. #endif
  335. inode->uid = hstat.st_uid;
  336. inode->gid = hstat.st_gid;
  337. inode->size = hstat.st_size;
  338. inode->mtime = hstat.st_mtime;
  339. inode->atime = hstat.st_atime;
  340. inode->ctime = hstat.st_ctime;
  341. if (current_link_name != NULL && S_ISLNK (hstat.st_mode)) {
  342. inode->linkname = current_link_name;
  343. current_link_name = NULL;
  344. } else {
  345. if (S_ISLNK( hstat.st_mode))
  346. inode->mode &= ~S_IFLNK; /* You *DON'T* want to do this always */
  347. inode->linkname = NULL;
  348. }
  349. if (S_ISDIR (hstat.st_mode))
  350. make_dot_doubledot (entry);
  351. }
  352. }
  353. read_extfs_continue:
  354. g_free (current_file_name);
  355. if (current_link_name != NULL)
  356. g_free (current_link_name);
  357. }
  358. }
  359. pclose (extfsd);
  360. #ifdef SCO_FLAVOR
  361. waitpid(-1,NULL,WNOHANG);
  362. #endif /* SCO_FLAVOR */
  363. *pparc = current_archive;
  364. g_free (buffer);
  365. return 0;
  366. }
  367. static char *get_path (char *inname, struct archive **archive, int is_dir,
  368. int do_not_open);
  369. /* Returns path inside argument. Returned char* is inside inname, which is mangled
  370. * by this operation (so you must not free it's return value)
  371. */
  372. static char *get_path_mangle (char *inname, struct archive **archive, int is_dir,
  373. int do_not_open)
  374. {
  375. char *local, *archive_name, *op;
  376. int result = -1;
  377. struct archive *parc;
  378. struct vfs_stamping *parent;
  379. vfs *v;
  380. int fstype;
  381. archive_name = inname;
  382. vfs_split( inname, &local, &op );
  383. fstype = extfs_which( NULL, op ); /* FIXME: we really should pass
  384. self pointer. But as we know that extfs_which does not touch vfs
  385. *me, it does not matter for now */
  386. if (fstype == -1)
  387. return NULL;
  388. if (!local)
  389. local = "";
  390. /* All filesystems should have some local archive, at least
  391. * it can be '/'.
  392. *
  393. * Actually, we should implement an alias mechanism that would
  394. * translate: "a:" to "dos:a.
  395. *
  396. */
  397. for (parc = first_archive; parc != NULL; parc = parc->next)
  398. if (parc->name) {
  399. if (!strcmp (parc->name, archive_name)) {
  400. struct stat *s=&(parc->extfsstat);
  401. if (vfs_uid && (!(s->st_mode & 0004)))
  402. if ((s->st_gid != vfs_gid) || !(s->st_mode & 0040))
  403. if ((s->st_uid != vfs_uid) || !(s->st_mode & 0400))
  404. return NULL;
  405. /* This is not too secure - in some cases (/#mtools) files created
  406. under user a are probably visible to everyone else since / usually
  407. has permissions 755 */
  408. vfs_stamp (&vfs_extfs_ops, (vfsid) parc);
  409. goto return_success;
  410. }
  411. }
  412. result = do_not_open ? -1 : read_archive (fstype, archive_name, &parc);
  413. if (result == -1) ERRNOR (EIO, NULL);
  414. if (archive_name){
  415. v = vfs_type (archive_name);
  416. if (v == &vfs_local_ops) {
  417. parent = NULL;
  418. } else {
  419. parent = g_new (struct vfs_stamping, 1);
  420. parent->v = v;
  421. parent->next = 0;
  422. parent->id = (*v->getid) (v, archive_name, &(parent->parent));
  423. }
  424. vfs_add_noncurrent_stamps (&vfs_extfs_ops, (vfsid) parc, parent);
  425. vfs_rm_parents (parent);
  426. }
  427. return_success:
  428. *archive = parc;
  429. return local;
  430. }
  431. /* Returns allocated path (without leading slash) inside the archive */
  432. static char *get_path_from_entry (struct entry *entry)
  433. {
  434. struct list {
  435. struct list *next;
  436. char *name;
  437. } *head, *p;
  438. char *localpath;
  439. size_t len;
  440. for (len = 0, head = 0; entry->dir; entry = entry->dir) {
  441. p = g_new (struct list, 1);
  442. p->next = head;
  443. p->name = entry->name;
  444. head = p;
  445. len += strlen (entry->name) + 1;
  446. }
  447. if (len == 0)
  448. return g_strdup ("");
  449. localpath = g_malloc (len);
  450. *localpath = '\0';
  451. while (head) {
  452. strcat (localpath, head->name);
  453. if (head->next)
  454. strcat (localpath, "/");
  455. p = head;
  456. head = head->next;
  457. g_free (p);
  458. }
  459. return (localpath);
  460. }
  461. struct loop_protect {
  462. struct entry *entry;
  463. struct loop_protect *next;
  464. };
  465. static int errloop;
  466. static int notadir;
  467. static struct entry *
  468. __find_entry (struct entry *dir, char *name,
  469. struct loop_protect *list, int make_dirs, int make_file);
  470. static struct entry *
  471. __resolve_symlinks (struct entry *entry,
  472. struct loop_protect *list)
  473. {
  474. struct entry *pent;
  475. struct loop_protect *looping;
  476. if (!S_ISLNK (entry->inode->mode))
  477. return entry;
  478. for (looping = list; looping != NULL; looping = looping->next)
  479. if (entry == looping->entry) { /* Here we protect us against symlink looping */
  480. errloop = 1;
  481. return NULL;
  482. }
  483. looping = g_new (struct loop_protect, 1);
  484. looping->entry = entry;
  485. looping->next = list;
  486. pent = __find_entry (entry->dir, entry->inode->linkname, looping, 0, 0);
  487. g_free (looping);
  488. if (pent == NULL)
  489. my_errno = ENOENT;
  490. return pent;
  491. }
  492. static struct entry *my_resolve_symlinks (struct entry *entry)
  493. {
  494. struct entry *res;
  495. errloop = 0;
  496. notadir = 0;
  497. res = __resolve_symlinks (entry, NULL);
  498. if (res == NULL) {
  499. if (errloop)
  500. my_errno = ELOOP;
  501. else if (notadir)
  502. my_errno = ENOTDIR;
  503. }
  504. return res;
  505. }
  506. static char *get_archive_name (struct archive *archive)
  507. {
  508. char *archive_name;
  509. if (archive->local_name)
  510. archive_name = archive->local_name;
  511. else
  512. archive_name = archive->name;
  513. if (!archive_name || !*archive_name)
  514. return "no_archive_name";
  515. else
  516. return archive_name;
  517. }
  518. static void extfs_run (char *file)
  519. {
  520. struct archive *archive;
  521. char *p, *q, *archive_name, *mc_extfsdir;
  522. char *cmd;
  523. if ((p = get_path (file, &archive, 0, 0)) == NULL)
  524. return;
  525. q = name_quote (p, 0);
  526. g_free (p);
  527. archive_name = name_quote (get_archive_name(archive), 0);
  528. mc_extfsdir = concat_dir_and_file (mc_home, "extfs/");
  529. cmd = g_strconcat (mc_extfsdir, extfs_prefixes [archive->fstype],
  530. " run ", archive_name, " ", q, NULL);
  531. g_free (mc_extfsdir);
  532. g_free (archive_name);
  533. g_free (q);
  534. #ifndef VFS_STANDALONE
  535. shell_execute(cmd, 0);
  536. #else
  537. vfs_die( "shell_execute: implement me!" );
  538. #endif
  539. g_free(cmd);
  540. }
  541. static void *extfs_open (vfs *me, char *file, int flags, int mode)
  542. {
  543. struct pseudofile *extfs_info;
  544. struct archive *archive;
  545. char *q;
  546. char *mc_extfsdir;
  547. struct entry *entry;
  548. int local_handle;
  549. const int do_create = (flags & O_ACCMODE) != O_RDONLY;
  550. if ((q = get_path_mangle (file, &archive, 0, 0)) == NULL)
  551. return NULL;
  552. entry = find_entry (archive->root_entry, q, 0, do_create);
  553. if (entry == NULL)
  554. return NULL;
  555. if ((entry = my_resolve_symlinks (entry)) == NULL)
  556. return NULL;
  557. if (S_ISDIR (entry->inode->mode)) ERRNOR (EISDIR, NULL);
  558. if (entry->inode->local_filename == NULL) {
  559. char *cmd;
  560. char *archive_name, *p;
  561. {
  562. int handle;
  563. handle = mc_mkstemps (&entry->inode->local_filename, "extfs", NULL);
  564. if (handle == -1)
  565. return NULL;
  566. close(handle);
  567. }
  568. p = get_path_from_entry (entry);
  569. q = name_quote (p, 0);
  570. g_free (p);
  571. archive_name = name_quote (get_archive_name (archive), 0);
  572. mc_extfsdir = concat_dir_and_file (mc_home, "extfs/");
  573. cmd = g_strconcat (mc_extfsdir, extfs_prefixes [archive->fstype],
  574. " copyout ",
  575. archive_name,
  576. " ", q, " ", entry->inode->local_filename, NULL);
  577. g_free (q);
  578. g_free (mc_extfsdir);
  579. g_free (archive_name);
  580. if (my_system (EXECUTE_AS_SHELL | EXECUTE_SETUID | EXECUTE_WAIT, shell, cmd) && !do_create){
  581. free (entry->inode->local_filename);
  582. entry->inode->local_filename = NULL;
  583. g_free (cmd);
  584. my_errno = EIO;
  585. return NULL;
  586. }
  587. g_free (cmd);
  588. }
  589. local_handle = open (entry->inode->local_filename, flags, mode);
  590. if (local_handle == -1) ERRNOR (EIO, NULL);
  591. extfs_info = g_new (struct pseudofile, 1);
  592. extfs_info->archive = archive;
  593. extfs_info->entry = entry;
  594. extfs_info->has_changed = do_create;
  595. extfs_info->local_handle = local_handle;
  596. /* i.e. we had no open files and now we have one */
  597. vfs_rmstamp (&vfs_extfs_ops, (vfsid) archive, 1);
  598. archive->fd_usage++;
  599. return extfs_info;
  600. }
  601. static int extfs_read (void *data, char *buffer, int count)
  602. {
  603. struct pseudofile *file = (struct pseudofile *)data;
  604. return read (file->local_handle, buffer, count);
  605. }
  606. static int extfs_close (void *data)
  607. {
  608. struct pseudofile *file;
  609. int errno_code = 0;
  610. file = (struct pseudofile *)data;
  611. close (file->local_handle);
  612. /* Commit the file if it has changed */
  613. if (file->has_changed){
  614. struct archive *archive;
  615. char *archive_name, *file_name;
  616. char *cmd;
  617. char *mc_extfsdir;
  618. char *p;
  619. archive = file->archive;
  620. archive_name = name_quote (get_archive_name (archive), 0);
  621. p = get_path_from_entry (file->entry);
  622. file_name = name_quote (p, 0);
  623. g_free (p);
  624. mc_extfsdir = concat_dir_and_file (mc_home, "extfs/");
  625. cmd = g_strconcat (mc_extfsdir,
  626. extfs_prefixes [archive->fstype],
  627. " copyin ", archive_name, " ",
  628. file_name, " ",
  629. file->entry->inode->local_filename, NULL);
  630. g_free (archive_name);
  631. g_free (file_name);
  632. g_free (mc_extfsdir);
  633. if (my_system (EXECUTE_AS_SHELL | EXECUTE_SETUID | EXECUTE_WAIT, shell, cmd))
  634. errno_code = EIO;
  635. g_free (cmd);
  636. {
  637. struct stat file_status;
  638. if (stat(file->entry->inode->local_filename,&file_status) != 0)
  639. errno_code = EIO;
  640. else
  641. file->entry->inode->size = file_status.st_size;
  642. }
  643. file->entry->inode->mtime = time (NULL);
  644. }
  645. file->archive->fd_usage--;
  646. if (!file->archive->fd_usage) {
  647. struct vfs_stamping *parent;
  648. vfs *v;
  649. if (!file->archive->name || !*file->archive->name || (v = vfs_type (file->archive->name)) == &vfs_local_ops) {
  650. parent = NULL;
  651. } else {
  652. parent = g_new (struct vfs_stamping, 1);
  653. parent->v = v;
  654. parent->next = 0;
  655. parent->id = (*v->getid) (v, file->archive->name, &(parent->parent));
  656. }
  657. vfs_add_noncurrent_stamps (&vfs_extfs_ops, (vfsid) (file->archive), parent);
  658. vfs_rm_parents (parent);
  659. }
  660. g_free (data);
  661. if (errno_code) ERRNOR (EIO, -1);
  662. return 0;
  663. }
  664. #define RECORDSIZE 512
  665. static char *get_path (char *inname, struct archive **archive, int is_dir,
  666. int do_not_open)
  667. {
  668. char *buf = g_strdup (inname);
  669. char *res = get_path_mangle( buf, archive, is_dir, do_not_open );
  670. char *res2 = NULL;
  671. if (res)
  672. res2 = g_strdup(res);
  673. g_free(buf);
  674. return res2;
  675. }
  676. static struct entry*
  677. __find_entry (struct entry *dir, char *name,
  678. struct loop_protect *list, int make_dirs, int make_file)
  679. {
  680. struct entry *pent, *pdir;
  681. char *p, *q, *name_end;
  682. char c;
  683. if (*name == '/') { /* Handle absolute paths */
  684. name++;
  685. dir = dir->inode->archive->root_entry;
  686. }
  687. pent = dir;
  688. p = name;
  689. name_end = name + strlen (name);
  690. q = strchr (p, '/');
  691. c = '/';
  692. if (!q)
  693. q = strchr (p, 0);
  694. for (; pent != NULL && c && *p; ){
  695. c = *q;
  696. *q = 0;
  697. if (strcmp (p, ".")){
  698. if (!strcmp (p, ".."))
  699. pent = pent->dir;
  700. else {
  701. if ((pent = __resolve_symlinks (pent, list))==NULL){
  702. *q = c;
  703. return NULL;
  704. }
  705. if (!S_ISDIR (pent->inode->mode)){
  706. *q = c;
  707. notadir = 1;
  708. return NULL;
  709. }
  710. pdir = pent;
  711. for (pent = pent->inode->first_in_subdir; pent; pent = pent->next_in_dir)
  712. /* Hack: I keep the original semanthic unless
  713. q+1 would break in the strchr */
  714. if (!strcmp (pent->name, p)){
  715. if (q + 1 > name_end){
  716. *q = c;
  717. notadir = !S_ISDIR (pent->inode->mode);
  718. return pent;
  719. }
  720. break;
  721. }
  722. /* When we load archive, we create automagically
  723. * non-existant directories
  724. */
  725. if (pent == NULL && make_dirs) {
  726. pent = generate_entry (dir->inode->archive, p, pdir, S_IFDIR | 0777);
  727. }
  728. if (pent == NULL && make_file) {
  729. pent = generate_entry (dir->inode->archive, p, pdir, 0777);
  730. }
  731. }
  732. }
  733. /* Next iteration */
  734. *q = c;
  735. p = q + 1;
  736. q = strchr (p, '/');
  737. if (!q)
  738. q = strchr (p, 0);
  739. }
  740. if (pent == NULL)
  741. my_errno = ENOENT;
  742. return pent;
  743. }
  744. static struct entry *find_entry (struct entry *dir, char *name, int make_dirs, int make_file)
  745. {
  746. struct entry *res;
  747. errloop = 0;
  748. notadir = 0;
  749. res = __find_entry (dir, name, NULL, make_dirs, make_file);
  750. if (res == NULL) {
  751. if (errloop)
  752. my_errno = ELOOP;
  753. else if (notadir)
  754. my_errno = ENOTDIR;
  755. }
  756. return res;
  757. }
  758. static int s_errno (vfs *me)
  759. {
  760. return my_errno;
  761. }
  762. static void * s_opendir (vfs *me, char *dirname)
  763. {
  764. struct archive *archive;
  765. char *q;
  766. struct entry *entry;
  767. struct entry **info;
  768. if ((q = get_path_mangle (dirname, &archive, 1, 0)) == NULL)
  769. return NULL;
  770. entry = find_entry (archive->root_entry, q, 0, 0);
  771. if (entry == NULL)
  772. return NULL;
  773. if ((entry = my_resolve_symlinks (entry)) == NULL)
  774. return NULL;
  775. if (!S_ISDIR (entry->inode->mode)) ERRNOR (ENOTDIR, NULL);
  776. info = g_new (struct entry *, 2);
  777. info[0] = entry->inode->first_in_subdir;
  778. info[1] = entry->inode->first_in_subdir;
  779. return info;
  780. }
  781. static void * s_readdir (void *data)
  782. {
  783. static struct {
  784. struct dirent dir;
  785. #ifdef NEED_EXTRA_DIRENT_BUFFER
  786. char extra_buffer [MC_MAXPATHLEN];
  787. #endif
  788. } dir;
  789. struct entry **info = (struct entry **) data;
  790. if (!*info)
  791. return NULL;
  792. strcpy (&(dir.dir.d_name [0]), (*info)->name);
  793. #ifndef DIRENT_LENGTH_COMPUTED
  794. dir.d_namlen = strlen (dir.dir.d_name);
  795. #endif
  796. *info = (*info)->next_in_dir;
  797. return (void *)&dir;
  798. }
  799. static int s_telldir (void *data)
  800. {
  801. struct entry **info = (struct entry **) data;
  802. struct entry *cur;
  803. int num = 0;
  804. cur = info[1];
  805. while (cur!=NULL) {
  806. if (cur == info[0]) return num;
  807. num++;
  808. cur = cur->next_in_dir;
  809. }
  810. return -1;
  811. }
  812. static void s_seekdir (void *data, int offset)
  813. {
  814. struct entry **info = (struct entry **) data;
  815. int i;
  816. info[0] = info[1];
  817. for (i=0; i<offset; i++)
  818. s_readdir( data );
  819. }
  820. static int s_closedir (void *data)
  821. {
  822. g_free (data);
  823. return 0;
  824. }
  825. static void stat_move( struct stat *buf, struct inode *inode )
  826. {
  827. buf->st_dev = inode->dev;
  828. buf->st_ino = inode->inode;
  829. buf->st_mode = inode->mode;
  830. buf->st_nlink = inode->nlink;
  831. buf->st_uid = inode->uid;
  832. buf->st_gid = inode->gid;
  833. #ifdef HAVE_ST_RDEV
  834. buf->st_rdev = inode->rdev;
  835. #endif
  836. buf->st_size = inode->size;
  837. #ifdef HAVE_ST_BLKSIZE
  838. buf->st_blksize = RECORDSIZE;
  839. #endif
  840. #ifdef HAVE_ST_BLOCKS
  841. buf->st_blocks = (inode->size + RECORDSIZE - 1) / RECORDSIZE;
  842. #endif
  843. buf->st_atime = inode->atime;
  844. buf->st_mtime = inode->mtime;
  845. buf->st_ctime = inode->ctime;
  846. }
  847. static int s_internal_stat (char *path, struct stat *buf, int resolve)
  848. {
  849. struct archive *archive;
  850. char *q;
  851. struct entry *entry;
  852. struct inode *inode;
  853. if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
  854. return -1;
  855. entry = find_entry (archive->root_entry, q, 0, 0);
  856. if (entry == NULL)
  857. return -1;
  858. if (resolve && (entry = my_resolve_symlinks (entry)) == NULL)
  859. return -1;
  860. inode = entry->inode;
  861. stat_move( buf, inode );
  862. return 0;
  863. }
  864. static int s_stat (vfs *me, char *path, struct stat *buf)
  865. {
  866. return s_internal_stat (path, buf, 1);
  867. }
  868. static int s_lstat (vfs *me, char *path, struct stat *buf)
  869. {
  870. return s_internal_stat (path, buf, 0);
  871. }
  872. static int s_fstat (void *data, struct stat *buf)
  873. {
  874. struct pseudofile *file = (struct pseudofile *)data;
  875. struct inode *inode;
  876. inode = file->entry->inode;
  877. stat_move( buf, inode );
  878. return 0;
  879. }
  880. static int s_readlink (vfs *me, char *path, char *buf, int size)
  881. {
  882. struct archive *archive;
  883. char *q;
  884. int i;
  885. struct entry *entry;
  886. if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
  887. return -1;
  888. entry = find_entry (archive->root_entry, q, 0, 0);
  889. if (entry == NULL)
  890. return -1;
  891. if (!S_ISLNK (entry->inode->mode)) ERRNOR (EINVAL, -1);
  892. if (size > (i = strlen (entry->inode->linkname))) {
  893. size = i;
  894. }
  895. strncpy (buf, entry->inode->linkname, i);
  896. return i;
  897. }
  898. static int extfs_chmod (vfs *me, char *path, int mode)
  899. {
  900. return 0;
  901. }
  902. static int extfs_write (void *data, char *buf, int nbyte)
  903. {
  904. struct pseudofile *file = (struct pseudofile *)data;
  905. file->has_changed = 1;
  906. return write (file->local_handle, buf, nbyte);
  907. }
  908. static int extfs_unlink (vfs *me, char *file)
  909. {
  910. struct archive *archive;
  911. char *q;
  912. char *mc_extfsdir;
  913. struct entry *entry;
  914. char *cmd;
  915. char *archive_name, *p;
  916. if ((q = get_path_mangle (file, &archive, 0, 0)) == NULL)
  917. return -1;
  918. entry = find_entry (archive->root_entry, q, 0, 0);
  919. if (entry == NULL)
  920. return -1;
  921. if ((entry = my_resolve_symlinks (entry)) == NULL)
  922. return -1;
  923. if (S_ISDIR (entry->inode->mode)) ERRNOR (EISDIR, -1);
  924. p = get_path_from_entry (entry);
  925. q = name_quote (p, 0);
  926. g_free (p);
  927. archive_name = name_quote (get_archive_name (archive), 0);
  928. mc_extfsdir = concat_dir_and_file (mc_home, "extfs/");
  929. cmd = g_strconcat (mc_extfsdir, extfs_prefixes [archive->fstype],
  930. " rm ", archive_name, " ", q, NULL);
  931. g_free (q);
  932. g_free (mc_extfsdir);
  933. g_free (archive_name);
  934. if (my_system (EXECUTE_AS_SHELL | EXECUTE_SETUID | EXECUTE_WAIT, shell, cmd)){
  935. g_free (cmd);
  936. my_errno = EIO;
  937. return -1;
  938. }
  939. g_free (cmd);
  940. remove_entry (entry);
  941. return 0;
  942. }
  943. static int extfs_mkdir (vfs *me, char *path, mode_t mode)
  944. {
  945. struct archive *archive;
  946. char *q;
  947. char *mc_extfsdir;
  948. struct entry *entry;
  949. char *cmd;
  950. char *archive_name, *p;
  951. if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
  952. return -1;
  953. entry = find_entry (archive->root_entry, q, 0, 0);
  954. if (entry != NULL) ERRNOR (EEXIST, -1);
  955. entry = find_entry (archive->root_entry, q, 1, 0);
  956. if (entry == NULL)
  957. return -1;
  958. if ((entry = my_resolve_symlinks (entry)) == NULL)
  959. return -1;
  960. if (!S_ISDIR (entry->inode->mode)) ERRNOR (ENOTDIR, -1);
  961. p = get_path_from_entry (entry);
  962. q = name_quote (p, 0);
  963. g_free (p);
  964. archive_name = name_quote (get_archive_name (archive), 0);
  965. mc_extfsdir = concat_dir_and_file (mc_home, "extfs/");
  966. cmd = g_strconcat (mc_extfsdir, extfs_prefixes [archive->fstype],
  967. " mkdir ", archive_name, " ", q, NULL);
  968. g_free (q);
  969. g_free (mc_extfsdir);
  970. g_free (archive_name);
  971. if (my_system (EXECUTE_AS_SHELL | EXECUTE_SETUID | EXECUTE_WAIT, shell, cmd)){
  972. g_free (cmd);
  973. my_errno = EIO;
  974. remove_entry (entry);
  975. return -1;
  976. }
  977. g_free (cmd);
  978. return 0;
  979. }
  980. static int extfs_rmdir (vfs *me, char *path)
  981. {
  982. struct archive *archive;
  983. char *q;
  984. char *mc_extfsdir;
  985. struct entry *entry;
  986. char *cmd;
  987. char *archive_name, *p;
  988. if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
  989. return -1;
  990. entry = find_entry (archive->root_entry, q, 0, 0);
  991. if (entry == NULL)
  992. return -1;
  993. if ((entry = my_resolve_symlinks (entry)) == NULL)
  994. return -1;
  995. if (!S_ISDIR (entry->inode->mode)) ERRNOR (ENOTDIR, -1);
  996. p = get_path_from_entry (entry);
  997. q = name_quote (p, 0);
  998. g_free (p);
  999. archive_name = name_quote (get_archive_name (archive), 0);
  1000. mc_extfsdir = concat_dir_and_file (mc_home, "extfs/");
  1001. cmd = g_strconcat (mc_extfsdir, extfs_prefixes [archive->fstype],
  1002. " rmdir ", archive_name, " ", q, NULL);
  1003. g_free (q);
  1004. g_free (mc_extfsdir);
  1005. g_free (archive_name);
  1006. if (my_system (EXECUTE_AS_SHELL | EXECUTE_SETUID | EXECUTE_WAIT, shell, cmd)){
  1007. g_free (cmd);
  1008. my_errno = EIO;
  1009. return -1;
  1010. }
  1011. g_free (cmd);
  1012. remove_entry (entry);
  1013. return 0;
  1014. }
  1015. static int extfs_chdir (vfs *me, char *path)
  1016. {
  1017. struct archive *archive;
  1018. char *q;
  1019. struct entry *entry;
  1020. my_errno = ENOTDIR;
  1021. if ((q = get_path_mangle (path, &archive, 1, 0)) == NULL)
  1022. return -1;
  1023. entry = find_entry (archive->root_entry, q, 0, 0);
  1024. if (!entry)
  1025. return -1;
  1026. entry = my_resolve_symlinks (entry);
  1027. if ((!entry) || (!S_ISDIR (entry->inode->mode)))
  1028. return -1;
  1029. entry->inode->archive->current_dir = entry;
  1030. my_errno = 0;
  1031. return 0;
  1032. }
  1033. static int extfs_lseek (void *data, off_t offset, int whence)
  1034. {
  1035. struct pseudofile *file = (struct pseudofile *) data;
  1036. return lseek (file->local_handle, offset, whence);
  1037. }
  1038. static vfsid extfs_getid (vfs *me, char *path, struct vfs_stamping **parent)
  1039. {
  1040. struct archive *archive;
  1041. vfs *v;
  1042. vfsid id;
  1043. struct vfs_stamping *par;
  1044. char *p;
  1045. *parent = NULL;
  1046. if (!(p = get_path (path, &archive, 1, 1)))
  1047. return (vfsid) -1;
  1048. g_free(p);
  1049. if (archive->name){
  1050. v = vfs_type (archive->name);
  1051. id = (*v->getid) (v, archive->name, &par);
  1052. if (id != (vfsid)-1) {
  1053. *parent = g_new (struct vfs_stamping, 1);
  1054. (*parent)->v = v;
  1055. (*parent)->id = id;
  1056. (*parent)->parent = par;
  1057. (*parent)->next = NULL;
  1058. }
  1059. }
  1060. return (vfsid) archive;
  1061. }
  1062. static int extfs_nothingisopen (vfsid id)
  1063. {
  1064. if (((struct archive *)id)->fd_usage <= 0)
  1065. return 1;
  1066. return 0;
  1067. }
  1068. static void remove_entry (struct entry *e)
  1069. {
  1070. int i = --(e->inode->nlink);
  1071. struct entry *pe, *ent, *prev;
  1072. if (S_ISDIR (e->inode->mode) && e->inode->first_in_subdir != NULL) {
  1073. struct entry *f = e->inode->first_in_subdir;
  1074. e->inode->first_in_subdir = NULL;
  1075. remove_entry (f);
  1076. }
  1077. pe = e->dir;
  1078. if (e == pe->inode->first_in_subdir)
  1079. pe->inode->first_in_subdir = e->next_in_dir;
  1080. prev = NULL;
  1081. for (ent = pe->inode->first_in_subdir; ent && ent->next_in_dir;
  1082. ent = ent->next_in_dir)
  1083. if (e == ent->next_in_dir) {
  1084. prev = ent;
  1085. break;
  1086. }
  1087. if (prev)
  1088. prev->next_in_dir = e->next_in_dir;
  1089. if (e == pe->inode->last_in_subdir)
  1090. pe->inode->last_in_subdir = prev;
  1091. if (i <= 0) {
  1092. if (e->inode->local_filename != NULL) {
  1093. unlink (e->inode->local_filename);
  1094. free (e->inode->local_filename);
  1095. }
  1096. if (e->inode->linkname != NULL)
  1097. g_free (e->inode->linkname);
  1098. g_free (e->inode);
  1099. }
  1100. g_free (e->name);
  1101. g_free (e);
  1102. }
  1103. static void free_entry (struct entry *e)
  1104. {
  1105. int i = --(e->inode->nlink);
  1106. if (S_ISDIR (e->inode->mode) && e->inode->first_in_subdir != NULL) {
  1107. struct entry *f = e->inode->first_in_subdir;
  1108. e->inode->first_in_subdir = NULL;
  1109. free_entry (f);
  1110. }
  1111. if (i <= 0) {
  1112. if (e->inode->local_filename != NULL) {
  1113. unlink (e->inode->local_filename);
  1114. free (e->inode->local_filename);
  1115. }
  1116. if (e->inode->linkname != NULL)
  1117. g_free (e->inode->linkname);
  1118. g_free (e->inode);
  1119. }
  1120. if (e->next_in_dir != NULL)
  1121. free_entry (e->next_in_dir);
  1122. g_free (e->name);
  1123. g_free (e);
  1124. }
  1125. static void extfs_free (vfsid id)
  1126. {
  1127. struct archive *parc;
  1128. struct archive *archive = (struct archive *)id;
  1129. free_entry (archive->root_entry);
  1130. if (archive == first_archive) {
  1131. first_archive = archive->next;
  1132. } else {
  1133. for (parc = first_archive; parc != NULL; parc = parc->next)
  1134. if (parc->next == archive)
  1135. break;
  1136. if (parc != NULL)
  1137. parc->next = archive->next;
  1138. }
  1139. free_archive (archive);
  1140. }
  1141. static char *extfs_getlocalcopy (vfs *me, char *path)
  1142. {
  1143. struct pseudofile *fp =
  1144. (struct pseudofile *) extfs_open (me, path, O_RDONLY, 0);
  1145. char *p;
  1146. if (fp == NULL)
  1147. return NULL;
  1148. if (fp->entry->inode->local_filename == NULL) {
  1149. extfs_close ((void *) fp);
  1150. return NULL;
  1151. }
  1152. p = g_strdup (fp->entry->inode->local_filename);
  1153. fp->archive->fd_usage++;
  1154. extfs_close ((void *) fp);
  1155. return p;
  1156. }
  1157. static int extfs_ungetlocalcopy (vfs *me, char *path, char *local, int has_changed)
  1158. {
  1159. struct pseudofile *fp =
  1160. (struct pseudofile *) extfs_open (me, path, O_WRONLY, 0);
  1161. if (fp == NULL)
  1162. return 0;
  1163. if (!strcmp (fp->entry->inode->local_filename, local)) {
  1164. fp->archive->fd_usage--;
  1165. extfs_close ((void *) fp);
  1166. return 0;
  1167. } else {
  1168. /* Should not happen */
  1169. extfs_close ((void *) fp);
  1170. return mc_def_ungetlocalcopy (me, path, local, has_changed);
  1171. }
  1172. }
  1173. #include "../src/profile.h"
  1174. static int extfs_init (vfs *me)
  1175. {
  1176. FILE *cfg;
  1177. char *mc_extfsini;
  1178. mc_extfsini = concat_dir_and_file (mc_home, "extfs/extfs.ini");
  1179. cfg = fopen (mc_extfsini, "r");
  1180. if (!cfg) {
  1181. fprintf(stderr, "Warning: file %s not found\n", mc_extfsini);
  1182. g_free (mc_extfsini);
  1183. return 0;
  1184. }
  1185. extfs_no = 0;
  1186. while ( extfs_no < MAXEXTFS ) {
  1187. char key[256];
  1188. char *c;
  1189. if (!fgets( key, sizeof (key)-1, cfg ))
  1190. break;
  1191. /* Handle those with a trailing ':', those flag that the
  1192. * file system does not require an archive to work
  1193. */
  1194. if (*key == '[') {
  1195. /* We may not use vfs_die() message or message_1s or similar,
  1196. * UI is not initialized at this time and message would not
  1197. * appear on screen. */
  1198. fprintf(stderr, "Warning: You need to update your %s file.\n",
  1199. mc_extfsini);
  1200. fclose(cfg);
  1201. g_free (mc_extfsini);
  1202. return 0;
  1203. }
  1204. if (*key == '#')
  1205. continue;
  1206. if ((c = strchr (key, '\n'))){
  1207. *c = 0;
  1208. c = &key [strlen (key) - 1];
  1209. } else {
  1210. c = key;
  1211. }
  1212. extfs_need_archive [extfs_no] = !(*c == ':');
  1213. if (*c == ':')
  1214. *c = 0;
  1215. if (!(*key))
  1216. continue;
  1217. extfs_prefixes [extfs_no] = g_strdup (key);
  1218. extfs_no++;
  1219. }
  1220. fclose(cfg);
  1221. g_free (mc_extfsini);
  1222. return 1;
  1223. }
  1224. /* Do NOT use me argument in this function */
  1225. static int extfs_which (vfs *me, char *path)
  1226. {
  1227. int i;
  1228. for (i = 0; i < extfs_no; i++)
  1229. if (!strcmp (path, extfs_prefixes [i]))
  1230. return i;
  1231. return -1;
  1232. }
  1233. static void extfs_done (vfs *me)
  1234. {
  1235. int i;
  1236. for (i = 0; i < extfs_no; i++ )
  1237. g_free (extfs_prefixes [i]);
  1238. extfs_no = 0;
  1239. }
  1240. static int extfs_setctl (vfs *me, char *path, int ctlop, char *arg)
  1241. {
  1242. if (ctlop == MCCTL_EXTFS_RUN) {
  1243. extfs_run (path);
  1244. return 1;
  1245. }
  1246. return 0;
  1247. }
  1248. vfs vfs_extfs_ops = {
  1249. NULL, /* This is place of next pointer */
  1250. "extfs",
  1251. F_EXEC, /* flags */
  1252. NULL, /* prefix */
  1253. NULL, /* data */
  1254. 0, /* errno */
  1255. extfs_init,
  1256. extfs_done,
  1257. extfs_fill_names,
  1258. extfs_which,
  1259. extfs_open,
  1260. extfs_close,
  1261. extfs_read,
  1262. extfs_write,
  1263. s_opendir,
  1264. s_readdir,
  1265. s_closedir,
  1266. s_telldir,
  1267. s_seekdir,
  1268. s_stat,
  1269. s_lstat,
  1270. s_fstat,
  1271. extfs_chmod, /* chmod ... strange, returns success? */
  1272. NULL,
  1273. NULL,
  1274. s_readlink,
  1275. NULL, /* symlink */
  1276. NULL,
  1277. extfs_unlink,
  1278. NULL,
  1279. extfs_chdir,
  1280. s_errno,
  1281. extfs_lseek,
  1282. NULL,
  1283. extfs_getid,
  1284. extfs_nothingisopen,
  1285. extfs_free,
  1286. extfs_getlocalcopy,
  1287. extfs_ungetlocalcopy,
  1288. extfs_mkdir, /* mkdir */
  1289. extfs_rmdir,
  1290. NULL,
  1291. extfs_setctl
  1292. MMAPNULL
  1293. };