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