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