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