]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_attrlist.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_attrlist.c
1 /*
2 * Copyright (c) 2000-2005 Apple Computer, 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 /*
30 * hfs_attrlist.c - HFS attribute list processing
31 *
32 * Copyright (c) 1998-2002, Apple Computer, Inc. All Rights Reserved.
33 */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/attr.h>
40 #include <sys/stat.h>
41 #include <sys/unistd.h>
42 #include <sys/mount_internal.h>
43 #include <sys/kauth.h>
44
45 #include <kern/locks.h>
46
47 #include "hfs.h"
48 #include "hfs_cnode.h"
49 #include "hfs_mount.h"
50 #include "hfs_dbg.h"
51 #include "hfs_attrlist.h"
52
53
54
55 /* Routines that are shared by hfs_setattr: */
56 extern int hfs_write_access(struct vnode *vp, kauth_cred_t cred,
57 struct proc *p, Boolean considerFlags);
58
59 extern int hfs_chflags(struct vnode *vp, uint32_t flags, kauth_cred_t cred,
60 struct proc *p);
61
62 extern int hfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred,
63 struct proc *p);
64
65 extern int hfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
66 struct proc *p);
67
68 __private_extern__ int hfs_vnop_readdirattr(struct vnop_readdirattr_args *ap);
69
70 __private_extern__ int hfs_vnop_setattrlist(struct vnop_setattrlist_args *ap);
71
72 __private_extern__ int hfs_vnop_getattrlist(struct vnop_getattrlist_args *ap);
73
74 /* Packing routines: */
75
76
77 static void packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp,
78 struct vnode *vp, struct proc *p);
79
80 static void packvolattr(struct attrblock *abp, struct hfsmount *hfsmp,
81 struct vnode *vp);
82
83 static void packcommonattr(struct attrblock *abp, struct hfsmount *hfsmp,
84 struct vnode *vp, struct cat_desc * cdp,
85 struct cat_attr * cap, struct proc *p);
86
87 static void packfileattr(struct attrblock *abp, struct hfsmount *hfsmp,
88 struct cat_attr *cattrp, struct cat_fork *datafork,
89 struct cat_fork *rsrcfork);
90
91 static void packdirattr(struct attrblock *abp, struct hfsmount *hfsmp,
92 struct vnode *vp, struct cat_desc * descp,
93 struct cat_attr * cattrp);
94
95
96 #if 0
97 static int unpackattrblk(struct attrblock *abp, struct vnode *vp);
98
99 static void unpackcommonattr(struct attrblock *abp, struct vnode *vp);
100
101 static int unpackvolattr(struct attrblock *abp, struct hfsmount *hfsmp,
102 struct vnode *root_vp);
103
104
105 /*
106 * Get a list of attributes.
107 */
108 __private_extern__
109 int
110 hfs_vnop_getattrlist(ap)
111 struct vnop_getattrlist_args /* {
112 struct vnode *a_vp;
113 struct attrlist *a_alist
114 struct uio *a_uio;
115 int a_options;
116 vfs_context_t a_context;
117 } */ *ap;
118 {
119 struct vnode *vp = ap->a_vp;
120 struct cnode *cp;
121 struct hfsmount *hfsmp;
122 struct attrlist *alist = ap->a_alist;
123 proc_t p = vfs_context_proc(ap->a_context);
124 int fixedblocksize;
125 int attrblocksize;
126 int attrbufsize;
127 void *attrbufptr = NULL;
128 void *attrptr;
129 void *varptr;
130 struct attrblock attrblk;
131 struct cat_fork *datafp = NULL;
132 struct cat_fork *rsrcfp = NULL;
133 struct cat_fork rsrcfork;
134 int lockflags;
135 int error = 0;
136
137 if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
138 ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
139 ((alist->volattr & ~ATTR_VOL_VALIDMASK) != 0) ||
140 ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
141 ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0)) {
142 return (EINVAL);
143 }
144
145 /*
146 * Requesting volume information requires setting the
147 * ATTR_VOL_INFO bit. Also, volume info requests are
148 * mutually exclusive with all other info requests.
149 */
150 if ((alist->volattr != 0) &&
151 (((alist->volattr & ATTR_VOL_INFO) == 0) ||
152 (alist->dirattr != 0) || (alist->fileattr != 0))) {
153 return (EINVAL);
154 }
155
156 /* Reject requests for unsupported options for now: */
157 if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) ||
158 (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) {
159 return (EINVAL);
160 }
161
162 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK)))
163 return (error);
164 cp = VTOC(vp);
165 hfsmp = VTOHFS(vp);
166
167 /* Requesting volume information requires root vnode */
168 if ((alist->volattr) && cp->c_fileid != kHFSRootFolderID) {
169 error = EINVAL;
170 goto exit;
171 }
172 /* Asking for data fork attributes from the rsrc fork is not supported */
173 if (VNODE_IS_RSRC(vp) && (alist->fileattr & ATTR_DATAFORK_MASK)) {
174 error = EINVAL;
175 goto exit;
176 }
177 /* This file no longer exists! */
178 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
179 error = ENOENT;
180 goto exit;
181 }
182 /* This file doesn't have a name! */
183 if ((cp->c_desc.cd_namelen == 0) && (alist->commonattr & ATTR_CMN_NAME)) {
184 error = ENOENT;
185 goto exit;
186 }
187
188 /* Update cnode times if needed */
189 hfs_touchtimes(hfsmp, cp);
190
191 /*
192 * If a File ID (ATTR_CMN_OBJPERMANENTID) is requested on
193 * an HFS volume we must be sure to create the thread
194 * record before returning it. (yikes)
195 */
196 if (vnode_isreg(vp) &&
197 (alist->commonattr & ATTR_CMN_OBJPERMANENTID) &&
198 (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)) {
199
200 cat_cookie_t cookie;
201
202 if (hfsmp->hfs_flags & HFS_READ_ONLY) {
203 error = EROFS;
204 goto exit;
205 }
206 if ((error = hfs_write_access(vp, vfs_context_ucred(ap->a_context),
207 p, false)) != 0) {
208 goto exit;
209 }
210 /*
211 * Reserve some space in the Catalog file.
212 */
213 bzero(&cookie, sizeof(cookie));
214 error = cat_preflight(hfsmp, CAT_CREATE, &cookie, p);
215 if (error) {
216 goto exit;
217 }
218
219 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
220
221 error = cat_insertfilethread(hfsmp, &cp->c_desc);
222
223 hfs_systemfile_unlock(hfsmp, lockflags);
224
225 cat_postflight(hfsmp, &cookie, p);
226
227 if (error)
228 goto exit;
229 }
230 bzero(&rsrcfork, sizeof(rsrcfork));
231 /* Establish known fork data */
232 if (cp->c_datafork != NULL) {
233 datafp = &cp->c_datafork->ff_data;
234 if ((cp->c_rsrcfork == NULL) &&
235 (cp->c_blocks == datafp->cf_blocks))
236 rsrcfp = &rsrcfork; /* rsrc fork is empty */
237 }
238 if (cp->c_rsrcfork != NULL)
239 rsrcfp = &cp->c_rsrcfork->ff_data;
240
241 /*
242 * When resource fork data is requested and its not available
243 * in the cnode and the fork is not empty then it needs to be
244 * fetched from the catalog.
245 */
246 if ((alist->fileattr & ATTR_RSRCFORK_MASK) && (rsrcfp == NULL)) {
247
248 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
249
250 /* Get resource fork data */
251 error = cat_lookup(hfsmp, &cp->c_desc, 1,
252 (struct cat_desc *)0, (struct cat_attr *)0, &rsrcfork, NULL);
253
254 hfs_systemfile_unlock(hfsmp, lockflags);
255
256 if (error)
257 goto exit;
258
259 rsrcfp = &rsrcfork;
260 }
261
262 fixedblocksize = hfs_attrblksize(alist);
263 attrblocksize = fixedblocksize + (sizeof(uint32_t)); /* uint32_t for length word */
264 if (alist->commonattr & ATTR_CMN_NAME)
265 attrblocksize += kHFSPlusMaxFileNameBytes + 1;
266 if (alist->volattr & ATTR_VOL_MOUNTPOINT)
267 attrblocksize += PATH_MAX;
268 if (alist->volattr & ATTR_VOL_NAME)
269 attrblocksize += kHFSPlusMaxFileNameBytes + 1;
270 #if 0
271 if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST)
272 attrblocksize += 0;
273 if (alist->fileattr & ATTR_FILE_FORKLIST)
274 attrblocksize += 0;
275 #endif
276 attrbufsize = MIN(uio_resid(ap->a_uio), attrblocksize);
277 MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
278 attrptr = attrbufptr;
279 *((uint32_t *)attrptr) = 0; /* Set buffer length in case of errors */
280 ++((uint32_t *)attrptr); /* Reserve space for length field */
281 varptr = ((char *)attrptr) + fixedblocksize;
282
283 attrblk.ab_attrlist = alist;
284 attrblk.ab_attrbufpp = &attrptr;
285 attrblk.ab_varbufpp = &varptr;
286 attrblk.ab_flags = 0;
287 attrblk.ab_blocksize = attrblocksize;
288
289 hfs_packattrblk(&attrblk, hfsmp, vp, &cp->c_desc, &cp->c_attr,
290 datafp, rsrcfp, p);
291
292 /* Don't copy out more data than was generated */
293 attrbufsize = MIN((u_int)attrbufsize, (u_int)varptr - (u_int)attrbufptr);
294 /* Set actual buffer length for return to caller */
295 *((uint32_t *)attrbufptr) = attrbufsize;
296 error = uiomove((caddr_t)attrbufptr, attrbufsize, ap->a_uio);
297 exit:
298 if (attrbufptr)
299 FREE(attrbufptr, M_TEMP);
300 hfs_unlock(cp);
301 return (error);
302 }
303
304
305 /*
306 * Set a list of attributes.
307 */
308 __private_extern__
309 int
310 hfs_vnop_setattrlist(ap)
311 struct vnop_setattrlist_args /* {
312 struct vnode *a_vp;
313 struct attrlist *a_alist
314 struct uio *a_uio;
315 int a_options;
316 vfs_context_t a_context;
317 } */ *ap;
318 {
319 struct vnode *vp = ap->a_vp;
320 struct cnode *cp;
321 struct hfsmount * hfsmp;
322 struct attrlist *alist = ap->a_alist;
323 kauth_cred_t cred = vfs_context_ucred(ap->a_context);
324 struct proc *p = vfs_context_proc(ap->a_context);
325 int attrblocksize;
326 void *attrbufptr = NULL;
327 void *attrptr;
328 void *varptr = NULL;
329 struct attrblock attrblk;
330 uid_t saved_uid;
331 gid_t saved_gid;
332 mode_t saved_mode;
333 uint32_t saved_flags;
334 int error = 0;
335
336 hfsmp = VTOHFS(vp);
337
338 if (hfsmp->hfs_flags & HFS_READ_ONLY)
339 return (EROFS);
340 if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
341 ((alist->commonattr & ~ATTR_CMN_SETMASK) != 0) ||
342 ((alist->volattr & ~ATTR_VOL_SETMASK) != 0) ||
343 ((alist->dirattr & ~ATTR_DIR_SETMASK) != 0) ||
344 ((alist->fileattr & ~ATTR_FILE_SETMASK) != 0)) {
345 return (EINVAL);
346 }
347 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK)))
348 return (error);
349 cp = VTOC(vp);
350
351 /*
352 * When setting volume attributes make sure
353 * that ATTR_VOL_INFO is set and that all
354 * the attributes are valid.
355 */
356 if ((alist->volattr != 0) &&
357 (((alist->volattr & ATTR_VOL_INFO) == 0) ||
358 (alist->commonattr & ~ATTR_CMN_VOLSETMASK) ||
359 (cp->c_fileid != kHFSRootFolderID))) {
360 if ((alist->volattr & ATTR_VOL_INFO) == 0)
361 printf("hfs_setattrlist: you forgot to set ATTR_VOL_INFO bit!\n");
362 else
363 printf("hfs_setattrlist: you cannot set bits 0x%08X!\n",
364 alist->commonattr & ~ATTR_CMN_VOLSETMASK);
365 error = EINVAL;
366 goto ErrorExit;
367 }
368 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
369 error = ENOENT;
370 goto ErrorExit;
371 }
372 // XXXdbg - don't allow modifying the journal or journal_info_block
373 if (hfsmp->jnl && cp->c_datafork) {
374 struct HFSPlusExtentDescriptor *extd;
375
376 extd = &cp->c_datafork->ff_extents[0];
377 if (extd->startBlock == HFSTOVCB(hfsmp)->vcbJinfoBlock || extd->startBlock == hfsmp->jnl_start) {
378 error = EPERM;
379 goto ErrorExit;
380 }
381 }
382
383 /*
384 * Ownership of a file is required in one of two classes of calls:
385 *
386 * (a) When setting any ownership-requiring attribute other
387 * than ATTR_CMN_FLAGS, or
388 * (b) When setting ATTR_CMN_FLAGS on a volume that's not
389 * plain HFS (for which no real per-object ownership
390 * information is stored)
391 */
392 if ((alist->commonattr & (ATTR_OWNERSHIP_SETMASK & ~ATTR_CMN_FLAGS)) ||
393 ((alist->commonattr & ATTR_CMN_FLAGS) &&
394 (VTOVCB(vp)->vcbSigWord != kHFSSigWord))) {
395 /*
396 * NOTE: The following isn't ENTIRELY complete: even if
397 * you're the superuser you cannot change the flags as
398 * long as SF_IMMUTABLE or SF_APPEND is set and the
399 * securelevel > 0. This is verified in hfs_chflags
400 * which gets invoked to do the actual flags field
401 * change so this check is sufficient for now.
402 */
403 if ((error = hfs_owner_rights(hfsmp, cp->c_uid, cred, p, true)) != 0)
404 goto ErrorExit;
405 }
406 /*
407 * For any other attributes, check to see if the user has
408 * write access to the cnode in question [unlike vn_access,
409 * ignore IMMUTABLE here]:
410 */
411 if (((alist->commonattr & ~ATTR_OWNERSHIP_SETMASK) != 0) ||
412 (alist->volattr != 0) || (alist->dirattr != 0) ||
413 (alist->fileattr != 0)) {
414 if ((error = hfs_write_access(vp, cred, p, false)) != 0)
415 goto ErrorExit;
416 }
417
418 /*
419 * Allocate the buffer now to minimize the time we might
420 * be blocked holding the catalog lock.
421 */
422 // LP64todo - fix this
423 attrblocksize = uio_resid(ap->a_uio);
424 if (attrblocksize < hfs_attrblksize(alist)) {
425 error = EINVAL;
426 goto ErrorExit;
427 }
428
429 MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
430
431 error = uiomove((caddr_t)attrbufptr, attrblocksize, ap->a_uio);
432 if (error)
433 goto ErrorExit;
434
435 /* Save original state so changes can be detected. */
436 saved_uid = cp->c_uid;
437 saved_gid = cp->c_gid;
438 saved_mode = cp->c_mode;
439 saved_flags = cp->c_flags;
440
441 attrptr = attrbufptr;
442 attrblk.ab_attrlist = alist;
443 attrblk.ab_attrbufpp = &attrptr;
444 attrblk.ab_varbufpp = &varptr;
445 attrblk.ab_flags = 0;
446 attrblk.ab_blocksize = attrblocksize;
447 error = unpackattrblk(&attrblk, vp);
448 if (error)
449 goto ErrorExit;
450
451 /* If unpacking changed the owner/group then call hfs_chown() */
452 if ((saved_uid != cp->c_uid) || (saved_gid != cp->c_gid)) {
453 uid_t uid;
454 gid_t gid;
455
456 uid = cp->c_uid;
457 cp->c_uid = saved_uid;
458 gid = cp->c_gid;
459 cp->c_gid = saved_gid;
460 if ((error = hfs_chown(vp, uid, gid, cred, p)))
461 goto ErrorExit;
462 }
463 /* If unpacking changed the mode then call hfs_chmod() */
464 if (saved_mode != cp->c_mode) {
465 mode_t mode;
466
467 mode = cp->c_mode;
468 cp->c_mode = saved_mode;
469 if ((error = hfs_chmod(vp, mode, cred, p)))
470 goto ErrorExit;
471 }
472 /* If unpacking changed the flags then call hfs_chflags() */
473 if (saved_flags !=cp->c_flags) {
474 uint32_t flags;
475
476 flags = cp->c_flags;
477 cp->c_flags = saved_flags;
478 if ((error = hfs_chflags(vp, flags, cred, p)))
479 goto ErrorExit;
480 }
481 /*
482 * If any cnode attributes changed then do an update.
483 */
484 if (alist->volattr == 0) {
485 cp->c_flag |= C_MODIFIED;
486 if ((error = hfs_update(vp, TRUE))) {
487 goto ErrorExit;
488 }
489 }
490 /* Volume Rename */
491 if (alist->volattr & ATTR_VOL_NAME) {
492 ExtendedVCB *vcb = VTOVCB(vp);
493
494 if (vcb->vcbVN[0] == 0) {
495 /*
496 * Ignore attempts to rename a volume to a zero-length name:
497 * restore the original name from the cnode.
498 */
499 copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
500 } else {
501 struct cat_desc to_desc;
502 struct cat_desc todir_desc;
503 struct cat_desc new_desc;
504 cat_cookie_t cookie;
505 int catreserve = 0;
506 int catlocked = 0;
507 int started_tr = 0;
508 int lockflags;
509
510 bzero(&to_desc, sizeof(to_desc));
511 bzero(&todir_desc, sizeof(todir_desc));
512 bzero(&new_desc, sizeof(new_desc));
513 bzero(&cookie, sizeof(cookie));
514
515 todir_desc.cd_parentcnid = kHFSRootParentID;
516 todir_desc.cd_cnid = kHFSRootFolderID;
517 todir_desc.cd_flags = CD_ISDIR;
518
519 to_desc.cd_nameptr = vcb->vcbVN;
520 to_desc.cd_namelen = strlen(vcb->vcbVN);
521 to_desc.cd_parentcnid = kHFSRootParentID;
522 to_desc.cd_cnid = cp->c_cnid;
523 to_desc.cd_flags = CD_ISDIR;
524
525 if ((error = hfs_start_transaction(hfsmp) != 0)) {
526 goto rename_out;
527 }
528 started_tr = 1;
529
530 /*
531 * Reserve some space in the Catalog file.
532 */
533 error = cat_preflight(hfsmp, CAT_RENAME, &cookie, p);
534 if (error) {
535 goto rename_out;
536 }
537 catreserve = 1;
538
539 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
540 catlocked = 1;
541
542 error = cat_rename(hfsmp, &cp->c_desc, &todir_desc, &to_desc, &new_desc);
543 rename_out:
544 if (catlocked) {
545 hfs_systemfile_unlock(hfsmp, lockflags);
546 }
547 if (catreserve) {
548 cat_postflight(hfsmp, &cookie, p);
549 }
550 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
551 if (started_tr) {
552 hfs_end_transaction(hfsmp);
553 }
554
555 if (error) {
556 /* Restore the old name in the VCB */
557 copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
558 vcb->vcbFlags |= 0xFF00;
559 goto ErrorExit;
560 }
561 /* Release old allocated name buffer */
562 if (cp->c_desc.cd_flags & CD_HASBUF) {
563 char *name = cp->c_desc.cd_nameptr;
564
565 cp->c_desc.cd_nameptr = 0;
566 cp->c_desc.cd_namelen = 0;
567 cp->c_desc.cd_flags &= ~CD_HASBUF;
568 vfs_removename(name);
569 }
570 /* Update cnode's catalog descriptor */
571 replace_desc(cp, &new_desc);
572 vcb->volumeNameEncodingHint = new_desc.cd_encoding;
573 cp->c_touch_chgtime = TRUE;
574 }
575 }
576
577 /*
578 * When the volume name changes or the volume's finder info
579 * changes then force them to disk immediately.
580 */
581 if ((alist->volattr & ATTR_VOL_INFO) &&
582 ((alist->volattr & ATTR_VOL_NAME) ||
583 (alist->commonattr & ATTR_CMN_FNDRINFO))) {
584 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
585 }
586 ErrorExit:
587 if (attrbufptr)
588 FREE(attrbufptr, M_TEMP);
589
590 hfs_unlock(cp);
591 return (error);
592 }
593 #endif
594
595 /*
596 * readdirattr operation will return attributes for the items in the
597 * directory specified.
598 *
599 * It does not do . and .. entries. The problem is if you are at the root of the
600 * hfs directory and go to .. you could be crossing a mountpoint into a
601 * different (ufs) file system. The attributes that apply for it may not
602 * apply for the file system you are doing the readdirattr on. To make life
603 * simpler, this call will only return entries in its directory, hfs like.
604 * TO DO LATER:
605 * 1. more than one for uiovcnt support.
606 * 2. put knohint (hints) in state for next call in
607 * 3. credentials checking when rest of hfs does it.
608 * 4. Do return permissions concatenation ???
609 */
610
611 /*
612 #
613 #% readdirattr vp L L L
614 #
615 vnop_readdirattr {
616 IN struct vnode *vp;
617 IN struct attrlist *alist;
618 INOUT struct uio *uio;
619 IN u_long maxcount:
620 IN u_long options;
621 OUT u_long *newstate;
622 OUT int *eofflag;
623 OUT u_long *actualCount;
624 OUT u_long **cookies;
625 IN kauth_cred_t cred;
626 };
627 */
628 __private_extern__
629 int
630 hfs_vnop_readdirattr(ap)
631 struct vnop_readdirattr_args /* {
632 struct vnode *a_vp;
633 struct attrlist *a_alist;
634 struct uio *a_uio;
635 u_long a_maxcount;
636 u_long a_options;
637 u_long *a_newstate;
638 int *a_eofflag;
639 u_long *a_actualcount;
640 vfs_context_t a_context;
641 } */ *ap;
642 {
643 struct vnode *dvp = ap->a_vp;
644 struct cnode *dcp;
645 struct hfsmount * hfsmp;
646 struct attrlist *alist = ap->a_alist;
647 uio_t uio = ap->a_uio;
648 int maxcount = ap->a_maxcount;
649 struct proc *p = vfs_context_proc(ap->a_context);
650 uint32_t fixedblocksize;
651 uint32_t maxattrblocksize;
652 uint32_t currattrbufsize;
653 void *attrbufptr = NULL;
654 void *attrptr;
655 void *varptr;
656 struct attrblock attrblk;
657 int error = 0;
658 int depleted = 0;
659 int index;
660 int i, dir_entries;
661 struct cat_desc *lastdescp = NULL;
662 struct cat_entrylist *ce_list = NULL;
663 directoryhint_t *dirhint = NULL;
664 unsigned int tag;
665 int shared_cnode_lock = 0;
666
667 *(ap->a_actualcount) = 0;
668 *(ap->a_eofflag) = 0;
669
670 /* Check for invalid options and buffer space. */
671 if (((ap->a_options & ~(FSOPT_NOINMEMUPDATE | FSOPT_NOFOLLOW)) != 0)
672 || (uio_resid(uio) <= 0) || (uio_iovcnt(uio) > 1) || (maxcount <= 0))
673 return (EINVAL);
674
675 /* This call doesn't take volume attributes. */
676 if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
677 ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
678 (alist->volattr != 0) ||
679 ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
680 ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0))
681 return (EINVAL);
682
683 if ((error = hfs_lock(VTOC(dvp), HFS_EXCLUSIVE_LOCK)))
684 return (error);
685 dcp = VTOC(dvp);
686 hfsmp = VTOHFS(dvp);
687
688 /* Reject requests for unsupported options. */
689 if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST |
690 ATTR_CMN_OBJPERMANENTID)) ||
691 (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT |
692 ATTR_FILE_FORKLIST | ATTR_FILE_DATAEXTENTS | ATTR_FILE_RSRCEXTENTS))) {
693 printf("readdirattr: unsupported attributes! (%s)\n", dcp->c_desc.cd_nameptr);
694 error = EINVAL;
695 goto exit;
696 }
697
698 dir_entries = dcp->c_entries;
699 if (dcp->c_attr.ca_fileid == kHFSRootFolderID && (hfsmp->jnl || ((HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY)))) {
700 dir_entries -= 3;
701 }
702
703 /* Convert uio_offset into a directory index. */
704 index = uio_offset(uio) & HFS_INDEX_MASK;
705 tag = uio_offset(uio) & ~HFS_INDEX_MASK;
706 if ((index + 1) > dir_entries) {
707 *(ap->a_eofflag) = 1;
708 error = 0;
709 goto exit;
710 }
711
712 /* Get a buffer to hold packed attributes. */
713 fixedblocksize = (sizeof(uint32_t) + hfs_attrblksize(alist)); /* 4 bytes for length */
714 maxattrblocksize = fixedblocksize;
715 if (alist->commonattr & ATTR_CMN_NAME)
716 maxattrblocksize += kHFSPlusMaxFileNameBytes + 1;
717 MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK);
718 attrptr = attrbufptr;
719 varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */
720
721 /* Initialize a catalog entry list. */
722 MALLOC(ce_list, struct cat_entrylist *, sizeof(*ce_list), M_TEMP, M_WAITOK);
723 bzero(ce_list, sizeof(*ce_list));
724 ce_list->maxentries = MAXCATENTRIES;
725
726 /* Get a directory hint (cnode must be locked exclusive) */
727 dirhint = hfs_getdirhint(dcp, ((index - 1) & HFS_INDEX_MASK) | tag);
728
729 /* Hide tag from catalog layer. */
730 dirhint->dh_index &= HFS_INDEX_MASK;
731 if (dirhint->dh_index == HFS_INDEX_MASK) {
732 dirhint->dh_index = -1;
733 }
734
735 /*
736 * An ATTR_CMN_USERACCESS attribute request can result in a
737 * call to kauth_cred_ismember_gid(). So when requesting
738 * this attribute we downgrade our exclusive lock on dcp to
739 * a shared lock in case kauth_cred_ismember_gid generates
740 * an indirect call back into the file system.
741 */
742 if (alist->commonattr & ATTR_CMN_USERACCESS) {
743 lck_rw_lock_exclusive_to_shared(&dcp->c_rwlock);
744 dcp->c_lockowner = HFS_SHARED_OWNER;
745 shared_cnode_lock = 1;
746 }
747 /*
748 * Obtain a list of catalog entries and pack their attributes until
749 * the output buffer is full or maxcount entries have been packed.
750 */
751 while (!depleted) {
752 int maxentries;
753 int lockflags;
754
755 /* Constrain our list size. */
756 maxentries = uio_resid(uio) / (fixedblocksize + HFS_AVERAGE_NAME_SIZE);
757 maxentries = min(maxentries, dcp->c_entries - index);
758 maxentries = min(maxentries, maxcount);
759 ce_list->maxentries = min(maxentries, ce_list->maxentries);
760 lastdescp = NULL;
761
762 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
763
764 error = cat_getentriesattr(hfsmp, dirhint, ce_list);
765 /* Don't forget to release the descriptors later! */
766
767 hfs_systemfile_unlock(hfsmp, lockflags);
768
769 if (error == ENOENT) {
770 *(ap->a_eofflag) = TRUE;
771 error = 0;
772 depleted = 1;
773 }
774 if (error)
775 break;
776
777 /* Process the catalog entries. */
778 for (i = 0; i < (int)ce_list->realentries; ++i) {
779 struct cnode *cp = NULL;
780 struct vnode *vp = NULL;
781 struct cat_desc * cdescp;
782 struct cat_attr * cattrp;
783 struct cat_fork c_datafork;
784 struct cat_fork c_rsrcfork;
785
786 bzero(&c_datafork, sizeof(c_datafork));
787 bzero(&c_rsrcfork, sizeof(c_rsrcfork));
788 cdescp = &ce_list->entry[i].ce_desc;
789 cattrp = &ce_list->entry[i].ce_attr;
790 c_datafork.cf_size = ce_list->entry[i].ce_datasize;
791 c_datafork.cf_blocks = ce_list->entry[i].ce_datablks;
792 c_rsrcfork.cf_size = ce_list->entry[i].ce_rsrcsize;
793 c_rsrcfork.cf_blocks = ce_list->entry[i].ce_rsrcblks;
794 /*
795 * Get in memory cnode data (if any).
796 */
797 if (!(ap->a_options & FSOPT_NOINMEMUPDATE)) {
798 vp = hfs_chash_getvnode(dcp->c_dev, cattrp->ca_fileid, 0, 0);
799
800 if (vp != NULL) {
801 cp = VTOC(vp);
802 /* Only use cnode's decriptor for non-hardlinks */
803 if (!(cp->c_flag & C_HARDLINK))
804 cdescp = &cp->c_desc;
805 cattrp = &cp->c_attr;
806 if (cp->c_datafork) {
807 c_datafork.cf_size = cp->c_datafork->ff_size;
808 c_datafork.cf_blocks = cp->c_datafork->ff_blocks;
809 }
810 if (cp->c_rsrcfork) {
811 c_rsrcfork.cf_size = cp->c_rsrcfork->ff_size;
812 c_rsrcfork.cf_blocks = cp->c_rsrcfork->ff_blocks;
813 }
814 }
815 }
816 *((uint32_t *)attrptr)++ = 0; /* move it past length */
817 attrblk.ab_attrlist = alist;
818 attrblk.ab_attrbufpp = &attrptr;
819 attrblk.ab_varbufpp = &varptr;
820 attrblk.ab_flags = 0;
821 attrblk.ab_blocksize = maxattrblocksize;
822
823 /* Pack catalog entries into attribute buffer. */
824 hfs_packattrblk(&attrblk, hfsmp, vp, cdescp, cattrp,
825 &c_datafork, &c_rsrcfork, p);
826 currattrbufsize = ((char *)varptr - (char *)attrbufptr);
827
828 /* All done with cnode. */
829 if (vp != NULL) {
830 hfs_unlock(VTOC(vp));
831 vnode_put(vp);
832 vp = NULL;
833 cp = NULL;
834 }
835
836 /* Make sure there's enough buffer space remaining. */
837 // LP64todo - fix this!
838 if (uio_resid(uio) < 0 || currattrbufsize > (uint32_t)uio_resid(uio)) {
839 depleted = 1;
840 break;
841 } else {
842 *((uint32_t *)attrbufptr) = currattrbufsize;
843 error = uiomove((caddr_t)attrbufptr, currattrbufsize, ap->a_uio);
844 if (error != E_NONE) {
845 depleted = 1;
846 break;
847 }
848 attrptr = attrbufptr;
849 varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */
850 /* Save the last valid catalog entry */
851 lastdescp = &ce_list->entry[i].ce_desc;
852 index++;
853 *ap->a_actualcount += 1;
854
855 /* Termination checks */
856 if ((--maxcount <= 0) ||
857 // LP64todo - fix this!
858 uio_resid(uio) < 0 ||
859 ((uint32_t)uio_resid(uio) < (fixedblocksize + HFS_AVERAGE_NAME_SIZE)) ||
860 (index >= dir_entries)) {
861 depleted = 1;
862 break;
863 }
864 }
865 } /* for each catalog entry */
866
867 /* If there are more entries then save the last name. */
868 if (index < dir_entries
869 && !(*(ap->a_eofflag))
870 && lastdescp != NULL) {
871
872 /* Remember last entry */
873 if (dirhint->dh_desc.cd_nameptr != NULL) {
874 vfs_removename(dirhint->dh_desc.cd_nameptr);
875 }
876 dirhint->dh_desc.cd_namelen = lastdescp->cd_namelen;
877 dirhint->dh_desc.cd_nameptr =
878 vfs_addname(lastdescp->cd_nameptr, lastdescp->cd_namelen, 0, 0);
879 dirhint->dh_index = index - 1;
880 dirhint->dh_desc.cd_cnid = lastdescp->cd_cnid;
881 dirhint->dh_desc.cd_hint = lastdescp->cd_hint;
882 dirhint->dh_desc.cd_encoding = lastdescp->cd_encoding;
883 }
884
885 /* All done with the catalog descriptors. */
886 for (i = 0; i < (int)ce_list->realentries; ++i)
887 cat_releasedesc(&ce_list->entry[i].ce_desc);
888 ce_list->realentries = 0;
889
890 } /* while not depleted */
891
892 *ap->a_newstate = dcp->c_mtime;
893
894 /* Make sure dcp is locked exclusive before changing c_dirhinttag. */
895 if (shared_cnode_lock) {
896 /*
897 * If the upgrade fails we loose the lock and
898 * have to take the exclusive lock on our own.
899 */
900 if (lck_rw_lock_shared_to_exclusive(&dcp->c_rwlock) != 0)
901 lck_rw_lock_exclusive(&dcp->c_rwlock);
902 dcp->c_lockowner = current_thread();
903 shared_cnode_lock = 0;
904 }
905
906 /* Convert directory index back into a uio_offset. */
907 while (tag == 0) tag = (++dcp->c_dirhinttag) << HFS_INDEX_BITS;
908 uio_setoffset(uio, index | tag);
909 dirhint->dh_index |= tag;
910
911 exit:
912 /* Drop directory hint on error or if there are no more entries */
913 if (dirhint && (error || index >= dir_entries)) {
914 if (shared_cnode_lock) {
915 /*
916 * If the upgrade fails we loose the lock and
917 * have to take the exclusive lock on our own.
918 */
919 if (lck_rw_lock_shared_to_exclusive(&dcp->c_rwlock) != 0)
920 lck_rw_lock_exclusive(&dcp->c_rwlock);
921 dcp->c_lockowner = current_thread();
922 }
923 hfs_reldirhint(dcp, dirhint);
924 }
925 if (attrbufptr)
926 FREE(attrbufptr, M_TEMP);
927 if (ce_list)
928 FREE(ce_list, M_TEMP);
929
930 hfs_unlock(dcp);
931 return (error);
932 }
933
934
935 /*==================== Attribute list support routines ====================*/
936
937 /*
938 * Pack cnode attributes into an attribute block.
939 */
940 __private_extern__
941 void
942 hfs_packattrblk(struct attrblock *abp,
943 struct hfsmount *hfsmp,
944 struct vnode *vp,
945 struct cat_desc *descp,
946 struct cat_attr *attrp,
947 struct cat_fork *datafork,
948 struct cat_fork *rsrcfork,
949 struct proc *p)
950 {
951 struct attrlist *attrlistp = abp->ab_attrlist;
952
953 if (attrlistp->volattr) {
954 if (attrlistp->commonattr)
955 packvolcommonattr(abp, hfsmp, vp, p);
956
957 if (attrlistp->volattr & ~ATTR_VOL_INFO)
958 packvolattr(abp, hfsmp, vp);
959 } else {
960 if (attrlistp->commonattr)
961 packcommonattr(abp, hfsmp, vp, descp, attrp, p);
962
963 if (attrlistp->dirattr && S_ISDIR(attrp->ca_mode))
964 packdirattr(abp, hfsmp, vp, descp,attrp);
965
966 if (attrlistp->fileattr && !S_ISDIR(attrp->ca_mode))
967 packfileattr(abp, hfsmp, attrp, datafork, rsrcfork);
968 }
969 }
970
971
972 static char*
973 mountpointname(struct mount *mp)
974 {
975 size_t namelength = strlen(mp->mnt_vfsstat.f_mntonname);
976 int foundchars = 0;
977 char *c;
978
979 if (namelength == 0)
980 return (NULL);
981
982 /*
983 * Look backwards through the name string, looking for
984 * the first slash encountered (which must precede the
985 * last part of the pathname).
986 */
987 for (c = mp->mnt_vfsstat.f_mntonname + namelength - 1;
988 namelength > 0; --c, --namelength) {
989 if (*c != '/') {
990 foundchars = 1;
991 } else if (foundchars) {
992 return (c + 1);
993 }
994 }
995
996 return (mp->mnt_vfsstat.f_mntonname);
997 }
998
999
1000 static void
1001 packnameattr(
1002 struct attrblock *abp,
1003 struct vnode *vp,
1004 char *name,
1005 int namelen)
1006 {
1007 void *varbufptr;
1008 struct attrreference * attr_refptr;
1009 char *mpname;
1010 size_t mpnamelen;
1011 uint32_t attrlength;
1012 char empty = 0;
1013
1014 /* A cnode's name may be incorrect for the root of a mounted
1015 * filesystem (it can be mounted on a different directory name
1016 * than the name of the volume, such as "blah-1"). So for the
1017 * root directory, it's best to return the last element of the
1018 location where the volume's mounted:
1019 */
1020 if ((vp != NULL) && vnode_isvroot(vp) &&
1021 (mpname = mountpointname(vnode_mount(vp)))) {
1022 mpnamelen = strlen(mpname);
1023
1024 /* Trim off any trailing slashes: */
1025 while ((mpnamelen > 0) && (mpname[mpnamelen-1] == '/'))
1026 --mpnamelen;
1027
1028 /* If there's anything left, use it instead of the volume's name */
1029 if (mpnamelen > 0) {
1030 name = mpname;
1031 namelen = mpnamelen;
1032 }
1033 }
1034 if (name == NULL) {
1035 name = &empty;
1036 namelen = 0;
1037 }
1038
1039 varbufptr = *abp->ab_varbufpp;
1040 attr_refptr = (struct attrreference *)(*abp->ab_attrbufpp);
1041
1042 attrlength = namelen + 1;
1043 attr_refptr->attr_dataoffset = (char *)varbufptr - (char *)attr_refptr;
1044 attr_refptr->attr_length = attrlength;
1045 (void) strncpy((unsigned char *)varbufptr, name, attrlength);
1046 /*
1047 * Advance beyond the space just allocated and
1048 * round up to the next 4-byte boundary:
1049 */
1050 (char *)(varbufptr) += attrlength + ((4 - (attrlength & 3)) & 3);
1051 ++attr_refptr;
1052
1053 *abp->ab_attrbufpp = attr_refptr;
1054 *abp->ab_varbufpp = varbufptr;
1055 }
1056
1057 /*
1058 * Pack common volume attributes.
1059 */
1060 static void
1061 packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp, struct proc *p)
1062 {
1063 attrgroup_t attr;
1064 void *attrbufptr = *abp->ab_attrbufpp;
1065 void *varbufptr = *abp->ab_varbufpp;
1066 struct cnode *cp = VTOC(vp);
1067 struct mount *mp = VTOVFS(vp);
1068 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1069 u_int32_t attrlength;
1070 boolean_t is_64_bit = proc_is64bit(p);
1071
1072 attr = abp->ab_attrlist->commonattr;
1073
1074 if (ATTR_CMN_NAME & attr) {
1075 packnameattr(abp, vp, cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen);
1076 attrbufptr = *abp->ab_attrbufpp;
1077 varbufptr = *abp->ab_varbufpp;
1078 }
1079 if (ATTR_CMN_DEVID & attr) {
1080 *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev;
1081 }
1082 if (ATTR_CMN_FSID & attr) {
1083 fsid_t fsid;
1084
1085 fsid.val[0] = (long)hfsmp->hfs_raw_dev;
1086 fsid.val[1] = (long)vfs_typenum(mp);
1087 *((fsid_t *)attrbufptr) = fsid;
1088 ++((fsid_t *)attrbufptr);
1089 }
1090 if (ATTR_CMN_OBJTYPE & attr) {
1091 *((fsobj_type_t *)attrbufptr)++ = 0;
1092 }
1093 if (ATTR_CMN_OBJTAG & attr) {
1094 *((fsobj_tag_t *)attrbufptr)++ = VT_HFS;
1095 }
1096 if (ATTR_CMN_OBJID & attr) {
1097 ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1098 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1099 ++((fsobj_id_t *)attrbufptr);
1100 }
1101 if (ATTR_CMN_OBJPERMANENTID & attr) {
1102 ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1103 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1104 ++((fsobj_id_t *)attrbufptr);
1105 }
1106 if (ATTR_CMN_PAROBJID & attr) {
1107 ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1108 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1109 ++((fsobj_id_t *)attrbufptr);
1110 }
1111 if (ATTR_CMN_SCRIPT & attr) {
1112 uint32_t encoding;
1113
1114 if (vcb->vcbSigWord == kHFSPlusSigWord)
1115 encoding = vcb->volumeNameEncodingHint;
1116 else
1117 encoding = hfsmp->hfs_encoding;
1118 *((text_encoding_t *)attrbufptr)++ = encoding;
1119 }
1120 if (ATTR_CMN_CRTIME & attr) {
1121 if (is_64_bit) {
1122 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbCrDate;
1123 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1124 ++((struct user_timespec *)attrbufptr);
1125 }
1126 else {
1127 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbCrDate;
1128 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1129 ++((struct timespec *)attrbufptr);
1130 }
1131 }
1132 if (ATTR_CMN_MODTIME & attr) {
1133 if (is_64_bit) {
1134 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1135 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1136 ++((struct user_timespec *)attrbufptr);
1137 }
1138 else {
1139 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1140 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1141 ++((struct timespec *)attrbufptr);
1142 }
1143 }
1144 if (ATTR_CMN_CHGTIME & attr) {
1145 if (is_64_bit) {
1146 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1147 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1148 ++((struct user_timespec *)attrbufptr);
1149 }
1150 else {
1151 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1152 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1153 ++((struct timespec *)attrbufptr);
1154 }
1155 }
1156 if (ATTR_CMN_ACCTIME & attr) {
1157 if (is_64_bit) {
1158 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1159 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1160 ++((struct user_timespec *)attrbufptr);
1161 }
1162 else {
1163 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1164 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1165 ++((struct timespec *)attrbufptr);
1166 }
1167 }
1168 if (ATTR_CMN_BKUPTIME & attr) {
1169 if (is_64_bit) {
1170 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbVolBkUp;
1171 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1172 ++((struct user_timespec *)attrbufptr);
1173 }
1174 else {
1175 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbVolBkUp;
1176 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1177 ++((struct timespec *)attrbufptr);
1178 }
1179 }
1180 if (ATTR_CMN_FNDRINFO & attr) {
1181 bcopy (&vcb->vcbFndrInfo, attrbufptr, sizeof(vcb->vcbFndrInfo));
1182 (char *)attrbufptr += sizeof(vcb->vcbFndrInfo);
1183 }
1184 if (ATTR_CMN_OWNERID & attr) {
1185 if (cp->c_uid == UNKNOWNUID)
1186 *((uid_t *)attrbufptr)++ = kauth_cred_getuid(proc_ucred(p));
1187 else
1188 *((uid_t *)attrbufptr)++ = cp->c_uid;
1189 }
1190 if (ATTR_CMN_GRPID & attr) {
1191 *((gid_t *)attrbufptr)++ = cp->c_gid;
1192 }
1193
1194 if (ATTR_CMN_ACCESSMASK & attr) {
1195 /*
1196 * [2856576] Since we are dynamically changing the owner, also
1197 * effectively turn off the set-user-id and set-group-id bits,
1198 * just like chmod(2) would when changing ownership. This prevents
1199 * a security hole where set-user-id programs run as whoever is
1200 * logged on (or root if nobody is logged in yet!)
1201 */
1202 *((uint32_t *)attrbufptr)++ =
1203 (cp->c_uid == UNKNOWNUID) ? cp->c_mode & ~(S_ISUID | S_ISGID) : cp->c_mode;
1204 }
1205 if (ATTR_CMN_NAMEDATTRCOUNT & attr) {
1206 *((uint32_t *)attrbufptr)++ = 0; /* XXX PPD TBC */
1207 }
1208 if (ATTR_CMN_NAMEDATTRLIST & attr) {
1209 attrlength = 0;
1210 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1211 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1212 /*
1213 * Advance beyond the space just allocated and
1214 * round up to the next 4-byte boundary:
1215 */
1216 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1217 ++((struct attrreference *)attrbufptr);
1218 }
1219 if (ATTR_CMN_FLAGS & attr) {
1220 *((uint32_t *)attrbufptr)++ = cp->c_flags;
1221 }
1222 if (ATTR_CMN_USERACCESS & attr) {
1223 *((uint32_t *)attrbufptr)++ =
1224 DerivePermissionSummary(cp->c_uid, cp->c_gid, cp->c_mode,
1225 VTOVFS(vp), kauth_cred_get(), proc_self());
1226 }
1227
1228 *abp->ab_attrbufpp = attrbufptr;
1229 *abp->ab_varbufpp = varbufptr;
1230 }
1231
1232
1233 static void
1234 packvolattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp)
1235 {
1236 attrgroup_t attr;
1237 void *attrbufptr = *abp->ab_attrbufpp;
1238 void *varbufptr = *abp->ab_varbufpp;
1239 struct cnode *cp = VTOC(vp);
1240 struct mount *mp = VTOVFS(vp);
1241 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1242 uint32_t attrlength;
1243
1244 attr = abp->ab_attrlist->volattr;
1245
1246 if (ATTR_VOL_FSTYPE & attr) {
1247 *((uint32_t *)attrbufptr)++ = (uint32_t)vfs_typenum(mp);
1248 }
1249 if (ATTR_VOL_SIGNATURE & attr) {
1250 *((uint32_t *)attrbufptr)++ = (uint32_t)vcb->vcbSigWord;
1251 }
1252 if (ATTR_VOL_SIZE & attr) {
1253 *((off_t *)attrbufptr)++ =
1254 (off_t)vcb->totalBlocks * (off_t)vcb->blockSize;
1255 }
1256 if (ATTR_VOL_SPACEFREE & attr) {
1257 *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 0) *
1258 (off_t)vcb->blockSize;
1259 }
1260 if (ATTR_VOL_SPACEAVAIL & attr) {
1261 *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 1) *
1262 (off_t)vcb->blockSize;
1263 }
1264 if (ATTR_VOL_MINALLOCATION & attr) {
1265 *((off_t *)attrbufptr)++ = (off_t)vcb->blockSize;
1266 }
1267 if (ATTR_VOL_ALLOCATIONCLUMP & attr) {
1268 *((off_t *)attrbufptr)++ = (off_t)(vcb->vcbClpSiz);
1269 }
1270 if (ATTR_VOL_IOBLOCKSIZE & attr) {
1271 *((uint32_t *)attrbufptr)++ = hfsmp->hfs_logBlockSize;
1272 }
1273 if (ATTR_VOL_OBJCOUNT & attr) {
1274 *((uint32_t *)attrbufptr)++ =
1275 (uint32_t)vcb->vcbFilCnt + (uint32_t)vcb->vcbDirCnt;
1276 }
1277 if (ATTR_VOL_FILECOUNT & attr) {
1278 *((uint32_t *)attrbufptr)++ = (uint32_t)vcb->vcbFilCnt;
1279 }
1280 if (ATTR_VOL_DIRCOUNT & attr) {
1281 *((uint32_t *)attrbufptr)++ = (uint32_t)vcb->vcbDirCnt;
1282 }
1283 if (ATTR_VOL_MAXOBJCOUNT & attr) {
1284 *((uint32_t *)attrbufptr)++ = 0xFFFFFFFF;
1285 }
1286 if (ATTR_VOL_MOUNTPOINT & attr) {
1287 ((struct attrreference *)attrbufptr)->attr_dataoffset =
1288 (char *)varbufptr - (char *)attrbufptr;
1289 ((struct attrreference *)attrbufptr)->attr_length =
1290 strlen(mp->mnt_vfsstat.f_mntonname) + 1;
1291 attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1292 /* round up to the next 4-byte boundary: */
1293 attrlength = attrlength + ((4 - (attrlength & 3)) & 3);
1294 (void) bcopy(mp->mnt_vfsstat.f_mntonname, varbufptr, attrlength);
1295
1296 /* Advance beyond the space just allocated: */
1297 (char *)varbufptr += attrlength;
1298 ++((struct attrreference *)attrbufptr);
1299 }
1300 if (ATTR_VOL_NAME & attr) {
1301 ((struct attrreference *)attrbufptr)->attr_dataoffset =
1302 (char *)varbufptr - (char *)attrbufptr;
1303 ((struct attrreference *)attrbufptr)->attr_length =
1304 cp->c_desc.cd_namelen + 1;
1305 attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1306 /* round up to the next 4-byte boundary: */
1307 attrlength = attrlength + ((4 - (attrlength & 3)) & 3);
1308 /* XXX this could read off the end of cd_nameptr! */
1309 bcopy(cp->c_desc.cd_nameptr, varbufptr, attrlength);
1310
1311 /* Advance beyond the space just allocated: */
1312 (char *)varbufptr += attrlength;
1313 ++((struct attrreference *)attrbufptr);
1314 }
1315 if (ATTR_VOL_MOUNTFLAGS & attr) {
1316 *((uint32_t *)attrbufptr)++ = (uint32_t)vfs_flags(mp);
1317 }
1318 if (ATTR_VOL_MOUNTEDDEVICE & attr) {
1319 ((struct attrreference *)attrbufptr)->attr_dataoffset =
1320 (char *)varbufptr - (char *)attrbufptr;
1321 ((struct attrreference *)attrbufptr)->attr_length =
1322 strlen(mp->mnt_vfsstat.f_mntfromname) + 1;
1323 attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1324 /* round up to the next 4-byte boundary: */
1325 attrlength = attrlength + ((4 - (attrlength & 3)) & 3);
1326 (void) bcopy(mp->mnt_vfsstat.f_mntfromname, varbufptr, attrlength);
1327
1328 /* Advance beyond the space just allocated: */
1329 (char *)varbufptr += attrlength;
1330 ++((struct attrreference *)attrbufptr);
1331 }
1332 if (ATTR_VOL_ENCODINGSUSED & attr) {
1333 *((unsigned long long *)attrbufptr)++ =
1334 (unsigned long long)vcb->encodingsBitmap;
1335 }
1336 if (ATTR_VOL_CAPABILITIES & attr) {
1337 vol_capabilities_attr_t *vcapattrptr;
1338
1339 vcapattrptr = (vol_capabilities_attr_t *)attrbufptr;
1340
1341 if (vcb->vcbSigWord == kHFSPlusSigWord) {
1342 u_int32_t journal_active_cap;
1343 u_int32_t case_sensitive;
1344
1345 if (hfsmp->jnl)
1346 journal_active_cap = VOL_CAP_FMT_JOURNAL_ACTIVE;
1347 else
1348 journal_active_cap = 0;
1349
1350 if (hfsmp->hfs_flags & HFS_CASE_SENSITIVE)
1351 case_sensitive = VOL_CAP_FMT_CASE_SENSITIVE;
1352 else
1353 case_sensitive = 0;
1354
1355 vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] =
1356 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1357 VOL_CAP_FMT_SYMBOLICLINKS |
1358 VOL_CAP_FMT_HARDLINKS |
1359 VOL_CAP_FMT_JOURNAL |
1360 journal_active_cap |
1361 case_sensitive |
1362 VOL_CAP_FMT_CASE_PRESERVING |
1363 VOL_CAP_FMT_FAST_STATFS |
1364 VOL_CAP_FMT_2TB_FILESIZE;
1365 } else { /* Plain HFS */
1366 vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] =
1367 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1368 VOL_CAP_FMT_CASE_PRESERVING |
1369 VOL_CAP_FMT_FAST_STATFS ;
1370 }
1371 vcapattrptr->capabilities[VOL_CAPABILITIES_INTERFACES] =
1372 VOL_CAP_INT_SEARCHFS |
1373 VOL_CAP_INT_ATTRLIST |
1374 VOL_CAP_INT_NFSEXPORT |
1375 VOL_CAP_INT_READDIRATTR |
1376 VOL_CAP_INT_EXCHANGEDATA |
1377 VOL_CAP_INT_ALLOCATE |
1378 VOL_CAP_INT_VOL_RENAME |
1379 VOL_CAP_INT_ADVLOCK |
1380 VOL_CAP_INT_FLOCK ;
1381 vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
1382 vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
1383
1384 vcapattrptr->valid[VOL_CAPABILITIES_FORMAT] =
1385 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1386 VOL_CAP_FMT_SYMBOLICLINKS |
1387 VOL_CAP_FMT_HARDLINKS |
1388 VOL_CAP_FMT_JOURNAL |
1389 VOL_CAP_FMT_JOURNAL_ACTIVE |
1390 VOL_CAP_FMT_NO_ROOT_TIMES |
1391 VOL_CAP_FMT_SPARSE_FILES |
1392 VOL_CAP_FMT_ZERO_RUNS |
1393 VOL_CAP_FMT_CASE_SENSITIVE |
1394 VOL_CAP_FMT_CASE_PRESERVING |
1395 VOL_CAP_FMT_FAST_STATFS |
1396 VOL_CAP_FMT_2TB_FILESIZE;
1397 vcapattrptr->valid[VOL_CAPABILITIES_INTERFACES] =
1398 VOL_CAP_INT_SEARCHFS |
1399 VOL_CAP_INT_ATTRLIST |
1400 VOL_CAP_INT_NFSEXPORT |
1401 VOL_CAP_INT_READDIRATTR |
1402 VOL_CAP_INT_EXCHANGEDATA |
1403 VOL_CAP_INT_COPYFILE |
1404 VOL_CAP_INT_ALLOCATE |
1405 VOL_CAP_INT_VOL_RENAME |
1406 VOL_CAP_INT_ADVLOCK |
1407 VOL_CAP_INT_FLOCK ;
1408 vcapattrptr->valid[VOL_CAPABILITIES_RESERVED1] = 0;
1409 vcapattrptr->valid[VOL_CAPABILITIES_RESERVED2] = 0;
1410
1411 ++((vol_capabilities_attr_t *)attrbufptr);
1412 }
1413 if (ATTR_VOL_ATTRIBUTES & attr) {
1414 vol_attributes_attr_t *volattrattrp;
1415
1416 volattrattrp = (vol_attributes_attr_t *)attrbufptr;
1417 volattrattrp->validattr.commonattr = ATTR_CMN_VALIDMASK;
1418 volattrattrp->validattr.volattr = ATTR_VOL_VALIDMASK;
1419 volattrattrp->validattr.dirattr = ATTR_DIR_VALIDMASK;
1420 volattrattrp->validattr.fileattr = ATTR_FILE_VALIDMASK;
1421 volattrattrp->validattr.forkattr = ATTR_FORK_VALIDMASK;
1422
1423 volattrattrp->nativeattr.commonattr = ATTR_CMN_VALIDMASK;
1424 volattrattrp->nativeattr.volattr = ATTR_VOL_VALIDMASK;
1425 volattrattrp->nativeattr.dirattr = ATTR_DIR_VALIDMASK;
1426 volattrattrp->nativeattr.fileattr = ATTR_FILE_VALIDMASK;
1427 volattrattrp->nativeattr.forkattr = ATTR_FORK_VALIDMASK;
1428 ++((vol_attributes_attr_t *)attrbufptr);
1429 }
1430
1431 *abp->ab_attrbufpp = attrbufptr;
1432 *abp->ab_varbufpp = varbufptr;
1433 }
1434
1435
1436 static void
1437 packcommonattr(
1438 struct attrblock *abp,
1439 struct hfsmount *hfsmp,
1440 struct vnode *vp,
1441 struct cat_desc * cdp,
1442 struct cat_attr * cap,
1443 struct proc *p)
1444 {
1445 attrgroup_t attr = abp->ab_attrlist->commonattr;
1446 struct mount *mp = HFSTOVFS(hfsmp);
1447 void *attrbufptr = *abp->ab_attrbufpp;
1448 void *varbufptr = *abp->ab_varbufpp;
1449 uint32_t attrlength = 0;
1450 boolean_t is_64_bit = proc_is64bit(p);
1451
1452 if (ATTR_CMN_NAME & attr) {
1453 packnameattr(abp, vp, cdp->cd_nameptr, cdp->cd_namelen);
1454 attrbufptr = *abp->ab_attrbufpp;
1455 varbufptr = *abp->ab_varbufpp;
1456 }
1457 if (ATTR_CMN_DEVID & attr) {
1458 *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev;
1459 }
1460 if (ATTR_CMN_FSID & attr) {
1461 fsid_t fsid;
1462
1463 fsid.val[0] = (long)hfsmp->hfs_raw_dev;
1464 fsid.val[1] = (long)vfs_typenum(mp);
1465 *((fsid_t *)attrbufptr) = fsid;
1466 ++((fsid_t *)attrbufptr);
1467 }
1468 if (ATTR_CMN_OBJTYPE & attr) {
1469 *((fsobj_type_t *)attrbufptr)++ = IFTOVT(cap->ca_mode);
1470 }
1471 if (ATTR_CMN_OBJTAG & attr) {
1472 *((fsobj_tag_t *)attrbufptr)++ = VT_HFS;
1473 }
1474 /*
1475 * Exporting file IDs from HFS Plus:
1476 *
1477 * For "normal" files the c_fileid is the same value as the
1478 * c_cnid. But for hard link files, they are different - the
1479 * c_cnid belongs to the active directory entry (ie the link)
1480 * and the c_fileid is for the actual inode (ie the data file).
1481 *
1482 * The stat call (getattr) will always return the c_fileid
1483 * and Carbon APIs, which are hardlink-ignorant, will always
1484 * receive the c_cnid (from getattrlist).
1485 */
1486 if (ATTR_CMN_OBJID & attr) {
1487 ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid;
1488 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1489 ++((fsobj_id_t *)attrbufptr);
1490 }
1491 if (ATTR_CMN_OBJPERMANENTID & attr) {
1492 ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid;
1493 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1494 ++((fsobj_id_t *)attrbufptr);
1495 }
1496 if (ATTR_CMN_PAROBJID & attr) {
1497 ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_parentcnid;
1498 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1499 ++((fsobj_id_t *)attrbufptr);
1500 }
1501 if (ATTR_CMN_SCRIPT & attr) {
1502 *((text_encoding_t *)attrbufptr)++ = cdp->cd_encoding;
1503 }
1504 if (ATTR_CMN_CRTIME & attr) {
1505 if (is_64_bit) {
1506 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_itime;
1507 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1508 ++((struct user_timespec *)attrbufptr);
1509 }
1510 else {
1511 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_itime;
1512 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1513 ++((struct timespec *)attrbufptr);
1514 }
1515 }
1516 if (ATTR_CMN_MODTIME & attr) {
1517 if (is_64_bit) {
1518 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_mtime;
1519 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1520 ++((struct user_timespec *)attrbufptr);
1521 }
1522 else {
1523 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_mtime;
1524 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1525 ++((struct timespec *)attrbufptr);
1526 }
1527 }
1528 if (ATTR_CMN_CHGTIME & attr) {
1529 if (is_64_bit) {
1530 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_ctime;
1531 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1532 ++((struct user_timespec *)attrbufptr);
1533 }
1534 else {
1535 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_ctime;
1536 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1537 ++((struct timespec *)attrbufptr);
1538 }
1539 }
1540 if (ATTR_CMN_ACCTIME & attr) {
1541 if (is_64_bit) {
1542 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_atime;
1543 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1544 ++((struct user_timespec *)attrbufptr);
1545 }
1546 else {
1547 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_atime;
1548 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1549 ++((struct timespec *)attrbufptr);
1550 }
1551 }
1552 if (ATTR_CMN_BKUPTIME & attr) {
1553 if (is_64_bit) {
1554 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_btime;
1555 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1556 ++((struct user_timespec *)attrbufptr);
1557 }
1558 else {
1559 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_btime;
1560 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1561 ++((struct timespec *)attrbufptr);
1562 }
1563 }
1564 if (ATTR_CMN_FNDRINFO & attr) {
1565 bcopy(&cap->ca_finderinfo, attrbufptr, sizeof(u_int8_t) * 32);
1566 (char *)attrbufptr += sizeof(u_int8_t) * 32;
1567 }
1568 if (ATTR_CMN_OWNERID & attr) {
1569 *((uid_t *)attrbufptr)++ =
1570 (cap->ca_uid == UNKNOWNUID) ? kauth_cred_getuid(proc_ucred(p)) : cap->ca_uid;
1571 }
1572 if (ATTR_CMN_GRPID & attr) {
1573 *((gid_t *)attrbufptr)++ = cap->ca_gid;
1574 }
1575 if (ATTR_CMN_ACCESSMASK & attr) {
1576 /*
1577 * [2856576] Since we are dynamically changing the owner, also
1578 * effectively turn off the set-user-id and set-group-id bits,
1579 * just like chmod(2) would when changing ownership. This prevents
1580 * a security hole where set-user-id programs run as whoever is
1581 * logged on (or root if nobody is logged in yet!)
1582 */
1583 *((uint32_t *)attrbufptr)++ =
1584 (cap->ca_uid == UNKNOWNUID) ? cap->ca_mode & ~(S_ISUID | S_ISGID) : cap->ca_mode;
1585 }
1586 if (ATTR_CMN_NAMEDATTRCOUNT & attr) {
1587 *((uint32_t *)attrbufptr)++ = 0;
1588 }
1589 if (ATTR_CMN_NAMEDATTRLIST & attr) {
1590 attrlength = 0;
1591 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1592 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1593 /*
1594 * Advance beyond the space just allocated and
1595 * round up to the next 4-byte boundary:
1596 */
1597 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1598 ++((struct attrreference *)attrbufptr);
1599 }
1600 if (ATTR_CMN_FLAGS & attr) {
1601 *((uint32_t *)attrbufptr)++ = cap->ca_flags;
1602 }
1603 if (ATTR_CMN_USERACCESS & attr) {
1604 *((uint32_t *)attrbufptr)++ =
1605 DerivePermissionSummary(cap->ca_uid, cap->ca_gid,
1606 cap->ca_mode, mp, proc_ucred(current_proc()),
1607 current_proc());
1608 }
1609
1610 *abp->ab_attrbufpp = attrbufptr;
1611 *abp->ab_varbufpp = varbufptr;
1612 }
1613
1614 static void
1615 packdirattr(
1616 struct attrblock *abp,
1617 struct hfsmount *hfsmp,
1618 struct vnode *vp,
1619 struct cat_desc * descp,
1620 struct cat_attr * cattrp)
1621 {
1622 attrgroup_t attr = abp->ab_attrlist->dirattr;
1623 void *attrbufptr = *abp->ab_attrbufpp;
1624
1625 if (ATTR_DIR_LINKCOUNT & attr)
1626 *((uint32_t *)attrbufptr)++ = cattrp->ca_nlink;
1627 if (ATTR_DIR_ENTRYCOUNT & attr) {
1628 uint32_t entries = cattrp->ca_entries;
1629
1630 if (descp->cd_parentcnid == kHFSRootParentID) {
1631 if (hfsmp->hfs_privdir_desc.cd_cnid != 0)
1632 --entries; /* hide private dir */
1633 if (hfsmp->jnl || ((HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY)))
1634 entries -= 2; /* hide the journal files */
1635 }
1636
1637 *((uint32_t *)attrbufptr)++ = entries;
1638 }
1639 if (ATTR_DIR_MOUNTSTATUS & attr) {
1640 if (vp != NULL && vnode_mountedhere(vp) != NULL)
1641 *((uint32_t *)attrbufptr)++ = DIR_MNTSTATUS_MNTPOINT;
1642 else
1643 *((uint32_t *)attrbufptr)++ = 0;
1644 }
1645 *abp->ab_attrbufpp = attrbufptr;
1646 }
1647
1648 static void
1649 packfileattr(
1650 struct attrblock *abp,
1651 struct hfsmount *hfsmp,
1652 struct cat_attr *cattrp,
1653 struct cat_fork *datafork,
1654 struct cat_fork *rsrcfork)
1655 {
1656 attrgroup_t attr = abp->ab_attrlist->fileattr;
1657 void *attrbufptr = *abp->ab_attrbufpp;
1658 void *varbufptr = *abp->ab_varbufpp;
1659 uint32_t attrlength;
1660 uint32_t allocblksize;
1661
1662 allocblksize = HFSTOVCB(hfsmp)->blockSize;
1663
1664 if (ATTR_FILE_LINKCOUNT & attr) {
1665 *((uint32_t *)attrbufptr)++ = cattrp->ca_nlink;
1666 }
1667 if (ATTR_FILE_TOTALSIZE & attr) {
1668 *((off_t *)attrbufptr)++ = datafork->cf_size + rsrcfork->cf_size;
1669 }
1670 if (ATTR_FILE_ALLOCSIZE & attr) {
1671 *((off_t *)attrbufptr)++ =
1672 (off_t)cattrp->ca_blocks * (off_t)allocblksize;
1673 }
1674 if (ATTR_FILE_IOBLOCKSIZE & attr) {
1675 *((uint32_t *)attrbufptr)++ = hfsmp->hfs_logBlockSize;
1676 }
1677 if (ATTR_FILE_CLUMPSIZE & attr) {
1678 *((uint32_t *)attrbufptr)++ = HFSTOVCB(hfsmp)->vcbClpSiz;
1679 }
1680 if (ATTR_FILE_DEVTYPE & attr) {
1681 if (S_ISBLK(cattrp->ca_mode) || S_ISCHR(cattrp->ca_mode))
1682 *((uint32_t *)attrbufptr)++ = (uint32_t)cattrp->ca_rdev;
1683 else
1684 *((uint32_t *)attrbufptr)++ = 0;
1685 }
1686 if (ATTR_FILE_FILETYPE & attr) {
1687 *((uint32_t *)attrbufptr)++ = 0;
1688 }
1689 if (ATTR_FILE_FORKCOUNT & attr) {
1690 *((uint32_t *)attrbufptr)++ = 2;
1691 }
1692 if (ATTR_FILE_FORKLIST & attr) {
1693 attrlength = 0;
1694 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1695 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1696 /*
1697 * Advance beyond the space just allocated and
1698 * round up to the next 4-byte boundary:
1699 */
1700 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1701 ++((struct attrreference *)attrbufptr);
1702 }
1703 if (ATTR_FILE_DATALENGTH & attr) {
1704 *((off_t *)attrbufptr)++ = datafork->cf_size;
1705 }
1706 if (ATTR_FILE_DATAALLOCSIZE & attr) {
1707 *((off_t *)attrbufptr)++ =
1708 (off_t)datafork->cf_blocks * (off_t)allocblksize;
1709 }
1710 if (ATTR_FILE_DATAEXTENTS & attr) {
1711 bcopy(&datafork->cf_extents, attrbufptr, sizeof(extentrecord));
1712 (char *)attrbufptr += sizeof(extentrecord);
1713 }
1714 if (ATTR_FILE_RSRCLENGTH & attr) {
1715 *((off_t *)attrbufptr)++ = rsrcfork->cf_size;
1716 }
1717 if (ATTR_FILE_RSRCALLOCSIZE & attr) {
1718 *((off_t *)attrbufptr)++ =
1719 (off_t)rsrcfork->cf_blocks * (off_t)allocblksize;
1720 }
1721 if (ATTR_FILE_RSRCEXTENTS & attr) {
1722 bcopy(&rsrcfork->cf_extents, attrbufptr, sizeof(extentrecord));
1723 (char *)attrbufptr += sizeof(extentrecord);
1724 }
1725 *abp->ab_attrbufpp = attrbufptr;
1726 *abp->ab_varbufpp = varbufptr;
1727 }
1728
1729 #if 0
1730 static int
1731 unpackattrblk(struct attrblock *abp, struct vnode *vp)
1732 {
1733 struct attrlist *attrlistp = abp->ab_attrlist;
1734 int error;
1735
1736 if (attrlistp->volattr) {
1737 error = unpackvolattr(abp, VTOHFS(vp), vp);
1738 if (error)
1739 return (error);
1740 } else if (attrlistp->commonattr) {
1741 unpackcommonattr(abp, vp);
1742 }
1743 return (0);
1744 }
1745
1746
1747 static void
1748 unpackcommonattr(
1749 struct attrblock *abp,
1750 struct vnode *vp)
1751 {
1752 attrgroup_t attr = abp->ab_attrlist->commonattr;
1753 void *attrbufptr = *abp->ab_attrbufpp;
1754 struct cnode *cp = VTOC(vp);
1755 boolean_t is_64_bit = proc_is64bit(current_proc());
1756
1757 if (ATTR_CMN_SCRIPT & attr) {
1758 cp->c_encoding = (u_int32_t)*((text_encoding_t *)attrbufptr)++;
1759 hfs_setencodingbits(VTOHFS(vp), cp->c_encoding);
1760 }
1761 if (ATTR_CMN_CRTIME & attr) {
1762 if (is_64_bit) {
1763 cp->c_itime = ((struct user_timespec *)attrbufptr)->tv_sec;
1764 ++((struct user_timespec *)attrbufptr);
1765 }
1766 else {
1767 cp->c_itime = ((struct timespec *)attrbufptr)->tv_sec;
1768 ++((struct timespec *)attrbufptr);
1769 }
1770 }
1771 if (ATTR_CMN_MODTIME & attr) {
1772 cp->c_mtime = ((struct timespec *)attrbufptr)->tv_sec;
1773 ++((struct timespec *)attrbufptr);
1774 cp->c_touch_modtime = FALSE;
1775 }
1776 if (ATTR_CMN_CHGTIME & attr) {
1777 cp->c_ctime = ((struct timespec *)attrbufptr)->tv_sec;
1778 ++((struct timespec *)attrbufptr);
1779 cp->c_touch_chgtime = FALSE;
1780 }
1781 if (ATTR_CMN_ACCTIME & attr) {
1782 cp->c_atime = ((struct timespec *)attrbufptr)->tv_sec;
1783 ++((struct timespec *)attrbufptr);
1784 cp->c_touch_acctime = FALSE;
1785 }
1786 if (ATTR_CMN_BKUPTIME & attr) {
1787 cp->c_btime = ((struct timespec *)attrbufptr)->tv_sec;
1788 ++((struct timespec *)attrbufptr);
1789 }
1790 if (ATTR_CMN_FNDRINFO & attr) {
1791 bcopy(attrbufptr, &cp->c_attr.ca_finderinfo,
1792 sizeof(cp->c_attr.ca_finderinfo));
1793 (char *)attrbufptr += sizeof(cp->c_attr.ca_finderinfo);
1794 }
1795 if (ATTR_CMN_OWNERID & attr) {
1796 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
1797 u_int32_t uid = (u_int32_t)*((uid_t *)attrbufptr)++;
1798 if (uid != (uid_t)VNOVAL)
1799 cp->c_uid = uid;
1800 } else {
1801 ((uid_t *)attrbufptr)++;
1802 }
1803 }
1804 if (ATTR_CMN_GRPID & attr) {
1805 u_int32_t gid = (u_int32_t)*((gid_t *)attrbufptr)++;
1806 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
1807 if (gid != (gid_t)VNOVAL)
1808 cp->c_gid = gid;
1809 }
1810 }
1811 if (ATTR_CMN_ACCESSMASK & attr) {
1812 u_int16_t mode = (u_int16_t)*((uint32_t *)attrbufptr)++;
1813 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
1814 if (mode != (mode_t)VNOVAL) {
1815 cp->c_mode &= ~ALLPERMS;
1816 cp->c_mode |= (mode & ALLPERMS);
1817 }
1818 }
1819 }
1820 if (ATTR_CMN_FLAGS & attr) {
1821 uint32_t flags = *((uint32_t *)attrbufptr)++;
1822 /*
1823 * Flags are settable only on HFS+ volumes. A special
1824 * exception is made for the IMMUTABLE flags
1825 * (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on
1826 * HFS volumes as well:
1827 */
1828 if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) ||
1829 ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) &&
1830 ((flags & ~IMMUTABLE) == 0))) {
1831 if (flags != (uint32_t)VNOVAL) {
1832 cp->c_flags = flags;
1833 }
1834 }
1835 }
1836 *abp->ab_attrbufpp = attrbufptr;
1837 }
1838
1839
1840 static int
1841 unpackvolattr(
1842 struct attrblock *abp,
1843 struct hfsmount *hfsmp,
1844 struct vnode *root_vp)
1845 {
1846 void *attrbufptr = *abp->ab_attrbufpp;
1847 attrgroup_t attr;
1848 int error = 0;
1849 boolean_t is_64_bit = proc_is64bit(current_proc());
1850
1851 HFS_MOUNT_LOCK(hfsmp, TRUE);
1852
1853 attr = abp->ab_attrlist->commonattr;
1854 if (attr == 0)
1855 goto volattr;
1856
1857 if (ATTR_CMN_SCRIPT & attr) {
1858 hfsmp->volumeNameEncodingHint =
1859 (u_int32_t)*(((text_encoding_t *)attrbufptr)++);
1860 }
1861 if (ATTR_CMN_CRTIME & attr) {
1862 if (is_64_bit) {
1863 hfsmp->vcbCrDate = ((struct user_timespec *)attrbufptr)->tv_sec;
1864 ++((struct user_timespec *)attrbufptr);
1865 }
1866 else {
1867 hfsmp->vcbCrDate = ((struct timespec *)attrbufptr)->tv_sec;
1868 ++((struct timespec *)attrbufptr);
1869 }
1870
1871 /* The volume's create date comes from the root directory */
1872 VTOC(root_vp)->c_itime = hfsmp->vcbCrDate;
1873 VTOC(root_vp)->c_flag |= C_MODIFIED;
1874 /*
1875 * XXX Should we also do a relative change to the
1876 * the volume header's create date in local time?
1877 */
1878 }
1879 if (ATTR_CMN_MODTIME & attr) {
1880 hfsmp->vcbLsMod = ((struct timespec *)attrbufptr)->tv_sec;
1881 ++((struct timespec *)attrbufptr);
1882 }
1883 if (ATTR_CMN_BKUPTIME & attr) {
1884 hfsmp->vcbVolBkUp = ((struct timespec *)attrbufptr)->tv_sec;
1885 ++((struct timespec *)attrbufptr);
1886 }
1887 if (ATTR_CMN_FNDRINFO & attr) {
1888 bcopy(attrbufptr, &hfsmp->vcbFndrInfo, sizeof(hfsmp->vcbFndrInfo));
1889 (char *)attrbufptr += sizeof(hfsmp->vcbFndrInfo);
1890 }
1891
1892 volattr:
1893 attr = abp->ab_attrlist->volattr & ~ATTR_VOL_INFO;
1894 /*
1895 * XXX - no validation is done on the name!
1896 * It could be empty or garbage (bad UTF-8).
1897 */
1898 if (ATTR_VOL_NAME & attr) {
1899 attrreference_t * attr_refp = (attrreference_t *) attrbufptr;
1900
1901 error = copystr(((char *)attrbufptr) + attr_refp->attr_dataoffset,
1902 hfsmp->vcbVN, MIN(attr_refp->attr_length, sizeof(hfsmp->vcbVN)),
1903 NULL);
1904 if (error == 0)
1905 (char *)attrbufptr += sizeof(struct attrreference);
1906 }
1907 *abp->ab_attrbufpp = attrbufptr;
1908
1909 hfsmp->vcbFlags |= 0xFF00;
1910 HFS_MOUNT_UNLOCK(hfsmp, TRUE);
1911
1912 return (error);
1913 }
1914 #endif
1915
1916 /*
1917 * Calculate the total size of an attribute block.
1918 */
1919 __private_extern__
1920 int
1921 hfs_attrblksize(struct attrlist *attrlist)
1922 {
1923 int size;
1924 attrgroup_t a;
1925 int sizeof_timespec;
1926 boolean_t is_64_bit = proc_is64bit(current_proc());
1927
1928 if (is_64_bit)
1929 sizeof_timespec = sizeof(struct user_timespec);
1930 else
1931 sizeof_timespec = sizeof(struct timespec);
1932
1933 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1934 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | \
1935 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | \
1936 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | \
1937 ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1938 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | \
1939 ATTR_CMN_NAMEDATTRLIST | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) \
1940 != ATTR_CMN_VALIDMASK)
1941 #error hfs_attrblksize: Missing bits in common mask computation!
1942 #endif
1943 DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0);
1944
1945 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | \
1946 ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
1947 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1948 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | \
1949 ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | \
1950 ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | ATTR_VOL_MOUNTEDDEVICE | \
1951 ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) \
1952 != ATTR_VOL_VALIDMASK)
1953 #error hfs_attrblksize: Missing bits in volume mask computation!
1954 #endif
1955 DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0);
1956
1957 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) \
1958 != ATTR_DIR_VALIDMASK)
1959 #error hfs_attrblksize: Missing bits in directory mask computation!
1960 #endif
1961 DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0);
1962
1963 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \
1964 ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | \
1965 ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST | \
1966 ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1967 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) \
1968 != ATTR_FILE_VALIDMASK)
1969 #error hfs_attrblksize: Missing bits in file mask computation!
1970 #endif
1971 DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0);
1972
1973 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1974 #error hfs_attrblksize: Missing bits in fork mask computation!
1975 #endif
1976 DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0);
1977
1978 size = 0;
1979
1980 if ((a = attrlist->commonattr) != 0) {
1981 if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference);
1982 if (a & ATTR_CMN_DEVID) size += sizeof(dev_t);
1983 if (a & ATTR_CMN_FSID) size += sizeof(fsid_t);
1984 if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t);
1985 if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t);
1986 if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t);
1987 if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t);
1988 if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t);
1989 if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t);
1990 if (a & ATTR_CMN_CRTIME) size += sizeof_timespec;
1991 if (a & ATTR_CMN_MODTIME) size += sizeof_timespec;
1992 if (a & ATTR_CMN_CHGTIME) size += sizeof_timespec;
1993 if (a & ATTR_CMN_ACCTIME) size += sizeof_timespec;
1994 if (a & ATTR_CMN_BKUPTIME) size += sizeof_timespec;
1995 if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(u_int8_t);
1996 if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t);
1997 if (a & ATTR_CMN_GRPID) size += sizeof(gid_t);
1998 if (a & ATTR_CMN_ACCESSMASK) size += sizeof(uint32_t);
1999 if (a & ATTR_CMN_NAMEDATTRCOUNT) size += sizeof(uint32_t);
2000 if (a & ATTR_CMN_NAMEDATTRLIST) size += sizeof(struct attrreference);
2001 if (a & ATTR_CMN_FLAGS) size += sizeof(uint32_t);
2002 if (a & ATTR_CMN_USERACCESS) size += sizeof(uint32_t);
2003 };
2004 if ((a = attrlist->volattr) != 0) {
2005 if (a & ATTR_VOL_FSTYPE) size += sizeof(uint32_t);
2006 if (a & ATTR_VOL_SIGNATURE) size += sizeof(uint32_t);
2007 if (a & ATTR_VOL_SIZE) size += sizeof(off_t);
2008 if (a & ATTR_VOL_SPACEFREE) size += sizeof(off_t);
2009 if (a & ATTR_VOL_SPACEAVAIL) size += sizeof(off_t);
2010 if (a & ATTR_VOL_MINALLOCATION) size += sizeof(off_t);
2011 if (a & ATTR_VOL_ALLOCATIONCLUMP) size += sizeof(off_t);
2012 if (a & ATTR_VOL_IOBLOCKSIZE) size += sizeof(uint32_t);
2013 if (a & ATTR_VOL_OBJCOUNT) size += sizeof(uint32_t);
2014 if (a & ATTR_VOL_FILECOUNT) size += sizeof(uint32_t);
2015 if (a & ATTR_VOL_DIRCOUNT) size += sizeof(uint32_t);
2016 if (a & ATTR_VOL_MAXOBJCOUNT) size += sizeof(uint32_t);
2017 if (a & ATTR_VOL_MOUNTPOINT) size += sizeof(struct attrreference);
2018 if (a & ATTR_VOL_NAME) size += sizeof(struct attrreference);
2019 if (a & ATTR_VOL_MOUNTFLAGS) size += sizeof(uint32_t);
2020 if (a & ATTR_VOL_MOUNTEDDEVICE) size += sizeof(struct attrreference);
2021 if (a & ATTR_VOL_ENCODINGSUSED) size += sizeof(unsigned long long);
2022 if (a & ATTR_VOL_CAPABILITIES) size += sizeof(vol_capabilities_attr_t);
2023 if (a & ATTR_VOL_ATTRIBUTES) size += sizeof(vol_attributes_attr_t);
2024 };
2025 if ((a = attrlist->dirattr) != 0) {
2026 if (a & ATTR_DIR_LINKCOUNT) size += sizeof(uint32_t);
2027 if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(uint32_t);
2028 if (a & ATTR_DIR_MOUNTSTATUS) size += sizeof(uint32_t);
2029 };
2030 if ((a = attrlist->fileattr) != 0) {
2031 if (a & ATTR_FILE_LINKCOUNT) size += sizeof(uint32_t);
2032 if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t);
2033 if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t);
2034 if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(uint32_t);
2035 if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(uint32_t);
2036 if (a & ATTR_FILE_DEVTYPE) size += sizeof(uint32_t);
2037 if (a & ATTR_FILE_FILETYPE) size += sizeof(uint32_t);
2038 if (a & ATTR_FILE_FORKCOUNT) size += sizeof(uint32_t);
2039 if (a & ATTR_FILE_FORKLIST) size += sizeof(struct attrreference);
2040 if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t);
2041 if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t);
2042 if (a & ATTR_FILE_DATAEXTENTS) size += sizeof(extentrecord);
2043 if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t);
2044 if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t);
2045 if (a & ATTR_FILE_RSRCEXTENTS) size += sizeof(extentrecord);
2046 };
2047 if ((a = attrlist->forkattr) != 0) {
2048 if (a & ATTR_FORK_TOTALSIZE) size += sizeof(off_t);
2049 if (a & ATTR_FORK_ALLOCSIZE) size += sizeof(off_t);
2050 };
2051
2052 return size;
2053 }
2054
2055
2056 __private_extern__
2057 unsigned long
2058 DerivePermissionSummary(uid_t obj_uid, gid_t obj_gid, mode_t obj_mode,
2059 struct mount *mp, kauth_cred_t cred, struct proc *p)
2060 {
2061 unsigned long permissions;
2062
2063 if (obj_uid == UNKNOWNUID)
2064 obj_uid = kauth_cred_getuid(proc_ucred(p));
2065
2066 /* User id 0 (root) always gets access. */
2067 if (!suser(cred, NULL)) {
2068 permissions = R_OK | W_OK | X_OK;
2069 goto Exit;
2070 };
2071
2072 /* Otherwise, check the owner. */
2073 if (hfs_owner_rights(VFSTOHFS(mp), obj_uid, cred, p, false) == 0) {
2074 permissions = ((unsigned long)obj_mode & S_IRWXU) >> 6;
2075 goto Exit;
2076 }
2077
2078 /* Otherwise, check the groups. */
2079 if (! (((unsigned int)vfs_flags(mp)) & MNT_UNKNOWNPERMISSIONS)) {
2080 int is_member;
2081
2082 if (kauth_cred_ismember_gid(cred, obj_gid, &is_member) == 0 && is_member) {
2083 permissions = ((unsigned long)obj_mode & S_IRWXG) >> 3;
2084 goto Exit;
2085 }
2086 }
2087
2088 /* Otherwise, settle for 'others' access. */
2089 permissions = (unsigned long)obj_mode & S_IRWXO;
2090
2091 Exit:
2092 return (permissions);
2093 }
2094