]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
5d5c5d0d A |
2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
3 | * | |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved. | |
30 | * | |
31 | * Modification History: | |
32 | * | |
33 | * 02-Feb-2000 Clark Warner Added copyfile to table | |
34 | * 17-Aug-1999 Pat Dirks New today. | |
35 | */ | |
36 | ||
37 | #include <mach/mach_types.h> | |
38 | #include <mach/machine/boolean.h> | |
39 | #include <sys/param.h> | |
40 | #include <sys/systm.h> | |
41 | #include <sys/kernel.h> | |
42 | #include <sys/file.h> | |
43 | #include <sys/stat.h> | |
1c79356b | 44 | #include <sys/proc.h> |
91447636 | 45 | #include <sys/kauth.h> |
1c79356b | 46 | #include <sys/conf.h> |
91447636 A |
47 | #include <sys/mount_internal.h> |
48 | #include <sys/vnode_internal.h> | |
1c79356b A |
49 | #include <sys/malloc.h> |
50 | #include <sys/dirent.h> | |
51 | #include <sys/namei.h> | |
52 | #include <sys/attr.h> | |
91447636 | 53 | #include <sys/uio_internal.h> |
1c79356b A |
54 | |
55 | #include <sys/vm.h> | |
56 | #include <sys/errno.h> | |
57 | #include <vfs/vfs_support.h> | |
58 | ||
59 | #include "synthfs.h" | |
60 | ||
61 | #define RWSUPPORT 0 | |
62 | ||
63 | #if RWSUPPORT | |
64 | #error NOT PORTED FOR UBC | |
1c79356b A |
65 | #include <sys/ubc.h> |
66 | #endif | |
67 | ||
91447636 A |
68 | static int synthfs_remove_internal(struct vnode *dvp, struct vnode *vp, |
69 | struct componentname *cnp, vfs_context_t context); | |
70 | ||
1c79356b A |
71 | |
72 | #define VOPFUNC int (*)(void *) | |
73 | ||
74 | /* Global vfs data structures for synthfs. */ | |
75 | int (**synthfs_vnodeop_p) (void *); | |
76 | struct vnodeopv_entry_desc synthfs_vnodeop_entries[] = { | |
91447636 A |
77 | {&vnop_default_desc, (VOPFUNC)vn_default_error}, |
78 | {&vnop_strategy_desc, (VOPFUNC)err_strategy}, /* strategy - not supported */ | |
79 | {&vnop_bwrite_desc, (VOPFUNC)err_bwrite}, /* bwrite - not supported */ | |
80 | {&vnop_lookup_desc, (VOPFUNC)synthfs_cached_lookup}, /* cached lookup */ | |
81 | {&vnop_create_desc, (VOPFUNC)synthfs_create}, /* create - DEBUGGER */ | |
82 | {&vnop_whiteout_desc, (VOPFUNC)err_whiteout}, /* whiteout - not supported */ | |
83 | {&vnop_mknod_desc, (VOPFUNC)err_mknod}, /* mknod - not supported */ | |
84 | {&vnop_open_desc, (VOPFUNC)synthfs_open}, /* open - DEBUGGER */ | |
85 | {&vnop_close_desc, (VOPFUNC)nop_close}, /* close - NOP */ | |
86 | {&vnop_getattr_desc, (VOPFUNC)synthfs_getattr}, /* getattr */ | |
87 | {&vnop_setattr_desc, (VOPFUNC)synthfs_setattr}, /* setattr */ | |
88 | {&vnop_getattrlist_desc, (VOPFUNC)err_getattrlist}, /* getattrlist - not supported */ | |
89 | {&vnop_setattrlist_desc, (VOPFUNC)err_setattrlist}, /* setattrlist - not supported */ | |
90 | {&vnop_read_desc, (VOPFUNC)err_read}, /* read - not supported */ | |
91 | {&vnop_write_desc, (VOPFUNC)err_write}, /* write - not supported */ | |
92 | {&vnop_ioctl_desc, (VOPFUNC)err_ioctl}, /* ioctl - not supported */ | |
93 | {&vnop_select_desc, (VOPFUNC)synthfs_select}, /* select */ | |
94 | {&vnop_exchange_desc, (VOPFUNC)err_exchange}, /* exchange - not supported */ | |
95 | {&vnop_revoke_desc, (VOPFUNC)nop_revoke}, /* revoke - NOP */ | |
96 | {&vnop_mmap_desc, (VOPFUNC)synthfs_mmap}, /* mmap - DEBUGGER */ | |
97 | {&vnop_fsync_desc, (VOPFUNC)nop_fsync}, /* fsync - NOP */ | |
98 | {&vnop_remove_desc, (VOPFUNC)synthfs_remove}, /* remove */ | |
99 | {&vnop_link_desc, (VOPFUNC)err_link}, /* link - not supported */ | |
100 | {&vnop_rename_desc, (VOPFUNC)synthfs_rename}, /* rename */ | |
101 | {&vnop_mkdir_desc, (VOPFUNC)synthfs_mkdir}, /* mkdir */ | |
102 | {&vnop_rmdir_desc, (VOPFUNC)synthfs_rmdir}, /* rmdir */ | |
103 | {&vnop_symlink_desc, (VOPFUNC)synthfs_symlink}, /* symlink */ | |
104 | {&vnop_readdir_desc, (VOPFUNC)synthfs_readdir}, /* readdir */ | |
105 | {&vnop_readdirattr_desc, (VOPFUNC)err_readdirattr}, /* readdirattr - not supported */ | |
106 | {&vnop_readlink_desc, (VOPFUNC)synthfs_readlink}, /* readlink */ | |
107 | {&vnop_inactive_desc, (VOPFUNC)synthfs_inactive}, /* inactive */ | |
108 | {&vnop_reclaim_desc, (VOPFUNC)synthfs_reclaim}, /* reclaim */ | |
109 | {&vnop_pathconf_desc, (VOPFUNC)synthfs_pathconf}, /* pathconf */ | |
110 | {&vnop_advlock_desc, (VOPFUNC)err_advlock}, /* advlock - not supported */ | |
111 | {&vnop_allocate_desc, (VOPFUNC)err_allocate}, /* allocate - not supported */ | |
112 | {&vnop_pagein_desc, (VOPFUNC)err_pagein}, /* pagein - not supported */ | |
113 | {&vnop_pageout_desc, (VOPFUNC)err_pageout}, /* pageout - not supported */ | |
91447636 A |
114 | {&vnop_searchfs_desc, (VOPFUNC)err_searchfs}, /* searchfs - not supported */ |
115 | {&vnop_copyfile_desc, (VOPFUNC)err_copyfile}, /* copyfile - not supported */ | |
116 | { &vnop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff not supported */ | |
117 | { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk not supported */ | |
118 | { &vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap not supported */ | |
1c79356b A |
119 | {(struct vnodeop_desc *) NULL, (int (*) ()) NULL} |
120 | }; | |
121 | ||
122 | /* | |
123 | * Oh what a tangled web we weave. This structure will be used by | |
124 | * bsd/vfs/vfs_conf.c to actually do the initialization of synthfs_vnodeop_p | |
125 | */ | |
126 | struct vnodeopv_desc synthfs_vnodeop_opv_desc = | |
127 | {&synthfs_vnodeop_p, synthfs_vnodeop_entries}; | |
128 | ||
129 | ||
130 | ||
131 | /* | |
132 | * Create a regular file | |
133 | #% create dvp L U U | |
134 | #% create vpp - L - | |
135 | # | |
91447636 | 136 | vnop_create { |
1c79356b A |
137 | IN WILLRELE struct vnode *dvp; |
138 | OUT struct vnode **vpp; | |
139 | IN struct componentname *cnp; | |
91447636 | 140 | IN struct vnode_attr *vap; |
1c79356b A |
141 | |
142 | We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is | |
143 | a previous error. | |
144 | ||
145 | */ | |
146 | ||
147 | int | |
148 | synthfs_create(ap) | |
91447636 | 149 | struct vnop_create_args /* { |
1c79356b A |
150 | struct vnode *a_dvp; |
151 | struct vnode **a_vpp; | |
152 | struct componentname *a_cnp; | |
91447636 A |
153 | struct vnode_attr *a_vap; |
154 | vfs_context_t a_context; | |
1c79356b A |
155 | } */ *ap; |
156 | { | |
157 | #if DEBUG | |
158 | struct vnode *dvp = ap->a_dvp; | |
159 | char debugmsg[255]; | |
160 | ||
161 | sprintf(debugmsg, "synthfs_create: attempt to create '%s' in '%s' ?!", ap->a_cnp->cn_nameptr, VTOS(dvp)->s_name); | |
162 | Debugger(debugmsg); | |
163 | #endif | |
164 | ||
55e303ae | 165 | return err_create(ap); |
1c79356b A |
166 | } |
167 | ||
168 | ||
169 | ||
170 | /* | |
171 | * Open called. | |
172 | #% open vp L L L | |
173 | # | |
91447636 | 174 | vnop_open { |
1c79356b A |
175 | IN struct vnode *vp; |
176 | IN int mode; | |
91447636 | 177 | IN vfs_context_t a_context; |
1c79356b A |
178 | */ |
179 | ||
180 | int | |
181 | synthfs_open(ap) | |
91447636 | 182 | struct vnop_open_args /* { |
1c79356b A |
183 | struct vnode *a_vp; |
184 | int a_mode; | |
91447636 | 185 | vfs_context_t a_context; |
1c79356b A |
186 | } */ *ap; |
187 | { | |
188 | struct vnode *vp = ap->a_vp; | |
189 | ||
190 | if (vp->v_type == VDIR) { | |
191 | return 0; | |
192 | } else { | |
193 | #if DEBUG | |
194 | struct synthfsnode *sp = VTOS(vp); | |
195 | char debugmsg[255]; | |
196 | ||
197 | sprintf(debugmsg, "synthfs_open: attempt to open '/%s' ?!", sp->s_name); | |
198 | Debugger(debugmsg); | |
199 | #endif | |
200 | }; | |
201 | ||
202 | return 0; | |
203 | } | |
204 | ||
205 | ||
206 | ||
207 | /* | |
208 | * Mmap a file | |
209 | * | |
210 | * NB Currently unsupported. | |
211 | # XXX - not used | |
212 | # | |
91447636 | 213 | vnop_mmap { |
1c79356b A |
214 | IN struct vnode *vp; |
215 | IN int fflags; | |
91447636 | 216 | IN kauth_cred_t cred; |
1c79356b A |
217 | IN struct proc *p; |
218 | ||
219 | */ | |
220 | ||
221 | /* ARGSUSED */ | |
222 | ||
223 | int | |
91447636 | 224 | synthfs_mmap(__unused struct vnop_mmap_args *ap) |
1c79356b | 225 | { |
1c79356b A |
226 | return EINVAL; |
227 | } | |
228 | ||
229 | ||
230 | ||
1c79356b A |
231 | /* |
232 | #% getattr vp = = = | |
233 | # | |
91447636 | 234 | vnop_getattr { |
1c79356b | 235 | IN struct vnode *vp; |
91447636 A |
236 | IN struct vnode_attr *vap; |
237 | IN vfs_context_t context; | |
1c79356b A |
238 | |
239 | */ | |
240 | int | |
241 | synthfs_getattr(ap) | |
91447636 | 242 | struct vnop_getattr_args /* { |
1c79356b | 243 | struct vnode *a_vp; |
91447636 A |
244 | struct vnode_attr *a_vap; |
245 | vfs_context_t a_context; | |
1c79356b A |
246 | } */ *ap; |
247 | { | |
91447636 A |
248 | struct vnode *vp = ap->a_vp; |
249 | struct vnode_attr *vap = ap->a_vap; | |
250 | struct synthfsnode *sp = VTOS(vp); | |
251 | ||
252 | VATTR_RETURN(vap, va_type, vp->v_type); | |
253 | VATTR_RETURN(vap, va_mode, sp->s_mode); | |
254 | VATTR_RETURN(vap, va_nlink, sp->s_linkcount); | |
255 | VATTR_RETURN(vap, va_uid, sp->s_uid); | |
256 | VATTR_RETURN(vap, va_gid, sp->s_gid); | |
257 | VATTR_RETURN(vap, va_fsid, VTOVFS(vp)->mnt_vfsstat.f_fsid.val[0]); | |
258 | VATTR_RETURN(vap, va_fileid, sp->s_nodeid); | |
1c79356b | 259 | switch (vp->v_type) { |
91447636 A |
260 | case VDIR: |
261 | VATTR_RETURN(vap, va_data_size, (sp->s_u.d.d_entrycount + 2) * sizeof(struct dirent)); | |
1c79356b A |
262 | break; |
263 | ||
91447636 A |
264 | case VREG: |
265 | VATTR_RETURN(vap, va_data_size, sp->s_u.f.f_size); | |
1c79356b A |
266 | break; |
267 | ||
91447636 A |
268 | case VLNK: |
269 | VATTR_RETURN(vap, va_data_size, sp->s_u.s.s_length); | |
1c79356b A |
270 | break; |
271 | ||
91447636 A |
272 | default: |
273 | VATTR_RETURN(vap, va_data_size, 0); | |
1c79356b | 274 | }; |
91447636 A |
275 | VATTR_RETURN(vap, va_iosize, 512); |
276 | vap->va_access_time.tv_sec = sp->s_accesstime.tv_sec; | |
277 | vap->va_access_time.tv_nsec = sp->s_accesstime.tv_usec * 1000; | |
278 | VATTR_SET_SUPPORTED(vap, va_access_time); | |
279 | vap->va_modify_time.tv_sec = sp->s_modificationtime.tv_sec; | |
280 | vap->va_modify_time.tv_nsec = sp->s_modificationtime.tv_usec * 1000; | |
281 | VATTR_SET_SUPPORTED(vap, va_modify_time); | |
282 | vap->va_change_time.tv_sec = sp->s_changetime.tv_sec; | |
283 | vap->va_change_time.tv_nsec = sp->s_changetime.tv_usec * 1000; | |
284 | VATTR_SET_SUPPORTED(vap, va_change_time); | |
285 | VATTR_RETURN(vap, va_gen, sp->s_generation); | |
286 | VATTR_RETURN(vap, va_flags, sp->s_flags); | |
287 | VATTR_RETURN(vap, va_rdev, sp->s_rdev); | |
288 | VATTR_RETURN(vap, va_filerev, 0); | |
289 | VATTR_RETURN(vap, va_acl, NULL); | |
290 | ||
291 | return (0); | |
1c79356b A |
292 | } |
293 | ||
294 | ||
295 | ||
296 | /* | |
297 | * Change the mode on a file or directory. | |
298 | * vnode vp must be locked on entry. | |
299 | */ | |
91447636 | 300 | int synthfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct proc *p) |
1c79356b A |
301 | { |
302 | struct synthfsnode *sp = VTOS(vp); | |
303 | int result; | |
304 | ||
1c79356b A |
305 | sp->s_mode &= ~ALLPERMS; |
306 | sp->s_mode |= (mode & ALLPERMS); | |
307 | sp->s_nodeflags |= IN_CHANGE; | |
308 | #if RWSUPPORT | |
309 | if ((vp->v_flag & VTEXT) && (sp->s_mode & S_ISTXT) == 0) (void) vnode_uncache(vp); | |
310 | #endif | |
311 | ||
312 | return 0; | |
313 | } | |
314 | ||
315 | ||
316 | ||
317 | /* | |
318 | * Change the flags on a file or directory. | |
319 | * vnode vp must be locked on entry. | |
320 | */ | |
91447636 | 321 | int synthfs_chflags(struct vnode *vp, u_long flags, kauth_cred_t cred, struct proc *p) |
1c79356b A |
322 | { |
323 | struct synthfsnode *sp = VTOS(vp); | |
1c79356b | 324 | |
91447636 | 325 | sp->s_flags = flags; |
1c79356b A |
326 | sp->s_nodeflags |= IN_CHANGE; |
327 | ||
328 | return 0; | |
329 | } | |
330 | ||
331 | ||
332 | ||
333 | /* | |
334 | * Perform chown operation on vnode vp; | |
335 | * vnode vp must be locked on entry. | |
336 | */ | |
91447636 | 337 | int synthfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, struct proc *p) |
1c79356b A |
338 | { |
339 | struct synthfsnode *sp = VTOS(vp); | |
340 | uid_t ouid; | |
341 | gid_t ogid; | |
342 | int result = 0; | |
91447636 | 343 | int is_member; |
1c79356b A |
344 | |
345 | if (uid == (uid_t)VNOVAL) uid = sp->s_uid; | |
346 | if (gid == (gid_t)VNOVAL) gid = sp->s_gid; | |
347 | ||
1c79356b A |
348 | ogid = sp->s_gid; |
349 | ouid = sp->s_uid; | |
350 | ||
351 | sp->s_gid = gid; | |
352 | sp->s_uid = uid; | |
353 | ||
354 | if (ouid != uid || ogid != gid) sp->s_nodeflags |= IN_CHANGE; | |
91447636 A |
355 | if (ouid != uid && suser(cred, NULL)) sp->s_mode &= ~S_ISUID; |
356 | if (ogid != gid && suser(cred, NULL)) sp->s_mode &= ~S_ISGID; | |
1c79356b A |
357 | |
358 | return 0; | |
359 | } | |
360 | ||
361 | ||
362 | ||
363 | /* | |
364 | * Set attribute vnode op. called from several syscalls | |
365 | #% setattr vp L L L | |
366 | # | |
91447636 | 367 | vnop_setattr { |
1c79356b | 368 | IN struct vnode *vp; |
91447636 A |
369 | IN struct vnode_attr *vap; |
370 | IN vfs_context_t context; | |
1c79356b A |
371 | */ |
372 | ||
373 | int | |
374 | synthfs_setattr(ap) | |
91447636 | 375 | struct vnop_setattr_args /* { |
1c79356b | 376 | struct vnode *a_vp; |
91447636 A |
377 | struct vnode_attr *a_vap; |
378 | vfs_context_t a_context; | |
1c79356b A |
379 | } */ *ap; |
380 | { | |
91447636 A |
381 | struct vnode *vp = ap->a_vp; |
382 | struct synthfsnode *sp = VTOS(vp); | |
383 | struct vnode_attr *vap = ap->a_vap; | |
384 | kauth_cred_t cred = vfs_context_ucred(ap->a_context); | |
385 | struct proc *p = vfs_context_proc(ap->a_context); | |
386 | struct timeval atimeval, mtimeval; | |
387 | uid_t nuid; | |
388 | gid_t ngid; | |
389 | int result; | |
390 | ||
391 | result = 0; | |
392 | ||
393 | if (VATTR_IS_ACTIVE(vap, va_flags)) { | |
394 | if ((result = synthfs_chflags(vp, vap->va_flags, cred, p))) { | |
395 | goto Err_Exit; | |
396 | } | |
397 | } | |
398 | VATTR_SET_SUPPORTED(vap, va_flags); | |
399 | ||
400 | nuid = (uid_t)ngid = (gid_t)VNOVAL; | |
401 | if (VATTR_IS_ACTIVE(vap, va_uid)) | |
402 | nuid = vap->va_uid; | |
403 | if (VATTR_IS_ACTIVE(vap, va_gid)) | |
404 | ngid = vap->va_gid; | |
405 | if (nuid != (uid_t)VNOVAL || ngid != (gid_t)VNOVAL) { | |
406 | if ((result = synthfs_chown(vp, nuid, ngid, cred, p))) { | |
407 | goto Err_Exit; | |
408 | } | |
409 | } | |
410 | VATTR_SET_SUPPORTED(vap, va_uid); | |
411 | VATTR_SET_SUPPORTED(vap, va_gid); | |
1c79356b | 412 | |
91447636 | 413 | if (VATTR_IS_ACTIVE(vap, va_data_size)) { |
1c79356b | 414 | #if RWSUPPORT |
91447636 A |
415 | if ((result = vnode_setsize(vp, vap->va_data_size, 0, ap->a_context))) { |
416 | goto Err_Exit; | |
417 | }; | |
418 | VATTR_SET_SUPPORTED(vap, va_data_size); | |
1c79356b | 419 | #else |
91447636 A |
420 | result = EINVAL; |
421 | goto Err_Exit; | |
1c79356b | 422 | #endif |
91447636 | 423 | } |
1c79356b | 424 | |
91447636 A |
425 | sp = VTOS(vp); |
426 | if (VATTR_IS_ACTIVE(vap, va_access_time) || VATTR_IS_ACTIVE(vap, va_modify_time)) { | |
427 | if (VATTR_IS_ACTIVE(vap, va_access_time)) { | |
428 | sp->s_nodeflags |= IN_ACCESS; | |
429 | atimeval.tv_sec = vap->va_access_time.tv_sec; | |
430 | atimeval.tv_usec = vap->va_access_time.tv_nsec / 1000; | |
431 | } | |
432 | if (VATTR_IS_ACTIVE(vap, va_modify_time)) { | |
433 | sp->s_nodeflags |= IN_CHANGE | IN_UPDATE; | |
434 | mtimeval.tv_sec = vap->va_modify_time.tv_sec; | |
435 | mtimeval.tv_usec = vap->va_modify_time.tv_nsec / 1000; | |
436 | } | |
437 | if ((result = synthfs_update(vp, &atimeval, &mtimeval, 1))) { | |
438 | goto Err_Exit; | |
439 | } | |
440 | } | |
441 | VATTR_SET_SUPPORTED(vap, va_access_time); | |
442 | VATTR_SET_SUPPORTED(vap, va_modify_time); | |
1c79356b | 443 | |
91447636 A |
444 | if (VATTR_IS_ACTIVE(vap, va_mode)) |
445 | result = synthfs_chmod(vp, (int)vap->va_mode, cred, p); | |
446 | VATTR_SET_SUPPORTED(vap, va_mode); | |
1c79356b | 447 | |
91447636 | 448 | Err_Exit: |
1c79356b | 449 | |
91447636 | 450 | DBG_VOP(("synthfs_setattr: returning %d...\n", result)); |
1c79356b | 451 | |
91447636 | 452 | return (result); |
1c79356b A |
453 | } |
454 | ||
455 | ||
456 | ||
457 | /* | |
458 | ||
459 | #% rename sourcePar_vp U U U | |
460 | #% rename source_vp U U U | |
461 | #% rename targetPar_vp L U U | |
462 | #% rename target_vp X U U | |
463 | # | |
91447636 | 464 | vnop_rename { |
1c79356b A |
465 | IN WILLRELE struct vnode *sourcePar_vp; |
466 | IN WILLRELE struct vnode *source_vp; | |
467 | IN struct componentname *source_cnp; | |
468 | IN WILLRELE struct vnode *targetPar_vp; | |
469 | IN WILLRELE struct vnode *target_vp; | |
470 | IN struct componentname *target_cnp; | |
471 | ||
472 | ||
473 | */ | |
474 | ||
475 | /* | |
476 | * On entry: | |
477 | * source's parent directory is unlocked | |
478 | * source file or directory is unlocked | |
479 | * destination's parent directory is locked | |
480 | * destination file or directory is locked if it exists | |
481 | * | |
482 | * On exit: | |
483 | * all denodes should be released | |
484 | * | |
485 | */ | |
486 | ||
487 | int | |
488 | synthfs_rename(ap) | |
91447636 | 489 | struct vnop_rename_args /* { |
1c79356b A |
490 | struct vnode *a_fdvp; |
491 | struct vnode *a_fvp; | |
492 | struct componentname *a_fcnp; | |
493 | struct vnode *a_tdvp; | |
494 | struct vnode *a_tvp; | |
495 | struct componentname *a_tcnp; | |
91447636 | 496 | vfs_context_t a_context; |
1c79356b A |
497 | } */ *ap; |
498 | { | |
499 | struct vnode *target_vp = ap->a_tvp; | |
500 | struct vnode *targetPar_vp = ap->a_tdvp; | |
501 | struct vnode *source_vp = ap->a_fvp; | |
502 | struct vnode *sourcePar_vp = ap->a_fdvp; | |
503 | struct componentname *target_cnp = ap->a_tcnp; | |
504 | struct componentname *source_cnp = ap->a_fcnp; | |
1c79356b A |
505 | struct synthfsnode *target_sp, *targetPar_sp, *source_sp, *sourcePar_sp; |
506 | u_short doingdirectory = 0, oldparent = 0, newparent = 0; | |
507 | int retval = 0; | |
508 | struct timeval tv; | |
509 | ||
510 | #if SYNTHFS_DIAGNOSTIC | |
511 | if ((target_cnp->cn_flags & HASBUF) == 0 || | |
512 | (source_cnp->cn_flags & HASBUF) == 0) | |
513 | panic("synthfs_rename: no name"); | |
514 | #endif | |
515 | ||
516 | DBG_ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR)); | |
517 | target_sp = targetPar_sp = source_sp = sourcePar_sp = NULL; | |
518 | ||
1c79356b A |
519 | |
520 | sourcePar_sp = VTOS(sourcePar_vp); | |
521 | source_sp = VTOS(source_vp); | |
522 | oldparent = sourcePar_sp->s_nodeid; | |
1c79356b A |
523 | |
524 | /* | |
525 | * Be sure we are not renaming ".", "..", or an alias of ".". This | |
526 | * leads to a crippled directory tree. It's pretty tough to do a | |
527 | * "ls" or "pwd" with the "." directory entry missing, and "cd .." | |
528 | * doesn't work if the ".." entry is missing. | |
529 | */ | |
530 | if (source_sp->s_type == SYNTHFS_DIRECTORY) { | |
531 | if ((source_cnp->cn_namelen == 1 && source_cnp->cn_nameptr[0] == '.') | |
532 | || sourcePar_sp == source_sp | |
533 | || (source_cnp->cn_flags & ISDOTDOT) | |
534 | || (source_sp->s_nodeflags & IN_RENAME)) { | |
1c79356b A |
535 | retval = EINVAL; |
536 | goto abortit; | |
537 | } | |
538 | source_sp->s_nodeflags |= IN_RENAME; | |
539 | doingdirectory = TRUE; | |
540 | } | |
541 | ||
542 | /* Transit between abort and bad */ | |
543 | ||
544 | targetPar_sp = VTOS(targetPar_vp); | |
545 | target_sp = target_vp ? VTOS(target_vp) : NULL; | |
546 | newparent = targetPar_sp->s_nodeid; | |
547 | ||
1c79356b A |
548 | |
549 | /* | |
550 | * If the destination exists, then be sure its type (file or dir) | |
551 | * matches that of the source. And, if it is a directory make sure | |
552 | * it is empty. Then delete the destination. | |
553 | */ | |
554 | if (target_vp) { | |
1c79356b | 555 | |
1c79356b | 556 | #if RWSUPPORT |
91447636 A |
557 | if (target_vp->v_type == VREG) { |
558 | (void) vnode_uncache(target_vp); | |
559 | }; | |
1c79356b | 560 | #endif |
91447636 | 561 | cache_purge(target_vp); |
1c79356b | 562 | |
91447636 | 563 | retval = synthfs_remove_internal(targetPar_vp, target_vp, target_cnp, ap->a_context); |
1c79356b A |
564 | |
565 | target_vp = NULL; | |
566 | target_sp = NULL; | |
567 | ||
568 | if (retval) goto bad; | |
569 | }; | |
570 | ||
571 | ||
1c79356b A |
572 | /* remove the existing entry from the namei cache: */ |
573 | if (source_vp->v_type == VREG) cache_purge(source_vp); | |
574 | ||
575 | retval = synthfs_move_rename_entry( source_vp, targetPar_vp, target_cnp->cn_nameptr); | |
576 | ||
1c79356b A |
577 | if (retval) goto bad; |
578 | ||
579 | source_sp->s_nodeflags &= ~IN_RENAME; | |
580 | ||
581 | /* | |
582 | * Timestamp both parent directories. | |
583 | * Note that if this is a rename within the same directory, | |
584 | * (where targetPar_hp == sourcePar_hp) | |
585 | * the code below is still safe and correct. | |
586 | */ | |
587 | targetPar_sp->s_nodeflags |= IN_UPDATE; | |
588 | sourcePar_sp->s_nodeflags |= IN_UPDATE; | |
91447636 A |
589 | |
590 | microtime(&tv); | |
1c79356b A |
591 | SYNTHFSTIMES(targetPar_sp, &tv, &tv); |
592 | SYNTHFSTIMES(sourcePar_sp, &tv, &tv); | |
593 | ||
1c79356b A |
594 | return (retval); |
595 | ||
596 | bad:; | |
597 | if (retval && doingdirectory) | |
598 | source_sp->s_nodeflags &= ~IN_RENAME; | |
599 | ||
91447636 | 600 | return (retval); |
1c79356b A |
601 | |
602 | abortit:; | |
91447636 | 603 | return (retval); |
1c79356b A |
604 | } |
605 | ||
606 | ||
607 | ||
608 | /* | |
609 | * Mkdir system call | |
610 | ||
611 | #% mkdir dvp L U U | |
612 | #% mkdir vpp - L - | |
613 | # | |
91447636 | 614 | vnop_mkdir { |
1c79356b A |
615 | IN WILLRELE struct vnode *dvp; |
616 | OUT struct vnode **vpp; | |
617 | IN struct componentname *cnp; | |
91447636 A |
618 | IN struct vnode_attr *vap; |
619 | IN vfs_context_t context; | |
1c79356b A |
620 | |
621 | We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is | |
622 | a previous error. | |
623 | ||
624 | */ | |
625 | ||
626 | int | |
627 | synthfs_mkdir(ap) | |
91447636 | 628 | struct vnop_mkdir_args /* { |
1c79356b A |
629 | struct vnode *a_dvp; |
630 | struct vnode **a_vpp; | |
631 | struct componentname *a_cnp; | |
91447636 A |
632 | struct vnode_attr *a_vap; |
633 | vfs_context_t a_context; | |
1c79356b A |
634 | } */ *ap; |
635 | { | |
636 | int retval; | |
637 | struct vnode *dvp = ap->a_dvp; | |
638 | struct componentname *cnp = ap->a_cnp; | |
639 | int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); | |
640 | struct vnode *vp = NULL; | |
641 | ||
91447636 | 642 | *ap->a_vpp = NULL; |
1c79356b | 643 | |
91447636 A |
644 | retval = synthfs_new_directory(VTOVFS(dvp), dvp, cnp->cn_nameptr, VTOSFS(dvp)->synthfs_nextid++, mode, vfs_context_proc(cnp->cn_context), &vp); |
645 | if (retval) goto Error_Exit; | |
1c79356b | 646 | |
91447636 | 647 | *ap->a_vpp = vp; |
1c79356b | 648 | |
91447636 A |
649 | retval = vnode_setattr(vp, ap->a_vap, ap->a_context); |
650 | if (retval != 0) goto Error_Exit; | |
1c79356b | 651 | |
91447636 A |
652 | Error_Exit:; |
653 | if (retval != 0) { | |
654 | if (vp) synthfs_remove_directory(vp); | |
655 | } | |
1c79356b A |
656 | |
657 | return retval; | |
658 | } | |
659 | ||
660 | ||
661 | ||
662 | /* | |
663 | ||
664 | #% remove dvp L U U | |
665 | #% remove vp L U U | |
666 | # | |
91447636 | 667 | vnop_remove { |
1c79356b A |
668 | IN WILLRELE struct vnode *dvp; |
669 | IN WILLRELE struct vnode *vp; | |
670 | IN struct componentname *cnp; | |
91447636 A |
671 | IN vfs_context_t context; |
672 | ||
1c79356b A |
673 | */ |
674 | ||
675 | int | |
676 | synthfs_remove(ap) | |
91447636 | 677 | struct vnop_remove_args /* { |
1c79356b A |
678 | struct vnode *a_dvp; |
679 | struct vnode *a_vp; | |
680 | struct componentname *a_cnp; | |
91447636 | 681 | vfs_context_t a_context; |
1c79356b A |
682 | } */ *ap; |
683 | { | |
91447636 A |
684 | return synthfs_remove_internal(ap->a_dvp, ap->a_vp, ap->a_cnp, ap->a_context); |
685 | } | |
686 | ||
687 | static int | |
688 | synthfs_remove_internal(struct vnode *dvp, struct vnode *vp, | |
689 | __unused struct componentname *cnp, | |
690 | __unused vfs_context_t context) | |
691 | { | |
1c79356b | 692 | struct synthfsnode *sp = VTOS(vp); |
91447636 | 693 | struct timeval tv; |
1c79356b A |
694 | int retval = 0; |
695 | ||
1c79356b A |
696 | /* This is sort of silly right now but someday it may make sense... */ |
697 | if (sp->s_nodeflags & IN_MODIFIED) { | |
91447636 A |
698 | microtime(&tv); |
699 | synthfs_update(vp, &tv, &tv, 0); | |
1c79356b A |
700 | }; |
701 | ||
702 | /* remove the entry from the namei cache: */ | |
703 | cache_purge(vp); | |
704 | ||
705 | /* remove entry from tree and reclaim any resources consumed: */ | |
706 | switch (sp->s_type) { | |
707 | case SYNTHFS_DIRECTORY: | |
708 | synthfs_remove_directory(vp); | |
709 | break; | |
710 | ||
711 | ||
712 | case SYNTHFS_SYMLINK: | |
713 | synthfs_remove_symlink(vp); | |
714 | break; | |
715 | ||
716 | case SYNTHFS_FILE: | |
717 | /* Fall through to default case */ | |
718 | ||
719 | default: | |
720 | synthfs_remove_entry(vp); | |
721 | }; | |
722 | ||
723 | out: | |
724 | ||
725 | if (! retval) | |
726 | VTOS(dvp)->s_nodeflags |= IN_CHANGE | IN_UPDATE; | |
727 | ||
1c79356b A |
728 | return (retval); |
729 | } | |
730 | ||
731 | ||
732 | ||
733 | /* | |
734 | #% rmdir dvp L U U | |
735 | #% rmdir vp L U U | |
736 | # | |
91447636 | 737 | vnop_rmdir { |
1c79356b A |
738 | IN WILLRELE struct vnode *dvp; |
739 | IN WILLRELE struct vnode *vp; | |
740 | IN struct componentname *cnp; | |
91447636 | 741 | IN vfs_context_t context; |
1c79356b A |
742 | |
743 | */ | |
744 | ||
745 | int | |
746 | synthfs_rmdir(ap) | |
91447636 | 747 | struct vnop_rmdir_args /* { |
1c79356b A |
748 | struct vnode *a_dvp; |
749 | struct vnode *a_vp; | |
750 | struct componentname *a_cnp; | |
91447636 | 751 | vfs_context_t a_context; |
1c79356b A |
752 | } */ *ap; |
753 | { | |
91447636 | 754 | return synthfs_remove((struct vnop_remove_args *)ap); |
1c79356b A |
755 | } |
756 | ||
757 | ||
758 | ||
759 | /* | |
760 | * synthfs_select - just say OK. Only possible op is readdir | |
761 | * | |
762 | * Locking policy: ignore | |
763 | */ | |
764 | int | |
91447636 A |
765 | synthfs_select(__unused |
766 | struct vnop_select_args /* { | |
1c79356b A |
767 | struct vnode *a_vp; |
768 | int a_which; | |
769 | int a_fflags; | |
91447636 | 770 | kauth_cred_t a_cred; |
0b4e3aa0 | 771 | void *a_wql; |
1c79356b | 772 | struct proc *a_p; |
91447636 | 773 | } */ *ap) |
1c79356b A |
774 | { |
775 | DBG_VOP(("synthfs_select called\n")); | |
776 | ||
777 | return (1); | |
778 | } | |
779 | ||
780 | /* | |
781 | # | |
782 | #% symlink dvp L U U | |
783 | #% symlink vpp - U - | |
784 | # | |
91447636 A |
785 | # XXX - note that the return vnode has already been vnode_put'ed |
786 | # by the filesystem layer. To use it you must use vnode_get, | |
1c79356b A |
787 | # possibly with a further namei. |
788 | # | |
91447636 | 789 | vnop_symlink { |
1c79356b A |
790 | IN WILLRELE struct vnode *dvp; |
791 | OUT WILLRELE struct vnode **vpp; | |
792 | IN struct componentname *cnp; | |
91447636 | 793 | IN struct vnode_attr *vap; |
1c79356b A |
794 | IN char *target; |
795 | ||
796 | We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is | |
797 | a previous error. | |
798 | ||
799 | ||
800 | */ | |
801 | ||
802 | int | |
803 | synthfs_symlink(ap) | |
91447636 | 804 | struct vnop_symlink_args /* { |
1c79356b A |
805 | struct vnode *a_dvp; |
806 | struct vnode **a_vpp; | |
807 | struct componentname *a_cnp; | |
91447636 | 808 | struct vnode_attr *a_vap; |
1c79356b | 809 | char *a_target; |
91447636 | 810 | vfs_context_t a_context; |
1c79356b A |
811 | } */ *ap; |
812 | { | |
813 | struct vnode *dvp = ap->a_dvp; | |
814 | struct vnode **vpp = ap->a_vpp; | |
815 | struct componentname *cnp = ap->a_cnp; | |
816 | int retval; | |
817 | ||
818 | *vpp = NULL; | |
819 | ||
91447636 | 820 | retval = synthfs_new_symlink(VTOVFS(dvp), dvp, cnp->cn_nameptr, VTOSFS(dvp)->synthfs_nextid++, ap->a_target, vfs_context_proc(cnp->cn_context), vpp); |
1c79356b A |
821 | |
822 | return (retval); | |
823 | } | |
824 | ||
825 | ||
826 | ||
827 | /* | |
828 | # | |
829 | #% readlink vp L L L | |
830 | # | |
91447636 | 831 | vnop_readlink { |
1c79356b A |
832 | IN struct vnode *vp; |
833 | INOUT struct uio *uio; | |
91447636 | 834 | IN kauth_cred_t cred; |
1c79356b A |
835 | */ |
836 | ||
837 | int | |
838 | synthfs_readlink(ap) | |
91447636 | 839 | struct vnop_readlink_args /* { |
1c79356b A |
840 | struct vnode *a_vp; |
841 | struct uio *a_uio; | |
91447636 | 842 | vfs_context_t a_context; |
1c79356b A |
843 | } */ *ap; |
844 | { | |
845 | struct vnode *vp = ap->a_vp; | |
846 | struct synthfsnode *sp = VTOS(vp); | |
847 | struct uio *uio = ap->a_uio; | |
848 | int retval; | |
849 | unsigned long count; | |
850 | ||
851 | if (ap->a_uio->uio_offset > sp->s_u.s.s_length) { | |
852 | return 0; | |
853 | }; | |
854 | ||
91447636 A |
855 | // LP64todo - fix this! |
856 | if (uio->uio_offset + uio_resid(uio) <= sp->s_u.s.s_length) { | |
857 | count = uio_resid(uio); | |
1c79356b A |
858 | } else { |
859 | count = sp->s_u.s.s_length - uio->uio_offset; | |
860 | }; | |
861 | retval = uiomove((void *)((unsigned char *)sp->s_u.s.s_symlinktarget + uio->uio_offset), count, uio); | |
862 | return (retval); | |
863 | ||
864 | } | |
865 | ||
866 | ||
867 | ||
868 | ||
869 | ||
870 | ||
871 | /* | |
91447636 A |
872 | * Read directory entries. |
873 | */ | |
1c79356b A |
874 | int |
875 | synthfs_readdir(ap) | |
91447636 A |
876 | struct vnop_readdir_args /* { |
877 | struct vnode *a_vp; | |
878 | struct uio *a_uio; | |
879 | int a_flags; | |
880 | int *a_eofflag; | |
881 | int *a_numdirent; | |
882 | vfs_context_t a_context; | |
1c79356b A |
883 | } */ *ap; |
884 | { | |
885 | struct synthfsnode *sp = VTOS(ap->a_vp); | |
886 | register struct uio *uio = ap->a_uio; | |
887 | off_t diroffset; /* Offset into simulated directory file */ | |
888 | struct synthfsnode *entry; | |
889 | ||
91447636 A |
890 | DBG_VOP(("\tuio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio))); |
891 | ||
892 | if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) | |
893 | return (EINVAL); | |
1c79356b A |
894 | |
895 | /* We assume it's all one big buffer... */ | |
896 | if (uio->uio_iovcnt > 1) { | |
897 | DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio->uio_iovcnt)); | |
898 | return EINVAL; | |
899 | }; | |
1c79356b A |
900 | |
901 | diroffset = 0; | |
902 | ||
903 | /* | |
904 | * We must synthesize . and .. | |
905 | */ | |
91447636 | 906 | DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio))); |
1c79356b A |
907 | if (uio->uio_offset == diroffset) |
908 | { | |
909 | DBG_VOP(("\tAdding .\n")); | |
910 | diroffset += synthfs_adddirentry(sp->s_nodeid, DT_DIR, ".", uio); | |
91447636 | 911 | DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio))); |
1c79356b | 912 | } |
91447636 | 913 | if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) { |
1c79356b A |
914 | /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */ |
915 | return EINVAL; | |
916 | }; | |
917 | ||
918 | if (uio->uio_offset == diroffset) | |
919 | { | |
920 | DBG_VOP(("\tAdding ..\n")); | |
921 | if (sp->s_parent != NULL) { | |
922 | diroffset += synthfs_adddirentry(sp->s_parent->s_nodeid, DT_DIR, "..", uio); | |
923 | } else { | |
924 | diroffset += synthfs_adddirentry(sp->s_nodeid, DT_DIR, "..", uio); | |
925 | } | |
91447636 | 926 | DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio))); |
1c79356b | 927 | } |
91447636 | 928 | if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) { |
1c79356b A |
929 | /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */ |
930 | return EINVAL; | |
931 | }; | |
932 | ||
933 | /* OK, so much for the fakes. Now for the "real thing": */ | |
934 | TAILQ_FOREACH(entry, &sp->s_u.d.d_subnodes, s_sibling) { | |
935 | if (diroffset == uio->uio_offset) { | |
936 | /* Return this entry */ | |
937 | diroffset += synthfs_adddirentry(entry->s_nodeid, VTTOIF(STOV(entry)->v_type), entry->s_name, uio); | |
938 | }; | |
91447636 | 939 | if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) { |
1c79356b A |
940 | /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */ |
941 | return EINVAL; | |
942 | }; | |
943 | }; | |
944 | ||
945 | if (ap->a_eofflag) | |
946 | *ap->a_eofflag = (entry == NULL); /* If we ran all the way through the list, there is no more */ | |
947 | ||
948 | return 0; | |
949 | } | |
950 | ||
951 | ||
952 | ||
953 | /* | |
954 | ||
955 | #% lookup dvp L ? ? | |
956 | #% lookup vpp - L - | |
957 | ||
958 | */ | |
959 | ||
960 | int | |
961 | synthfs_cached_lookup(ap) | |
91447636 | 962 | struct vnop_lookup_args /* { |
1c79356b A |
963 | struct vnode *a_dvp; |
964 | struct vnode **a_vpp; | |
965 | struct componentname *a_cnp; | |
966 | } */ *ap; | |
967 | { | |
968 | struct vnode *dp = ap->a_dvp; | |
969 | struct componentname *cnp = ap->a_cnp; | |
970 | u_long nameiop = cnp->cn_nameiop; | |
971 | u_long flags = cnp->cn_flags; | |
1c79356b A |
972 | struct vnode **vpp = ap->a_vpp; |
973 | int result = 0; | |
974 | ||
975 | DBG_VOP(("synthfs_cached_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen)); | |
91447636 | 976 | #if DEBUG |
1c79356b | 977 | if (flags & ISLASTCN) DBG_VOP(("\tISLASTCN is set\n")); |
91447636 | 978 | #endif |
1c79356b A |
979 | |
980 | *vpp = NULL; | |
981 | ||
1c79356b A |
982 | /* |
983 | * Look up an entry in the namei cache | |
984 | */ | |
985 | ||
986 | result = cache_lookup(dp, vpp, cnp); | |
987 | if (result == 0) { | |
988 | /* There was no entry in the cache for this parent vnode/name pair: | |
989 | do the full-blown pathname lookup | |
990 | */ | |
991 | return synthfs_lookup(ap); | |
992 | }; | |
993 | if (result == ENOENT) return result; | |
994 | ||
995 | /* An entry matching the parent vnode/name was found in the cache: */ | |
996 | ||
91447636 | 997 | return (0); |
1c79356b A |
998 | |
999 | Err_Exit:; | |
91447636 | 1000 | return result; |
1c79356b A |
1001 | } |
1002 | ||
1003 | ||
1004 | ||
1005 | int | |
1006 | synthfs_lookup(ap) | |
91447636 | 1007 | struct vnop_lookup_args /* { |
1c79356b A |
1008 | struct vnode *a_dvp; |
1009 | struct vnode **a_vpp; | |
1010 | struct componentname *a_cnp; | |
91447636 | 1011 | vfs_context_t a_context; |
1c79356b A |
1012 | } */ *ap; |
1013 | { | |
1014 | struct vnode *dp = ap->a_dvp; | |
1015 | struct synthfsnode *dsp = VTOS(dp); | |
1016 | struct componentname *cnp = ap->a_cnp; | |
1017 | u_long nameiop = cnp->cn_nameiop; | |
1018 | // char *nameptr = cnp->cn_nameptr; | |
1019 | u_long flags = cnp->cn_flags; | |
1020 | long namelen = cnp->cn_namelen; | |
91447636 A |
1021 | // struct proc *p = cnp->cn_proc; |
1022 | vfs_context_t ctx = cnp->cn_context; | |
1023 | kauth_cred_t cred = vfs_context_ucred(ctx); | |
1c79356b A |
1024 | struct synthfsnode *entry; |
1025 | struct vnode *target_vp = NULL; | |
1026 | int result = 0; | |
1027 | boolean_t found = FALSE; | |
1028 | boolean_t isDot = FALSE; | |
1029 | boolean_t isDotDot = FALSE; | |
1030 | struct vnode *starting_parent = dp; | |
1031 | ||
1032 | DBG_VOP(("synthfs_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen)); | |
91447636 | 1033 | #if DEBUG |
1c79356b A |
1034 | if (flags & LOCKPARENT) DBG_VOP(("\tLOCKPARENT is set\n")); |
1035 | if (flags & ISLASTCN) DBG_VOP(("\tISLASTCN is set\n")); | |
91447636 | 1036 | #endif |
1c79356b A |
1037 | |
1038 | *ap->a_vpp = NULL; | |
1039 | ||
1c79356b A |
1040 | /* first check for "." and ".." */ |
1041 | if (cnp->cn_nameptr[0] == '.') { | |
1042 | if (namelen == 1) { | |
1043 | /* | |
1044 | "." requested | |
1045 | */ | |
1046 | isDot = TRUE; | |
1047 | found = TRUE; | |
1048 | ||
1049 | target_vp = dp; | |
91447636 | 1050 | vnode_get(target_vp); |
1c79356b A |
1051 | |
1052 | result = 0; | |
1053 | ||
1054 | goto Std_Exit; | |
1055 | } else if ((namelen == 2) && (cnp->cn_nameptr[1] == '.')) { | |
1056 | /* | |
1057 | ".." requested | |
1058 | */ | |
1059 | isDotDot = TRUE; | |
1060 | found = TRUE; | |
1061 | ||
1062 | if ((dsp->s_parent != NULL) && (dsp->s_parent != VTOS(dp))) { | |
1063 | target_vp = STOV(dsp->s_parent); | |
1064 | /* | |
1065 | * Special case for ".." to prevent deadlock: | |
1066 | * always release the parent vnode BEFORE trying to acquire | |
1067 | * ITS parent. This avoids deadlocking with another lookup | |
91447636 | 1068 | * starting from the target_vp trying to vnode_get() this directory. |
1c79356b | 1069 | */ |
91447636 A |
1070 | result = vnode_get(target_vp); |
1071 | ||
1c79356b A |
1072 | } else { |
1073 | target_vp = dp; | |
1074 | /* dp is alread locked and ref'ed */ | |
1075 | result = 0; | |
1076 | } | |
1077 | ||
1078 | goto Std_Exit; | |
1079 | } | |
1080 | } | |
1081 | ||
1082 | /* finally, just look for entries by name (making sure the entry's length | |
1083 | matches the cnp's namelen... */ | |
1084 | TAILQ_FOREACH(entry, &dsp->s_u.d.d_subnodes, s_sibling) { | |
1085 | if ((bcmp(cnp->cn_nameptr, entry->s_name, (unsigned)namelen) == 0) && | |
1086 | (*(entry->s_name + namelen) == (char)0)) { | |
1087 | found = TRUE; | |
1088 | target_vp = STOV(entry); | |
91447636 | 1089 | result = vnode_getwithref(target_vp); /* refcount is always > 0 for any vnode in this list... */ |
1c79356b | 1090 | if (result != 0) { |
1c79356b A |
1091 | goto Err_Exit; |
1092 | }; | |
1093 | ||
1094 | /* The specified entry was found and successfully acquired: */ | |
1095 | goto Std_Exit; | |
1096 | }; | |
1097 | }; | |
1098 | ||
1099 | found = FALSE; | |
1100 | ||
1101 | Std_Exit:; | |
1102 | if (found) { | |
1103 | if ((nameiop == DELETE) && (flags & ISLASTCN)) { | |
1c79356b A |
1104 | |
1105 | /* | |
1106 | * If the parent directory is "sticky" then the user must own | |
1107 | * the directory, or the file in it, in order to be allowed to | |
1108 | * delete it (unless the user is root). This implements | |
1109 | * append-only directories | |
1110 | */ | |
1111 | if ((dsp->s_mode & S_ISVTX) && | |
91447636 A |
1112 | suser(cred, NULL) && |
1113 | (kauth_cred_getuid(cred) != dsp->s_uid) && | |
1c79356b A |
1114 | (target_vp != NULL) && |
1115 | (target_vp->v_type != VLNK) && | |
91447636 A |
1116 | (VTOS(target_vp)->s_uid != kauth_cred_getuid(cred))) { |
1117 | vnode_put(target_vp); | |
1c79356b A |
1118 | result = EPERM; |
1119 | goto Err_Exit; | |
1120 | }; | |
1121 | }; | |
1122 | ||
1123 | if ((nameiop == RENAME) && (flags & WANTPARENT) && (flags * ISLASTCN)) { | |
1c79356b A |
1124 | |
1125 | if (isDot) { | |
91447636 | 1126 | vnode_put(target_vp); |
1c79356b A |
1127 | result = EISDIR; |
1128 | goto Err_Exit; | |
1129 | }; | |
1130 | }; | |
1131 | } else { | |
1132 | /* The specified entry wasn't found: */ | |
1133 | result = ENOENT; | |
1134 | ||
1135 | if ((flags & ISLASTCN) && | |
1136 | ((nameiop == CREATE) || | |
1137 | (nameiop == RENAME) || | |
1138 | ((nameiop == DELETE) && (flags & DOWHITEOUT) && (flags & ISWHITEOUT)))) { | |
91447636 | 1139 | /* create a new entry */ |
1c79356b A |
1140 | result = EJUSTRETURN; |
1141 | } | |
1142 | }; | |
1143 | ||
1c79356b A |
1144 | *ap->a_vpp = target_vp; |
1145 | ||
1146 | Err_Exit:; | |
1147 | DBG_VOP(("synthfs_lookup: result = %d.\n", result)); | |
1148 | if (found) { | |
1149 | if (target_vp) { | |
91447636 | 1150 | DBG_VOP(("synthfs_lookup: target_vp = 0x%08X \n", (u_long)target_vp)); |
1c79356b A |
1151 | } else { |
1152 | DBG_VOP(("synthfs_lookup: found = true but target_vp = NULL?\n")); | |
1153 | }; | |
1154 | } else { | |
1155 | DBG_VOP(("synthf_lookup: target not found.\n")); | |
1156 | }; | |
91447636 | 1157 | DBG_VOP(("synthfs_lookup: dp = %08X; starting_parent = 0x%08X .\n", (u_long)dp, (u_long)starting_parent)); |
1c79356b A |
1158 | |
1159 | return result; | |
1160 | } | |
1161 | ||
1162 | ||
1163 | ||
1164 | /* | |
1165 | ||
1166 | #% pathconf vp L L L | |
1167 | # | |
91447636 | 1168 | vnop_pathconf { |
1c79356b A |
1169 | IN struct vnode *vp; |
1170 | IN int name; | |
1171 | OUT register_t *retval; | |
1172 | */ | |
1173 | int | |
1174 | synthfs_pathconf(ap) | |
91447636 | 1175 | struct vnop_pathconf_args /* { |
1c79356b A |
1176 | struct vnode *a_vp; |
1177 | int a_name; | |
1178 | int *a_retval; | |
91447636 | 1179 | vfs_context_t a_context; |
1c79356b A |
1180 | } */ *ap; |
1181 | { | |
1182 | DBG_VOP(("synthfs_pathconf called\n")); | |
1183 | ||
1184 | switch (ap->a_name) | |
1185 | { | |
1186 | case _PC_LINK_MAX: | |
1187 | *ap->a_retval = LINK_MAX; | |
1188 | return (0); | |
1189 | case _PC_NAME_MAX: | |
1190 | *ap->a_retval = NAME_MAX; | |
1191 | return (0); | |
1192 | case _PC_PATH_MAX: | |
1193 | *ap->a_retval = PATH_MAX; | |
1194 | return (0); | |
1195 | case _PC_PIPE_BUF: | |
1196 | *ap->a_retval = PIPE_BUF; | |
1197 | return (0); | |
1198 | case _PC_CHOWN_RESTRICTED: | |
2d21ac55 | 1199 | *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */ |
1c79356b A |
1200 | return (0); |
1201 | case _PC_NO_TRUNC: | |
2d21ac55 | 1202 | *ap->a_retval = 200112; /* _POSIX_NO_TRUNC */ |
1c79356b A |
1203 | return (0); |
1204 | default: | |
1205 | return (EINVAL); | |
1206 | } | |
1207 | /* NOTREACHED */ | |
1208 | } | |
1209 | ||
1210 | ||
1211 | /* | |
1212 | * Update the access, modified, and node change times as specified by the | |
1213 | * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is | |
1214 | * used to specify that the node needs to be updated but that the times have | |
1215 | * already been set. The access and modified times are taken from the second | |
1216 | * and third parameters; the node change time is always taken from the current | |
1217 | * time. If waitfor is set, then wait for the disk write of the node to | |
1218 | * complete. | |
1219 | */ | |
1c79356b A |
1220 | |
1221 | int | |
91447636 | 1222 | synthfs_update(struct vnode *vp, struct timeval *access, struct timeval *modify, __unused int waitfor) |
1c79356b | 1223 | { |
1c79356b | 1224 | struct synthfsnode *sp = VTOS(vp); |
91447636 | 1225 | struct timeval tv; |
1c79356b A |
1226 | |
1227 | DBG_ASSERT(sp != NULL); | |
1c79356b A |
1228 | |
1229 | if (((sp->s_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) != 0) && | |
91447636 A |
1230 | !(VTOVFS(vp)->mnt_flag & MNT_RDONLY)) { |
1231 | if (sp->s_nodeflags & IN_ACCESS) sp->s_accesstime = *access; | |
1232 | if (sp->s_nodeflags & IN_UPDATE) sp->s_modificationtime = *modify; | |
1233 | if (sp->s_nodeflags & IN_CHANGE) { | |
1234 | ||
1235 | microtime(&tv); | |
1236 | sp->s_changetime = tv; | |
1237 | } | |
1c79356b A |
1238 | }; |
1239 | ||
1240 | /* After the updates are finished, clear the flags */ | |
1241 | sp->s_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); | |
1242 | ||
1c79356b A |
1243 | return 0; |
1244 | } | |
1245 | ||
1246 | ||
1247 | ||
1248 | /******************************************************************************************* | |
1249 | ||
1250 | Utility/housekeeping vnode operations: | |
1251 | ||
1252 | ******************************************************************************************/ | |
1253 | ||
1254 | ||
1c79356b A |
1255 | /* |
1256 | # | |
1257 | #% inactive vp L U U | |
1258 | # | |
91447636 | 1259 | vnop_inactive { |
1c79356b A |
1260 | IN struct vnode *vp; |
1261 | IN struct proc *p; | |
1262 | ||
1263 | */ | |
1264 | ||
1265 | int | |
1266 | synthfs_inactive(ap) | |
91447636 | 1267 | struct vnop_inactive_args /* { |
1c79356b | 1268 | struct vnode *a_vp; |
91447636 | 1269 | vfs_context_t a_context; |
1c79356b A |
1270 | } */ *ap; |
1271 | { | |
1272 | struct vnode *vp = ap->a_vp; | |
1c79356b A |
1273 | struct synthfsnode *sp = VTOS(vp); |
1274 | struct timeval tv; | |
1275 | ||
91447636 | 1276 | #if DEBUG |
1c79356b A |
1277 | if (vp->v_usecount != 0) |
1278 | DBG_VOP(("synthfs_inactive: bad usecount = %d\n", vp->v_usecount )); | |
91447636 | 1279 | #endif |
1c79356b A |
1280 | |
1281 | /* | |
1282 | * Ignore nodes related to stale file handles. | |
1283 | */ | |
1284 | if (vp->v_type == VNON) | |
1285 | goto out; | |
1286 | ||
1287 | /* This is sort of silly but might make sense in the future: */ | |
1288 | if (sp->s_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { | |
91447636 A |
1289 | microtime(&tv); |
1290 | synthfs_update(vp, &tv, &tv, 0); | |
1c79356b A |
1291 | } |
1292 | ||
1293 | out: | |
1c79356b A |
1294 | /* |
1295 | * If we are done with the inode, reclaim it | |
1296 | * so that it can be reused immediately. | |
1297 | */ | |
1298 | if (vp->v_type == VNON) { | |
91447636 | 1299 | vnode_recycle(vp); |
1c79356b A |
1300 | }; |
1301 | ||
1302 | return 0; | |
1303 | } | |
1304 | ||
1305 | ||
1306 | ||
1307 | /* | |
1308 | * synthfs_reclaim - Reclaim a vnode so that it can be used for other purposes. | |
1309 | * | |
1310 | * Locking policy: ignored | |
1311 | */ | |
1312 | int | |
1313 | synthfs_reclaim(ap) | |
91447636 | 1314 | struct vnop_reclaim_args /* { struct vnode *a_vp; struct proc *a_p; } */ *ap; |
1c79356b A |
1315 | { |
1316 | struct vnode *vp = ap->a_vp; | |
1317 | struct synthfsnode *sp = VTOS(vp); | |
1318 | void *name = sp->s_name; | |
1319 | ||
1320 | sp->s_name = NULL; | |
1321 | FREE(name, M_TEMP); | |
1322 | ||
1323 | vp->v_data = NULL; | |
1324 | FREE((void *)sp, M_SYNTHFS); | |
1325 | ||
1326 | return (0); | |
1327 | } |