/core/10.4/fusefs/fuse_internal.c

http://macfuse.googlecode.com/ · C · 1525 lines · 1089 code · 299 blank · 137 comment · 208 complexity · b0aae47d34ad691836998bb76a57abe1 MD5 · raw file

  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 "fuse.h"
  28. #include "fuse_file.h"
  29. #include "fuse_internal.h"
  30. #include "fuse_ipc.h"
  31. #include "fuse_locking.h"
  32. #include "fuse_node.h"
  33. #include "fuse_file.h"
  34. #include "fuse_nodehash.h"
  35. #include "fuse_sysctl.h"
  36. #include "fuse_kludges.h"
  37. /* access */
  38. __private_extern__
  39. int
  40. fuse_internal_access(vnode_t vp,
  41. int action,
  42. vfs_context_t context,
  43. struct fuse_access_param *facp)
  44. {
  45. int err = 0;
  46. int default_error = 0;
  47. uint32_t mask = 0;
  48. int dataflags;
  49. mount_t mp;
  50. struct fuse_dispatcher fdi;
  51. struct fuse_access_in *fai;
  52. struct fuse_data *data;
  53. fuse_trace_printf_func();
  54. mp = vnode_mount(vp);
  55. data = fuse_get_mpdata(mp);
  56. dataflags = data->dataflags;
  57. /* Allow for now; let checks be handled inline later. */
  58. if (fuse_isdeferpermissions_mp(mp)) {
  59. return 0;
  60. }
  61. if (facp->facc_flags & FACCESS_FROM_VNOP) {
  62. default_error = ENOTSUP;
  63. }
  64. /*
  65. * (action & KAUTH_VNODE_GENERIC_WRITE_BITS) on a read-only file system
  66. * would have been handled by higher layers.
  67. */
  68. if (!fuse_implemented(data, FSESS_NOIMPLBIT(ACCESS))) {
  69. return default_error;
  70. }
  71. /* Unless explicitly permitted, deny everyone except the fs owner. */
  72. if (!vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) {
  73. if (!(dataflags & FSESS_ALLOW_OTHER)) {
  74. int denied = fuse_match_cred(data->daemoncred,
  75. vfs_context_ucred(context));
  76. if (denied) {
  77. return EPERM;
  78. }
  79. }
  80. facp->facc_flags |= FACCESS_NOCHECKSPY;
  81. }
  82. if (!(facp->facc_flags & FACCESS_DO_ACCESS)) {
  83. return default_error;
  84. }
  85. if (vnode_isdir(vp)) {
  86. if (action & (KAUTH_VNODE_LIST_DIRECTORY |
  87. KAUTH_VNODE_READ_EXTATTRIBUTES)) {
  88. mask |= R_OK;
  89. }
  90. if (action & (KAUTH_VNODE_ADD_FILE |
  91. KAUTH_VNODE_ADD_SUBDIRECTORY |
  92. KAUTH_VNODE_DELETE_CHILD)) {
  93. mask |= W_OK;
  94. }
  95. if (action & KAUTH_VNODE_SEARCH) {
  96. mask |= X_OK;
  97. }
  98. } else {
  99. if (action & (KAUTH_VNODE_READ_DATA | KAUTH_VNODE_READ_EXTATTRIBUTES)) {
  100. mask |= R_OK;
  101. }
  102. if (action & (KAUTH_VNODE_WRITE_DATA | KAUTH_VNODE_APPEND_DATA)) {
  103. mask |= W_OK;
  104. }
  105. if (action & KAUTH_VNODE_EXECUTE) {
  106. mask |= X_OK;
  107. }
  108. }
  109. if (action & (KAUTH_VNODE_WRITE_ATTRIBUTES |
  110. KAUTH_VNODE_WRITE_EXTATTRIBUTES |
  111. KAUTH_VNODE_WRITE_SECURITY)) {
  112. mask |= W_OK;
  113. }
  114. bzero(&fdi, sizeof(fdi));
  115. fdisp_init(&fdi, sizeof(*fai));
  116. fdisp_make_vp(&fdi, FUSE_ACCESS, vp, context);
  117. fai = fdi.indata;
  118. fai->mask = F_OK;
  119. fai->mask |= mask;
  120. if (!(err = fdisp_wait_answ(&fdi))) {
  121. fuse_ticket_drop(fdi.tick);
  122. }
  123. if (err == ENOSYS) {
  124. /*
  125. * Make sure we don't come in here again.
  126. */
  127. vfs_clearauthopaque(mp);
  128. fuse_clear_implemented(data, FSESS_NOIMPLBIT(ACCESS));
  129. err = default_error;
  130. }
  131. if (err == ENOENT) {
  132. const char *vname = NULL;
  133. #if M_MACFUSE_ENABLE_UNSUPPORTED
  134. vname = vnode_getname(vp);
  135. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  136. IOLog("MacFUSE: disappearing vnode %p (name=%s type=%d action=%x)\n",
  137. vp, (vname) ? vname : "?", vnode_vtype(vp), action);
  138. #if M_MACFUSE_ENABLE_UNSUPPORTED
  139. if (vname) {
  140. vnode_putname(vname);
  141. }
  142. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  143. /*
  144. * On 10.4, I think I can get Finder to lock because of /.Trashes/<uid>
  145. * unless I use REVOKE_NONE here.
  146. */
  147. fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT);
  148. }
  149. return err;
  150. }
  151. #if M_MACFUSE_ENABLE_EXCHANGE
  152. /* exchange */
  153. __private_extern__
  154. int
  155. fuse_internal_exchange(vnode_t fvp,
  156. const char *fname,
  157. size_t flen,
  158. vnode_t tvp,
  159. const char *tname,
  160. size_t tlen,
  161. int options,
  162. vfs_context_t context)
  163. {
  164. struct fuse_dispatcher fdi;
  165. struct fuse_exchange_in *fei;
  166. struct fuse_vnode_data *ffud = VTOFUD(fvp);
  167. struct fuse_vnode_data *tfud = VTOFUD(tvp);
  168. vnode_t fdvp = ffud->parentvp;
  169. vnode_t tdvp = tfud->parentvp;
  170. int err = 0;
  171. fdisp_init(&fdi, sizeof(*fei) + flen + tlen + 2);
  172. fdisp_make_vp(&fdi, FUSE_EXCHANGE, fvp, context);
  173. fei = fdi.indata;
  174. fei->olddir = VTOI(fdvp);
  175. fei->newdir = VTOI(tdvp);
  176. fei->options = (uint64_t)options;
  177. memcpy((char *)fdi.indata + sizeof(*fei), fname, flen);
  178. ((char *)fdi.indata)[sizeof(*fei) + flen] = '\0';
  179. memcpy((char *)fdi.indata + sizeof(*fei) + flen + 1, tname, tlen);
  180. ((char *)fdi.indata)[sizeof(*fei) + flen + tlen + 1] = '\0';
  181. ubc_sync_range(fvp, (off_t)0, (off_t)ffud->filesize,
  182. UBC_PUSHALL | UBC_INVALIDATE | UBC_SYNC);
  183. ubc_sync_range(tvp, (off_t)0, (off_t)tfud->filesize,
  184. UBC_PUSHALL | UBC_INVALIDATE | UBC_SYNC);
  185. if (!(err = fdisp_wait_answ(&fdi))) {
  186. fuse_ticket_drop(fdi.tick);
  187. }
  188. if (err == 0) {
  189. if (fdvp) {
  190. fuse_invalidate_attr(fdvp);
  191. }
  192. if (tdvp != fdvp) {
  193. if (tdvp) {
  194. fuse_invalidate_attr(tdvp);
  195. }
  196. }
  197. fuse_invalidate_attr(fvp);
  198. fuse_invalidate_attr(tvp);
  199. cache_purge(fvp);
  200. cache_purge(tvp);
  201. /* Swap sizes */
  202. off_t tmpfilesize = ffud->filesize;
  203. ffud->filesize = tfud->filesize;
  204. tfud->filesize = tmpfilesize;
  205. ubc_setsize(fvp, (off_t)ffud->filesize);
  206. ubc_setsize(tvp, (off_t)tfud->filesize);
  207. fuse_kludge_exchange(fvp, tvp);
  208. /*
  209. * Another approach (will need additional kernel support to work):
  210. *
  211. vnode_t tmpvp = ffud->vp;
  212. ffud->vp = tfud->vp;
  213. tfud->vp = tmpvp;
  214. vnode_t tmpparentvp = ffud->parentvp;
  215. ffud->parentvp = tfud->parentvp;
  216. tfud->parentvp = tmpparentvp;
  217. off_t tmpfilesize = ffud->filesize;
  218. ffud->filesize = tfud->filesize;
  219. tfud->filesize = tmpfilesize;
  220. struct fuse_vnode_data tmpfud;
  221. memcpy(&tmpfud, ffud, sizeof(struct fuse_vnode_data));
  222. memcpy(ffud, tfud, sizeof(struct fuse_vnode_data));
  223. memcpy(tfud, &tmpfud, sizeof(struct fuse_vnode_data));
  224. HNodeExchangeFromFSNode(ffud, tfud);
  225. *
  226. */
  227. }
  228. return err;
  229. }
  230. #endif /* M_MACFUSE_ENABLE_EXCHANGE */
  231. /* fsync */
  232. __private_extern__
  233. int
  234. fuse_internal_fsync_callback(struct fuse_ticket *ftick, __unused uio_t uio)
  235. {
  236. fuse_trace_printf_func();
  237. if (ftick->tk_aw_ohead.error == ENOSYS) {
  238. if (fticket_opcode(ftick) == FUSE_FSYNC) {
  239. fuse_clear_implemented(ftick->tk_data, FSESS_NOIMPLBIT(FSYNC));
  240. } else if (fticket_opcode(ftick) == FUSE_FSYNCDIR) {
  241. fuse_clear_implemented(ftick->tk_data, FSESS_NOIMPLBIT(FSYNCDIR));
  242. } else {
  243. IOLog("MacFUSE: unexpected opcode in sync handling\n");
  244. }
  245. }
  246. fuse_ticket_drop(ftick);
  247. return 0;
  248. }
  249. __private_extern__
  250. int
  251. fuse_internal_fsync(vnode_t vp,
  252. vfs_context_t context,
  253. struct fuse_filehandle *fufh,
  254. void *param,
  255. fuse_op_waitfor_t waitfor)
  256. {
  257. int err = 0;
  258. int op = FUSE_FSYNC;
  259. struct fuse_fsync_in *ffsi;
  260. struct fuse_dispatcher *fdip = param;
  261. fuse_trace_printf_func();
  262. fdip->iosize = sizeof(*ffsi);
  263. fdip->tick = NULL;
  264. if (vnode_isdir(vp)) {
  265. op = FUSE_FSYNCDIR;
  266. }
  267. fdisp_make_vp(fdip, op, vp, context);
  268. ffsi = fdip->indata;
  269. ffsi->fh = fufh->fh_id;
  270. ffsi->fsync_flags = 1; /* datasync */
  271. if (waitfor == FUSE_OP_FOREGROUNDED) {
  272. if ((err = fdisp_wait_answ(fdip))) {
  273. if (err == ENOSYS) {
  274. if (op == FUSE_FSYNC) {
  275. fuse_clear_implemented(fdip->tick->tk_data,
  276. FSESS_NOIMPLBIT(FSYNC));
  277. } else if (op == FUSE_FSYNCDIR) {
  278. fuse_clear_implemented(fdip->tick->tk_data,
  279. FSESS_NOIMPLBIT(FSYNCDIR));
  280. }
  281. }
  282. goto out;
  283. } else {
  284. fuse_ticket_drop(fdip->tick);
  285. }
  286. } else {
  287. fuse_insert_callback(fdip->tick, fuse_internal_fsync_callback);
  288. fuse_insert_message(fdip->tick);
  289. }
  290. out:
  291. return err;
  292. }
  293. /* getattr sidekicks */
  294. __private_extern__
  295. int
  296. fuse_internal_loadxtimes(vnode_t vp, struct vnode_attr *out_vap,
  297. vfs_context_t context)
  298. {
  299. struct vnode_attr *in_vap = VTOVA(vp);
  300. struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
  301. struct fuse_dispatcher fdi;
  302. struct fuse_getxtimes_out *fgxo = NULL;
  303. int isvroot = vnode_isvroot(vp);
  304. struct timespec t = { 0, 0 };
  305. const struct timespec kZeroTime = { 0, 0 };
  306. int err = 0;
  307. if (!(data->dataflags & FSESS_XTIMES)) {
  308. /* We don't return anything. */
  309. goto out;
  310. }
  311. if (VTOFUD(vp)->c_flag & C_XTIMES_VALID) {
  312. VATTR_RETURN(out_vap, va_backup_time, in_vap->va_backup_time);
  313. VATTR_RETURN(out_vap, va_create_time, in_vap->va_create_time);
  314. goto out;
  315. }
  316. if (!fuse_implemented(data, FSESS_NOIMPLBIT(GETXTIMES))) {
  317. goto fake;
  318. }
  319. if (fuse_isdeadfs(vp) && isvroot) {
  320. goto fake;
  321. }
  322. if (!(data->dataflags & FSESS_INITED) && isvroot) {
  323. goto fake;
  324. }
  325. err = fdisp_simple_putget_vp(&fdi, FUSE_GETXTIMES, vp, context);
  326. if (err) {
  327. /* We don't ever treat this as a hard error. */
  328. err = 0;
  329. goto fake;
  330. }
  331. fgxo = (struct fuse_getxtimes_out *)fdi.answ;
  332. t.tv_sec = (time_t)fgxo->bkuptime; /* XXX: truncation */
  333. t.tv_nsec = fgxo->bkuptimensec;
  334. VATTR_RETURN(in_vap, va_backup_time, t);
  335. VATTR_RETURN(out_vap, va_backup_time, t);
  336. t.tv_sec = (time_t)fgxo->crtime; /* XXX: truncation */
  337. t.tv_nsec = fgxo->crtimensec;
  338. VATTR_RETURN(in_vap, va_create_time, t);
  339. VATTR_RETURN(out_vap, va_create_time, t);
  340. fuse_ticket_drop(fdi.tick);
  341. VTOFUD(vp)->c_flag |= C_XTIMES_VALID;
  342. goto out;
  343. fake:
  344. VATTR_RETURN(out_vap, va_backup_time, kZeroTime);
  345. VATTR_RETURN(out_vap, va_create_time, kZeroTime);
  346. out:
  347. return err;
  348. }
  349. /* ioctl */
  350. __private_extern__
  351. int
  352. fuse_internal_ioctl_avfi(vnode_t vp, __unused vfs_context_t context,
  353. struct fuse_avfi_ioctl *avfi)
  354. {
  355. int ret = 0;
  356. uint32_t hint = 0;
  357. if (!avfi) {
  358. return EINVAL;
  359. }
  360. if (avfi->cmd & FUSE_AVFI_MARKGONE) {
  361. /*
  362. * TBD
  363. */
  364. return EINVAL;
  365. }
  366. /* The result of this /does/ alter our return value. */
  367. if (avfi->cmd & FUSE_AVFI_UBC) {
  368. int ubc_flags = avfi->ubc_flags & (UBC_PUSHDIRTY | UBC_PUSHALL |
  369. UBC_INVALIDATE | UBC_SYNC);
  370. if (ubc_sync_range(vp, (off_t)0, ubc_getsize(vp), ubc_flags) == 0) {
  371. /* failed */
  372. ret = EINVAL; /* don't really have a good error to return */
  373. }
  374. }
  375. if (avfi->cmd & FUSE_AVFI_UBC_SETSIZE) {
  376. if (VTOFUD(vp)->filesize != avfi->size) {
  377. hint |= NOTE_WRITE;
  378. if (avfi->size > VTOFUD(vp)->filesize) {
  379. hint |= NOTE_EXTEND;
  380. }
  381. VTOFUD(vp)->filesize = avfi->size;
  382. ubc_setsize(vp, avfi->size);
  383. }
  384. (void)fuse_invalidate_attr(vp);
  385. }
  386. /* The result of this doesn't alter our return value. */
  387. if (avfi->cmd & FUSE_AVFI_PURGEATTRCACHE) {
  388. hint |= NOTE_ATTRIB;
  389. (void)fuse_invalidate_attr(vp);
  390. }
  391. /* The result of this doesn't alter our return value. */
  392. if (avfi->cmd & FUSE_AVFI_PURGEVNCACHE) {
  393. (void)fuse_vncache_purge(vp);
  394. }
  395. if (avfi->cmd & FUSE_AVFI_KNOTE) {
  396. hint |= avfi->note;
  397. }
  398. if (hint) {
  399. FUSE_KNOTE(vp, hint);
  400. }
  401. return ret;
  402. }
  403. /* readdir */
  404. __private_extern__
  405. int
  406. fuse_internal_readdir(vnode_t vp,
  407. uio_t uio,
  408. vfs_context_t context,
  409. struct fuse_filehandle *fufh,
  410. struct fuse_iov *cookediov,
  411. int *numdirent)
  412. {
  413. int err = 0;
  414. struct fuse_dispatcher fdi;
  415. struct fuse_read_in *fri;
  416. struct fuse_data *data;
  417. if (uio_resid(uio) == 0) {
  418. return 0;
  419. }
  420. fdisp_init(&fdi, 0);
  421. /* Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p I/O). */
  422. while (uio_resid(uio) > 0) {
  423. fdi.iosize = sizeof(*fri);
  424. fdisp_make_vp(&fdi, FUSE_READDIR, vp, context);
  425. fri = fdi.indata;
  426. fri->fh = fufh->fh_id;
  427. fri->offset = uio_offset(uio);
  428. data = fuse_get_mpdata(vnode_mount(vp));
  429. fri->size = (typeof(fri->size))min((size_t)uio_resid(uio), data->iosize);
  430. if ((err = fdisp_wait_answ(&fdi))) {
  431. goto out;
  432. }
  433. if ((err = fuse_internal_readdir_processdata(vp,
  434. uio,
  435. fri->size,
  436. fdi.answ,
  437. fdi.iosize,
  438. cookediov,
  439. numdirent))) {
  440. break;
  441. }
  442. }
  443. /* done: */
  444. fuse_ticket_drop(fdi.tick);
  445. out:
  446. return ((err == -1) ? 0 : err);
  447. }
  448. __private_extern__
  449. int
  450. fuse_internal_readdir_processdata(vnode_t vp,
  451. uio_t uio,
  452. __unused size_t reqsize,
  453. void *buf,
  454. size_t bufsize,
  455. struct fuse_iov *cookediov,
  456. int *numdirent)
  457. {
  458. int err = 0;
  459. int cou = 0;
  460. int n = 0;
  461. size_t bytesavail;
  462. size_t freclen;
  463. struct dirent *de;
  464. struct fuse_dirent *fudge;
  465. if (bufsize < FUSE_NAME_OFFSET) {
  466. return -1;
  467. }
  468. for (;;) {
  469. if (bufsize < FUSE_NAME_OFFSET) {
  470. err = -1;
  471. break;
  472. }
  473. fudge = (struct fuse_dirent *)buf;
  474. freclen = FUSE_DIRENT_SIZE(fudge);
  475. cou++;
  476. if (bufsize < freclen) {
  477. err = ((cou == 1) ? -1 : 0);
  478. break;
  479. }
  480. /*
  481. * if (isbzero(buf, FUSE_NAME_OFFSET)) {
  482. * // zero-pad incomplete buffer
  483. * ...
  484. * err = -1;
  485. * break;
  486. * }
  487. */
  488. if (!fudge->namelen) {
  489. err = EINVAL;
  490. break;
  491. }
  492. if (fudge->namelen > MAXNAMLEN) {
  493. err = EIO;
  494. break;
  495. }
  496. #define GENERIC_DIRSIZ(dp) \
  497. ((sizeof(struct dirent) - (MAXNAMLEN + 1)) + (((dp)->d_namlen + 1 + 3) & ~3))
  498. bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)&fudge->namelen);
  499. if (bytesavail > (size_t)uio_resid(uio)) {
  500. err = -1;
  501. break;
  502. }
  503. fiov_refresh(cookediov);
  504. fiov_adjust(cookediov, bytesavail);
  505. de = (struct dirent *)cookediov->base;
  506. #if __DARWIN_64_BIT_INO_T
  507. de->d_fileno = fudge->ino;
  508. #else
  509. de->d_fileno = (ino_t)fudge->ino; /* XXX: truncation */
  510. #endif /* __DARWIN_64_BIT_INO_T */
  511. de->d_reclen = bytesavail;
  512. de->d_type = fudge->type;
  513. de->d_namlen = fudge->namelen;
  514. /* Filter out any ._* files if the mount is configured as such. */
  515. if (fuse_skip_apple_double_mp(vnode_mount(vp),
  516. fudge->name, fudge->namelen)) {
  517. de->d_fileno = 0;
  518. de->d_type = DT_WHT;
  519. }
  520. memcpy((char *)cookediov->base + sizeof(struct dirent) - MAXNAMLEN - 1,
  521. (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
  522. ((char *)cookediov->base)[bytesavail] = '\0';
  523. err = uiomove(cookediov->base, (int)cookediov->len, uio);
  524. if (err) {
  525. break;
  526. }
  527. n++;
  528. buf = (char *)buf + freclen;
  529. bufsize -= freclen;
  530. uio_setoffset(uio, fudge->off);
  531. }
  532. if (!err && numdirent) {
  533. *numdirent = n;
  534. }
  535. return err;
  536. }
  537. /* remove */
  538. static int
  539. fuse_internal_remove_callback(vnode_t vp, void *cargs)
  540. {
  541. struct vnode_attr *vap;
  542. uint64_t target_nlink;
  543. vap = VTOVA(vp);
  544. target_nlink = *(uint64_t *)cargs;
  545. /* somewhat lame "heuristics", but you got better ideas? */
  546. if ((vap->va_nlink == target_nlink) && vnode_isreg(vp)) {
  547. fuse_invalidate_attr(vp);
  548. }
  549. return VNODE_RETURNED;
  550. }
  551. __private_extern__
  552. int
  553. fuse_internal_remove(vnode_t dvp,
  554. vnode_t vp,
  555. struct componentname *cnp,
  556. enum fuse_opcode op,
  557. vfs_context_t context)
  558. {
  559. struct fuse_dispatcher fdi;
  560. struct vnode_attr *vap = VTOVA(vp);
  561. int need_invalidate = 0;
  562. uint64_t target_nlink = 0;
  563. mount_t mp = vnode_mount(vp);
  564. int err = 0;
  565. fdisp_init(&fdi, cnp->cn_namelen + 1);
  566. fdisp_make_vp(&fdi, op, dvp, context);
  567. memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
  568. ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
  569. if ((vap->va_nlink > 1) && vnode_isreg(vp)) {
  570. need_invalidate = 1;
  571. target_nlink = vap->va_nlink;
  572. }
  573. if (!(err = fdisp_wait_answ(&fdi))) {
  574. fuse_ticket_drop(fdi.tick);
  575. }
  576. fuse_invalidate_attr(dvp);
  577. fuse_invalidate_attr(vp);
  578. /*
  579. * XXX: M_MACFUSE_INVALIDATE_CACHED_VATTRS_UPON_UNLINK
  580. *
  581. * Consider the case where vap->va_nlink > 1 for the entity being
  582. * removed. In our world, other in-memory vnodes that share a link
  583. * count each with this one may not know right way that this one just
  584. * got deleted. We should let them know, say, through a vnode_iterate()
  585. * here and a callback that does fuse_invalidate_attr(vp) on each
  586. * relevant vnode.
  587. */
  588. if (need_invalidate && !err) {
  589. if (!vfs_busy(mp, LK_NOWAIT)) {
  590. vnode_iterate(mp, 0, fuse_internal_remove_callback,
  591. (void *)&target_nlink);
  592. vfs_unbusy(mp);
  593. } else {
  594. IOLog("MacFUSE: skipping link count fixup upon remove\n");
  595. }
  596. }
  597. return err;
  598. }
  599. /* rename */
  600. __private_extern__
  601. int
  602. fuse_internal_rename(vnode_t fdvp,
  603. __unused vnode_t fvp,
  604. struct componentname *fcnp,
  605. vnode_t tdvp,
  606. __unused vnode_t tvp,
  607. struct componentname *tcnp,
  608. vfs_context_t context)
  609. {
  610. struct fuse_dispatcher fdi;
  611. struct fuse_rename_in *fri;
  612. int err = 0;
  613. fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2);
  614. fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, context);
  615. fri = fdi.indata;
  616. fri->newdir = VTOI(tdvp);
  617. memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr,
  618. fcnp->cn_namelen);
  619. ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0';
  620. memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1,
  621. tcnp->cn_nameptr, tcnp->cn_namelen);
  622. ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen +
  623. tcnp->cn_namelen + 1] = '\0';
  624. if (!(err = fdisp_wait_answ(&fdi))) {
  625. fuse_ticket_drop(fdi.tick);
  626. }
  627. if (err == 0) {
  628. fuse_invalidate_attr(fdvp);
  629. if (tdvp != fdvp) {
  630. fuse_invalidate_attr(tdvp);
  631. }
  632. }
  633. return err;
  634. }
  635. /* revoke */
  636. __private_extern__
  637. int
  638. fuse_internal_revoke(vnode_t vp, int flags, vfs_context_t context, int how)
  639. {
  640. int ret = 0;
  641. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  642. fvdat->flag |= FN_REVOKED;
  643. if (how == REVOKE_HARD) {
  644. ret = vn_revoke(vp, flags, context);
  645. }
  646. return ret;
  647. }
  648. /* strategy */
  649. __private_extern__
  650. int
  651. fuse_internal_strategy(vnode_t vp, buf_t bp)
  652. {
  653. size_t biosize;
  654. size_t chunksize;
  655. size_t respsize;
  656. int mapped = FALSE;
  657. int mode;
  658. int op;
  659. int vtype = vnode_vtype(vp);
  660. int err = 0;
  661. caddr_t bufdat;
  662. off_t left;
  663. off_t offset;
  664. int32_t bflags = buf_flags(bp);
  665. fufh_type_t fufh_type;
  666. struct fuse_dispatcher fdi;
  667. struct fuse_data *data;
  668. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  669. struct fuse_filehandle *fufh = NULL;
  670. mount_t mp = vnode_mount(vp);
  671. data = fuse_get_mpdata(mp);
  672. biosize = data->blocksize;
  673. if (!(vtype == VREG || vtype == VDIR)) {
  674. return ENOTSUP;
  675. }
  676. if (bflags & B_READ) {
  677. mode = FREAD;
  678. fufh_type = FUFH_RDONLY; /* FUFH_RDWR will also do */
  679. } else {
  680. mode = FWRITE;
  681. fufh_type = FUFH_WRONLY; /* FUFH_RDWR will also do */
  682. }
  683. if (fvdat->flag & FN_CREATING) {
  684. fuse_lck_mtx_lock(fvdat->createlock);
  685. if (fvdat->flag & FN_CREATING) {
  686. (void)fuse_msleep(fvdat->creator, fvdat->createlock,
  687. PDROP | PINOD | PCATCH, "fuse_internal_strategy",
  688. NULL);
  689. } else {
  690. fuse_lck_mtx_unlock(fvdat->createlock);
  691. }
  692. }
  693. fufh = &(fvdat->fufh[fufh_type]);
  694. if (!FUFH_IS_VALID(fufh)) {
  695. fufh_type = FUFH_RDWR;
  696. fufh = &(fvdat->fufh[fufh_type]);
  697. if (!FUFH_IS_VALID(fufh)) {
  698. fufh = NULL;
  699. } else {
  700. /* We've successfully fallen back to FUFH_RDWR. */
  701. }
  702. }
  703. if (!fufh) {
  704. if (mode == FREAD) {
  705. fufh_type = FUFH_RDONLY;
  706. } else {
  707. fufh_type = FUFH_RDWR;
  708. }
  709. /*
  710. * Lets NOT do the filehandle preflight check here.
  711. */
  712. err = fuse_filehandle_get(vp, NULL, fufh_type, 0 /* mode */);
  713. if (!err) {
  714. fufh = &(fvdat->fufh[fufh_type]);
  715. FUFH_AUX_INC(fufh);
  716. /* We've created a NEW fufh of type fufh_type. open_count is 1. */
  717. }
  718. } else { /* good fufh */
  719. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_reuse_count);
  720. /* We're using an existing fufh of type fufh_type. */
  721. }
  722. if (err) {
  723. /* A more typical error case. */
  724. if ((err == ENOTCONN) || fuse_isdeadfs(vp)) {
  725. buf_seterror(bp, EIO);
  726. buf_biodone(bp);
  727. return EIO;
  728. }
  729. IOLog("MacFUSE: strategy failed to get fh "
  730. "(vtype=%d, fufh_type=%d, err=%d)\n", vtype, fufh_type, err);
  731. if (!vfs_issynchronous(mp)) {
  732. IOLog("MacFUSE: asynchronous write failed!\n");
  733. }
  734. buf_seterror(bp, EIO);
  735. buf_biodone(bp);
  736. return EIO;
  737. }
  738. if (!fufh) {
  739. panic("MacFUSE: tried everything but still no fufh");
  740. /* NOTREACHED */
  741. }
  742. #define B_INVAL 0x00040000 /* Does not contain valid info. */
  743. #define B_ERROR 0x00080000 /* I/O error occurred. */
  744. if (bflags & B_INVAL) {
  745. IOLog("MacFUSE: buffer does not contain valid information\n");
  746. }
  747. if (bflags & B_ERROR) {
  748. IOLog("MacFUSE: an I/O error has occured\n");
  749. }
  750. if (buf_count(bp) == 0) {
  751. return 0;
  752. }
  753. fdisp_init(&fdi, 0);
  754. if (mode == FREAD) {
  755. struct fuse_read_in *fri;
  756. buf_setresid(bp, buf_count(bp));
  757. offset = (off_t)((off_t)buf_blkno(bp) * biosize);
  758. if (offset >= fvdat->filesize) {
  759. /* Trying to read at/after EOF? */
  760. if (offset != fvdat->filesize) {
  761. /* Trying to read after EOF? */
  762. buf_seterror(bp, EINVAL);
  763. }
  764. buf_biodone(bp);
  765. return 0;
  766. }
  767. /* Note that we just made sure that offset < fvdat->filesize. */
  768. if ((offset + buf_count(bp)) > fvdat->filesize) {
  769. /* Trimming read */
  770. buf_setcount(bp, (uint32_t)(fvdat->filesize - offset));
  771. }
  772. if (buf_map(bp, &bufdat)) {
  773. IOLog("MacFUSE: failed to map buffer in strategy\n");
  774. return EFAULT;
  775. } else {
  776. mapped = TRUE;
  777. }
  778. while (buf_resid(bp) > 0) {
  779. chunksize = min((size_t)buf_resid(bp), data->iosize);
  780. fdi.iosize = sizeof(*fri);
  781. op = FUSE_READ;
  782. if (vtype == VDIR) {
  783. op = FUSE_READDIR;
  784. }
  785. fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0);
  786. fri = fdi.indata;
  787. fri->fh = fufh->fh_id;
  788. /*
  789. * Historical note:
  790. *
  791. * fri->offset = ((off_t)(buf_blkno(bp))) * biosize;
  792. *
  793. * This wasn't being incremented!?
  794. */
  795. fri->offset = offset;
  796. fri->size = (typeof(fri->size))chunksize;
  797. fdi.tick->tk_aw_type = FT_A_BUF;
  798. fdi.tick->tk_aw_bufdata = bufdat;
  799. if ((err = fdisp_wait_answ(&fdi))) {
  800. /* There was a problem with reading. */
  801. goto out;
  802. }
  803. respsize = fdi.tick->tk_aw_bufsize;
  804. if (respsize < 0) { /* Cannot really happen... */
  805. err = EIO;
  806. goto out;
  807. }
  808. buf_setresid(bp, (uint32_t)(buf_resid(bp) - respsize));
  809. bufdat += respsize;
  810. offset += respsize;
  811. /* Did we hit EOF before being done? */
  812. if ((respsize == 0) && (buf_resid(bp) > 0)) {
  813. /*
  814. * Historical note:
  815. * If we don't get enough data, just fill the rest with zeros.
  816. * In NFS context, this would mean a hole in the file.
  817. */
  818. /* Zero-pad the incomplete buffer. */
  819. bzero(bufdat, buf_resid(bp));
  820. buf_setresid(bp, 0);
  821. break;
  822. }
  823. } /* while (buf_resid(bp) > 0) */
  824. } else {
  825. /* write */
  826. struct fuse_write_in *fwi;
  827. struct fuse_write_out *fwo;
  828. int merr = 0;
  829. off_t diff;
  830. if (buf_map(bp, &bufdat)) {
  831. IOLog("MacFUSE: failed to map buffer in strategy\n");
  832. return EFAULT;
  833. } else {
  834. mapped = TRUE;
  835. }
  836. /* Write begin */
  837. buf_setresid(bp, buf_count(bp));
  838. offset = (off_t)((off_t)buf_blkno(bp) * biosize);
  839. /* XXX: TBD -- Check here for extension (writing past end) */
  840. left = buf_count(bp);
  841. while (left) {
  842. fdi.iosize = sizeof(*fwi);
  843. op = FUSE_WRITE;
  844. fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0);
  845. chunksize = min((size_t)left, data->iosize);
  846. fwi = fdi.indata;
  847. fwi->fh = fufh->fh_id;
  848. fwi->offset = offset;
  849. fwi->size = (typeof(fwi->size))chunksize;
  850. fdi.tick->tk_ms_type = FT_M_BUF;
  851. fdi.tick->tk_ms_bufdata = bufdat;
  852. fdi.tick->tk_ms_bufsize = chunksize;
  853. /* About to write <chunksize> at <offset> */
  854. if ((err = fdisp_wait_answ(&fdi))) {
  855. merr = 1;
  856. break;
  857. }
  858. fwo = fdi.answ;
  859. diff = chunksize - fwo->size;
  860. if (diff < 0) {
  861. err = EINVAL;
  862. break;
  863. }
  864. left -= fwo->size;
  865. bufdat += fwo->size;
  866. offset += fwo->size;
  867. buf_setresid(bp, buf_resid(bp) - fwo->size);
  868. }
  869. if (merr) {
  870. goto out;
  871. }
  872. }
  873. if (fdi.tick) {
  874. fuse_ticket_drop(fdi.tick);
  875. } else {
  876. /* No ticket upon leaving */
  877. }
  878. out:
  879. if (err) {
  880. buf_seterror(bp, err);
  881. }
  882. if (mapped == TRUE) {
  883. buf_unmap(bp);
  884. }
  885. buf_biodone(bp);
  886. return err;
  887. }
  888. __private_extern__
  889. errno_t
  890. fuse_internal_strategy_buf(struct vnop_strategy_args *ap)
  891. {
  892. int32_t bflags;
  893. upl_t bupl;
  894. daddr64_t blkno, lblkno;
  895. int bmap_flags;
  896. buf_t bp = ap->a_bp;
  897. vnode_t vp = buf_vnode(bp);
  898. int vtype = vnode_vtype(vp);
  899. struct fuse_data *data;
  900. if (!vp || vtype == VCHR || vtype == VBLK) {
  901. panic("MacFUSE: buf_strategy: b_vp == NULL || vtype == VCHR | VBLK\n");
  902. }
  903. bflags = buf_flags(bp);
  904. if (bflags & B_READ) {
  905. bmap_flags = VNODE_READ;
  906. } else {
  907. bmap_flags = VNODE_WRITE;
  908. }
  909. bupl = buf_upl(bp);
  910. blkno = buf_blkno(bp);
  911. lblkno = buf_lblkno(bp);
  912. if (!(bflags & B_CLUSTER)) {
  913. if (bupl) {
  914. return cluster_bp(bp);
  915. }
  916. if (blkno == lblkno) {
  917. off_t f_offset;
  918. size_t contig_bytes;
  919. data = fuse_get_mpdata(vnode_mount(vp));
  920. // Still think this is a kludge?
  921. f_offset = lblkno * data->blocksize;
  922. blkno = f_offset / data->blocksize;
  923. buf_setblkno(bp, blkno);
  924. contig_bytes = buf_count(bp);
  925. if (blkno == -1) {
  926. buf_clear(bp);
  927. }
  928. /*
  929. * Our "device" is always /all contiguous/. We don't wanna be
  930. * doing things like:
  931. *
  932. * ...
  933. * else if ((long)contig_bytes < buf_count(bp)) {
  934. * ret = buf_strategy_fragmented(devvp, bp, f_offset,
  935. * contig_bytes));
  936. * return ret;
  937. * }
  938. */
  939. }
  940. if (blkno == -1) {
  941. buf_biodone(bp);
  942. return 0;
  943. }
  944. }
  945. // Issue the I/O
  946. return fuse_internal_strategy(vp, bp);
  947. }
  948. /* entity creation */
  949. __private_extern__
  950. void
  951. fuse_internal_newentry_makerequest(mount_t mp,
  952. uint64_t dnid,
  953. struct componentname *cnp,
  954. enum fuse_opcode op,
  955. void *buf,
  956. size_t bufsize,
  957. struct fuse_dispatcher *fdip,
  958. vfs_context_t context)
  959. {
  960. fdisp_init(fdip, bufsize + cnp->cn_namelen + 1);
  961. fdisp_make(fdip, op, mp, dnid, context);
  962. memcpy(fdip->indata, buf, bufsize);
  963. memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen);
  964. ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0';
  965. }
  966. __private_extern__
  967. int
  968. fuse_internal_newentry_core(vnode_t dvp,
  969. vnode_t *vpp,
  970. struct componentname *cnp,
  971. enum vtype vtyp,
  972. struct fuse_dispatcher *fdip,
  973. vfs_context_t context)
  974. {
  975. int err = 0;
  976. struct fuse_entry_out *feo;
  977. mount_t mp = vnode_mount(dvp);
  978. if ((err = fdisp_wait_answ(fdip))) {
  979. return err;
  980. }
  981. feo = fdip->answ;
  982. if ((err = fuse_internal_checkentry(feo, vtyp))) {
  983. goto out;
  984. }
  985. err = fuse_vget_i(vpp, 0 /* flags */, feo, cnp, dvp, mp, context);
  986. if (err) {
  987. fuse_internal_forget_send(mp, context, feo->nodeid, 1, fdip);
  988. return err;
  989. }
  990. cache_attrs(*vpp, feo);
  991. out:
  992. fuse_ticket_drop(fdip->tick);
  993. return err;
  994. }
  995. __private_extern__
  996. int
  997. fuse_internal_newentry(vnode_t dvp,
  998. vnode_t *vpp,
  999. struct componentname *cnp,
  1000. enum fuse_opcode op,
  1001. void *buf,
  1002. size_t bufsize,
  1003. enum vtype vtype,
  1004. vfs_context_t context)
  1005. {
  1006. int err;
  1007. struct fuse_dispatcher fdi;
  1008. mount_t mp = vnode_mount(dvp);
  1009. if (fuse_skip_apple_double_mp(mp, cnp->cn_nameptr, cnp->cn_namelen)) {
  1010. return EACCES;
  1011. }
  1012. fdisp_init(&fdi, 0);
  1013. fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf,
  1014. bufsize, &fdi, context);
  1015. err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi, context);
  1016. fuse_invalidate_attr(dvp);
  1017. return err;
  1018. }
  1019. /* entity destruction */
  1020. __private_extern__
  1021. int
  1022. fuse_internal_forget_callback(struct fuse_ticket *ftick, __unused uio_t uio)
  1023. {
  1024. struct fuse_dispatcher fdi;
  1025. fdi.tick = ftick;
  1026. fuse_internal_forget_send(ftick->tk_data->mp, (vfs_context_t)0,
  1027. ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1, &fdi);
  1028. return 0;
  1029. }
  1030. __private_extern__
  1031. void
  1032. fuse_internal_forget_send(mount_t mp,
  1033. vfs_context_t context,
  1034. uint64_t nodeid,
  1035. uint64_t nlookup,
  1036. struct fuse_dispatcher *fdip)
  1037. {
  1038. struct fuse_forget_in *ffi;
  1039. /*
  1040. * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu",
  1041. * (long long unsigned) nodeid));
  1042. */
  1043. fdisp_init(fdip, sizeof(*ffi));
  1044. fdisp_make(fdip, FUSE_FORGET, mp, nodeid, context);
  1045. ffi = fdip->indata;
  1046. ffi->nlookup = nlookup;
  1047. fticket_invalidate(fdip->tick);
  1048. fuse_insert_message(fdip->tick);
  1049. }
  1050. __private_extern__
  1051. void
  1052. fuse_internal_interrupt_send(struct fuse_ticket *ftick)
  1053. {
  1054. struct fuse_dispatcher fdi;
  1055. struct fuse_interrupt_in *fii;
  1056. fdi.tick = ftick;
  1057. fdisp_init(&fdi, sizeof(*fii));
  1058. fdisp_make(&fdi, FUSE_INTERRUPT, ftick->tk_data->mp, (uint64_t)0,
  1059. (vfs_context_t)0);
  1060. fii = fdi.indata;
  1061. fii->unique = ftick->tk_unique;
  1062. fticket_invalidate(fdi.tick);
  1063. fuse_insert_message(fdi.tick);
  1064. }
  1065. __private_extern__
  1066. void
  1067. fuse_internal_vnode_disappear(vnode_t vp, vfs_context_t context, int how)
  1068. {
  1069. int err = 0;
  1070. fuse_vncache_purge(vp);
  1071. if (how != REVOKE_NONE) {
  1072. err = fuse_internal_revoke(vp, REVOKEALL, context, how);
  1073. if (err) {
  1074. IOLog("MacFUSE: disappearing act: revoke failed (%d)\n", err);
  1075. }
  1076. err = vnode_recycle(vp);
  1077. if (err) {
  1078. IOLog("MacFUSE: disappearing act: recycle failed (%d)\n", err);
  1079. }
  1080. }
  1081. }
  1082. /* fuse start/stop */
  1083. __private_extern__
  1084. int
  1085. fuse_internal_init_synchronous(struct fuse_ticket *ftick)
  1086. {
  1087. int err = 0;
  1088. struct fuse_init_out *fiio;
  1089. struct fuse_data *data = ftick->tk_data;
  1090. if ((err = ftick->tk_aw_ohead.error)) {
  1091. goto out;
  1092. }
  1093. fiio = fticket_resp(ftick)->base;
  1094. if ((fiio->major < MACFUSE_MIN_USER_VERSION_MAJOR) ||
  1095. (fiio->minor < MACFUSE_MIN_USER_VERSION_MINOR)){
  1096. IOLog("MacFUSE: user-space library has too low a version\n");
  1097. err = EPROTONOSUPPORT;
  1098. goto out;
  1099. }
  1100. data->fuse_libabi_major = fiio->major;
  1101. data->fuse_libabi_minor = fiio->minor;
  1102. if (fuse_libabi_geq(data, MACFUSE_MIN_USER_VERSION_MAJOR,
  1103. MACFUSE_MIN_USER_VERSION_MINOR)) {
  1104. if (fticket_resp(ftick)->len == sizeof(struct fuse_init_out)) {
  1105. data->max_write = fiio->max_write;
  1106. } else {
  1107. err = EINVAL;
  1108. }
  1109. } else {
  1110. /* Old fix values */
  1111. data->max_write = 4096;
  1112. }
  1113. if (fiio->flags & FUSE_CASE_INSENSITIVE) {
  1114. data->dataflags |= FSESS_CASE_INSENSITIVE;
  1115. }
  1116. if (fiio->flags & FUSE_VOL_RENAME) {
  1117. data->dataflags |= FSESS_VOL_RENAME;
  1118. }
  1119. if (fiio->flags & FUSE_XTIMES) {
  1120. data->dataflags |= FSESS_XTIMES;
  1121. }
  1122. out:
  1123. fuse_ticket_drop(ftick);
  1124. if (err) {
  1125. fdata_set_dead(data);
  1126. }
  1127. fuse_lck_mtx_lock(data->ticket_mtx);
  1128. data->dataflags |= FSESS_INITED;
  1129. fuse_wakeup(&data->ticketer);
  1130. fuse_lck_mtx_unlock(data->ticket_mtx);
  1131. return 0;
  1132. }
  1133. __private_extern__
  1134. int
  1135. fuse_internal_send_init(struct fuse_data *data, vfs_context_t context)
  1136. {
  1137. int err = 0;
  1138. struct fuse_init_in *fiii;
  1139. struct fuse_dispatcher fdi;
  1140. fdisp_init(&fdi, sizeof(*fiii));
  1141. fdisp_make(&fdi, FUSE_INIT, data->mp, 0, context);
  1142. fiii = fdi.indata;
  1143. fiii->major = FUSE_KERNEL_VERSION;
  1144. fiii->minor = FUSE_KERNEL_MINOR_VERSION;
  1145. fiii->max_readahead = data->iosize * 16;
  1146. fiii->flags = 0;
  1147. /* blocking FUSE_INIT up to user space */
  1148. err = fdisp_wait_answ(&fdi);
  1149. if (err) {
  1150. IOLog("MacFUSE: user-space initialization failed (%d)\n", err);
  1151. return err;
  1152. }
  1153. err = fuse_internal_init_synchronous(fdi.tick);
  1154. if (err) {
  1155. IOLog("MacFUSE: in-kernel initialization failed (%d)\n", err);
  1156. return err;
  1157. }
  1158. return 0;
  1159. }
  1160. /* other */
  1161. static int
  1162. fuse_internal_print_vnodes_callback(vnode_t vp, __unused void *cargs)
  1163. {
  1164. const char *vname = NULL;
  1165. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  1166. #if M_MACFUSE_ENABLE_UNSUPPORTED
  1167. vname = vnode_getname(vp);
  1168. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  1169. if (vname) {
  1170. IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d %s\n",
  1171. vp, fvdat->nodeid, fvdat->parent_nodeid,
  1172. vnode_isinuse(vp, 0), vname);
  1173. } else {
  1174. if (fvdat->nodeid == FUSE_ROOT_ID) {
  1175. IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d /\n",
  1176. vp, fvdat->nodeid, fvdat->parent_nodeid,
  1177. vnode_isinuse(vp, 0));
  1178. } else {
  1179. IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d\n",
  1180. vp, fvdat->nodeid, fvdat->parent_nodeid,
  1181. vnode_isinuse(vp, 0));
  1182. }
  1183. }
  1184. #if M_MACFUSE_ENABLE_UNSUPPORTED
  1185. if (vname) {
  1186. vnode_putname(vname);
  1187. }
  1188. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  1189. return VNODE_RETURNED;
  1190. }
  1191. __private_extern__
  1192. void
  1193. fuse_internal_print_vnodes(mount_t mp)
  1194. {
  1195. vnode_iterate(mp, VNODE_ITERATE_ALL,
  1196. fuse_internal_print_vnodes_callback, NULL);
  1197. }
  1198. __private_extern__
  1199. void
  1200. fuse_preflight_log(vnode_t vp, fufh_type_t fufh_type, int err, char *message)
  1201. {
  1202. const char *vname = NULL;
  1203. #if M_MACFUSE_ENABLE_UNSUPPORTED
  1204. vname = vnode_getname(vp);
  1205. #else
  1206. (void)vname;
  1207. (void)vp;
  1208. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  1209. if (vname) {
  1210. IOLog("MacFUSE: file handle preflight "
  1211. "(caller=%s, type=%d, err=%d, name=%s)\n",
  1212. message, fufh_type, err, vname);
  1213. } else {
  1214. IOLog("MacFUSE: file handle preflight "
  1215. "(caller=%s, type=%d, err=%d)\n", message, fufh_type, err);
  1216. }
  1217. #if M_MACFUSE_ENABLE_UNSUPPORTED
  1218. if (vname) {
  1219. vnode_putname(vname);
  1220. }
  1221. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  1222. }