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