extfs.c 36 KB

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