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