PageRenderTime 88ms CodeModel.GetById 41ms RepoModel.GetById 1ms app.codeStats 1ms

/core/10.5/fusefs/fuse_vnops.c

http://macfuse.googlecode.com/
C | 3792 lines | 2329 code | 703 blank | 760 comment | 498 complexity | 9ac337dac621a0b2874afb66ce10d9ae MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, GPL-2.0
  1. /*
  2. * Copyright (C) 2006-2008 Google. All Rights Reserved.
  3. * Amit Singh <singh@>
  4. */
  5. #include <sys/param.h>
  6. #include <kern/assert.h>
  7. #include <libkern/libkern.h>
  8. #include <libkern/OSMalloc.h>
  9. #include <libkern/locks.h>
  10. #include <mach/mach_types.h>
  11. #include <sys/dirent.h>
  12. #include <sys/disk.h>
  13. #include <sys/errno.h>
  14. #include <sys/fcntl.h>
  15. #include <sys/kernel_types.h>
  16. #include <sys/mount.h>
  17. #include <sys/proc.h>
  18. #include <sys/stat.h>
  19. #include <sys/ubc.h>
  20. #include <sys/unistd.h>
  21. #include <sys/vnode.h>
  22. #include <sys/vnode_if.h>
  23. #include <sys/xattr.h>
  24. #include <sys/buf.h>
  25. #include <sys/namei.h>
  26. #include <sys/mman.h>
  27. #include <vfs/vfs_support.h>
  28. #include "fuse.h"
  29. #include "fuse_file.h"
  30. #include "fuse_internal.h"
  31. #include <fuse_ioctl.h>
  32. #include "fuse_ipc.h"
  33. #include "fuse_kludges.h"
  34. #include "fuse_knote.h"
  35. #include "fuse_locking.h"
  36. #include "fuse_node.h"
  37. #include "fuse_nodehash.h"
  38. #include <fuse_param.h>
  39. #include "fuse_sysctl.h"
  40. #include "fuse_vnops.h"
  41. /*
  42. struct vnop_access_args {
  43. struct vnodeop_desc *a_desc;
  44. vnode_t a_vp;
  45. int a_action;
  46. vfs_context_t a_context;
  47. };
  48. */
  49. FUSE_VNOP_EXPORT
  50. int
  51. fuse_vnop_access(struct vnop_access_args *ap)
  52. {
  53. vnode_t vp = ap->a_vp;
  54. int action = ap->a_action;
  55. vfs_context_t context = ap->a_context;
  56. struct fuse_access_param facp;
  57. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  58. struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
  59. fuse_trace_printf_vnop();
  60. if (fuse_isdeadfs(vp)) {
  61. if (vnode_isvroot(vp)) {
  62. return 0;
  63. } else {
  64. return EBADF;
  65. }
  66. }
  67. if (!(data->dataflags & FSESS_INITED)) {
  68. if (vnode_isvroot(vp)) {
  69. if (fuse_vfs_context_issuser(context) ||
  70. (fuse_match_cred(data->daemoncred,
  71. vfs_context_ucred(context)) == 0)) {
  72. return 0;
  73. }
  74. }
  75. return EBADF;
  76. }
  77. if (vnode_islnk(vp)) {
  78. return 0;
  79. }
  80. bzero(&facp, sizeof(facp));
  81. if (fvdat->flag & FN_ACCESS_NOOP) {
  82. fvdat->flag &= ~FN_ACCESS_NOOP;
  83. } else {
  84. facp.facc_flags |= FACCESS_DO_ACCESS;
  85. }
  86. facp.facc_flags |= FACCESS_FROM_VNOP;
  87. return fuse_internal_access(vp, action, context, &facp);
  88. }
  89. /*
  90. struct vnop_blktooff_args {
  91. struct vnodeop_desc *a_desc;
  92. vnode_t a_vp;
  93. daddr64_t a_lblkno;
  94. off_t *a_offset;
  95. };
  96. */
  97. FUSE_VNOP_EXPORT
  98. int
  99. fuse_vnop_blktooff(struct vnop_blktooff_args *ap)
  100. {
  101. vnode_t vp = ap->a_vp;
  102. daddr64_t lblkno = ap->a_lblkno;
  103. off_t *offsetPtr = ap->a_offset;
  104. struct fuse_data *data;
  105. fuse_trace_printf_vnop();
  106. if (fuse_isdeadfs(vp)) {
  107. return EIO;
  108. }
  109. data = fuse_get_mpdata(vnode_mount(vp));
  110. *offsetPtr = lblkno * (off_t)(data->blocksize);
  111. return 0;
  112. }
  113. /*
  114. struct vnop_blockmap_args {
  115. struct vnodeop_desc *a_desc;
  116. vnode_t a_vp;
  117. off_t a_foffset;
  118. size_t a_size;
  119. daddr64_t *a_bpn;
  120. size_t *a_run;
  121. void *a_poff;
  122. int a_flags;
  123. vfs_context_t a_context;
  124. };
  125. */
  126. FUSE_VNOP_EXPORT
  127. int
  128. fuse_vnop_blockmap(struct vnop_blockmap_args *ap)
  129. {
  130. vnode_t vp = ap->a_vp;
  131. off_t foffset = ap->a_foffset;
  132. size_t size = ap->a_size;
  133. daddr64_t *bpnPtr = ap->a_bpn;
  134. size_t *runPtr = ap->a_run;
  135. int *poffPtr = (int *)ap->a_poff;
  136. /* Ignoring flags and context */
  137. struct fuse_vnode_data *fvdat;
  138. struct fuse_data *data;
  139. off_t contiguousPhysicalBytes;
  140. fuse_trace_printf_vnop();
  141. if (fuse_isdeadfs(vp)) {
  142. return EIO;
  143. }
  144. if (vnode_isdir(vp)) {
  145. return ENOTSUP;
  146. }
  147. if (ap->a_bpn == NULL) {
  148. return 0;
  149. }
  150. fvdat = VTOFUD(vp);
  151. data = fuse_get_mpdata(vnode_mount(vp));
  152. /*
  153. * We could assert that:
  154. *
  155. * (foffset % data->blocksize) == 0
  156. * (foffset < fvdat->filesize)
  157. * (size % data->blocksize) == 0)
  158. */
  159. *bpnPtr = foffset / data->blocksize;
  160. contiguousPhysicalBytes = \
  161. fvdat->filesize - (off_t)(*bpnPtr * data->blocksize);
  162. /* contiguousPhysicalBytes cannot really be negative (could assert) */
  163. if (contiguousPhysicalBytes > (off_t)size) {
  164. contiguousPhysicalBytes = (off_t)size;
  165. }
  166. if (runPtr != NULL) {
  167. *runPtr = (size_t)contiguousPhysicalBytes;
  168. }
  169. if (poffPtr != NULL) {
  170. *poffPtr = 0;
  171. }
  172. return 0;
  173. }
  174. /*
  175. struct vnop_close_args {
  176. struct vnodeop_desc *a_desc;
  177. vnode_t a_vp;
  178. int a_fflag;
  179. vfs_context_t a_context;
  180. };
  181. */
  182. FUSE_VNOP_EXPORT
  183. int
  184. fuse_vnop_close(struct vnop_close_args *ap)
  185. {
  186. vnode_t vp = ap->a_vp;
  187. int fflag = ap->a_fflag;
  188. vfs_context_t context = ap->a_context;
  189. int err = 0;
  190. int isdir = (vnode_isdir(vp)) ? 1 : 0;
  191. fufh_type_t fufh_type;
  192. struct fuse_data *data;
  193. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  194. struct fuse_filehandle *fufh = NULL;
  195. fuse_trace_printf_vnop();
  196. if (fuse_isdeadfs(vp)) {
  197. return 0;
  198. }
  199. /* vclean() calls VNOP_CLOSE with fflag set to IO_NDELAY. */
  200. if (fflag == IO_NDELAY) {
  201. return 0;
  202. }
  203. if (isdir) {
  204. fufh_type = FUFH_RDONLY;
  205. } else {
  206. fufh_type = fuse_filehandle_xlate_from_fflags(fflag);
  207. }
  208. fufh = &(fvdat->fufh[fufh_type]);
  209. if (!FUFH_IS_VALID(fufh)) {
  210. IOLog("MacFUSE: fufh invalid in close [type=%d oc=%d vtype=%d cf=%d]\n",
  211. fufh_type, fufh->open_count, vnode_vtype(vp), fflag);
  212. return 0;
  213. }
  214. if (isdir) {
  215. goto skipdir;
  216. }
  217. /*
  218. * Enforce sync-on-close unless explicitly told not to.
  219. *
  220. * We do this to maintain correct semantics in the not so common case when
  221. * you create a file with O_RDWR but without write permissions--you /are/
  222. * supposed to be able to write to such a file given the descriptor you
  223. * you got from open()/create(). Therefore, if we don't finish all our
  224. * writing before we close this precious writable descriptor, we might
  225. * be doomed.
  226. */
  227. if (vnode_hasdirtyblks(vp) && !fuse_isnosynconclose(vp)) {
  228. (void)cluster_push(vp, IO_SYNC | IO_CLOSE);
  229. }
  230. data = fuse_get_mpdata(vnode_mount(vp));
  231. if (fuse_implemented(data, FSESS_NOIMPLBIT(FLUSH))) {
  232. struct fuse_dispatcher fdi;
  233. struct fuse_flush_in *ffi;
  234. fdisp_init(&fdi, sizeof(*ffi));
  235. fdisp_make_vp(&fdi, FUSE_FLUSH, vp, context);
  236. ffi = fdi.indata;
  237. ffi->fh = fufh->fh_id;
  238. ffi->unused = 0;
  239. ffi->padding = 0;
  240. ffi->lock_owner = 0;
  241. err = fdisp_wait_answ(&fdi);
  242. if (!err) {
  243. fuse_ticket_drop(fdi.tick);
  244. } else {
  245. if (err == ENOSYS) {
  246. fuse_clear_implemented(data, FSESS_NOIMPLBIT(FLUSH));
  247. err = 0;
  248. }
  249. }
  250. }
  251. skipdir:
  252. /* This must be done after we have flushed any pending I/O. */
  253. FUFH_USE_DEC(fufh);
  254. if (!FUFH_IS_VALID(fufh)) {
  255. (void)fuse_filehandle_put(vp, context, fufh_type, FUSE_OP_FOREGROUNDED);
  256. }
  257. return err;
  258. }
  259. /*
  260. struct vnop_create_args {
  261. struct vnodeop_desc *a_desc;
  262. vnode_t a_dvp;
  263. vnode_t *a_vpp;
  264. struct componentname *a_cnp;
  265. struct vnode_attr *a_vap;
  266. vfs_context_t a_context;
  267. };
  268. */
  269. FUSE_VNOP_EXPORT
  270. int
  271. fuse_vnop_create(struct vnop_create_args *ap)
  272. {
  273. vnode_t dvp = ap->a_dvp;
  274. vnode_t *vpp = ap->a_vpp;
  275. struct componentname *cnp = ap->a_cnp;
  276. struct vnode_attr *vap = ap->a_vap;
  277. vfs_context_t context = ap->a_context;
  278. struct fuse_open_in *foi;
  279. struct fuse_mknod_in fmni;
  280. struct fuse_entry_out *feo;
  281. struct fuse_dispatcher fdi;
  282. struct fuse_dispatcher *fdip = &fdi;
  283. int err;
  284. int gone_good_old = 0;
  285. struct fuse_data *data = NULL;
  286. mount_t mp = vnode_mount(dvp);
  287. uint64_t parent_nodeid = VTOFUD(dvp)->nodeid;
  288. mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode);
  289. fuse_trace_printf_vnop_novp();
  290. if (fuse_isdeadfs_fs(dvp)) {
  291. panic("MacFUSE: fuse_vnop_create(): called on a dead file system");
  292. }
  293. CHECK_BLANKET_DENIAL(dvp, context, EPERM);
  294. if (fuse_skip_apple_double_mp(mp, cnp->cn_nameptr, cnp->cn_namelen)) {
  295. return EPERM;
  296. }
  297. bzero(&fdi, sizeof(fdi));
  298. data = fuse_get_mpdata(mp);
  299. if (!fuse_implemented(data, FSESS_NOIMPLBIT(CREATE)) ||
  300. (vap->va_type != VREG)) {
  301. /* User-space file system does not implement CREATE */
  302. goto good_old;
  303. }
  304. fdisp_init(fdip, sizeof(*foi) + cnp->cn_namelen + 1);
  305. fdisp_make(fdip, FUSE_CREATE, vnode_mount(dvp), parent_nodeid, context);
  306. foi = fdip->indata;
  307. foi->mode = mode;
  308. /* XXX: We /always/ creat() like this. Wish we were on Linux. */
  309. foi->flags = O_CREAT | O_RDWR;
  310. memcpy((char *)fdip->indata + sizeof(*foi), cnp->cn_nameptr,
  311. cnp->cn_namelen);
  312. ((char *)fdip->indata)[sizeof(*foi) + cnp->cn_namelen] = '\0';
  313. err = fdisp_wait_answ(fdip);
  314. if (err == ENOSYS) {
  315. fuse_clear_implemented(data, FSESS_NOIMPLBIT(CREATE));
  316. fdip->tick = NULL;
  317. goto good_old;
  318. } else if (err) {
  319. goto undo;
  320. }
  321. goto bringup;
  322. good_old:
  323. gone_good_old = 1;
  324. fmni.mode = mode; /* fvdat->flags; */
  325. fmni.rdev = 0;
  326. fuse_internal_newentry_makerequest(vnode_mount(dvp), parent_nodeid, cnp,
  327. FUSE_MKNOD, &fmni, sizeof(fmni),
  328. fdip, context);
  329. err = fdisp_wait_answ(fdip);
  330. if (err) {
  331. goto undo;
  332. }
  333. bringup:
  334. feo = fdip->answ;
  335. if ((err = fuse_internal_checkentry(feo, VREG))) { // VBLK/VCHR not allowed
  336. fuse_ticket_drop(fdip->tick);
  337. goto undo;
  338. }
  339. err = FSNodeGetOrCreateFileVNodeByID(
  340. vpp, (gone_good_old) ? 0 : FN_CREATING,
  341. feo, mp, dvp, context, NULL /* oflags */);
  342. if (err) {
  343. if (gone_good_old) {
  344. fuse_internal_forget_send(mp, context, feo->nodeid, 1, fdip);
  345. } else {
  346. struct fuse_release_in *fri;
  347. uint64_t nodeid = feo->nodeid;
  348. uint64_t fh_id = ((struct fuse_open_out *)(feo + 1))->fh;
  349. fdisp_init(fdip, sizeof(*fri));
  350. fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, context);
  351. fri = fdip->indata;
  352. fri->fh = fh_id;
  353. fri->flags = OFLAGS(mode);
  354. fuse_insert_callback(fdip->tick, fuse_internal_forget_callback);
  355. fuse_insert_message(fdip->tick);
  356. }
  357. return err;
  358. }
  359. fdip->answ = gone_good_old ? NULL : feo + 1;
  360. if (!gone_good_old) {
  361. uint64_t x_fh_id = ((struct fuse_open_out *)(feo + 1))->fh;
  362. uint32_t x_open_flags = ((struct fuse_open_out *)(feo + 1))->open_flags;
  363. struct fuse_vnode_data *fvdat = VTOFUD(*vpp);
  364. struct fuse_filehandle *fufh = &(fvdat->fufh[FUFH_RDWR]);
  365. fufh->fh_id = x_fh_id;
  366. fufh->open_flags = x_open_flags;
  367. /*
  368. * We're stashing this to be picked up by open. Meanwhile, we set
  369. * the use count to 1 because that's what it is. The use count will
  370. * later transfer to the slot that this handle ends up falling in.
  371. */
  372. fufh->open_count = 1;
  373. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_current);
  374. }
  375. cache_purge_negatives(dvp);
  376. fuse_ticket_drop(fdip->tick);
  377. FUSE_KNOTE(dvp, NOTE_WRITE);
  378. return 0;
  379. undo:
  380. return err;
  381. }
  382. /*
  383. struct vnop_exchange_args {
  384. struct vnodeop_desc *a_desc;
  385. vnode_t a_fvp;
  386. vnode_t a_tvp;
  387. int a_options;
  388. vfs_context_t a_context;
  389. };
  390. */
  391. FUSE_VNOP_EXPORT
  392. int
  393. fuse_vnop_exchange(struct vnop_exchange_args *ap)
  394. {
  395. #if M_MACFUSE_ENABLE_EXCHANGE
  396. vnode_t fvp = ap->a_fvp;
  397. vnode_t tvp = ap->a_tvp;
  398. int options = ap->a_options;
  399. vfs_context_t context = ap->a_context;
  400. const char *fname = NULL;
  401. const char *tname = NULL;
  402. size_t flen = 0;
  403. size_t tlen = 0;
  404. struct fuse_data *data = fuse_get_mpdata(vnode_mount(fvp));
  405. int err = 0;
  406. fuse_trace_printf_vnop_novp();
  407. if (vnode_mount(fvp) != vnode_mount(tvp)) {
  408. return EXDEV;
  409. }
  410. /* We now know f and t are on the same volume. */
  411. if (!fuse_implemented(data, FSESS_NOIMPLBIT(EXCHANGE))) {
  412. return ENOTSUP;
  413. }
  414. if (fuse_isnovncache(fvp)) {
  415. return ENOTSUP;
  416. }
  417. if (fvp == tvp) {
  418. return EINVAL;
  419. }
  420. if (!vnode_isreg(fvp) || !vnode_isreg(tvp)) {
  421. return EINVAL;
  422. }
  423. if (fuse_isdeadfs_fs(fvp)) {
  424. panic("MacFUSE: fuse_vnop_exchange(): called on a dead file system");
  425. }
  426. fname = vnode_getname(fvp);
  427. if (!fname) {
  428. return EIO;
  429. }
  430. tname = vnode_getname(tvp);
  431. if (!tname) {
  432. vnode_putname(fname);
  433. return EIO;
  434. }
  435. flen = strlen(fname);
  436. tlen = strlen(tname);
  437. if ((flen > 2) && (*fname == '.') && (*(fname + 1) == '_')) {
  438. err = EINVAL;
  439. goto out;
  440. }
  441. if ((tlen > 2) && (*tname == '.') && (*(tname + 1) == '_')) {
  442. err = EINVAL;
  443. goto out;
  444. }
  445. err = fuse_internal_exchange(fvp, fname, flen, tvp, tname, tlen, options,
  446. context);
  447. if (err == ENOSYS) {
  448. fuse_clear_implemented(data, FSESS_NOIMPLBIT(EXCHANGE));
  449. err = ENOTSUP;
  450. }
  451. out:
  452. vnode_putname(fname);
  453. vnode_putname(tname);
  454. if (err == 0) {
  455. FUSE_KNOTE(fvp, NOTE_ATTRIB);
  456. FUSE_KNOTE(tvp, NOTE_ATTRIB);
  457. }
  458. return err;
  459. #else /* !M_MACFUSE_ENABLE_EXCHANGE */
  460. (void)ap;
  461. return ENOTSUP;
  462. #endif /* M_MACFUSE_ENABLE_EXCHANGE */
  463. }
  464. /*
  465. * Our vnop_fsync roughly corresponds to the FUSE_FSYNC method. The Linux
  466. * version of FUSE also has a FUSE_FLUSH method.
  467. *
  468. * On Linux, fsync() synchronizes a file's complete in-core state with that
  469. * on disk. The call is not supposed to return until the system has completed
  470. * that action or until an error is detected.
  471. *
  472. * Linux also has an fdatasync() call that is similar to fsync() but is not
  473. * required to update the metadata such as access time and modification time.
  474. */
  475. /*
  476. struct vnop_fsync_args {
  477. struct vnodeop_desc *a_desc;
  478. vnode_t a_vp;
  479. int a_waitfor;
  480. vfs_context_t a_context;
  481. };
  482. */
  483. FUSE_VNOP_EXPORT
  484. int
  485. fuse_vnop_fsync(struct vnop_fsync_args *ap)
  486. {
  487. vnode_t vp = ap->a_vp;
  488. int waitfor = ap->a_waitfor;
  489. vfs_context_t context = ap->a_context;
  490. struct fuse_dispatcher fdi;
  491. struct fuse_filehandle *fufh;
  492. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  493. int type, err = 0, tmp_err = 0;
  494. (void)waitfor;
  495. fuse_trace_printf_vnop();
  496. if (fuse_isdeadfs(vp)) {
  497. return 0;
  498. }
  499. cluster_push(vp, 0);
  500. /*
  501. * struct timeval tv;
  502. * int wait = (waitfor == MNT_WAIT)
  503. *
  504. * In another world, we could be doing something like:
  505. *
  506. * buf_flushdirtyblks(vp, wait, 0, (char *)"fuse_fsync");
  507. * microtime(&tv);
  508. * ...
  509. */
  510. /*
  511. * - UBC and vnode are in lock-step.
  512. * - Can call vnode_isinuse().
  513. * - Can call ubc_msync().
  514. */
  515. mount_t mp = vnode_mount(vp);
  516. if (!fuse_implemented(fuse_get_mpdata(mp), ((vnode_isdir(vp)) ?
  517. FSESS_NOIMPLBIT(FSYNCDIR) : FSESS_NOIMPLBIT(FSYNC)))) {
  518. err = ENOSYS;
  519. goto out;
  520. }
  521. fdisp_init(&fdi, 0);
  522. for (type = 0; type < FUFH_MAXTYPE; type++) {
  523. fufh = &(fvdat->fufh[type]);
  524. if (FUFH_IS_VALID(fufh)) {
  525. tmp_err = fuse_internal_fsync(vp, context, fufh, &fdi,
  526. FUSE_OP_FOREGROUNDED);
  527. if (tmp_err) {
  528. err = tmp_err;
  529. }
  530. }
  531. }
  532. out:
  533. if ((err == ENOSYS) && !fuse_isnosyncwrites_mp(mp)) {
  534. err = 0;
  535. }
  536. return err;
  537. }
  538. /*
  539. struct vnop_getattr_args {
  540. struct vnodeop_desc *a_desc;
  541. vnode_t a_vp;
  542. struct vnode_attr *a_vap;
  543. vfs_context_t a_context;
  544. };
  545. */
  546. FUSE_VNOP_EXPORT
  547. int
  548. fuse_vnop_getattr(struct vnop_getattr_args *ap)
  549. {
  550. vnode_t vp = ap->a_vp;
  551. struct vnode_attr *vap = ap->a_vap;
  552. vfs_context_t context = ap->a_context;
  553. int err = 0;
  554. int dataflags;
  555. struct timespec uptsp;
  556. struct fuse_dispatcher fdi;
  557. struct fuse_data *data;
  558. data = fuse_get_mpdata(vnode_mount(vp));
  559. fuse_trace_printf_vnop();
  560. if (fuse_isdeadfs(vp)) {
  561. if (vnode_isvroot(vp)) {
  562. goto fake;
  563. } else {
  564. return EBADF;
  565. }
  566. }
  567. if (!vnode_isvroot(vp) || !fuse_vfs_context_issuser(context)) {
  568. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  569. }
  570. dataflags = data->dataflags;
  571. /* Note that we are not bailing out on a dead file system just yet. */
  572. /* look for cached attributes */
  573. nanouptime(&uptsp);
  574. if (fuse_timespec_cmp(&uptsp, &VTOFUD(vp)->attr_valid, <=)) {
  575. if (vap != VTOVA(vp)) {
  576. fuse_internal_attr_loadvap(vp, vap, context);
  577. }
  578. return 0;
  579. }
  580. if (!(dataflags & FSESS_INITED)) {
  581. if (!vnode_isvroot(vp)) {
  582. fdata_set_dead(data);
  583. err = ENOTCONN;
  584. return err;
  585. } else {
  586. goto fake;
  587. }
  588. }
  589. if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, context))) {
  590. if ((err == ENOTCONN) && vnode_isvroot(vp)) {
  591. /* see comment at similar place in fuse_statfs() */
  592. goto fake;
  593. }
  594. if (err == ENOENT) {
  595. fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT);
  596. }
  597. return err;
  598. }
  599. /* XXX: Could check the sanity/volatility of va_mode here. */
  600. if ((((struct fuse_attr_out *)fdi.answ)->attr.mode & S_IFMT) == 0) {
  601. return EIO;
  602. }
  603. cache_attrs(vp, (struct fuse_attr_out *)fdi.answ);
  604. VTOFUD(vp)->c_flag &= ~C_XTIMES_VALID;
  605. fuse_internal_attr_loadvap(vp, vap, context);
  606. #if M_MACFUSE_EXPERIMENTAL_JUNK
  607. if (vap != VTOVA(vp)) {
  608. memcpy(vap, VTOVA(vp), sizeof(*vap));
  609. }
  610. #endif
  611. /* ATTR_FUDGE_CASE */
  612. if (vnode_isreg(vp) && fuse_isnoubc(vp)) {
  613. /*
  614. * This is for those cases when the file size changed without us
  615. * knowing, and we want to catch up.
  616. *
  617. * For the sake of sanity, we don't want to do it with UBC.
  618. * We also don't want to do it when we have asynchronous writes
  619. * enabled because we might have pending writes on *our* side.
  620. * We're not researching distributed file systems here!
  621. *
  622. */
  623. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  624. off_t new_filesize = ((struct fuse_attr_out *)fdi.answ)->attr.size;
  625. fvdat->filesize = new_filesize;
  626. }
  627. fuse_ticket_drop(fdi.tick);
  628. if (vnode_vtype(vp) != vap->va_type) {
  629. if ((vnode_vtype(vp) == VNON) && (vap->va_type != VNON)) {
  630. /*
  631. * We should be doing the following:
  632. *
  633. * vp->vtype = vap->v_type
  634. */
  635. } else {
  636. /*
  637. * STALE vnode, ditch
  638. *
  639. * The vnode has changed its type "behind our back". There's
  640. * nothing really we can do, so let us just force an internal
  641. * revocation.
  642. */
  643. fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT);
  644. return EIO;
  645. }
  646. }
  647. return 0;
  648. fake:
  649. bzero(vap, sizeof(*vap));
  650. VATTR_RETURN(vap, va_type, vnode_vtype(vp));
  651. VATTR_RETURN(vap, va_uid, data->daemoncred->cr_uid);
  652. VATTR_RETURN(vap, va_gid, data->daemoncred->cr_gid);
  653. VATTR_RETURN(vap, va_mode, S_IRWXU);
  654. return 0;
  655. }
  656. #if M_MACFUSE_ENABLE_XATTR
  657. /*
  658. struct vnop_getxattr_args {
  659. struct vnodeop_desc *a_desc;
  660. vnode_t a_vp;
  661. char *a_name;
  662. uio_t a_uio;
  663. size_t *a_size;
  664. int a_options;
  665. vfs_context_t a_context;
  666. };
  667. */
  668. FUSE_VNOP_EXPORT
  669. int
  670. fuse_vnop_getxattr(struct vnop_getxattr_args *ap)
  671. {
  672. vnode_t vp = ap->a_vp;
  673. const char *name = ap->a_name;
  674. uio_t uio = ap->a_uio;
  675. vfs_context_t context = ap->a_context;
  676. struct fuse_dispatcher fdi;
  677. struct fuse_getxattr_in *fgxi;
  678. struct fuse_getxattr_out *fgxo;
  679. struct fuse_data *data;
  680. mount_t mp;
  681. int err = 0;
  682. size_t namelen;
  683. fuse_trace_printf_vnop();
  684. if (fuse_isdeadfs(vp)) {
  685. return EBADF;
  686. }
  687. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  688. if (name == NULL || name[0] == '\0') {
  689. return EINVAL;
  690. }
  691. mp = vnode_mount(vp);
  692. data = fuse_get_mpdata(mp);
  693. if (fuse_skip_apple_xattr_mp(mp, name)) {
  694. return EPERM;
  695. }
  696. if (data->dataflags & FSESS_AUTO_XATTR) {
  697. return ENOTSUP;
  698. }
  699. if (!fuse_implemented(data, FSESS_NOIMPLBIT(GETXATTR))) {
  700. return ENOTSUP;
  701. }
  702. namelen = strlen(name);
  703. fdisp_init(&fdi, sizeof(*fgxi) + namelen + 1);
  704. fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, context);
  705. fgxi = fdi.indata;
  706. if (uio) {
  707. fgxi->size = (uint32_t)uio_resid(uio);
  708. } else {
  709. fgxi->size = 0;
  710. }
  711. fgxi->position = (uint32_t)uio_offset(uio);
  712. memcpy((char *)fdi.indata + sizeof(*fgxi), name, namelen);
  713. ((char *)fdi.indata)[sizeof(*fgxi) + namelen] = '\0';
  714. if (fgxi->size > FUSE_REASONABLE_XATTRSIZE) {
  715. fticket_set_killl(fdi.tick);
  716. }
  717. err = fdisp_wait_answ(&fdi);
  718. if (err) {
  719. if (err == ENOSYS) {
  720. fuse_clear_implemented(data, FSESS_NOIMPLBIT(GETXATTR));
  721. return ENOTSUP;
  722. }
  723. return err;
  724. }
  725. if (uio) {
  726. *ap->a_size = fdi.iosize;
  727. if ((user_ssize_t)fdi.iosize > uio_resid(uio)) {
  728. err = ERANGE;
  729. } else {
  730. err = uiomove((char *)fdi.answ, (int)fdi.iosize, uio);
  731. }
  732. } else {
  733. fgxo = (struct fuse_getxattr_out *)fdi.answ;
  734. *ap->a_size = fgxo->size;
  735. }
  736. fuse_ticket_drop(fdi.tick);
  737. return err;
  738. }
  739. #endif /* M_MACFUSE_ENABLE_XATTR */
  740. /*
  741. struct vnop_inactive_args {
  742. struct vnodeop_desc *a_desc;
  743. vnode_t a_vp;
  744. vfs_context_t a_context;
  745. };
  746. */
  747. FUSE_VNOP_EXPORT
  748. int
  749. fuse_vnop_inactive(struct vnop_inactive_args *ap)
  750. {
  751. vnode_t vp = ap->a_vp;
  752. vfs_context_t context = ap->a_context;
  753. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  754. struct fuse_filehandle *fufh = NULL;
  755. int fufh_type;
  756. fuse_trace_printf_vnop();
  757. /*
  758. * Cannot do early bail out on a dead file system in this case.
  759. */
  760. for (fufh_type = 0; fufh_type < FUFH_MAXTYPE; fufh_type++) {
  761. fufh = &(fvdat->fufh[fufh_type]);
  762. if (FUFH_IS_VALID(fufh)) {
  763. FUFH_USE_RESET(fufh);
  764. (void)fuse_filehandle_put(vp, context, fufh_type,
  765. FUSE_OP_FOREGROUNDED);
  766. }
  767. }
  768. return 0;
  769. }
  770. extern int fuse_setextendedsecurity(mount_t mp, int state);
  771. /*
  772. struct vnop_ioctl_args {
  773. struct vnodeop_desc *a_desc;
  774. vnode_t a_vp;
  775. u_long a_command;
  776. caddr_t a_data;
  777. int a_fflag;
  778. vfs_context_t a_context;
  779. };
  780. */
  781. FUSE_VNOP_EXPORT
  782. int
  783. fuse_vnop_ioctl(struct vnop_ioctl_args *ap)
  784. {
  785. vnode_t vp = ap->a_vp;
  786. u_long cmd = ap->a_command;
  787. vfs_context_t context = ap->a_context;
  788. int ret = EINVAL;
  789. fuse_trace_printf_vnop();
  790. if (fuse_isdeadfs(vp)) {
  791. return EBADF;
  792. }
  793. switch (cmd) {
  794. case FSCTLSETACLSTATE:
  795. {
  796. int state;
  797. mount_t mp;
  798. struct fuse_data *data;
  799. if (ap->a_data == NULL) {
  800. return EINVAL;
  801. }
  802. mp = vnode_mount(vp);
  803. data = fuse_get_mpdata(mp);
  804. if (!fuse_vfs_context_issuser(context) &&
  805. !(fuse_match_cred(data->daemoncred,
  806. vfs_context_ucred(context)))) {
  807. return EPERM;
  808. }
  809. state = *(int *)ap->a_data;
  810. return fuse_setextendedsecurity(mp, state);
  811. }
  812. break;
  813. case FSCTLALTERVNODEFORINODE:
  814. /*
  815. * This is the fsctl() version of the AVFI device ioctl's in
  816. * fuse_device.c. Since the device ioctl's must be used from
  817. * within the file system (we don't allow multiple device opens),
  818. * it's rather painful to test/experiment with them. The fsctl
  819. * version is easier to use. To simplify things, the "path" in
  820. * the fsctl() call /must/ be the root of the file system.
  821. */
  822. if (!vnode_isvroot(vp)) {
  823. return EINVAL;
  824. }
  825. ret = fuse_internal_ioctl_avfi(vp, context,
  826. (struct fuse_avfi_ioctl *)(ap->a_data));
  827. break;
  828. default:
  829. break;
  830. }
  831. return ret;
  832. }
  833. #if M_MACFUSE_ENABLE_KQUEUE
  834. #include "fuse_knote.h"
  835. /*
  836. struct vnop_kqfilt_add_args {
  837. struct vnodeop_desc *a_desc;
  838. vnode_t a_vp;
  839. struct knote *a_kn;
  840. struct proc *p;
  841. vfs_context_t a_context;
  842. };
  843. */
  844. FUSE_VNOP_EXPORT
  845. int
  846. fuse_vnop_kqfilt_add(struct vnop_kqfilt_add_args *ap)
  847. {
  848. vnode_t vp = ap->a_vp;
  849. struct knote *kn = ap->a_kn;
  850. fuse_trace_printf_vnop();
  851. if (fuse_isdeadfs(vp)) {
  852. return EBADF;
  853. }
  854. switch (kn->kn_filter) {
  855. case EVFILT_READ:
  856. if (vnode_isreg(vp)) {
  857. kn->kn_fop = &fuseread_filtops;
  858. } else {
  859. return EINVAL;
  860. }
  861. break;
  862. case EVFILT_WRITE:
  863. if (vnode_isreg(vp)) {
  864. kn->kn_fop = &fusewrite_filtops;
  865. } else {
  866. return EINVAL;
  867. }
  868. break;
  869. case EVFILT_VNODE:
  870. kn->kn_fop = &fusevnode_filtops;
  871. break;
  872. default:
  873. return 1;
  874. }
  875. kn->kn_hook = (caddr_t)vp;
  876. kn->kn_hookid = vnode_vid(vp);
  877. /* lock */
  878. KNOTE_ATTACH(&VTOFUD(vp)->c_knotes, kn);
  879. /* unlock */
  880. return 0;
  881. }
  882. /*
  883. struct vnop_kqfilt_remove_args {
  884. struct vnodeop_desc *a_desc;
  885. vnode_t a_vp;
  886. uintptr_t ident;
  887. vfs_context_t a_context;
  888. };
  889. */
  890. FUSE_VNOP_EXPORT
  891. int
  892. fuse_vnop_kqfilt_remove(__unused struct vnop_kqfilt_remove_args *ap)
  893. {
  894. fuse_trace_printf_vnop_novp();
  895. return ENOTSUP;
  896. }
  897. #endif /* M_MACFUSE_ENABLE_KQUEUE */
  898. /*
  899. struct vnop_link_args {
  900. struct vnodeop_desc *a_desc;
  901. vnode_t a_vp;
  902. vnode_t a_tdvp;
  903. struct componentname *a_cnp;
  904. vfs_context_t a_context;
  905. };
  906. */
  907. FUSE_VNOP_EXPORT
  908. int
  909. fuse_vnop_link(struct vnop_link_args *ap)
  910. {
  911. vnode_t vp = ap->a_vp;
  912. vnode_t tdvp = ap->a_tdvp;
  913. struct componentname *cnp = ap->a_cnp;
  914. vfs_context_t context = ap->a_context;
  915. struct vnode_attr *vap = VTOVA(vp);
  916. struct fuse_dispatcher fdi;
  917. struct fuse_entry_out *feo;
  918. struct fuse_link_in fli;
  919. int err;
  920. fuse_trace_printf_vnop();
  921. if (fuse_isdeadfs_fs(vp)) {
  922. panic("MacFUSE: fuse_vnop_link(): called on a dead file system");
  923. }
  924. if (vnode_mount(tdvp) != vnode_mount(vp)) {
  925. return EXDEV;
  926. }
  927. if (vap->va_nlink >= FUSE_LINK_MAX) {
  928. return EMLINK;
  929. }
  930. CHECK_BLANKET_DENIAL(vp, context, EPERM);
  931. fli.oldnodeid = VTOI(vp);
  932. fdisp_init(&fdi, 0);
  933. fuse_internal_newentry_makerequest(vnode_mount(tdvp), VTOI(tdvp), cnp,
  934. FUSE_LINK, &fli, sizeof(fli), &fdi,
  935. context);
  936. if ((err = fdisp_wait_answ(&fdi))) {
  937. return err;
  938. }
  939. feo = fdi.answ;
  940. err = fuse_internal_checkentry(feo, vnode_vtype(vp));
  941. fuse_ticket_drop(fdi.tick);
  942. fuse_invalidate_attr(tdvp);
  943. fuse_invalidate_attr(vp);
  944. if (err == 0) {
  945. FUSE_KNOTE(vp, NOTE_LINK);
  946. FUSE_KNOTE(tdvp, NOTE_WRITE);
  947. VTOFUD(vp)->nlookup++;
  948. }
  949. return err;
  950. }
  951. #if M_MACFUSE_ENABLE_XATTR
  952. /*
  953. struct vnop_listxattr_args {
  954. struct vnodeop_desc *a_desc;
  955. vnode_t a_vp;
  956. uio_t a_uio;
  957. size_t *a_size;
  958. int a_options;
  959. vfs_context_t a_context;
  960. };
  961. */
  962. FUSE_VNOP_EXPORT
  963. int
  964. fuse_vnop_listxattr(struct vnop_listxattr_args *ap)
  965. {
  966. vnode_t vp = ap->a_vp;
  967. uio_t uio = ap->a_uio;
  968. vfs_context_t context = ap->a_context;
  969. struct fuse_dispatcher fdi;
  970. struct fuse_getxattr_in *fgxi;
  971. struct fuse_getxattr_out *fgxo;
  972. struct fuse_data *data;
  973. int err = 0;
  974. fuse_trace_printf_vnop();
  975. if (fuse_isdeadfs(vp)) {
  976. return EBADF;
  977. }
  978. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  979. data = fuse_get_mpdata(vnode_mount(vp));
  980. if (data->dataflags & FSESS_AUTO_XATTR) {
  981. return ENOTSUP;
  982. }
  983. if (!fuse_implemented(data, FSESS_NOIMPLBIT(LISTXATTR))) {
  984. return ENOTSUP;
  985. }
  986. fdisp_init(&fdi, sizeof(*fgxi));
  987. fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, context);
  988. fgxi = fdi.indata;
  989. if (uio) {
  990. fgxi->size = (uint32_t)uio_resid(uio);
  991. } else {
  992. fgxi->size = 0;
  993. }
  994. err = fdisp_wait_answ(&fdi);
  995. if (err) {
  996. if (err == ENOSYS) {
  997. fuse_clear_implemented(data, FSESS_NOIMPLBIT(LISTXATTR));
  998. return ENOTSUP;
  999. }
  1000. return err;
  1001. }
  1002. if (uio) {
  1003. *ap->a_size = fdi.iosize;
  1004. if ((user_ssize_t)fdi.iosize > uio_resid(uio)) {
  1005. err = ERANGE;
  1006. } else {
  1007. err = uiomove((char *)fdi.answ, (int)fdi.iosize, uio);
  1008. }
  1009. } else {
  1010. fgxo = (struct fuse_getxattr_out *)fdi.answ;
  1011. *ap->a_size = fgxo->size;
  1012. }
  1013. fuse_ticket_drop(fdi.tick);
  1014. return err;
  1015. }
  1016. #endif /* M_MACFUSE_ENABLE_XATTR */
  1017. /*
  1018. struct vnop_lookup_args {
  1019. struct vnodeop_desc *a_desc;
  1020. vnode_t a_dvp;
  1021. vnode_t *a_vpp;
  1022. struct componentname *a_cnp;
  1023. vfs_context_t a_context;
  1024. };
  1025. */
  1026. FUSE_VNOP_EXPORT
  1027. int
  1028. fuse_vnop_lookup(struct vnop_lookup_args *ap)
  1029. {
  1030. vnode_t dvp = ap->a_dvp;
  1031. vnode_t *vpp = ap->a_vpp;
  1032. struct componentname *cnp = ap->a_cnp;
  1033. vfs_context_t context = ap->a_context;
  1034. int nameiop = cnp->cn_nameiop;
  1035. int flags = cnp->cn_flags;
  1036. int wantparent = flags & (LOCKPARENT|WANTPARENT);
  1037. int islastcn = flags & ISLASTCN;
  1038. int isdot = FALSE;
  1039. int isdotdot = FALSE;
  1040. mount_t mp = vnode_mount(dvp);
  1041. int err = 0;
  1042. int lookup_err = 0;
  1043. vnode_t vp = NULL;
  1044. vnode_t pdp = (vnode_t)NULL;
  1045. uint64_t size = FUSE_ZERO_SIZE;
  1046. struct fuse_dispatcher fdi;
  1047. enum fuse_opcode op;
  1048. uint64_t nodeid;
  1049. uint64_t parent_nodeid;
  1050. *vpp = NULLVP;
  1051. fuse_trace_printf_vnop_novp();
  1052. if (fuse_isdeadfs(dvp)) {
  1053. *ap->a_vpp = NULLVP;
  1054. return ENOTDIR;
  1055. }
  1056. if (fuse_skip_apple_double_mp(mp, cnp->cn_nameptr, cnp->cn_namelen)) {
  1057. return ENOENT;
  1058. }
  1059. if (!vnode_isdir(dvp)) {
  1060. return ENOTDIR;
  1061. }
  1062. if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP)) {
  1063. return EROFS;
  1064. }
  1065. if (cnp->cn_namelen > FUSE_MAXNAMLEN) {
  1066. return ENAMETOOLONG;
  1067. }
  1068. if (flags & ISDOTDOT) {
  1069. isdotdot = TRUE;
  1070. } else if ((cnp->cn_nameptr[0] == '.') && (cnp->cn_namelen == 1)) {
  1071. isdot = TRUE;
  1072. }
  1073. if (isdotdot) {
  1074. pdp = VTOFUD(dvp)->parentvp;
  1075. nodeid = VTOI(pdp);
  1076. parent_nodeid = VTOFUD(dvp)->parent_nodeid;
  1077. fdisp_init(&fdi, 0);
  1078. op = FUSE_GETATTR;
  1079. goto calldaemon;
  1080. } else if (isdot) {
  1081. nodeid = VTOI(dvp);
  1082. parent_nodeid = VTOFUD(dvp)->parent_nodeid;
  1083. fdisp_init(&fdi, 0);
  1084. op = FUSE_GETATTR;
  1085. goto calldaemon;
  1086. } else {
  1087. err = fuse_vncache_lookup(dvp, vpp, cnp);
  1088. switch (err) {
  1089. case -1: /* positive match */
  1090. if (fuse_isnovncache(*vpp)) {
  1091. fuse_vncache_purge(*vpp);
  1092. vnode_put(*vpp);
  1093. *vpp = NULL;
  1094. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_lookup_cache_overrides);
  1095. err = 0;
  1096. break; /* pretend it's a miss */
  1097. }
  1098. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_lookup_cache_hits);
  1099. return 0;
  1100. case 0: /* no match in cache (or aged out) */
  1101. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_lookup_cache_misses);
  1102. break;
  1103. case ENOENT: /* negative match */
  1104. /* fall through */
  1105. default:
  1106. return err;
  1107. }
  1108. }
  1109. nodeid = VTOI(dvp);
  1110. parent_nodeid = VTOI(dvp);
  1111. fdisp_init(&fdi, cnp->cn_namelen + 1);
  1112. op = FUSE_LOOKUP;
  1113. calldaemon:
  1114. fdisp_make(&fdi, op, mp, nodeid, context);
  1115. if (op == FUSE_LOOKUP) {
  1116. memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
  1117. ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
  1118. }
  1119. lookup_err = fdisp_wait_answ(&fdi);
  1120. if ((op == FUSE_LOOKUP) && !lookup_err) { /* lookup call succeeded */
  1121. nodeid = ((struct fuse_entry_out *)fdi.answ)->nodeid;
  1122. size = ((struct fuse_entry_out *)fdi.answ)->attr.size;
  1123. if (!nodeid) {
  1124. fdi.answ_stat = ENOENT; /* XXX: negative_timeout case */
  1125. lookup_err = ENOENT;
  1126. } else if (nodeid == FUSE_ROOT_ID) {
  1127. lookup_err = EINVAL;
  1128. }
  1129. }
  1130. /*
  1131. * If we get (lookup_err != 0), that means we didn't find what we were
  1132. * looking for. This can still be OK if we're creating or renaming and
  1133. * are at the end of the pathname.
  1134. */
  1135. if (lookup_err &&
  1136. (!fdi.answ_stat || lookup_err != ENOENT || op != FUSE_LOOKUP)) {
  1137. return lookup_err;
  1138. }
  1139. /* lookup_err, if non-zero, must be ENOENT at this point */
  1140. if (lookup_err) {
  1141. if ((nameiop == CREATE || nameiop == RENAME) && islastcn
  1142. /* && directory dvp has not been removed */) {
  1143. /*
  1144. * EROFS case has already been covered.
  1145. *
  1146. * if (vfs_isrdonly(mp)) {
  1147. * err = EROFS;
  1148. * goto out;
  1149. * }
  1150. */
  1151. err = EJUSTRETURN;
  1152. goto out;
  1153. }
  1154. if (fuse_isnegativevncache_mp(mp)) {
  1155. if ((cnp->cn_flags & MAKEENTRY) && (nameiop != CREATE)) {
  1156. fuse_vncache_enter(dvp, NULLVP, cnp);
  1157. }
  1158. }
  1159. err = ENOENT;
  1160. goto out;
  1161. } else {
  1162. /* !lookup_err */
  1163. struct fuse_entry_out *feo = NULL;
  1164. struct fuse_attr *fattr = NULL;
  1165. if (op == FUSE_GETATTR) {
  1166. fattr = &((struct fuse_attr_out *)fdi.answ)->attr;
  1167. } else {
  1168. feo = (struct fuse_entry_out *)fdi.answ;
  1169. fattr = &(feo->attr);
  1170. }
  1171. /* Sanity check(s) */
  1172. if ((fattr->mode & S_IFMT) == 0) {
  1173. err = EIO;
  1174. goto out;
  1175. }
  1176. if ((nameiop == DELETE) && islastcn) {
  1177. if (isdot) {
  1178. err = vnode_get(dvp);
  1179. if (err == 0) {
  1180. *vpp = dvp;
  1181. }
  1182. goto out;
  1183. }
  1184. if ((err = fuse_vget_i(&vp, 0 /* flags */, feo, cnp, dvp,
  1185. mp, context))) {
  1186. goto out;
  1187. }
  1188. *vpp = vp;
  1189. goto out;
  1190. }
  1191. if ((nameiop == RENAME) && islastcn && wantparent) {
  1192. if (isdot) {
  1193. err = EISDIR;
  1194. goto out;
  1195. }
  1196. if ((err = fuse_vget_i(&vp, 0 /* flags */, feo, cnp, dvp,
  1197. mp, context))) {
  1198. goto out;
  1199. }
  1200. *vpp = vp;
  1201. goto out;
  1202. }
  1203. if (isdotdot) {
  1204. err = vnode_get(pdp);
  1205. if (err == 0) {
  1206. *vpp = pdp;
  1207. }
  1208. } else if (isdot) { /* nodeid == VTOI(dvp) */
  1209. err = vnode_get(dvp);
  1210. if (err == 0) {
  1211. *vpp = dvp;
  1212. }
  1213. } else {
  1214. if ((err = fuse_vget_i(&vp, 0 /* flags */, feo, cnp, dvp,
  1215. mp, context))) {
  1216. goto out;
  1217. }
  1218. *vpp = vp;
  1219. }
  1220. if (op == FUSE_GETATTR) {
  1221. /* ATTR_FUDGE_CASE */
  1222. if (vnode_isreg(*vpp) && fuse_isnoubc(vp)) {
  1223. VTOFUD(*vpp)->filesize =
  1224. ((struct fuse_attr_out *)fdi.answ)->attr.size;
  1225. }
  1226. cache_attrs(*vpp, (struct fuse_attr_out *)fdi.answ);
  1227. } else {
  1228. /* ATTR_FUDGE_CASE */
  1229. if (vnode_isreg(*vpp) && fuse_isnoubc(vp)) {
  1230. VTOFUD(*vpp)->filesize =
  1231. ((struct fuse_entry_out *)fdi.answ)->attr.size;
  1232. }
  1233. cache_attrs(*vpp, (struct fuse_entry_out *)fdi.answ);
  1234. }
  1235. /*
  1236. * We do this elsewhere...
  1237. *
  1238. * if (cnp->cn_flags & MAKEENTRY) {
  1239. * fuse_vncache_enter(dvp, *vpp, cnp);
  1240. * }
  1241. */
  1242. }
  1243. out:
  1244. if (!lookup_err) {
  1245. /* No lookup error; need to clean up. */
  1246. if (err) { /* Found inode; exit with no vnode. */
  1247. if (op == FUSE_LOOKUP) {
  1248. fuse_internal_forget_send(vnode_mount(dvp), context,
  1249. nodeid, 1, &fdi);
  1250. }
  1251. return err;
  1252. } else {
  1253. if (!islastcn) {
  1254. int tmpvtype = vnode_vtype(*vpp);
  1255. if ((tmpvtype != VDIR) && (tmpvtype != VLNK)) {
  1256. err = ENOTDIR;
  1257. }
  1258. /* if (!err && !vnode_mountedhere(*vpp)) { ... */
  1259. if (err) {
  1260. vnode_put(*vpp);
  1261. *vpp = NULL;
  1262. }
  1263. }
  1264. }
  1265. fuse_ticket_drop(fdi.tick);
  1266. }
  1267. return err;
  1268. }
  1269. /*
  1270. struct vnop_mkdir_args {
  1271. struct vnodeop_desc *a_desc;
  1272. vnode_t a_dvp;
  1273. vnode_t *a_vpp;
  1274. struct componentname *a_cnp;
  1275. struct vnode_attr *a_vap;
  1276. vfs_context_t a_context;
  1277. };
  1278. */
  1279. FUSE_VNOP_EXPORT
  1280. int
  1281. fuse_vnop_mkdir(struct vnop_mkdir_args *ap)
  1282. {
  1283. vnode_t dvp = ap->a_dvp;
  1284. vnode_t *vpp = ap->a_vpp;
  1285. struct componentname *cnp = ap->a_cnp;
  1286. struct vnode_attr *vap = ap->a_vap;
  1287. vfs_context_t context = ap->a_context;
  1288. int err = 0;
  1289. struct fuse_mkdir_in fmdi;
  1290. fuse_trace_printf_vnop_novp();
  1291. if (fuse_isdeadfs_fs(dvp)) {
  1292. panic("MacFUSE: fuse_vnop_mkdir(): called on a dead file system");
  1293. }
  1294. CHECK_BLANKET_DENIAL(dvp, context, EPERM);
  1295. fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
  1296. err = fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi,
  1297. sizeof(fmdi), VDIR, context);
  1298. if (err == 0) {
  1299. fuse_invalidate_attr(dvp);
  1300. FUSE_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
  1301. }
  1302. return err;
  1303. }
  1304. /*
  1305. struct vnop_mknod_args {
  1306. struct vnodeop_desc *a_desc;
  1307. vnode_t a_dvp;
  1308. vnode_t *a_vpp;
  1309. struct componentname *a_cnp;
  1310. struct vnode_attr *a_vap;
  1311. vfs_context_t a_context;
  1312. };
  1313. */
  1314. FUSE_VNOP_EXPORT
  1315. int
  1316. fuse_vnop_mknod(struct vnop_mknod_args *ap)
  1317. {
  1318. vnode_t dvp = ap->a_dvp;
  1319. vnode_t *vpp = ap->a_vpp;
  1320. struct componentname *cnp = ap->a_cnp;
  1321. struct vnode_attr *vap = ap->a_vap;
  1322. vfs_context_t context = ap->a_context;
  1323. struct fuse_mknod_in fmni;
  1324. int err;
  1325. fuse_trace_printf_vnop_novp();
  1326. if (fuse_isdeadfs_fs(dvp)) {
  1327. panic("MacFUSE: fuse_vnop_mknod(): called on a dead file system");
  1328. }
  1329. CHECK_BLANKET_DENIAL(dvp, context, EPERM);
  1330. fmni.mode = MAKEIMODE(vap->va_type, vap->va_mode);
  1331. fmni.rdev = vap->va_rdev;
  1332. err = fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKNOD, &fmni,
  1333. sizeof(fmni), vap->va_type, context);
  1334. if (err== 0) {
  1335. fuse_invalidate_attr(dvp);
  1336. FUSE_KNOTE(dvp, NOTE_WRITE);
  1337. }
  1338. return err;
  1339. }
  1340. /*
  1341. struct vnop_mmap_args {
  1342. struct vnodeop_desc *a_desc;
  1343. vnode_t a_vp;
  1344. int a_fflags;
  1345. vfs_context_t a_context;
  1346. };
  1347. */
  1348. FUSE_VNOP_EXPORT
  1349. int
  1350. fuse_vnop_mmap(struct vnop_mmap_args *ap)
  1351. {
  1352. vnode_t vp = ap->a_vp;
  1353. int fflags = ap->a_fflags;
  1354. vfs_context_t context = ap->a_context;
  1355. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  1356. struct fuse_filehandle *fufh = NULL;
  1357. fufh_type_t fufh_type = fuse_filehandle_xlate_from_mmap(fflags);
  1358. int err = 0;
  1359. int deleted = 0;
  1360. int retried = 0;
  1361. fuse_trace_printf_vnop();
  1362. if (fuse_isdeadfs_fs(vp)) {
  1363. panic("MacFUSE: fuse_vnop_mmap(): called on a dead file system");
  1364. }
  1365. if (fuse_isdirectio(vp)) {
  1366. /*
  1367. * We should be returning ENODEV here, but ubc_map() translates
  1368. * all errors except ENOPERM to 0. Even then, this is not going
  1369. * to prevent the mmap()!
  1370. */
  1371. return EPERM;
  1372. }
  1373. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  1374. if (fufh_type == FUFH_INVALID) { /* nothing to do */
  1375. return 0;
  1376. }
  1377. /* XXX: For PROT_WRITE, we should only care if file is mapped MAP_SHARED. */
  1378. retry:
  1379. fufh = &(fvdat->fufh[fufh_type]);
  1380. if (FUFH_IS_VALID(fufh)) {
  1381. FUFH_USE_INC(fufh);
  1382. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_reuse_count);
  1383. goto out;
  1384. }
  1385. if (!deleted) {
  1386. err = fuse_filehandle_preflight_status(vp, fvdat->parentvp,
  1387. context, fufh_type);
  1388. if (err == ENOENT) {
  1389. deleted = 1;
  1390. err = 0;
  1391. }
  1392. }
  1393. #if FUSE_DEBUG
  1394. fuse_preflight_log(vp, fufh_type, err, "mmap");
  1395. #endif /* FUSE_DEBUG */
  1396. if (!err) {
  1397. err = fuse_filehandle_get(vp, context, fufh_type, 0 /* mode */);
  1398. }
  1399. if (err) {
  1400. /*
  1401. * XXX: This is a kludge because xnu doesn't tell us whether this
  1402. * is a MAP_SHARED or MAP_PRIVATE mapping. If we want shared
  1403. * library mapping to go well, we need to do this.
  1404. */
  1405. if (!retried && (err == EACCES) &&
  1406. ((fufh_type == FUFH_RDWR) || (fufh_type == FUFH_WRONLY))) {
  1407. IOLog("MacFUSE: filehandle_get retrying (type=%d, err=%d)\n",
  1408. fufh_type, err);
  1409. fufh_type = FUFH_RDONLY;
  1410. retried = 1;
  1411. goto retry;
  1412. } else {
  1413. IOLog("MacFUSE: filehandle_get failed in mmap (type=%d, err=%d)\n",
  1414. fufh_type, err);
  1415. }
  1416. return EPERM;
  1417. }
  1418. out:
  1419. return 0;
  1420. }
  1421. /*
  1422. struct vnop_mnomap_args {
  1423. struct vnodeop_desc *a_desc;
  1424. vnode_t a_vp;
  1425. vfs_context_t a_context;
  1426. };
  1427. */
  1428. FUSE_VNOP_EXPORT
  1429. int
  1430. fuse_vnop_mnomap(struct vnop_mnomap_args *ap)
  1431. {
  1432. vnode_t vp = ap->a_vp;
  1433. fuse_trace_printf_vnop();
  1434. if (fuse_isdeadfs(vp)) {
  1435. return 0;
  1436. }
  1437. if (fuse_isdirectio(vp)) {
  1438. /*
  1439. * ubc_unmap() doesn't care about the return value.
  1440. */
  1441. return ENODEV;
  1442. }
  1443. /*
  1444. * XXX
  1445. *
  1446. * What behavior do we want here?
  1447. *
  1448. * I once noted that sync() is not going to help here, but I think
  1449. * I've forgotten the context. Need to think about this again.
  1450. *
  1451. * ubc_msync(vp, (off_t)0, ubc_getsize(vp), (off_t*)0, UBC_PUSHDIRTY);
  1452. */
  1453. /*
  1454. * Earlier, we used to go through our vnode's fufh list here, doing
  1455. * something like the following:
  1456. *
  1457. * for (type = 0; type < FUFH_MAXTYPE; type++) {
  1458. * fufh = &(fvdat->fufh[type]);
  1459. * if ((fufh->fufh_flags & FUFH_VALID) &&
  1460. * (fufh->fufh_flags & FUFH_MAPPED)) {
  1461. * fufh->fufh_flags &= ~FUFH_MAPPED;
  1462. * if (fufh->open_count == 0) {
  1463. * (void)fuse_filehandle_put(vp, context, type,
  1464. * FUSE_OP_BACKGROUNDED);
  1465. * }
  1466. * }
  1467. * }
  1468. *
  1469. * Now, cleanup is all taken care of in vnop_inactive/reclaim.
  1470. *
  1471. */
  1472. return 0;
  1473. }
  1474. /*
  1475. struct vnop_offtoblk_args {
  1476. struct vnodeop_desc *a_desc;
  1477. vnode_t a_vp;
  1478. off_t a_offset;
  1479. daddr64_t *a_lblkno;
  1480. };
  1481. */
  1482. FUSE_VNOP_EXPORT
  1483. int
  1484. fuse_vnop_offtoblk(struct vnop_offtoblk_args *ap)
  1485. {
  1486. vnode_t vp = ap->a_vp;
  1487. off_t offset = ap->a_offset;
  1488. daddr64_t *lblknoPtr = ap->a_lblkno;
  1489. struct fuse_data *data;
  1490. fuse_trace_printf_vnop();
  1491. if (fuse_isdeadfs(vp)) {
  1492. return EIO;
  1493. }
  1494. data = fuse_get_mpdata(vnode_mount(vp));
  1495. *lblknoPtr = offset / data->blocksize;
  1496. return 0;
  1497. }
  1498. /*
  1499. struct vnop_open_args {
  1500. struct vnodeop_desc *a_desc;
  1501. vnode_t a_vp;
  1502. int a_mode;
  1503. vfs_context_t a_context;
  1504. };
  1505. */
  1506. FUSE_VNOP_EXPORT
  1507. int
  1508. fuse_vnop_open(struct vnop_open_args *ap)
  1509. {
  1510. vnode_t vp = ap->a_vp;
  1511. int mode = ap->a_mode;
  1512. vfs_context_t context = ap->a_context;
  1513. fufh_type_t fufh_type;
  1514. struct fuse_vnode_data *fvdat;
  1515. struct fuse_filehandle *fufh = NULL;
  1516. struct fuse_filehandle *fufh_rw = NULL;
  1517. int error, isdir = 0;
  1518. long hint = 0;
  1519. fuse_trace_printf_vnop();
  1520. if (fuse_isdeadfs(vp)) {
  1521. return ENXIO;
  1522. }
  1523. #if !M_MACFUSE_ENABLE_FIFOFS
  1524. if (vnode_isfifo(vp)) {
  1525. return EPERM;
  1526. }
  1527. #endif
  1528. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  1529. fvdat = VTOFUD(vp);
  1530. if (vnode_isdir(vp)) {
  1531. isdir = 1;
  1532. }
  1533. if (isdir) {
  1534. fufh_type = FUFH_RDONLY;
  1535. } else {
  1536. fufh_type = fuse_filehandle_xlate_from_fflags(mode);
  1537. }
  1538. fufh = &(fvdat->fufh[fufh_type]);
  1539. if (!isdir && (fvdat->flag & FN_CREATING)) {
  1540. fuse_lck_mtx_lock(fvdat->createlock);
  1541. if (fvdat->flag & FN_CREATING) { // check again
  1542. if (fvdat->creator == current_thread()) {
  1543. /*
  1544. * For testing the race condition we want to prevent here,
  1545. * try something like the following:
  1546. *
  1547. * int dummyctr = 0;
  1548. *
  1549. * for (; dummyctr < 2048000000; dummyctr++);
  1550. */
  1551. fufh_rw = &(fvdat->fufh[FUFH_RDWR]);
  1552. fufh->open_flags = fufh_rw->open_flags;
  1553. fufh->fh_id = fufh_rw->fh_id;
  1554. /* Note that fufh_rw can be the same as fufh! Order is key. */
  1555. fufh_rw->open_count = 0;
  1556. fufh->open_count = 1;
  1557. /*
  1558. * Creator has picked up stashed handle and moved it to the
  1559. * fufh_type slot.
  1560. */
  1561. fvdat->flag &= ~FN_CREATING;
  1562. fuse_lck_mtx_unlock(fvdat->createlock);
  1563. fuse_wakeup((caddr_t)fvdat->creator); // wake up all
  1564. goto ok; /* return 0 */
  1565. } else {
  1566. /* Contender is going to sleep now. */
  1567. error = fuse_msleep(fvdat->creator, fvdat->createlock,
  1568. PDROP | PINOD | PCATCH, "fuse_open", NULL);
  1569. /*
  1570. * msleep will drop the mutex. since we have PDROP specified,
  1571. * it will NOT regrab the mutex when it returns.
  1572. */
  1573. /* Contender is awake now. */
  1574. if (error) {
  1575. /*
  1576. * Since we specified PCATCH above, we'll be woken up in
  1577. * case a signal arrives. The value of error could be
  1578. * EINTR or ERESTART.
  1579. */
  1580. return error;
  1581. }
  1582. }
  1583. } else {
  1584. fuse_lck_mtx_unlock(fvdat->createlock);
  1585. /* Can proceed from here. */
  1586. }
  1587. }
  1588. if (FUFH_IS_VALID(fufh)) {
  1589. FUFH_USE_INC(fufh);
  1590. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_reuse_count);
  1591. goto ok; /* return 0 */
  1592. }
  1593. error = fuse_filehandle_get(vp, context, fufh_type, mode);
  1594. if (error) {
  1595. IOLog("MacFUSE: filehandle_get failed in open (type=%d, err=%d)\n",
  1596. fufh_type, error);
  1597. if (error == ENOENT) {
  1598. cache_purge(vp);
  1599. }
  1600. return error;
  1601. }
  1602. ok:
  1603. /*
  1604. * Doing this here because when a vnode goes inactive, things like
  1605. * no-cache and no-readahead are cleared by the kernel.
  1606. */
  1607. if ((fufh->fuse_open_flags & FOPEN_DIRECT_IO) || (fuse_isdirectio(vp))) {
  1608. /*
  1609. * direct_io for a vnode implies:
  1610. * - no ubc for the vnode
  1611. * - no readahead for the vnode
  1612. * - nosyncwrites disabled FOR THE ENTIRE MOUNT
  1613. * - no vncache for the vnode (handled in lookup)
  1614. */
  1615. ubc_msync(vp, (off_t)0, ubc_getsize(vp), (off_t*)0,
  1616. UBC_PUSHALL | UBC_INVALIDATE);
  1617. vnode_setnocache(vp);
  1618. vnode_setnoreadahead(vp);
  1619. fuse_clearnosyncwrites_mp(vnode_mount(vp));
  1620. fvdat->flag |= FN_DIRECT_IO;
  1621. goto out;
  1622. } else if (fufh->fuse_open_flags & FOPEN_PURGE_UBC) {
  1623. ubc_msync(vp, (off_t)0, ubc_getsize(vp), (off_t*)0,
  1624. UBC_PUSHALL | UBC_INVALIDATE);
  1625. fufh->fuse_open_flags &= ~FOPEN_PURGE_UBC;
  1626. hint |= NOTE_WRITE;
  1627. if (fufh->fuse_open_flags & FOPEN_PURGE_ATTR) {
  1628. int serr = 0;
  1629. struct fuse_dispatcher fdi;
  1630. fuse_invalidate_attr(vp);
  1631. hint |= NOTE_ATTRIB;
  1632. serr = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, context);
  1633. if (!serr) {
  1634. /* XXX: Could check the sanity/volatility of va_mode here. */
  1635. if ((((struct fuse_attr_out*)fdi.answ)->attr.mode & S_IFMT)) {
  1636. cache_attrs(vp, (struct fuse_attr_out *)fdi.answ);
  1637. off_t new_filesize =
  1638. ((struct fuse_attr_out *)fdi.answ)->attr.size;
  1639. if (new_filesize > VTOFUD(vp)->filesize) {
  1640. hint |= NOTE_EXTEND;
  1641. }
  1642. VTOFUD(vp)->filesize = new_filesize;
  1643. ubc_setsize(vp, (off_t)new_filesize);
  1644. }
  1645. fuse_ticket_drop(fdi.tick);
  1646. }
  1647. fufh->fuse_open_flags &= ~FOPEN_PURGE_ATTR;
  1648. }
  1649. }
  1650. if (hint) {
  1651. FUSE_KNOTE(vp, hint);
  1652. }
  1653. if (fuse_isnoreadahead(vp)) {
  1654. vnode_setnoreadahead(vp);
  1655. }
  1656. if (fuse_isnoubc(vp)) {
  1657. vnode_setnocache(vp);
  1658. }
  1659. out:
  1660. return 0;
  1661. }
  1662. /*
  1663. struct vnop_pagein_args {
  1664. struct vnodeop_desc *a_desc;
  1665. vnode_t a_vp;
  1666. upl_t a_pl;
  1667. vm_offset_t a_pl_offset;
  1668. off_t a_f_offset;
  1669. size_t a_size;
  1670. int a_flags;
  1671. vfs_context_t a_context;
  1672. };
  1673. */
  1674. FUSE_VNOP_EXPORT
  1675. int
  1676. fuse_vnop_pagein(struct vnop_pagein_args *ap)
  1677. {
  1678. vnode_t vp = ap->a_vp;
  1679. upl_t pl = ap->a_pl;
  1680. vm_offset_t pl_offset = ap->a_pl_offset;
  1681. off_t f_offset = ap->a_f_offset;
  1682. size_t size = ap->a_size;
  1683. int flags = ap->a_flags;
  1684. struct fuse_vnode_data *fvdat;
  1685. int err;
  1686. fuse_trace_printf_vnop();
  1687. if (fuse_isdeadfs(vp) || fuse_isdirectio(vp)) {
  1688. if (!(flags & UPL_NOCOMMIT)) {
  1689. ubc_upl_abort_range(pl, (upl_offset_t)pl_offset, (int)size,
  1690. UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR);
  1691. }
  1692. /*
  1693. * Will cause PAGER_ERROR (pager unable to read or write page).
  1694. */
  1695. return ENOTSUP;
  1696. }
  1697. fvdat = VTOFUD(vp);
  1698. if (!fvdat) {
  1699. return EIO;
  1700. }
  1701. err = cluster_pagein(vp, pl, (upl_offset_t)pl_offset, f_offset, (int)size,
  1702. fvdat->filesize, flags);
  1703. return err;
  1704. }
  1705. /*
  1706. struct vnop_pageout_args {
  1707. struct vnodeop_desc *a_desc;
  1708. vnode_t a_vp;
  1709. upl_t a_pl;
  1710. vm_offset_t a_pl_offset;
  1711. off_t a_f_offset;
  1712. size_t a_size;
  1713. int a_flags;
  1714. vfs_context_t a_context;
  1715. };
  1716. */
  1717. FUSE_VNOP_EXPORT
  1718. int
  1719. fuse_vnop_pageout(struct vnop_pageout_args *ap)
  1720. {
  1721. vnode_t vp = ap->a_vp;
  1722. upl_t pl = ap->a_pl;
  1723. vm_offset_t pl_offset = ap->a_pl_offset;
  1724. off_t f_offset = ap->a_f_offset;
  1725. size_t size = ap->a_size;
  1726. int flags = ap->a_flags;
  1727. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  1728. int error;
  1729. fuse_trace_printf_vnop();
  1730. if (fuse_isdeadfs(vp) || fuse_isdirectio(vp)) {
  1731. if (!(flags & UPL_NOCOMMIT)) {
  1732. ubc_upl_abort_range(pl, (upl_offset_t)pl_offset, (upl_size_t)size,
  1733. UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR);
  1734. }
  1735. /*
  1736. * Will cause PAGER_ERROR (pager unable to read or write page).
  1737. */
  1738. return ENOTSUP;
  1739. }
  1740. error = cluster_pageout(vp, pl, (upl_offset_t)pl_offset, f_offset,
  1741. (int)size, (off_t)fvdat->filesize, flags);
  1742. return error;
  1743. }
  1744. /*
  1745. struct vnop_pathconf_args {
  1746. struct vnodeop_desc *a_desc;
  1747. vnode_t a_vp;
  1748. int a_name;
  1749. int *a_retval;
  1750. vfs_context_t a_context;
  1751. };
  1752. */
  1753. FUSE_VNOP_EXPORT
  1754. int
  1755. fuse_vnop_pathconf(struct vnop_pathconf_args *ap)
  1756. {
  1757. vnode_t vp = ap->a_vp;
  1758. int name = ap->a_name;
  1759. int *retvalPtr = ap->a_retval;
  1760. vfs_context_t context = ap->a_context;
  1761. int err;
  1762. fuse_trace_printf_vnop();
  1763. if (fuse_isdeadfs(vp)) {
  1764. return EBADF;
  1765. }
  1766. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  1767. err = 0;
  1768. switch (name) {
  1769. case _PC_LINK_MAX:
  1770. *retvalPtr = FUSE_LINK_MAX;
  1771. break;
  1772. case _PC_NAME_MAX:
  1773. *retvalPtr = FUSE_MAXNAMLEN;
  1774. break;
  1775. case _PC_PATH_MAX:
  1776. *retvalPtr = MAXPATHLEN;
  1777. break;
  1778. case _PC_PIPE_BUF:
  1779. *retvalPtr = PIPE_BUF;
  1780. break;
  1781. case _PC_CHOWN_RESTRICTED:
  1782. *retvalPtr = 1;
  1783. break;
  1784. case _PC_NO_TRUNC:
  1785. *retvalPtr = 0;
  1786. break;
  1787. case _PC_NAME_CHARS_MAX:
  1788. *retvalPtr = 255; // chars as opposed to bytes
  1789. break;
  1790. case _PC_CASE_SENSITIVE:
  1791. *retvalPtr = 1;
  1792. break;
  1793. case _PC_CASE_PRESERVING:
  1794. *retvalPtr = 1;
  1795. break;
  1796. /*
  1797. * _PC_EXTENDED_SECURITY_NP and _PC_AUTH_OPAQUE_NP are handled
  1798. * by the VFS.
  1799. */
  1800. // The following are terminal device stuff that we don't support:
  1801. case _PC_MAX_CANON:
  1802. case _PC_MAX_INPUT:
  1803. case _PC_VDISABLE:
  1804. default:
  1805. err = EINVAL;
  1806. break;
  1807. }
  1808. return err;
  1809. }
  1810. /*
  1811. struct vnop_read_args {
  1812. struct vnodeop_desc *a_desc;
  1813. vnode_t a_vp;
  1814. struct uio *a_uio;
  1815. int a_ioflag;
  1816. vfs_context_t a_context;
  1817. };
  1818. */
  1819. FUSE_VNOP_EXPORT
  1820. int
  1821. fuse_vnop_read(struct vnop_read_args *ap)
  1822. {
  1823. vnode_t vp = ap->a_vp;
  1824. uio_t uio = ap->a_uio;
  1825. int ioflag = ap->a_ioflag;
  1826. vfs_context_t context = ap->a_context;
  1827. struct fuse_vnode_data *fvdat;
  1828. struct fuse_data *data;
  1829. off_t orig_resid;
  1830. off_t orig_offset;
  1831. int err = EIO;
  1832. /*
  1833. * XXX: Locking
  1834. *
  1835. * lock_shared(truncatelock)
  1836. * call the cluster layer (note that we are always block-aligned)
  1837. * lock(nodelock)
  1838. * do cleanup
  1839. * unlock(nodelock)
  1840. * unlock(truncatelock)
  1841. */
  1842. fuse_trace_printf_vnop();
  1843. if (fuse_isdeadfs(vp)) {
  1844. if (!vnode_ischr(vp)) {
  1845. return EIO;
  1846. } else {
  1847. return 0;
  1848. }
  1849. }
  1850. if (!vnode_isreg(vp)) {
  1851. if (vnode_isdir(vp)) {
  1852. return EISDIR;
  1853. } else {
  1854. return EPERM;
  1855. }
  1856. }
  1857. /*
  1858. * if (uio_offset(uio) > SOME_MAXIMUM_SIZE) {
  1859. * return 0;
  1860. * }
  1861. */
  1862. orig_resid = uio_resid(uio);
  1863. if (orig_resid == 0) {
  1864. return 0;
  1865. }
  1866. orig_offset = uio_offset(uio);
  1867. if (orig_offset < 0) {
  1868. return EINVAL;
  1869. }
  1870. fvdat = VTOFUD(vp);
  1871. if (!fvdat) {
  1872. return EINVAL;
  1873. }
  1874. /* Protect against size change here. */
  1875. data = fuse_get_mpdata(vnode_mount(vp));
  1876. if (!fuse_isdirectio(vp)) {
  1877. if (fuse_isnoubc(vp)) {
  1878. /* In case we get here through a short cut (e.g. no open). */
  1879. ioflag |= IO_NOCACHE;
  1880. }
  1881. return cluster_read(vp, uio, fvdat->filesize, ioflag);
  1882. }
  1883. /* direct_io */
  1884. {
  1885. fufh_type_t fufh_type = FUFH_RDONLY;
  1886. struct fuse_dispatcher fdi;
  1887. struct fuse_filehandle *fufh = NULL;
  1888. struct fuse_read_in *fri = NULL;
  1889. off_t rounded_iolength;
  1890. fufh = &(fvdat->fufh[fufh_type]);
  1891. if (!FUFH_IS_VALID(fufh)) {
  1892. fufh_type = FUFH_RDWR;
  1893. fufh = &(fvdat->fufh[fufh_type]);
  1894. if (!FUFH_IS_VALID(fufh)) {
  1895. fufh = NULL;
  1896. } else {
  1897. /* Read falling back to FUFH_RDWR. */
  1898. }
  1899. }
  1900. if (!fufh) {
  1901. /* Failing direct I/O because of no fufh. */
  1902. return EIO;
  1903. } else {
  1904. /* Using existing fufh of type fufh_type. */
  1905. }
  1906. rounded_iolength = (off_t)round_page_64(uio_offset(uio) +
  1907. uio_resid(uio));
  1908. fdisp_init(&fdi, 0);
  1909. while (uio_resid(uio) > 0) {
  1910. fdi.iosize = sizeof(*fri);
  1911. fdisp_make_vp(&fdi, FUSE_READ, vp, context);
  1912. fri = fdi.indata;
  1913. fri->fh = fufh->fh_id;
  1914. fri->offset = uio_offset(uio);
  1915. fri->size = (uint32_t)min((size_t)uio_resid(uio), data->iosize);
  1916. if ((err = fdisp_wait_answ(&fdi))) {
  1917. return err;
  1918. }
  1919. if ((err = uiomove(fdi.answ, (int)min(fri->size, fdi.iosize),
  1920. uio))) {
  1921. break;
  1922. }
  1923. if (fdi.iosize < fri->size) {
  1924. err = -1;
  1925. break;
  1926. }
  1927. }
  1928. fuse_ticket_drop(fdi.tick);
  1929. } /* direct_io */
  1930. return ((err == -1) ? 0 : err);
  1931. }
  1932. /*
  1933. struct vnop_readdir_args {
  1934. struct vnodeop_desc *a_desc;
  1935. vnode_t a_vp;
  1936. struct uio *a_uio;
  1937. int a_flags;
  1938. int *a_eofflag;
  1939. int *a_numdirent;
  1940. vfs_context_t a_context;
  1941. };
  1942. */
  1943. FUSE_VNOP_EXPORT
  1944. int
  1945. fuse_vnop_readdir(struct vnop_readdir_args *ap)
  1946. {
  1947. vnode_t vp = ap->a_vp;
  1948. uio_t uio = ap->a_uio;
  1949. int flags = ap->a_flags;
  1950. __unused int *eofflagPtr = ap->a_eofflag;
  1951. int *numdirentPtr = ap->a_numdirent;
  1952. vfs_context_t context = ap->a_context;
  1953. struct fuse_filehandle *fufh = NULL;
  1954. struct fuse_vnode_data *fvdat;
  1955. struct fuse_iov cookediov;
  1956. int err = 0;
  1957. int freefufh = 0;
  1958. fuse_trace_printf_vnop();
  1959. if (fuse_isdeadfs(vp)) {
  1960. return EBADF;
  1961. }
  1962. CHECK_BLANKET_DENIAL(vp, context, EPERM);
  1963. /* No cookies yet. */
  1964. if (flags & (VNODE_READDIR_REQSEEKOFF | VNODE_READDIR_EXTENDED)) {
  1965. return EINVAL;
  1966. }
  1967. #define DE_SIZE (int)(sizeof(struct fuse_dirent))
  1968. if ((uio_iovcnt(uio) > 1) ||
  1969. (uio_resid(uio) < (user_ssize_t)DE_SIZE)) {
  1970. return EINVAL;
  1971. }
  1972. /*
  1973. * if ((uio_offset(uio) % DE_SIZE) != 0) { ...
  1974. */
  1975. fvdat = VTOFUD(vp);
  1976. fufh = &(fvdat->fufh[FUFH_RDONLY]);
  1977. if (!FUFH_IS_VALID(fufh)) {
  1978. err = fuse_filehandle_get(vp, context, FUFH_RDONLY, 0 /* mode */);
  1979. if (err) {
  1980. IOLog("MacFUSE: filehandle_get failed in readdir (err=%d)\n", err);
  1981. return err;
  1982. }
  1983. freefufh = 1;
  1984. } else {
  1985. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_reuse_count);
  1986. }
  1987. #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1)
  1988. fiov_init(&cookediov, DIRCOOKEDSIZE);
  1989. err = fuse_internal_readdir(vp, uio, context, fufh, &cookediov,
  1990. numdirentPtr);
  1991. fiov_teardown(&cookediov);
  1992. if (freefufh) {
  1993. FUFH_USE_DEC(fufh);
  1994. (void)fuse_filehandle_put(vp, context, FUFH_RDONLY,
  1995. FUSE_OP_FOREGROUNDED);
  1996. }
  1997. fuse_invalidate_attr(vp);
  1998. return err;
  1999. }
  2000. /*
  2001. struct vnop_readlink_args {
  2002. struct vnodeop_desc *a_desc;
  2003. vnode_t a_vp;
  2004. struct uio *a_uio;
  2005. vfs_context_t a_context;
  2006. };
  2007. */
  2008. FUSE_VNOP_EXPORT
  2009. int
  2010. fuse_vnop_readlink(struct vnop_readlink_args *ap)
  2011. {
  2012. vnode_t vp = ap->a_vp;
  2013. uio_t uio = ap->a_uio;
  2014. vfs_context_t context = ap->a_context;
  2015. struct fuse_dispatcher fdi;
  2016. int err;
  2017. fuse_trace_printf_vnop();
  2018. if (fuse_isdeadfs(vp)) {
  2019. return EBADF;
  2020. }
  2021. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  2022. if (!vnode_islnk(vp)) {
  2023. return EINVAL;
  2024. }
  2025. if ((err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, context))) {
  2026. return err;
  2027. }
  2028. if (((char *)fdi.answ)[0] == '/' &&
  2029. fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_JAIL_SYMLINKS) {
  2030. char *mpth = vfs_statfs(vnode_mount(vp))->f_mntonname;
  2031. err = uiomove(mpth, (int)strlen(mpth), uio);
  2032. }
  2033. if (!err) {
  2034. err = uiomove(fdi.answ, (int)fdi.iosize, uio);
  2035. }
  2036. fuse_ticket_drop(fdi.tick);
  2037. fuse_invalidate_attr(vp);
  2038. return err;
  2039. }
  2040. /*
  2041. struct vnop_reclaim_args {
  2042. struct vnodeop_desc *a_desc;
  2043. vnode_t a_vp;
  2044. vfs_context_t a_context;
  2045. };
  2046. */
  2047. FUSE_VNOP_EXPORT
  2048. int
  2049. fuse_vnop_reclaim(struct vnop_reclaim_args *ap)
  2050. {
  2051. vnode_t vp = ap->a_vp;
  2052. vfs_context_t context = ap->a_context;
  2053. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  2054. struct fuse_filehandle *fufh = NULL;
  2055. int type;
  2056. HNodeRef hn;
  2057. fuse_trace_printf_vnop();
  2058. if (!fvdat) {
  2059. panic("MacFUSE: no vnode data during recycling");
  2060. }
  2061. /*
  2062. * Cannot do early bail out on a dead file system in this case.
  2063. */
  2064. for (type = 0; type < FUFH_MAXTYPE; type++) {
  2065. fufh = &(fvdat->fufh[type]);
  2066. if (FUFH_IS_VALID(fufh)) {
  2067. int open_count = fufh->open_count;
  2068. int aux_count = fufh->aux_count;
  2069. FUFH_USE_RESET(fufh);
  2070. if (vfs_isforce(vnode_mount(vp))) {
  2071. (void)fuse_filehandle_put(vp, context, type,
  2072. FUSE_OP_FOREGROUNDED);
  2073. } else {
  2074. /*
  2075. * This is not a forced unmount. So why is the vnode being
  2076. * reclaimed if a fufh is valid? Well...
  2077. *
  2078. * One reason is that we are dead.
  2079. *
  2080. * Another reason is an unmount-time vlush race with ongoing
  2081. * vnops. Typically happens for a VDIR here.
  2082. *
  2083. * More often, the following happened:
  2084. *
  2085. * open()
  2086. * mmap()
  2087. * close()
  2088. * pagein... read... strategy
  2089. * done... reclaim
  2090. */
  2091. if (!fuse_isdeadfs(vp)) {
  2092. /*
  2093. * Miselading symptoms (can be seen at unmount time):
  2094. *
  2095. * open
  2096. * close
  2097. * inactive
  2098. * open
  2099. * reclaim <--
  2100. *
  2101. */
  2102. if (open_count != aux_count) {
  2103. #if M_MACFUSE_ENABLE_UNSUPPORTED
  2104. const char *vname = vnode_getname(vp);
  2105. IOLog("MacFUSE: vnode reclaimed with valid fufh "
  2106. "(%s type=%d, vtype=%d, open_count=%d, busy=%d, "
  2107. "aux_count=%d)\n",
  2108. (vname) ? vname : "?", type, vnode_vtype(vp),
  2109. open_count, vnode_isinuse(vp, 0), aux_count);
  2110. if (vname) {
  2111. vnode_putname(vname);
  2112. }
  2113. #else
  2114. IOLog("MacFUSE: vnode reclaimed with valid fufh "
  2115. "(type=%d, vtype=%d, open_count=%d, busy=%d, "
  2116. "aux_count=%d)\n",
  2117. type, vnode_vtype(vp), open_count,
  2118. vnode_isinuse(vp, 0), aux_count);
  2119. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  2120. } /* if counts did not match (both=1 for match currently) */
  2121. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_zombies);
  2122. } /* !deadfs */
  2123. (void)fuse_filehandle_put(vp, context, type,
  2124. FUSE_OP_FOREGROUNDED);
  2125. } /* !forced unmount */
  2126. } /* valid fufh */
  2127. } /* fufh loop */
  2128. if ((!fuse_isdeadfs(vp)) && (fvdat->nlookup)) {
  2129. struct fuse_dispatcher fdi;
  2130. fdi.tick = NULL;
  2131. fuse_internal_forget_send(vnode_mount(vp), context, VTOI(vp),
  2132. fvdat->nlookup, &fdi);
  2133. }
  2134. fuse_vncache_purge(vp);
  2135. hn = HNodeFromVNode(vp);
  2136. if (HNodeDetachVNode(hn, vp)) {
  2137. FSNodeScrub(fvdat);
  2138. HNodeScrubDone(hn);
  2139. FUSE_OSAddAtomic(-1, (SInt32 *)&fuse_vnodes_current);
  2140. }
  2141. return 0;
  2142. }
  2143. /*
  2144. struct vnop_remove_args {
  2145. struct vnodeop_desc *a_desc;
  2146. vnode_t a_dvp;
  2147. vnode_t a_vp;
  2148. struct componentname *a_cnp;
  2149. int a_flags;
  2150. vfs_context_t a_context;
  2151. };
  2152. */
  2153. FUSE_VNOP_EXPORT
  2154. int
  2155. fuse_vnop_remove(struct vnop_remove_args *ap)
  2156. {
  2157. vnode_t dvp = ap->a_dvp;
  2158. vnode_t vp = ap->a_vp;
  2159. struct componentname *cnp = ap->a_cnp;
  2160. int flags = ap->a_flags;
  2161. vfs_context_t context = ap->a_context;
  2162. int err;
  2163. fuse_trace_printf_vnop();
  2164. if (fuse_isdeadfs_fs(vp)) {
  2165. panic("MacFUSE: fuse_vnop_remove(): called on a dead file system");
  2166. }
  2167. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  2168. if (vnode_isdir(vp)) {
  2169. return EPERM;
  2170. }
  2171. /* Check for Carbon delete semantics. */
  2172. if ((flags & VNODE_REMOVE_NODELETEBUSY) && vnode_isinuse(vp, 0)) {
  2173. return EBUSY;
  2174. }
  2175. fuse_vncache_purge(vp);
  2176. err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK, context);
  2177. if (err == 0) {
  2178. FUSE_KNOTE(vp, NOTE_DELETE);
  2179. FUSE_KNOTE(dvp, NOTE_WRITE);
  2180. fuse_vncache_purge(vp);
  2181. fuse_invalidate_attr(dvp);
  2182. /*
  2183. * If we really want, we could...
  2184. * if (!vnode_isinuse(vp, 0)) {
  2185. * vnode_recycle(vp);
  2186. * }
  2187. */
  2188. }
  2189. return err;
  2190. }
  2191. #if M_MACFUSE_ENABLE_XATTR
  2192. /*
  2193. struct vnop_removexattr_args {
  2194. struct vnodeop_desc *a_desc;
  2195. vnode_t a_vp;
  2196. char *a_name;
  2197. int a_options;
  2198. vfs_context_t a_context;
  2199. };
  2200. */
  2201. FUSE_VNOP_EXPORT
  2202. int
  2203. fuse_vnop_removexattr(struct vnop_removexattr_args *ap)
  2204. {
  2205. vnode_t vp = ap->a_vp;
  2206. const char *name = ap->a_name;
  2207. vfs_context_t context = ap->a_context;
  2208. struct fuse_dispatcher fdi;
  2209. struct fuse_data *data;
  2210. mount_t mp;
  2211. size_t namelen;
  2212. int err = 0;
  2213. fuse_trace_printf_vnop();
  2214. if (fuse_isdeadfs(vp)) {
  2215. return EBADF;
  2216. }
  2217. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  2218. if (name == NULL || name[0] == '\0') {
  2219. return EINVAL; /* invalid name */
  2220. }
  2221. mp = vnode_mount(vp);
  2222. data = fuse_get_mpdata(mp);
  2223. if (fuse_skip_apple_xattr_mp(mp, name)) {
  2224. return EPERM;
  2225. }
  2226. if (data->dataflags & FSESS_AUTO_XATTR) {
  2227. return ENOTSUP;
  2228. }
  2229. if (!fuse_implemented(data, FSESS_NOIMPLBIT(REMOVEXATTR))) {
  2230. return ENOTSUP;
  2231. }
  2232. namelen = strlen(name);
  2233. fdisp_init(&fdi, namelen + 1);
  2234. fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, context);
  2235. memcpy((char *)fdi.indata, name, namelen);
  2236. ((char *)fdi.indata)[namelen] = '\0';
  2237. err = fdisp_wait_answ(&fdi);
  2238. if (!err) {
  2239. fuse_ticket_drop(fdi.tick);
  2240. VTOFUD(vp)->c_flag |= C_TOUCH_CHGTIME;
  2241. fuse_invalidate_attr(vp);
  2242. FUSE_KNOTE(vp, NOTE_ATTRIB);
  2243. } else {
  2244. if (err == ENOSYS) {
  2245. fuse_clear_implemented(data, FSESS_NOIMPLBIT(REMOVEXATTR));
  2246. return ENOTSUP;
  2247. }
  2248. }
  2249. return err;
  2250. }
  2251. #endif /* M_MACFUSE_ENABLE_XATTR */
  2252. /*
  2253. struct vnop_rename_args {
  2254. struct vnodeop_desc *a_desc;
  2255. vnode_t a_fdvp;
  2256. vnode_t a_fvp;
  2257. struct componentname *a_fcnp;
  2258. vnode_t a_tdvp;
  2259. vnode_t a_tvp;
  2260. struct componentname *a_tcnp;
  2261. vfs_context_t a_context;
  2262. };
  2263. */
  2264. FUSE_VNOP_EXPORT
  2265. int
  2266. fuse_vnop_rename(struct vnop_rename_args *ap)
  2267. {
  2268. vnode_t fdvp = ap->a_fdvp;
  2269. vnode_t fvp = ap->a_fvp;
  2270. struct componentname *fcnp = ap->a_fcnp;
  2271. vnode_t tdvp = ap->a_tdvp;
  2272. vnode_t tvp = ap->a_tvp;
  2273. struct componentname *tcnp = ap->a_tcnp;
  2274. vfs_context_t context = ap->a_context;
  2275. int err = 0;
  2276. fuse_trace_printf_vnop_novp();
  2277. if (fuse_isdeadfs_fs(fdvp)) {
  2278. panic("MacFUSE: fuse_vnop_rename(): called on a dead file system");
  2279. }
  2280. CHECK_BLANKET_DENIAL(fdvp, context, ENOENT);
  2281. fuse_vncache_purge(fvp);
  2282. err = fuse_internal_rename(fdvp, fvp, fcnp, tdvp, tvp, tcnp, ap->a_context);
  2283. if (err == 0) {
  2284. FUSE_KNOTE(fdvp, NOTE_WRITE);
  2285. fuse_invalidate_attr(fdvp);
  2286. if (tdvp != fdvp) {
  2287. fuse_invalidate_attr(tdvp);
  2288. FUSE_KNOTE(tdvp, NOTE_WRITE);
  2289. }
  2290. }
  2291. if (tvp != NULLVP) {
  2292. if (tvp != fvp) {
  2293. fuse_vncache_purge(tvp);
  2294. FUSE_KNOTE(tvp, NOTE_DELETE);
  2295. }
  2296. if (err == 0) {
  2297. /*
  2298. * If we want the file to just "disappear" from the standpoint
  2299. * of those who might have it open, we can do a revoke/recycle
  2300. * here. Otherwise, don't do anything. Only doing a recycle will
  2301. * make our fufh-checking code in reclaim unhappy, leading us to
  2302. * proactively panic.
  2303. */
  2304. /*
  2305. * 1. revoke
  2306. * 2. recycle
  2307. */
  2308. }
  2309. }
  2310. if (vnode_isdir(fvp)) {
  2311. if ((tvp != NULLVP) && vnode_isdir(tvp)) {
  2312. fuse_vncache_purge(tdvp);
  2313. }
  2314. fuse_vncache_purge(fdvp);
  2315. }
  2316. if (err == 0) {
  2317. FUSE_KNOTE(fvp, NOTE_RENAME);
  2318. }
  2319. return err;
  2320. }
  2321. /*
  2322. * struct vnop_revoke_args {
  2323. * struct vnodeop_desc *a_desc;
  2324. * vnode_t a_vp;
  2325. * int a_flags;
  2326. * vfs_context_t a_context;
  2327. * };
  2328. */
  2329. FUSE_VNOP_EXPORT
  2330. int
  2331. fuse_vnop_revoke(struct vnop_revoke_args *ap)
  2332. {
  2333. vnode_t vp = ap->a_vp;
  2334. vfs_context_t context = ap->a_context;
  2335. fuse_trace_printf_vnop();
  2336. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  2337. return fuse_internal_revoke(ap->a_vp, ap->a_flags, ap->a_context, 1);
  2338. }
  2339. /*
  2340. struct vnop_rmdir_args {
  2341. struct vnodeop_desc *a_desc;
  2342. vnode_t a_dvp;
  2343. vnode_t a_vp;
  2344. struct componentname *a_cnp;
  2345. vfs_context_t a_context;
  2346. };
  2347. */
  2348. FUSE_VNOP_EXPORT
  2349. int
  2350. fuse_vnop_rmdir(struct vnop_rmdir_args *ap)
  2351. {
  2352. vnode_t dvp = ap->a_dvp;
  2353. vnode_t vp = ap->a_vp;
  2354. struct componentname *cnp = ap->a_cnp;
  2355. vfs_context_t context = ap->a_context;
  2356. int err;
  2357. fuse_trace_printf_vnop();
  2358. if (fuse_isdeadfs_fs(vp)) {
  2359. panic("MacFUSE: fuse_vnop_rmdir(): called on a dead file system");
  2360. }
  2361. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  2362. if (VTOFUD(vp) == VTOFUD(dvp)) {
  2363. return EINVAL;
  2364. }
  2365. fuse_vncache_purge(vp);
  2366. err = fuse_internal_remove(dvp, vp, cnp, FUSE_RMDIR, context);
  2367. if (err == 0) {
  2368. fuse_invalidate_attr(dvp);
  2369. FUSE_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
  2370. FUSE_KNOTE(vp, NOTE_DELETE);
  2371. }
  2372. return err;
  2373. }
  2374. /*
  2375. struct vnop_select_args {
  2376. struct vnodeop_desc *a_desc;
  2377. vnode_t a_vp;
  2378. int a_which;
  2379. int a_fflags;
  2380. void *a_wql;
  2381. vfs_context_t a_context;
  2382. };
  2383. */
  2384. FUSE_VNOP_EXPORT
  2385. int
  2386. fuse_vnop_select(__unused struct vnop_select_args *ap)
  2387. {
  2388. fuse_trace_printf_vnop_novp();
  2389. return 1;
  2390. }
  2391. /*
  2392. struct vnop_setattr_args {
  2393. struct vnodeop_desc *a_desc;
  2394. vnode_t a_vp;
  2395. struct vnode_attr *a_vap;
  2396. vfs_context_t a_context;
  2397. };
  2398. */
  2399. FUSE_VNOP_EXPORT
  2400. int
  2401. fuse_vnop_setattr(struct vnop_setattr_args *ap)
  2402. {
  2403. vnode_t vp = ap->a_vp;
  2404. struct vnode_attr *vap = ap->a_vap;
  2405. vfs_context_t context = ap->a_context;
  2406. struct fuse_dispatcher fdi;
  2407. struct fuse_setattr_in *fsai;
  2408. int err = 0;
  2409. enum vtype vtyp;
  2410. int sizechanged = 0;
  2411. uint64_t newsize = 0;
  2412. fuse_trace_printf_vnop();
  2413. /*
  2414. * XXX: Locking
  2415. *
  2416. * We need to worry about the file size changing in setattr(). If the call
  2417. * is indeed altering the size, then:
  2418. *
  2419. * lock_exclusive(truncatelock)
  2420. * lock(nodelock)
  2421. * set the new size
  2422. * unlock(nodelock)
  2423. * adjust ubc
  2424. * lock(nodelock)
  2425. * do cleanup
  2426. * unlock(nodelock)
  2427. * unlock(truncatelock)
  2428. * ...
  2429. */
  2430. if (fuse_isdeadfs(vp)) {
  2431. return EBADF;
  2432. }
  2433. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  2434. fdisp_init(&fdi, sizeof(*fsai));
  2435. fdisp_make_vp(&fdi, FUSE_SETATTR, vp, context);
  2436. fsai = fdi.indata;
  2437. sizechanged = fuse_internal_attr_vat2fsai(vnode_mount(vp), vp, vap,
  2438. fsai, &newsize);
  2439. if (!fsai->valid) {
  2440. goto out;
  2441. }
  2442. vtyp = vnode_vtype(vp);
  2443. if (fsai->valid & FATTR_SIZE && vtyp == VDIR) {
  2444. err = EISDIR;
  2445. goto out;
  2446. }
  2447. if (vnode_vfsisrdonly(vp) && (fsai->valid & ~FATTR_SIZE || vtyp == VREG)) {
  2448. err = EROFS;
  2449. goto out;
  2450. }
  2451. if ((err = fdisp_wait_answ(&fdi))) {
  2452. fuse_invalidate_attr(vp);
  2453. return err;
  2454. }
  2455. vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode);
  2456. if (vnode_vtype(vp) != vtyp) {
  2457. if ((vnode_vtype(vp) == VNON) && (vtyp != VNON)) {
  2458. /* What just happened here? */
  2459. } else {
  2460. /*
  2461. * STALE vnode, ditch
  2462. *
  2463. * The vnode has changed its type "behind our back". There's
  2464. * nothing really we can do, so let us just force an internal
  2465. * revocation and tell the caller to try again, if interested.
  2466. */
  2467. fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT);
  2468. err = EAGAIN;
  2469. }
  2470. }
  2471. if (!err) {
  2472. if (sizechanged) {
  2473. fuse_invalidate_attr(vp);
  2474. } else {
  2475. cache_attrs(vp, (struct fuse_attr_out *)fdi.answ);
  2476. if (fsai->valid & FATTR_BKUPTIME || fsai->valid & FATTR_CRTIME) {
  2477. VTOFUD(vp)->c_flag &= ~C_XTIMES_VALID;
  2478. }
  2479. }
  2480. }
  2481. out:
  2482. fuse_ticket_drop(fdi.tick);
  2483. if (!err && sizechanged) {
  2484. VTOFUD(vp)->filesize = newsize;
  2485. ubc_setsize(vp, (off_t)newsize);
  2486. }
  2487. if (err == 0) {
  2488. FUSE_KNOTE(vp, NOTE_ATTRIB);
  2489. }
  2490. return err;
  2491. }
  2492. #if M_MACFUSE_ENABLE_XATTR
  2493. /*
  2494. struct vnop_setxattr_args {
  2495. struct vnodeop_desc *a_desc;
  2496. vnode_t a_vp;
  2497. char *a_name;
  2498. uio_t a_uio;
  2499. int a_options;
  2500. vfs_context_t a_context;
  2501. };
  2502. */
  2503. FUSE_VNOP_EXPORT
  2504. int
  2505. fuse_vnop_setxattr(struct vnop_setxattr_args *ap)
  2506. {
  2507. vnode_t vp = ap->a_vp;
  2508. const char *name = ap->a_name;
  2509. uio_t uio = ap->a_uio;
  2510. vfs_context_t context = ap->a_context;
  2511. struct fuse_dispatcher fdi;
  2512. struct fuse_setxattr_in *fsxi;
  2513. struct fuse_data *data;
  2514. user_addr_t a_baseaddr[FUSE_UIO_BACKUP_MAX];
  2515. user_size_t a_length[FUSE_UIO_BACKUP_MAX];
  2516. mount_t mp;
  2517. int err = 0;
  2518. int iov_err = 0;
  2519. int i, iov_cnt;
  2520. size_t namelen;
  2521. size_t attrsize;
  2522. off_t saved_offset;
  2523. fuse_trace_printf_vnop();
  2524. if (fuse_isdeadfs(vp)) {
  2525. return EBADF;
  2526. }
  2527. CHECK_BLANKET_DENIAL(vp, context, ENOENT);
  2528. if (name == NULL || name[0] == '\0') {
  2529. return EINVAL;
  2530. }
  2531. mp = vnode_mount(vp);
  2532. data = fuse_get_mpdata(mp);
  2533. if (fuse_skip_apple_xattr_mp(mp, name)) {
  2534. return EPERM;
  2535. }
  2536. if (data->dataflags & FSESS_AUTO_XATTR) {
  2537. return ENOTSUP;
  2538. }
  2539. if (!fuse_implemented(data, FSESS_NOIMPLBIT(SETXATTR))) {
  2540. return ENOTSUP;
  2541. }
  2542. attrsize = (size_t)uio_resid(uio);
  2543. saved_offset = uio_offset(uio);
  2544. iov_cnt = uio_iovcnt(uio);
  2545. if (iov_cnt > FUSE_UIO_BACKUP_MAX) {
  2546. /* no need to make it more complicated */
  2547. iov_cnt = FUSE_UIO_BACKUP_MAX;
  2548. }
  2549. for (i = 0; i < iov_cnt; i++) {
  2550. iov_err = uio_getiov(uio, i, &(a_baseaddr[i]), &(a_length[i]));
  2551. }
  2552. /*
  2553. * Check attrsize for some sane maximum: otherwise, we can fail malloc()
  2554. * in fdisp_make_vp().
  2555. */
  2556. if (attrsize > data->userkernel_bufsize) {
  2557. return E2BIG;
  2558. }
  2559. namelen = strlen(name);
  2560. fdisp_init(&fdi, sizeof(*fsxi) + namelen + 1 + attrsize);
  2561. err = fdisp_make_vp_canfail(&fdi, FUSE_SETXATTR, vp, ap->a_context);
  2562. if (err) {
  2563. IOLog("MacFUSE: setxattr failed for too large attribute (%lu)\n",
  2564. attrsize);
  2565. return ERANGE;
  2566. }
  2567. fsxi = fdi.indata;
  2568. fsxi->size = (uint32_t)attrsize;
  2569. fsxi->flags = ap->a_options;
  2570. fsxi->position = (uint32_t)saved_offset;
  2571. if (attrsize > FUSE_REASONABLE_XATTRSIZE) {
  2572. fticket_set_killl(fdi.tick);
  2573. }
  2574. memcpy((char *)fdi.indata + sizeof(*fsxi), name, namelen);
  2575. ((char *)fdi.indata)[sizeof(*fsxi) + namelen] = '\0';
  2576. err = uiomove((char *)fdi.indata + sizeof(*fsxi) + namelen + 1,
  2577. (int)attrsize, uio);
  2578. if (!err) {
  2579. err = fdisp_wait_answ(&fdi);
  2580. }
  2581. if (!err) {
  2582. fuse_ticket_drop(fdi.tick);
  2583. fuse_invalidate_attr(vp);
  2584. FUSE_KNOTE(vp, NOTE_ATTRIB);
  2585. VTOFUD(vp)->c_flag |= C_TOUCH_CHGTIME;
  2586. } else {
  2587. if ((err == ENOSYS) || (err == ENOTSUP)) {
  2588. int a_spacetype = UIO_USERSPACE;
  2589. if (err == ENOSYS) {
  2590. fuse_clear_implemented(data, FSESS_NOIMPLBIT(SETXATTR));
  2591. }
  2592. if (iov_err) {
  2593. return EAGAIN;
  2594. }
  2595. if (!uio_isuserspace(uio)) {
  2596. a_spacetype = UIO_SYSSPACE;
  2597. }
  2598. uio_reset(uio, saved_offset, a_spacetype, uio_rw(uio));
  2599. for (i = 0; i < iov_cnt; i++) {
  2600. uio_addiov(uio, CAST_USER_ADDR_T(a_baseaddr[i]), a_length[i]);
  2601. }
  2602. return ENOTSUP;
  2603. }
  2604. }
  2605. return err;
  2606. }
  2607. #endif /* M_MACFUSE_ENABLE_XATTR */
  2608. /*
  2609. struct vnop_strategy_args {
  2610. struct vnodeop_desc *a_desc;
  2611. struct buf *a_bp;
  2612. };
  2613. */
  2614. FUSE_VNOP_EXPORT
  2615. int
  2616. fuse_vnop_strategy(struct vnop_strategy_args *ap)
  2617. {
  2618. buf_t bp = ap->a_bp;
  2619. vnode_t vp = buf_vnode(bp);
  2620. fuse_trace_printf_vnop();
  2621. if (!vp || fuse_isdeadfs(vp)) {
  2622. buf_seterror(bp, EIO);
  2623. buf_biodone(bp);
  2624. return EIO;
  2625. }
  2626. return fuse_internal_strategy_buf(ap);
  2627. }
  2628. /*
  2629. struct vnop_symlink_args {
  2630. struct vnodeop_desc *a_desc;
  2631. vnode_t a_dvp;
  2632. vnode_t *a_vpp;
  2633. struct componentname *a_cnp;
  2634. struct vnode_attr *a_vap;
  2635. char *a_target;
  2636. vfs_context_t a_context;
  2637. };
  2638. */
  2639. FUSE_VNOP_EXPORT
  2640. int
  2641. fuse_vnop_symlink(struct vnop_symlink_args *ap)
  2642. {
  2643. vnode_t dvp = ap->a_dvp;
  2644. vnode_t *vpp = ap->a_vpp;
  2645. struct componentname *cnp = ap->a_cnp;
  2646. char *target = ap->a_target;
  2647. vfs_context_t context = ap->a_context;
  2648. struct fuse_dispatcher fdi;
  2649. int err;
  2650. size_t len;
  2651. fuse_trace_printf_vnop_novp();
  2652. if (fuse_isdeadfs_fs(dvp)) {
  2653. panic("MacFUSE: fuse_vnop_symlink(): called on a dead file system");
  2654. }
  2655. CHECK_BLANKET_DENIAL(dvp, context, EPERM);
  2656. len = strlen(target) + 1;
  2657. fdisp_init(&fdi, len + cnp->cn_namelen + 1);
  2658. fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, context);
  2659. memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
  2660. ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
  2661. memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len);
  2662. /* XXX: Need to take vap into account. */
  2663. err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi, context);
  2664. if (err == 0) {
  2665. fuse_invalidate_attr(dvp);
  2666. FUSE_KNOTE(dvp, NOTE_WRITE);
  2667. }
  2668. return err;
  2669. }
  2670. /*
  2671. struct vnop_write_args {
  2672. struct vnodeop_desc *a_desc;
  2673. vnode_t a_vp;
  2674. struct uio *a_uio;
  2675. int a_ioflag;
  2676. vfs_context_t a_context;
  2677. };
  2678. */
  2679. FUSE_VNOP_EXPORT
  2680. int
  2681. fuse_vnop_write(struct vnop_write_args *ap)
  2682. {
  2683. vnode_t vp = ap->a_vp;
  2684. uio_t uio = ap->a_uio;
  2685. int ioflag = ap->a_ioflag;
  2686. vfs_context_t context = ap->a_context;
  2687. int error = 0;
  2688. int lflag;
  2689. off_t offset;
  2690. off_t zero_off;
  2691. off_t filesize;
  2692. off_t original_offset;
  2693. off_t original_size;
  2694. user_ssize_t original_resid;
  2695. struct fuse_vnode_data *fvdat;
  2696. /*
  2697. * XXX: Locking
  2698. *
  2699. * lock_shared(truncatelock)
  2700. * lock(nodelock)
  2701. * if (file is being extended) {
  2702. * unlock(nodelock)
  2703. * unlock(truncatelock)
  2704. * lock_exclusive(truncatelock)
  2705. * lock(nodelock)
  2706. * current_size = the file's current size
  2707. * }
  2708. * if (file is being extended) { // check again
  2709. * // do whatever needs to be done to allocate storage
  2710. * }
  2711. * // We are always block-aligned
  2712. * unlock(nodelock)
  2713. * call the cluster layer
  2714. * adjust ubc
  2715. * lock(nodelock)
  2716. * do cleanup
  2717. * unlock(nodelock)
  2718. * unlock(truncatelock)
  2719. */
  2720. fuse_trace_printf_vnop();
  2721. if (fuse_isdeadfs(vp)) {
  2722. return EIO;
  2723. }
  2724. fvdat = VTOFUD(vp);
  2725. switch (vnode_vtype(vp)) {
  2726. case VREG:
  2727. break;
  2728. case VDIR:
  2729. return EISDIR;
  2730. default:
  2731. return EPERM; /* or EINVAL? panic? */
  2732. }
  2733. original_resid = uio_resid(uio);
  2734. original_offset = uio_offset(uio);
  2735. offset = original_offset;
  2736. if (original_resid == 0) {
  2737. return E_NONE;
  2738. }
  2739. if (original_offset < 0) {
  2740. return EINVAL;
  2741. }
  2742. if (fuse_isdirectio(vp)) { /* direct_io */
  2743. fufh_type_t fufh_type = FUFH_WRONLY;
  2744. struct fuse_dispatcher fdi;
  2745. struct fuse_filehandle *fufh = NULL;
  2746. struct fuse_write_in *fwi = NULL;
  2747. struct fuse_write_out *fwo = NULL;
  2748. struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
  2749. size_t chunksize;
  2750. off_t diff;
  2751. fufh = &(fvdat->fufh[fufh_type]);
  2752. if (!FUFH_IS_VALID(fufh)) {
  2753. fufh_type = FUFH_RDWR;
  2754. fufh = &(fvdat->fufh[fufh_type]);
  2755. if (!FUFH_IS_VALID(fufh)) {
  2756. fufh = NULL;
  2757. } else {
  2758. /* Write falling back to FUFH_RDWR. */
  2759. }
  2760. }
  2761. if (!fufh) {
  2762. /* Failing direct I/O because of no fufh. */
  2763. return EIO;
  2764. } else {
  2765. /* Using existing fufh of type fufh_type. */
  2766. }
  2767. fdisp_init(&fdi, 0);
  2768. while (uio_resid(uio) > 0) {
  2769. chunksize = min((size_t)uio_resid(uio), data->iosize);
  2770. fdi.iosize = sizeof(*fwi) + chunksize;
  2771. fdisp_make_vp(&fdi, FUSE_WRITE, vp, context);
  2772. fwi = fdi.indata;
  2773. fwi->fh = fufh->fh_id;
  2774. fwi->offset = uio_offset(uio);
  2775. fwi->size = (uint32_t)chunksize;
  2776. error = uiomove((char *)fdi.indata + sizeof(*fwi), (int)chunksize,
  2777. uio);
  2778. if (error) {
  2779. break;
  2780. }
  2781. error = fdisp_wait_answ(&fdi);
  2782. if (error) {
  2783. return error;
  2784. }
  2785. fwo = (struct fuse_write_out *)fdi.answ;
  2786. diff = chunksize - fwo->size;
  2787. if (diff < 0) {
  2788. error = EINVAL;
  2789. break;
  2790. }
  2791. uio_setresid(uio, (uio_resid(uio) + diff));
  2792. uio_setoffset(uio, (uio_offset(uio) - diff));
  2793. } /* while */
  2794. if (!error) {
  2795. fuse_invalidate_attr(vp);
  2796. }
  2797. fuse_ticket_drop(fdi.tick);
  2798. return error;
  2799. } /* direct_io */
  2800. /* !direct_io */
  2801. /* Be wary of a size change here. */
  2802. original_size = fvdat->filesize;
  2803. if (ioflag & IO_APPEND) {
  2804. /* Arrange for append */
  2805. uio_setoffset(uio, fvdat->filesize);
  2806. offset = fvdat->filesize;
  2807. }
  2808. if (offset < 0) {
  2809. return EFBIG;
  2810. }
  2811. #if M_MACFUSE_EXPERIMENTAL_JUNK
  2812. if (original_resid == 0) {
  2813. return 0;
  2814. }
  2815. if (offset + original_resid > /* some maximum file size */) {
  2816. return EFBIG;
  2817. }
  2818. #endif
  2819. if (offset + original_resid > original_size) {
  2820. /* Need to extend the file. */
  2821. filesize = offset + original_resid;
  2822. fvdat->filesize = filesize;
  2823. } else {
  2824. /* Original size OK. */
  2825. filesize = original_size;
  2826. }
  2827. lflag = (ioflag & (IO_SYNC | IO_NOCACHE));
  2828. if (fuse_isnoubc(vp)) {
  2829. lflag |= (IO_SYNC | IO_NOCACHE);
  2830. } else if (vfs_issynchronous(vnode_mount(vp))) {
  2831. lflag |= IO_SYNC;
  2832. }
  2833. if (offset > original_size) {
  2834. zero_off = original_size;
  2835. lflag |= IO_HEADZEROFILL;
  2836. /* Zero-filling enabled. */
  2837. } else {
  2838. zero_off = 0;
  2839. }
  2840. error = cluster_write(vp, uio, (off_t)original_size, (off_t)filesize,
  2841. (off_t)zero_off, (off_t)0, lflag);
  2842. if (!error) {
  2843. if (uio_offset(uio) > original_size) {
  2844. /* Updating to new size. */
  2845. fvdat->filesize = uio_offset(uio);
  2846. ubc_setsize(vp, (off_t)fvdat->filesize);
  2847. FUSE_KNOTE(vp, NOTE_WRITE | NOTE_EXTEND);
  2848. } else {
  2849. fvdat->filesize = original_size;
  2850. FUSE_KNOTE(vp, NOTE_WRITE);
  2851. }
  2852. fuse_invalidate_attr(vp);
  2853. }
  2854. /*
  2855. * If original_resid > uio_resid(uio), we could set an internal
  2856. * flag bit to "update" (e.g., dep->de_flag |= DE_UPDATE).
  2857. */
  2858. /*
  2859. * If the write failed and they want us to, truncate the file back
  2860. * to the size it was before the write was attempted.
  2861. */
  2862. /* errexit: */
  2863. if (error) {
  2864. if (ioflag & IO_UNIT) {
  2865. /*
  2866. * e.g.: detrunc(dep, original_size, ioflag & IO_SYNC, context);
  2867. */
  2868. uio_setoffset(uio, original_offset);
  2869. uio_setresid(uio, original_resid);
  2870. } else {
  2871. /*
  2872. * e.g.: detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, context);
  2873. */
  2874. if (uio_resid(uio) != original_resid) {
  2875. error = 0;
  2876. }
  2877. }
  2878. } else if (ioflag & IO_SYNC) {
  2879. /*
  2880. * e.g.: error = deupdat(dep, 1, context);
  2881. */
  2882. }
  2883. /*
  2884. if ((original_resid > uio_resid(uio)) &&
  2885. !fuse_vfs_context_issuser(context)) {
  2886. // clear setuid/setgid here
  2887. }
  2888. */
  2889. return error;
  2890. }
  2891. #if M_MACFUSE_ENABLE_FIFOFS
  2892. /* fifofs */
  2893. FUSE_VNOP_EXPORT
  2894. int
  2895. fuse_fifo_vnop_close(struct vnop_close_args *ap)
  2896. {
  2897. if (vnode_isinuse(ap->a_vp, 1)) {
  2898. /* XXX: TBD */
  2899. }
  2900. return fifo_close(ap);
  2901. }
  2902. FUSE_VNOP_EXPORT
  2903. int
  2904. fuse_fifo_vnop_read(struct vnop_read_args *ap)
  2905. {
  2906. VTOFUD(ap->a_vp)->c_flag |= C_TOUCH_ACCTIME;
  2907. return fifo_read(ap);
  2908. }
  2909. FUSE_VNOP_EXPORT
  2910. int
  2911. fuse_fifo_vnop_write(struct vnop_write_args *ap)
  2912. {
  2913. VTOFUD(ap->a_vp)->c_flag |= (C_TOUCH_CHGTIME | C_TOUCH_MODTIME);
  2914. return fifo_write(ap);
  2915. }
  2916. #endif /* M_MACFUSE_ENABLE_FIFOFS */
  2917. #if M_MACFUSE_ENABLE_SPECFS
  2918. /* specfs */
  2919. FUSE_VNOP_EXPORT
  2920. int
  2921. fuse_spec_vnop_close(struct vnop_close_args *ap)
  2922. {
  2923. if (vnode_isinuse(ap->a_vp, 1)) {
  2924. /* XXX: TBD */
  2925. }
  2926. return spec_close(ap);
  2927. }
  2928. FUSE_VNOP_EXPORT
  2929. int
  2930. fuse_spec_vnop_read(struct vnop_read_args *ap)
  2931. {
  2932. VTOFUD(ap->a_vp)->c_flag |= C_TOUCH_ACCTIME;
  2933. return spec_read(ap);
  2934. }
  2935. FUSE_VNOP_EXPORT
  2936. int
  2937. fuse_spec_vnop_write(struct vnop_write_args *ap)
  2938. {
  2939. VTOFUD(ap->a_vp)->c_flag |= (C_TOUCH_CHGTIME | C_TOUCH_MODTIME);
  2940. return spec_write(ap);
  2941. }
  2942. #endif /* M_MACFUSE_ENABLE_SPECFS */
  2943. struct vnodeopv_entry_desc fuse_vnode_operation_entries[] = {
  2944. { &vnop_access_desc, (fuse_vnode_op_t) fuse_vnop_access },
  2945. { &vnop_advlock_desc, (fuse_vnode_op_t) err_advlock },
  2946. // { &vnop_allocate_desc, (fuse_vnode_op_t) fuse_vnop_allocate },
  2947. { &vnop_blktooff_desc, (fuse_vnode_op_t) fuse_vnop_blktooff },
  2948. { &vnop_blockmap_desc, (fuse_vnode_op_t) fuse_vnop_blockmap },
  2949. // { &vnop_bwrite_desc, (fuse_vnode_op_t) fuse_vnop_bwrite },
  2950. { &vnop_close_desc, (fuse_vnode_op_t) fuse_vnop_close },
  2951. // { &vnop_copyfile_desc, (fuse_vnode_op_t) fuse_vnop_copyfile },
  2952. { &vnop_create_desc, (fuse_vnode_op_t) fuse_vnop_create },
  2953. { &vnop_default_desc, (fuse_vnode_op_t) vn_default_error },
  2954. { &vnop_exchange_desc, (fuse_vnode_op_t) fuse_vnop_exchange },
  2955. { &vnop_fsync_desc, (fuse_vnode_op_t) fuse_vnop_fsync },
  2956. { &vnop_getattr_desc, (fuse_vnode_op_t) fuse_vnop_getattr },
  2957. // { &vnop_getattrlist_desc, (fuse_vnode_op_t) fuse_vnop_getattrlist },
  2958. #if M_MACFUSE_ENABLE_XATTR
  2959. { &vnop_getxattr_desc, (fuse_vnode_op_t) fuse_vnop_getxattr },
  2960. #endif /* M_MACFUSE_ENABLE_XATTR */
  2961. { &vnop_inactive_desc, (fuse_vnode_op_t) fuse_vnop_inactive },
  2962. { &vnop_ioctl_desc, (fuse_vnode_op_t) fuse_vnop_ioctl },
  2963. { &vnop_link_desc, (fuse_vnode_op_t) fuse_vnop_link },
  2964. #if M_MACFUSE_ENABLE_XATTR
  2965. { &vnop_listxattr_desc, (fuse_vnode_op_t) fuse_vnop_listxattr },
  2966. #endif /* M_MACFUSE_ENABLE_XATTR */
  2967. { &vnop_lookup_desc, (fuse_vnode_op_t) fuse_vnop_lookup },
  2968. #if M_MACFUSE_ENABLE_KQUEUE
  2969. { &vnop_kqfilt_add_desc, (fuse_vnode_op_t) fuse_vnop_kqfilt_add },
  2970. { &vnop_kqfilt_remove_desc, (fuse_vnode_op_t) fuse_vnop_kqfilt_remove },
  2971. #endif /* M_MACFUSE_ENABLE_KQUEUE */
  2972. { &vnop_mkdir_desc, (fuse_vnode_op_t) fuse_vnop_mkdir },
  2973. { &vnop_mknod_desc, (fuse_vnode_op_t) fuse_vnop_mknod },
  2974. { &vnop_mmap_desc, (fuse_vnode_op_t) fuse_vnop_mmap },
  2975. { &vnop_mnomap_desc, (fuse_vnode_op_t) fuse_vnop_mnomap },
  2976. { &vnop_offtoblk_desc, (fuse_vnode_op_t) fuse_vnop_offtoblk },
  2977. { &vnop_open_desc, (fuse_vnode_op_t) fuse_vnop_open },
  2978. { &vnop_pagein_desc, (fuse_vnode_op_t) fuse_vnop_pagein },
  2979. { &vnop_pageout_desc, (fuse_vnode_op_t) fuse_vnop_pageout },
  2980. { &vnop_pathconf_desc, (fuse_vnode_op_t) fuse_vnop_pathconf },
  2981. { &vnop_read_desc, (fuse_vnode_op_t) fuse_vnop_read },
  2982. { &vnop_readdir_desc, (fuse_vnode_op_t) fuse_vnop_readdir },
  2983. // { &vnop_readdirattr_desc, (fuse_vnode_op_t) fuse_vnop_readdirattr },
  2984. { &vnop_readlink_desc, (fuse_vnode_op_t) fuse_vnop_readlink },
  2985. { &vnop_reclaim_desc, (fuse_vnode_op_t) fuse_vnop_reclaim },
  2986. { &vnop_remove_desc, (fuse_vnode_op_t) fuse_vnop_remove },
  2987. #if M_MACFUSE_ENABLE_XATTR
  2988. { &vnop_removexattr_desc, (fuse_vnode_op_t) fuse_vnop_removexattr },
  2989. #endif /* M_MACFUSE_ENABLE_XATTR */
  2990. { &vnop_rename_desc, (fuse_vnode_op_t) fuse_vnop_rename },
  2991. { &vnop_revoke_desc, (fuse_vnode_op_t) fuse_vnop_revoke },
  2992. { &vnop_rmdir_desc, (fuse_vnode_op_t) fuse_vnop_rmdir },
  2993. // { &vnop_searchfs_desc, (fuse_vnode_op_t) fuse_vnop_searchfs },
  2994. { &vnop_select_desc, (fuse_vnode_op_t) fuse_vnop_select },
  2995. { &vnop_setattr_desc, (fuse_vnode_op_t) fuse_vnop_setattr },
  2996. // { &vnop_setattrlist_desc, (fuse_vnode_op_t) fuse_vnop_setattrlist },
  2997. #if M_MACFUSE_ENABLE_XATTR
  2998. { &vnop_setxattr_desc, (fuse_vnode_op_t) fuse_vnop_setxattr },
  2999. #endif /* M_MACFUSE_ENABLE_XATTR */
  3000. { &vnop_strategy_desc, (fuse_vnode_op_t) fuse_vnop_strategy },
  3001. { &vnop_symlink_desc, (fuse_vnode_op_t) fuse_vnop_symlink },
  3002. // { &vnop_whiteout_desc, (fuse_vnode_op_t) fuse_vnop_whiteout },
  3003. { &vnop_write_desc, (fuse_vnode_op_t) fuse_vnop_write },
  3004. { NULL, NULL }
  3005. };
  3006. #if M_MACFUSE_ENABLE_FIFOFS
  3007. /* fifofs */
  3008. struct vnodeopv_entry_desc fuse_fifo_operation_entries[] = {
  3009. { &vnop_advlock_desc, (fuse_fifo_op_t)err_advlock },
  3010. { &vnop_blktooff_desc, (fuse_fifo_op_t)err_blktooff },
  3011. { &vnop_blockmap_desc, (fuse_fifo_op_t)err_blockmap },
  3012. { &vnop_bwrite_desc, (fuse_fifo_op_t)fifo_bwrite },
  3013. { &vnop_close_desc, (fuse_fifo_op_t)fuse_fifo_vnop_close }, // c
  3014. { &vnop_copyfile_desc, (fuse_fifo_op_t)err_copyfile },
  3015. { &vnop_create_desc, (fuse_fifo_op_t)fifo_create },
  3016. { &vnop_default_desc, (fuse_fifo_op_t)vn_default_error },
  3017. { &vnop_fsync_desc, (fuse_fifo_op_t)fuse_vnop_fsync },
  3018. { &vnop_getattr_desc, (fuse_fifo_op_t)fuse_vnop_getattr },
  3019. { &vnop_inactive_desc, (fuse_fifo_op_t)fuse_vnop_inactive },
  3020. { &vnop_ioctl_desc, (fuse_fifo_op_t)fifo_ioctl },
  3021. #if M_MACFUSE_ENABLE_KQUEUE
  3022. { &vnop_kqfilt_add_desc, (fuse_fifo_op_t)fuse_vnop_kqfilt_add },
  3023. { &vnop_kqfilt_remove_desc, (fuse_fifo_op_t)fuse_vnop_kqfilt_remove },
  3024. #endif
  3025. { &vnop_link_desc, (fuse_fifo_op_t)fifo_link },
  3026. { &vnop_lookup_desc, (fuse_fifo_op_t)fifo_lookup },
  3027. { &vnop_mkdir_desc, (fuse_fifo_op_t)fifo_mkdir },
  3028. { &vnop_mknod_desc, (fuse_fifo_op_t)fifo_mknod },
  3029. { &vnop_mmap_desc, (fuse_fifo_op_t)fifo_mmap },
  3030. { &vnop_offtoblk_desc, (fuse_fifo_op_t)err_offtoblk },
  3031. { &vnop_open_desc, (fuse_fifo_op_t)fifo_open },
  3032. { &vnop_pagein_desc, (fuse_fifo_op_t)fuse_vnop_pagein }, // n
  3033. { &vnop_pageout_desc, (fuse_fifo_op_t)fuse_vnop_pageout }, // n
  3034. { &vnop_pathconf_desc, (fuse_fifo_op_t)fifo_pathconf },
  3035. { &vnop_read_desc, (fuse_fifo_op_t)fuse_fifo_vnop_read }, // c
  3036. { &vnop_readdir_desc, (fuse_fifo_op_t)fifo_readdir },
  3037. { &vnop_readlink_desc, (fuse_fifo_op_t)fifo_readlink },
  3038. { &vnop_reclaim_desc, (fuse_fifo_op_t)fuse_vnop_reclaim }, // n
  3039. { &vnop_remove_desc, (fuse_fifo_op_t)fifo_remove },
  3040. { &vnop_rename_desc, (fuse_fifo_op_t)fifo_rename },
  3041. { &vnop_revoke_desc, (fuse_fifo_op_t)fifo_revoke },
  3042. { &vnop_rmdir_desc, (fuse_fifo_op_t)fifo_rmdir },
  3043. { &vnop_select_desc, (fuse_fifo_op_t)fifo_select },
  3044. { &vnop_setattr_desc, (fuse_fifo_op_t)fuse_vnop_setattr }, // n
  3045. { &vnop_strategy_desc, (fuse_fifo_op_t)fifo_strategy },
  3046. { &vnop_symlink_desc, (fuse_fifo_op_t)fifo_symlink },
  3047. { &vnop_write_desc, (fuse_fifo_op_t)fuse_fifo_vnop_write },
  3048. { (struct vnodeop_desc*)NULL, (fuse_fifo_op_t)NULL }
  3049. };
  3050. #endif /* M_MACFUSE_ENABLE_FIFOFS */
  3051. #if M_MACFUSE_ENABLE_SPECFS
  3052. /* specfs */
  3053. struct vnodeopv_entry_desc fuse_spec_operation_entries[] = {
  3054. { &vnop_advlock_desc, (fuse_spec_op_t)err_advlock },
  3055. { &vnop_blktooff_desc, (fuse_spec_op_t)fuse_vnop_blktooff }, // native
  3056. { &vnop_close_desc, (fuse_spec_op_t)fuse_spec_vnop_close }, // custom
  3057. { &vnop_copyfile_desc, (fuse_spec_op_t)err_copyfile },
  3058. { &vnop_create_desc, (fuse_spec_op_t)spec_create },
  3059. { &vnop_default_desc, (fuse_spec_op_t)vn_default_error },
  3060. { &vnop_fsync_desc, (fuse_spec_op_t)fuse_vnop_fsync }, // native
  3061. { &vnop_getattr_desc, (fuse_spec_op_t)fuse_vnop_getattr }, // native
  3062. { &vnop_inactive_desc, (fuse_spec_op_t)fuse_vnop_inactive }, // native
  3063. { &vnop_ioctl_desc, (fuse_spec_op_t)spec_ioctl },
  3064. { &vnop_link_desc, (fuse_spec_op_t)spec_link },
  3065. { &vnop_lookup_desc, (fuse_spec_op_t)spec_lookup },
  3066. { &vnop_mkdir_desc, (fuse_spec_op_t)spec_mkdir },
  3067. { &vnop_mknod_desc, (fuse_spec_op_t)spec_mknod },
  3068. { &vnop_mmap_desc, (fuse_spec_op_t)spec_mmap },
  3069. { &vnop_offtoblk_desc, (fuse_spec_op_t)fuse_vnop_offtoblk }, // native
  3070. { &vnop_open_desc, (fuse_spec_op_t)spec_open },
  3071. { &vnop_pagein_desc, (fuse_spec_op_t)fuse_vnop_pagein }, // native
  3072. { &vnop_pageout_desc, (fuse_spec_op_t)fuse_vnop_pageout }, // native
  3073. { &vnop_pathconf_desc, (fuse_spec_op_t)spec_pathconf },
  3074. { &vnop_read_desc, (fuse_spec_op_t)fuse_spec_vnop_read }, // custom
  3075. { &vnop_readdir_desc, (fuse_spec_op_t)spec_readdir },
  3076. { &vnop_readlink_desc, (fuse_spec_op_t)spec_readlink },
  3077. { &vnop_reclaim_desc, (fuse_spec_op_t)fuse_vnop_reclaim }, // native
  3078. { &vnop_remove_desc, (fuse_spec_op_t)spec_remove },
  3079. { &vnop_rename_desc, (fuse_spec_op_t)spec_rename },
  3080. { &vnop_revoke_desc, (fuse_spec_op_t)spec_revoke },
  3081. { &vnop_rmdir_desc, (fuse_spec_op_t)spec_rmdir },
  3082. { &vnop_select_desc, (fuse_spec_op_t)spec_select },
  3083. { &vnop_setattr_desc, (fuse_spec_op_t)fuse_vnop_setattr }, // native
  3084. { &vnop_strategy_desc, (fuse_spec_op_t)spec_strategy },
  3085. { &vnop_symlink_desc, (fuse_spec_op_t)spec_symlink },
  3086. { &vnop_write_desc, (fuse_spec_op_t)fuse_spec_vnop_write }, // custom
  3087. { (struct vnodeop_desc*)NULL, (fuse_spec_op_t)NULL },
  3088. };
  3089. #endif /* M_MACFUSE_ENABLE_SPECFS */