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