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