/core/10.5/fusefs/fuse_internal.c

http://macfuse.googlecode.com/ · C · 1686 lines · 1189 code · 321 blank · 176 comment · 229 complexity · 46c89690522011a7aff5d520886ee8ee 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_msync(fvp, (off_t)0, (off_t)ffud->filesize, (off_t*)0,
  182. UBC_PUSHALL | UBC_INVALIDATE | UBC_SYNC);
  183. ubc_msync(tvp, (off_t)0, (off_t)tfud->filesize, (off_t*)0,
  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. /* setattr sidekicks */
  350. __private_extern__
  351. int
  352. fuse_internal_attr_vat2fsai(mount_t mp,
  353. vnode_t vp,
  354. struct vnode_attr *vap,
  355. struct fuse_setattr_in *fsai,
  356. uint64_t *newsize)
  357. {
  358. /*
  359. * XXX: Locking
  360. *
  361. * We need to worry about the file size changing in setattr(). If the call
  362. * is indeed altering the size, then:
  363. *
  364. * lock_exclusive(truncatelock)
  365. * lock(nodelock)
  366. * set the new size
  367. * unlock(nodelock)
  368. * adjust ubc
  369. * lock(nodelock)
  370. * do cleanup
  371. * unlock(nodelock)
  372. * unlock(truncatelock)
  373. * ...
  374. */
  375. int sizechanged = 0;
  376. uid_t nuid;
  377. gid_t ngid;
  378. fsai->valid = 0;
  379. if (newsize) {
  380. *newsize = 0;
  381. }
  382. nuid = VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : (uid_t)VNOVAL;
  383. if (nuid != (uid_t)VNOVAL) {
  384. fsai->uid = nuid;
  385. fsai->valid |= FATTR_UID;
  386. }
  387. VATTR_SET_SUPPORTED(vap, va_uid);
  388. ngid = VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : (gid_t)VNOVAL;
  389. if (ngid != (gid_t)VNOVAL) {
  390. fsai->gid = ngid;
  391. fsai->valid |= FATTR_GID;
  392. }
  393. VATTR_SET_SUPPORTED(vap, va_gid);
  394. if (VATTR_IS_ACTIVE(vap, va_data_size)) {
  395. // Truncate to a new value.
  396. fsai->size = vap->va_data_size;
  397. sizechanged = 1;
  398. if (newsize) {
  399. *newsize = vap->va_data_size;
  400. }
  401. fsai->valid |= FATTR_SIZE;
  402. if (vp) {
  403. struct fuse_filehandle *fufh = NULL;
  404. fufh_type_t fufh_type = FUFH_WRONLY;
  405. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  406. fufh = &(fvdat->fufh[fufh_type]);
  407. if (!FUFH_IS_VALID(fufh)) {
  408. fufh_type = FUFH_RDWR;
  409. fufh = &(fvdat->fufh[fufh_type]);
  410. if (!FUFH_IS_VALID(fufh)) {
  411. fufh = NULL;
  412. }
  413. }
  414. if (fufh) {
  415. fsai->fh = fufh->fh_id;
  416. fsai->valid |= FATTR_FH;
  417. }
  418. }
  419. }
  420. VATTR_SET_SUPPORTED(vap, va_data_size);
  421. /*
  422. * Possible timestamps:
  423. *
  424. * Mac OS X Linux FUSE API
  425. *
  426. * va_access_time last access time atime atime
  427. * va_backup_time last backup time - -
  428. * va_change_time last metadata change time ctime* -
  429. * va_create_time creation time - -
  430. * va_modify_time last data modification time mtime mtime
  431. *
  432. */
  433. if (VATTR_IS_ACTIVE(vap, va_access_time)) {
  434. fsai->atime = vap->va_access_time.tv_sec;
  435. /* XXX: truncation */
  436. fsai->atimensec = (uint32_t)vap->va_access_time.tv_nsec;
  437. fsai->valid |= FATTR_ATIME;
  438. }
  439. VATTR_SET_SUPPORTED(vap, va_access_time);
  440. if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
  441. fsai->mtime = vap->va_modify_time.tv_sec;
  442. /* XXX: truncation */
  443. fsai->mtimensec = (uint32_t)vap->va_modify_time.tv_nsec;
  444. fsai->valid |= FATTR_MTIME;
  445. }
  446. VATTR_SET_SUPPORTED(vap, va_modify_time);
  447. if (VATTR_IS_ACTIVE(vap, va_backup_time) && fuse_isxtimes_mp(mp)) {
  448. fsai->bkuptime = vap->va_backup_time.tv_sec;
  449. /* XXX: truncation */
  450. fsai->bkuptimensec = (uint32_t)vap->va_backup_time.tv_nsec;
  451. fsai->valid |= FATTR_BKUPTIME;
  452. VATTR_SET_SUPPORTED(vap, va_backup_time);
  453. }
  454. if (VATTR_IS_ACTIVE(vap, va_change_time)) {
  455. if (fuse_isxtimes_mp(mp)) {
  456. fsai->chgtime = vap->va_change_time.tv_sec;
  457. /* XXX: truncation */
  458. fsai->chgtimensec = (uint32_t)vap->va_change_time.tv_nsec;
  459. fsai->valid |= FATTR_CHGTIME;
  460. VATTR_SET_SUPPORTED(vap, va_change_time);
  461. }
  462. }
  463. if (VATTR_IS_ACTIVE(vap, va_create_time) && fuse_isxtimes_mp(mp)) {
  464. fsai->crtime = vap->va_create_time.tv_sec;
  465. /* XXX: truncation */
  466. fsai->crtimensec = (uint32_t)vap->va_create_time.tv_nsec;
  467. fsai->valid |= FATTR_CRTIME;
  468. VATTR_SET_SUPPORTED(vap, va_create_time);
  469. }
  470. if (VATTR_IS_ACTIVE(vap, va_mode)) {
  471. fsai->mode = vap->va_mode & ALLPERMS;
  472. fsai->valid |= FATTR_MODE;
  473. }
  474. VATTR_SET_SUPPORTED(vap, va_mode);
  475. if (VATTR_IS_ACTIVE(vap, va_flags)) {
  476. fsai->flags = vap->va_flags;
  477. fsai->valid |= FATTR_FLAGS;
  478. }
  479. VATTR_SET_SUPPORTED(vap, va_flags);
  480. /*
  481. * We /are/ OK with va_acl, va_guuid, and va_uuuid passing through here.
  482. */
  483. return sizechanged;
  484. }
  485. /* ioctl */
  486. __private_extern__
  487. int
  488. fuse_internal_ioctl_avfi(vnode_t vp, __unused vfs_context_t context,
  489. struct fuse_avfi_ioctl *avfi)
  490. {
  491. int ret = 0;
  492. uint32_t hint = 0;
  493. if (!avfi) {
  494. return EINVAL;
  495. }
  496. if (avfi->cmd & FUSE_AVFI_MARKGONE) {
  497. /*
  498. * TBD
  499. */
  500. return EINVAL;
  501. }
  502. /* The result of this /does/ alter our return value. */
  503. if (avfi->cmd & FUSE_AVFI_UBC) {
  504. int ubc_flags = avfi->ubc_flags & (UBC_PUSHDIRTY | UBC_PUSHALL |
  505. UBC_INVALIDATE | UBC_SYNC);
  506. if (ubc_msync(vp, (off_t)0, ubc_getsize(vp), (off_t*)0,
  507. ubc_flags) == 0) {
  508. /* failed */
  509. ret = EINVAL; /* don't really have a good error to return */
  510. }
  511. }
  512. if (avfi->cmd & FUSE_AVFI_UBC_SETSIZE) {
  513. if (VTOFUD(vp)->filesize != avfi->size) {
  514. hint |= NOTE_WRITE;
  515. if (avfi->size > VTOFUD(vp)->filesize) {
  516. hint |= NOTE_EXTEND;
  517. }
  518. VTOFUD(vp)->filesize = avfi->size;
  519. ubc_setsize(vp, avfi->size);
  520. }
  521. (void)fuse_invalidate_attr(vp);
  522. }
  523. /* The result of this doesn't alter our return value. */
  524. if (avfi->cmd & FUSE_AVFI_PURGEATTRCACHE) {
  525. hint |= NOTE_ATTRIB;
  526. (void)fuse_invalidate_attr(vp);
  527. }
  528. /* The result of this doesn't alter our return value. */
  529. if (avfi->cmd & FUSE_AVFI_PURGEVNCACHE) {
  530. (void)fuse_vncache_purge(vp);
  531. }
  532. if (avfi->cmd & FUSE_AVFI_KNOTE) {
  533. hint |= avfi->note;
  534. }
  535. if (hint) {
  536. FUSE_KNOTE(vp, hint);
  537. }
  538. return ret;
  539. }
  540. /* readdir */
  541. __private_extern__
  542. int
  543. fuse_internal_readdir(vnode_t vp,
  544. uio_t uio,
  545. vfs_context_t context,
  546. struct fuse_filehandle *fufh,
  547. struct fuse_iov *cookediov,
  548. int *numdirent)
  549. {
  550. int err = 0;
  551. struct fuse_dispatcher fdi;
  552. struct fuse_read_in *fri;
  553. struct fuse_data *data;
  554. if (uio_resid(uio) == 0) {
  555. return 0;
  556. }
  557. fdisp_init(&fdi, 0);
  558. /* Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p I/O). */
  559. while (uio_resid(uio) > 0) {
  560. fdi.iosize = sizeof(*fri);
  561. fdisp_make_vp(&fdi, FUSE_READDIR, vp, context);
  562. fri = fdi.indata;
  563. fri->fh = fufh->fh_id;
  564. fri->offset = uio_offset(uio);
  565. data = fuse_get_mpdata(vnode_mount(vp));
  566. fri->size = (typeof(fri->size))min((size_t)uio_resid(uio), data->iosize);
  567. if ((err = fdisp_wait_answ(&fdi))) {
  568. goto out;
  569. }
  570. if ((err = fuse_internal_readdir_processdata(vp,
  571. uio,
  572. fri->size,
  573. fdi.answ,
  574. fdi.iosize,
  575. cookediov,
  576. numdirent))) {
  577. break;
  578. }
  579. }
  580. /* done: */
  581. fuse_ticket_drop(fdi.tick);
  582. out:
  583. return ((err == -1) ? 0 : err);
  584. }
  585. __private_extern__
  586. int
  587. fuse_internal_readdir_processdata(vnode_t vp,
  588. uio_t uio,
  589. __unused size_t reqsize,
  590. void *buf,
  591. size_t bufsize,
  592. struct fuse_iov *cookediov,
  593. int *numdirent)
  594. {
  595. int err = 0;
  596. int cou = 0;
  597. int n = 0;
  598. size_t bytesavail;
  599. size_t freclen;
  600. struct dirent *de;
  601. struct fuse_dirent *fudge;
  602. if (bufsize < FUSE_NAME_OFFSET) {
  603. return -1;
  604. }
  605. for (;;) {
  606. if (bufsize < FUSE_NAME_OFFSET) {
  607. err = -1;
  608. break;
  609. }
  610. fudge = (struct fuse_dirent *)buf;
  611. freclen = FUSE_DIRENT_SIZE(fudge);
  612. cou++;
  613. if (bufsize < freclen) {
  614. err = ((cou == 1) ? -1 : 0);
  615. break;
  616. }
  617. /*
  618. * if (isbzero(buf, FUSE_NAME_OFFSET)) {
  619. * // zero-pad incomplete buffer
  620. * ...
  621. * err = -1;
  622. * break;
  623. * }
  624. */
  625. if (!fudge->namelen) {
  626. err = EINVAL;
  627. break;
  628. }
  629. if (fudge->namelen > FUSE_MAXNAMLEN) {
  630. err = EIO;
  631. break;
  632. }
  633. #define GENERIC_DIRSIZ(dp) \
  634. ((sizeof(struct dirent) - (FUSE_MAXNAMLEN + 1)) + \
  635. (((dp)->d_namlen + 1 + 3) & ~3))
  636. bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)&fudge->namelen);
  637. if (bytesavail > (size_t)uio_resid(uio)) {
  638. err = -1;
  639. break;
  640. }
  641. fiov_refresh(cookediov);
  642. fiov_adjust(cookediov, bytesavail);
  643. de = (struct dirent *)cookediov->base;
  644. #if __DARWIN_64_BIT_INO_T
  645. de->d_fileno = fudge->ino;
  646. #else
  647. de->d_fileno = (ino_t)fudge->ino; /* XXX: truncation */
  648. #endif /* __DARWIN_64_BIT_INO_T */
  649. de->d_reclen = bytesavail;
  650. de->d_type = fudge->type;
  651. de->d_namlen = fudge->namelen;
  652. /* Filter out any ._* files if the mount is configured as such. */
  653. if (fuse_skip_apple_double_mp(vnode_mount(vp),
  654. fudge->name, fudge->namelen)) {
  655. de->d_fileno = 0;
  656. de->d_type = DT_WHT;
  657. }
  658. memcpy((char *)cookediov->base +
  659. sizeof(struct dirent) - FUSE_MAXNAMLEN - 1,
  660. (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
  661. ((char *)cookediov->base)[bytesavail] = '\0';
  662. err = uiomove(cookediov->base, (int)cookediov->len, uio);
  663. if (err) {
  664. break;
  665. }
  666. n++;
  667. buf = (char *)buf + freclen;
  668. bufsize -= freclen;
  669. uio_setoffset(uio, fudge->off);
  670. }
  671. if (!err && numdirent) {
  672. *numdirent = n;
  673. }
  674. return err;
  675. }
  676. /* remove */
  677. static int
  678. fuse_internal_remove_callback(vnode_t vp, void *cargs)
  679. {
  680. struct vnode_attr *vap;
  681. uint64_t target_nlink;
  682. vap = VTOVA(vp);
  683. target_nlink = *(uint64_t *)cargs;
  684. /* somewhat lame "heuristics", but you got better ideas? */
  685. if ((vap->va_nlink == target_nlink) && vnode_isreg(vp)) {
  686. fuse_invalidate_attr(vp);
  687. }
  688. return VNODE_RETURNED;
  689. }
  690. __private_extern__
  691. int
  692. fuse_internal_remove(vnode_t dvp,
  693. vnode_t vp,
  694. struct componentname *cnp,
  695. enum fuse_opcode op,
  696. vfs_context_t context)
  697. {
  698. struct fuse_dispatcher fdi;
  699. struct vnode_attr *vap = VTOVA(vp);
  700. int need_invalidate = 0;
  701. uint64_t target_nlink = 0;
  702. mount_t mp = vnode_mount(vp);
  703. int err = 0;
  704. fdisp_init(&fdi, cnp->cn_namelen + 1);
  705. fdisp_make_vp(&fdi, op, dvp, context);
  706. memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
  707. ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
  708. if ((vap->va_nlink > 1) && vnode_isreg(vp)) {
  709. need_invalidate = 1;
  710. target_nlink = vap->va_nlink;
  711. }
  712. if (!(err = fdisp_wait_answ(&fdi))) {
  713. fuse_ticket_drop(fdi.tick);
  714. }
  715. fuse_invalidate_attr(dvp);
  716. fuse_invalidate_attr(vp);
  717. /*
  718. * XXX: M_MACFUSE_INVALIDATE_CACHED_VATTRS_UPON_UNLINK
  719. *
  720. * Consider the case where vap->va_nlink > 1 for the entity being
  721. * removed. In our world, other in-memory vnodes that share a link
  722. * count each with this one may not know right way that this one just
  723. * got deleted. We should let them know, say, through a vnode_iterate()
  724. * here and a callback that does fuse_invalidate_attr(vp) on each
  725. * relevant vnode.
  726. */
  727. if (need_invalidate && !err) {
  728. if (!vfs_busy(mp, LK_NOWAIT)) {
  729. vnode_iterate(mp, 0, fuse_internal_remove_callback,
  730. (void *)&target_nlink);
  731. vfs_unbusy(mp);
  732. } else {
  733. IOLog("MacFUSE: skipping link count fixup upon remove\n");
  734. }
  735. }
  736. return err;
  737. }
  738. /* rename */
  739. __private_extern__
  740. int
  741. fuse_internal_rename(vnode_t fdvp,
  742. __unused vnode_t fvp,
  743. struct componentname *fcnp,
  744. vnode_t tdvp,
  745. __unused vnode_t tvp,
  746. struct componentname *tcnp,
  747. vfs_context_t context)
  748. {
  749. struct fuse_dispatcher fdi;
  750. struct fuse_rename_in *fri;
  751. int err = 0;
  752. fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2);
  753. fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, context);
  754. fri = fdi.indata;
  755. fri->newdir = VTOI(tdvp);
  756. memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr,
  757. fcnp->cn_namelen);
  758. ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0';
  759. memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1,
  760. tcnp->cn_nameptr, tcnp->cn_namelen);
  761. ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen +
  762. tcnp->cn_namelen + 1] = '\0';
  763. if (!(err = fdisp_wait_answ(&fdi))) {
  764. fuse_ticket_drop(fdi.tick);
  765. }
  766. if (err == 0) {
  767. fuse_invalidate_attr(fdvp);
  768. if (tdvp != fdvp) {
  769. fuse_invalidate_attr(tdvp);
  770. }
  771. }
  772. return err;
  773. }
  774. /* revoke */
  775. __private_extern__
  776. int
  777. fuse_internal_revoke(vnode_t vp, int flags, vfs_context_t context, int how)
  778. {
  779. int ret = 0;
  780. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  781. fvdat->flag |= FN_REVOKED;
  782. if (how == REVOKE_HARD) {
  783. ret = vn_revoke(vp, flags, context);
  784. }
  785. return ret;
  786. }
  787. /* strategy */
  788. __private_extern__
  789. int
  790. fuse_internal_strategy(vnode_t vp, buf_t bp)
  791. {
  792. size_t biosize;
  793. size_t chunksize;
  794. size_t respsize;
  795. int mapped = FALSE;
  796. int mode;
  797. int op;
  798. int vtype = vnode_vtype(vp);
  799. int err = 0;
  800. caddr_t bufdat;
  801. off_t left;
  802. off_t offset;
  803. int32_t bflags = buf_flags(bp);
  804. fufh_type_t fufh_type;
  805. struct fuse_dispatcher fdi;
  806. struct fuse_data *data;
  807. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  808. struct fuse_filehandle *fufh = NULL;
  809. mount_t mp = vnode_mount(vp);
  810. data = fuse_get_mpdata(mp);
  811. biosize = data->blocksize;
  812. if (!(vtype == VREG || vtype == VDIR)) {
  813. return ENOTSUP;
  814. }
  815. if (bflags & B_READ) {
  816. mode = FREAD;
  817. fufh_type = FUFH_RDONLY; /* FUFH_RDWR will also do */
  818. } else {
  819. mode = FWRITE;
  820. fufh_type = FUFH_WRONLY; /* FUFH_RDWR will also do */
  821. }
  822. if (fvdat->flag & FN_CREATING) {
  823. fuse_lck_mtx_lock(fvdat->createlock);
  824. if (fvdat->flag & FN_CREATING) {
  825. (void)fuse_msleep(fvdat->creator, fvdat->createlock,
  826. PDROP | PINOD | PCATCH, "fuse_internal_strategy",
  827. NULL);
  828. } else {
  829. fuse_lck_mtx_unlock(fvdat->createlock);
  830. }
  831. }
  832. fufh = &(fvdat->fufh[fufh_type]);
  833. if (!FUFH_IS_VALID(fufh)) {
  834. fufh_type = FUFH_RDWR;
  835. fufh = &(fvdat->fufh[fufh_type]);
  836. if (!FUFH_IS_VALID(fufh)) {
  837. fufh = NULL;
  838. } else {
  839. /* We've successfully fallen back to FUFH_RDWR. */
  840. }
  841. }
  842. if (!fufh) {
  843. if (mode == FREAD) {
  844. fufh_type = FUFH_RDONLY;
  845. } else {
  846. fufh_type = FUFH_RDWR;
  847. }
  848. /*
  849. * Lets NOT do the filehandle preflight check here.
  850. */
  851. err = fuse_filehandle_get(vp, NULL, fufh_type, 0 /* mode */);
  852. if (!err) {
  853. fufh = &(fvdat->fufh[fufh_type]);
  854. FUFH_AUX_INC(fufh);
  855. /* We've created a NEW fufh of type fufh_type. open_count is 1. */
  856. }
  857. } else { /* good fufh */
  858. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_reuse_count);
  859. /* We're using an existing fufh of type fufh_type. */
  860. }
  861. if (err) {
  862. /* A more typical error case. */
  863. if ((err == ENOTCONN) || fuse_isdeadfs(vp)) {
  864. buf_seterror(bp, EIO);
  865. buf_biodone(bp);
  866. return EIO;
  867. }
  868. IOLog("MacFUSE: strategy failed to get fh "
  869. "(vtype=%d, fufh_type=%d, err=%d)\n", vtype, fufh_type, err);
  870. if (!vfs_issynchronous(mp)) {
  871. IOLog("MacFUSE: asynchronous write failed!\n");
  872. }
  873. buf_seterror(bp, EIO);
  874. buf_biodone(bp);
  875. return EIO;
  876. }
  877. if (!fufh) {
  878. panic("MacFUSE: tried everything but still no fufh");
  879. /* NOTREACHED */
  880. }
  881. #define B_INVAL 0x00040000 /* Does not contain valid info. */
  882. #define B_ERROR 0x00080000 /* I/O error occurred. */
  883. if (bflags & B_INVAL) {
  884. IOLog("MacFUSE: buffer does not contain valid information\n");
  885. }
  886. if (bflags & B_ERROR) {
  887. IOLog("MacFUSE: an I/O error has occured\n");
  888. }
  889. if (buf_count(bp) == 0) {
  890. return 0;
  891. }
  892. fdisp_init(&fdi, 0);
  893. if (mode == FREAD) {
  894. struct fuse_read_in *fri;
  895. buf_setresid(bp, buf_count(bp));
  896. offset = (off_t)((off_t)buf_blkno(bp) * biosize);
  897. if (offset >= fvdat->filesize) {
  898. /* Trying to read at/after EOF? */
  899. if (offset != fvdat->filesize) {
  900. /* Trying to read after EOF? */
  901. buf_seterror(bp, EINVAL);
  902. }
  903. buf_biodone(bp);
  904. return 0;
  905. }
  906. /* Note that we just made sure that offset < fvdat->filesize. */
  907. if ((offset + buf_count(bp)) > fvdat->filesize) {
  908. /* Trimming read */
  909. buf_setcount(bp, (uint32_t)(fvdat->filesize - offset));
  910. }
  911. if (buf_map(bp, &bufdat)) {
  912. IOLog("MacFUSE: failed to map buffer in strategy\n");
  913. return EFAULT;
  914. } else {
  915. mapped = TRUE;
  916. }
  917. while (buf_resid(bp) > 0) {
  918. chunksize = min((size_t)buf_resid(bp), data->iosize);
  919. fdi.iosize = sizeof(*fri);
  920. op = FUSE_READ;
  921. if (vtype == VDIR) {
  922. op = FUSE_READDIR;
  923. }
  924. fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0);
  925. fri = fdi.indata;
  926. fri->fh = fufh->fh_id;
  927. /*
  928. * Historical note:
  929. *
  930. * fri->offset = ((off_t)(buf_blkno(bp))) * biosize;
  931. *
  932. * This wasn't being incremented!?
  933. */
  934. fri->offset = offset;
  935. fri->size = (typeof(fri->size))chunksize;
  936. fdi.tick->tk_aw_type = FT_A_BUF;
  937. fdi.tick->tk_aw_bufdata = bufdat;
  938. if ((err = fdisp_wait_answ(&fdi))) {
  939. /* There was a problem with reading. */
  940. goto out;
  941. }
  942. respsize = fdi.tick->tk_aw_bufsize;
  943. if (respsize < 0) { /* Cannot really happen... */
  944. err = EIO;
  945. goto out;
  946. }
  947. buf_setresid(bp, (uint32_t)(buf_resid(bp) - respsize));
  948. bufdat += respsize;
  949. offset += respsize;
  950. /* Did we hit EOF before being done? */
  951. if ((respsize == 0) && (buf_resid(bp) > 0)) {
  952. /*
  953. * Historical note:
  954. * If we don't get enough data, just fill the rest with zeros.
  955. * In NFS context, this would mean a hole in the file.
  956. */
  957. /* Zero-pad the incomplete buffer. */
  958. bzero(bufdat, buf_resid(bp));
  959. buf_setresid(bp, 0);
  960. break;
  961. }
  962. } /* while (buf_resid(bp) > 0) */
  963. } else {
  964. /* write */
  965. struct fuse_write_in *fwi;
  966. struct fuse_write_out *fwo;
  967. int merr = 0;
  968. off_t diff;
  969. if (buf_map(bp, &bufdat)) {
  970. IOLog("MacFUSE: failed to map buffer in strategy\n");
  971. return EFAULT;
  972. } else {
  973. mapped = TRUE;
  974. }
  975. /* Write begin */
  976. buf_setresid(bp, buf_count(bp));
  977. offset = (off_t)((off_t)buf_blkno(bp) * biosize);
  978. /* XXX: TBD -- Check here for extension (writing past end) */
  979. left = buf_count(bp);
  980. while (left) {
  981. fdi.iosize = sizeof(*fwi);
  982. op = FUSE_WRITE;
  983. fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0);
  984. chunksize = min((size_t)left, data->iosize);
  985. fwi = fdi.indata;
  986. fwi->fh = fufh->fh_id;
  987. fwi->offset = offset;
  988. fwi->size = (typeof(fwi->size))chunksize;
  989. fdi.tick->tk_ms_type = FT_M_BUF;
  990. fdi.tick->tk_ms_bufdata = bufdat;
  991. fdi.tick->tk_ms_bufsize = chunksize;
  992. /* About to write <chunksize> at <offset> */
  993. if ((err = fdisp_wait_answ(&fdi))) {
  994. merr = 1;
  995. break;
  996. }
  997. fwo = fdi.answ;
  998. diff = chunksize - fwo->size;
  999. if (diff < 0) {
  1000. err = EINVAL;
  1001. break;
  1002. }
  1003. left -= fwo->size;
  1004. bufdat += fwo->size;
  1005. offset += fwo->size;
  1006. buf_setresid(bp, buf_resid(bp) - fwo->size);
  1007. }
  1008. if (merr) {
  1009. goto out;
  1010. }
  1011. }
  1012. if (fdi.tick) {
  1013. fuse_ticket_drop(fdi.tick);
  1014. } else {
  1015. /* No ticket upon leaving */
  1016. }
  1017. out:
  1018. if (err) {
  1019. buf_seterror(bp, err);
  1020. }
  1021. if (mapped == TRUE) {
  1022. buf_unmap(bp);
  1023. }
  1024. buf_biodone(bp);
  1025. return err;
  1026. }
  1027. __private_extern__
  1028. errno_t
  1029. fuse_internal_strategy_buf(struct vnop_strategy_args *ap)
  1030. {
  1031. int32_t bflags;
  1032. upl_t bupl;
  1033. daddr64_t blkno, lblkno;
  1034. int bmap_flags;
  1035. buf_t bp = ap->a_bp;
  1036. vnode_t vp = buf_vnode(bp);
  1037. int vtype = vnode_vtype(vp);
  1038. struct fuse_data *data;
  1039. if (!vp || vtype == VCHR || vtype == VBLK) {
  1040. panic("MacFUSE: buf_strategy: b_vp == NULL || vtype == VCHR | VBLK\n");
  1041. }
  1042. bflags = buf_flags(bp);
  1043. if (bflags & B_READ) {
  1044. bmap_flags = VNODE_READ;
  1045. } else {
  1046. bmap_flags = VNODE_WRITE;
  1047. }
  1048. bupl = buf_upl(bp);
  1049. blkno = buf_blkno(bp);
  1050. lblkno = buf_lblkno(bp);
  1051. if (!(bflags & B_CLUSTER)) {
  1052. if (bupl) {
  1053. return cluster_bp(bp);
  1054. }
  1055. if (blkno == lblkno) {
  1056. off_t f_offset;
  1057. size_t contig_bytes;
  1058. data = fuse_get_mpdata(vnode_mount(vp));
  1059. // Still think this is a kludge?
  1060. f_offset = lblkno * data->blocksize;
  1061. blkno = f_offset / data->blocksize;
  1062. buf_setblkno(bp, blkno);
  1063. contig_bytes = buf_count(bp);
  1064. if (blkno == -1) {
  1065. buf_clear(bp);
  1066. }
  1067. /*
  1068. * Our "device" is always /all contiguous/. We don't wanna be
  1069. * doing things like:
  1070. *
  1071. * ...
  1072. * else if ((long)contig_bytes < buf_count(bp)) {
  1073. * ret = buf_strategy_fragmented(devvp, bp, f_offset,
  1074. * contig_bytes));
  1075. * return ret;
  1076. * }
  1077. */
  1078. }
  1079. if (blkno == -1) {
  1080. buf_biodone(bp);
  1081. return 0;
  1082. }
  1083. }
  1084. // Issue the I/O
  1085. return fuse_internal_strategy(vp, bp);
  1086. }
  1087. /* entity creation */
  1088. __private_extern__
  1089. void
  1090. fuse_internal_newentry_makerequest(mount_t mp,
  1091. uint64_t dnid,
  1092. struct componentname *cnp,
  1093. enum fuse_opcode op,
  1094. void *buf,
  1095. size_t bufsize,
  1096. struct fuse_dispatcher *fdip,
  1097. vfs_context_t context)
  1098. {
  1099. fdisp_init(fdip, bufsize + cnp->cn_namelen + 1);
  1100. fdisp_make(fdip, op, mp, dnid, context);
  1101. memcpy(fdip->indata, buf, bufsize);
  1102. memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen);
  1103. ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0';
  1104. }
  1105. __private_extern__
  1106. int
  1107. fuse_internal_newentry_core(vnode_t dvp,
  1108. vnode_t *vpp,
  1109. struct componentname *cnp,
  1110. enum vtype vtyp,
  1111. struct fuse_dispatcher *fdip,
  1112. vfs_context_t context)
  1113. {
  1114. int err = 0;
  1115. struct fuse_entry_out *feo;
  1116. mount_t mp = vnode_mount(dvp);
  1117. if ((err = fdisp_wait_answ(fdip))) {
  1118. return err;
  1119. }
  1120. feo = fdip->answ;
  1121. if ((err = fuse_internal_checkentry(feo, vtyp))) {
  1122. goto out;
  1123. }
  1124. err = fuse_vget_i(vpp, 0 /* flags */, feo, cnp, dvp, mp, context);
  1125. if (err) {
  1126. fuse_internal_forget_send(mp, context, feo->nodeid, 1, fdip);
  1127. return err;
  1128. }
  1129. cache_attrs(*vpp, feo);
  1130. out:
  1131. fuse_ticket_drop(fdip->tick);
  1132. return err;
  1133. }
  1134. __private_extern__
  1135. int
  1136. fuse_internal_newentry(vnode_t dvp,
  1137. vnode_t *vpp,
  1138. struct componentname *cnp,
  1139. enum fuse_opcode op,
  1140. void *buf,
  1141. size_t bufsize,
  1142. enum vtype vtype,
  1143. vfs_context_t context)
  1144. {
  1145. int err;
  1146. struct fuse_dispatcher fdi;
  1147. mount_t mp = vnode_mount(dvp);
  1148. if (fuse_skip_apple_double_mp(mp, cnp->cn_nameptr, cnp->cn_namelen)) {
  1149. return EACCES;
  1150. }
  1151. fdisp_init(&fdi, 0);
  1152. fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf,
  1153. bufsize, &fdi, context);
  1154. err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi, context);
  1155. fuse_invalidate_attr(dvp);
  1156. return err;
  1157. }
  1158. /* entity destruction */
  1159. __private_extern__
  1160. int
  1161. fuse_internal_forget_callback(struct fuse_ticket *ftick, __unused uio_t uio)
  1162. {
  1163. struct fuse_dispatcher fdi;
  1164. fdi.tick = ftick;
  1165. fuse_internal_forget_send(ftick->tk_data->mp, (vfs_context_t)0,
  1166. ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1, &fdi);
  1167. return 0;
  1168. }
  1169. __private_extern__
  1170. void
  1171. fuse_internal_forget_send(mount_t mp,
  1172. vfs_context_t context,
  1173. uint64_t nodeid,
  1174. uint64_t nlookup,
  1175. struct fuse_dispatcher *fdip)
  1176. {
  1177. struct fuse_forget_in *ffi;
  1178. /*
  1179. * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu",
  1180. * (long long unsigned) nodeid));
  1181. */
  1182. fdisp_init(fdip, sizeof(*ffi));
  1183. fdisp_make(fdip, FUSE_FORGET, mp, nodeid, context);
  1184. ffi = fdip->indata;
  1185. ffi->nlookup = nlookup;
  1186. fticket_invalidate(fdip->tick);
  1187. fuse_insert_message(fdip->tick);
  1188. }
  1189. __private_extern__
  1190. void
  1191. fuse_internal_interrupt_send(struct fuse_ticket *ftick)
  1192. {
  1193. struct fuse_dispatcher fdi;
  1194. struct fuse_interrupt_in *fii;
  1195. fdi.tick = ftick;
  1196. fdisp_init(&fdi, sizeof(*fii));
  1197. fdisp_make(&fdi, FUSE_INTERRUPT, ftick->tk_data->mp, (uint64_t)0,
  1198. (vfs_context_t)0);
  1199. fii = fdi.indata;
  1200. fii->unique = ftick->tk_unique;
  1201. fticket_invalidate(fdi.tick);
  1202. fuse_insert_message(fdi.tick);
  1203. }
  1204. __private_extern__
  1205. void
  1206. fuse_internal_vnode_disappear(vnode_t vp, vfs_context_t context, int how)
  1207. {
  1208. int err = 0;
  1209. fuse_vncache_purge(vp);
  1210. if (how != REVOKE_NONE) {
  1211. err = fuse_internal_revoke(vp, REVOKEALL, context, how);
  1212. if (err) {
  1213. IOLog("MacFUSE: disappearing act: revoke failed (%d)\n", err);
  1214. }
  1215. err = vnode_recycle(vp);
  1216. if (err) {
  1217. IOLog("MacFUSE: disappearing act: recycle failed (%d)\n", err);
  1218. }
  1219. }
  1220. }
  1221. /* fuse start/stop */
  1222. __private_extern__
  1223. int
  1224. fuse_internal_init_synchronous(struct fuse_ticket *ftick)
  1225. {
  1226. int err = 0;
  1227. struct fuse_init_out *fiio;
  1228. struct fuse_data *data = ftick->tk_data;
  1229. if ((err = ftick->tk_aw_ohead.error)) {
  1230. goto out;
  1231. }
  1232. fiio = fticket_resp(ftick)->base;
  1233. if ((fiio->major < MACFUSE_MIN_USER_VERSION_MAJOR) ||
  1234. (fiio->minor < MACFUSE_MIN_USER_VERSION_MINOR)){
  1235. IOLog("MacFUSE: user-space library has too low a version\n");
  1236. err = EPROTONOSUPPORT;
  1237. goto out;
  1238. }
  1239. data->fuse_libabi_major = fiio->major;
  1240. data->fuse_libabi_minor = fiio->minor;
  1241. if (fuse_libabi_geq(data, MACFUSE_MIN_USER_VERSION_MAJOR,
  1242. MACFUSE_MIN_USER_VERSION_MINOR)) {
  1243. if (fticket_resp(ftick)->len == sizeof(struct fuse_init_out)) {
  1244. data->max_write = fiio->max_write;
  1245. } else {
  1246. err = EINVAL;
  1247. }
  1248. } else {
  1249. /* Old fix values */
  1250. data->max_write = 4096;
  1251. }
  1252. if (fiio->flags & FUSE_CASE_INSENSITIVE) {
  1253. data->dataflags |= FSESS_CASE_INSENSITIVE;
  1254. }
  1255. if (fiio->flags & FUSE_VOL_RENAME) {
  1256. data->dataflags |= FSESS_VOL_RENAME;
  1257. }
  1258. if (fiio->flags & FUSE_XTIMES) {
  1259. data->dataflags |= FSESS_XTIMES;
  1260. }
  1261. out:
  1262. fuse_ticket_drop(ftick);
  1263. if (err) {
  1264. fdata_set_dead(data);
  1265. }
  1266. fuse_lck_mtx_lock(data->ticket_mtx);
  1267. data->dataflags |= FSESS_INITED;
  1268. fuse_wakeup(&data->ticketer);
  1269. fuse_lck_mtx_unlock(data->ticket_mtx);
  1270. return 0;
  1271. }
  1272. __private_extern__
  1273. int
  1274. fuse_internal_send_init(struct fuse_data *data, vfs_context_t context)
  1275. {
  1276. int err = 0;
  1277. struct fuse_init_in *fiii;
  1278. struct fuse_dispatcher fdi;
  1279. fdisp_init(&fdi, sizeof(*fiii));
  1280. fdisp_make(&fdi, FUSE_INIT, data->mp, 0, context);
  1281. fiii = fdi.indata;
  1282. fiii->major = FUSE_KERNEL_VERSION;
  1283. fiii->minor = FUSE_KERNEL_MINOR_VERSION;
  1284. fiii->max_readahead = data->iosize * 16;
  1285. fiii->flags = 0;
  1286. /* blocking FUSE_INIT up to user space */
  1287. err = fdisp_wait_answ(&fdi);
  1288. if (err) {
  1289. IOLog("MacFUSE: user-space initialization failed (%d)\n", err);
  1290. return err;
  1291. }
  1292. err = fuse_internal_init_synchronous(fdi.tick);
  1293. if (err) {
  1294. IOLog("MacFUSE: in-kernel initialization failed (%d)\n", err);
  1295. return err;
  1296. }
  1297. return 0;
  1298. }
  1299. /* other */
  1300. static int
  1301. fuse_internal_print_vnodes_callback(vnode_t vp, __unused void *cargs)
  1302. {
  1303. const char *vname = NULL;
  1304. struct fuse_vnode_data *fvdat = VTOFUD(vp);
  1305. #if M_MACFUSE_ENABLE_UNSUPPORTED
  1306. vname = vnode_getname(vp);
  1307. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  1308. if (vname) {
  1309. IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d %s\n",
  1310. vp, fvdat->nodeid, fvdat->parent_nodeid,
  1311. vnode_isinuse(vp, 0), vname);
  1312. } else {
  1313. if (fvdat->nodeid == FUSE_ROOT_ID) {
  1314. IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d /\n",
  1315. vp, fvdat->nodeid, fvdat->parent_nodeid,
  1316. vnode_isinuse(vp, 0));
  1317. } else {
  1318. IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d\n",
  1319. vp, fvdat->nodeid, fvdat->parent_nodeid,
  1320. vnode_isinuse(vp, 0));
  1321. }
  1322. }
  1323. #if M_MACFUSE_ENABLE_UNSUPPORTED
  1324. if (vname) {
  1325. vnode_putname(vname);
  1326. }
  1327. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  1328. return VNODE_RETURNED;
  1329. }
  1330. __private_extern__
  1331. void
  1332. fuse_internal_print_vnodes(mount_t mp)
  1333. {
  1334. vnode_iterate(mp, VNODE_ITERATE_ALL,
  1335. fuse_internal_print_vnodes_callback, NULL);
  1336. }
  1337. __private_extern__
  1338. void
  1339. fuse_preflight_log(vnode_t vp, fufh_type_t fufh_type, int err, char *message)
  1340. {
  1341. const char *vname = NULL;
  1342. #if M_MACFUSE_ENABLE_UNSUPPORTED
  1343. vname = vnode_getname(vp);
  1344. #else
  1345. (void)vname;
  1346. (void)vp;
  1347. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  1348. if (vname) {
  1349. IOLog("MacFUSE: file handle preflight "
  1350. "(caller=%s, type=%d, err=%d, name=%s)\n",
  1351. message, fufh_type, err, vname);
  1352. } else {
  1353. IOLog("MacFUSE: file handle preflight "
  1354. "(caller=%s, type=%d, err=%d)\n", message, fufh_type, err);
  1355. }
  1356. #if M_MACFUSE_ENABLE_UNSUPPORTED
  1357. if (vname) {
  1358. vnode_putname(vname);
  1359. }
  1360. #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
  1361. }