1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <mach/mach_types.h>
32#include <mach/machine/boolean.h>
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/file.h>
37#include <sys/stat.h>
38#include <sys/proc.h>
39#include <sys/kauth.h>
40#include <sys/conf.h>
41#include <sys/mount_internal.h>
42#include <sys/vnode_internal.h>
43#include <sys/malloc.h>
44#include <sys/dirent.h>
45#include <sys/namei.h>
46#include <sys/attr.h>
47#include <sys/uio_internal.h>
48
49#include <sys/vm.h>
50#include <sys/errno.h>
51#include <vfs/vfs_support.h>
52
53#include "synthfs.h"
54
55#define RWSUPPORT 0
56
57#if RWSUPPORT
58#error NOT PORTED FOR UBC
59#include <sys/ubc.h>
60#endif
61
62static int synthfs_remove_internal(struct vnode *dvp, struct vnode *vp,
63 struct componentname *cnp, vfs_context_t context);
64
65
66#define VOPFUNC int (*)(void *)
67
68
69int (**synthfs_vnodeop_p) (void *);
70struct vnodeopv_entry_desc synthfs_vnodeop_entries[] = {
71 {&vnop_default_desc, (VOPFUNC)vn_default_error},
72 {&vnop_strategy_desc, (VOPFUNC)err_strategy},
73 {&vnop_bwrite_desc, (VOPFUNC)err_bwrite},
74 {&vnop_lookup_desc, (VOPFUNC)synthfs_cached_lookup},
75 {&vnop_create_desc, (VOPFUNC)synthfs_create},
76 {&vnop_whiteout_desc, (VOPFUNC)err_whiteout},
77 {&vnop_mknod_desc, (VOPFUNC)err_mknod},
78 {&vnop_open_desc, (VOPFUNC)synthfs_open},
79 {&vnop_close_desc, (VOPFUNC)nop_close},
80 {&vnop_getattr_desc, (VOPFUNC)synthfs_getattr},
81 {&vnop_setattr_desc, (VOPFUNC)synthfs_setattr},
82 {&vnop_getattrlist_desc, (VOPFUNC)err_getattrlist},
83 {&vnop_setattrlist_desc, (VOPFUNC)err_setattrlist},
84 {&vnop_read_desc, (VOPFUNC)err_read},
85 {&vnop_write_desc, (VOPFUNC)err_write},
86 {&vnop_ioctl_desc, (VOPFUNC)err_ioctl},
87 {&vnop_select_desc, (VOPFUNC)synthfs_select},
88 {&vnop_exchange_desc, (VOPFUNC)err_exchange},
89 {&vnop_revoke_desc, (VOPFUNC)nop_revoke},
90 {&vnop_mmap_desc, (VOPFUNC)synthfs_mmap},
91 {&vnop_fsync_desc, (VOPFUNC)nop_fsync},
92 {&vnop_remove_desc, (VOPFUNC)synthfs_remove},
93 {&vnop_link_desc, (VOPFUNC)err_link},
94 {&vnop_rename_desc, (VOPFUNC)synthfs_rename},
95 {&vnop_mkdir_desc, (VOPFUNC)synthfs_mkdir},
96 {&vnop_rmdir_desc, (VOPFUNC)synthfs_rmdir},
97 {&vnop_symlink_desc, (VOPFUNC)synthfs_symlink},
98 {&vnop_readdir_desc, (VOPFUNC)synthfs_readdir},
99 {&vnop_readdirattr_desc, (VOPFUNC)err_readdirattr},
100 {&vnop_readlink_desc, (VOPFUNC)synthfs_readlink},
101 {&vnop_inactive_desc, (VOPFUNC)synthfs_inactive},
102 {&vnop_reclaim_desc, (VOPFUNC)synthfs_reclaim},
103 {&vnop_pathconf_desc, (VOPFUNC)synthfs_pathconf},
104 {&vnop_advlock_desc, (VOPFUNC)err_advlock},
105 {&vnop_allocate_desc, (VOPFUNC)err_allocate},
106 {&vnop_pagein_desc, (VOPFUNC)err_pagein},
107 {&vnop_pageout_desc, (VOPFUNC)err_pageout},
108 {&vnop_devblocksize_desc, (VOPFUNC)err_devblocksize},
109 {&vnop_searchfs_desc, (VOPFUNC)err_searchfs},
110 {&vnop_copyfile_desc, (VOPFUNC)err_copyfile},
111 { &vnop_blktooff_desc, (VOPFUNC)err_blktooff },
112 { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk },
113 { &vnop_blockmap_desc, (VOPFUNC)err_blockmap },
114 {(struct vnodeop_desc *) NULL, (int (*) ()) NULL}
115};
116
117
118
119
120
121struct vnodeopv_desc synthfs_vnodeop_opv_desc =
122{&synthfs_vnodeop_p, synthfs_vnodeop_entries};
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142int
143synthfs_create(ap)
144struct vnop_create_args
145
146
147
148
149
150 *ap;
151{
152#if DEBUG
153 struct vnode *dvp = ap->a_dvp;
154 char debugmsg[255];
155
156 sprintf(debugmsg, "synthfs_create: attempt to create '%s' in '%s' ?!", ap->a_cnp->cn_nameptr, VTOS(dvp)->s_name);
157 Debugger(debugmsg);
158#endif
159
160 return err_create(ap);
161}
162
163
164
165
166
167
168
169
170
171
172
173
174
175int
176synthfs_open(ap)
177struct vnop_open_args
178
179
180
181 *ap;
182{
183 struct vnode *vp = ap->a_vp;
184
185 if (vp->v_type == VDIR) {
186 return 0;
187 } else {
188#if DEBUG
189 struct synthfsnode *sp = VTOS(vp);
190 char debugmsg[255];
191
192 sprintf(debugmsg, "synthfs_open: attempt to open '/%s' ?!", sp->s_name);
193 Debugger(debugmsg);
194#endif
195 };
196
197 return 0;
198}
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218int
219synthfs_mmap(__unused struct vnop_mmap_args *ap)
220{
221 return EINVAL;
222}
223
224
225
226
227
228
229
230
231
232
233
234
235int
236synthfs_getattr(ap)
237struct vnop_getattr_args
238
239
240
241 *ap;
242{
243 struct vnode *vp = ap->a_vp;
244 struct vnode_attr *vap = ap->a_vap;
245 struct synthfsnode *sp = VTOS(vp);
246
247 VATTR_RETURN(vap, va_type, vp->v_type);
248 VATTR_RETURN(vap, va_mode, sp->s_mode);
249 VATTR_RETURN(vap, va_nlink, sp->s_linkcount);
250 VATTR_RETURN(vap, va_uid, sp->s_uid);
251 VATTR_RETURN(vap, va_gid, sp->s_gid);
252 VATTR_RETURN(vap, va_fsid, VTOVFS(vp)->mnt_vfsstat.f_fsid.val[0]);
253 VATTR_RETURN(vap, va_fileid, sp->s_nodeid);
254 switch (vp->v_type) {
255 case VDIR:
256 VATTR_RETURN(vap, va_data_size, (sp->s_u.d.d_entrycount + 2) * sizeof(struct dirent));
257 break;
258
259 case VREG:
260 VATTR_RETURN(vap, va_data_size, sp->s_u.f.f_size);
261 break;
262
263 case VLNK:
264 VATTR_RETURN(vap, va_data_size, sp->s_u.s.s_length);
265 break;
266
267 default:
268 VATTR_RETURN(vap, va_data_size, 0);
269 };
270 VATTR_RETURN(vap, va_iosize, 512);
271 vap->va_access_time.tv_sec = sp->s_accesstime.tv_sec;
272 vap->va_access_time.tv_nsec = sp->s_accesstime.tv_usec * 1000;
273 VATTR_SET_SUPPORTED(vap, va_access_time);
274 vap->va_modify_time.tv_sec = sp->s_modificationtime.tv_sec;
275 vap->va_modify_time.tv_nsec = sp->s_modificationtime.tv_usec * 1000;
276 VATTR_SET_SUPPORTED(vap, va_modify_time);
277 vap->va_change_time.tv_sec = sp->s_changetime.tv_sec;
278 vap->va_change_time.tv_nsec = sp->s_changetime.tv_usec * 1000;
279 VATTR_SET_SUPPORTED(vap, va_change_time);
280 VATTR_RETURN(vap, va_gen, sp->s_generation);
281 VATTR_RETURN(vap, va_flags, sp->s_flags);
282 VATTR_RETURN(vap, va_rdev, sp->s_rdev);
283 VATTR_RETURN(vap, va_filerev, 0);
284 VATTR_RETURN(vap, va_acl, NULL);
285
286 return (0);
287}
288
289
290
291
292
293
294
295int synthfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct proc *p)
296{
297 struct synthfsnode *sp = VTOS(vp);
298 int result;
299
300 sp->s_mode &= ~ALLPERMS;
301 sp->s_mode |= (mode & ALLPERMS);
302 sp->s_nodeflags |= IN_CHANGE;
303#if RWSUPPORT
304 if ((vp->v_flag & VTEXT) && (sp->s_mode & S_ISTXT) == 0) (void) vnode_uncache(vp);
305#endif
306
307 return 0;
308}
309
310
311
312
313
314
315
316int synthfs_chflags(struct vnode *vp, u_long flags, kauth_cred_t cred, struct proc *p)
317{
318 struct synthfsnode *sp = VTOS(vp);
319
320 sp->s_flags = flags;
321 sp->s_nodeflags |= IN_CHANGE;
322
323 return 0;
324}
325
326
327
328
329
330
331
332int synthfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, struct proc *p)
333{
334 struct synthfsnode *sp = VTOS(vp);
335 uid_t ouid;
336 gid_t ogid;
337 int result = 0;
338 int is_member;
339
340 if (uid == (uid_t)VNOVAL) uid = sp->s_uid;
341 if (gid == (gid_t)VNOVAL) gid = sp->s_gid;
342
343 ogid = sp->s_gid;
344 ouid = sp->s_uid;
345
346 sp->s_gid = gid;
347 sp->s_uid = uid;
348
349 if (ouid != uid || ogid != gid) sp->s_nodeflags |= IN_CHANGE;
350 if (ouid != uid && suser(cred, NULL)) sp->s_mode &= ~S_ISUID;
351 if (ogid != gid && suser(cred, NULL)) sp->s_mode &= ~S_ISGID;
352
353 return 0;
354}
355
356
357
358
359
360
361
362
363
364
365
366
367
368int
369synthfs_setattr(ap)
370struct vnop_setattr_args
371
372
373
374 *ap;
375{
376 struct vnode *vp = ap->a_vp;
377 struct synthfsnode *sp = VTOS(vp);
378 struct vnode_attr *vap = ap->a_vap;
379 kauth_cred_t cred = vfs_context_ucred(ap->a_context);
380 struct proc *p = vfs_context_proc(ap->a_context);
381 struct timeval atimeval, mtimeval;
382 uid_t nuid;
383 gid_t ngid;
384 int result;
385
386 result = 0;
387
388 if (VATTR_IS_ACTIVE(vap, va_flags)) {
389 if ((result = synthfs_chflags(vp, vap->va_flags, cred, p))) {
390 goto Err_Exit;
391 }
392 }
393 VATTR_SET_SUPPORTED(vap, va_flags);
394
395 nuid = (uid_t)ngid = (gid_t)VNOVAL;
396 if (VATTR_IS_ACTIVE(vap, va_uid))
397 nuid = vap->va_uid;
398 if (VATTR_IS_ACTIVE(vap, va_gid))
399 ngid = vap->va_gid;
400 if (nuid != (uid_t)VNOVAL || ngid != (gid_t)VNOVAL) {
401 if ((result = synthfs_chown(vp, nuid, ngid, cred, p))) {
402 goto Err_Exit;
403 }
404 }
405 VATTR_SET_SUPPORTED(vap, va_uid);
406 VATTR_SET_SUPPORTED(vap, va_gid);
407
408 if (VATTR_IS_ACTIVE(vap, va_data_size)) {
409#if RWSUPPORT
410 if ((result = vnode_setsize(vp, vap->va_data_size, 0, ap->a_context))) {
411 goto Err_Exit;
412 };
413 VATTR_SET_SUPPORTED(vap, va_data_size);
414#else
415 result = EINVAL;
416 goto Err_Exit;
417#endif
418 }
419
420 sp = VTOS(vp);
421 if (VATTR_IS_ACTIVE(vap, va_access_time) || VATTR_IS_ACTIVE(vap, va_modify_time)) {
422 if (VATTR_IS_ACTIVE(vap, va_access_time)) {
423 sp->s_nodeflags |= IN_ACCESS;
424 atimeval.tv_sec = vap->va_access_time.tv_sec;
425 atimeval.tv_usec = vap->va_access_time.tv_nsec / 1000;
426 }
427 if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
428 sp->s_nodeflags |= IN_CHANGE | IN_UPDATE;
429 mtimeval.tv_sec = vap->va_modify_time.tv_sec;
430 mtimeval.tv_usec = vap->va_modify_time.tv_nsec / 1000;
431 }
432 if ((result = synthfs_update(vp, &atimeval, &mtimeval, 1))) {
433 goto Err_Exit;
434 }
435 }
436 VATTR_SET_SUPPORTED(vap, va_access_time);
437 VATTR_SET_SUPPORTED(vap, va_modify_time);
438
439 if (VATTR_IS_ACTIVE(vap, va_mode))
440 result = synthfs_chmod(vp, (int)vap->va_mode, cred, p);
441 VATTR_SET_SUPPORTED(vap, va_mode);
442
443 Err_Exit:
444
445 DBG_VOP(("synthfs_setattr: returning %d...\n", result));
446
447 return (result);
448}
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482int
483synthfs_rename(ap)
484struct vnop_rename_args
485
486
487
488
489
490
491
492 *ap;
493{
494 struct vnode *target_vp = ap->a_tvp;
495 struct vnode *targetPar_vp = ap->a_tdvp;
496 struct vnode *source_vp = ap->a_fvp;
497 struct vnode *sourcePar_vp = ap->a_fdvp;
498 struct componentname *target_cnp = ap->a_tcnp;
499 struct componentname *source_cnp = ap->a_fcnp;
500 struct synthfsnode *target_sp, *targetPar_sp, *source_sp, *sourcePar_sp;
501 u_short doingdirectory = 0, oldparent = 0, newparent = 0;
502 int retval = 0;
503 struct timeval tv;
504
505#if SYNTHFS_DIAGNOSTIC
506 if ((target_cnp->cn_flags & HASBUF) == 0 ||
507 (source_cnp->cn_flags & HASBUF) == 0)
508 panic("synthfs_rename: no name");
509#endif
510
511 DBG_ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR));
512 target_sp = targetPar_sp = source_sp = sourcePar_sp = NULL;
513
514
515 sourcePar_sp = VTOS(sourcePar_vp);
516 source_sp = VTOS(source_vp);
517 oldparent = sourcePar_sp->s_nodeid;
518
519
520
521
522
523
524
525 if (source_sp->s_type == SYNTHFS_DIRECTORY) {
526 if ((source_cnp->cn_namelen == 1 && source_cnp->cn_nameptr[0] == '.')
527 || sourcePar_sp == source_sp
528 || (source_cnp->cn_flags & ISDOTDOT)
529 || (source_sp->s_nodeflags & IN_RENAME)) {
530 retval = EINVAL;
531 goto abortit;
532 }
533 source_sp->s_nodeflags |= IN_RENAME;
534 doingdirectory = TRUE;
535 }
536
537
538
539 targetPar_sp = VTOS(targetPar_vp);
540 target_sp = target_vp ? VTOS(target_vp) : NULL;
541 newparent = targetPar_sp->s_nodeid;
542
543
544
545
546
547
548
549 if (target_vp) {
550
551#if RWSUPPORT
552 if (target_vp->v_type == VREG) {
553 (void) vnode_uncache(target_vp);
554 };
555#endif
556 cache_purge(target_vp);
557
558 retval = synthfs_remove_internal(targetPar_vp, target_vp, target_cnp, ap->a_context);
559
560 target_vp = NULL;
561 target_sp = NULL;
562
563 if (retval) goto bad;
564 };
565
566
567
568 if (source_vp->v_type == VREG) cache_purge(source_vp);
569
570 retval = synthfs_move_rename_entry( source_vp, targetPar_vp, target_cnp->cn_nameptr);
571
572 if (retval) goto bad;
573
574 source_sp->s_nodeflags &= ~IN_RENAME;
575
576
577
578
579
580
581
582 targetPar_sp->s_nodeflags |= IN_UPDATE;
583 sourcePar_sp->s_nodeflags |= IN_UPDATE;
584
585 microtime(&tv);
586 SYNTHFSTIMES(targetPar_sp, &tv, &tv);
587 SYNTHFSTIMES(sourcePar_sp, &tv, &tv);
588
589 return (retval);
590
591bad:;
592 if (retval && doingdirectory)
593 source_sp->s_nodeflags &= ~IN_RENAME;
594
595 return (retval);
596
597abortit:;
598 return (retval);
599}
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621int
622synthfs_mkdir(ap)
623struct vnop_mkdir_args
624
625
626
627
628
629 *ap;
630{
631 int retval;
632 struct vnode *dvp = ap->a_dvp;
633 struct componentname *cnp = ap->a_cnp;
634 int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
635 struct vnode *vp = NULL;
636
637 *ap->a_vpp = NULL;
638
639 retval = synthfs_new_directory(VTOVFS(dvp), dvp, cnp->cn_nameptr, VTOSFS(dvp)->synthfs_nextid++, mode, vfs_context_proc(cnp->cn_context), &vp);
640 if (retval) goto Error_Exit;
641
642 *ap->a_vpp = vp;
643
644 retval = vnode_setattr(vp, ap->a_vap, ap->a_context);
645 if (retval != 0) goto Error_Exit;
646
647 Error_Exit:;
648 if (retval != 0) {
649 if (vp) synthfs_remove_directory(vp);
650 }
651
652 return retval;
653}
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670int
671synthfs_remove(ap)
672struct vnop_remove_args
673
674
675
676
677 *ap;
678{
679 return synthfs_remove_internal(ap->a_dvp, ap->a_vp, ap->a_cnp, ap->a_context);
680}
681
682static int
683synthfs_remove_internal(struct vnode *dvp, struct vnode *vp,
684 __unused struct componentname *cnp,
685 __unused vfs_context_t context)
686{
687 struct synthfsnode *sp = VTOS(vp);
688 struct timeval tv;
689 int retval = 0;
690
691
692 if (sp->s_nodeflags & IN_MODIFIED) {
693 microtime(&tv);
694 synthfs_update(vp, &tv, &tv, 0);
695 };
696
697
698 cache_purge(vp);
699
700
701 switch (sp->s_type) {
702 case SYNTHFS_DIRECTORY:
703 synthfs_remove_directory(vp);
704 break;
705
706
707 case SYNTHFS_SYMLINK:
708 synthfs_remove_symlink(vp);
709 break;
710
711 case SYNTHFS_FILE:
712
713
714 default:
715 synthfs_remove_entry(vp);
716 };
717
718out:
719
720 if (! retval)
721 VTOS(dvp)->s_nodeflags |= IN_CHANGE | IN_UPDATE;
722
723 return (retval);
724}
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740int
741synthfs_rmdir(ap)
742 struct vnop_rmdir_args
743
744
745
746
747 *ap;
748{
749 return synthfs_remove((struct vnop_remove_args *)ap);
750}
751
752
753
754
755
756
757
758
759int
760synthfs_select(__unused
761struct vnop_select_args
762
763
764
765
766
767
768 *ap)
769{
770 DBG_VOP(("synthfs_select called\n"));
771
772 return (1);
773}
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797int
798synthfs_symlink(ap)
799 struct vnop_symlink_args
800
801
802
803
804
805
806 *ap;
807{
808 struct vnode *dvp = ap->a_dvp;
809 struct vnode **vpp = ap->a_vpp;
810 struct componentname *cnp = ap->a_cnp;
811 int retval;
812
813 *vpp = NULL;
814
815 retval = synthfs_new_symlink(VTOVFS(dvp), dvp, cnp->cn_nameptr, VTOSFS(dvp)->synthfs_nextid++, ap->a_target, vfs_context_proc(cnp->cn_context), vpp);
816
817 return (retval);
818}
819
820
821
822
823
824
825
826
827
828
829
830
831
832int
833synthfs_readlink(ap)
834struct vnop_readlink_args
835
836
837
838 *ap;
839{
840 struct vnode *vp = ap->a_vp;
841 struct synthfsnode *sp = VTOS(vp);
842 struct uio *uio = ap->a_uio;
843 int retval;
844 unsigned long count;
845
846 if (ap->a_uio->uio_offset > sp->s_u.s.s_length) {
847 return 0;
848 };
849
850
851 if (uio->uio_offset + uio_resid(uio) <= sp->s_u.s.s_length) {
852 count = uio_resid(uio);
853 } else {
854 count = sp->s_u.s.s_length - uio->uio_offset;
855 };
856 retval = uiomove((void *)((unsigned char *)sp->s_u.s.s_symlinktarget + uio->uio_offset), count, uio);
857 return (retval);
858
859}
860
861
862
863
864
865
866
867
868
869int
870synthfs_readdir(ap)
871struct vnop_readdir_args
872
873
874
875
876
877
878 *ap;
879{
880 struct synthfsnode *sp = VTOS(ap->a_vp);
881 register struct uio *uio = ap->a_uio;
882 off_t diroffset;
883 struct synthfsnode *entry;
884
885 DBG_VOP(("\tuio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio)));
886
887 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
888 return (EINVAL);
889
890
891 if (uio->uio_iovcnt > 1) {
892 DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio->uio_iovcnt));
893 return EINVAL;
894 };
895
896 diroffset = 0;
897
898
899
900
901 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio)));
902 if (uio->uio_offset == diroffset)
903 {
904 DBG_VOP(("\tAdding .\n"));
905 diroffset += synthfs_adddirentry(sp->s_nodeid, DT_DIR, ".", uio);
906 DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio)));
907 }
908 if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) {
909
910 return EINVAL;
911 };
912
913 if (uio->uio_offset == diroffset)
914 {
915 DBG_VOP(("\tAdding ..\n"));
916 if (sp->s_parent != NULL) {
917 diroffset += synthfs_adddirentry(sp->s_parent->s_nodeid, DT_DIR, "..", uio);
918 } else {
919 diroffset += synthfs_adddirentry(sp->s_nodeid, DT_DIR, "..", uio);
920 }
921 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio)));
922 }
923 if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) {
924
925 return EINVAL;
926 };
927
928
929 TAILQ_FOREACH(entry, &sp->s_u.d.d_subnodes, s_sibling) {
930 if (diroffset == uio->uio_offset) {
931
932 diroffset += synthfs_adddirentry(entry->s_nodeid, VTTOIF(STOV(entry)->v_type), entry->s_name, uio);
933 };
934 if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) {
935
936 return EINVAL;
937 };
938 };
939
940 if (ap->a_eofflag)
941 *ap->a_eofflag = (entry == NULL);
942
943 return 0;
944}
945
946
947
948
949
950
951
952
953
954
955int
956synthfs_cached_lookup(ap)
957 struct vnop_lookup_args
958
959
960
961 *ap;
962{
963 struct vnode *dp = ap->a_dvp;
964 struct componentname *cnp = ap->a_cnp;
965 u_long nameiop = cnp->cn_nameiop;
966 u_long flags = cnp->cn_flags;
967 struct vnode **vpp = ap->a_vpp;
968 int result = 0;
969
970 DBG_VOP(("synthfs_cached_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
971#if DEBUG
972 if (flags & ISLASTCN) DBG_VOP(("\tISLASTCN is set\n"));
973#endif
974
975 *vpp = NULL;
976
977
978
979
980
981 result = cache_lookup(dp, vpp, cnp);
982 if (result == 0) {
983
984
985
986 return synthfs_lookup(ap);
987 };
988 if (result == ENOENT) return result;
989
990
991
992 return (0);
993
994Err_Exit:;
995 return result;
996}
997
998
999
1000int
1001synthfs_lookup(ap)
1002 struct vnop_lookup_args
1003
1004
1005
1006
1007 *ap;
1008{
1009 struct vnode *dp = ap->a_dvp;
1010 struct synthfsnode *dsp = VTOS(dp);
1011 struct componentname *cnp = ap->a_cnp;
1012 u_long nameiop = cnp->cn_nameiop;
1013
1014 u_long flags = cnp->cn_flags;
1015 long namelen = cnp->cn_namelen;
1016
1017 vfs_context_t ctx = cnp->cn_context;
1018 kauth_cred_t cred = vfs_context_ucred(ctx);
1019 struct synthfsnode *entry;
1020 struct vnode *target_vp = NULL;
1021 int result = 0;
1022 boolean_t found = FALSE;
1023 boolean_t isDot = FALSE;
1024 boolean_t isDotDot = FALSE;
1025 struct vnode *starting_parent = dp;
1026
1027 DBG_VOP(("synthfs_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
1028#if DEBUG
1029 if (flags & LOCKPARENT) DBG_VOP(("\tLOCKPARENT is set\n"));
1030 if (flags & ISLASTCN) DBG_VOP(("\tISLASTCN is set\n"));
1031#endif
1032
1033 *ap->a_vpp = NULL;
1034
1035
1036 if (cnp->cn_nameptr[0] == '.') {
1037 if (namelen == 1) {
1038
1039
1040
1041 isDot = TRUE;
1042 found = TRUE;
1043
1044 target_vp = dp;
1045 vnode_get(target_vp);
1046
1047 result = 0;
1048
1049 goto Std_Exit;
1050 } else if ((namelen == 2) && (cnp->cn_nameptr[1] == '.')) {
1051
1052
1053
1054 isDotDot = TRUE;
1055 found = TRUE;
1056
1057 if ((dsp->s_parent != NULL) && (dsp->s_parent != VTOS(dp))) {
1058 target_vp = STOV(dsp->s_parent);
1059
1060
1061
1062
1063
1064
1065 result = vnode_get(target_vp);
1066
1067 } else {
1068 target_vp = dp;
1069
1070 result = 0;
1071 }
1072
1073 goto Std_Exit;
1074 }
1075 }
1076
1077
1078
1079 TAILQ_FOREACH(entry, &dsp->s_u.d.d_subnodes, s_sibling) {
1080 if ((bcmp(cnp->cn_nameptr, entry->s_name, (unsigned)namelen) == 0) &&
1081 (*(entry->s_name + namelen) == (char)0)) {
1082 found = TRUE;
1083 target_vp = STOV(entry);
1084 result = vnode_getwithref(target_vp);
1085 if (result != 0) {
1086 goto Err_Exit;
1087 };
1088
1089
1090 goto Std_Exit;
1091 };
1092 };
1093
1094 found = FALSE;
1095
1096Std_Exit:;
1097 if (found) {
1098 if ((nameiop == DELETE) && (flags & ISLASTCN)) {
1099
1100
1101
1102
1103
1104
1105
1106 if ((dsp->s_mode & S_ISVTX) &&
1107 suser(cred, NULL) &&
1108 (kauth_cred_getuid(cred) != dsp->s_uid) &&
1109 (target_vp != NULL) &&
1110 (target_vp->v_type != VLNK) &&
1111 (VTOS(target_vp)->s_uid != kauth_cred_getuid(cred))) {
1112 vnode_put(target_vp);
1113 result = EPERM;
1114 goto Err_Exit;
1115 };
1116 };
1117
1118 if ((nameiop == RENAME) && (flags & WANTPARENT) && (flags * ISLASTCN)) {
1119
1120 if (isDot) {
1121 vnode_put(target_vp);
1122 result = EISDIR;
1123 goto Err_Exit;
1124 };
1125 };
1126 } else {
1127
1128 result = ENOENT;
1129
1130 if ((flags & ISLASTCN) &&
1131 ((nameiop == CREATE) ||
1132 (nameiop == RENAME) ||
1133 ((nameiop == DELETE) && (flags & DOWHITEOUT) && (flags & ISWHITEOUT)))) {
1134
1135 result = EJUSTRETURN;
1136 }
1137 };
1138
1139 *ap->a_vpp = target_vp;
1140
1141Err_Exit:;
1142 DBG_VOP(("synthfs_lookup: result = %d.\n", result));
1143 if (found) {
1144 if (target_vp) {
1145 DBG_VOP(("synthfs_lookup: target_vp = 0x%08X \n", (u_long)target_vp));
1146 } else {
1147 DBG_VOP(("synthfs_lookup: found = true but target_vp = NULL?\n"));
1148 };
1149 } else {
1150 DBG_VOP(("synthf_lookup: target not found.\n"));
1151 };
1152 DBG_VOP(("synthfs_lookup: dp = %08X; starting_parent = 0x%08X .\n", (u_long)dp, (u_long)starting_parent));
1153
1154 return result;
1155}
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168int
1169synthfs_pathconf(ap)
1170struct vnop_pathconf_args
1171
1172
1173
1174
1175 *ap;
1176{
1177 DBG_VOP(("synthfs_pathconf called\n"));
1178
1179 switch (ap->a_name)
1180 {
1181 case _PC_LINK_MAX:
1182 *ap->a_retval = LINK_MAX;
1183 return (0);
1184 case _PC_NAME_MAX:
1185 *ap->a_retval = NAME_MAX;
1186 return (0);
1187 case _PC_PATH_MAX:
1188 *ap->a_retval = PATH_MAX;
1189 return (0);
1190 case _PC_PIPE_BUF:
1191 *ap->a_retval = PIPE_BUF;
1192 return (0);
1193 case _PC_CHOWN_RESTRICTED:
1194 *ap->a_retval = 1;
1195 return (0);
1196 case _PC_NO_TRUNC:
1197 *ap->a_retval = 1;
1198 return (0);
1199 default:
1200 return (EINVAL);
1201 }
1202
1203}
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216int
1217synthfs_update(struct vnode *vp, struct timeval *access, struct timeval *modify, __unused int waitfor)
1218{
1219 struct synthfsnode *sp = VTOS(vp);
1220 struct timeval tv;
1221
1222 DBG_ASSERT(sp != NULL);
1223
1224 if (((sp->s_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) != 0) &&
1225 !(VTOVFS(vp)->mnt_flag & MNT_RDONLY)) {
1226 if (sp->s_nodeflags & IN_ACCESS) sp->s_accesstime = *access;
1227 if (sp->s_nodeflags & IN_UPDATE) sp->s_modificationtime = *modify;
1228 if (sp->s_nodeflags & IN_CHANGE) {
1229
1230 microtime(&tv);
1231 sp->s_changetime = tv;
1232 }
1233 };
1234
1235
1236 sp->s_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
1237
1238 return 0;
1239}
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260int
1261synthfs_inactive(ap)
1262struct vnop_inactive_args
1263
1264
1265 *ap;
1266{
1267 struct vnode *vp = ap->a_vp;
1268 struct synthfsnode *sp = VTOS(vp);
1269 struct timeval tv;
1270
1271#if DEBUG
1272 if (vp->v_usecount != 0)
1273 DBG_VOP(("synthfs_inactive: bad usecount = %d\n", vp->v_usecount ));
1274#endif
1275
1276
1277
1278
1279 if (vp->v_type == VNON)
1280 goto out;
1281
1282
1283 if (sp->s_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
1284 microtime(&tv);
1285 synthfs_update(vp, &tv, &tv, 0);
1286 }
1287
1288out:
1289
1290
1291
1292
1293 if (vp->v_type == VNON) {
1294 vnode_recycle(vp);
1295 };
1296
1297 return 0;
1298}
1299
1300
1301
1302
1303
1304
1305
1306
1307int
1308synthfs_reclaim(ap)
1309 struct vnop_reclaim_args *ap;
1310{
1311 struct vnode *vp = ap->a_vp;
1312 struct synthfsnode *sp = VTOS(vp);
1313 void *name = sp->s_name;
1314
1315 sp->s_name = NULL;
1316 FREE(name, M_TEMP);
1317
1318 vp->v_data = NULL;
1319 FREE((void *)sp, M_SYNTHFS);
1320
1321 return (0);
1322}
1323