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