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