4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
34 #include <sys/param.h>
35 #include <sys/isa_defs.h>
36 #include <sys/types.h>
37 #include <sys/inttypes.h>
38 #include <sys/sysmacros.h>
40 #include <sys/dirent.h>
41 #include <sys/systm.h>
42 #include <sys/errno.h>
43 #include <sys/vnode.h>
47 #include <sys/filio.h>
48 #include <sys/debug.h>
50 #include <sys/cmn_err.h>
52 #if defined(_SYSCALL32_IMPL) || defined(_ILP32)
55 * Get directory entries in a file system-independent format.
57 * The 32-bit version of this function now allocates a buffer to grab the
58 * directory entries in dirent64 formats from fop_readdir routines.
59 * The dirent64 structures are converted to dirent32 structures and
60 * copied to the user space.
62 * Both 32-bit and 64-bit versions of libc use getdents64() and therefore
63 * we don't expect any major performance impact due to the extra kmem_alloc's
64 * and copying done in this routine.
68 * Native 32-bit system call for non-large-file applications.
71 getdents32(int fd
, void *buf
, size_t count
)
86 if (count
< sizeof (struct dirent32
))
87 return (set_errno(EINVAL
));
89 if ((fp
= getf(fd
)) == NULL
)
90 return (set_errno(EBADF
));
92 if (vp
->v_type
!= VDIR
) {
94 return (set_errno(ENOTDIR
));
96 if (!(fp
->f_flag
& FREAD
)) {
98 return (set_errno(EBADF
));
102 * Don't let the user overcommit kernel resources.
104 if (count
> MAXGETDENTS_SIZE
)
105 count
= MAXGETDENTS_SIZE
;
108 newbuf
= kmem_alloc(bufsize
, KM_SLEEP
);
109 obuf
= kmem_alloc(bufsize
, KM_SLEEP
);
111 aiov
.iov_base
= newbuf
;
112 aiov
.iov_len
= count
;
113 auio
.uio_iov
= &aiov
;
115 auio
.uio_loffset
= fp
->f_offset
;
116 auio
.uio_segflg
= UIO_SYSSPACE
;
117 auio
.uio_resid
= count
;
119 auio
.uio_extflg
= UIO_COPY_CACHED
;
120 (void) fop_rwlock(vp
, V_WRITELOCK_FALSE
, NULL
);
121 error
= fop_readdir(vp
, &auio
, fp
->f_cred
, &sink
, NULL
, 0);
122 fop_rwunlock(vp
, V_WRITELOCK_FALSE
, NULL
);
125 count
= count
- auio
.uio_resid
;
126 fp
->f_offset
= auio
.uio_loffset
;
128 dp
= (struct dirent64
*)newbuf
;
129 op
= (struct dirent32
*)obuf
;
133 while (nsize
< count
) {
134 uint32_t reclen
, namlen
;
137 * This check ensures that the 64 bit d_ino and d_off
138 * fields will fit into their 32 bit equivalents.
140 * Although d_off is a signed value, the check is done
141 * against the full 32 bits because certain file systems,
142 * NFS for one, allow directory cookies to use the full
143 * 32 bits. We use uint64_t because there is no exact
144 * unsigned analog to the off64_t type of dp->d_off.
146 if (dp
->d_ino
> (ino64_t
)UINT32_MAX
||
147 dp
->d_off
> (uint64_t)UINT32_MAX
) {
151 op
->d_ino
= (ino32_t
)dp
->d_ino
;
152 op
->d_off
= (off32_t
)dp
->d_off
;
153 namlen
= strlen(dp
->d_name
);
154 reclen
= DIRENT32_RECLEN(namlen
);
155 op
->d_reclen
= (uint16_t)reclen
;
157 /* use strncpy(9f) to zero out uninitialized bytes */
159 (void) strncpy(op
->d_name
, dp
->d_name
,
160 DIRENT32_NAMELEN(reclen
));
161 nsize
+= (uint_t
)dp
->d_reclen
;
162 osize
+= (uint_t
)op
->d_reclen
;
163 dp
= (struct dirent64
*)((char *)dp
+ (uint_t
)dp
->d_reclen
);
164 op
= (struct dirent32
*)((char *)op
+ (uint_t
)op
->d_reclen
);
167 ASSERT(osize
<= count
);
168 ASSERT((char *)op
<= (char *)obuf
+ bufsize
);
169 ASSERT((char *)dp
<= (char *)newbuf
+ bufsize
);
171 if ((error
= copyout(obuf
, buf
, osize
)) < 0)
174 kmem_free(newbuf
, bufsize
);
175 kmem_free(obuf
, bufsize
);
179 return (set_errno(error
));
186 #endif /* _SYSCALL32 || _ILP32 */
189 getdents64(int fd
, void *buf
, size_t count
)
198 if (count
< sizeof (struct dirent64
))
199 return (set_errno(EINVAL
));
202 * Don't let the user overcommit kernel resources.
204 if (count
> MAXGETDENTS_SIZE
)
205 count
= MAXGETDENTS_SIZE
;
207 if ((fp
= getf(fd
)) == NULL
)
208 return (set_errno(EBADF
));
210 if (vp
->v_type
!= VDIR
) {
212 return (set_errno(ENOTDIR
));
214 if (!(fp
->f_flag
& FREAD
)) {
216 return (set_errno(EBADF
));
219 aiov
.iov_len
= count
;
220 auio
.uio_iov
= &aiov
;
222 auio
.uio_loffset
= fp
->f_offset
;
223 auio
.uio_segflg
= UIO_USERSPACE
;
224 auio
.uio_resid
= count
;
226 auio
.uio_extflg
= UIO_COPY_CACHED
;
227 (void) fop_rwlock(vp
, V_WRITELOCK_FALSE
, NULL
);
228 error
= fop_readdir(vp
, &auio
, fp
->f_cred
, &sink
, NULL
, 0);
229 fop_rwunlock(vp
, V_WRITELOCK_FALSE
, NULL
);
232 return (set_errno(error
));
234 count
= count
- auio
.uio_resid
;
235 fp
->f_offset
= auio
.uio_loffset
;