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