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