PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/core/10.4/fusefs/fuse_vnops.c

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