]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_vnops.c
1d0497a0f6ba1cce55743c67df4fe7f79ccfe69f
[apple/xnu.git] / bsd / hfs / hfs_vnops.c
1 /*
2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <sys/systm.h>
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/file_internal.h>
33 #include <sys/dirent.h>
34 #include <sys/stat.h>
35 #include <sys/buf.h>
36 #include <sys/buf_internal.h>
37 #include <sys/mount.h>
38 #include <sys/vnode_if.h>
39 #include <sys/vnode_internal.h>
40 #include <sys/malloc.h>
41 #include <sys/ubc.h>
42 #include <sys/ubc_internal.h>
43 #include <sys/paths.h>
44 #include <sys/quota.h>
45 #include <sys/time.h>
46 #include <sys/disk.h>
47 #include <sys/kauth.h>
48 #include <sys/uio_internal.h>
49 #include <sys/fsctl.h>
50 #include <sys/cprotect.h>
51 #include <sys/xattr.h>
52 #include <string.h>
53
54 #include <miscfs/specfs/specdev.h>
55 #include <miscfs/fifofs/fifo.h>
56 #include <vfs/vfs_support.h>
57 #include <machine/spl.h>
58
59 #include <sys/kdebug.h>
60 #include <sys/sysctl.h>
61
62 #include "hfs.h"
63 #include "hfs_catalog.h"
64 #include "hfs_cnode.h"
65 #include "hfs_dbg.h"
66 #include "hfs_mount.h"
67 #include "hfs_quota.h"
68 #include "hfs_endian.h"
69
70 #include "hfscommon/headers/BTreesInternal.h"
71 #include "hfscommon/headers/FileMgrInternal.h"
72
73 #define KNDETACH_VNLOCKED 0x00000001
74
75 /* Global vfs data structures for hfs */
76
77 /* Always F_FULLFSYNC? 1=yes,0=no (default due to "various" reasons is 'no') */
78 int always_do_fullfsync = 0;
79 SYSCTL_DECL(_vfs_generic);
80 SYSCTL_INT (_vfs_generic, OID_AUTO, always_do_fullfsync, CTLFLAG_RW | CTLFLAG_LOCKED, &always_do_fullfsync, 0, "always F_FULLFSYNC when fsync is called");
81
82 int hfs_makenode(struct vnode *dvp, struct vnode **vpp,
83 struct componentname *cnp, struct vnode_attr *vap,
84 vfs_context_t ctx);
85 int hfs_metasync(struct hfsmount *hfsmp, daddr64_t node, __unused struct proc *p);
86 int hfs_metasync_all(struct hfsmount *hfsmp);
87
88 int hfs_removedir(struct vnode *, struct vnode *, struct componentname *,
89 int, int);
90 int hfs_removefile(struct vnode *, struct vnode *, struct componentname *,
91 int, int, int, struct vnode *, int);
92
93 /* Used here and in cnode teardown -- for symlinks */
94 int hfs_removefile_callback(struct buf *bp, void *hfsmp);
95
96 int hfs_movedata (struct vnode *, struct vnode*);
97 static int hfs_move_fork (struct filefork *srcfork, struct cnode *src,
98 struct filefork *dstfork, struct cnode *dst);
99
100 #if FIFO
101 static int hfsfifo_read(struct vnop_read_args *);
102 static int hfsfifo_write(struct vnop_write_args *);
103 static int hfsfifo_close(struct vnop_close_args *);
104
105 extern int (**fifo_vnodeop_p)(void *);
106 #endif /* FIFO */
107
108 int hfs_vnop_close(struct vnop_close_args*);
109 int hfs_vnop_create(struct vnop_create_args*);
110 int hfs_vnop_exchange(struct vnop_exchange_args*);
111 int hfs_vnop_fsync(struct vnop_fsync_args*);
112 int hfs_vnop_mkdir(struct vnop_mkdir_args*);
113 int hfs_vnop_mknod(struct vnop_mknod_args*);
114 int hfs_vnop_getattr(struct vnop_getattr_args*);
115 int hfs_vnop_open(struct vnop_open_args*);
116 int hfs_vnop_readdir(struct vnop_readdir_args*);
117 int hfs_vnop_remove(struct vnop_remove_args*);
118 int hfs_vnop_rename(struct vnop_rename_args*);
119 int hfs_vnop_rmdir(struct vnop_rmdir_args*);
120 int hfs_vnop_symlink(struct vnop_symlink_args*);
121 int hfs_vnop_setattr(struct vnop_setattr_args*);
122 int hfs_vnop_readlink(struct vnop_readlink_args *);
123 int hfs_vnop_pathconf(struct vnop_pathconf_args *);
124 int hfs_vnop_whiteout(struct vnop_whiteout_args *);
125 int hfs_vnop_mmap(struct vnop_mmap_args *ap);
126 int hfsspec_read(struct vnop_read_args *);
127 int hfsspec_write(struct vnop_write_args *);
128 int hfsspec_close(struct vnop_close_args *);
129
130 /* Options for hfs_removedir and hfs_removefile */
131 #define HFSRM_SKIP_RESERVE 0x01
132
133
134
135
136 /*****************************************************************************
137 *
138 * Common Operations on vnodes
139 *
140 *****************************************************************************/
141
142 /*
143 * Is the given cnode either the .journal or .journal_info_block file on
144 * a volume with an active journal? Many VNOPs use this to deny access
145 * to those files.
146 *
147 * Note: the .journal file on a volume with an external journal still
148 * returns true here, even though it does not actually hold the contents
149 * of the volume's journal.
150 */
151 static _Bool
152 hfs_is_journal_file(struct hfsmount *hfsmp, struct cnode *cp)
153 {
154 if (hfsmp->jnl != NULL &&
155 (cp->c_fileid == hfsmp->hfs_jnlinfoblkid ||
156 cp->c_fileid == hfsmp->hfs_jnlfileid)) {
157 return true;
158 } else {
159 return false;
160 }
161 }
162
163 /*
164 * Create a regular file.
165 */
166 int
167 hfs_vnop_create(struct vnop_create_args *ap)
168 {
169 int error;
170
171 again:
172 error = hfs_makenode(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap, ap->a_context);
173
174 /*
175 * We speculatively skipped the original lookup of the leaf
176 * for CREATE. Since it exists, go get it as long as they
177 * didn't want an exclusive create.
178 */
179 if ((error == EEXIST) && !(ap->a_vap->va_vaflags & VA_EXCLUSIVE)) {
180 struct vnop_lookup_args args;
181
182 args.a_desc = &vnop_lookup_desc;
183 args.a_dvp = ap->a_dvp;
184 args.a_vpp = ap->a_vpp;
185 args.a_cnp = ap->a_cnp;
186 args.a_context = ap->a_context;
187 args.a_cnp->cn_nameiop = LOOKUP;
188 error = hfs_vnop_lookup(&args);
189 /*
190 * We can also race with remove for this file.
191 */
192 if (error == ENOENT) {
193 goto again;
194 }
195
196 /* Make sure it was file. */
197 if ((error == 0) && !vnode_isreg(*args.a_vpp)) {
198 vnode_put(*args.a_vpp);
199 *args.a_vpp = NULLVP;
200 error = EEXIST;
201 }
202 args.a_cnp->cn_nameiop = CREATE;
203 }
204 return (error);
205 }
206
207 /*
208 * Make device special file.
209 */
210 int
211 hfs_vnop_mknod(struct vnop_mknod_args *ap)
212 {
213 struct vnode_attr *vap = ap->a_vap;
214 struct vnode *dvp = ap->a_dvp;
215 struct vnode **vpp = ap->a_vpp;
216 struct cnode *cp;
217 int error;
218
219 if (VTOVCB(dvp)->vcbSigWord != kHFSPlusSigWord) {
220 return (ENOTSUP);
221 }
222
223 /* Create the vnode */
224 error = hfs_makenode(dvp, vpp, ap->a_cnp, vap, ap->a_context);
225 if (error)
226 return (error);
227
228 cp = VTOC(*vpp);
229 cp->c_touch_acctime = TRUE;
230 cp->c_touch_chgtime = TRUE;
231 cp->c_touch_modtime = TRUE;
232
233 if ((vap->va_rdev != VNOVAL) &&
234 (vap->va_type == VBLK || vap->va_type == VCHR))
235 cp->c_rdev = vap->va_rdev;
236
237 return (0);
238 }
239
240 #if HFS_COMPRESSION
241 /*
242 * hfs_ref_data_vp(): returns the data fork vnode for a given cnode.
243 * In the (hopefully rare) case where the data fork vnode is not
244 * present, it will use hfs_vget() to create a new vnode for the
245 * data fork.
246 *
247 * NOTE: If successful and a vnode is returned, the caller is responsible
248 * for releasing the returned vnode with vnode_rele().
249 */
250 static int
251 hfs_ref_data_vp(struct cnode *cp, struct vnode **data_vp, int skiplock)
252 {
253 int vref = 0;
254
255 if (!data_vp || !cp) /* sanity check incoming parameters */
256 return EINVAL;
257
258 /* maybe we should take the hfs cnode lock here, and if so, use the skiplock parameter to tell us not to */
259
260 if (!skiplock) hfs_lock(cp, HFS_SHARED_LOCK);
261 struct vnode *c_vp = cp->c_vp;
262 if (c_vp) {
263 /* we already have a data vnode */
264 *data_vp = c_vp;
265 vref = vnode_ref(*data_vp);
266 if (!skiplock) hfs_unlock(cp);
267 if (vref == 0) {
268 return 0;
269 }
270 return EINVAL;
271 }
272 /* no data fork vnode in the cnode, so ask hfs for one. */
273
274 if (!cp->c_rsrc_vp) {
275 /* if we don't have either a c_vp or c_rsrc_vp, we can't really do anything useful */
276 *data_vp = NULL;
277 if (!skiplock) hfs_unlock(cp);
278 return EINVAL;
279 }
280
281 if (0 == hfs_vget(VTOHFS(cp->c_rsrc_vp), cp->c_cnid, data_vp, 1, 0) &&
282 0 != data_vp) {
283 vref = vnode_ref(*data_vp);
284 vnode_put(*data_vp);
285 if (!skiplock) hfs_unlock(cp);
286 if (vref == 0) {
287 return 0;
288 }
289 return EINVAL;
290 }
291 /* there was an error getting the vnode */
292 *data_vp = NULL;
293 if (!skiplock) hfs_unlock(cp);
294 return EINVAL;
295 }
296
297 /*
298 * hfs_lazy_init_decmpfs_cnode(): returns the decmpfs_cnode for a cnode,
299 * allocating it if necessary; returns NULL if there was an allocation error
300 */
301 static decmpfs_cnode *
302 hfs_lazy_init_decmpfs_cnode(struct cnode *cp)
303 {
304 if (!cp->c_decmp) {
305 decmpfs_cnode *dp = NULL;
306 MALLOC_ZONE(dp, decmpfs_cnode *, sizeof(decmpfs_cnode), M_DECMPFS_CNODE, M_WAITOK);
307 if (!dp) {
308 /* error allocating a decmpfs cnode */
309 return NULL;
310 }
311 decmpfs_cnode_init(dp);
312 if (!OSCompareAndSwapPtr(NULL, dp, (void * volatile *)&cp->c_decmp)) {
313 /* another thread got here first, so free the decmpfs_cnode we allocated */
314 decmpfs_cnode_destroy(dp);
315 FREE_ZONE(dp, sizeof(*dp), M_DECMPFS_CNODE);
316 }
317 }
318
319 return cp->c_decmp;
320 }
321
322 /*
323 * hfs_file_is_compressed(): returns 1 if the file is compressed, and 0 (zero) if not.
324 * if the file's compressed flag is set, makes sure that the decmpfs_cnode field
325 * is allocated by calling hfs_lazy_init_decmpfs_cnode(), then makes sure it is populated,
326 * or else fills it in via the decmpfs_file_is_compressed() function.
327 */
328 int
329 hfs_file_is_compressed(struct cnode *cp, int skiplock)
330 {
331 int ret = 0;
332
333 /* fast check to see if file is compressed. If flag is clear, just answer no */
334 if (!(cp->c_bsdflags & UF_COMPRESSED)) {
335 return 0;
336 }
337
338 decmpfs_cnode *dp = hfs_lazy_init_decmpfs_cnode(cp);
339 if (!dp) {
340 /* error allocating a decmpfs cnode, treat the file as uncompressed */
341 return 0;
342 }
343
344 /* flag was set, see if the decmpfs_cnode state is valid (zero == invalid) */
345 uint32_t decmpfs_state = decmpfs_cnode_get_vnode_state(dp);
346 switch(decmpfs_state) {
347 case FILE_IS_COMPRESSED:
348 case FILE_IS_CONVERTING: /* treat decompressing files as if they are compressed */
349 return 1;
350 case FILE_IS_NOT_COMPRESSED:
351 return 0;
352 /* otherwise the state is not cached yet */
353 }
354
355 /* decmpfs hasn't seen this file yet, so call decmpfs_file_is_compressed() to init the decmpfs_cnode struct */
356 struct vnode *data_vp = NULL;
357 if (0 == hfs_ref_data_vp(cp, &data_vp, skiplock)) {
358 if (data_vp) {
359 ret = decmpfs_file_is_compressed(data_vp, VTOCMP(data_vp)); // fill in decmpfs_cnode
360 vnode_rele(data_vp);
361 }
362 }
363 return ret;
364 }
365
366 /* hfs_uncompressed_size_of_compressed_file() - get the uncompressed size of the file.
367 * if the caller has passed a valid vnode (has a ref count > 0), then hfsmp and fid are not required.
368 * if the caller doesn't have a vnode, pass NULL in vp, and pass valid hfsmp and fid.
369 * files size is returned in size (required)
370 * if the indicated file is a directory (or something that doesn't have a data fork), then this call
371 * will return an error and the caller should fall back to treating the item as an uncompressed file
372 */
373 int
374 hfs_uncompressed_size_of_compressed_file(struct hfsmount *hfsmp, struct vnode *vp, cnid_t fid, off_t *size, int skiplock)
375 {
376 int ret = 0;
377 int putaway = 0; /* flag to remember if we used hfs_vget() */
378
379 if (!size) {
380 return EINVAL; /* no place to put the file size */
381 }
382
383 if (NULL == vp) {
384 if (!hfsmp || !fid) { /* make sure we have the required parameters */
385 return EINVAL;
386 }
387 if (0 != hfs_vget(hfsmp, fid, &vp, skiplock, 0)) { /* vnode is null, use hfs_vget() to get it */
388 vp = NULL;
389 } else {
390 putaway = 1; /* note that hfs_vget() was used to aquire the vnode */
391 }
392 }
393 /* this double check for compression (hfs_file_is_compressed)
394 * ensures the cached size is present in case decmpfs hasn't
395 * encountered this node yet.
396 */
397 if (vp) {
398 if (hfs_file_is_compressed(VTOC(vp), skiplock) ) {
399 *size = decmpfs_cnode_get_vnode_cached_size(VTOCMP(vp)); /* file info will be cached now, so get size */
400 } else {
401 if (VTOCMP(vp) && VTOCMP(vp)->cmp_type >= CMP_MAX) {
402 if (VTOCMP(vp)->cmp_type != DATALESS_CMPFS_TYPE) {
403 // if we don't recognize this type, just use the real data fork size
404 if (VTOC(vp)->c_datafork) {
405 *size = VTOC(vp)->c_datafork->ff_size;
406 ret = 0;
407 } else {
408 ret = EINVAL;
409 }
410 } else {
411 *size = decmpfs_cnode_get_vnode_cached_size(VTOCMP(vp)); /* file info will be cached now, so get size */
412 ret = 0;
413 }
414 } else {
415 ret = EINVAL;
416 }
417 }
418 }
419
420 if (putaway) { /* did we use hfs_vget() to get this vnode? */
421 vnode_put(vp); /* if so, release it and set it to null */
422 vp = NULL;
423 }
424 return ret;
425 }
426
427 int
428 hfs_hides_rsrc(vfs_context_t ctx, struct cnode *cp, int skiplock)
429 {
430 if (ctx == decmpfs_ctx)
431 return 0;
432 if (!hfs_file_is_compressed(cp, skiplock))
433 return 0;
434 return decmpfs_hides_rsrc(ctx, cp->c_decmp);
435 }
436
437 int
438 hfs_hides_xattr(vfs_context_t ctx, struct cnode *cp, const char *name, int skiplock)
439 {
440 if (ctx == decmpfs_ctx)
441 return 0;
442 if (!hfs_file_is_compressed(cp, skiplock))
443 return 0;
444 return decmpfs_hides_xattr(ctx, cp->c_decmp, name);
445 }
446 #endif /* HFS_COMPRESSION */
447
448 /*
449 * Open a file/directory.
450 */
451 int
452 hfs_vnop_open(struct vnop_open_args *ap)
453 {
454 struct vnode *vp = ap->a_vp;
455 struct filefork *fp;
456 struct timeval tv;
457 int error;
458 static int past_bootup = 0;
459 struct cnode *cp = VTOC(vp);
460 struct hfsmount *hfsmp = VTOHFS(vp);
461
462 #if HFS_COMPRESSION
463 if (ap->a_mode & FWRITE) {
464 /* open for write */
465 if ( hfs_file_is_compressed(cp, 1) ) { /* 1 == don't take the cnode lock */
466 /* opening a compressed file for write, so convert it to decompressed */
467 struct vnode *data_vp = NULL;
468 error = hfs_ref_data_vp(cp, &data_vp, 1); /* 1 == don't take the cnode lock */
469 if (0 == error) {
470 if (data_vp) {
471 error = decmpfs_decompress_file(data_vp, VTOCMP(data_vp), -1, 1, 0);
472 vnode_rele(data_vp);
473 } else {
474 error = EINVAL;
475 }
476 }
477 if (error != 0)
478 return error;
479 }
480 } else {
481 /* open for read */
482 if (hfs_file_is_compressed(cp, 1) ) { /* 1 == don't take the cnode lock */
483 if (VNODE_IS_RSRC(vp)) {
484 /* opening the resource fork of a compressed file, so nothing to do */
485 } else {
486 /* opening a compressed file for read, make sure it validates */
487 error = decmpfs_validate_compressed_file(vp, VTOCMP(vp));
488 if (error != 0)
489 return error;
490 }
491 }
492 }
493 #endif
494
495 /*
496 * Files marked append-only must be opened for appending.
497 */
498 if ((cp->c_bsdflags & APPEND) && !vnode_isdir(vp) &&
499 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
500 return (EPERM);
501
502 if (vnode_isreg(vp) && !UBCINFOEXISTS(vp))
503 return (EBUSY); /* file is in use by the kernel */
504
505 /* Don't allow journal to be opened externally. */
506 if (hfs_is_journal_file(hfsmp, cp))
507 return (EPERM);
508
509 if ((hfsmp->hfs_flags & HFS_READ_ONLY) ||
510 (hfsmp->jnl == NULL) ||
511 #if NAMEDSTREAMS
512 !vnode_isreg(vp) || vnode_isinuse(vp, 0) || vnode_isnamedstream(vp)) {
513 #else
514 !vnode_isreg(vp) || vnode_isinuse(vp, 0)) {
515 #endif
516 return (0);
517 }
518
519 if ((error = hfs_lock(cp, HFS_EXCLUSIVE_LOCK)))
520 return (error);
521
522 #if QUOTA
523 /* If we're going to write to the file, initialize quotas. */
524 if ((ap->a_mode & FWRITE) && (hfsmp->hfs_flags & HFS_QUOTAS))
525 (void)hfs_getinoquota(cp);
526 #endif /* QUOTA */
527
528 /*
529 * On the first (non-busy) open of a fragmented
530 * file attempt to de-frag it (if its less than 20MB).
531 */
532 fp = VTOF(vp);
533 if (fp->ff_blocks &&
534 fp->ff_extents[7].blockCount != 0 &&
535 fp->ff_size <= (20 * 1024 * 1024)) {
536 int no_mods = 0;
537 struct timeval now;
538 /*
539 * Wait until system bootup is done (3 min).
540 * And don't relocate a file that's been modified
541 * within the past minute -- this can lead to
542 * system thrashing.
543 */
544
545 if (!past_bootup) {
546 microuptime(&tv);
547 if (tv.tv_sec > (60*3)) {
548 past_bootup = 1;
549 }
550 }
551
552 microtime(&now);
553 if ((now.tv_sec - cp->c_mtime) > 60) {
554 no_mods = 1;
555 }
556
557 if (past_bootup && no_mods) {
558 (void) hfs_relocate(vp, hfsmp->nextAllocation + 4096,
559 vfs_context_ucred(ap->a_context),
560 vfs_context_proc(ap->a_context));
561 }
562 }
563
564 hfs_unlock(cp);
565
566 return (0);
567 }
568
569
570 /*
571 * Close a file/directory.
572 */
573 int
574 hfs_vnop_close(ap)
575 struct vnop_close_args /* {
576 struct vnode *a_vp;
577 int a_fflag;
578 vfs_context_t a_context;
579 } */ *ap;
580 {
581 register struct vnode *vp = ap->a_vp;
582 register struct cnode *cp;
583 struct proc *p = vfs_context_proc(ap->a_context);
584 struct hfsmount *hfsmp;
585 int busy;
586 int tooktrunclock = 0;
587 int knownrefs = 0;
588
589 if ( hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK) != 0)
590 return (0);
591 cp = VTOC(vp);
592 hfsmp = VTOHFS(vp);
593
594 /*
595 * If the rsrc fork is a named stream, it can cause the data fork to
596 * stay around, preventing de-allocation of these blocks.
597 * Do checks for truncation on close. Purge extra extents if they exist.
598 * Make sure the vp is not a directory, and that it has a resource fork,
599 * and that resource fork is also a named stream.
600 */
601
602 if ((vp->v_type == VREG) && (cp->c_rsrc_vp)
603 && (vnode_isnamedstream(cp->c_rsrc_vp))) {
604 uint32_t blks;
605
606 blks = howmany(VTOF(vp)->ff_size, VTOVCB(vp)->blockSize);
607 /*
608 * If there are extra blocks and there are only 2 refs on
609 * this vp (ourselves + rsrc fork holding ref on us), go ahead
610 * and try to truncate.
611 */
612 if ((blks < VTOF(vp)->ff_blocks) && (!vnode_isinuse(vp, 2))) {
613 // release cnode lock; must acquire truncate lock BEFORE cnode lock
614 hfs_unlock(cp);
615
616 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK);
617 tooktrunclock = 1;
618
619 if (hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK) != 0) {
620 hfs_unlock_truncate(cp, 0);
621 // bail out if we can't re-acquire cnode lock
622 return 0;
623 }
624 // now re-test to make sure it's still valid
625 if (cp->c_rsrc_vp) {
626 knownrefs = 1 + vnode_isnamedstream(cp->c_rsrc_vp);
627 if (!vnode_isinuse(vp, knownrefs)){
628 // now we can truncate the file, if necessary
629 blks = howmany(VTOF(vp)->ff_size, VTOVCB(vp)->blockSize);
630 if (blks < VTOF(vp)->ff_blocks){
631 (void) hfs_truncate(vp, VTOF(vp)->ff_size, IO_NDELAY, 0, 0, ap->a_context);
632 }
633 }
634 }
635 }
636 }
637
638
639 // if we froze the fs and we're exiting, then "thaw" the fs
640 if (hfsmp->hfs_freezing_proc == p && proc_exiting(p)) {
641 hfsmp->hfs_freezing_proc = NULL;
642 hfs_unlock_global (hfsmp);
643 lck_rw_unlock_exclusive(&hfsmp->hfs_insync);
644 }
645
646 busy = vnode_isinuse(vp, 1);
647
648 if (busy) {
649 hfs_touchtimes(VTOHFS(vp), cp);
650 }
651 if (vnode_isdir(vp)) {
652 hfs_reldirhints(cp, busy);
653 } else if (vnode_issystem(vp) && !busy) {
654 vnode_recycle(vp);
655 }
656
657 if (tooktrunclock){
658 hfs_unlock_truncate(cp, 0);
659 }
660 hfs_unlock(cp);
661
662 if (ap->a_fflag & FWASWRITTEN) {
663 hfs_sync_ejectable(hfsmp);
664 }
665
666 return (0);
667 }
668
669 /*
670 * Get basic attributes.
671 */
672 int
673 hfs_vnop_getattr(struct vnop_getattr_args *ap)
674 {
675 #define VNODE_ATTR_TIMES \
676 (VNODE_ATTR_va_access_time|VNODE_ATTR_va_change_time|VNODE_ATTR_va_modify_time)
677 #define VNODE_ATTR_AUTH \
678 (VNODE_ATTR_va_mode | VNODE_ATTR_va_uid | VNODE_ATTR_va_gid | \
679 VNODE_ATTR_va_flags | VNODE_ATTR_va_acl)
680
681 struct vnode *vp = ap->a_vp;
682 struct vnode_attr *vap = ap->a_vap;
683 struct vnode *rvp = NULLVP;
684 struct hfsmount *hfsmp;
685 struct cnode *cp;
686 uint64_t data_size;
687 enum vtype v_type;
688 int error = 0;
689 cp = VTOC(vp);
690
691 #if HFS_COMPRESSION
692 /* we need to inspect the decmpfs state of the file before we take the hfs cnode lock */
693 int compressed = 0;
694 int hide_size = 0;
695 off_t uncompressed_size = -1;
696 if (VATTR_IS_ACTIVE(vap, va_data_size) || VATTR_IS_ACTIVE(vap, va_total_alloc) || VATTR_IS_ACTIVE(vap, va_data_alloc) || VATTR_IS_ACTIVE(vap, va_total_size)) {
697 /* we only care about whether the file is compressed if asked for the uncompressed size */
698 if (VNODE_IS_RSRC(vp)) {
699 /* if it's a resource fork, decmpfs may want us to hide the size */
700 hide_size = hfs_hides_rsrc(ap->a_context, cp, 0);
701 } else {
702 /* if it's a data fork, we need to know if it was compressed so we can report the uncompressed size */
703 compressed = hfs_file_is_compressed(cp, 0);
704 }
705 if ((VATTR_IS_ACTIVE(vap, va_data_size) || VATTR_IS_ACTIVE(vap, va_total_size))) {
706 // if it's compressed
707 if (compressed || (!VNODE_IS_RSRC(vp) && cp->c_decmp && cp->c_decmp->cmp_type >= CMP_MAX)) {
708 if (0 != hfs_uncompressed_size_of_compressed_file(NULL, vp, 0, &uncompressed_size, 0)) {
709 /* failed to get the uncompressed size, we'll check for this later */
710 uncompressed_size = -1;
711 } else {
712 // fake that it's compressed
713 compressed = 1;
714 }
715 }
716 }
717 }
718 #endif
719
720 /*
721 * Shortcut for vnode_authorize path. Each of the attributes
722 * in this set is updated atomically so we don't need to take
723 * the cnode lock to access them.
724 */
725 if ((vap->va_active & ~VNODE_ATTR_AUTH) == 0) {
726 /* Make sure file still exists. */
727 if (cp->c_flag & C_NOEXISTS)
728 return (ENOENT);
729
730 vap->va_uid = cp->c_uid;
731 vap->va_gid = cp->c_gid;
732 vap->va_mode = cp->c_mode;
733 vap->va_flags = cp->c_bsdflags;
734 vap->va_supported |= VNODE_ATTR_AUTH & ~VNODE_ATTR_va_acl;
735
736 if ((cp->c_attr.ca_recflags & kHFSHasSecurityMask) == 0) {
737 vap->va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE;
738 VATTR_SET_SUPPORTED(vap, va_acl);
739 }
740
741 return (0);
742 }
743
744 hfsmp = VTOHFS(vp);
745 v_type = vnode_vtype(vp);
746 /*
747 * If time attributes are requested and we have cnode times
748 * that require updating, then acquire an exclusive lock on
749 * the cnode before updating the times. Otherwise we can
750 * just acquire a shared lock.
751 */
752 if ((vap->va_active & VNODE_ATTR_TIMES) &&
753 (cp->c_touch_acctime || cp->c_touch_chgtime || cp->c_touch_modtime)) {
754 if ((error = hfs_lock(cp, HFS_EXCLUSIVE_LOCK)))
755 return (error);
756 hfs_touchtimes(hfsmp, cp);
757 }
758 else {
759 if ((error = hfs_lock(cp, HFS_SHARED_LOCK)))
760 return (error);
761 }
762
763 if (v_type == VDIR) {
764 data_size = (cp->c_entries + 2) * AVERAGE_HFSDIRENTRY_SIZE;
765
766 if (VATTR_IS_ACTIVE(vap, va_nlink)) {
767 int nlink;
768
769 /*
770 * For directories, the va_nlink is esentially a count
771 * of the ".." references to a directory plus the "."
772 * reference and the directory itself. So for HFS+ this
773 * becomes the sub-directory count plus two.
774 *
775 * In the absence of a sub-directory count we use the
776 * directory's item count. This will be too high in
777 * most cases since it also includes files.
778 */
779 if ((hfsmp->hfs_flags & HFS_FOLDERCOUNT) &&
780 (cp->c_attr.ca_recflags & kHFSHasFolderCountMask))
781 nlink = cp->c_attr.ca_dircount; /* implied ".." entries */
782 else
783 nlink = cp->c_entries;
784
785 /* Account for ourself and our "." entry */
786 nlink += 2;
787 /* Hide our private directories. */
788 if (cp->c_cnid == kHFSRootFolderID) {
789 if (hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid != 0) {
790 --nlink;
791 }
792 if (hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid != 0) {
793 --nlink;
794 }
795 }
796 VATTR_RETURN(vap, va_nlink, (u_int64_t)nlink);
797 }
798 if (VATTR_IS_ACTIVE(vap, va_nchildren)) {
799 int entries;
800
801 entries = cp->c_entries;
802 /* Hide our private files and directories. */
803 if (cp->c_cnid == kHFSRootFolderID) {
804 if (hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid != 0)
805 --entries;
806 if (hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid != 0)
807 --entries;
808 if (hfsmp->jnl || ((hfsmp->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY)))
809 entries -= 2; /* hide the journal files */
810 }
811 VATTR_RETURN(vap, va_nchildren, entries);
812 }
813 /*
814 * The va_dirlinkcount is the count of real directory hard links.
815 * (i.e. its not the sum of the implied "." and ".." references)
816 */
817 if (VATTR_IS_ACTIVE(vap, va_dirlinkcount)) {
818 VATTR_RETURN(vap, va_dirlinkcount, (uint32_t)cp->c_linkcount);
819 }
820 } else /* !VDIR */ {
821 data_size = VCTOF(vp, cp)->ff_size;
822
823 VATTR_RETURN(vap, va_nlink, (u_int64_t)cp->c_linkcount);
824 if (VATTR_IS_ACTIVE(vap, va_data_alloc)) {
825 u_int64_t blocks;
826
827 #if HFS_COMPRESSION
828 if (hide_size) {
829 VATTR_RETURN(vap, va_data_alloc, 0);
830 } else if (compressed) {
831 /* for compressed files, we report all allocated blocks as belonging to the data fork */
832 blocks = cp->c_blocks;
833 VATTR_RETURN(vap, va_data_alloc, blocks * (u_int64_t)hfsmp->blockSize);
834 }
835 else
836 #endif
837 {
838 blocks = VCTOF(vp, cp)->ff_blocks;
839 VATTR_RETURN(vap, va_data_alloc, blocks * (u_int64_t)hfsmp->blockSize);
840 }
841 }
842 }
843
844 /* conditional because 64-bit arithmetic can be expensive */
845 if (VATTR_IS_ACTIVE(vap, va_total_size)) {
846 if (v_type == VDIR) {
847 VATTR_RETURN(vap, va_total_size, (cp->c_entries + 2) * AVERAGE_HFSDIRENTRY_SIZE);
848 } else {
849 u_int64_t total_size = ~0ULL;
850 struct cnode *rcp;
851 #if HFS_COMPRESSION
852 if (hide_size) {
853 /* we're hiding the size of this file, so just return 0 */
854 total_size = 0;
855 } else if (compressed) {
856 if (uncompressed_size == -1) {
857 /*
858 * We failed to get the uncompressed size above,
859 * so we'll fall back to the standard path below
860 * since total_size is still -1
861 */
862 } else {
863 /* use the uncompressed size we fetched above */
864 total_size = uncompressed_size;
865 }
866 }
867 #endif
868 if (total_size == ~0ULL) {
869 if (cp->c_datafork) {
870 total_size = cp->c_datafork->ff_size;
871 }
872
873 if (cp->c_blocks - VTOF(vp)->ff_blocks) {
874 /* We deal with rsrc fork vnode iocount at the end of the function */
875 error = hfs_vgetrsrc(hfsmp, vp, &rvp, TRUE, FALSE);
876 if (error) {
877 /*
878 * Note that we call hfs_vgetrsrc with error_on_unlinked
879 * set to FALSE. This is because we may be invoked via
880 * fstat() on an open-unlinked file descriptor and we must
881 * continue to support access to the rsrc fork until it disappears.
882 * The code at the end of this function will be
883 * responsible for releasing the iocount generated by
884 * hfs_vgetrsrc. This is because we can't drop the iocount
885 * without unlocking the cnode first.
886 */
887 goto out;
888 }
889
890 rcp = VTOC(rvp);
891 if (rcp && rcp->c_rsrcfork) {
892 total_size += rcp->c_rsrcfork->ff_size;
893 }
894 }
895 }
896
897 VATTR_RETURN(vap, va_total_size, total_size);
898 }
899 }
900 if (VATTR_IS_ACTIVE(vap, va_total_alloc)) {
901 if (v_type == VDIR) {
902 VATTR_RETURN(vap, va_total_alloc, 0);
903 } else {
904 VATTR_RETURN(vap, va_total_alloc, (u_int64_t)cp->c_blocks * (u_int64_t)hfsmp->blockSize);
905 }
906 }
907
908 /*
909 * If the VFS wants extended security data, and we know that we
910 * don't have any (because it never told us it was setting any)
911 * then we can return the supported bit and no data. If we do
912 * have extended security, we can just leave the bit alone and
913 * the VFS will use the fallback path to fetch it.
914 */
915 if (VATTR_IS_ACTIVE(vap, va_acl)) {
916 if ((cp->c_attr.ca_recflags & kHFSHasSecurityMask) == 0) {
917 vap->va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE;
918 VATTR_SET_SUPPORTED(vap, va_acl);
919 }
920 }
921 if (VATTR_IS_ACTIVE(vap, va_access_time)) {
922 /* Access times are lazily updated, get current time if needed */
923 if (cp->c_touch_acctime) {
924 struct timeval tv;
925
926 microtime(&tv);
927 vap->va_access_time.tv_sec = tv.tv_sec;
928 } else {
929 vap->va_access_time.tv_sec = cp->c_atime;
930 }
931 vap->va_access_time.tv_nsec = 0;
932 VATTR_SET_SUPPORTED(vap, va_access_time);
933 }
934 vap->va_create_time.tv_sec = cp->c_itime;
935 vap->va_create_time.tv_nsec = 0;
936 vap->va_modify_time.tv_sec = cp->c_mtime;
937 vap->va_modify_time.tv_nsec = 0;
938 vap->va_change_time.tv_sec = cp->c_ctime;
939 vap->va_change_time.tv_nsec = 0;
940 vap->va_backup_time.tv_sec = cp->c_btime;
941 vap->va_backup_time.tv_nsec = 0;
942
943 /* See if we need to emit the date added field to the user */
944 if (VATTR_IS_ACTIVE(vap, va_addedtime)) {
945 u_int32_t dateadded = hfs_get_dateadded (cp);
946 if (dateadded) {
947 vap->va_addedtime.tv_sec = dateadded;
948 vap->va_addedtime.tv_nsec = 0;
949 VATTR_SET_SUPPORTED (vap, va_addedtime);
950 }
951 }
952
953 /* XXX is this really a good 'optimal I/O size'? */
954 vap->va_iosize = hfsmp->hfs_logBlockSize;
955 vap->va_uid = cp->c_uid;
956 vap->va_gid = cp->c_gid;
957 vap->va_mode = cp->c_mode;
958 vap->va_flags = cp->c_bsdflags;
959
960 /*
961 * Exporting file IDs from HFS Plus:
962 *
963 * For "normal" files the c_fileid is the same value as the
964 * c_cnid. But for hard link files, they are different - the
965 * c_cnid belongs to the active directory entry (ie the link)
966 * and the c_fileid is for the actual inode (ie the data file).
967 *
968 * The stat call (getattr) uses va_fileid and the Carbon APIs,
969 * which are hardlink-ignorant, will ask for va_linkid.
970 */
971 vap->va_fileid = (u_int64_t)cp->c_fileid;
972 /*
973 * We need to use the origin cache for both hardlinked files
974 * and directories. Hardlinked directories have multiple cnids
975 * and parents (one per link). Hardlinked files also have their
976 * own parents and link IDs separate from the indirect inode number.
977 * If we don't use the cache, we could end up vending the wrong ID
978 * because the cnode will only reflect the link that was looked up most recently.
979 */
980 if (cp->c_flag & C_HARDLINK) {
981 vap->va_linkid = (u_int64_t)hfs_currentcnid(cp);
982 vap->va_parentid = (u_int64_t)hfs_currentparent(cp);
983 } else {
984 vap->va_linkid = (u_int64_t)cp->c_cnid;
985 vap->va_parentid = (u_int64_t)cp->c_parentcnid;
986 }
987 vap->va_fsid = hfsmp->hfs_raw_dev;
988 vap->va_filerev = 0;
989 vap->va_encoding = cp->c_encoding;
990 vap->va_rdev = (v_type == VBLK || v_type == VCHR) ? cp->c_rdev : 0;
991 #if HFS_COMPRESSION
992 if (VATTR_IS_ACTIVE(vap, va_data_size)) {
993 if (hide_size)
994 vap->va_data_size = 0;
995 else if (compressed) {
996 if (uncompressed_size == -1) {
997 /* failed to get the uncompressed size above, so just return data_size */
998 vap->va_data_size = data_size;
999 } else {
1000 /* use the uncompressed size we fetched above */
1001 vap->va_data_size = uncompressed_size;
1002 }
1003 } else
1004 vap->va_data_size = data_size;
1005 // vap->va_supported |= VNODE_ATTR_va_data_size;
1006 VATTR_SET_SUPPORTED(vap, va_data_size);
1007 }
1008 #else
1009 vap->va_data_size = data_size;
1010 vap->va_supported |= VNODE_ATTR_va_data_size;
1011 #endif
1012
1013 /* Mark them all at once instead of individual VATTR_SET_SUPPORTED calls. */
1014 vap->va_supported |= VNODE_ATTR_va_create_time | VNODE_ATTR_va_modify_time |
1015 VNODE_ATTR_va_change_time| VNODE_ATTR_va_backup_time |
1016 VNODE_ATTR_va_iosize | VNODE_ATTR_va_uid |
1017 VNODE_ATTR_va_gid | VNODE_ATTR_va_mode |
1018 VNODE_ATTR_va_flags |VNODE_ATTR_va_fileid |
1019 VNODE_ATTR_va_linkid | VNODE_ATTR_va_parentid |
1020 VNODE_ATTR_va_fsid | VNODE_ATTR_va_filerev |
1021 VNODE_ATTR_va_encoding | VNODE_ATTR_va_rdev;
1022
1023 /* If this is the root, let VFS to find out the mount name, which
1024 * may be different from the real name. Otherwise, we need to take care
1025 * for hardlinked files, which need to be looked up, if necessary
1026 */
1027 if (VATTR_IS_ACTIVE(vap, va_name) && (cp->c_cnid != kHFSRootFolderID)) {
1028 struct cat_desc linkdesc;
1029 int lockflags;
1030 int uselinkdesc = 0;
1031 cnid_t nextlinkid = 0;
1032 cnid_t prevlinkid = 0;
1033
1034 /* Get the name for ATTR_CMN_NAME. We need to take special care for hardlinks
1035 * here because the info. for the link ID requested by getattrlist may be
1036 * different than what's currently in the cnode. This is because the cnode
1037 * will be filled in with the information for the most recent link ID that went
1038 * through namei/lookup(). If there are competing lookups for hardlinks that point
1039 * to the same inode, one (or more) getattrlists could be vended incorrect name information.
1040 * Also, we need to beware of open-unlinked files which could have a namelen of 0.
1041 */
1042
1043 if ((cp->c_flag & C_HARDLINK) &&
1044 ((cp->c_desc.cd_namelen == 0) || (vap->va_linkid != cp->c_cnid))) {
1045 /* If we have no name and our link ID is the raw inode number, then we may
1046 * have an open-unlinked file. Go to the next link in this case.
1047 */
1048 if ((cp->c_desc.cd_namelen == 0) && (vap->va_linkid == cp->c_fileid)) {
1049 if ((error = hfs_lookup_siblinglinks(hfsmp, vap->va_linkid, &prevlinkid, &nextlinkid))){
1050 goto out;
1051 }
1052 }
1053 else {
1054 /* just use link obtained from vap above */
1055 nextlinkid = vap->va_linkid;
1056 }
1057
1058 /* We need to probe the catalog for the descriptor corresponding to the link ID
1059 * stored in nextlinkid. Note that we don't know if we have the exclusive lock
1060 * for the cnode here, so we can't just update the descriptor. Instead,
1061 * we should just store the descriptor's value locally and then use it to pass
1062 * out the name value as needed below.
1063 */
1064 if (nextlinkid){
1065 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
1066 error = cat_findname(hfsmp, nextlinkid, &linkdesc);
1067 hfs_systemfile_unlock(hfsmp, lockflags);
1068 if (error == 0) {
1069 uselinkdesc = 1;
1070 }
1071 }
1072 }
1073
1074 /* By this point, we've either patched up the name above and the c_desc
1075 * points to the correct data, or it already did, in which case we just proceed
1076 * by copying the name into the vap. Note that we will never set va_name to
1077 * supported if nextlinkid is never initialized. This could happen in the degenerate
1078 * case above involving the raw inode number, where it has no nextlinkid. In this case
1079 * we will simply not mark the name bit as supported.
1080 */
1081 if (uselinkdesc) {
1082 strlcpy(vap->va_name, (const char*) linkdesc.cd_nameptr, MAXPATHLEN);
1083 VATTR_SET_SUPPORTED(vap, va_name);
1084 cat_releasedesc(&linkdesc);
1085 }
1086 else if (cp->c_desc.cd_namelen) {
1087 strlcpy(vap->va_name, (const char*) cp->c_desc.cd_nameptr, MAXPATHLEN);
1088 VATTR_SET_SUPPORTED(vap, va_name);
1089 }
1090 }
1091
1092 out:
1093 hfs_unlock(cp);
1094 /*
1095 * We need to vnode_put the rsrc fork vnode only *after* we've released
1096 * the cnode lock, since vnode_put can trigger an inactive call, which
1097 * will go back into HFS and try to acquire a cnode lock.
1098 */
1099 if (rvp) {
1100 vnode_put (rvp);
1101 }
1102
1103 return (error);
1104 }
1105
1106 int
1107 hfs_vnop_setattr(ap)
1108 struct vnop_setattr_args /* {
1109 struct vnode *a_vp;
1110 struct vnode_attr *a_vap;
1111 vfs_context_t a_context;
1112 } */ *ap;
1113 {
1114 struct vnode_attr *vap = ap->a_vap;
1115 struct vnode *vp = ap->a_vp;
1116 struct cnode *cp = NULL;
1117 struct hfsmount *hfsmp;
1118 kauth_cred_t cred = vfs_context_ucred(ap->a_context);
1119 struct proc *p = vfs_context_proc(ap->a_context);
1120 int error = 0;
1121 uid_t nuid;
1122 gid_t ngid;
1123 time_t orig_ctime;
1124
1125 orig_ctime = VTOC(vp)->c_ctime;
1126
1127 #if HFS_COMPRESSION
1128 int decmpfs_reset_state = 0;
1129 /*
1130 we call decmpfs_update_attributes even if the file is not compressed
1131 because we want to update the incoming flags if the xattrs are invalid
1132 */
1133 error = decmpfs_update_attributes(vp, vap);
1134 if (error)
1135 return error;
1136
1137 //
1138 // if this is not a size-changing setattr and it is not just
1139 // an atime update, then check for a snapshot.
1140 //
1141 if (!VATTR_IS_ACTIVE(vap, va_data_size) && !(vap->va_active == VNODE_ATTR_va_access_time)) {
1142 check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_METADATA_MOD, NULL);
1143 }
1144 #endif
1145
1146
1147 #if CONFIG_PROTECT
1148 if ((error = cp_handle_vnop(vp, CP_WRITE_ACCESS, 0)) != 0) {
1149 return (error);
1150 }
1151 #endif /* CONFIG_PROTECT */
1152
1153 hfsmp = VTOHFS(vp);
1154
1155 /* Don't allow modification of the journal. */
1156 if (hfs_is_journal_file(hfsmp, VTOC(vp))) {
1157 return (EPERM);
1158 }
1159
1160 /*
1161 * File size change request.
1162 * We are guaranteed that this is not a directory, and that
1163 * the filesystem object is writeable.
1164 *
1165 * NOTE: HFS COMPRESSION depends on the data_size being set *before* the bsd flags are updated
1166 */
1167 VATTR_SET_SUPPORTED(vap, va_data_size);
1168 if (VATTR_IS_ACTIVE(vap, va_data_size) && !vnode_islnk(vp)) {
1169 #if HFS_COMPRESSION
1170 /* keep the compressed state locked until we're done truncating the file */
1171 decmpfs_cnode *dp = VTOCMP(vp);
1172 if (!dp) {
1173 /*
1174 * call hfs_lazy_init_decmpfs_cnode() to make sure that the decmpfs_cnode
1175 * is filled in; we need a decmpfs_cnode to lock out decmpfs state changes
1176 * on this file while it's truncating
1177 */
1178 dp = hfs_lazy_init_decmpfs_cnode(VTOC(vp));
1179 if (!dp) {
1180 /* failed to allocate a decmpfs_cnode */
1181 return ENOMEM; /* what should this be? */
1182 }
1183 }
1184
1185 check_for_tracked_file(vp, orig_ctime, vap->va_data_size == 0 ? NAMESPACE_HANDLER_TRUNCATE_OP|NAMESPACE_HANDLER_DELETE_OP : NAMESPACE_HANDLER_TRUNCATE_OP, NULL);
1186
1187 decmpfs_lock_compressed_data(dp, 1);
1188 if (hfs_file_is_compressed(VTOC(vp), 1)) {
1189 error = decmpfs_decompress_file(vp, dp, -1/*vap->va_data_size*/, 0, 1);
1190 if (error != 0) {
1191 decmpfs_unlock_compressed_data(dp, 1);
1192 return error;
1193 }
1194 }
1195 #endif
1196
1197 /* Take truncate lock before taking cnode lock. */
1198 hfs_lock_truncate(VTOC(vp), HFS_EXCLUSIVE_LOCK);
1199
1200 /* Perform the ubc_setsize before taking the cnode lock. */
1201 ubc_setsize(vp, vap->va_data_size);
1202
1203 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) {
1204 hfs_unlock_truncate(VTOC(vp), 0);
1205 #if HFS_COMPRESSION
1206 decmpfs_unlock_compressed_data(dp, 1);
1207 #endif
1208 return (error);
1209 }
1210 cp = VTOC(vp);
1211
1212 error = hfs_truncate(vp, vap->va_data_size, vap->va_vaflags & 0xffff, 1, 0, ap->a_context);
1213
1214 hfs_unlock_truncate(cp, 0);
1215 #if HFS_COMPRESSION
1216 decmpfs_unlock_compressed_data(dp, 1);
1217 #endif
1218 if (error)
1219 goto out;
1220 }
1221 if (cp == NULL) {
1222 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK)))
1223 return (error);
1224 cp = VTOC(vp);
1225 }
1226
1227 /*
1228 * If it is just an access time update request by itself
1229 * we know the request is from kernel level code, and we
1230 * can delay it without being as worried about consistency.
1231 * This change speeds up mmaps, in the rare case that they
1232 * get caught behind a sync.
1233 */
1234
1235 if (vap->va_active == VNODE_ATTR_va_access_time) {
1236 cp->c_touch_acctime=TRUE;
1237 goto out;
1238 }
1239
1240
1241
1242 /*
1243 * Owner/group change request.
1244 * We are guaranteed that the new owner/group is valid and legal.
1245 */
1246 VATTR_SET_SUPPORTED(vap, va_uid);
1247 VATTR_SET_SUPPORTED(vap, va_gid);
1248 nuid = VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : (uid_t)VNOVAL;
1249 ngid = VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : (gid_t)VNOVAL;
1250 if (((nuid != (uid_t)VNOVAL) || (ngid != (gid_t)VNOVAL)) &&
1251 ((error = hfs_chown(vp, nuid, ngid, cred, p)) != 0))
1252 goto out;
1253
1254 /*
1255 * Mode change request.
1256 * We are guaranteed that the mode value is valid and that in
1257 * conjunction with the owner and group, this change is legal.
1258 */
1259 VATTR_SET_SUPPORTED(vap, va_mode);
1260 if (VATTR_IS_ACTIVE(vap, va_mode) &&
1261 ((error = hfs_chmod(vp, (int)vap->va_mode, cred, p)) != 0))
1262 goto out;
1263
1264 /*
1265 * File flags change.
1266 * We are guaranteed that only flags allowed to change given the
1267 * current securelevel are being changed.
1268 */
1269 VATTR_SET_SUPPORTED(vap, va_flags);
1270 if (VATTR_IS_ACTIVE(vap, va_flags)) {
1271 u_int16_t *fdFlags;
1272
1273 #if HFS_COMPRESSION
1274 if ((cp->c_bsdflags ^ vap->va_flags) & UF_COMPRESSED) {
1275 /*
1276 * the UF_COMPRESSED was toggled, so reset our cached compressed state
1277 * but we don't want to actually do the update until we've released the cnode lock down below
1278 * NOTE: turning the flag off doesn't actually decompress the file, so that we can
1279 * turn off the flag and look at the "raw" file for debugging purposes
1280 */
1281 decmpfs_reset_state = 1;
1282 }
1283 #endif
1284
1285 cp->c_bsdflags = vap->va_flags;
1286 cp->c_touch_chgtime = TRUE;
1287
1288 /*
1289 * Mirror the UF_HIDDEN flag to the invisible bit of the Finder Info.
1290 *
1291 * The fdFlags for files and frFlags for folders are both 8 bytes
1292 * into the userInfo (the first 16 bytes of the Finder Info). They
1293 * are both 16-bit fields.
1294 */
1295 fdFlags = (u_int16_t *) &cp->c_finderinfo[8];
1296 if (vap->va_flags & UF_HIDDEN)
1297 *fdFlags |= OSSwapHostToBigConstInt16(kFinderInvisibleMask);
1298 else
1299 *fdFlags &= ~OSSwapHostToBigConstInt16(kFinderInvisibleMask);
1300 }
1301
1302 /*
1303 * Timestamp updates.
1304 */
1305 VATTR_SET_SUPPORTED(vap, va_create_time);
1306 VATTR_SET_SUPPORTED(vap, va_access_time);
1307 VATTR_SET_SUPPORTED(vap, va_modify_time);
1308 VATTR_SET_SUPPORTED(vap, va_backup_time);
1309 VATTR_SET_SUPPORTED(vap, va_change_time);
1310 if (VATTR_IS_ACTIVE(vap, va_create_time) ||
1311 VATTR_IS_ACTIVE(vap, va_access_time) ||
1312 VATTR_IS_ACTIVE(vap, va_modify_time) ||
1313 VATTR_IS_ACTIVE(vap, va_backup_time)) {
1314 if (VATTR_IS_ACTIVE(vap, va_create_time))
1315 cp->c_itime = vap->va_create_time.tv_sec;
1316 if (VATTR_IS_ACTIVE(vap, va_access_time)) {
1317 cp->c_atime = vap->va_access_time.tv_sec;
1318 cp->c_touch_acctime = FALSE;
1319 }
1320 if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
1321 cp->c_mtime = vap->va_modify_time.tv_sec;
1322 cp->c_touch_modtime = FALSE;
1323 cp->c_touch_chgtime = TRUE;
1324
1325 /*
1326 * The utimes system call can reset the modification
1327 * time but it doesn't know about HFS create times.
1328 * So we need to ensure that the creation time is
1329 * always at least as old as the modification time.
1330 */
1331 if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) &&
1332 (cp->c_cnid != kHFSRootFolderID) &&
1333 (cp->c_mtime < cp->c_itime)) {
1334 cp->c_itime = cp->c_mtime;
1335 }
1336 }
1337 if (VATTR_IS_ACTIVE(vap, va_backup_time))
1338 cp->c_btime = vap->va_backup_time.tv_sec;
1339 cp->c_flag |= C_MODIFIED;
1340 }
1341
1342 /*
1343 * Set name encoding.
1344 */
1345 VATTR_SET_SUPPORTED(vap, va_encoding);
1346 if (VATTR_IS_ACTIVE(vap, va_encoding)) {
1347 cp->c_encoding = vap->va_encoding;
1348 hfs_setencodingbits(hfsmp, cp->c_encoding);
1349 }
1350
1351 if ((error = hfs_update(vp, TRUE)) != 0)
1352 goto out;
1353 out:
1354 if (cp) {
1355 /* Purge origin cache for cnode, since caller now has correct link ID for it
1356 * We purge it here since it was acquired for us during lookup, and we no longer need it.
1357 */
1358 if ((cp->c_flag & C_HARDLINK) && (vp->v_type != VDIR)){
1359 hfs_relorigin(cp, 0);
1360 }
1361
1362 hfs_unlock(cp);
1363 #if HFS_COMPRESSION
1364 if (decmpfs_reset_state) {
1365 /*
1366 * we've changed the UF_COMPRESSED flag, so reset the decmpfs state for this cnode
1367 * but don't do it while holding the hfs cnode lock
1368 */
1369 decmpfs_cnode *dp = VTOCMP(vp);
1370 if (!dp) {
1371 /*
1372 * call hfs_lazy_init_decmpfs_cnode() to make sure that the decmpfs_cnode
1373 * is filled in; we need a decmpfs_cnode to prevent decmpfs state changes
1374 * on this file if it's locked
1375 */
1376 dp = hfs_lazy_init_decmpfs_cnode(VTOC(vp));
1377 if (!dp) {
1378 /* failed to allocate a decmpfs_cnode */
1379 return ENOMEM; /* what should this be? */
1380 }
1381 }
1382 decmpfs_cnode_set_vnode_state(dp, FILE_TYPE_UNKNOWN, 0);
1383 }
1384 #endif
1385 }
1386 return (error);
1387 }
1388
1389
1390 /*
1391 * Change the mode on a file.
1392 * cnode must be locked before calling.
1393 */
1394 int
1395 hfs_chmod(struct vnode *vp, int mode, __unused kauth_cred_t cred, __unused struct proc *p)
1396 {
1397 register struct cnode *cp = VTOC(vp);
1398
1399 if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)
1400 return (0);
1401
1402 // Don't allow modification of the journal or journal_info_block
1403 if (hfs_is_journal_file(VTOHFS(vp), cp)) {
1404 return EPERM;
1405 }
1406
1407 #if OVERRIDE_UNKNOWN_PERMISSIONS
1408 if (((unsigned int)vfs_flags(VTOVFS(vp))) & MNT_UNKNOWNPERMISSIONS) {
1409 return (0);
1410 };
1411 #endif
1412 cp->c_mode &= ~ALLPERMS;
1413 cp->c_mode |= (mode & ALLPERMS);
1414 cp->c_touch_chgtime = TRUE;
1415 return (0);
1416 }
1417
1418
1419 int
1420 hfs_write_access(struct vnode *vp, kauth_cred_t cred, struct proc *p, Boolean considerFlags)
1421 {
1422 struct cnode *cp = VTOC(vp);
1423 int retval = 0;
1424 int is_member;
1425
1426 /*
1427 * Disallow write attempts on read-only file systems;
1428 * unless the file is a socket, fifo, or a block or
1429 * character device resident on the file system.
1430 */
1431 switch (vnode_vtype(vp)) {
1432 case VDIR:
1433 case VLNK:
1434 case VREG:
1435 if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY)
1436 return (EROFS);
1437 break;
1438 default:
1439 break;
1440 }
1441
1442 /* If immutable bit set, nobody gets to write it. */
1443 if (considerFlags && (cp->c_bsdflags & IMMUTABLE))
1444 return (EPERM);
1445
1446 /* Otherwise, user id 0 always gets access. */
1447 if (!suser(cred, NULL))
1448 return (0);
1449
1450 /* Otherwise, check the owner. */
1451 if ((retval = hfs_owner_rights(VTOHFS(vp), cp->c_uid, cred, p, false)) == 0)
1452 return ((cp->c_mode & S_IWUSR) == S_IWUSR ? 0 : EACCES);
1453
1454 /* Otherwise, check the groups. */
1455 if (kauth_cred_ismember_gid(cred, cp->c_gid, &is_member) == 0 && is_member) {
1456 return ((cp->c_mode & S_IWGRP) == S_IWGRP ? 0 : EACCES);
1457 }
1458
1459 /* Otherwise, check everyone else. */
1460 return ((cp->c_mode & S_IWOTH) == S_IWOTH ? 0 : EACCES);
1461 }
1462
1463
1464 /*
1465 * Perform chown operation on cnode cp;
1466 * code must be locked prior to call.
1467 */
1468 int
1469 #if !QUOTA
1470 hfs_chown(struct vnode *vp, uid_t uid, gid_t gid, __unused kauth_cred_t cred,
1471 __unused struct proc *p)
1472 #else
1473 hfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
1474 __unused struct proc *p)
1475 #endif
1476 {
1477 register struct cnode *cp = VTOC(vp);
1478 uid_t ouid;
1479 gid_t ogid;
1480 #if QUOTA
1481 int error = 0;
1482 register int i;
1483 int64_t change;
1484 #endif /* QUOTA */
1485
1486 if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)
1487 return (ENOTSUP);
1488
1489 if (((unsigned int)vfs_flags(VTOVFS(vp))) & MNT_UNKNOWNPERMISSIONS)
1490 return (0);
1491
1492 if (uid == (uid_t)VNOVAL)
1493 uid = cp->c_uid;
1494 if (gid == (gid_t)VNOVAL)
1495 gid = cp->c_gid;
1496
1497 #if 0 /* we are guaranteed that this is already the case */
1498 /*
1499 * If we don't own the file, are trying to change the owner
1500 * of the file, or are not a member of the target group,
1501 * the caller must be superuser or the call fails.
1502 */
1503 if ((kauth_cred_getuid(cred) != cp->c_uid || uid != cp->c_uid ||
1504 (gid != cp->c_gid &&
1505 (kauth_cred_ismember_gid(cred, gid, &is_member) || !is_member))) &&
1506 (error = suser(cred, 0)))
1507 return (error);
1508 #endif
1509
1510 ogid = cp->c_gid;
1511 ouid = cp->c_uid;
1512 #if QUOTA
1513 if ((error = hfs_getinoquota(cp)))
1514 return (error);
1515 if (ouid == uid) {
1516 dqrele(cp->c_dquot[USRQUOTA]);
1517 cp->c_dquot[USRQUOTA] = NODQUOT;
1518 }
1519 if (ogid == gid) {
1520 dqrele(cp->c_dquot[GRPQUOTA]);
1521 cp->c_dquot[GRPQUOTA] = NODQUOT;
1522 }
1523
1524 /*
1525 * Eventually need to account for (fake) a block per directory
1526 * if (vnode_isdir(vp))
1527 * change = VTOHFS(vp)->blockSize;
1528 * else
1529 */
1530
1531 change = (int64_t)(cp->c_blocks) * (int64_t)VTOVCB(vp)->blockSize;
1532 (void) hfs_chkdq(cp, -change, cred, CHOWN);
1533 (void) hfs_chkiq(cp, -1, cred, CHOWN);
1534 for (i = 0; i < MAXQUOTAS; i++) {
1535 dqrele(cp->c_dquot[i]);
1536 cp->c_dquot[i] = NODQUOT;
1537 }
1538 #endif /* QUOTA */
1539 cp->c_gid = gid;
1540 cp->c_uid = uid;
1541 #if QUOTA
1542 if ((error = hfs_getinoquota(cp)) == 0) {
1543 if (ouid == uid) {
1544 dqrele(cp->c_dquot[USRQUOTA]);
1545 cp->c_dquot[USRQUOTA] = NODQUOT;
1546 }
1547 if (ogid == gid) {
1548 dqrele(cp->c_dquot[GRPQUOTA]);
1549 cp->c_dquot[GRPQUOTA] = NODQUOT;
1550 }
1551 if ((error = hfs_chkdq(cp, change, cred, CHOWN)) == 0) {
1552 if ((error = hfs_chkiq(cp, 1, cred, CHOWN)) == 0)
1553 goto good;
1554 else
1555 (void) hfs_chkdq(cp, -change, cred, CHOWN|FORCE);
1556 }
1557 for (i = 0; i < MAXQUOTAS; i++) {
1558 dqrele(cp->c_dquot[i]);
1559 cp->c_dquot[i] = NODQUOT;
1560 }
1561 }
1562 cp->c_gid = ogid;
1563 cp->c_uid = ouid;
1564 if (hfs_getinoquota(cp) == 0) {
1565 if (ouid == uid) {
1566 dqrele(cp->c_dquot[USRQUOTA]);
1567 cp->c_dquot[USRQUOTA] = NODQUOT;
1568 }
1569 if (ogid == gid) {
1570 dqrele(cp->c_dquot[GRPQUOTA]);
1571 cp->c_dquot[GRPQUOTA] = NODQUOT;
1572 }
1573 (void) hfs_chkdq(cp, change, cred, FORCE|CHOWN);
1574 (void) hfs_chkiq(cp, 1, cred, FORCE|CHOWN);
1575 (void) hfs_getinoquota(cp);
1576 }
1577 return (error);
1578 good:
1579 if (hfs_getinoquota(cp))
1580 panic("hfs_chown: lost quota");
1581 #endif /* QUOTA */
1582
1583
1584 /*
1585 According to the SUSv3 Standard, chown() shall mark
1586 for update the st_ctime field of the file.
1587 (No exceptions mentioned)
1588 */
1589 cp->c_touch_chgtime = TRUE;
1590 return (0);
1591 }
1592
1593
1594 /*
1595 * The hfs_exchange routine swaps the fork data in two files by
1596 * exchanging some of the information in the cnode. It is used
1597 * to preserve the file ID when updating an existing file, in
1598 * case the file is being tracked through its file ID. Typically
1599 * its used after creating a new file during a safe-save.
1600 */
1601 int
1602 hfs_vnop_exchange(ap)
1603 struct vnop_exchange_args /* {
1604 struct vnode *a_fvp;
1605 struct vnode *a_tvp;
1606 int a_options;
1607 vfs_context_t a_context;
1608 } */ *ap;
1609 {
1610 struct vnode *from_vp = ap->a_fvp;
1611 struct vnode *to_vp = ap->a_tvp;
1612 struct cnode *from_cp;
1613 struct cnode *to_cp;
1614 struct hfsmount *hfsmp;
1615 struct cat_desc tempdesc;
1616 struct cat_attr tempattr;
1617 const unsigned char *from_nameptr;
1618 const unsigned char *to_nameptr;
1619 char from_iname[32];
1620 char to_iname[32];
1621 uint32_t to_flag_special;
1622 uint32_t from_flag_special;
1623 cnid_t from_parid;
1624 cnid_t to_parid;
1625 int lockflags;
1626 int error = 0, started_tr = 0, got_cookie = 0;
1627 cat_cookie_t cookie;
1628 time_t orig_from_ctime, orig_to_ctime;
1629
1630 /* The files must be on the same volume. */
1631 if (vnode_mount(from_vp) != vnode_mount(to_vp))
1632 return (EXDEV);
1633
1634 if (from_vp == to_vp)
1635 return (EINVAL);
1636
1637 orig_from_ctime = VTOC(from_vp)->c_ctime;
1638 orig_to_ctime = VTOC(to_vp)->c_ctime;
1639
1640
1641 #if CONFIG_PROTECT
1642 /*
1643 * Do not allow exchangedata/F_MOVEDATAEXTENTS on data-protected filesystems
1644 * because the EAs will not be swapped. As a result, the persistent keys would not
1645 * match and the files will be garbage.
1646 */
1647 if (cp_fs_protected (vnode_mount(from_vp))) {
1648 return EINVAL;
1649 }
1650 #endif
1651
1652 #if HFS_COMPRESSION
1653 if ( hfs_file_is_compressed(VTOC(from_vp), 0) ) {
1654 if ( 0 != ( error = decmpfs_decompress_file(from_vp, VTOCMP(from_vp), -1, 0, 1) ) ) {
1655 return error;
1656 }
1657 }
1658
1659 if ( hfs_file_is_compressed(VTOC(to_vp), 0) ) {
1660 if ( 0 != ( error = decmpfs_decompress_file(to_vp, VTOCMP(to_vp), -1, 0, 1) ) ) {
1661 return error;
1662 }
1663 }
1664 #endif // HFS_COMPRESSION
1665
1666 /*
1667 * Normally, we want to notify the user handlers about the event,
1668 * except if it's a handler driving the event.
1669 */
1670 if ((ap->a_options & FSOPT_EXCHANGE_DATA_ONLY) == 0) {
1671 check_for_tracked_file(from_vp, orig_from_ctime, NAMESPACE_HANDLER_WRITE_OP, NULL);
1672 check_for_tracked_file(to_vp, orig_to_ctime, NAMESPACE_HANDLER_WRITE_OP, NULL);
1673 } else {
1674 /*
1675 * We're doing a data-swap.
1676 * Take the truncate lock/cnode lock, then verify there are no mmap references.
1677 * Issue a hfs_filedone to flush out all of the remaining state for this file.
1678 * Allow the rest of the codeflow to re-acquire the cnode locks in order.
1679 */
1680
1681 hfs_lock_truncate (VTOC(from_vp), HFS_SHARED_LOCK);
1682
1683 if ((error = hfs_lock(VTOC(from_vp), HFS_EXCLUSIVE_LOCK))) {
1684 hfs_unlock_truncate (VTOC(from_vp), 0);
1685 return error;
1686 }
1687
1688 /* Verify the source file is not in use by anyone besides us (including mmap refs) */
1689 if (vnode_isinuse(from_vp, 1)) {
1690 error = EBUSY;
1691 hfs_unlock(VTOC(from_vp));
1692 hfs_unlock_truncate (VTOC(from_vp), 0);
1693 return error;
1694 }
1695
1696 /* Flush out the data in the source file */
1697 VTOC(from_vp)->c_flag |= C_SWAPINPROGRESS;
1698 error = hfs_filedone (from_vp, ap->a_context);
1699 VTOC(from_vp)->c_flag &= ~C_SWAPINPROGRESS;
1700 hfs_unlock(VTOC(from_vp));
1701 hfs_unlock_truncate(VTOC(from_vp), 0);
1702
1703 if (error) {
1704 return error;
1705 }
1706 }
1707
1708 if ((error = hfs_lockpair(VTOC(from_vp), VTOC(to_vp), HFS_EXCLUSIVE_LOCK)))
1709 return (error);
1710
1711 from_cp = VTOC(from_vp);
1712 to_cp = VTOC(to_vp);
1713 hfsmp = VTOHFS(from_vp);
1714
1715 /* Resource forks cannot be exchanged. */
1716 if (VNODE_IS_RSRC(from_vp) || VNODE_IS_RSRC(to_vp)) {
1717 error = EINVAL;
1718 goto exit;
1719 }
1720
1721 // Don't allow modification of the journal or journal_info_block
1722 if (hfs_is_journal_file(hfsmp, from_cp) ||
1723 hfs_is_journal_file(hfsmp, to_cp)) {
1724 error = EPERM;
1725 goto exit;
1726 }
1727
1728 /*
1729 * Ok, now that all of the pre-flighting is done, call the underlying
1730 * function if needed.
1731 */
1732 if (ap->a_options & FSOPT_EXCHANGE_DATA_ONLY) {
1733 error = hfs_movedata(from_vp, to_vp);
1734 goto exit;
1735 }
1736
1737
1738 if ((error = hfs_start_transaction(hfsmp)) != 0) {
1739 goto exit;
1740 }
1741 started_tr = 1;
1742
1743 /*
1744 * Reserve some space in the Catalog file.
1745 */
1746 if ((error = cat_preflight(hfsmp, CAT_EXCHANGE, &cookie, vfs_context_proc(ap->a_context)))) {
1747 goto exit;
1748 }
1749 got_cookie = 1;
1750
1751 /* The backend code always tries to delete the virtual
1752 * extent id for exchanging files so we need to lock
1753 * the extents b-tree.
1754 */
1755 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_EXTENTS | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
1756
1757 /* Account for the location of the catalog objects. */
1758 if (from_cp->c_flag & C_HARDLINK) {
1759 MAKE_INODE_NAME(from_iname, sizeof(from_iname),
1760 from_cp->c_attr.ca_linkref);
1761 from_nameptr = (unsigned char *)from_iname;
1762 from_parid = hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid;
1763 from_cp->c_hint = 0;
1764 } else {
1765 from_nameptr = from_cp->c_desc.cd_nameptr;
1766 from_parid = from_cp->c_parentcnid;
1767 }
1768 if (to_cp->c_flag & C_HARDLINK) {
1769 MAKE_INODE_NAME(to_iname, sizeof(to_iname),
1770 to_cp->c_attr.ca_linkref);
1771 to_nameptr = (unsigned char *)to_iname;
1772 to_parid = hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid;
1773 to_cp->c_hint = 0;
1774 } else {
1775 to_nameptr = to_cp->c_desc.cd_nameptr;
1776 to_parid = to_cp->c_parentcnid;
1777 }
1778
1779 /* Do the exchange */
1780 error = ExchangeFileIDs(hfsmp, from_nameptr, to_nameptr, from_parid,
1781 to_parid, from_cp->c_hint, to_cp->c_hint);
1782 hfs_systemfile_unlock(hfsmp, lockflags);
1783
1784 /*
1785 * Note that we don't need to exchange any extended attributes
1786 * since the attributes are keyed by file ID.
1787 */
1788
1789 if (error != E_NONE) {
1790 error = MacToVFSError(error);
1791 goto exit;
1792 }
1793
1794 /* Purge the vnodes from the name cache */
1795 if (from_vp)
1796 cache_purge(from_vp);
1797 if (to_vp)
1798 cache_purge(to_vp);
1799
1800 /* Save a copy of from attributes before swapping. */
1801 bcopy(&from_cp->c_desc, &tempdesc, sizeof(struct cat_desc));
1802 bcopy(&from_cp->c_attr, &tempattr, sizeof(struct cat_attr));
1803
1804 /* Save whether or not each cnode is a hardlink or has EAs */
1805 from_flag_special = from_cp->c_flag & (C_HARDLINK | C_HASXATTRS);
1806 to_flag_special = to_cp->c_flag & (C_HARDLINK | C_HASXATTRS);
1807
1808 /* Drop the special bits from each cnode */
1809 from_cp->c_flag &= ~(C_HARDLINK | C_HASXATTRS);
1810 to_cp->c_flag &= ~(C_HARDLINK | C_HASXATTRS);
1811
1812 /*
1813 * Swap the descriptors and all non-fork related attributes.
1814 * (except the modify date)
1815 */
1816 bcopy(&to_cp->c_desc, &from_cp->c_desc, sizeof(struct cat_desc));
1817
1818 from_cp->c_hint = 0;
1819 /*
1820 * If 'to' was a hardlink, then we copied over its link ID/CNID/(namespace ID)
1821 * when we bcopy'd the descriptor above. However, we need to be careful
1822 * when setting up the fileID below, because we cannot assume that the
1823 * file ID is the same as the CNID if either one was a hardlink.
1824 * The file ID is stored in the c_attr as the ca_fileid. So it needs
1825 * to be pulled explicitly; we cannot just use the CNID.
1826 */
1827 from_cp->c_fileid = to_cp->c_attr.ca_fileid;
1828
1829 from_cp->c_itime = to_cp->c_itime;
1830 from_cp->c_btime = to_cp->c_btime;
1831 from_cp->c_atime = to_cp->c_atime;
1832 from_cp->c_ctime = to_cp->c_ctime;
1833 from_cp->c_gid = to_cp->c_gid;
1834 from_cp->c_uid = to_cp->c_uid;
1835 from_cp->c_bsdflags = to_cp->c_bsdflags;
1836 from_cp->c_mode = to_cp->c_mode;
1837 from_cp->c_linkcount = to_cp->c_linkcount;
1838 from_cp->c_attr.ca_linkref = to_cp->c_attr.ca_linkref;
1839 from_cp->c_attr.ca_firstlink = to_cp->c_attr.ca_firstlink;
1840
1841 /*
1842 * The cnode flags need to stay with the cnode and not get transferred
1843 * over along with everything else because they describe the content; they are
1844 * not attributes that reflect changes specific to the file ID. In general,
1845 * fields that are tied to the file ID are the ones that will move.
1846 *
1847 * This reflects the fact that the file may have borrowed blocks, dirty metadata,
1848 * or other extents, which may not yet have been written to the catalog. If
1849 * they were, they would have been transferred above in the ExchangeFileIDs call above...
1850 *
1851 * The flags that are special are:
1852 * C_HARDLINK, C_HASXATTRS
1853 *
1854 * These flags move with the item and file ID in the namespace since their
1855 * state is tied to that of the file ID.
1856 *
1857 * So to transfer the flags, we have to take the following steps
1858 * 1) Store in a localvar whether or not the special bits are set.
1859 * 2) Drop the special bits from the current flags
1860 * 3) swap the special flag bits to their destination
1861 */
1862 from_cp->c_flag |= to_flag_special;
1863
1864 from_cp->c_attr.ca_recflags = to_cp->c_attr.ca_recflags;
1865 bcopy(to_cp->c_finderinfo, from_cp->c_finderinfo, 32);
1866
1867 bcopy(&tempdesc, &to_cp->c_desc, sizeof(struct cat_desc));
1868 to_cp->c_hint = 0;
1869 /*
1870 * Pull the file ID from the tempattr we copied above. We can't assume
1871 * it is the same as the CNID.
1872 */
1873 to_cp->c_fileid = tempattr.ca_fileid;
1874 to_cp->c_itime = tempattr.ca_itime;
1875 to_cp->c_btime = tempattr.ca_btime;
1876 to_cp->c_atime = tempattr.ca_atime;
1877 to_cp->c_ctime = tempattr.ca_ctime;
1878 to_cp->c_gid = tempattr.ca_gid;
1879 to_cp->c_uid = tempattr.ca_uid;
1880 to_cp->c_bsdflags = tempattr.ca_flags;
1881 to_cp->c_mode = tempattr.ca_mode;
1882 to_cp->c_linkcount = tempattr.ca_linkcount;
1883 to_cp->c_attr.ca_linkref = tempattr.ca_linkref;
1884 to_cp->c_attr.ca_firstlink = tempattr.ca_firstlink;
1885
1886 /*
1887 * Only OR in the "from" flags into our cnode flags below.
1888 * Leave the rest of the flags alone.
1889 */
1890 to_cp->c_flag |= from_flag_special;
1891
1892 to_cp->c_attr.ca_recflags = tempattr.ca_recflags;
1893 bcopy(tempattr.ca_finderinfo, to_cp->c_finderinfo, 32);
1894
1895 /* Rehash the cnodes using their new file IDs */
1896 hfs_chash_rehash(hfsmp, from_cp, to_cp);
1897
1898 /*
1899 * When a file moves out of "Cleanup At Startup"
1900 * we can drop its NODUMP status.
1901 */
1902 if ((from_cp->c_bsdflags & UF_NODUMP) &&
1903 (from_cp->c_parentcnid != to_cp->c_parentcnid)) {
1904 from_cp->c_bsdflags &= ~UF_NODUMP;
1905 from_cp->c_touch_chgtime = TRUE;
1906 }
1907 if ((to_cp->c_bsdflags & UF_NODUMP) &&
1908 (to_cp->c_parentcnid != from_cp->c_parentcnid)) {
1909 to_cp->c_bsdflags &= ~UF_NODUMP;
1910 to_cp->c_touch_chgtime = TRUE;
1911 }
1912
1913 exit:
1914 if (got_cookie) {
1915 cat_postflight(hfsmp, &cookie, vfs_context_proc(ap->a_context));
1916 }
1917 if (started_tr) {
1918 hfs_end_transaction(hfsmp);
1919 }
1920
1921 hfs_unlockpair(from_cp, to_cp);
1922 return (error);
1923 }
1924
1925 int
1926 hfs_vnop_mmap(struct vnop_mmap_args *ap)
1927 {
1928 struct vnode *vp = ap->a_vp;
1929 int error;
1930
1931 if (VNODE_IS_RSRC(vp)) {
1932 /* allow pageins of the resource fork */
1933 } else {
1934 int compressed = hfs_file_is_compressed(VTOC(vp), 1); /* 1 == don't take the cnode lock */
1935 time_t orig_ctime = VTOC(vp)->c_ctime;
1936
1937 if (!compressed && (VTOC(vp)->c_bsdflags & UF_COMPRESSED)) {
1938 error = check_for_dataless_file(vp, NAMESPACE_HANDLER_READ_OP);
1939 if (error != 0) {
1940 return error;
1941 }
1942 }
1943
1944 if (ap->a_fflags & PROT_WRITE) {
1945 check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_WRITE_OP, NULL);
1946 }
1947 }
1948
1949 //
1950 // NOTE: we return ENOTSUP because we want the cluster layer
1951 // to actually do all the real work.
1952 //
1953 return (ENOTSUP);
1954 }
1955
1956 /*
1957 * hfs_movedata
1958 *
1959 * This is a non-symmetric variant of exchangedata. In this function,
1960 * the contents of the fork in from_vp are moved to the fork
1961 * specified by to_vp.
1962 *
1963 * The cnodes pointed to by 'from_vp' and 'to_vp' must be locked.
1964 *
1965 * The vnode pointed to by 'to_vp' *must* be empty prior to invoking this function.
1966 * We impose this restriction because we may not be able to fully delete the entire
1967 * file's contents in a single transaction, particularly if it has a lot of extents.
1968 * In the normal file deletion codepath, the file is screened for two conditions:
1969 * 1) bigger than 400MB, and 2) more than 8 extents. If so, the file is relocated to
1970 * the hidden directory and the deletion is broken up into multiple truncates. We can't
1971 * do that here because both files need to exist in the namespace. The main reason this
1972 * is imposed is that we may have to touch a whole lot of bitmap blocks if there are
1973 * many extents.
1974 *
1975 * Any data written to 'from_vp' after this call completes is not guaranteed
1976 * to be moved.
1977 *
1978 * Arguments:
1979 * vnode from_vp: source file
1980 * vnode to_vp: destination file; must be empty
1981 *
1982 * Returns:
1983 * EFBIG - Destination file was not empty
1984 * 0 - success
1985 *
1986 *
1987 */
1988 int hfs_movedata (struct vnode *from_vp, struct vnode *to_vp) {
1989
1990 struct cnode *from_cp;
1991 struct cnode *to_cp;
1992 struct hfsmount *hfsmp = NULL;
1993 int error = 0;
1994 int started_tr = 0;
1995 int lockflags = 0;
1996 int overflow_blocks;
1997 int rsrc = 0;
1998
1999
2000 /* Get the HFS pointers */
2001 from_cp = VTOC(from_vp);
2002 to_cp = VTOC(to_vp);
2003 hfsmp = VTOHFS(from_vp);
2004
2005 /* Verify that neither source/dest file is open-unlinked */
2006 if (from_cp->c_flag & (C_DELETED | C_NOEXISTS)) {
2007 error = EBUSY;
2008 goto movedata_exit;
2009 }
2010
2011 if (to_cp->c_flag & (C_DELETED | C_NOEXISTS)) {
2012 error = EBUSY;
2013 goto movedata_exit;
2014 }
2015
2016 /*
2017 * Verify the source file is not in use by anyone besides us.
2018 *
2019 * This function is typically invoked by a namespace handler
2020 * process responding to a temporarily stalled system call.
2021 * The FD that it is working off of is opened O_EVTONLY, so
2022 * it really has no active usecounts (the kusecount from O_EVTONLY
2023 * is subtracted from the total usecounts).
2024 *
2025 * As a result, we shouldn't have any active usecounts against
2026 * this vnode when we go to check it below.
2027 */
2028 if (vnode_isinuse(from_vp, 0)) {
2029 error = EBUSY;
2030 goto movedata_exit;
2031 }
2032
2033 if (from_cp->c_rsrc_vp == from_vp) {
2034 rsrc = 1;
2035 }
2036
2037 /*
2038 * We assume that the destination file is already empty.
2039 * Verify that it is.
2040 */
2041 if (rsrc) {
2042 if (to_cp->c_rsrcfork->ff_size > 0) {
2043 error = EFBIG;
2044 goto movedata_exit;
2045 }
2046 }
2047 else {
2048 if (to_cp->c_datafork->ff_size > 0) {
2049 error = EFBIG;
2050 goto movedata_exit;
2051 }
2052 }
2053
2054 /* If the source has the rsrc open, make sure the destination is also the rsrc */
2055 if (rsrc) {
2056 if (to_vp != to_cp->c_rsrc_vp) {
2057 error = EINVAL;
2058 goto movedata_exit;
2059 }
2060 }
2061 else {
2062 /* Verify that both forks are data forks */
2063 if (to_vp != to_cp->c_vp) {
2064 error = EINVAL;
2065 goto movedata_exit;
2066 }
2067 }
2068
2069 /*
2070 * See if the source file has overflow extents. If it doesn't, we don't
2071 * need to call into MoveData, and the catalog will be enough.
2072 */
2073 if (rsrc) {
2074 overflow_blocks = overflow_extents(from_cp->c_rsrcfork);
2075 }
2076 else {
2077 overflow_blocks = overflow_extents(from_cp->c_datafork);
2078 }
2079
2080 if ((error = hfs_start_transaction (hfsmp)) != 0) {
2081 goto movedata_exit;
2082 }
2083 started_tr = 1;
2084
2085 /* Lock the system files: catalog, extents, attributes */
2086 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_EXTENTS | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
2087
2088 /* Copy over any catalog allocation data into the new spot. */
2089 if (rsrc) {
2090 if ((error = hfs_move_fork (from_cp->c_rsrcfork, from_cp, to_cp->c_rsrcfork, to_cp))){
2091 hfs_systemfile_unlock(hfsmp, lockflags);
2092 goto movedata_exit;
2093 }
2094 }
2095 else {
2096 if ((error = hfs_move_fork (from_cp->c_datafork, from_cp, to_cp->c_datafork, to_cp))) {
2097 hfs_systemfile_unlock(hfsmp, lockflags);
2098 goto movedata_exit;
2099 }
2100 }
2101
2102 /*
2103 * Note that because all we're doing is moving the extents around, we can
2104 * probably do this in a single transaction: Each extent record (group of 8)
2105 * is 64 bytes. A extent overflow B-Tree node is typically 4k. This means
2106 * each node can hold roughly ~60 extent records == (480 extents).
2107 *
2108 * If a file was massively fragmented and had 20k extents, this means we'd
2109 * roughly touch 20k/480 == 41 to 42 nodes, plus the index nodes, for half
2110 * of the operation. (inserting or deleting). So if we're manipulating 80-100
2111 * nodes, this is basically 320k of data to write to the journal in
2112 * a bad case.
2113 */
2114 if (overflow_blocks != 0) {
2115 if (rsrc) {
2116 error = MoveData(hfsmp, from_cp->c_cnid, to_cp->c_cnid, 1);
2117 }
2118 else {
2119 error = MoveData (hfsmp, from_cp->c_cnid, to_cp->c_cnid, 0);
2120 }
2121 }
2122
2123 if (error) {
2124 /* Reverse the operation. Copy the fork data back into the source */
2125 if (rsrc) {
2126 hfs_move_fork (to_cp->c_rsrcfork, to_cp, from_cp->c_rsrcfork, from_cp);
2127 }
2128 else {
2129 hfs_move_fork (to_cp->c_datafork, to_cp, from_cp->c_datafork, from_cp);
2130 }
2131 }
2132 else {
2133 struct cat_fork *src_data = NULL;
2134 struct cat_fork *src_rsrc = NULL;
2135 struct cat_fork *dst_data = NULL;
2136 struct cat_fork *dst_rsrc = NULL;
2137
2138 /* Touch the times*/
2139 to_cp->c_touch_acctime = TRUE;
2140 to_cp->c_touch_chgtime = TRUE;
2141 to_cp->c_touch_modtime = TRUE;
2142
2143 from_cp->c_touch_acctime = TRUE;
2144 from_cp->c_touch_chgtime = TRUE;
2145 from_cp->c_touch_modtime = TRUE;
2146
2147 hfs_touchtimes(hfsmp, to_cp);
2148 hfs_touchtimes(hfsmp, from_cp);
2149
2150 if (from_cp->c_datafork) {
2151 src_data = &from_cp->c_datafork->ff_data;
2152 }
2153 if (from_cp->c_rsrcfork) {
2154 src_rsrc = &from_cp->c_rsrcfork->ff_data;
2155 }
2156
2157 if (to_cp->c_datafork) {
2158 dst_data = &to_cp->c_datafork->ff_data;
2159 }
2160 if (to_cp->c_rsrcfork) {
2161 dst_rsrc = &to_cp->c_rsrcfork->ff_data;
2162 }
2163
2164 /* Update the catalog nodes */
2165 (void) cat_update(hfsmp, &from_cp->c_desc, &from_cp->c_attr,
2166 src_data, src_rsrc);
2167
2168 (void) cat_update(hfsmp, &to_cp->c_desc, &to_cp->c_attr,
2169 dst_data, dst_rsrc);
2170
2171 }
2172 /* unlock the system files */
2173 hfs_systemfile_unlock(hfsmp, lockflags);
2174
2175
2176 movedata_exit:
2177 if (started_tr) {
2178 hfs_end_transaction(hfsmp);
2179 }
2180
2181 return error;
2182
2183 }
2184
2185 /*
2186 * Copy all of the catalog and runtime data in srcfork to dstfork.
2187 *
2188 * This allows us to maintain the invalid ranges across the movedata operation so
2189 * we don't need to force all of the pending IO right now. In addition, we move all
2190 * non overflow-extent extents into the destination here.
2191 */
2192 static int hfs_move_fork (struct filefork *srcfork, struct cnode *src_cp,
2193 struct filefork *dstfork, struct cnode *dst_cp) {
2194 struct rl_entry *invalid_range;
2195 int size = sizeof(struct HFSPlusExtentDescriptor);
2196 size = size * kHFSPlusExtentDensity;
2197
2198 /* If the dstfork has any invalid ranges, bail out */
2199 invalid_range = TAILQ_FIRST(&dstfork->ff_invalidranges);
2200 if (invalid_range != NULL) {
2201 return EFBIG;
2202 }
2203
2204 if (dstfork->ff_data.cf_size != 0 || dstfork->ff_data.cf_new_size != 0) {
2205 return EFBIG;
2206 }
2207
2208 /* First copy the invalid ranges */
2209 while ((invalid_range = TAILQ_FIRST(&srcfork->ff_invalidranges))) {
2210 off_t start = invalid_range->rl_start;
2211 off_t end = invalid_range->rl_end;
2212
2213 /* Remove it from the srcfork and add it to dstfork */
2214 rl_remove(start, end, &srcfork->ff_invalidranges);
2215 rl_add(start, end, &dstfork->ff_invalidranges);
2216 }
2217
2218 /*
2219 * Ignore the ff_union. We don't move symlinks or system files.
2220 * Now copy the in-catalog extent information
2221 */
2222 dstfork->ff_data.cf_size = srcfork->ff_data.cf_size;
2223 dstfork->ff_data.cf_new_size = srcfork->ff_data.cf_new_size;
2224 dstfork->ff_data.cf_vblocks = srcfork->ff_data.cf_vblocks;
2225 dstfork->ff_data.cf_blocks = srcfork->ff_data.cf_blocks;
2226
2227 /* just memcpy the whole array of extents to the new location. */
2228 memcpy (dstfork->ff_data.cf_extents, srcfork->ff_data.cf_extents, size);
2229
2230 /*
2231 * Copy the cnode attribute data.
2232 *
2233 */
2234 src_cp->c_blocks -= srcfork->ff_data.cf_vblocks;
2235 src_cp->c_blocks -= srcfork->ff_data.cf_blocks;
2236
2237 dst_cp->c_blocks += srcfork->ff_data.cf_vblocks;
2238 dst_cp->c_blocks += srcfork->ff_data.cf_blocks;
2239
2240 /* Now delete the entries in the source fork */
2241 srcfork->ff_data.cf_size = 0;
2242 srcfork->ff_data.cf_new_size = 0;
2243 srcfork->ff_data.cf_union.cfu_bytesread = 0;
2244 srcfork->ff_data.cf_vblocks = 0;
2245 srcfork->ff_data.cf_blocks = 0;
2246
2247 /* Zero out the old extents */
2248 bzero (srcfork->ff_data.cf_extents, size);
2249 return 0;
2250 }
2251
2252
2253 /*
2254 * cnode must be locked
2255 */
2256 int
2257 hfs_fsync(struct vnode *vp, int waitfor, int fullsync, struct proc *p)
2258 {
2259 struct cnode *cp = VTOC(vp);
2260 struct filefork *fp = NULL;
2261 int retval = 0;
2262 struct hfsmount *hfsmp = VTOHFS(vp);
2263 struct rl_entry *invalid_range;
2264 struct timeval tv;
2265 int waitdata; /* attributes necessary for data retrieval */
2266 int wait; /* all other attributes (e.g. atime, etc.) */
2267 int lockflag;
2268 int took_trunc_lock = 0;
2269 int locked_buffers = 0;
2270
2271 /*
2272 * Applications which only care about data integrity rather than full
2273 * file integrity may opt out of (delay) expensive metadata update
2274 * operations as a performance optimization.
2275 */
2276 wait = (waitfor == MNT_WAIT);
2277 waitdata = (waitfor == MNT_DWAIT) | wait;
2278 if (always_do_fullfsync)
2279 fullsync = 1;
2280
2281 /* HFS directories don't have any data blocks. */
2282 if (vnode_isdir(vp))
2283 goto metasync;
2284 fp = VTOF(vp);
2285
2286 /*
2287 * For system files flush the B-tree header and
2288 * for regular files write out any clusters
2289 */
2290 if (vnode_issystem(vp)) {
2291 if (VTOF(vp)->fcbBTCBPtr != NULL) {
2292 // XXXdbg
2293 if (hfsmp->jnl == NULL) {
2294 BTFlushPath(VTOF(vp));
2295 }
2296 }
2297 } else if (UBCINFOEXISTS(vp)) {
2298 hfs_unlock(cp);
2299 hfs_lock_truncate(cp, HFS_SHARED_LOCK);
2300 took_trunc_lock = 1;
2301
2302 if (fp->ff_unallocblocks != 0) {
2303 hfs_unlock_truncate(cp, 0);
2304
2305 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK);
2306 }
2307 /* Don't hold cnode lock when calling into cluster layer. */
2308 (void) cluster_push(vp, waitdata ? IO_SYNC : 0);
2309
2310 hfs_lock(cp, HFS_FORCE_LOCK);
2311 }
2312 /*
2313 * When MNT_WAIT is requested and the zero fill timeout
2314 * has expired then we must explicitly zero out any areas
2315 * that are currently marked invalid (holes).
2316 *
2317 * Files with NODUMP can bypass zero filling here.
2318 */
2319 if (fp && (((cp->c_flag & C_ALWAYS_ZEROFILL) && !TAILQ_EMPTY(&fp->ff_invalidranges)) ||
2320 ((wait || (cp->c_flag & C_ZFWANTSYNC)) &&
2321 ((cp->c_bsdflags & UF_NODUMP) == 0) &&
2322 UBCINFOEXISTS(vp) && (vnode_issystem(vp) ==0) &&
2323 cp->c_zftimeout != 0))) {
2324
2325 microuptime(&tv);
2326 if ((cp->c_flag & C_ALWAYS_ZEROFILL) == 0 && !fullsync && tv.tv_sec < (long)cp->c_zftimeout) {
2327 /* Remember that a force sync was requested. */
2328 cp->c_flag |= C_ZFWANTSYNC;
2329 goto datasync;
2330 }
2331 if (!TAILQ_EMPTY(&fp->ff_invalidranges)) {
2332 if (!took_trunc_lock || (cp->c_truncatelockowner == HFS_SHARED_OWNER)) {
2333 hfs_unlock(cp);
2334 if (took_trunc_lock) {
2335 hfs_unlock_truncate(cp, 0);
2336 }
2337 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK);
2338 hfs_lock(cp, HFS_FORCE_LOCK);
2339 took_trunc_lock = 1;
2340 }
2341 while ((invalid_range = TAILQ_FIRST(&fp->ff_invalidranges))) {
2342 off_t start = invalid_range->rl_start;
2343 off_t end = invalid_range->rl_end;
2344
2345 /* The range about to be written must be validated
2346 * first, so that VNOP_BLOCKMAP() will return the
2347 * appropriate mapping for the cluster code:
2348 */
2349 rl_remove(start, end, &fp->ff_invalidranges);
2350
2351 /* Don't hold cnode lock when calling into cluster layer. */
2352 hfs_unlock(cp);
2353 (void) cluster_write(vp, (struct uio *) 0,
2354 fp->ff_size, end + 1, start, (off_t)0,
2355 IO_HEADZEROFILL | IO_NOZERODIRTY | IO_NOCACHE);
2356 hfs_lock(cp, HFS_FORCE_LOCK);
2357 cp->c_flag |= C_MODIFIED;
2358 }
2359 hfs_unlock(cp);
2360 (void) cluster_push(vp, waitdata ? IO_SYNC : 0);
2361 hfs_lock(cp, HFS_FORCE_LOCK);
2362 }
2363 cp->c_flag &= ~C_ZFWANTSYNC;
2364 cp->c_zftimeout = 0;
2365 }
2366 datasync:
2367 if (took_trunc_lock) {
2368 hfs_unlock_truncate(cp, 0);
2369 took_trunc_lock = 0;
2370 }
2371 /*
2372 * if we have a journal and if journal_active() returns != 0 then the
2373 * we shouldn't do anything to a locked block (because it is part
2374 * of a transaction). otherwise we'll just go through the normal
2375 * code path and flush the buffer. note journal_active() can return
2376 * -1 if the journal is invalid -- however we still need to skip any
2377 * locked blocks as they get cleaned up when we finish the transaction
2378 * or close the journal.
2379 */
2380 // if (hfsmp->jnl && journal_active(hfsmp->jnl) >= 0)
2381 if (hfsmp->jnl)
2382 lockflag = BUF_SKIP_LOCKED;
2383 else
2384 lockflag = 0;
2385
2386 /*
2387 * Flush all dirty buffers associated with a vnode.
2388 * Record how many of them were dirty AND locked (if necessary).
2389 */
2390 locked_buffers = buf_flushdirtyblks_skipinfo(vp, waitdata, lockflag, "hfs_fsync");
2391 if ((lockflag & BUF_SKIP_LOCKED) && (locked_buffers) && (vnode_vtype(vp) == VLNK)) {
2392 /*
2393 * If there are dirty symlink buffers, then we may need to take action
2394 * to prevent issues later on if we are journaled. If we're fsyncing a
2395 * symlink vnode then we are in one of three cases:
2396 *
2397 * 1) automatic sync has fired. In this case, we don't want the behavior to change.
2398 *
2399 * 2) Someone has opened the FD for the symlink (not what it points to)
2400 * and has issued an fsync against it. This should be rare, and we don't
2401 * want the behavior to change.
2402 *
2403 * 3) We are being called by a vclean which is trying to reclaim this
2404 * symlink vnode. If this is the case, then allowing this fsync to
2405 * proceed WITHOUT flushing the journal could result in the vclean
2406 * invalidating the buffer's blocks before the journal transaction is
2407 * written to disk. To prevent this, we force a journal flush
2408 * if the vnode is in the middle of a recycle (VL_TERMINATE or VL_DEAD is set).
2409 */
2410 if (vnode_isrecycled(vp)) {
2411 fullsync = 1;
2412 }
2413 }
2414
2415 metasync:
2416 if (vnode_isreg(vp) && vnode_issystem(vp)) {
2417 if (VTOF(vp)->fcbBTCBPtr != NULL) {
2418 microuptime(&tv);
2419 BTSetLastSync(VTOF(vp), tv.tv_sec);
2420 }
2421 cp->c_touch_acctime = FALSE;
2422 cp->c_touch_chgtime = FALSE;
2423 cp->c_touch_modtime = FALSE;
2424 } else if ( !(vp->v_flag & VSWAP) ) /* User file */ {
2425 retval = hfs_update(vp, wait);
2426
2427 /*
2428 * When MNT_WAIT is requested push out the catalog record for
2429 * this file. If they asked for a full fsync, we can skip this
2430 * because the journal_flush or hfs_metasync_all will push out
2431 * all of the metadata changes.
2432 */
2433 if ((retval == 0) && wait && !fullsync && cp->c_hint &&
2434 !ISSET(cp->c_flag, C_DELETED | C_NOEXISTS)) {
2435 hfs_metasync(VTOHFS(vp), (daddr64_t)cp->c_hint, p);
2436 }
2437
2438 /*
2439 * If this was a full fsync, make sure all metadata
2440 * changes get to stable storage.
2441 */
2442 if (fullsync) {
2443 if (hfsmp->jnl) {
2444 hfs_journal_flush(hfsmp, FALSE);
2445
2446 if (journal_uses_fua(hfsmp->jnl)) {
2447 /*
2448 * the journal_flush did NOT issue a sync track cache command,
2449 * and the fullsync indicates we are supposed to flush all cached
2450 * data to the media, so issue the sync track cache command
2451 * explicitly
2452 */
2453 VNOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE, NULL, FWRITE, NULL);
2454 }
2455 } else {
2456 retval = hfs_metasync_all(hfsmp);
2457 /* XXX need to pass context! */
2458 VNOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE, NULL, FWRITE, NULL);
2459 }
2460 }
2461 }
2462
2463 return (retval);
2464 }
2465
2466
2467 /* Sync an hfs catalog b-tree node */
2468 int
2469 hfs_metasync(struct hfsmount *hfsmp, daddr64_t node, __unused struct proc *p)
2470 {
2471 vnode_t vp;
2472 buf_t bp;
2473 int lockflags;
2474
2475 vp = HFSTOVCB(hfsmp)->catalogRefNum;
2476
2477 // XXXdbg - don't need to do this on a journaled volume
2478 if (hfsmp->jnl) {
2479 return 0;
2480 }
2481
2482 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
2483 /*
2484 * Look for a matching node that has been delayed
2485 * but is not part of a set (B_LOCKED).
2486 *
2487 * BLK_ONLYVALID causes buf_getblk to return a
2488 * buf_t for the daddr64_t specified only if it's
2489 * currently resident in the cache... the size
2490 * parameter to buf_getblk is ignored when this flag
2491 * is set
2492 */
2493 bp = buf_getblk(vp, node, 0, 0, 0, BLK_META | BLK_ONLYVALID);
2494
2495 if (bp) {
2496 if ((buf_flags(bp) & (B_LOCKED | B_DELWRI)) == B_DELWRI)
2497 (void) VNOP_BWRITE(bp);
2498 else
2499 buf_brelse(bp);
2500 }
2501
2502 hfs_systemfile_unlock(hfsmp, lockflags);
2503
2504 return (0);
2505 }
2506
2507
2508 /*
2509 * Sync all hfs B-trees. Use this instead of journal_flush for a volume
2510 * without a journal. Note that the volume bitmap does not get written;
2511 * we rely on fsck_hfs to fix that up (which it can do without any loss
2512 * of data).
2513 */
2514 int
2515 hfs_metasync_all(struct hfsmount *hfsmp)
2516 {
2517 int lockflags;
2518
2519 /* Lock all of the B-trees so we get a mutually consistent state */
2520 lockflags = hfs_systemfile_lock(hfsmp,
2521 SFL_CATALOG|SFL_EXTENTS|SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
2522
2523 /* Sync each of the B-trees */
2524 if (hfsmp->hfs_catalog_vp)
2525 hfs_btsync(hfsmp->hfs_catalog_vp, 0);
2526 if (hfsmp->hfs_extents_vp)
2527 hfs_btsync(hfsmp->hfs_extents_vp, 0);
2528 if (hfsmp->hfs_attribute_vp)
2529 hfs_btsync(hfsmp->hfs_attribute_vp, 0);
2530
2531 /* Wait for all of the writes to complete */
2532 if (hfsmp->hfs_catalog_vp)
2533 vnode_waitforwrites(hfsmp->hfs_catalog_vp, 0, 0, 0, "hfs_metasync_all");
2534 if (hfsmp->hfs_extents_vp)
2535 vnode_waitforwrites(hfsmp->hfs_extents_vp, 0, 0, 0, "hfs_metasync_all");
2536 if (hfsmp->hfs_attribute_vp)
2537 vnode_waitforwrites(hfsmp->hfs_attribute_vp, 0, 0, 0, "hfs_metasync_all");
2538
2539 hfs_systemfile_unlock(hfsmp, lockflags);
2540
2541 return 0;
2542 }
2543
2544
2545 /*ARGSUSED 1*/
2546 static int
2547 hfs_btsync_callback(struct buf *bp, __unused void *dummy)
2548 {
2549 buf_clearflags(bp, B_LOCKED);
2550 (void) buf_bawrite(bp);
2551
2552 return(BUF_CLAIMED);
2553 }
2554
2555
2556 int
2557 hfs_btsync(struct vnode *vp, int sync_transaction)
2558 {
2559 struct cnode *cp = VTOC(vp);
2560 struct timeval tv;
2561 int flags = 0;
2562
2563 if (sync_transaction)
2564 flags |= BUF_SKIP_NONLOCKED;
2565 /*
2566 * Flush all dirty buffers associated with b-tree.
2567 */
2568 buf_iterate(vp, hfs_btsync_callback, flags, 0);
2569
2570 microuptime(&tv);
2571 if (vnode_issystem(vp) && (VTOF(vp)->fcbBTCBPtr != NULL))
2572 (void) BTSetLastSync(VTOF(vp), tv.tv_sec);
2573 cp->c_touch_acctime = FALSE;
2574 cp->c_touch_chgtime = FALSE;
2575 cp->c_touch_modtime = FALSE;
2576
2577 return 0;
2578 }
2579
2580 /*
2581 * Remove a directory.
2582 */
2583 int
2584 hfs_vnop_rmdir(ap)
2585 struct vnop_rmdir_args /* {
2586 struct vnode *a_dvp;
2587 struct vnode *a_vp;
2588 struct componentname *a_cnp;
2589 vfs_context_t a_context;
2590 } */ *ap;
2591 {
2592 struct vnode *dvp = ap->a_dvp;
2593 struct vnode *vp = ap->a_vp;
2594 struct cnode *dcp = VTOC(dvp);
2595 struct cnode *cp = VTOC(vp);
2596 int error;
2597 time_t orig_ctime;
2598
2599 orig_ctime = VTOC(vp)->c_ctime;
2600
2601 if (!S_ISDIR(cp->c_mode)) {
2602 return (ENOTDIR);
2603 }
2604 if (dvp == vp) {
2605 return (EINVAL);
2606 }
2607
2608 check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_DELETE_OP, NULL);
2609 cp = VTOC(vp);
2610
2611 if ((error = hfs_lockpair(dcp, cp, HFS_EXCLUSIVE_LOCK))) {
2612 return (error);
2613 }
2614
2615 /* Check for a race with rmdir on the parent directory */
2616 if (dcp->c_flag & (C_DELETED | C_NOEXISTS)) {
2617 hfs_unlockpair (dcp, cp);
2618 return ENOENT;
2619 }
2620 error = hfs_removedir(dvp, vp, ap->a_cnp, 0, 0);
2621
2622 hfs_unlockpair(dcp, cp);
2623
2624 return (error);
2625 }
2626
2627 /*
2628 * Remove a directory
2629 *
2630 * Both dvp and vp cnodes are locked
2631 */
2632 int
2633 hfs_removedir(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
2634 int skip_reserve, int only_unlink)
2635 {
2636 struct cnode *cp;
2637 struct cnode *dcp;
2638 struct hfsmount * hfsmp;
2639 struct cat_desc desc;
2640 int lockflags;
2641 int error = 0, started_tr = 0;
2642
2643 cp = VTOC(vp);
2644 dcp = VTOC(dvp);
2645 hfsmp = VTOHFS(vp);
2646
2647 if (dcp == cp) {
2648 return (EINVAL); /* cannot remove "." */
2649 }
2650 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
2651 return (0);
2652 }
2653 if (cp->c_entries != 0) {
2654 return (ENOTEMPTY);
2655 }
2656
2657 /*
2658 * If the directory is open or in use (e.g. opendir() or current working
2659 * directory for some process); wait for inactive/reclaim to actually
2660 * remove cnode from the catalog. Both inactive and reclaim codepaths are capable
2661 * of removing open-unlinked directories from the catalog, as well as getting rid
2662 * of EAs still on the element. So change only_unlink to true, so that it will get
2663 * cleaned up below.
2664 *
2665 * Otherwise, we can get into a weird old mess where the directory has C_DELETED,
2666 * but it really means C_NOEXISTS because the item was actually removed from the
2667 * catalog. Then when we try to remove the entry from the catalog later on, it won't
2668 * really be there anymore.
2669 */
2670 if (vnode_isinuse(vp, 0)) {
2671 only_unlink = 1;
2672 }
2673
2674 /* Deal with directory hardlinks */
2675 if (cp->c_flag & C_HARDLINK) {
2676 /*
2677 * Note that if we have a directory which was a hardlink at any point,
2678 * its actual directory data is stored in the directory inode in the hidden
2679 * directory rather than the leaf element(s) present in the namespace.
2680 *
2681 * If there are still other hardlinks to this directory,
2682 * then we'll just eliminate this particular link and the vnode will still exist.
2683 * If this is the last link to an empty directory, then we'll open-unlink the
2684 * directory and it will be only tagged with C_DELETED (as opposed to C_NOEXISTS).
2685 *
2686 * We could also return EBUSY here.
2687 */
2688
2689 return hfs_unlink(hfsmp, dvp, vp, cnp, skip_reserve);
2690 }
2691
2692 /*
2693 * In a few cases, we may want to allow the directory to persist in an
2694 * open-unlinked state. If the directory is being open-unlinked (still has usecount
2695 * references), or if it has EAs, or if it was being deleted as part of a rename,
2696 * then we go ahead and move it to the hidden directory.
2697 *
2698 * If the directory is being open-unlinked, then we want to keep the catalog entry
2699 * alive so that future EA calls and fchmod/fstat etc. do not cause issues later.
2700 *
2701 * If the directory had EAs, then we want to use the open-unlink trick so that the
2702 * EA removal is not done in one giant transaction. Otherwise, it could cause a panic
2703 * due to overflowing the journal.
2704 *
2705 * Finally, if it was deleted as part of a rename, we move it to the hidden directory
2706 * in order to maintain rename atomicity.
2707 *
2708 * Note that the allow_dirs argument to hfs_removefile specifies that it is
2709 * supposed to handle directories for this case.
2710 */
2711
2712 if (((hfsmp->hfs_attribute_vp != NULL) &&
2713 ((cp->c_attr.ca_recflags & kHFSHasAttributesMask) != 0)) ||
2714 (only_unlink != 0)) {
2715
2716 int ret = hfs_removefile(dvp, vp, cnp, 0, 0, 1, NULL, only_unlink);
2717 /*
2718 * Even though hfs_vnop_rename calls vnode_recycle for us on tvp we call
2719 * it here just in case we were invoked by rmdir() on a directory that had
2720 * EAs. To ensure that we start reclaiming the space as soon as possible,
2721 * we call vnode_recycle on the directory.
2722 */
2723 vnode_recycle(vp);
2724
2725 return ret;
2726
2727 }
2728
2729 dcp->c_flag |= C_DIR_MODIFICATION;
2730
2731 #if QUOTA
2732 if (hfsmp->hfs_flags & HFS_QUOTAS)
2733 (void)hfs_getinoquota(cp);
2734 #endif
2735 if ((error = hfs_start_transaction(hfsmp)) != 0) {
2736 goto out;
2737 }
2738 started_tr = 1;
2739
2740 /*
2741 * Verify the directory is empty (and valid).
2742 * (Rmdir ".." won't be valid since
2743 * ".." will contain a reference to
2744 * the current directory and thus be
2745 * non-empty.)
2746 */
2747 if ((dcp->c_bsdflags & APPEND) || (cp->c_bsdflags & (IMMUTABLE | APPEND))) {
2748 error = EPERM;
2749 goto out;
2750 }
2751
2752 /* Remove the entry from the namei cache: */
2753 cache_purge(vp);
2754
2755 /*
2756 * Protect against a race with rename by using the component
2757 * name passed in and parent id from dvp (instead of using
2758 * the cp->c_desc which may have changed).
2759 */
2760 desc.cd_nameptr = (const u_int8_t *)cnp->cn_nameptr;
2761 desc.cd_namelen = cnp->cn_namelen;
2762 desc.cd_parentcnid = dcp->c_fileid;
2763 desc.cd_cnid = cp->c_cnid;
2764 desc.cd_flags = CD_ISDIR;
2765 desc.cd_encoding = cp->c_encoding;
2766 desc.cd_hint = 0;
2767
2768 if (!hfs_valid_cnode(hfsmp, dvp, cnp, cp->c_fileid, NULL, &error)) {
2769 error = 0;
2770 goto out;
2771 }
2772
2773 /* Remove entry from catalog */
2774 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE | SFL_BITMAP, HFS_EXCLUSIVE_LOCK);
2775
2776 if (!skip_reserve) {
2777 /*
2778 * Reserve some space in the Catalog file.
2779 */
2780 if ((error = cat_preflight(hfsmp, CAT_DELETE, NULL, 0))) {
2781 hfs_systemfile_unlock(hfsmp, lockflags);
2782 goto out;
2783 }
2784 }
2785
2786 error = cat_delete(hfsmp, &desc, &cp->c_attr);
2787 if (error == 0) {
2788 /* The parent lost a child */
2789 if (dcp->c_entries > 0)
2790 dcp->c_entries--;
2791 DEC_FOLDERCOUNT(hfsmp, dcp->c_attr);
2792 dcp->c_dirchangecnt++;
2793 dcp->c_touch_chgtime = TRUE;
2794 dcp->c_touch_modtime = TRUE;
2795 hfs_touchtimes(hfsmp, cp);
2796 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL);
2797 cp->c_flag &= ~(C_MODIFIED | C_FORCEUPDATE);
2798 }
2799
2800 hfs_systemfile_unlock(hfsmp, lockflags);
2801
2802 if (error)
2803 goto out;
2804
2805 #if QUOTA
2806 if (hfsmp->hfs_flags & HFS_QUOTAS)
2807 (void)hfs_chkiq(cp, -1, NOCRED, 0);
2808 #endif /* QUOTA */
2809
2810 hfs_volupdate(hfsmp, VOL_RMDIR, (dcp->c_cnid == kHFSRootFolderID));
2811
2812 /* Mark C_NOEXISTS since the catalog entry is now gone */
2813 cp->c_flag |= C_NOEXISTS;
2814 out:
2815 dcp->c_flag &= ~C_DIR_MODIFICATION;
2816 wakeup((caddr_t)&dcp->c_flag);
2817
2818 if (started_tr) {
2819 hfs_end_transaction(hfsmp);
2820 }
2821
2822 return (error);
2823 }
2824
2825
2826 /*
2827 * Remove a file or link.
2828 */
2829 int
2830 hfs_vnop_remove(ap)
2831 struct vnop_remove_args /* {
2832 struct vnode *a_dvp;
2833 struct vnode *a_vp;
2834 struct componentname *a_cnp;
2835 int a_flags;
2836 vfs_context_t a_context;
2837 } */ *ap;
2838 {
2839 struct vnode *dvp = ap->a_dvp;
2840 struct vnode *vp = ap->a_vp;
2841 struct cnode *dcp = VTOC(dvp);
2842 struct cnode *cp;
2843 struct vnode *rvp = NULL;
2844 int error=0, recycle_rsrc=0;
2845 time_t orig_ctime;
2846 uint32_t rsrc_vid = 0;
2847
2848 if (dvp == vp) {
2849 return (EINVAL);
2850 }
2851
2852 orig_ctime = VTOC(vp)->c_ctime;
2853 if ( (!vnode_isnamedstream(vp)) && ((ap->a_flags & VNODE_REMOVE_SKIP_NAMESPACE_EVENT) == 0)) {
2854 error = check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_DELETE_OP, NULL);
2855 if (error) {
2856 // XXXdbg - decide on a policy for handling namespace handler failures!
2857 // for now we just let them proceed.
2858 }
2859 }
2860 error = 0;
2861
2862 cp = VTOC(vp);
2863
2864 relock:
2865
2866 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK);
2867
2868 if ((error = hfs_lockpair(dcp, cp, HFS_EXCLUSIVE_LOCK))) {
2869 hfs_unlock_truncate(cp, 0);
2870 if (rvp) {
2871 vnode_put (rvp);
2872 }
2873 return (error);
2874 }
2875
2876 /*
2877 * Lazily respond to determining if there is a valid resource fork
2878 * vnode attached to 'cp' if it is a regular file or symlink.
2879 * If the vnode does not exist, then we may proceed without having to
2880 * create it.
2881 *
2882 * If, however, it does exist, then we need to acquire an iocount on the
2883 * vnode after acquiring its vid. This ensures that if we have to do I/O
2884 * against it, it can't get recycled from underneath us in the middle
2885 * of this call.
2886 *
2887 * Note: this function may be invoked for directory hardlinks, so just skip these
2888 * steps if 'vp' is a directory.
2889 */
2890
2891
2892 if ((vp->v_type == VLNK) || (vp->v_type == VREG)) {
2893 if ((cp->c_rsrc_vp) && (rvp == NULL)) {
2894 /* We need to acquire the rsrc vnode */
2895 rvp = cp->c_rsrc_vp;
2896 rsrc_vid = vnode_vid (rvp);
2897
2898 /* Unlock everything to acquire iocount on the rsrc vnode */
2899 hfs_unlock_truncate (cp, 0);
2900 hfs_unlockpair (dcp, cp);
2901
2902 /* Use the vid to maintain identity on rvp */
2903 if (vnode_getwithvid(rvp, rsrc_vid)) {
2904 /*
2905 * If this fails, then it was recycled or
2906 * reclaimed in the interim. Reset fields and
2907 * start over.
2908 */
2909 rvp = NULL;
2910 rsrc_vid = 0;
2911 }
2912 goto relock;
2913 }
2914 }
2915
2916 /*
2917 * Check to see if we raced rmdir for the parent directory
2918 * hfs_removefile already checks for a race on vp/cp
2919 */
2920 if (dcp->c_flag & (C_DELETED | C_NOEXISTS)) {
2921 error = ENOENT;
2922 goto rm_done;
2923 }
2924
2925 error = hfs_removefile(dvp, vp, ap->a_cnp, ap->a_flags, 0, 0, NULL, 0);
2926
2927 /*
2928 * If the remove succeeded in deleting the file, then we may need to mark
2929 * the resource fork for recycle so that it is reclaimed as quickly
2930 * as possible. If it were not recycled quickly, then this resource fork
2931 * vnode could keep a v_parent reference on the data fork, which prevents it
2932 * from going through reclaim (by giving it extra usecounts), except in the force-
2933 * unmount case.
2934 *
2935 * However, a caveat: we need to continue to supply resource fork
2936 * access to open-unlinked files even if the resource fork is not open. This is
2937 * a requirement for the compressed files work. Luckily, hfs_vgetrsrc will handle
2938 * this already if the data fork has been re-parented to the hidden directory.
2939 *
2940 * As a result, all we really need to do here is mark the resource fork vnode
2941 * for recycle. If it goes out of core, it can be brought in again if needed.
2942 * If the cnode was instead marked C_NOEXISTS, then there wouldn't be any
2943 * more work.
2944 */
2945 if ((error == 0) && (rvp)) {
2946 recycle_rsrc = 1;
2947 }
2948
2949 /*
2950 * Drop the truncate lock before unlocking the cnode
2951 * (which can potentially perform a vnode_put and
2952 * recycle the vnode which in turn might require the
2953 * truncate lock)
2954 */
2955 rm_done:
2956 hfs_unlock_truncate(cp, 0);
2957 hfs_unlockpair(dcp, cp);
2958
2959 if (recycle_rsrc) {
2960 /* inactive or reclaim on rvp will clean up the blocks from the rsrc fork */
2961 vnode_recycle(rvp);
2962 }
2963
2964 if (rvp) {
2965 /* drop iocount on rsrc fork, was obtained at beginning of fxn */
2966 vnode_put(rvp);
2967 }
2968
2969 return (error);
2970 }
2971
2972
2973 int
2974 hfs_removefile_callback(struct buf *bp, void *hfsmp) {
2975
2976 if ( !(buf_flags(bp) & B_META))
2977 panic("hfs: symlink bp @ %p is not marked meta-data!\n", bp);
2978 /*
2979 * it's part of the current transaction, kill it.
2980 */
2981 journal_kill_block(((struct hfsmount *)hfsmp)->jnl, bp);
2982
2983 return (BUF_CLAIMED);
2984 }
2985
2986 /*
2987 * hfs_removefile
2988 *
2989 * Similar to hfs_vnop_remove except there are additional options.
2990 * This function may be used to remove directories if they have
2991 * lots of EA's -- note the 'allow_dirs' argument.
2992 *
2993 * This function is able to delete blocks & fork data for the resource
2994 * fork even if it does not exist in core (and have a backing vnode).
2995 * It should infer the correct behavior based on the number of blocks
2996 * in the cnode and whether or not the resource fork pointer exists or
2997 * not. As a result, one only need pass in the 'vp' corresponding to the
2998 * data fork of this file (or main vnode in the case of a directory).
2999 * Passing in a resource fork will result in an error.
3000 *
3001 * Because we do not create any vnodes in this function, we are not at
3002 * risk of deadlocking against ourselves by double-locking.
3003 *
3004 * Requires cnode and truncate locks to be held.
3005 */
3006 int
3007 hfs_removefile(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
3008 int flags, int skip_reserve, int allow_dirs,
3009 __unused struct vnode *rvp, int only_unlink)
3010 {
3011 struct cnode *cp;
3012 struct cnode *dcp;
3013 struct vnode *rsrc_vp = NULL;
3014 struct hfsmount *hfsmp;
3015 struct cat_desc desc;
3016 struct timeval tv;
3017 int dataforkbusy = 0;
3018 int rsrcforkbusy = 0;
3019 int lockflags;
3020 int error = 0;
3021 int started_tr = 0;
3022 int isbigfile = 0, defer_remove=0, isdir=0;
3023 int update_vh = 0;
3024
3025 cp = VTOC(vp);
3026 dcp = VTOC(dvp);
3027 hfsmp = VTOHFS(vp);
3028
3029 /* Check if we lost a race post lookup. */
3030 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
3031 return (0);
3032 }
3033
3034 if (!hfs_valid_cnode(hfsmp, dvp, cnp, cp->c_fileid, NULL, &error)) {
3035 return 0;
3036 }
3037
3038 /* Make sure a remove is permitted */
3039 if (VNODE_IS_RSRC(vp)) {
3040 return (EPERM);
3041 }
3042 else {
3043 /*
3044 * We know it's a data fork.
3045 * Probe the cnode to see if we have a valid resource fork
3046 * in hand or not.
3047 */
3048 rsrc_vp = cp->c_rsrc_vp;
3049 }
3050
3051 /* Don't allow deleting the journal or journal_info_block. */
3052 if (hfs_is_journal_file(hfsmp, cp)) {
3053 return (EPERM);
3054 }
3055
3056 /*
3057 * If removing a symlink, then we need to ensure that the
3058 * data blocks for the symlink are not still in-flight or pending.
3059 * If so, we will unlink the symlink here, making its blocks
3060 * available for re-allocation by a subsequent transaction. That is OK, but
3061 * then the I/O for the data blocks could then go out before the journal
3062 * transaction that created it was flushed, leading to I/O ordering issues.
3063 */
3064 if (vp->v_type == VLNK) {
3065 /*
3066 * This will block if the asynchronous journal flush is in progress.
3067 * If this symlink is not being renamed over and doesn't have any open FDs,
3068 * then we'll remove it from the journal's bufs below in kill_block.
3069 */
3070 buf_wait_for_shadow_io (vp, 0);
3071 }
3072
3073 /*
3074 * Hard links require special handling.
3075 */
3076 if (cp->c_flag & C_HARDLINK) {
3077 if ((flags & VNODE_REMOVE_NODELETEBUSY) && vnode_isinuse(vp, 0)) {
3078 return (EBUSY);
3079 } else {
3080 /* A directory hard link with a link count of one is
3081 * treated as a regular directory. Therefore it should
3082 * only be removed using rmdir().
3083 */
3084 if ((vnode_isdir(vp) == 1) && (cp->c_linkcount == 1) &&
3085 (allow_dirs == 0)) {
3086 return (EPERM);
3087 }
3088 return hfs_unlink(hfsmp, dvp, vp, cnp, skip_reserve);
3089 }
3090 }
3091
3092 /* Directories should call hfs_rmdir! (unless they have a lot of attributes) */
3093 if (vnode_isdir(vp)) {
3094 if (allow_dirs == 0)
3095 return (EPERM); /* POSIX */
3096 isdir = 1;
3097 }
3098 /* Sanity check the parent ids. */
3099 if ((cp->c_parentcnid != hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
3100 (cp->c_parentcnid != dcp->c_fileid)) {
3101 return (EINVAL);
3102 }
3103
3104 dcp->c_flag |= C_DIR_MODIFICATION;
3105
3106 // this guy is going away so mark him as such
3107 cp->c_flag |= C_DELETED;
3108
3109
3110 /* Remove our entry from the namei cache. */
3111 cache_purge(vp);
3112
3113 /*
3114 * If the caller was operating on a file (as opposed to a
3115 * directory with EAs), then we need to figure out
3116 * whether or not it has a valid resource fork vnode.
3117 *
3118 * If there was a valid resource fork vnode, then we need
3119 * to use hfs_truncate to eliminate its data. If there is
3120 * no vnode, then we hold the cnode lock which would
3121 * prevent it from being created. As a result,
3122 * we can use the data deletion functions which do not
3123 * require that a cnode/vnode pair exist.
3124 */
3125
3126 /* Check if this file is being used. */
3127 if (isdir == 0) {
3128 dataforkbusy = vnode_isinuse(vp, 0);
3129 /*
3130 * At this point, we know that 'vp' points to the
3131 * a data fork because we checked it up front. And if
3132 * there is no rsrc fork, rsrc_vp will be NULL.
3133 */
3134 if (rsrc_vp && (cp->c_blocks - VTOF(vp)->ff_blocks)) {
3135 rsrcforkbusy = vnode_isinuse(rsrc_vp, 0);
3136 }
3137 }
3138
3139 /* Check if we have to break the deletion into multiple pieces. */
3140 if (isdir == 0) {
3141 isbigfile = ((cp->c_datafork->ff_size >= HFS_BIGFILE_SIZE) && overflow_extents(VTOF(vp)));
3142 }
3143
3144 /* Check if the file has xattrs. If it does we'll have to delete them in
3145 individual transactions in case there are too many */
3146 if ((hfsmp->hfs_attribute_vp != NULL) &&
3147 (cp->c_attr.ca_recflags & kHFSHasAttributesMask) != 0) {
3148 defer_remove = 1;
3149 }
3150
3151 /* If we are explicitly told to only unlink item and move to hidden dir, then do it */
3152 if (only_unlink) {
3153 defer_remove = 1;
3154 }
3155
3156 /*
3157 * Carbon semantics prohibit deleting busy files.
3158 * (enforced when VNODE_REMOVE_NODELETEBUSY is requested)
3159 */
3160 if (dataforkbusy || rsrcforkbusy) {
3161 if ((flags & VNODE_REMOVE_NODELETEBUSY) ||
3162 (hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid == 0)) {
3163 error = EBUSY;
3164 goto out;
3165 }
3166 }
3167
3168 #if QUOTA
3169 if (hfsmp->hfs_flags & HFS_QUOTAS)
3170 (void)hfs_getinoquota(cp);
3171 #endif /* QUOTA */
3172
3173 /*
3174 * Do a ubc_setsize to indicate we need to wipe contents if:
3175 * 1) item is a regular file.
3176 * 2) Neither fork is busy AND we are not told to unlink this.
3177 *
3178 * We need to check for the defer_remove since it can be set without
3179 * having a busy data or rsrc fork
3180 */
3181 if (isdir == 0 && (!dataforkbusy || !rsrcforkbusy) && (defer_remove == 0)) {
3182 /*
3183 * A ubc_setsize can cause a pagein so defer it
3184 * until after the cnode lock is dropped. The
3185 * cnode lock cannot be dropped/reacquired here
3186 * since we might already hold the journal lock.
3187 */
3188 if (!dataforkbusy && cp->c_datafork->ff_blocks && !isbigfile) {
3189 cp->c_flag |= C_NEED_DATA_SETSIZE;
3190 }
3191 if (!rsrcforkbusy && rsrc_vp) {
3192 cp->c_flag |= C_NEED_RSRC_SETSIZE;
3193 }
3194 }
3195
3196 if ((error = hfs_start_transaction(hfsmp)) != 0) {
3197 goto out;
3198 }
3199 started_tr = 1;
3200
3201 // XXXdbg - if we're journaled, kill any dirty symlink buffers
3202 if (hfsmp->jnl && vnode_islnk(vp) && (defer_remove == 0)) {
3203 buf_iterate(vp, hfs_removefile_callback, BUF_SKIP_NONLOCKED, (void *)hfsmp);
3204 }
3205
3206 /*
3207 * Prepare to truncate any non-busy forks. Busy forks will
3208 * get truncated when their vnode goes inactive.
3209 * Note that we will only enter this region if we
3210 * can avoid creating an open-unlinked file. If
3211 * either region is busy, we will have to create an open
3212 * unlinked file.
3213 *
3214 * Since we are deleting the file, we need to stagger the runtime
3215 * modifications to do things in such a way that a crash won't
3216 * result in us getting overlapped extents or any other
3217 * bad inconsistencies. As such, we call prepare_release_storage
3218 * which updates the UBC, updates quota information, and releases
3219 * any loaned blocks that belong to this file. No actual
3220 * truncation or bitmap manipulation is done until *AFTER*
3221 * the catalog record is removed.
3222 */
3223 if (isdir == 0 && (!dataforkbusy && !rsrcforkbusy) && (only_unlink == 0)) {
3224
3225 if (!dataforkbusy && !isbigfile && cp->c_datafork->ff_blocks != 0) {
3226
3227 error = hfs_prepare_release_storage (hfsmp, vp);
3228 if (error) {
3229 goto out;
3230 }
3231 update_vh = 1;
3232 }
3233
3234 /*
3235 * If the resource fork vnode does not exist, we can skip this step.
3236 */
3237 if (!rsrcforkbusy && rsrc_vp) {
3238 error = hfs_prepare_release_storage (hfsmp, rsrc_vp);
3239 if (error) {
3240 goto out;
3241 }
3242 update_vh = 1;
3243 }
3244 }
3245
3246 /*
3247 * Protect against a race with rename by using the component
3248 * name passed in and parent id from dvp (instead of using
3249 * the cp->c_desc which may have changed). Also, be aware that
3250 * because we allow directories to be passed in, we need to special case
3251 * this temporary descriptor in case we were handed a directory.
3252 */
3253 if (isdir) {
3254 desc.cd_flags = CD_ISDIR;
3255 }
3256 else {
3257 desc.cd_flags = 0;
3258 }
3259 desc.cd_encoding = cp->c_desc.cd_encoding;
3260 desc.cd_nameptr = (const u_int8_t *)cnp->cn_nameptr;
3261 desc.cd_namelen = cnp->cn_namelen;
3262 desc.cd_parentcnid = dcp->c_fileid;
3263 desc.cd_hint = cp->c_desc.cd_hint;
3264 desc.cd_cnid = cp->c_cnid;
3265 microtime(&tv);
3266
3267 /*
3268 * There are two cases to consider:
3269 * 1. File/Dir is busy/big/defer_remove ==> move/rename the file/dir
3270 * 2. File is not in use ==> remove the file
3271 *
3272 * We can get a directory in case 1 because it may have had lots of attributes,
3273 * which need to get removed here.
3274 */
3275 if (dataforkbusy || rsrcforkbusy || isbigfile || defer_remove) {
3276 char delname[32];
3277 struct cat_desc to_desc;
3278 struct cat_desc todir_desc;
3279
3280 /*
3281 * Orphan this file or directory (move to hidden directory).
3282 * Again, we need to take care that we treat directories as directories,
3283 * and files as files. Because directories with attributes can be passed in
3284 * check to make sure that we have a directory or a file before filling in the
3285 * temporary descriptor's flags. We keep orphaned directories AND files in
3286 * the FILE_HARDLINKS private directory since we're generalizing over all
3287 * orphaned filesystem objects.
3288 */
3289 bzero(&todir_desc, sizeof(todir_desc));
3290 todir_desc.cd_parentcnid = 2;
3291
3292 MAKE_DELETED_NAME(delname, sizeof(delname), cp->c_fileid);
3293 bzero(&to_desc, sizeof(to_desc));
3294 to_desc.cd_nameptr = (const u_int8_t *)delname;
3295 to_desc.cd_namelen = strlen(delname);
3296 to_desc.cd_parentcnid = hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid;
3297 if (isdir) {
3298 to_desc.cd_flags = CD_ISDIR;
3299 }
3300 else {
3301 to_desc.cd_flags = 0;
3302 }
3303 to_desc.cd_cnid = cp->c_cnid;
3304
3305 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
3306 if (!skip_reserve) {
3307 if ((error = cat_preflight(hfsmp, CAT_RENAME, NULL, 0))) {
3308 hfs_systemfile_unlock(hfsmp, lockflags);
3309 goto out;
3310 }
3311 }
3312
3313 error = cat_rename(hfsmp, &desc, &todir_desc,
3314 &to_desc, (struct cat_desc *)NULL);
3315
3316 if (error == 0) {
3317 hfsmp->hfs_private_attr[FILE_HARDLINKS].ca_entries++;
3318 if (isdir == 1) {
3319 INC_FOLDERCOUNT(hfsmp, hfsmp->hfs_private_attr[FILE_HARDLINKS]);
3320 }
3321 (void) cat_update(hfsmp, &hfsmp->hfs_private_desc[FILE_HARDLINKS],
3322 &hfsmp->hfs_private_attr[FILE_HARDLINKS], NULL, NULL);
3323
3324 /* Update the parent directory */
3325 if (dcp->c_entries > 0)
3326 dcp->c_entries--;
3327 if (isdir == 1) {
3328 DEC_FOLDERCOUNT(hfsmp, dcp->c_attr);
3329 }
3330 dcp->c_dirchangecnt++;
3331 dcp->c_ctime = tv.tv_sec;
3332 dcp->c_mtime = tv.tv_sec;
3333 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL);
3334
3335 /* Update the file or directory's state */
3336 cp->c_flag |= C_DELETED;
3337 cp->c_ctime = tv.tv_sec;
3338 --cp->c_linkcount;
3339 (void) cat_update(hfsmp, &to_desc, &cp->c_attr, NULL, NULL);
3340 }
3341 hfs_systemfile_unlock(hfsmp, lockflags);
3342 if (error)
3343 goto out;
3344
3345 }
3346 else {
3347 /*
3348 * Nobody is using this item; we can safely remove everything.
3349 */
3350 struct filefork *temp_rsrc_fork = NULL;
3351 #if QUOTA
3352 off_t savedbytes;
3353 int blksize = hfsmp->blockSize;
3354 #endif
3355 u_int32_t fileid = cp->c_fileid;
3356
3357 /*
3358 * Figure out if we need to read the resource fork data into
3359 * core before wiping out the catalog record.
3360 *
3361 * 1) Must not be a directory
3362 * 2) cnode's c_rsrcfork ptr must be NULL.
3363 * 3) rsrc fork must have actual blocks
3364 */
3365 if ((isdir == 0) && (cp->c_rsrcfork == NULL) &&
3366 (cp->c_blocks - VTOF(vp)->ff_blocks)) {
3367 /*
3368 * The resource fork vnode & filefork did not exist.
3369 * Create a temporary one for use in this function only.
3370 */
3371 MALLOC_ZONE (temp_rsrc_fork, struct filefork *, sizeof (struct filefork), M_HFSFORK, M_WAITOK);
3372 bzero(temp_rsrc_fork, sizeof(struct filefork));
3373 temp_rsrc_fork->ff_cp = cp;
3374 rl_init(&temp_rsrc_fork->ff_invalidranges);
3375 }
3376
3377 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE | SFL_BITMAP, HFS_EXCLUSIVE_LOCK);
3378
3379 /* Look up the resource fork first, if necessary */
3380 if (temp_rsrc_fork) {
3381 error = cat_lookup (hfsmp, &desc, 1, (struct cat_desc*) NULL,
3382 (struct cat_attr*) NULL, &temp_rsrc_fork->ff_data, NULL);
3383 if (error) {
3384 FREE_ZONE (temp_rsrc_fork, sizeof(struct filefork), M_HFSFORK);
3385 hfs_systemfile_unlock (hfsmp, lockflags);
3386 goto out;
3387 }
3388 }
3389
3390 if (!skip_reserve) {
3391 if ((error = cat_preflight(hfsmp, CAT_DELETE, NULL, 0))) {
3392 if (temp_rsrc_fork) {
3393 FREE_ZONE (temp_rsrc_fork, sizeof(struct filefork), M_HFSFORK);
3394 }
3395 hfs_systemfile_unlock(hfsmp, lockflags);
3396 goto out;
3397 }
3398 }
3399
3400 error = cat_delete(hfsmp, &desc, &cp->c_attr);
3401
3402 if (error && error != ENXIO && error != ENOENT) {
3403 printf("hfs_removefile: deleting file %s (%d), err: %d\n",
3404 cp->c_desc.cd_nameptr, cp->c_attr.ca_fileid, error);
3405 }
3406
3407 if (error == 0) {
3408 /* Update the parent directory */
3409 if (dcp->c_entries > 0)
3410 dcp->c_entries--;
3411 dcp->c_dirchangecnt++;
3412 dcp->c_ctime = tv.tv_sec;
3413 dcp->c_mtime = tv.tv_sec;
3414 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL);
3415 }
3416 hfs_systemfile_unlock(hfsmp, lockflags);
3417
3418 if (error) {
3419 if (temp_rsrc_fork) {
3420 FREE_ZONE (temp_rsrc_fork, sizeof(struct filefork), M_HFSFORK);
3421 }
3422 goto out;
3423 }
3424
3425 /*
3426 * Now that we've wiped out the catalog record, the file effectively doesn't
3427 * exist anymore. So update the quota records to reflect the loss of the
3428 * data fork and the resource fork.
3429 */
3430 #if QUOTA
3431 if (cp->c_datafork->ff_blocks > 0) {
3432 savedbytes = ((off_t)cp->c_datafork->ff_blocks * (off_t)blksize);
3433 (void) hfs_chkdq(cp, (int64_t)-(savedbytes), NOCRED, 0);
3434 }
3435
3436 /*
3437 * We may have just deleted the catalog record for a resource fork even
3438 * though it did not exist in core as a vnode. However, just because there
3439 * was a resource fork pointer in the cnode does not mean that it had any blocks.
3440 */
3441 if (temp_rsrc_fork || cp->c_rsrcfork) {
3442 if (cp->c_rsrcfork) {
3443 if (cp->c_rsrcfork->ff_blocks > 0) {
3444 savedbytes = ((off_t)cp->c_rsrcfork->ff_blocks * (off_t)blksize);
3445 (void) hfs_chkdq(cp, (int64_t)-(savedbytes), NOCRED, 0);
3446 }
3447 }
3448 else {
3449 /* we must have used a temporary fork */
3450 savedbytes = ((off_t)temp_rsrc_fork->ff_blocks * (off_t)blksize);
3451 (void) hfs_chkdq(cp, (int64_t)-(savedbytes), NOCRED, 0);
3452 }
3453 }
3454
3455 if (hfsmp->hfs_flags & HFS_QUOTAS) {
3456 (void)hfs_chkiq(cp, -1, NOCRED, 0);
3457 }
3458 #endif
3459
3460 /*
3461 * If we didn't get any errors deleting the catalog entry, then go ahead
3462 * and release the backing store now. The filefork pointers are still valid.
3463 */
3464 if (temp_rsrc_fork) {
3465 error = hfs_release_storage (hfsmp, cp->c_datafork, temp_rsrc_fork, fileid);
3466 }
3467 else {
3468 /* if cp->c_rsrcfork == NULL, hfs_release_storage will skip over it. */
3469 error = hfs_release_storage (hfsmp, cp->c_datafork, cp->c_rsrcfork, fileid);
3470 }
3471 if (error) {
3472 /*
3473 * If we encountered an error updating the extents and bitmap,
3474 * mark the volume inconsistent. At this point, the catalog record has
3475 * already been deleted, so we can't recover it at this point. We need
3476 * to proceed and update the volume header and mark the cnode C_NOEXISTS.
3477 * The subsequent fsck should be able to recover the free space for us.
3478 */
3479 hfs_mark_volume_inconsistent(hfsmp);
3480 }
3481 else {
3482 /* reset update_vh to 0, since hfs_release_storage should have done it for us */
3483 update_vh = 0;
3484 }
3485
3486 /* Get rid of the temporary rsrc fork */
3487 if (temp_rsrc_fork) {
3488 FREE_ZONE (temp_rsrc_fork, sizeof(struct filefork), M_HFSFORK);
3489 }
3490
3491 cp->c_flag |= C_NOEXISTS;
3492 cp->c_flag &= ~C_DELETED;
3493
3494 cp->c_touch_chgtime = TRUE; /* XXX needed ? */
3495 --cp->c_linkcount;
3496
3497 /*
3498 * We must never get a directory if we're in this else block. We could
3499 * accidentally drop the number of files in the volume header if we did.
3500 */
3501 hfs_volupdate(hfsmp, VOL_RMFILE, (dcp->c_cnid == kHFSRootFolderID));
3502
3503 }
3504
3505 /*
3506 * All done with this cnode's descriptor...
3507 *
3508 * Note: all future catalog calls for this cnode must be by
3509 * fileid only. This is OK for HFS (which doesn't have file
3510 * thread records) since HFS doesn't support the removal of
3511 * busy files.
3512 */
3513 cat_releasedesc(&cp->c_desc);
3514
3515 out:
3516 if (error) {
3517 cp->c_flag &= ~C_DELETED;
3518 }
3519
3520 if (update_vh) {
3521 /*
3522 * If we bailed out earlier, we may need to update the volume header
3523 * to deal with the borrowed blocks accounting.
3524 */
3525 hfs_volupdate (hfsmp, VOL_UPDATE, 0);
3526 }
3527
3528 if (started_tr) {
3529 hfs_end_transaction(hfsmp);
3530 }
3531
3532 dcp->c_flag &= ~C_DIR_MODIFICATION;
3533 wakeup((caddr_t)&dcp->c_flag);
3534
3535 return (error);
3536 }
3537
3538
3539 __private_extern__ void
3540 replace_desc(struct cnode *cp, struct cat_desc *cdp)
3541 {
3542 // fixes 4348457 and 4463138
3543 if (&cp->c_desc == cdp) {
3544 return;
3545 }
3546
3547 /* First release allocated name buffer */
3548 if (cp->c_desc.cd_flags & CD_HASBUF && cp->c_desc.cd_nameptr != 0) {
3549 const u_int8_t *name = cp->c_desc.cd_nameptr;
3550
3551 cp->c_desc.cd_nameptr = 0;
3552 cp->c_desc.cd_namelen = 0;
3553 cp->c_desc.cd_flags &= ~CD_HASBUF;
3554 vfs_removename((const char *)name);
3555 }
3556 bcopy(cdp, &cp->c_desc, sizeof(cp->c_desc));
3557
3558 /* Cnode now owns the name buffer */
3559 cdp->cd_nameptr = 0;
3560 cdp->cd_namelen = 0;
3561 cdp->cd_flags &= ~CD_HASBUF;
3562 }
3563
3564
3565 /*
3566 * Rename a cnode.
3567 *
3568 * The VFS layer guarantees that:
3569 * - source and destination will either both be directories, or
3570 * both not be directories.
3571 * - all the vnodes are from the same file system
3572 *
3573 * When the target is a directory, HFS must ensure that its empty.
3574 *
3575 * Note that this function requires up to 6 vnodes in order to work properly
3576 * if it is operating on files (and not on directories). This is because only
3577 * files can have resource forks, and we now require iocounts to be held on the
3578 * vnodes corresponding to the resource forks (if applicable) as well as
3579 * the files or directories undergoing rename. The problem with not holding
3580 * iocounts on the resource fork vnodes is that it can lead to a deadlock
3581 * situation: The rsrc fork of the source file may be recycled and reclaimed
3582 * in order to provide a vnode for the destination file's rsrc fork. Since
3583 * data and rsrc forks share the same cnode, we'd eventually try to lock the
3584 * source file's cnode in order to sync its rsrc fork to disk, but it's already
3585 * been locked. By taking the rsrc fork vnodes up front we ensure that they
3586 * cannot be recycled, and that the situation mentioned above cannot happen.
3587 */
3588 int
3589 hfs_vnop_rename(ap)
3590 struct vnop_rename_args /* {
3591 struct vnode *a_fdvp;
3592 struct vnode *a_fvp;
3593 struct componentname *a_fcnp;
3594 struct vnode *a_tdvp;
3595 struct vnode *a_tvp;
3596 struct componentname *a_tcnp;
3597 vfs_context_t a_context;
3598 } */ *ap;
3599 {
3600 struct vnode *tvp = ap->a_tvp;
3601 struct vnode *tdvp = ap->a_tdvp;
3602 struct vnode *fvp = ap->a_fvp;
3603 struct vnode *fdvp = ap->a_fdvp;
3604 /*
3605 * Note that we only need locals for the target/destination's
3606 * resource fork vnode (and only if necessary). We don't care if the
3607 * source has a resource fork vnode or not.
3608 */
3609 struct vnode *tvp_rsrc = NULLVP;
3610 uint32_t tvp_rsrc_vid = 0;
3611 struct componentname *tcnp = ap->a_tcnp;
3612 struct componentname *fcnp = ap->a_fcnp;
3613 struct proc *p = vfs_context_proc(ap->a_context);
3614 struct cnode *fcp;
3615 struct cnode *fdcp;
3616 struct cnode *tdcp;
3617 struct cnode *tcp;
3618 struct cnode *error_cnode;
3619 struct cat_desc from_desc;
3620 struct cat_desc to_desc;
3621 struct cat_desc out_desc;
3622 struct hfsmount *hfsmp;
3623 cat_cookie_t cookie;
3624 int tvp_deleted = 0;
3625 int started_tr = 0, got_cookie = 0;
3626 int took_trunc_lock = 0;
3627 int lockflags;
3628 int error;
3629 time_t orig_from_ctime, orig_to_ctime;
3630 int emit_rename = 1;
3631 int emit_delete = 1;
3632
3633 orig_from_ctime = VTOC(fvp)->c_ctime;
3634 if (tvp && VTOC(tvp)) {
3635 orig_to_ctime = VTOC(tvp)->c_ctime;
3636 } else {
3637 orig_to_ctime = ~0;
3638 }
3639
3640 hfsmp = VTOHFS(tdvp);
3641 /*
3642 * Do special case checks here. If fvp == tvp then we need to check the
3643 * cnode with locks held.
3644 */
3645 if (fvp == tvp) {
3646 int is_hardlink = 0;
3647 /*
3648 * In this case, we do *NOT* ever emit a DELETE event.
3649 * We may not necessarily emit a RENAME event
3650 */
3651 emit_delete = 0;
3652 if ((error = hfs_lock(VTOC(fvp), HFS_SHARED_LOCK))) {
3653 return error;
3654 }
3655 /* Check to see if the item is a hardlink or not */
3656 is_hardlink = (VTOC(fvp)->c_flag & C_HARDLINK);
3657 hfs_unlock (VTOC(fvp));
3658
3659 /*
3660 * If the item is not a hardlink, then case sensitivity must be off, otherwise
3661 * two names should not resolve to the same cnode unless they were case variants.
3662 */
3663 if (is_hardlink) {
3664 emit_rename = 0;
3665 /*
3666 * Hardlinks are a little trickier. We only want to emit a rename event
3667 * if the item is a hardlink, the parent directories are the same, case sensitivity
3668 * is off, and the case folded names are the same. See the fvp == tvp case below for more
3669 * info.
3670 */
3671
3672 if ((fdvp == tdvp) && ((hfsmp->hfs_flags & HFS_CASE_SENSITIVE) == 0)) {
3673 if (hfs_namecmp((const u_int8_t *)fcnp->cn_nameptr, fcnp->cn_namelen,
3674 (const u_int8_t *)tcnp->cn_nameptr, tcnp->cn_namelen) == 0) {
3675 /* Then in this case only it is ok to emit a rename */
3676 emit_rename = 1;
3677 }
3678 }
3679 }
3680 }
3681 if (emit_rename) {
3682 check_for_tracked_file(fvp, orig_from_ctime, NAMESPACE_HANDLER_RENAME_OP, NULL);
3683 }
3684
3685 if (tvp && VTOC(tvp)) {
3686 if (emit_delete) {
3687 check_for_tracked_file(tvp, orig_to_ctime, NAMESPACE_HANDLER_DELETE_OP, NULL);
3688 }
3689 }
3690
3691 retry:
3692 /* When tvp exists, take the truncate lock for hfs_removefile(). */
3693 if (tvp && (vnode_isreg(tvp) || vnode_islnk(tvp))) {
3694 hfs_lock_truncate(VTOC(tvp), HFS_EXCLUSIVE_LOCK);
3695 took_trunc_lock = 1;
3696 }
3697
3698 error = hfs_lockfour(VTOC(fdvp), VTOC(fvp), VTOC(tdvp), tvp ? VTOC(tvp) : NULL,
3699 HFS_EXCLUSIVE_LOCK, &error_cnode);
3700 if (error) {
3701 if (took_trunc_lock) {
3702 hfs_unlock_truncate(VTOC(tvp), 0);
3703 took_trunc_lock = 0;
3704 }
3705
3706 /*
3707 * We hit an error path. If we were trying to re-acquire the locks
3708 * after coming through here once, we might have already obtained
3709 * an iocount on tvp's resource fork vnode. Drop that before dealing
3710 * with the failure. Note this is safe -- since we are in an
3711 * error handling path, we can't be holding the cnode locks.
3712 */
3713 if (tvp_rsrc) {
3714 vnode_put (tvp_rsrc);
3715 tvp_rsrc_vid = 0;
3716 tvp_rsrc = NULL;
3717 }
3718
3719 /*
3720 * tvp might no longer exist. If the cause of the lock failure
3721 * was tvp, then we can try again with tvp/tcp set to NULL.
3722 * This is ok because the vfs syscall will vnode_put the vnodes
3723 * after we return from hfs_vnop_rename.
3724 */
3725 if ((error == ENOENT) && (tvp != NULL) && (error_cnode == VTOC(tvp))) {
3726 tcp = NULL;
3727 tvp = NULL;
3728 goto retry;
3729 }
3730
3731 return (error);
3732 }
3733
3734 fdcp = VTOC(fdvp);
3735 fcp = VTOC(fvp);
3736 tdcp = VTOC(tdvp);
3737 tcp = tvp ? VTOC(tvp) : NULL;
3738
3739 /*
3740 * Acquire iocounts on the destination's resource fork vnode
3741 * if necessary. If dst/src are files and the dst has a resource
3742 * fork vnode, then we need to try and acquire an iocount on the rsrc vnode.
3743 * If it does not exist, then we don't care and can skip it.
3744 */
3745 if ((vnode_isreg(fvp)) || (vnode_islnk(fvp))) {
3746 if ((tvp) && (tcp->c_rsrc_vp) && (tvp_rsrc == NULL)) {
3747 tvp_rsrc = tcp->c_rsrc_vp;
3748 /*
3749 * We can look at the vid here because we're holding the
3750 * cnode lock on the underlying cnode for this rsrc vnode.
3751 */
3752 tvp_rsrc_vid = vnode_vid (tvp_rsrc);
3753
3754 /* Unlock everything to acquire iocount on this rsrc vnode */
3755 if (took_trunc_lock) {
3756 hfs_unlock_truncate (VTOC(tvp), 0);
3757 took_trunc_lock = 0;
3758 }
3759 hfs_unlockfour(fdcp, fcp, tdcp, tcp);
3760
3761 if (vnode_getwithvid (tvp_rsrc, tvp_rsrc_vid)) {
3762 /* iocount acquisition failed. Reset fields and start over.. */
3763 tvp_rsrc_vid = 0;
3764 tvp_rsrc = NULL;
3765 }
3766 goto retry;
3767 }
3768 }
3769
3770 /* Ensure we didn't race src or dst parent directories with rmdir. */
3771 if (fdcp->c_flag & (C_NOEXISTS | C_DELETED)) {
3772 error = ENOENT;
3773 goto out;
3774 }
3775
3776 if (tdcp->c_flag & (C_NOEXISTS | C_DELETED)) {
3777 error = ENOENT;
3778 goto out;
3779 }
3780
3781
3782 /* Check for a race against unlink. The hfs_valid_cnode checks validate
3783 * the parent/child relationship with fdcp and tdcp, as well as the
3784 * component name of the target cnodes.
3785 */
3786 if ((fcp->c_flag & (C_NOEXISTS | C_DELETED)) || !hfs_valid_cnode(hfsmp, fdvp, fcnp, fcp->c_fileid, NULL, &error)) {
3787 error = ENOENT;
3788 goto out;
3789 }
3790
3791 if (tcp && ((tcp->c_flag & (C_NOEXISTS | C_DELETED)) || !hfs_valid_cnode(hfsmp, tdvp, tcnp, tcp->c_fileid, NULL, &error))) {
3792 //
3793 // hmm, the destination vnode isn't valid any more.
3794 // in this case we can just drop him and pretend he
3795 // never existed in the first place.
3796 //
3797 if (took_trunc_lock) {
3798 hfs_unlock_truncate(VTOC(tvp), 0);
3799 took_trunc_lock = 0;
3800 }
3801 error = 0;
3802
3803 hfs_unlockfour(fdcp, fcp, tdcp, tcp);
3804
3805 tcp = NULL;
3806 tvp = NULL;
3807
3808 // retry the locking with tvp null'ed out
3809 goto retry;
3810 }
3811
3812 fdcp->c_flag |= C_DIR_MODIFICATION;
3813 if (fdvp != tdvp) {
3814 tdcp->c_flag |= C_DIR_MODIFICATION;
3815 }
3816
3817 /*
3818 * Disallow renaming of a directory hard link if the source and
3819 * destination parent directories are different, or a directory whose
3820 * descendant is a directory hard link and the one of the ancestors
3821 * of the destination directory is a directory hard link.
3822 */
3823 if (vnode_isdir(fvp) && (fdvp != tdvp)) {
3824 if (fcp->c_flag & C_HARDLINK) {
3825 error = EPERM;
3826 goto out;
3827 }
3828 if (fcp->c_attr.ca_recflags & kHFSHasChildLinkMask) {
3829 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
3830 if (cat_check_link_ancestry(hfsmp, tdcp->c_fileid, 0)) {
3831 error = EPERM;
3832 hfs_systemfile_unlock(hfsmp, lockflags);
3833 goto out;
3834 }
3835 hfs_systemfile_unlock(hfsmp, lockflags);
3836 }
3837 }
3838
3839 /*
3840 * The following edge case is caught here:
3841 * (to cannot be a descendent of from)
3842 *
3843 * o fdvp
3844 * /
3845 * /
3846 * o fvp
3847 * \
3848 * \
3849 * o tdvp
3850 * /
3851 * /
3852 * o tvp
3853 */
3854 if (tdcp->c_parentcnid == fcp->c_fileid) {
3855 error = EINVAL;
3856 goto out;
3857 }
3858
3859 /*
3860 * The following two edge cases are caught here:
3861 * (note tvp is not empty)
3862 *
3863 * o tdvp o tdvp
3864 * / /
3865 * / /
3866 * o tvp tvp o fdvp
3867 * \ \
3868 * \ \
3869 * o fdvp o fvp
3870 * /
3871 * /
3872 * o fvp
3873 */
3874 if (tvp && vnode_isdir(tvp) && (tcp->c_entries != 0) && fvp != tvp) {
3875 error = ENOTEMPTY;
3876 goto out;
3877 }
3878
3879 /*
3880 * The following edge case is caught here:
3881 * (the from child and parent are the same)
3882 *
3883 * o tdvp
3884 * /
3885 * /
3886 * fdvp o fvp
3887 */
3888 if (fdvp == fvp) {
3889 error = EINVAL;
3890 goto out;
3891 }
3892
3893 /*
3894 * Make sure "from" vnode and its parent are changeable.
3895 */
3896 if ((fcp->c_bsdflags & (IMMUTABLE | APPEND)) || (fdcp->c_bsdflags & APPEND)) {
3897 error = EPERM;
3898 goto out;
3899 }
3900
3901 /*
3902 * If the destination parent directory is "sticky", then the
3903 * user must own the parent directory, or the destination of
3904 * the rename, otherwise the destination may not be changed
3905 * (except by root). This implements append-only directories.
3906 *
3907 * Note that checks for immutable and write access are done
3908 * by the call to hfs_removefile.
3909 */
3910 if (tvp && (tdcp->c_mode & S_ISTXT) &&
3911 (suser(vfs_context_ucred(tcnp->cn_context), NULL)) &&
3912 (kauth_cred_getuid(vfs_context_ucred(tcnp->cn_context)) != tdcp->c_uid) &&
3913 (hfs_owner_rights(hfsmp, tcp->c_uid, vfs_context_ucred(tcnp->cn_context), p, false)) ) {
3914 error = EPERM;
3915 goto out;
3916 }
3917
3918 /* Don't allow modification of the journal or journal_info_block */
3919 if (hfs_is_journal_file(hfsmp, fcp) ||
3920 (tcp && hfs_is_journal_file(hfsmp, tcp))) {
3921 error = EPERM;
3922 goto out;
3923 }
3924
3925 #if QUOTA
3926 if (tvp)
3927 (void)hfs_getinoquota(tcp);
3928 #endif
3929 /* Preflighting done, take fvp out of the name space. */
3930 cache_purge(fvp);
3931
3932 bzero(&from_desc, sizeof(from_desc));
3933 from_desc.cd_nameptr = (const u_int8_t *)fcnp->cn_nameptr;
3934 from_desc.cd_namelen = fcnp->cn_namelen;
3935 from_desc.cd_parentcnid = fdcp->c_fileid;
3936 from_desc.cd_flags = fcp->c_desc.cd_flags & ~(CD_HASBUF | CD_DECOMPOSED);
3937 from_desc.cd_cnid = fcp->c_cnid;
3938
3939 bzero(&to_desc, sizeof(to_desc));
3940 to_desc.cd_nameptr = (const u_int8_t *)tcnp->cn_nameptr;
3941 to_desc.cd_namelen = tcnp->cn_namelen;
3942 to_desc.cd_parentcnid = tdcp->c_fileid;
3943 to_desc.cd_flags = fcp->c_desc.cd_flags & ~(CD_HASBUF | CD_DECOMPOSED);
3944 to_desc.cd_cnid = fcp->c_cnid;
3945
3946 if ((error = hfs_start_transaction(hfsmp)) != 0) {
3947 goto out;
3948 }
3949 started_tr = 1;
3950
3951 /* hfs_vnop_link() and hfs_vnop_rename() set kHFSHasChildLinkMask
3952 * inside a journal transaction and without holding a cnode lock.
3953 * As setting of this bit depends on being in journal transaction for
3954 * concurrency, check this bit again after we start journal transaction for rename
3955 * to ensure that this directory does not have any descendant that
3956 * is a directory hard link.
3957 */
3958 if (vnode_isdir(fvp) && (fdvp != tdvp)) {
3959 if (fcp->c_attr.ca_recflags & kHFSHasChildLinkMask) {
3960 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
3961 if (cat_check_link_ancestry(hfsmp, tdcp->c_fileid, 0)) {
3962 error = EPERM;
3963 hfs_systemfile_unlock(hfsmp, lockflags);
3964 goto out;
3965 }
3966 hfs_systemfile_unlock(hfsmp, lockflags);
3967 }
3968 }
3969
3970 // if it's a hardlink then re-lookup the name so
3971 // that we get the correct cnid in from_desc (see
3972 // the comment in hfs_removefile for more details)
3973 //
3974 if (fcp->c_flag & C_HARDLINK) {
3975 struct cat_desc tmpdesc;
3976 cnid_t real_cnid;
3977
3978 tmpdesc.cd_nameptr = (const u_int8_t *)fcnp->cn_nameptr;
3979 tmpdesc.cd_namelen = fcnp->cn_namelen;
3980 tmpdesc.cd_parentcnid = fdcp->c_fileid;
3981 tmpdesc.cd_hint = fdcp->c_childhint;
3982 tmpdesc.cd_flags = fcp->c_desc.cd_flags & CD_ISDIR;
3983 tmpdesc.cd_encoding = 0;
3984
3985 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
3986
3987 if (cat_lookup(hfsmp, &tmpdesc, 0, NULL, NULL, NULL, &real_cnid) != 0) {
3988 hfs_systemfile_unlock(hfsmp, lockflags);
3989 goto out;
3990 }
3991
3992 // use the real cnid instead of whatever happened to be there
3993 from_desc.cd_cnid = real_cnid;
3994 hfs_systemfile_unlock(hfsmp, lockflags);
3995 }
3996
3997 /*
3998 * Reserve some space in the Catalog file.
3999 */
4000 if ((error = cat_preflight(hfsmp, CAT_RENAME + CAT_DELETE, &cookie, p))) {
4001 goto out;
4002 }
4003 got_cookie = 1;
4004
4005 /*
4006 * If the destination exists then it may need to be removed.
4007 *
4008 * Due to HFS's locking system, we should always move the
4009 * existing 'tvp' element to the hidden directory in hfs_vnop_rename.
4010 * Because the VNOP_LOOKUP call enters and exits the filesystem independently
4011 * of the actual vnop that it was trying to do (stat, link, readlink),
4012 * we must release the cnode lock of that element during the interim to
4013 * do MAC checking, vnode authorization, and other calls. In that time,
4014 * the item can be deleted (or renamed over). However, only in the rename
4015 * case is it inappropriate to return ENOENT from any of those calls. Either
4016 * the call should return information about the old element (stale), or get
4017 * information about the newer element that we are about to write in its place.
4018 *
4019 * HFS lookup has been modified to detect a rename and re-drive its
4020 * lookup internally. For other calls that have already succeeded in
4021 * their lookup call and are waiting to acquire the cnode lock in order
4022 * to proceed, that cnode lock will not fail due to the cnode being marked
4023 * C_NOEXISTS, because it won't have been marked as such. It will only
4024 * have C_DELETED. Thus, they will simply act on the stale open-unlinked
4025 * element. All future callers will get the new element.
4026 *
4027 * To implement this behavior, we pass the "only_unlink" argument to
4028 * hfs_removefile and hfs_removedir. This will result in the vnode acting
4029 * as though it is open-unlinked. Additionally, when we are done moving the
4030 * element to the hidden directory, we vnode_recycle the target so that it is
4031 * reclaimed as soon as possible. Reclaim and inactive are both
4032 * capable of clearing out unused blocks for an open-unlinked file or dir.
4033 */
4034 if (tvp) {
4035 /*
4036 * When fvp matches tvp they could be case variants
4037 * or matching hard links.
4038 */
4039 if (fvp == tvp) {
4040 if (!(fcp->c_flag & C_HARDLINK)) {
4041 /*
4042 * If they're not hardlinks, then fvp == tvp must mean we
4043 * are using case-insensitive HFS because case-sensitive would
4044 * not use the same vnode for both. In this case we just update
4045 * the catalog for: a -> A
4046 */
4047 goto skip_rm; /* simple case variant */
4048
4049 }
4050 /* For all cases below, we must be using hardlinks */
4051 else if ((fdvp != tdvp) ||
4052 (hfsmp->hfs_flags & HFS_CASE_SENSITIVE)) {
4053 /*
4054 * If the parent directories are not the same, AND the two items
4055 * are hardlinks, posix says to do nothing:
4056 * dir1/fred <-> dir2/bob and the op was mv dir1/fred -> dir2/bob
4057 * We just return 0 in this case.
4058 *
4059 * If case sensitivity is on, and we are using hardlinks
4060 * then renaming is supposed to do nothing.
4061 * dir1/fred <-> dir2/FRED, and op == mv dir1/fred -> dir2/FRED
4062 */
4063 goto out; /* matching hardlinks, nothing to do */
4064
4065 } else if (hfs_namecmp((const u_int8_t *)fcnp->cn_nameptr, fcnp->cn_namelen,
4066 (const u_int8_t *)tcnp->cn_nameptr, tcnp->cn_namelen) == 0) {
4067 /*
4068 * If we get here, then the following must be true:
4069 * a) We are running case-insensitive HFS+.
4070 * b) Both paths 'fvp' and 'tvp' are in the same parent directory.
4071 * c) the two names are case-variants of each other.
4072 *
4073 * In this case, we are really only dealing with a single catalog record
4074 * whose name is being updated.
4075 *
4076 * op is dir1/fred -> dir1/FRED
4077 *
4078 * We need to special case the name matching, because if
4079 * dir1/fred <-> dir1/bob were the two links, and the
4080 * op was dir1/fred -> dir1/bob
4081 * That would fail/do nothing.
4082 */
4083 goto skip_rm; /* case-variant hardlink in the same dir */
4084 } else {
4085 goto out; /* matching hardlink, nothing to do */
4086 }
4087 }
4088
4089
4090 if (vnode_isdir(tvp)) {
4091 /*
4092 * hfs_removedir will eventually call hfs_removefile on the directory
4093 * we're working on, because only hfs_removefile does the renaming of the
4094 * item to the hidden directory. The directory will stay around in the
4095 * hidden directory with C_DELETED until it gets an inactive or a reclaim.
4096 * That way, we can destroy all of the EAs as needed and allow new ones to be
4097 * written.
4098 */
4099 error = hfs_removedir(tdvp, tvp, tcnp, HFSRM_SKIP_RESERVE, 1);
4100 }
4101 else {
4102 error = hfs_removefile(tdvp, tvp, tcnp, 0, HFSRM_SKIP_RESERVE, 0, NULL, 1);
4103
4104 /*
4105 * If the destination file had a resource fork vnode, then we need to get rid of
4106 * its blocks when there are no more references to it. Because the call to
4107 * hfs_removefile above always open-unlinks things, we need to force an inactive/reclaim
4108 * on the resource fork vnode, in order to prevent block leaks. Otherwise,
4109 * the resource fork vnode could prevent the data fork vnode from going out of scope
4110 * because it holds a v_parent reference on it. So we mark it for termination
4111 * with a call to vnode_recycle. hfs_vnop_reclaim has been modified so that it
4112 * can clean up the blocks of open-unlinked files and resource forks.
4113 *
4114 * We can safely call vnode_recycle on the resource fork because we took an iocount
4115 * reference on it at the beginning of the function.
4116 */
4117
4118 if ((error == 0) && (tcp->c_flag & C_DELETED) && (tvp_rsrc)) {
4119 vnode_recycle(tvp_rsrc);
4120 }
4121 }
4122
4123 if (error) {
4124 goto out;
4125 }
4126
4127 tvp_deleted = 1;
4128
4129 /* Mark 'tcp' as being deleted due to a rename */
4130 tcp->c_flag |= C_RENAMED;
4131
4132 /*
4133 * Aggressively mark tvp/tcp for termination to ensure that we recover all blocks
4134 * as quickly as possible.
4135 */
4136 vnode_recycle(tvp);
4137 }
4138 skip_rm:
4139 /*
4140 * All done with tvp and fvp.
4141 *
4142 * We also jump to this point if there was no destination observed during lookup and namei.
4143 * However, because only iocounts are held at the VFS layer, there is nothing preventing a
4144 * competing thread from racing us and creating a file or dir at the destination of this rename
4145 * operation. If this occurs, it may cause us to get a spurious EEXIST out of the cat_rename
4146 * call below. To preserve rename's atomicity, we need to signal VFS to re-drive the
4147 * namei/lookup and restart the rename operation. EEXIST is an allowable errno to be bubbled
4148 * out of the rename syscall, but not for this reason, since it is a synonym errno for ENOTEMPTY.
4149 * To signal VFS, we return ERECYCLE (which is also used for lookup restarts). This errno
4150 * will be swallowed and it will restart the operation.
4151 */
4152
4153 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
4154 error = cat_rename(hfsmp, &from_desc, &tdcp->c_desc, &to_desc, &out_desc);
4155 hfs_systemfile_unlock(hfsmp, lockflags);
4156
4157 if (error) {
4158 if (error == EEXIST) {
4159 error = ERECYCLE;
4160 }
4161 goto out;
4162 }
4163
4164 /* Invalidate negative cache entries in the destination directory */
4165 if (tdcp->c_flag & C_NEG_ENTRIES) {
4166 cache_purge_negatives(tdvp);
4167 tdcp->c_flag &= ~C_NEG_ENTRIES;
4168 }
4169
4170 /* Update cnode's catalog descriptor */
4171 replace_desc(fcp, &out_desc);
4172 fcp->c_parentcnid = tdcp->c_fileid;
4173 fcp->c_hint = 0;
4174
4175 /* Now indicate this cnode needs to have date-added written to the finderinfo */
4176 fcp->c_flag |= C_NEEDS_DATEADDED;
4177 (void) hfs_update (fvp, 0);
4178
4179
4180 hfs_volupdate(hfsmp, vnode_isdir(fvp) ? VOL_RMDIR : VOL_RMFILE,
4181 (fdcp->c_cnid == kHFSRootFolderID));
4182 hfs_volupdate(hfsmp, vnode_isdir(fvp) ? VOL_MKDIR : VOL_MKFILE,
4183 (tdcp->c_cnid == kHFSRootFolderID));
4184
4185 /* Update both parent directories. */
4186 if (fdvp != tdvp) {
4187 if (vnode_isdir(fvp)) {
4188 /* If the source directory has directory hard link
4189 * descendants, set the kHFSHasChildLinkBit in the
4190 * destination parent hierarchy
4191 */
4192 if ((fcp->c_attr.ca_recflags & kHFSHasChildLinkMask) &&
4193 !(tdcp->c_attr.ca_recflags & kHFSHasChildLinkMask)) {
4194
4195 tdcp->c_attr.ca_recflags |= kHFSHasChildLinkMask;
4196
4197 error = cat_set_childlinkbit(hfsmp, tdcp->c_parentcnid);
4198 if (error) {
4199 printf ("hfs_vnop_rename: error updating parent chain for %u\n", tdcp->c_cnid);
4200 error = 0;
4201 }
4202 }
4203 INC_FOLDERCOUNT(hfsmp, tdcp->c_attr);
4204 DEC_FOLDERCOUNT(hfsmp, fdcp->c_attr);
4205 }
4206 tdcp->c_entries++;
4207 tdcp->c_dirchangecnt++;
4208 if (fdcp->c_entries > 0)
4209 fdcp->c_entries--;
4210 fdcp->c_dirchangecnt++;
4211 fdcp->c_touch_chgtime = TRUE;
4212 fdcp->c_touch_modtime = TRUE;
4213
4214 fdcp->c_flag |= C_FORCEUPDATE; // XXXdbg - force it out!
4215 (void) hfs_update(fdvp, 0);
4216 }
4217 tdcp->c_childhint = out_desc.cd_hint; /* Cache directory's location */
4218 tdcp->c_touch_chgtime = TRUE;
4219 tdcp->c_touch_modtime = TRUE;
4220
4221 tdcp->c_flag |= C_FORCEUPDATE; // XXXdbg - force it out!
4222 (void) hfs_update(tdvp, 0);
4223
4224 /* Update the vnode's name now that the rename has completed. */
4225 vnode_update_identity(fvp, tdvp, tcnp->cn_nameptr, tcnp->cn_namelen,
4226 tcnp->cn_hash, (VNODE_UPDATE_PARENT | VNODE_UPDATE_NAME));
4227
4228 /*
4229 * At this point, we may have a resource fork vnode attached to the
4230 * 'from' vnode. If it exists, we will want to update its name, because
4231 * it contains the old name + _PATH_RSRCFORKSPEC. ("/..namedfork/rsrc").
4232 *
4233 * Note that the only thing we need to update here is the name attached to
4234 * the vnode, since a resource fork vnode does not have a separate resource
4235 * cnode -- it's still 'fcp'.
4236 */
4237 if (fcp->c_rsrc_vp) {
4238 char* rsrc_path = NULL;
4239 int len;
4240
4241 /* Create a new temporary buffer that's going to hold the new name */
4242 MALLOC_ZONE (rsrc_path, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
4243 len = snprintf (rsrc_path, MAXPATHLEN, "%s%s", tcnp->cn_nameptr, _PATH_RSRCFORKSPEC);
4244 len = MIN(len, MAXPATHLEN);
4245
4246 /*
4247 * vnode_update_identity will do the following for us:
4248 * 1) release reference on the existing rsrc vnode's name.
4249 * 2) copy/insert new name into the name cache
4250 * 3) attach the new name to the resource vnode
4251 * 4) update the vnode's vid
4252 */
4253 vnode_update_identity (fcp->c_rsrc_vp, fvp, rsrc_path, len, 0, (VNODE_UPDATE_NAME | VNODE_UPDATE_CACHE));
4254
4255 /* Free the memory associated with the resource fork's name */
4256 FREE_ZONE (rsrc_path, MAXPATHLEN, M_NAMEI);
4257 }
4258 out:
4259 if (got_cookie) {
4260 cat_postflight(hfsmp, &cookie, p);
4261 }
4262 if (started_tr) {
4263 hfs_end_transaction(hfsmp);
4264 }
4265
4266 fdcp->c_flag &= ~C_DIR_MODIFICATION;
4267 wakeup((caddr_t)&fdcp->c_flag);
4268 if (fdvp != tdvp) {
4269 tdcp->c_flag &= ~C_DIR_MODIFICATION;
4270 wakeup((caddr_t)&tdcp->c_flag);
4271 }
4272
4273 if (took_trunc_lock) {
4274 hfs_unlock_truncate(VTOC(tvp), 0);
4275 }
4276
4277 hfs_unlockfour(fdcp, fcp, tdcp, tcp);
4278
4279 /* Now vnode_put the resource fork vnode if necessary */
4280 if (tvp_rsrc) {
4281 vnode_put(tvp_rsrc);
4282 tvp_rsrc = NULL;
4283 }
4284
4285 /* After tvp is removed the only acceptable error is EIO */
4286 if (error && tvp_deleted)
4287 error = EIO;
4288
4289 return (error);
4290 }
4291
4292
4293 /*
4294 * Make a directory.
4295 */
4296 int
4297 hfs_vnop_mkdir(struct vnop_mkdir_args *ap)
4298 {
4299 /***** HACK ALERT ********/
4300 ap->a_cnp->cn_flags |= MAKEENTRY;
4301 return hfs_makenode(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap, ap->a_context);
4302 }
4303
4304
4305 /*
4306 * Create a symbolic link.
4307 */
4308 int
4309 hfs_vnop_symlink(struct vnop_symlink_args *ap)
4310 {
4311 struct vnode **vpp = ap->a_vpp;
4312 struct vnode *dvp = ap->a_dvp;
4313 struct vnode *vp = NULL;
4314 struct cnode *cp = NULL;
4315 struct hfsmount *hfsmp;
4316 struct filefork *fp;
4317 struct buf *bp = NULL;
4318 char *datap;
4319 int started_tr = 0;
4320 u_int32_t len;
4321 int error;
4322
4323 /* HFS standard disks don't support symbolic links */
4324 if (VTOVCB(dvp)->vcbSigWord != kHFSPlusSigWord)
4325 return (ENOTSUP);
4326
4327 /* Check for empty target name */
4328 if (ap->a_target[0] == 0)
4329 return (EINVAL);
4330
4331 hfsmp = VTOHFS(dvp);
4332 len = strlen(ap->a_target);
4333
4334 /* Check for free space */
4335 if (((u_int64_t)hfs_freeblks(hfsmp, 0) * (u_int64_t)hfsmp->blockSize) < len) {
4336 return (ENOSPC);
4337 }
4338
4339 /* Create the vnode */
4340 ap->a_vap->va_mode |= S_IFLNK;
4341 if ((error = hfs_makenode(dvp, vpp, ap->a_cnp, ap->a_vap, ap->a_context))) {
4342 goto out;
4343 }
4344 vp = *vpp;
4345 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) {
4346 goto out;
4347 }
4348 cp = VTOC(vp);
4349 fp = VTOF(vp);
4350
4351 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
4352 goto out;
4353 }
4354
4355 #if QUOTA
4356 (void)hfs_getinoquota(cp);
4357 #endif /* QUOTA */
4358
4359 if ((error = hfs_start_transaction(hfsmp)) != 0) {
4360 goto out;
4361 }
4362 started_tr = 1;
4363
4364 /*
4365 * Allocate space for the link.
4366 *
4367 * Since we're already inside a transaction,
4368 * tell hfs_truncate to skip the ubc_setsize.
4369 *
4370 * Don't need truncate lock since a symlink is treated as a system file.
4371 */
4372 error = hfs_truncate(vp, len, IO_NOZEROFILL, 1, 0, ap->a_context);
4373
4374 /* On errors, remove the symlink file */
4375 if (error) {
4376 /*
4377 * End the transaction so we don't re-take the cnode lock
4378 * below while inside a transaction (lock order violation).
4379 */
4380 hfs_end_transaction(hfsmp);
4381
4382 /* hfs_removefile() requires holding the truncate lock */
4383 hfs_unlock(cp);
4384 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK);
4385 hfs_lock(cp, HFS_FORCE_LOCK);
4386
4387 if (hfs_start_transaction(hfsmp) != 0) {
4388 started_tr = 0;
4389 hfs_unlock_truncate(cp, TRUE);
4390 goto out;
4391 }
4392
4393 (void) hfs_removefile(dvp, vp, ap->a_cnp, 0, 0, 0, NULL, 0);
4394 hfs_unlock_truncate(cp, 0);
4395 goto out;
4396 }
4397
4398 /* Write the link to disk */
4399 bp = buf_getblk(vp, (daddr64_t)0, roundup((int)fp->ff_size, hfsmp->hfs_physical_block_size),
4400 0, 0, BLK_META);
4401 if (hfsmp->jnl) {
4402 journal_modify_block_start(hfsmp->jnl, bp);
4403 }
4404 datap = (char *)buf_dataptr(bp);
4405 bzero(datap, buf_size(bp));
4406 bcopy(ap->a_target, datap, len);
4407
4408 if (hfsmp->jnl) {
4409 journal_modify_block_end(hfsmp->jnl, bp, NULL, NULL);
4410 } else {
4411 buf_bawrite(bp);
4412 }
4413 /*
4414 * We defered the ubc_setsize for hfs_truncate
4415 * since we were inside a transaction.
4416 *
4417 * We don't need to drop the cnode lock here
4418 * since this is a symlink.
4419 */
4420 ubc_setsize(vp, len);
4421 out:
4422 if (started_tr)
4423 hfs_end_transaction(hfsmp);
4424 if ((cp != NULL) && (vp != NULL)) {
4425 hfs_unlock(cp);
4426 }
4427 if (error) {
4428 if (vp) {
4429 vnode_put(vp);
4430 }
4431 *vpp = NULL;
4432 }
4433 return (error);
4434 }
4435
4436
4437 /* structures to hold a "." or ".." directory entry */
4438 struct hfs_stddotentry {
4439 u_int32_t d_fileno; /* unique file number */
4440 u_int16_t d_reclen; /* length of this structure */
4441 u_int8_t d_type; /* dirent file type */
4442 u_int8_t d_namlen; /* len of filename */
4443 char d_name[4]; /* "." or ".." */
4444 };
4445
4446 struct hfs_extdotentry {
4447 u_int64_t d_fileno; /* unique file number */
4448 u_int64_t d_seekoff; /* seek offset (optional, used by servers) */
4449 u_int16_t d_reclen; /* length of this structure */
4450 u_int16_t d_namlen; /* len of filename */
4451 u_int8_t d_type; /* dirent file type */
4452 u_char d_name[3]; /* "." or ".." */
4453 };
4454
4455 typedef union {
4456 struct hfs_stddotentry std;
4457 struct hfs_extdotentry ext;
4458 } hfs_dotentry_t;
4459
4460 /*
4461 * hfs_vnop_readdir reads directory entries into the buffer pointed
4462 * to by uio, in a filesystem independent format. Up to uio_resid
4463 * bytes of data can be transferred. The data in the buffer is a
4464 * series of packed dirent structures where each one contains the
4465 * following entries:
4466 *
4467 * u_int32_t d_fileno; // file number of entry
4468 * u_int16_t d_reclen; // length of this record
4469 * u_int8_t d_type; // file type
4470 * u_int8_t d_namlen; // length of string in d_name
4471 * char d_name[MAXNAMELEN+1]; // null terminated file name
4472 *
4473 * The current position (uio_offset) refers to the next block of
4474 * entries. The offset can only be set to a value previously
4475 * returned by hfs_vnop_readdir or zero. This offset does not have
4476 * to match the number of bytes returned (in uio_resid).
4477 *
4478 * In fact, the offset used by HFS is essentially an index (26 bits)
4479 * with a tag (6 bits). The tag is for associating the next request
4480 * with the current request. This enables us to have multiple threads
4481 * reading the directory while the directory is also being modified.
4482 *
4483 * Each tag/index pair is tied to a unique directory hint. The hint
4484 * contains information (filename) needed to build the catalog b-tree
4485 * key for finding the next set of entries.
4486 *
4487 * If the directory is marked as deleted-but-in-use (cp->c_flag & C_DELETED),
4488 * do NOT synthesize entries for "." and "..".
4489 */
4490 int
4491 hfs_vnop_readdir(ap)
4492 struct vnop_readdir_args /* {
4493 vnode_t a_vp;
4494 uio_t a_uio;
4495 int a_flags;
4496 int *a_eofflag;
4497 int *a_numdirent;
4498 vfs_context_t a_context;
4499 } */ *ap;
4500 {
4501 struct vnode *vp = ap->a_vp;
4502 uio_t uio = ap->a_uio;
4503 struct cnode *cp;
4504 struct hfsmount *hfsmp;
4505 directoryhint_t *dirhint = NULL;
4506 directoryhint_t localhint;
4507 off_t offset;
4508 off_t startoffset;
4509 int error = 0;
4510 int eofflag = 0;
4511 user_addr_t user_start = 0;
4512 user_size_t user_len = 0;
4513 int index;
4514 unsigned int tag;
4515 int items;
4516 int lockflags;
4517 int extended;
4518 int nfs_cookies;
4519 cnid_t cnid_hint = 0;
4520
4521 items = 0;
4522 startoffset = offset = uio_offset(uio);
4523 extended = (ap->a_flags & VNODE_READDIR_EXTENDED);
4524 nfs_cookies = extended && (ap->a_flags & VNODE_READDIR_REQSEEKOFF);
4525
4526 /* Sanity check the uio data. */
4527 if (uio_iovcnt(uio) > 1)
4528 return (EINVAL);
4529
4530 if (VTOC(vp)->c_bsdflags & UF_COMPRESSED) {
4531 int compressed = hfs_file_is_compressed(VTOC(vp), 0); /* 0 == take the cnode lock */
4532 if (VTOCMP(vp) != NULL && !compressed) {
4533 error = check_for_dataless_file(vp, NAMESPACE_HANDLER_READ_OP);
4534 if (error) {
4535 return error;
4536 }
4537 }
4538 }
4539
4540 cp = VTOC(vp);
4541 hfsmp = VTOHFS(vp);
4542
4543 /* Note that the dirhint calls require an exclusive lock. */
4544 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK)))
4545 return (error);
4546
4547 /* Pick up cnid hint (if any). */
4548 if (nfs_cookies) {
4549 cnid_hint = (cnid_t)(uio_offset(uio) >> 32);
4550 uio_setoffset(uio, uio_offset(uio) & 0x00000000ffffffffLL);
4551 if (cnid_hint == INT_MAX) { /* searching pass the last item */
4552 eofflag = 1;
4553 goto out;
4554 }
4555 }
4556 /*
4557 * Synthesize entries for "." and "..", unless the directory has
4558 * been deleted, but not closed yet (lazy delete in progress).
4559 */
4560 if (offset == 0 && !(cp->c_flag & C_DELETED)) {
4561 hfs_dotentry_t dotentry[2];
4562 size_t uiosize;
4563
4564 if (extended) {
4565 struct hfs_extdotentry *entry = &dotentry[0].ext;
4566
4567 entry->d_fileno = cp->c_cnid;
4568 entry->d_reclen = sizeof(struct hfs_extdotentry);
4569 entry->d_type = DT_DIR;
4570 entry->d_namlen = 1;
4571 entry->d_name[0] = '.';
4572 entry->d_name[1] = '\0';
4573 entry->d_name[2] = '\0';
4574 entry->d_seekoff = 1;
4575
4576 ++entry;
4577 entry->d_fileno = cp->c_parentcnid;
4578 entry->d_reclen = sizeof(struct hfs_extdotentry);
4579 entry->d_type = DT_DIR;
4580 entry->d_namlen = 2;
4581 entry->d_name[0] = '.';
4582 entry->d_name[1] = '.';
4583 entry->d_name[2] = '\0';
4584 entry->d_seekoff = 2;
4585 uiosize = 2 * sizeof(struct hfs_extdotentry);
4586 } else {
4587 struct hfs_stddotentry *entry = &dotentry[0].std;
4588
4589 entry->d_fileno = cp->c_cnid;
4590 entry->d_reclen = sizeof(struct hfs_stddotentry);
4591 entry->d_type = DT_DIR;
4592 entry->d_namlen = 1;
4593 *(int *)&entry->d_name[0] = 0;
4594 entry->d_name[0] = '.';
4595
4596 ++entry;
4597 entry->d_fileno = cp->c_parentcnid;
4598 entry->d_reclen = sizeof(struct hfs_stddotentry);
4599 entry->d_type = DT_DIR;
4600 entry->d_namlen = 2;
4601 *(int *)&entry->d_name[0] = 0;
4602 entry->d_name[0] = '.';
4603 entry->d_name[1] = '.';
4604 uiosize = 2 * sizeof(struct hfs_stddotentry);
4605 }
4606 if ((error = uiomove((caddr_t)&dotentry, uiosize, uio))) {
4607 goto out;
4608 }
4609 offset += 2;
4610 }
4611
4612 /* If there are no real entries then we're done. */
4613 if (cp->c_entries == 0) {
4614 error = 0;
4615 eofflag = 1;
4616 uio_setoffset(uio, offset);
4617 goto seekoffcalc;
4618 }
4619
4620 //
4621 // We have to lock the user's buffer here so that we won't
4622 // fault on it after we've acquired a shared lock on the
4623 // catalog file. The issue is that you can get a 3-way
4624 // deadlock if someone else starts a transaction and then
4625 // tries to lock the catalog file but can't because we're
4626 // here and we can't service our page fault because VM is
4627 // blocked trying to start a transaction as a result of
4628 // trying to free up pages for our page fault. It's messy
4629 // but it does happen on dual-processors that are paging
4630 // heavily (see radar 3082639 for more info). By locking
4631 // the buffer up-front we prevent ourselves from faulting
4632 // while holding the shared catalog file lock.
4633 //
4634 // Fortunately this and hfs_search() are the only two places
4635 // currently (10/30/02) that can fault on user data with a
4636 // shared lock on the catalog file.
4637 //
4638 if (hfsmp->jnl && uio_isuserspace(uio)) {
4639 user_start = uio_curriovbase(uio);
4640 user_len = uio_curriovlen(uio);
4641
4642 if ((error = vslock(user_start, user_len)) != 0) {
4643 user_start = 0;
4644 goto out;
4645 }
4646 }
4647 /* Convert offset into a catalog directory index. */
4648 index = (offset & HFS_INDEX_MASK) - 2;
4649 tag = offset & ~HFS_INDEX_MASK;
4650
4651 /* Lock catalog during cat_findname and cat_getdirentries. */
4652 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
4653
4654 /* When called from NFS, try and resolve a cnid hint. */
4655 if (nfs_cookies && cnid_hint != 0) {
4656 if (cat_findname(hfsmp, cnid_hint, &localhint.dh_desc) == 0) {
4657 if ( localhint.dh_desc.cd_parentcnid == cp->c_fileid) {
4658 localhint.dh_index = index - 1;
4659 localhint.dh_time = 0;
4660 bzero(&localhint.dh_link, sizeof(localhint.dh_link));
4661 dirhint = &localhint; /* don't forget to release the descriptor */
4662 } else {
4663 cat_releasedesc(&localhint.dh_desc);
4664 }
4665 }
4666 }
4667
4668 /* Get a directory hint (cnode must be locked exclusive) */
4669 if (dirhint == NULL) {
4670 dirhint = hfs_getdirhint(cp, ((index - 1) & HFS_INDEX_MASK) | tag, 0);
4671
4672 /* Hide tag from catalog layer. */
4673 dirhint->dh_index &= HFS_INDEX_MASK;
4674 if (dirhint->dh_index == HFS_INDEX_MASK) {
4675 dirhint->dh_index = -1;
4676 }
4677 }
4678
4679 if (index == 0) {
4680 dirhint->dh_threadhint = cp->c_dirthreadhint;
4681 }
4682 else {
4683 /*
4684 * If we have a non-zero index, there is a possibility that during the last
4685 * call to hfs_vnop_readdir we hit EOF for this directory. If that is the case
4686 * then we don't want to return any new entries for the caller. Just return 0
4687 * items, mark the eofflag, and bail out. Because we won't have done any work, the
4688 * code at the end of the function will release the dirhint for us.
4689 *
4690 * Don't forget to unlock the catalog lock on the way out, too.
4691 */
4692 if (dirhint->dh_desc.cd_flags & CD_EOF) {
4693 error = 0;
4694 eofflag = 1;
4695 uio_setoffset(uio, startoffset);
4696 hfs_systemfile_unlock (hfsmp, lockflags);
4697
4698 goto seekoffcalc;
4699 }
4700 }
4701
4702 /* Pack the buffer with dirent entries. */
4703 error = cat_getdirentries(hfsmp, cp->c_entries, dirhint, uio, ap->a_flags, &items, &eofflag);
4704
4705 if (index == 0 && error == 0) {
4706 cp->c_dirthreadhint = dirhint->dh_threadhint;
4707 }
4708
4709 hfs_systemfile_unlock(hfsmp, lockflags);
4710
4711 if (error != 0) {
4712 goto out;
4713 }
4714
4715 /* Get index to the next item */
4716 index += items;
4717
4718 if (items >= (int)cp->c_entries) {
4719 eofflag = 1;
4720 }
4721
4722 /* Convert catalog directory index back into an offset. */
4723 while (tag == 0)
4724 tag = (++cp->c_dirhinttag) << HFS_INDEX_BITS;
4725 uio_setoffset(uio, (index + 2) | tag);
4726 dirhint->dh_index |= tag;
4727
4728 seekoffcalc:
4729 cp->c_touch_acctime = TRUE;
4730
4731 if (ap->a_numdirent) {
4732 if (startoffset == 0)
4733 items += 2;
4734 *ap->a_numdirent = items;
4735 }
4736
4737 out:
4738 if (user_start) {
4739 vsunlock(user_start, user_len, TRUE);
4740 }
4741 /* If we didn't do anything then go ahead and dump the hint. */
4742 if ((dirhint != NULL) &&
4743 (dirhint != &localhint) &&
4744 (uio_offset(uio) == startoffset)) {
4745 hfs_reldirhint(cp, dirhint);
4746 eofflag = 1;
4747 }
4748 if (ap->a_eofflag) {
4749 *ap->a_eofflag = eofflag;
4750 }
4751 if (dirhint == &localhint) {
4752 cat_releasedesc(&localhint.dh_desc);
4753 }
4754 hfs_unlock(cp);
4755 return (error);
4756 }
4757
4758
4759 /*
4760 * Read contents of a symbolic link.
4761 */
4762 int
4763 hfs_vnop_readlink(ap)
4764 struct vnop_readlink_args /* {
4765 struct vnode *a_vp;
4766 struct uio *a_uio;
4767 vfs_context_t a_context;
4768 } */ *ap;
4769 {
4770 struct vnode *vp = ap->a_vp;
4771 struct cnode *cp;
4772 struct filefork *fp;
4773 int error;
4774
4775 if (!vnode_islnk(vp))
4776 return (EINVAL);
4777
4778 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK)))
4779 return (error);
4780 cp = VTOC(vp);
4781 fp = VTOF(vp);
4782
4783 /* Zero length sym links are not allowed */
4784 if (fp->ff_size == 0 || fp->ff_size > MAXPATHLEN) {
4785 error = EINVAL;
4786 goto exit;
4787 }
4788
4789 /* Cache the path so we don't waste buffer cache resources */
4790 if (fp->ff_symlinkptr == NULL) {
4791 struct buf *bp = NULL;
4792
4793 MALLOC(fp->ff_symlinkptr, char *, fp->ff_size, M_TEMP, M_WAITOK);
4794 if (fp->ff_symlinkptr == NULL) {
4795 error = ENOMEM;
4796 goto exit;
4797 }
4798 error = (int)buf_meta_bread(vp, (daddr64_t)0,
4799 roundup((int)fp->ff_size, VTOHFS(vp)->hfs_physical_block_size),
4800 vfs_context_ucred(ap->a_context), &bp);
4801 if (error) {
4802 if (bp)
4803 buf_brelse(bp);
4804 if (fp->ff_symlinkptr) {
4805 FREE(fp->ff_symlinkptr, M_TEMP);
4806 fp->ff_symlinkptr = NULL;
4807 }
4808 goto exit;
4809 }
4810 bcopy((char *)buf_dataptr(bp), fp->ff_symlinkptr, (size_t)fp->ff_size);
4811
4812 if (VTOHFS(vp)->jnl && (buf_flags(bp) & B_LOCKED) == 0) {
4813 buf_markinvalid(bp); /* data no longer needed */
4814 }
4815 buf_brelse(bp);
4816 }
4817 error = uiomove((caddr_t)fp->ff_symlinkptr, (int)fp->ff_size, ap->a_uio);
4818
4819 /*
4820 * Keep track blocks read
4821 */
4822 if ((VTOHFS(vp)->hfc_stage == HFC_RECORDING) && (error == 0)) {
4823
4824 /*
4825 * If this file hasn't been seen since the start of
4826 * the current sampling period then start over.
4827 */
4828 if (cp->c_atime < VTOHFS(vp)->hfc_timebase)
4829 VTOF(vp)->ff_bytesread = fp->ff_size;
4830 else
4831 VTOF(vp)->ff_bytesread += fp->ff_size;
4832
4833 // if (VTOF(vp)->ff_bytesread > fp->ff_size)
4834 // cp->c_touch_acctime = TRUE;
4835 }
4836
4837 exit:
4838 hfs_unlock(cp);
4839 return (error);
4840 }
4841
4842
4843 /*
4844 * Get configurable pathname variables.
4845 */
4846 int
4847 hfs_vnop_pathconf(ap)
4848 struct vnop_pathconf_args /* {
4849 struct vnode *a_vp;
4850 int a_name;
4851 int *a_retval;
4852 vfs_context_t a_context;
4853 } */ *ap;
4854 {
4855 switch (ap->a_name) {
4856 case _PC_LINK_MAX:
4857 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_STANDARD)
4858 *ap->a_retval = 1;
4859 else
4860 *ap->a_retval = HFS_LINK_MAX;
4861 break;
4862 case _PC_NAME_MAX:
4863 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_STANDARD)
4864 *ap->a_retval = kHFSMaxFileNameChars; /* 31 */
4865 else
4866 *ap->a_retval = kHFSPlusMaxFileNameChars; /* 255 */
4867 break;
4868 case _PC_PATH_MAX:
4869 *ap->a_retval = PATH_MAX; /* 1024 */
4870 break;
4871 case _PC_PIPE_BUF:
4872 *ap->a_retval = PIPE_BUF;
4873 break;
4874 case _PC_CHOWN_RESTRICTED:
4875 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */
4876 break;
4877 case _PC_NO_TRUNC:
4878 *ap->a_retval = 200112; /* _POSIX_NO_TRUNC */
4879 break;
4880 case _PC_NAME_CHARS_MAX:
4881 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_STANDARD)
4882 *ap->a_retval = kHFSMaxFileNameChars; /* 31 */
4883 else
4884 *ap->a_retval = kHFSPlusMaxFileNameChars; /* 255 */
4885 break;
4886 case _PC_CASE_SENSITIVE:
4887 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_CASE_SENSITIVE)
4888 *ap->a_retval = 1;
4889 else
4890 *ap->a_retval = 0;
4891 break;
4892 case _PC_CASE_PRESERVING:
4893 *ap->a_retval = 1;
4894 break;
4895 case _PC_FILESIZEBITS:
4896 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_STANDARD)
4897 *ap->a_retval = 32;
4898 else
4899 *ap->a_retval = 64; /* number of bits to store max file size */
4900 break;
4901 case _PC_XATTR_SIZE_BITS:
4902 /* Number of bits to store maximum extended attribute size */
4903 *ap->a_retval = HFS_XATTR_SIZE_BITS;
4904 break;
4905 default:
4906 return (EINVAL);
4907 }
4908
4909 return (0);
4910 }
4911
4912
4913 /*
4914 * Update a cnode's on-disk metadata.
4915 *
4916 * If waitfor is set, then wait for the disk write of
4917 * the node to complete.
4918 *
4919 * The cnode must be locked exclusive
4920 */
4921 int
4922 hfs_update(struct vnode *vp, __unused int waitfor)
4923 {
4924 struct cnode *cp = VTOC(vp);
4925 struct proc *p;
4926 struct cat_fork *dataforkp = NULL;
4927 struct cat_fork *rsrcforkp = NULL;
4928 struct cat_fork datafork;
4929 struct cat_fork rsrcfork;
4930 struct hfsmount *hfsmp;
4931 int lockflags;
4932 int error;
4933
4934 p = current_proc();
4935 hfsmp = VTOHFS(vp);
4936
4937 if (((vnode_issystem(vp) && (cp->c_cnid < kHFSFirstUserCatalogNodeID))) ||
4938 hfsmp->hfs_catalog_vp == NULL){
4939 return (0);
4940 }
4941 if ((hfsmp->hfs_flags & HFS_READ_ONLY) || (cp->c_mode == 0)) {
4942 cp->c_flag &= ~C_MODIFIED;
4943 cp->c_touch_acctime = 0;
4944 cp->c_touch_chgtime = 0;
4945 cp->c_touch_modtime = 0;
4946 return (0);
4947 }
4948
4949 hfs_touchtimes(hfsmp, cp);
4950
4951 /* Nothing to update. */
4952 if ((cp->c_flag & (C_MODIFIED | C_FORCEUPDATE)) == 0) {
4953 return (0);
4954 }
4955
4956 if (cp->c_datafork)
4957 dataforkp = &cp->c_datafork->ff_data;
4958 if (cp->c_rsrcfork)
4959 rsrcforkp = &cp->c_rsrcfork->ff_data;
4960
4961 /*
4962 * For delayed allocations updates are
4963 * postponed until an fsync or the file
4964 * gets written to disk.
4965 *
4966 * Deleted files can defer meta data updates until inactive.
4967 *
4968 * If we're ever called with the C_FORCEUPDATE flag though
4969 * we have to do the update.
4970 */
4971 if (ISSET(cp->c_flag, C_FORCEUPDATE) == 0 &&
4972 (ISSET(cp->c_flag, C_DELETED) ||
4973 (dataforkp && cp->c_datafork->ff_unallocblocks) ||
4974 (rsrcforkp && cp->c_rsrcfork->ff_unallocblocks))) {
4975 // cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_UPDATE);
4976 cp->c_flag |= C_MODIFIED;
4977
4978 return (0);
4979 }
4980
4981 if ((error = hfs_start_transaction(hfsmp)) != 0) {
4982 return error;
4983 }
4984
4985 /*
4986 * Modify the values passed to cat_update based on whether or not
4987 * the file has invalid ranges or borrowed blocks.
4988 */
4989 if (dataforkp) {
4990 off_t numbytes = 0;
4991
4992 /* copy the datafork into a temporary copy so we don't pollute the cnode's */
4993 bcopy(dataforkp, &datafork, sizeof(datafork));
4994 dataforkp = &datafork;
4995
4996 /*
4997 * If there are borrowed blocks, ensure that they are subtracted
4998 * from the total block count before writing the cnode entry to disk.
4999 * Only extents that have actually been marked allocated in the bitmap
5000 * should be reflected in the total block count for this fork.
5001 */
5002 if (cp->c_datafork->ff_unallocblocks != 0) {
5003 // make sure that we don't assign a negative block count
5004 if (cp->c_datafork->ff_blocks < cp->c_datafork->ff_unallocblocks) {
5005 panic("hfs: ff_blocks %d is less than unalloc blocks %d\n",
5006 cp->c_datafork->ff_blocks, cp->c_datafork->ff_unallocblocks);
5007 }
5008
5009 /* Also cap the LEOF to the total number of bytes that are allocated. */
5010 datafork.cf_blocks = (cp->c_datafork->ff_blocks - cp->c_datafork->ff_unallocblocks);
5011 datafork.cf_size = datafork.cf_blocks * HFSTOVCB(hfsmp)->blockSize;
5012 }
5013
5014 /*
5015 * For files with invalid ranges (holes) the on-disk
5016 * field representing the size of the file (cf_size)
5017 * must be no larger than the start of the first hole.
5018 * However, note that if the first invalid range exists
5019 * solely within borrowed blocks, then our LEOF and block
5020 * count should both be zero. As a result, set it to the
5021 * min of the current cf_size and the start of the first
5022 * invalid range, because it may have already been reduced
5023 * to zero by the borrowed blocks check above.
5024 */
5025 if (!TAILQ_EMPTY(&cp->c_datafork->ff_invalidranges)) {
5026 numbytes = TAILQ_FIRST(&cp->c_datafork->ff_invalidranges)->rl_start;
5027 datafork.cf_size = MIN((numbytes), (datafork.cf_size));
5028 }
5029 }
5030
5031 /*
5032 * For resource forks with delayed allocations, make sure
5033 * the block count and file size match the number of blocks
5034 * actually allocated to the file on disk.
5035 */
5036 if (rsrcforkp && (cp->c_rsrcfork->ff_unallocblocks != 0)) {
5037 bcopy(rsrcforkp, &rsrcfork, sizeof(rsrcfork));
5038 rsrcfork.cf_blocks = (cp->c_rsrcfork->ff_blocks - cp->c_rsrcfork->ff_unallocblocks);
5039 rsrcfork.cf_size = rsrcfork.cf_blocks * HFSTOVCB(hfsmp)->blockSize;
5040 rsrcforkp = &rsrcfork;
5041 }
5042
5043 /*
5044 * Lock the Catalog b-tree file.
5045 */
5046 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
5047
5048 /* XXX - waitfor is not enforced */
5049 error = cat_update(hfsmp, &cp->c_desc, &cp->c_attr, dataforkp, rsrcforkp);
5050
5051 hfs_systemfile_unlock(hfsmp, lockflags);
5052
5053 /* After the updates are finished, clear the flags */
5054 cp->c_flag &= ~(C_MODIFIED | C_FORCEUPDATE);
5055
5056 hfs_end_transaction(hfsmp);
5057
5058 return (error);
5059 }
5060
5061 /*
5062 * Allocate a new node
5063 * Note - Function does not create and return a vnode for whiteout creation.
5064 */
5065 int
5066 hfs_makenode(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
5067 struct vnode_attr *vap, vfs_context_t ctx)
5068 {
5069 struct cnode *cp = NULL;
5070 struct cnode *dcp = NULL;
5071 struct vnode *tvp;
5072 struct hfsmount *hfsmp;
5073 struct cat_desc in_desc, out_desc;
5074 struct cat_attr attr;
5075 struct timeval tv;
5076 int lockflags;
5077 int error, started_tr = 0;
5078 enum vtype vnodetype;
5079 int mode;
5080 int newvnode_flags = 0;
5081 u_int32_t gnv_flags = 0;
5082 int protectable_target = 0;
5083
5084 #if CONFIG_PROTECT
5085 struct cprotect *entry = NULL;
5086 uint32_t cp_class = 0;
5087 if (VATTR_IS_ACTIVE(vap, va_dataprotect_class)) {
5088 cp_class = vap->va_dataprotect_class;
5089 }
5090 int protected_mount = 0;
5091 #endif
5092
5093
5094 if ((error = hfs_lock(VTOC(dvp), HFS_EXCLUSIVE_LOCK)))
5095 return (error);
5096
5097 /* set the cnode pointer only after successfully acquiring lock */
5098 dcp = VTOC(dvp);
5099
5100 /* Don't allow creation of new entries in open-unlinked directories */
5101 if ((error = hfs_checkdeleted(dcp))) {
5102 hfs_unlock(dcp);
5103 return error;
5104 }
5105
5106 dcp->c_flag |= C_DIR_MODIFICATION;
5107
5108 hfsmp = VTOHFS(dvp);
5109
5110 *vpp = NULL;
5111 tvp = NULL;
5112 out_desc.cd_flags = 0;
5113 out_desc.cd_nameptr = NULL;
5114
5115 vnodetype = vap->va_type;
5116 if (vnodetype == VNON)
5117 vnodetype = VREG;
5118 mode = MAKEIMODE(vnodetype, vap->va_mode);
5119
5120 if (S_ISDIR (mode) || S_ISREG (mode)) {
5121 protectable_target = 1;
5122 }
5123
5124
5125 /* Check if were out of usable disk space. */
5126 if ((hfs_freeblks(hfsmp, 1) == 0) && (vfs_context_suser(ctx) != 0)) {
5127 error = ENOSPC;
5128 goto exit;
5129 }
5130
5131 microtime(&tv);
5132
5133 /* Setup the default attributes */
5134 bzero(&attr, sizeof(attr));
5135 attr.ca_mode = mode;
5136 attr.ca_linkcount = 1;
5137 if (VATTR_IS_ACTIVE(vap, va_rdev)) {
5138 attr.ca_rdev = vap->va_rdev;
5139 }
5140 if (VATTR_IS_ACTIVE(vap, va_create_time)) {
5141 VATTR_SET_SUPPORTED(vap, va_create_time);
5142 attr.ca_itime = vap->va_create_time.tv_sec;
5143 } else {
5144 attr.ca_itime = tv.tv_sec;
5145 }
5146 if ((hfsmp->hfs_flags & HFS_STANDARD) && gTimeZone.tz_dsttime) {
5147 attr.ca_itime += 3600; /* Same as what hfs_update does */
5148 }
5149 attr.ca_atime = attr.ca_ctime = attr.ca_mtime = attr.ca_itime;
5150 attr.ca_atimeondisk = attr.ca_atime;
5151 if (VATTR_IS_ACTIVE(vap, va_flags)) {
5152 VATTR_SET_SUPPORTED(vap, va_flags);
5153 attr.ca_flags = vap->va_flags;
5154 }
5155
5156 /*
5157 * HFS+ only: all files get ThreadExists
5158 * HFSX only: dirs get HasFolderCount
5159 */
5160 if (!(hfsmp->hfs_flags & HFS_STANDARD)) {
5161 if (vnodetype == VDIR) {
5162 if (hfsmp->hfs_flags & HFS_FOLDERCOUNT)
5163 attr.ca_recflags = kHFSHasFolderCountMask;
5164 } else {
5165 attr.ca_recflags = kHFSThreadExistsMask;
5166 }
5167 }
5168
5169 #if CONFIG_PROTECT
5170 if (cp_fs_protected(hfsmp->hfs_mp)) {
5171 protected_mount = 1;
5172 }
5173 /*
5174 * On a content-protected HFS+/HFSX filesystem, files and directories
5175 * cannot be created without atomically setting/creating the EA that
5176 * contains the protection class metadata and keys at the same time, in
5177 * the same transaction. As a result, pre-set the "EAs exist" flag
5178 * on the cat_attr for protectable catalog record creations. This will
5179 * cause the cnode creation routine in hfs_getnewvnode to mark the cnode
5180 * as having EAs.
5181 */
5182 if ((protected_mount) && (protectable_target)) {
5183 attr.ca_recflags |= kHFSHasAttributesMask;
5184 }
5185 #endif
5186
5187
5188 /*
5189 * Add the date added to the item. See above, as
5190 * all of the dates are set to the itime.
5191 */
5192 hfs_write_dateadded (&attr, attr.ca_atime);
5193
5194 attr.ca_uid = vap->va_uid;
5195 attr.ca_gid = vap->va_gid;
5196 VATTR_SET_SUPPORTED(vap, va_mode);
5197 VATTR_SET_SUPPORTED(vap, va_uid);
5198 VATTR_SET_SUPPORTED(vap, va_gid);
5199
5200 #if QUOTA
5201 /* check to see if this node's creation would cause us to go over
5202 * quota. If so, abort this operation.
5203 */
5204 if (hfsmp->hfs_flags & HFS_QUOTAS) {
5205 if ((error = hfs_quotacheck(hfsmp, 1, attr.ca_uid, attr.ca_gid,
5206 vfs_context_ucred(ctx)))) {
5207 goto exit;
5208 }
5209 }
5210 #endif
5211
5212
5213 /* Tag symlinks with a type and creator. */
5214 if (vnodetype == VLNK) {
5215 struct FndrFileInfo *fip;
5216
5217 fip = (struct FndrFileInfo *)&attr.ca_finderinfo;
5218 fip->fdType = SWAP_BE32(kSymLinkFileType);
5219 fip->fdCreator = SWAP_BE32(kSymLinkCreator);
5220 }
5221 if (cnp->cn_flags & ISWHITEOUT)
5222 attr.ca_flags |= UF_OPAQUE;
5223
5224 /* Setup the descriptor */
5225 in_desc.cd_nameptr = (const u_int8_t *)cnp->cn_nameptr;
5226 in_desc.cd_namelen = cnp->cn_namelen;
5227 in_desc.cd_parentcnid = dcp->c_fileid;
5228 in_desc.cd_flags = S_ISDIR(mode) ? CD_ISDIR : 0;
5229 in_desc.cd_hint = dcp->c_childhint;
5230 in_desc.cd_encoding = 0;
5231
5232 #if CONFIG_PROTECT
5233 /*
5234 * To preserve file creation atomicity with regards to the content protection EA,
5235 * we must create the file in the catalog and then write out the EA in the same
5236 * transaction. Pre-flight any operations that we can (such as allocating/preparing
5237 * the buffer, wrapping the keys) before we start the txn and take the requisite
5238 * b-tree locks. We pass '0' as the fileid because we do not know it yet.
5239 */
5240 if ((protected_mount) && (protectable_target)) {
5241 error = cp_entry_create_keys (&entry, dcp, hfsmp, cp_class, 0, attr.ca_mode);
5242 if (error) {
5243 goto exit;
5244 }
5245 }
5246 #endif
5247
5248 if ((error = hfs_start_transaction(hfsmp)) != 0) {
5249 goto exit;
5250 }
5251 started_tr = 1;
5252
5253 // have to also lock the attribute file because cat_create() needs
5254 // to check that any fileID it wants to use does not have orphaned
5255 // attributes in it.
5256 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
5257
5258 /* Reserve some space in the Catalog file. */
5259 if ((error = cat_preflight(hfsmp, CAT_CREATE, NULL, 0))) {
5260 hfs_systemfile_unlock(hfsmp, lockflags);
5261 goto exit;
5262 }
5263 error = cat_create(hfsmp, &in_desc, &attr, &out_desc);
5264 if (error == 0) {
5265 /* Update the parent directory */
5266 dcp->c_childhint = out_desc.cd_hint; /* Cache directory's location */
5267 dcp->c_entries++;
5268 if (vnodetype == VDIR) {
5269 INC_FOLDERCOUNT(hfsmp, dcp->c_attr);
5270 }
5271 dcp->c_dirchangecnt++;
5272 dcp->c_ctime = tv.tv_sec;
5273 dcp->c_mtime = tv.tv_sec;
5274 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL);
5275
5276 #if CONFIG_PROTECT
5277 /*
5278 * If we are creating a content protected file, now is when
5279 * we create the EA. We must create it in the same transaction
5280 * that creates the file. We can also guarantee that the file
5281 * MUST exist because we are still holding the catalog lock
5282 * at this point.
5283 */
5284 if ((attr.ca_fileid != 0) && (protected_mount) && (protectable_target)) {
5285 error = cp_setxattr (NULL, entry, hfsmp, attr.ca_fileid, XATTR_CREATE);
5286
5287 if (error) {
5288 int delete_err;
5289 /*
5290 * If we fail the EA creation, then we need to delete the file.
5291 * Luckily, we are still holding all of the right locks.
5292 */
5293 delete_err = cat_delete (hfsmp, &out_desc, &attr);
5294 if (delete_err == 0) {
5295 /* Update the parent directory */
5296 if (dcp->c_entries > 0)
5297 dcp->c_entries--;
5298 dcp->c_dirchangecnt++;
5299 dcp->c_ctime = tv.tv_sec;
5300 dcp->c_mtime = tv.tv_sec;
5301 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL);
5302 }
5303
5304 /* Emit EINVAL if we fail to create EA*/
5305 error = EINVAL;
5306 }
5307 }
5308 #endif
5309 }
5310 hfs_systemfile_unlock(hfsmp, lockflags);
5311 if (error)
5312 goto exit;
5313
5314 /* Invalidate negative cache entries in the directory */
5315 if (dcp->c_flag & C_NEG_ENTRIES) {
5316 cache_purge_negatives(dvp);
5317 dcp->c_flag &= ~C_NEG_ENTRIES;
5318 }
5319
5320 hfs_volupdate(hfsmp, vnodetype == VDIR ? VOL_MKDIR : VOL_MKFILE,
5321 (dcp->c_cnid == kHFSRootFolderID));
5322
5323 // XXXdbg
5324 // have to end the transaction here before we call hfs_getnewvnode()
5325 // because that can cause us to try and reclaim a vnode on a different
5326 // file system which could cause us to start a transaction which can
5327 // deadlock with someone on that other file system (since we could be
5328 // holding two transaction locks as well as various vnodes and we did
5329 // not obtain the locks on them in the proper order).
5330 //
5331 // NOTE: this means that if the quota check fails or we have to update
5332 // the change time on a block-special device that those changes
5333 // will happen as part of independent transactions.
5334 //
5335 if (started_tr) {
5336 hfs_end_transaction(hfsmp);
5337 started_tr = 0;
5338 }
5339
5340 #if CONFIG_PROTECT
5341 /*
5342 * At this point, we must have encountered success with writing the EA.
5343 * Update MKB with the data for the cached key, then destroy it. This may
5344 * prevent information leakage by ensuring the cache key is only unwrapped
5345 * to perform file I/O and it is allowed.
5346 */
5347
5348 if ((attr.ca_fileid != 0) && (protected_mount) && (protectable_target)) {
5349 cp_update_mkb (entry, attr.ca_fileid);
5350 cp_entry_destroy (&entry);
5351 }
5352 #endif
5353
5354 /* Do not create vnode for whiteouts */
5355 if (S_ISWHT(mode)) {
5356 goto exit;
5357 }
5358
5359 gnv_flags |= GNV_CREATE;
5360
5361 /*
5362 * Create a vnode for the object just created.
5363 *
5364 * NOTE: Maintaining the cnode lock on the parent directory is important,
5365 * as it prevents race conditions where other threads want to look up entries
5366 * in the directory and/or add things as we are in the process of creating
5367 * the vnode below. However, this has the potential for causing a
5368 * double lock panic when dealing with shadow files on a HFS boot partition.
5369 * The panic could occur if we are not cleaning up after ourselves properly
5370 * when done with a shadow file or in the error cases. The error would occur if we
5371 * try to create a new vnode, and then end up reclaiming another shadow vnode to
5372 * create the new one. However, if everything is working properly, this should
5373 * be a non-issue as we would never enter that reclaim codepath.
5374 *
5375 * The cnode is locked on successful return.
5376 */
5377 error = hfs_getnewvnode(hfsmp, dvp, cnp, &out_desc, gnv_flags, &attr,
5378 NULL, &tvp, &newvnode_flags);
5379 if (error)
5380 goto exit;
5381
5382 cp = VTOC(tvp);
5383 *vpp = tvp;
5384
5385 #if QUOTA
5386 /*
5387 * Once we create this vnode, we need to initialize its quota data
5388 * structures, if necessary. We know that it is OK to just go ahead and
5389 * initialize because we've already validated earlier (through the hfs_quotacheck
5390 * function) to see if creating this cnode/vnode would cause us to go over quota.
5391 */
5392 if (hfsmp->hfs_flags & HFS_QUOTAS) {
5393 (void) hfs_getinoquota(cp);
5394 }
5395 #endif
5396
5397 exit:
5398 cat_releasedesc(&out_desc);
5399
5400 #if CONFIG_PROTECT
5401 /*
5402 * We may have jumped here in error-handling various situations above.
5403 * If we haven't already dumped the temporary CP used to initialize
5404 * the file atomically, then free it now. cp_entry_destroy should null
5405 * out the pointer if it was called already.
5406 */
5407 if (entry) {
5408 cp_entry_destroy (&entry);
5409 }
5410 #endif
5411
5412 /*
5413 * Make sure we release cnode lock on dcp.
5414 */
5415 if (dcp) {
5416 dcp->c_flag &= ~C_DIR_MODIFICATION;
5417 wakeup((caddr_t)&dcp->c_flag);
5418
5419 hfs_unlock(dcp);
5420 }
5421 if (error == 0 && cp != NULL) {
5422 hfs_unlock(cp);
5423 }
5424 if (started_tr) {
5425 hfs_end_transaction(hfsmp);
5426 started_tr = 0;
5427 }
5428
5429 return (error);
5430 }
5431
5432
5433 /*
5434 * hfs_vgetrsrc acquires a resource fork vnode corresponding to the cnode that is
5435 * found in 'vp'. The rsrc fork vnode is returned with the cnode locked and iocount
5436 * on the rsrc vnode.
5437 *
5438 * *rvpp is an output argument for returning the pointer to the resource fork vnode.
5439 * In most cases, the resource fork vnode will not be set if we return an error.
5440 * However, if error_on_unlinked is set, we may have already acquired the resource fork vnode
5441 * before we discover the error (the file has gone open-unlinked). In this case only,
5442 * we may return a vnode in the output argument despite an error.
5443 *
5444 * If can_drop_lock is set, then it is safe for this function to temporarily drop
5445 * and then re-acquire the cnode lock. We may need to do this, for example, in order to
5446 * acquire an iocount or promote our lock.
5447 *
5448 * error_on_unlinked is an argument which indicates that we are to return an error if we
5449 * discover that the cnode has gone into an open-unlinked state ( C_DELETED or C_NOEXISTS)
5450 * is set in the cnode flags. This is only necessary if can_drop_lock is true, otherwise
5451 * there's really no reason to double-check for errors on the cnode.
5452 */
5453
5454 int
5455 hfs_vgetrsrc(struct hfsmount *hfsmp, struct vnode *vp, struct vnode **rvpp,
5456 int can_drop_lock, int error_on_unlinked)
5457 {
5458 struct vnode *rvp;
5459 struct vnode *dvp = NULLVP;
5460 struct cnode *cp = VTOC(vp);
5461 int error;
5462 int vid;
5463 int delete_status = 0;
5464
5465 if (vnode_vtype(vp) == VDIR) {
5466 return EINVAL;
5467 }
5468
5469 /*
5470 * Need to check the status of the cnode to validate it hasn't gone
5471 * open-unlinked on us before we can actually do work with it.
5472 */
5473 delete_status = hfs_checkdeleted(cp);
5474 if ((delete_status) && (error_on_unlinked)) {
5475 return delete_status;
5476 }
5477
5478 restart:
5479 /* Attempt to use existing vnode */
5480 if ((rvp = cp->c_rsrc_vp)) {
5481 vid = vnode_vid(rvp);
5482
5483 /*
5484 * It is not safe to hold the cnode lock when calling vnode_getwithvid()
5485 * for the alternate fork -- vnode_getwithvid() could deadlock waiting
5486 * for a VL_WANTTERM while another thread has an iocount on the alternate
5487 * fork vnode and is attempting to acquire the common cnode lock.
5488 *
5489 * But it's also not safe to drop the cnode lock when we're holding
5490 * multiple cnode locks, like during a hfs_removefile() operation
5491 * since we could lock out of order when re-acquiring the cnode lock.
5492 *
5493 * So we can only drop the lock here if its safe to drop it -- which is
5494 * most of the time with the exception being hfs_removefile().
5495 */
5496 if (can_drop_lock)
5497 hfs_unlock(cp);
5498
5499 error = vnode_getwithvid(rvp, vid);
5500
5501 if (can_drop_lock) {
5502 (void) hfs_lock(cp, HFS_FORCE_LOCK);
5503
5504 /*
5505 * When we relinquished our cnode lock, the cnode could have raced
5506 * with a delete and gotten deleted. If the caller did not want
5507 * us to ignore open-unlinked files, then re-check the C_DELETED
5508 * state and see if we need to return an ENOENT here because the item
5509 * got deleted in the intervening time.
5510 */
5511 if (error_on_unlinked) {
5512 if ((delete_status = hfs_checkdeleted(cp))) {
5513 /*
5514 * If error == 0, this means that we succeeded in acquiring an iocount on the
5515 * rsrc fork vnode. However, if we're in this block of code, that means that we noticed
5516 * that the cnode has gone open-unlinked. In this case, the caller requested that we
5517 * not do any other work and return an errno. The caller will be responsible for
5518 * dropping the iocount we just acquired because we can't do it until we've released
5519 * the cnode lock.
5520 */
5521 if (error == 0) {
5522 *rvpp = rvp;
5523 }
5524 return delete_status;
5525 }
5526 }
5527
5528 /*
5529 * When our lock was relinquished, the resource fork
5530 * could have been recycled. Check for this and try
5531 * again.
5532 */
5533 if (error == ENOENT)
5534 goto restart;
5535 }
5536 if (error) {
5537 const char * name = (const char *)VTOC(vp)->c_desc.cd_nameptr;
5538
5539 if (name)
5540 printf("hfs_vgetrsrc: couldn't get resource"
5541 " fork for %s, err %d\n", name, error);
5542 return (error);
5543 }
5544 } else {
5545 struct cat_fork rsrcfork;
5546 struct componentname cn;
5547 struct cat_desc *descptr = NULL;
5548 struct cat_desc to_desc;
5549 char delname[32];
5550 int lockflags;
5551 int newvnode_flags = 0;
5552
5553 /*
5554 * Make sure cnode lock is exclusive, if not upgrade it.
5555 *
5556 * We assume that we were called from a read-only VNOP (getattr)
5557 * and that its safe to have the cnode lock dropped and reacquired.
5558 */
5559 if (cp->c_lockowner != current_thread()) {
5560 if (!can_drop_lock) {
5561 return (EINVAL);
5562 }
5563 /*
5564 * If the upgrade fails we lose the lock and
5565 * have to take the exclusive lock on our own.
5566 */
5567 if (lck_rw_lock_shared_to_exclusive(&cp->c_rwlock) == FALSE)
5568 lck_rw_lock_exclusive(&cp->c_rwlock);
5569 cp->c_lockowner = current_thread();
5570 }
5571
5572 /*
5573 * hfs_vgetsrc may be invoked for a cnode that has already been marked
5574 * C_DELETED. This is because we need to continue to provide rsrc
5575 * fork access to open-unlinked files. In this case, build a fake descriptor
5576 * like in hfs_removefile. If we don't do this, buildkey will fail in
5577 * cat_lookup because this cnode has no name in its descriptor. However,
5578 * only do this if the caller did not specify that they wanted us to
5579 * error out upon encountering open-unlinked files.
5580 */
5581
5582 if ((error_on_unlinked) && (can_drop_lock)) {
5583 if ((error = hfs_checkdeleted(cp))) {
5584 return error;
5585 }
5586 }
5587
5588 if ((cp->c_flag & C_DELETED ) && (cp->c_desc.cd_namelen == 0)) {
5589 bzero (&to_desc, sizeof(to_desc));
5590 bzero (delname, 32);
5591 MAKE_DELETED_NAME(delname, sizeof(delname), cp->c_fileid);
5592 to_desc.cd_nameptr = (const u_int8_t*) delname;
5593 to_desc.cd_namelen = strlen(delname);
5594 to_desc.cd_parentcnid = hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid;
5595 to_desc.cd_flags = 0;
5596 to_desc.cd_cnid = cp->c_cnid;
5597
5598 descptr = &to_desc;
5599 }
5600 else {
5601 descptr = &cp->c_desc;
5602 }
5603
5604
5605 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
5606
5607 /*
5608 * Get resource fork data
5609 *
5610 * We call cat_idlookup (instead of cat_lookup) below because we can't
5611 * trust the descriptor in the provided cnode for lookups at this point.
5612 * Between the time of the original lookup of this vnode and now, the
5613 * descriptor could have gotten swapped or replaced. If this occurred,
5614 * the parent/name combo originally desired may not necessarily be provided
5615 * if we use the descriptor. Even worse, if the vnode represents
5616 * a hardlink, we could have removed one of the links from the namespace
5617 * but left the descriptor alone, since hfs_unlink does not invalidate
5618 * the descriptor in the cnode if other links still point to the inode.
5619 *
5620 * Consider the following (slightly contrived) scenario:
5621 * /tmp/a <--> /tmp/b (hardlinks).
5622 * 1. Thread A: open rsrc fork on /tmp/b.
5623 * 1a. Thread A: does lookup, goes out to lunch right before calling getnamedstream.
5624 * 2. Thread B does 'mv /foo/b /tmp/b'
5625 * 2. Thread B succeeds.
5626 * 3. Thread A comes back and wants rsrc fork info for /tmp/b.
5627 *
5628 * Even though the hardlink backing /tmp/b is now eliminated, the descriptor
5629 * is not removed/updated during the unlink process. So, if you were to
5630 * do a lookup on /tmp/b, you'd acquire an entirely different record's resource
5631 * fork.
5632 *
5633 * As a result, we use the fileid, which should be invariant for the lifetime
5634 * of the cnode (possibly barring calls to exchangedata).
5635 */
5636
5637 error = cat_idlookup (hfsmp, cp->c_attr.ca_fileid, 0, 1, NULL, NULL, &rsrcfork);
5638
5639 hfs_systemfile_unlock(hfsmp, lockflags);
5640 if (error) {
5641 return (error);
5642 }
5643
5644 /*
5645 * Supply hfs_getnewvnode with a component name.
5646 */
5647 cn.cn_pnbuf = NULL;
5648 if (descptr->cd_nameptr) {
5649 MALLOC_ZONE(cn.cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
5650 cn.cn_nameiop = LOOKUP;
5651 cn.cn_flags = ISLASTCN | HASBUF;
5652 cn.cn_context = NULL;
5653 cn.cn_pnlen = MAXPATHLEN;
5654 cn.cn_nameptr = cn.cn_pnbuf;
5655 cn.cn_hash = 0;
5656 cn.cn_consume = 0;
5657 cn.cn_namelen = snprintf(cn.cn_nameptr, MAXPATHLEN,
5658 "%s%s", descptr->cd_nameptr,
5659 _PATH_RSRCFORKSPEC);
5660 }
5661 dvp = vnode_getparent(vp);
5662 error = hfs_getnewvnode(hfsmp, dvp, cn.cn_pnbuf ? &cn : NULL,
5663 descptr, GNV_WANTRSRC | GNV_SKIPLOCK, &cp->c_attr,
5664 &rsrcfork, &rvp, &newvnode_flags);
5665 if (dvp)
5666 vnode_put(dvp);
5667 if (cn.cn_pnbuf)
5668 FREE_ZONE(cn.cn_pnbuf, cn.cn_pnlen, M_NAMEI);
5669 if (error)
5670 return (error);
5671 }
5672
5673 *rvpp = rvp;
5674 return (0);
5675 }
5676
5677 /*
5678 * Wrapper for special device reads
5679 */
5680 int
5681 hfsspec_read(ap)
5682 struct vnop_read_args /* {
5683 struct vnode *a_vp;
5684 struct uio *a_uio;
5685 int a_ioflag;
5686 vfs_context_t a_context;
5687 } */ *ap;
5688 {
5689 /*
5690 * Set access flag.
5691 */
5692 VTOC(ap->a_vp)->c_touch_acctime = TRUE;
5693 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_read), ap));
5694 }
5695
5696 /*
5697 * Wrapper for special device writes
5698 */
5699 int
5700 hfsspec_write(ap)
5701 struct vnop_write_args /* {
5702 struct vnode *a_vp;
5703 struct uio *a_uio;
5704 int a_ioflag;
5705 vfs_context_t a_context;
5706 } */ *ap;
5707 {
5708 /*
5709 * Set update and change flags.
5710 */
5711 VTOC(ap->a_vp)->c_touch_chgtime = TRUE;
5712 VTOC(ap->a_vp)->c_touch_modtime = TRUE;
5713 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_write), ap));
5714 }
5715
5716 /*
5717 * Wrapper for special device close
5718 *
5719 * Update the times on the cnode then do device close.
5720 */
5721 int
5722 hfsspec_close(ap)
5723 struct vnop_close_args /* {
5724 struct vnode *a_vp;
5725 int a_fflag;
5726 vfs_context_t a_context;
5727 } */ *ap;
5728 {
5729 struct vnode *vp = ap->a_vp;
5730 struct cnode *cp;
5731
5732 if (vnode_isinuse(ap->a_vp, 0)) {
5733 if (hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK) == 0) {
5734 cp = VTOC(vp);
5735 hfs_touchtimes(VTOHFS(vp), cp);
5736 hfs_unlock(cp);
5737 }
5738 }
5739 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_close), ap));
5740 }
5741
5742 #if FIFO
5743 /*
5744 * Wrapper for fifo reads
5745 */
5746 static int
5747 hfsfifo_read(ap)
5748 struct vnop_read_args /* {
5749 struct vnode *a_vp;
5750 struct uio *a_uio;
5751 int a_ioflag;
5752 vfs_context_t a_context;
5753 } */ *ap;
5754 {
5755 /*
5756 * Set access flag.
5757 */
5758 VTOC(ap->a_vp)->c_touch_acctime = TRUE;
5759 return (VOCALL (fifo_vnodeop_p, VOFFSET(vnop_read), ap));
5760 }
5761
5762 /*
5763 * Wrapper for fifo writes
5764 */
5765 static int
5766 hfsfifo_write(ap)
5767 struct vnop_write_args /* {
5768 struct vnode *a_vp;
5769 struct uio *a_uio;
5770 int a_ioflag;
5771 vfs_context_t a_context;
5772 } */ *ap;
5773 {
5774 /*
5775 * Set update and change flags.
5776 */
5777 VTOC(ap->a_vp)->c_touch_chgtime = TRUE;
5778 VTOC(ap->a_vp)->c_touch_modtime = TRUE;
5779 return (VOCALL (fifo_vnodeop_p, VOFFSET(vnop_write), ap));
5780 }
5781
5782 /*
5783 * Wrapper for fifo close
5784 *
5785 * Update the times on the cnode then do device close.
5786 */
5787 static int
5788 hfsfifo_close(ap)
5789 struct vnop_close_args /* {
5790 struct vnode *a_vp;
5791 int a_fflag;
5792 vfs_context_t a_context;
5793 } */ *ap;
5794 {
5795 struct vnode *vp = ap->a_vp;
5796 struct cnode *cp;
5797
5798 if (vnode_isinuse(ap->a_vp, 1)) {
5799 if (hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK) == 0) {
5800 cp = VTOC(vp);
5801 hfs_touchtimes(VTOHFS(vp), cp);
5802 hfs_unlock(cp);
5803 }
5804 }
5805 return (VOCALL (fifo_vnodeop_p, VOFFSET(vnop_close), ap));
5806 }
5807
5808
5809 #endif /* FIFO */
5810
5811 /*
5812 * Synchronize a file's in-core state with that on disk.
5813 */
5814 int
5815 hfs_vnop_fsync(ap)
5816 struct vnop_fsync_args /* {
5817 struct vnode *a_vp;
5818 int a_waitfor;
5819 vfs_context_t a_context;
5820 } */ *ap;
5821 {
5822 struct vnode* vp = ap->a_vp;
5823 int error;
5824
5825 /* Note: We check hfs flags instead of vfs mount flag because during
5826 * read-write update, hfs marks itself read-write much earlier than
5827 * the vfs, and hence won't result in skipping of certain writes like
5828 * zero'ing out of unused nodes, creation of hotfiles btree, etc.
5829 */
5830 if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) {
5831 return 0;
5832 }
5833
5834 #if CONFIG_PROTECT
5835 if ((error = cp_handle_vnop(vp, CP_WRITE_ACCESS, 0)) != 0) {
5836 return (error);
5837 }
5838 #endif /* CONFIG_PROTECT */
5839
5840 /*
5841 * We need to allow ENOENT lock errors since unlink
5842 * systenm call can call VNOP_FSYNC during vclean.
5843 */
5844 error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK);
5845 if (error)
5846 return (0);
5847
5848 error = hfs_fsync(vp, ap->a_waitfor, 0, vfs_context_proc(ap->a_context));
5849
5850 hfs_unlock(VTOC(vp));
5851 return (error);
5852 }
5853
5854
5855 int
5856 hfs_vnop_whiteout(ap)
5857 struct vnop_whiteout_args /* {
5858 struct vnode *a_dvp;
5859 struct componentname *a_cnp;
5860 int a_flags;
5861 vfs_context_t a_context;
5862 } */ *ap;
5863 {
5864 int error = 0;
5865 struct vnode *vp = NULL;
5866 struct vnode_attr va;
5867 struct vnop_lookup_args lookup_args;
5868 struct vnop_remove_args remove_args;
5869 struct hfsmount *hfsmp;
5870
5871 hfsmp = VTOHFS(ap->a_dvp);
5872 if (hfsmp->hfs_flags & HFS_STANDARD) {
5873 error = ENOTSUP;
5874 goto exit;
5875 }
5876
5877 switch (ap->a_flags) {
5878 case LOOKUP:
5879 error = 0;
5880 break;
5881
5882 case CREATE:
5883 VATTR_INIT(&va);
5884 VATTR_SET(&va, va_type, VREG);
5885 VATTR_SET(&va, va_mode, S_IFWHT);
5886 VATTR_SET(&va, va_uid, 0);
5887 VATTR_SET(&va, va_gid, 0);
5888
5889 error = hfs_makenode(ap->a_dvp, &vp, ap->a_cnp, &va, ap->a_context);
5890 /* No need to release the vnode as no vnode is created for whiteouts */
5891 break;
5892
5893 case DELETE:
5894 lookup_args.a_dvp = ap->a_dvp;
5895 lookup_args.a_vpp = &vp;
5896 lookup_args.a_cnp = ap->a_cnp;
5897 lookup_args.a_context = ap->a_context;
5898
5899 error = hfs_vnop_lookup(&lookup_args);
5900 if (error) {
5901 break;
5902 }
5903
5904 remove_args.a_dvp = ap->a_dvp;
5905 remove_args.a_vp = vp;
5906 remove_args.a_cnp = ap->a_cnp;
5907 remove_args.a_flags = 0;
5908 remove_args.a_context = ap->a_context;
5909
5910 error = hfs_vnop_remove(&remove_args);
5911 vnode_put(vp);
5912 break;
5913
5914 default:
5915 panic("hfs_vnop_whiteout: unknown operation (flag = %x)\n", ap->a_flags);
5916 };
5917
5918 exit:
5919 return (error);
5920 }
5921
5922 int (**hfs_vnodeop_p)(void *);
5923 int (**hfs_std_vnodeop_p) (void *);
5924
5925 #define VOPFUNC int (*)(void *)
5926
5927 static int hfs_readonly_op (__unused void* ap) { return (EROFS); }
5928
5929 /*
5930 * In 10.6 and forward, HFS Standard is read-only and deprecated. The vnop table below
5931 * is for use with HFS standard to block out operations that would modify the file system
5932 */
5933
5934 struct vnodeopv_entry_desc hfs_standard_vnodeop_entries[] = {
5935 { &vnop_default_desc, (VOPFUNC)vn_default_error },
5936 { &vnop_lookup_desc, (VOPFUNC)hfs_vnop_lookup }, /* lookup */
5937 { &vnop_create_desc, (VOPFUNC)hfs_readonly_op }, /* create (READONLY) */
5938 { &vnop_mknod_desc, (VOPFUNC)hfs_readonly_op }, /* mknod (READONLY) */
5939 { &vnop_open_desc, (VOPFUNC)hfs_vnop_open }, /* open */
5940 { &vnop_close_desc, (VOPFUNC)hfs_vnop_close }, /* close */
5941 { &vnop_getattr_desc, (VOPFUNC)hfs_vnop_getattr }, /* getattr */
5942 { &vnop_setattr_desc, (VOPFUNC)hfs_readonly_op }, /* setattr */
5943 { &vnop_read_desc, (VOPFUNC)hfs_vnop_read }, /* read */
5944 { &vnop_write_desc, (VOPFUNC)hfs_readonly_op }, /* write (READONLY) */
5945 { &vnop_ioctl_desc, (VOPFUNC)hfs_vnop_ioctl }, /* ioctl */
5946 { &vnop_select_desc, (VOPFUNC)hfs_vnop_select }, /* select */
5947 { &vnop_revoke_desc, (VOPFUNC)nop_revoke }, /* revoke */
5948 { &vnop_exchange_desc, (VOPFUNC)hfs_readonly_op }, /* exchange (READONLY)*/
5949 { &vnop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */
5950 { &vnop_fsync_desc, (VOPFUNC)hfs_readonly_op}, /* fsync (READONLY) */
5951 { &vnop_remove_desc, (VOPFUNC)hfs_readonly_op }, /* remove (READONLY) */
5952 { &vnop_link_desc, (VOPFUNC)hfs_readonly_op }, /* link ( READONLLY) */
5953 { &vnop_rename_desc, (VOPFUNC)hfs_readonly_op }, /* rename (READONLY)*/
5954 { &vnop_mkdir_desc, (VOPFUNC)hfs_readonly_op }, /* mkdir (READONLY) */
5955 { &vnop_rmdir_desc, (VOPFUNC)hfs_readonly_op }, /* rmdir (READONLY) */
5956 { &vnop_symlink_desc, (VOPFUNC)hfs_readonly_op }, /* symlink (READONLY) */
5957 { &vnop_readdir_desc, (VOPFUNC)hfs_vnop_readdir }, /* readdir */
5958 { &vnop_readdirattr_desc, (VOPFUNC)hfs_vnop_readdirattr }, /* readdirattr */
5959 { &vnop_readlink_desc, (VOPFUNC)hfs_vnop_readlink }, /* readlink */
5960 { &vnop_inactive_desc, (VOPFUNC)hfs_vnop_inactive }, /* inactive */
5961 { &vnop_reclaim_desc, (VOPFUNC)hfs_vnop_reclaim }, /* reclaim */
5962 { &vnop_strategy_desc, (VOPFUNC)hfs_vnop_strategy }, /* strategy */
5963 { &vnop_pathconf_desc, (VOPFUNC)hfs_vnop_pathconf }, /* pathconf */
5964 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */
5965 { &vnop_allocate_desc, (VOPFUNC)hfs_readonly_op }, /* allocate (READONLY) */
5966 #if CONFIG_SEARCHFS
5967 { &vnop_searchfs_desc, (VOPFUNC)hfs_vnop_search }, /* search fs */
5968 #else
5969 { &vnop_searchfs_desc, (VOPFUNC)err_searchfs }, /* search fs */
5970 #endif
5971 { &vnop_bwrite_desc, (VOPFUNC)hfs_readonly_op }, /* bwrite (READONLY) */
5972 { &vnop_pagein_desc, (VOPFUNC)hfs_vnop_pagein }, /* pagein */
5973 { &vnop_pageout_desc,(VOPFUNC) hfs_readonly_op }, /* pageout (READONLY) */
5974 { &vnop_copyfile_desc, (VOPFUNC)hfs_readonly_op }, /* copyfile (READONLY)*/
5975 { &vnop_blktooff_desc, (VOPFUNC)hfs_vnop_blktooff }, /* blktooff */
5976 { &vnop_offtoblk_desc, (VOPFUNC)hfs_vnop_offtoblk }, /* offtoblk */
5977 { &vnop_blockmap_desc, (VOPFUNC)hfs_vnop_blockmap }, /* blockmap */
5978 { &vnop_getxattr_desc, (VOPFUNC)hfs_vnop_getxattr},
5979 { &vnop_setxattr_desc, (VOPFUNC)hfs_readonly_op}, /* set xattr (READONLY) */
5980 { &vnop_removexattr_desc, (VOPFUNC)hfs_readonly_op}, /* remove xattr (READONLY) */
5981 { &vnop_listxattr_desc, (VOPFUNC)hfs_vnop_listxattr},
5982 { &vnop_whiteout_desc, (VOPFUNC)hfs_readonly_op}, /* whiteout (READONLY) */
5983 #if NAMEDSTREAMS
5984 { &vnop_getnamedstream_desc, (VOPFUNC)hfs_vnop_getnamedstream },
5985 { &vnop_makenamedstream_desc, (VOPFUNC)hfs_readonly_op },
5986 { &vnop_removenamedstream_desc, (VOPFUNC)hfs_readonly_op },
5987 #endif
5988 { NULL, (VOPFUNC)NULL }
5989 };
5990
5991 struct vnodeopv_desc hfs_std_vnodeop_opv_desc =
5992 { &hfs_std_vnodeop_p, hfs_standard_vnodeop_entries };
5993
5994
5995 /* VNOP table for HFS+ */
5996 struct vnodeopv_entry_desc hfs_vnodeop_entries[] = {
5997 { &vnop_default_desc, (VOPFUNC)vn_default_error },
5998 { &vnop_lookup_desc, (VOPFUNC)hfs_vnop_lookup }, /* lookup */
5999 { &vnop_create_desc, (VOPFUNC)hfs_vnop_create }, /* create */
6000 { &vnop_mknod_desc, (VOPFUNC)hfs_vnop_mknod }, /* mknod */
6001 { &vnop_open_desc, (VOPFUNC)hfs_vnop_open }, /* open */
6002 { &vnop_close_desc, (VOPFUNC)hfs_vnop_close }, /* close */
6003 { &vnop_getattr_desc, (VOPFUNC)hfs_vnop_getattr }, /* getattr */
6004 { &vnop_setattr_desc, (VOPFUNC)hfs_vnop_setattr }, /* setattr */
6005 { &vnop_read_desc, (VOPFUNC)hfs_vnop_read }, /* read */
6006 { &vnop_write_desc, (VOPFUNC)hfs_vnop_write }, /* write */
6007 { &vnop_ioctl_desc, (VOPFUNC)hfs_vnop_ioctl }, /* ioctl */
6008 { &vnop_select_desc, (VOPFUNC)hfs_vnop_select }, /* select */
6009 { &vnop_revoke_desc, (VOPFUNC)nop_revoke }, /* revoke */
6010 { &vnop_exchange_desc, (VOPFUNC)hfs_vnop_exchange }, /* exchange */
6011 { &vnop_mmap_desc, (VOPFUNC)hfs_vnop_mmap }, /* mmap */
6012 { &vnop_fsync_desc, (VOPFUNC)hfs_vnop_fsync }, /* fsync */
6013 { &vnop_remove_desc, (VOPFUNC)hfs_vnop_remove }, /* remove */
6014 { &vnop_link_desc, (VOPFUNC)hfs_vnop_link }, /* link */
6015 { &vnop_rename_desc, (VOPFUNC)hfs_vnop_rename }, /* rename */
6016 { &vnop_mkdir_desc, (VOPFUNC)hfs_vnop_mkdir }, /* mkdir */
6017 { &vnop_rmdir_desc, (VOPFUNC)hfs_vnop_rmdir }, /* rmdir */
6018 { &vnop_symlink_desc, (VOPFUNC)hfs_vnop_symlink }, /* symlink */
6019 { &vnop_readdir_desc, (VOPFUNC)hfs_vnop_readdir }, /* readdir */
6020 { &vnop_readdirattr_desc, (VOPFUNC)hfs_vnop_readdirattr }, /* readdirattr */
6021 { &vnop_readlink_desc, (VOPFUNC)hfs_vnop_readlink }, /* readlink */
6022 { &vnop_inactive_desc, (VOPFUNC)hfs_vnop_inactive }, /* inactive */
6023 { &vnop_reclaim_desc, (VOPFUNC)hfs_vnop_reclaim }, /* reclaim */
6024 { &vnop_strategy_desc, (VOPFUNC)hfs_vnop_strategy }, /* strategy */
6025 { &vnop_pathconf_desc, (VOPFUNC)hfs_vnop_pathconf }, /* pathconf */
6026 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */
6027 { &vnop_allocate_desc, (VOPFUNC)hfs_vnop_allocate }, /* allocate */
6028 #if CONFIG_SEARCHFS
6029 { &vnop_searchfs_desc, (VOPFUNC)hfs_vnop_search }, /* search fs */
6030 #else
6031 { &vnop_searchfs_desc, (VOPFUNC)err_searchfs }, /* search fs */
6032 #endif
6033 { &vnop_bwrite_desc, (VOPFUNC)hfs_vnop_bwrite }, /* bwrite */
6034 { &vnop_pagein_desc, (VOPFUNC)hfs_vnop_pagein }, /* pagein */
6035 { &vnop_pageout_desc,(VOPFUNC) hfs_vnop_pageout }, /* pageout */
6036 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */
6037 { &vnop_blktooff_desc, (VOPFUNC)hfs_vnop_blktooff }, /* blktooff */
6038 { &vnop_offtoblk_desc, (VOPFUNC)hfs_vnop_offtoblk }, /* offtoblk */
6039 { &vnop_blockmap_desc, (VOPFUNC)hfs_vnop_blockmap }, /* blockmap */
6040 { &vnop_getxattr_desc, (VOPFUNC)hfs_vnop_getxattr},
6041 { &vnop_setxattr_desc, (VOPFUNC)hfs_vnop_setxattr},
6042 { &vnop_removexattr_desc, (VOPFUNC)hfs_vnop_removexattr},
6043 { &vnop_listxattr_desc, (VOPFUNC)hfs_vnop_listxattr},
6044 { &vnop_whiteout_desc, (VOPFUNC)hfs_vnop_whiteout},
6045 #if NAMEDSTREAMS
6046 { &vnop_getnamedstream_desc, (VOPFUNC)hfs_vnop_getnamedstream },
6047 { &vnop_makenamedstream_desc, (VOPFUNC)hfs_vnop_makenamedstream },
6048 { &vnop_removenamedstream_desc, (VOPFUNC)hfs_vnop_removenamedstream },
6049 #endif
6050 { NULL, (VOPFUNC)NULL }
6051 };
6052
6053 struct vnodeopv_desc hfs_vnodeop_opv_desc =
6054 { &hfs_vnodeop_p, hfs_vnodeop_entries };
6055
6056
6057 /* Spec Op vnop table for HFS+ */
6058 int (**hfs_specop_p)(void *);
6059 struct vnodeopv_entry_desc hfs_specop_entries[] = {
6060 { &vnop_default_desc, (VOPFUNC)vn_default_error },
6061 { &vnop_lookup_desc, (VOPFUNC)spec_lookup }, /* lookup */
6062 { &vnop_create_desc, (VOPFUNC)spec_create }, /* create */
6063 { &vnop_mknod_desc, (VOPFUNC)spec_mknod }, /* mknod */
6064 { &vnop_open_desc, (VOPFUNC)spec_open }, /* open */
6065 { &vnop_close_desc, (VOPFUNC)hfsspec_close }, /* close */
6066 { &vnop_getattr_desc, (VOPFUNC)hfs_vnop_getattr }, /* getattr */
6067 { &vnop_setattr_desc, (VOPFUNC)hfs_vnop_setattr }, /* setattr */
6068 { &vnop_read_desc, (VOPFUNC)hfsspec_read }, /* read */
6069 { &vnop_write_desc, (VOPFUNC)hfsspec_write }, /* write */
6070 { &vnop_ioctl_desc, (VOPFUNC)spec_ioctl }, /* ioctl */
6071 { &vnop_select_desc, (VOPFUNC)spec_select }, /* select */
6072 { &vnop_revoke_desc, (VOPFUNC)spec_revoke }, /* revoke */
6073 { &vnop_mmap_desc, (VOPFUNC)spec_mmap }, /* mmap */
6074 { &vnop_fsync_desc, (VOPFUNC)hfs_vnop_fsync }, /* fsync */
6075 { &vnop_remove_desc, (VOPFUNC)spec_remove }, /* remove */
6076 { &vnop_link_desc, (VOPFUNC)spec_link }, /* link */
6077 { &vnop_rename_desc, (VOPFUNC)spec_rename }, /* rename */
6078 { &vnop_mkdir_desc, (VOPFUNC)spec_mkdir }, /* mkdir */
6079 { &vnop_rmdir_desc, (VOPFUNC)spec_rmdir }, /* rmdir */
6080 { &vnop_symlink_desc, (VOPFUNC)spec_symlink }, /* symlink */
6081 { &vnop_readdir_desc, (VOPFUNC)spec_readdir }, /* readdir */
6082 { &vnop_readlink_desc, (VOPFUNC)spec_readlink }, /* readlink */
6083 { &vnop_inactive_desc, (VOPFUNC)hfs_vnop_inactive }, /* inactive */
6084 { &vnop_reclaim_desc, (VOPFUNC)hfs_vnop_reclaim }, /* reclaim */
6085 { &vnop_strategy_desc, (VOPFUNC)spec_strategy }, /* strategy */
6086 { &vnop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */
6087 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */
6088 { &vnop_bwrite_desc, (VOPFUNC)hfs_vnop_bwrite },
6089 { &vnop_pagein_desc, (VOPFUNC)hfs_vnop_pagein }, /* Pagein */
6090 { &vnop_pageout_desc, (VOPFUNC)hfs_vnop_pageout }, /* Pageout */
6091 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */
6092 { &vnop_blktooff_desc, (VOPFUNC)hfs_vnop_blktooff }, /* blktooff */
6093 { &vnop_offtoblk_desc, (VOPFUNC)hfs_vnop_offtoblk }, /* offtoblk */
6094 { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL }
6095 };
6096 struct vnodeopv_desc hfs_specop_opv_desc =
6097 { &hfs_specop_p, hfs_specop_entries };
6098
6099 #if FIFO
6100 /* HFS+ FIFO VNOP table */
6101 int (**hfs_fifoop_p)(void *);
6102 struct vnodeopv_entry_desc hfs_fifoop_entries[] = {
6103 { &vnop_default_desc, (VOPFUNC)vn_default_error },
6104 { &vnop_lookup_desc, (VOPFUNC)fifo_lookup }, /* lookup */
6105 { &vnop_create_desc, (VOPFUNC)fifo_create }, /* create */
6106 { &vnop_mknod_desc, (VOPFUNC)fifo_mknod }, /* mknod */
6107 { &vnop_open_desc, (VOPFUNC)fifo_open }, /* open */
6108 { &vnop_close_desc, (VOPFUNC)hfsfifo_close }, /* close */
6109 { &vnop_getattr_desc, (VOPFUNC)hfs_vnop_getattr }, /* getattr */
6110 { &vnop_setattr_desc, (VOPFUNC)hfs_vnop_setattr }, /* setattr */
6111 { &vnop_read_desc, (VOPFUNC)hfsfifo_read }, /* read */
6112 { &vnop_write_desc, (VOPFUNC)hfsfifo_write }, /* write */
6113 { &vnop_ioctl_desc, (VOPFUNC)fifo_ioctl }, /* ioctl */
6114 { &vnop_select_desc, (VOPFUNC)fifo_select }, /* select */
6115 { &vnop_revoke_desc, (VOPFUNC)fifo_revoke }, /* revoke */
6116 { &vnop_mmap_desc, (VOPFUNC)fifo_mmap }, /* mmap */
6117 { &vnop_fsync_desc, (VOPFUNC)hfs_vnop_fsync }, /* fsync */
6118 { &vnop_remove_desc, (VOPFUNC)fifo_remove }, /* remove */
6119 { &vnop_link_desc, (VOPFUNC)fifo_link }, /* link */
6120 { &vnop_rename_desc, (VOPFUNC)fifo_rename }, /* rename */
6121 { &vnop_mkdir_desc, (VOPFUNC)fifo_mkdir }, /* mkdir */
6122 { &vnop_rmdir_desc, (VOPFUNC)fifo_rmdir }, /* rmdir */
6123 { &vnop_symlink_desc, (VOPFUNC)fifo_symlink }, /* symlink */
6124 { &vnop_readdir_desc, (VOPFUNC)fifo_readdir }, /* readdir */
6125 { &vnop_readlink_desc, (VOPFUNC)fifo_readlink }, /* readlink */
6126 { &vnop_inactive_desc, (VOPFUNC)hfs_vnop_inactive }, /* inactive */
6127 { &vnop_reclaim_desc, (VOPFUNC)hfs_vnop_reclaim }, /* reclaim */
6128 { &vnop_strategy_desc, (VOPFUNC)fifo_strategy }, /* strategy */
6129 { &vnop_pathconf_desc, (VOPFUNC)fifo_pathconf }, /* pathconf */
6130 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */
6131 { &vnop_bwrite_desc, (VOPFUNC)hfs_vnop_bwrite },
6132 { &vnop_pagein_desc, (VOPFUNC)hfs_vnop_pagein }, /* Pagein */
6133 { &vnop_pageout_desc, (VOPFUNC)hfs_vnop_pageout }, /* Pageout */
6134 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */
6135 { &vnop_blktooff_desc, (VOPFUNC)hfs_vnop_blktooff }, /* blktooff */
6136 { &vnop_offtoblk_desc, (VOPFUNC)hfs_vnop_offtoblk }, /* offtoblk */
6137 { &vnop_blockmap_desc, (VOPFUNC)hfs_vnop_blockmap }, /* blockmap */
6138 { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL }
6139 };
6140 struct vnodeopv_desc hfs_fifoop_opv_desc =
6141 { &hfs_fifoop_p, hfs_fifoop_entries };
6142 #endif /* FIFO */
6143
6144
6145