1 /* $NetBSD: darwin_attr.c,v 1.25 2009/01/11 02:45:47 christos Exp $ */
4 * Copyright (c) 2003, 2008 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: darwin_attr.c,v 1.25 2009/01/11 02:45:47 christos Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/types.h>
39 #include <sys/mount.h>
42 #include <sys/filedesc.h>
43 #include <sys/namei.h>
44 #include <sys/vnode.h>
45 #include <sys/malloc.h>
47 #include <sys/syscallargs.h>
48 #include <sys/vfs_syscalls.h>
49 #include <sys/kauth.h>
51 #include <compat/sys/signal.h>
52 #include <compat/sys/mount.h>
54 #include <compat/common/compat_util.h>
56 #include <compat/mach/mach_types.h>
57 #include <compat/mach/mach_vm.h>
59 #include <compat/darwin/darwin_types.h>
60 #include <compat/darwin/darwin_audit.h>
61 #include <compat/darwin/darwin_attr.h>
62 #include <compat/darwin/darwin_syscallargs.h>
64 #define DARWIN_ATTR_MAXBUFLEN 4096
66 static int darwin_attr_append(const char *, size_t, char **, size_t *);
68 #define ATTR_APPEND(x, bp, len) \
69 darwin_attr_append((char *)&(x), sizeof(x), &(bp), &(len))
73 darwin_attr_append(const char *x
, size_t size
, char **bp
, size_t *len
)
78 (void)memcpy(*bp
, x
, size
);
87 darwin_sys_getattrlist(struct lwp
*l
, const struct darwin_sys_getattrlist_args
*uap
, register_t
*retval
)
90 syscallarg(const char *) path;
91 syscallarg(struct darwin_attrlist *) alist;
92 syscallarg(void *) attributes;
93 syscallarg(size_t) buflen;
94 syscallarg(unsigned long) options;
96 struct darwin_attrlist kalist
;
103 int follow
= NOFOLLOW
;
104 u_long
*whole_len_p
= NULL
;
105 darwin_attrreference_t
*cmn_name_p
= NULL
;
106 darwin_attrreference_t
*vol_mountpoint_p
= NULL
;
107 darwin_attrreference_t
*vol_name_p
= NULL
;
108 darwin_attrreference_t
*vol_mounteddevice_p
= NULL
;
115 if ((error
= copyin(SCARG(uap
, alist
), &kalist
, sizeof(kalist
))) != 0)
118 if (kalist
.bitmapcount
!= DARWIN_ATTR_BIT_MAP_COUNT
)
121 len
= SCARG(uap
, buflen
);
122 if (len
> DARWIN_ATTR_MAXBUFLEN
)
125 if ((SCARG(uap
, options
) & DARWIN_FSOPT_NOFOLLOW
) != 0)
129 printf("getattrlist: %08x %08x %08x %08x %08x\n",
130 kalist
.commonattr
, kalist
.volattr
, kalist
.dirattr
,
131 kalist
.fileattr
, kalist
.forkattr
);
134 /* Allocate buffers now... */
135 f
= STATVFSBUF_GET();
136 tbuf
= malloc(len
, M_TEMP
, M_WAITOK
);
138 /* We are going to need the vnode itself... */
140 cred
= kauth_cred_dup(l
->l_cred
);
141 kauth_cred_seteuid(cred
, kauth_cred_getuid(l
->l_cred
));
142 kauth_cred_setegid(cred
, kauth_cred_getgid(l
->l_cred
));
144 NDINIT(&nd
, LOOKUP
, follow
| LOCKLEAF
| TRYEMULROOT
, UIO_USERSPACE
,
146 if ((error
= namei(&nd
)) != 0)
150 if ((error
= VOP_ACCESS(vp
, VREAD
| VEXEC
, cred
)) != 0)
153 /* Get the informations for path: file related info */
154 error
= vn_stat(vp
, &st
);
158 /* filesystem related info */
159 error
= dostatvfs(vp
->v_mount
, f
, l
, 0, 1);
169 * Buffer whole length: is always present
175 whole_len_p
= (u_long
*)bp
;
176 if (ATTR_APPEND(whole_len
, bp
, len
) != 0)
180 if (kalist
.commonattr
& DARWIN_ATTR_CMN_NAME
) {
181 darwin_attrreference_t dar
;
183 cmn_name_p
= (darwin_attrreference_t
*)bp
;
184 if (ATTR_APPEND(dar
, bp
, len
) != 0)
188 if (kalist
.commonattr
& DARWIN_ATTR_CMN_DEVID
) {
192 if (ATTR_APPEND(device
, bp
, len
) != 0)
196 if (kalist
.commonattr
& DARWIN_ATTR_CMN_FSID
) {
199 if (ATTR_APPEND(fs
, bp
, len
) != 0)
203 if (kalist
.commonattr
& DARWIN_ATTR_CMN_OBJTYPE
) {
204 darwin_fsobj_type_t dft
;
207 if (ATTR_APPEND(dft
, bp
, len
) != 0)
211 if (kalist
.commonattr
& DARWIN_ATTR_CMN_OBJTAG
) {
212 darwin_fsobj_tag_t dft
;
215 if (ATTR_APPEND(dft
, bp
, len
) != 0)
219 if (kalist
.commonattr
& DARWIN_ATTR_CMN_OBJID
) {
220 darwin_fsobj_id_t dfi
;
222 dfi
.fid_objno
= st
.st_ino
;
223 dfi
.fid_generation
= 0; /* XXX root can read real value */
224 if (ATTR_APPEND(dfi
, bp
, len
) != 0)
228 if (kalist
.commonattr
& DARWIN_ATTR_CMN_OBJPERMANENTID
) {
229 darwin_fsobj_id_t dfi
;
231 dfi
.fid_objno
= st
.st_ino
; /* This is not really persistent */
232 dfi
.fid_generation
= 0; /* XXX root can read real value */
233 if (ATTR_APPEND(dfi
, bp
, len
) != 0)
237 if (kalist
.commonattr
& DARWIN_ATTR_CMN_PAROBJID
) {
238 darwin_fsobj_id_t dfi
;
240 dfi
.fid_objno
= 0; /* XXX do me */
241 dfi
.fid_generation
= 0; /* XXX root can read real value */
242 if (ATTR_APPEND(dfi
, bp
, len
) != 0)
246 if (kalist
.commonattr
& DARWIN_ATTR_CMN_SCRIPT
) {
247 darwin_text_encoding_t dte
;
249 dte
= DARWIN_US_ASCII
;
250 if (ATTR_APPEND(dte
, bp
, len
) != 0)
254 if (kalist
.commonattr
& DARWIN_ATTR_CMN_CRTIME
) {
255 if (ATTR_APPEND(st
.st_ctimespec
, bp
, len
) != 0)
259 if (kalist
.commonattr
& DARWIN_ATTR_CMN_MODTIME
) {
260 if (ATTR_APPEND(st
.st_mtimespec
, bp
, len
) != 0)
264 if (kalist
.commonattr
& DARWIN_ATTR_CMN_CHGTIME
) {
265 if (ATTR_APPEND(st
.st_ctimespec
, bp
, len
) != 0)
269 if (kalist
.commonattr
& DARWIN_ATTR_CMN_ACCTIME
) {
270 if (ATTR_APPEND(st
.st_atimespec
, bp
, len
) != 0)
274 if (kalist
.commonattr
& DARWIN_ATTR_CMN_BKUPTIME
) {
277 /* XXX no way I can do that one */
279 (void)memset(&ts
, 0, sizeof(ts
));
280 if (ATTR_APPEND(ts
, bp
, len
) != 0)
284 if (kalist
.commonattr
& DARWIN_ATTR_CMN_FNDRINFO
) { /* XXX */
287 (void)memset(&data
, 0, sizeof(data
));
288 if (ATTR_APPEND(data
, bp
, len
) != 0)
292 if (kalist
.commonattr
& DARWIN_ATTR_CMN_OWNERID
) {
296 if (ATTR_APPEND(uid
, bp
, len
) != 0)
300 if (kalist
.commonattr
& DARWIN_ATTR_CMN_GRPID
) {
304 if (ATTR_APPEND(gid
, bp
, len
) != 0)
308 if (kalist
.commonattr
& DARWIN_ATTR_CMN_ACCESSMASK
) {
312 if (ATTR_APPEND(mode
, bp
, len
) != 0)
316 if (kalist
.commonattr
& DARWIN_ATTR_CMN_NAMEDATTRCOUNT
) {
317 /* Data is unsigned long. Unsupported in Darwin */
322 if (kalist
.commonattr
& DARWIN_ATTR_CMN_NAMEDATTRLIST
) {
323 /* Data is darwin_attrreference_t. Unsupported in Darwin */
329 if (kalist
.commonattr
& DARWIN_ATTR_CMN_FLAGS
) {
332 flags
= st
.st_flags
; /* XXX need convertion */
333 if (ATTR_APPEND(flags
, bp
, len
) != 0)
337 if (kalist
.commonattr
& DARWIN_ATTR_CMN_USERACCESS
) {
338 unsigned long ua
= 0;
339 struct sys_access_args cup3
;
342 SCARG(&cup3
, path
) = SCARG(uap
, path
);
344 SCARG(&cup3
, flags
) = R_OK
;
345 if (sys_access(l
, &cup3
, &rv
) == 0)
348 SCARG(&cup3
, flags
) = W_OK
;
349 if (sys_access(l
, &cup3
, &rv
) == 0)
352 SCARG(&cup3
, flags
) = X_OK
;
353 if (sys_access(l
, &cup3
, &rv
) == 0)
356 if (ATTR_APPEND(ua
, bp
, len
) != 0)
361 if (kalist
.volattr
& DARWIN_ATTR_VOL_INFO
) {
362 /* Nothing added, just skip */
365 if (kalist
.volattr
& DARWIN_ATTR_VOL_FSTYPE
) {
366 unsigned long fstype
;
368 /* We'd need to convert f_fstypename - done for COMPAT_09 */
369 fstype
= 0; /* f->f_type; */
370 if (ATTR_APPEND(fstype
, bp
, len
) != 0)
374 if (kalist
.volattr
& DARWIN_ATTR_VOL_SIGNATURE
) {
378 * XXX Volume signature, used to distinguish
379 * between volumes inside the same filesystem.
381 sign
= f
->f_fsidx
.__fsid_val
[0];
382 if (ATTR_APPEND(sign
, bp
, len
) != 0)
386 if (kalist
.volattr
& DARWIN_ATTR_VOL_SIZE
) {
389 size
= f
->f_blocks
* f
->f_bsize
;
390 if (ATTR_APPEND(size
, bp
, len
) != 0)
394 if (kalist
.volattr
& DARWIN_ATTR_VOL_SPACEFREE
) {
397 ofree
= f
->f_bfree
* f
->f_bsize
;
398 if (ATTR_APPEND(ofree
, bp
, len
) != 0)
402 if (kalist
.volattr
& DARWIN_ATTR_VOL_SPACEAVAIL
) {
405 avail
= f
->f_bavail
* f
->f_bsize
;
406 if (ATTR_APPEND(avail
, bp
, len
) != 0)
410 if (kalist
.volattr
& DARWIN_ATTR_VOL_MINALLOCATION
) {
413 omin
= f
->f_bsize
; /* XXX probably wrong */
414 if (ATTR_APPEND(omin
, bp
, len
) != 0)
418 if (kalist
.volattr
& DARWIN_ATTR_VOL_ALLOCATIONCLUMP
) {
421 clump
= f
->f_bsize
; /* XXX proably wrong */
422 if (ATTR_APPEND(clump
, bp
, len
) != 0)
426 if (kalist
.volattr
& DARWIN_ATTR_VOL_IOBLOCKSIZE
) {
430 if (ATTR_APPEND(size
, bp
, len
) != 0)
434 if (kalist
.volattr
& DARWIN_ATTR_VOL_OBJCOUNT
) {
438 if (ATTR_APPEND(cnt
, bp
, len
) != 0)
442 if (kalist
.volattr
& DARWIN_ATTR_VOL_FILECOUNT
) {
445 cnt
= f
->f_files
; /* XXX only files */
446 if (ATTR_APPEND(cnt
, bp
, len
) != 0)
450 if (kalist
.volattr
& DARWIN_ATTR_VOL_DIRCOUNT
) {
453 cnt
= 0; /* XXX wrong, of course */
454 if (ATTR_APPEND(cnt
, bp
, len
) != 0)
458 if (kalist
.volattr
& DARWIN_ATTR_VOL_MAXOBJCOUNT
) {
461 cnt
= f
->f_files
+ f
->f_ffree
;
462 if (ATTR_APPEND(cnt
, bp
, len
) != 0)
466 if (kalist
.volattr
& DARWIN_ATTR_VOL_MOUNTPOINT
) {
467 darwin_attrreference_t dar
;
469 vol_mountpoint_p
= (darwin_attrreference_t
*)bp
;
470 if (ATTR_APPEND(dar
, bp
, len
) != 0)
474 if (kalist
.volattr
& DARWIN_ATTR_VOL_NAME
) {
475 darwin_attrreference_t dar
;
477 vol_name_p
= (darwin_attrreference_t
*)bp
;
478 if (ATTR_APPEND(dar
, bp
, len
) != 0)
482 if (kalist
.volattr
& DARWIN_ATTR_VOL_MOUNTFLAGS
) {
485 flags
= f
->f_flag
; /* XXX need convertion? */
486 if (ATTR_APPEND(flags
, bp
, len
) != 0)
490 if (kalist
.volattr
& DARWIN_ATTR_VOL_MOUNTEDDEVICE
) {
491 darwin_attrreference_t dar
;
493 vol_mounteddevice_p
= (darwin_attrreference_t
*)bp
;
494 if (ATTR_APPEND(dar
, bp
, len
) != 0)
498 if (kalist
.volattr
& DARWIN_ATTR_VOL_ENCODINGSUSED
) {
499 unsigned long long data
;
502 * XXX bitmap of encoding used in this volume
504 (void)memset(&data
, 0, sizeof(data
));
505 if (ATTR_APPEND(data
, bp
, len
) != 0)
509 if (kalist
.volattr
& DARWIN_ATTR_VOL_CAPABILITIES
) { /* XXX */
510 darwin_vol_capabilities_attr_t data
;
512 (void)memset(&data
, 0, sizeof(data
));
513 if (ATTR_APPEND(data
, bp
, len
) != 0)
517 if (kalist
.volattr
& DARWIN_ATTR_VOL_ATTRIBUTES
) { /* XXX */
518 darwin_vol_attributes_attr_t data
;
520 (void)memset(&data
, 0, sizeof(data
));
521 if (ATTR_APPEND(data
, bp
, len
) != 0)
525 if (kalist
.dirattr
& DARWIN_ATTR_DIR_LINKCOUNT
) {
529 if (ATTR_APPEND(cnt
, bp
, len
) != 0)
533 if (kalist
.dirattr
& DARWIN_ATTR_DIR_ENTRYCOUNT
) { /* XXX */
536 (void)memset(&data
, 0, sizeof(data
));
537 if (ATTR_APPEND(data
, bp
, len
) != 0)
541 if (kalist
.dirattr
& DARWIN_ATTR_DIR_MOUNTSTATUS
) { /* XXX */
544 (void)memset(&data
, 0, sizeof(data
));
545 if (ATTR_APPEND(data
, bp
, len
) != 0)
549 if (kalist
.fileattr
& DARWIN_ATTR_FILE_LINKCOUNT
) {
553 if (ATTR_APPEND(cnt
, bp
, len
) != 0)
557 if (kalist
.fileattr
& DARWIN_ATTR_FILE_TOTALSIZE
) {
561 if (ATTR_APPEND(size
, bp
, len
) != 0)
565 if (kalist
.fileattr
& DARWIN_ATTR_FILE_ALLOCSIZE
) {
568 size
= st
.st_blocks
* f
->f_bsize
;
569 if (ATTR_APPEND(size
, bp
, len
) != 0)
573 if (kalist
.fileattr
& DARWIN_ATTR_FILE_IOBLOCKSIZE
) {
576 size
= st
.st_blksize
;
577 if (ATTR_APPEND(size
, bp
, len
) != 0)
581 if (kalist
.fileattr
& DARWIN_ATTR_FILE_CLUMPSIZE
) {
584 size
= st
.st_blksize
; /* XXX probably wrong */
585 if (ATTR_APPEND(size
, bp
, len
) != 0)
589 if (kalist
.fileattr
& DARWIN_ATTR_FILE_DEVTYPE
) {
593 if (ATTR_APPEND(type
, bp
, len
) != 0)
597 if (kalist
.fileattr
& DARWIN_ATTR_FILE_FILETYPE
) {
600 /* Reserved, returns 0 */
601 (void)memset(&data
, 0, sizeof(data
));
602 if (ATTR_APPEND(data
, bp
, len
) != 0)
606 if (kalist
.fileattr
& DARWIN_ATTR_FILE_FORKCOUNT
) { /* XXX */
609 cnt
= 1; /* Only one fork, of course */
610 if (ATTR_APPEND(cnt
, bp
, len
) != 0)
614 if (kalist
.fileattr
& DARWIN_ATTR_FILE_FORKLIST
) {
615 /* Unsupported in Darwin */
620 if (kalist
.fileattr
& DARWIN_ATTR_FILE_DATALENGTH
) { /* All forks */
624 if (ATTR_APPEND(size
, bp
, len
) != 0)
628 if (kalist
.fileattr
& DARWIN_ATTR_FILE_DATAALLOCSIZE
) { /* All forks */
631 size
= st
.st_blocks
* f
->f_bsize
;
632 if (ATTR_APPEND(size
, bp
, len
) != 0)
636 if (kalist
.fileattr
& DARWIN_ATTR_FILE_DATAEXTENTS
) {
637 darwin_extentrecord data
;
639 /* Obsolete in Darwin */
640 (void)memset(&data
, 0, sizeof(data
));
641 if (ATTR_APPEND(data
, bp
, len
) != 0)
645 if (kalist
.fileattr
& DARWIN_ATTR_FILE_RSRCLENGTH
) {
649 if (ATTR_APPEND(size
, bp
, len
) != 0)
653 if (kalist
.fileattr
& DARWIN_ATTR_FILE_RSRCALLOCSIZE
) {
657 if (ATTR_APPEND(size
, bp
, len
) != 0)
661 if (kalist
.fileattr
& DARWIN_ATTR_FILE_RSRCEXTENTS
) {
662 darwin_extentrecord data
;
664 /* Obsolete in Darwin */
665 (void)memset(&data
, 0, sizeof(data
));
666 if (ATTR_APPEND(data
, bp
, len
) != 0)
670 if (kalist
.forkattr
& DARWIN_ATTR_FORK_TOTALSIZE
) {
674 if (ATTR_APPEND(size
, bp
, len
) != 0)
678 if (kalist
.forkattr
& DARWIN_ATTR_FORK_ALLOCSIZE
) {
681 size
= st
.st_blocks
* f
->f_bsize
;
682 if (ATTR_APPEND(size
, bp
, len
) != 0)
687 * Now the variable length fields
690 if (cmn_name_p
) { /* DARWIN_ATTR_CMN_NAME */
691 cmn_name_p
->attr_dataoffset
= (u_long
)bp
- (u_long
)cmn_name_p
;
692 cmn_name_p
->attr_length
= nd
.ni_cnd
.cn_namelen
;
693 if (darwin_attr_append(nd
.ni_cnd
.cn_nameptr
,
694 cmn_name_p
->attr_length
, &bp
, &len
) != 0)
697 /* word alignement */
698 shift
= (((u_long
)bp
& ~0x3UL
) + 4) - (u_long
)bp
;
699 if (darwin_attr_append((char *)null
, shift
, &bp
, &len
) != 0)
703 if (vol_mountpoint_p
) { /* DARWIN_ATTR_VOL_MOUNTPOINT */
704 vol_mountpoint_p
->attr_dataoffset
=
705 (u_long
)bp
- (u_long
)vol_mountpoint_p
;
706 vol_mountpoint_p
->attr_length
= strlen(f
->f_mntonname
);
707 if (darwin_attr_append(f
->f_mntonname
,
708 vol_mountpoint_p
->attr_length
, &bp
, &len
) != 0)
711 /* word alignement */
712 shift
= (((u_long
)bp
& ~0x3UL
) + 4) - (u_long
)bp
;
713 if (darwin_attr_append((char *)null
, shift
, &bp
, &len
) != 0)
717 if (vol_mounteddevice_p
) { /* DARWIN_ATTR_VOL_MOUNTEDDEVICE */
718 vol_mounteddevice_p
->attr_dataoffset
=
719 (u_long
)bp
- (u_long
)vol_mounteddevice_p
;
720 vol_mounteddevice_p
->attr_length
= strlen(f
->f_mntfromname
);
721 if (darwin_attr_append(f
->f_mntfromname
,
722 vol_mounteddevice_p
->attr_length
, &bp
, &len
) != 0)
725 /* word alignement */
726 shift
= (((u_long
)bp
& ~0x3UL
) + 4) - (u_long
)bp
;
727 if (darwin_attr_append((char *)null
, shift
, &bp
, &len
) != 0)
731 if (vol_name_p
) { /* DARWIN_ATTR_VOL_NAME */
732 char name
[] = "Volume"; /* XXX We have no volume names... */
733 size_t namelen
= strlen(name
);
735 vol_name_p
->attr_dataoffset
= (u_long
)bp
- (u_long
)vol_name_p
;
736 vol_name_p
->attr_length
= namelen
;
737 if (darwin_attr_append(name
, namelen
, &bp
, &len
) != 0)
740 /* word alignement */
741 shift
= (((u_long
)bp
& ~0x3UL
) + 4) - (u_long
)bp
;
742 if (darwin_attr_append((char *)null
, shift
, &bp
, &len
) != 0)
746 /* And, finnally, the whole buffer length */
748 *whole_len_p
= SCARG(uap
, buflen
) - len
;
752 * We are done! Copyout the stuff and get away
755 error
= copyout(tbuf
, SCARG(uap
, attributes
), *whole_len_p
);
759 kauth_cred_free(cred
);