1 1.68 christos /* $NetBSD: linux_file64.c,v 1.68 2023/07/29 15:04:29 christos Exp $ */ 2 1.1 jdolecek 3 1.1 jdolecek /*- 4 1.46 ad * Copyright (c) 1995, 1998, 2000, 2008 The NetBSD Foundation, Inc. 5 1.1 jdolecek * All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jdolecek * by Frank van der Linden and Eric Haszlakiewicz. 9 1.1 jdolecek * 10 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 11 1.1 jdolecek * modification, are permitted provided that the following conditions 12 1.1 jdolecek * are met: 13 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 14 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 15 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 17 1.1 jdolecek * documentation and/or other materials provided with the distribution. 18 1.1 jdolecek * 19 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jdolecek * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jdolecek */ 31 1.1 jdolecek 32 1.1 jdolecek /* 33 1.1 jdolecek * Linux 64bit filesystem calls. Used on 32bit archs, not used on 64bit ones. 34 1.1 jdolecek */ 35 1.6 lukem 36 1.6 lukem #include <sys/cdefs.h> 37 1.68 christos __KERNEL_RCSID(0, "$NetBSD: linux_file64.c,v 1.68 2023/07/29 15:04:29 christos Exp $"); 38 1.1 jdolecek 39 1.1 jdolecek #include <sys/param.h> 40 1.1 jdolecek #include <sys/systm.h> 41 1.1 jdolecek #include <sys/namei.h> 42 1.1 jdolecek #include <sys/proc.h> 43 1.11 tron #include <sys/dirent.h> 44 1.1 jdolecek #include <sys/file.h> 45 1.1 jdolecek #include <sys/stat.h> 46 1.1 jdolecek #include <sys/filedesc.h> 47 1.1 jdolecek #include <sys/ioctl.h> 48 1.1 jdolecek #include <sys/kernel.h> 49 1.1 jdolecek #include <sys/mount.h> 50 1.1 jdolecek #include <sys/malloc.h> 51 1.37 dsl #include <sys/namei.h> 52 1.37 dsl #include <sys/vfs_syscalls.h> 53 1.1 jdolecek #include <sys/vnode.h> 54 1.1 jdolecek #include <sys/tty.h> 55 1.1 jdolecek #include <sys/conf.h> 56 1.1 jdolecek 57 1.1 jdolecek #include <sys/syscallargs.h> 58 1.1 jdolecek 59 1.1 jdolecek #include <compat/linux/common/linux_types.h> 60 1.1 jdolecek #include <compat/linux/common/linux_signal.h> 61 1.1 jdolecek #include <compat/linux/common/linux_fcntl.h> 62 1.1 jdolecek #include <compat/linux/common/linux_util.h> 63 1.1 jdolecek #include <compat/linux/common/linux_machdep.h> 64 1.11 tron #include <compat/linux/common/linux_dirent.h> 65 1.40 njoly #include <compat/linux/common/linux_ipc.h> 66 1.40 njoly #include <compat/linux/common/linux_sem.h> 67 1.1 jdolecek 68 1.67 ryo #include <compat/linux/linux_syscall.h> 69 1.1 jdolecek #include <compat/linux/linux_syscallargs.h> 70 1.1 jdolecek 71 1.65 ryo static void bsd_to_linux_stat64(struct stat *, struct linux_stat64 *); 72 1.1 jdolecek 73 1.1 jdolecek /* 74 1.1 jdolecek * Convert a NetBSD stat structure to a Linux stat structure. 75 1.1 jdolecek * Only the order of the fields and the padding in the structure 76 1.1 jdolecek * is different. linux_fakedev is a machine-dependent function 77 1.1 jdolecek * which optionally converts device driver major/minor numbers 78 1.1 jdolecek * (XXX horrible, but what can you do against code that compares 79 1.1 jdolecek * things against constant major device numbers? sigh) 80 1.1 jdolecek */ 81 1.1 jdolecek static void 82 1.65 ryo bsd_to_linux_stat64(struct stat *bsp, struct linux_stat64 *lsp) 83 1.1 jdolecek { 84 1.61 maxv memset(lsp, 0, sizeof(*lsp)); 85 1.7 christos lsp->lst_dev = linux_fakedev(bsp->st_dev, 0); 86 1.1 jdolecek lsp->lst_ino = bsp->st_ino; 87 1.1 jdolecek lsp->lst_mode = (linux_mode_t)bsp->st_mode; 88 1.1 jdolecek if (bsp->st_nlink >= (1 << 15)) 89 1.1 jdolecek lsp->lst_nlink = (1 << 15) - 1; 90 1.1 jdolecek else 91 1.1 jdolecek lsp->lst_nlink = (linux_nlink_t)bsp->st_nlink; 92 1.1 jdolecek lsp->lst_uid = bsp->st_uid; 93 1.1 jdolecek lsp->lst_gid = bsp->st_gid; 94 1.7 christos lsp->lst_rdev = linux_fakedev(bsp->st_rdev, 1); 95 1.1 jdolecek lsp->lst_size = bsp->st_size; 96 1.1 jdolecek lsp->lst_blksize = bsp->st_blksize; 97 1.1 jdolecek lsp->lst_blocks = bsp->st_blocks; 98 1.1 jdolecek lsp->lst_atime = bsp->st_atime; 99 1.1 jdolecek lsp->lst_mtime = bsp->st_mtime; 100 1.1 jdolecek lsp->lst_ctime = bsp->st_ctime; 101 1.31 manu # ifdef LINUX_STAT64_HAS_NSEC 102 1.25 christos lsp->lst_atime_nsec = bsp->st_atimensec; 103 1.25 christos lsp->lst_mtime_nsec = bsp->st_mtimensec; 104 1.25 christos lsp->lst_ctime_nsec = bsp->st_ctimensec; 105 1.31 manu # endif 106 1.31 manu # if LINUX_STAT64_HAS_BROKEN_ST_INO 107 1.16 jdolecek lsp->__lst_ino = (linux_ino_t) bsp->st_ino; 108 1.31 manu # endif 109 1.1 jdolecek } 110 1.1 jdolecek 111 1.67 ryo int 112 1.67 ryo bsd_to_linux_statx(struct stat *st, struct linux_statx *stx, 113 1.67 ryo unsigned int mask) 114 1.67 ryo { 115 1.67 ryo if (mask & STATX__RESERVED) 116 1.67 ryo return EINVAL; 117 1.67 ryo 118 1.67 ryo /* XXX: STATX_MNT_ID is not supported */ 119 1.67 ryo unsigned int rmask = STATX_TYPE | STATX_MODE | STATX_NLINK | 120 1.67 ryo STATX_UID | STATX_GID | STATX_ATIME | STATX_MTIME | STATX_CTIME | 121 1.67 ryo STATX_INO | STATX_SIZE | STATX_BLOCKS | STATX_BTIME; 122 1.67 ryo 123 1.67 ryo memset(stx, 0, sizeof(*stx)); 124 1.67 ryo 125 1.67 ryo if ((st->st_flags & UF_NODUMP) != 0) 126 1.67 ryo stx->stx_attributes |= STATX_ATTR_NODUMP; 127 1.67 ryo if ((st->st_flags & (UF_IMMUTABLE|SF_IMMUTABLE)) != 0) 128 1.67 ryo stx->stx_attributes |= STATX_ATTR_IMMUTABLE; 129 1.67 ryo if ((st->st_flags & (UF_APPEND|SF_APPEND)) != 0) 130 1.67 ryo stx->stx_attributes |= STATX_ATTR_APPEND; 131 1.67 ryo 132 1.67 ryo stx->stx_attributes_mask = 133 1.67 ryo STATX_ATTR_NODUMP | STATX_ATTR_IMMUTABLE | STATX_ATTR_APPEND; 134 1.67 ryo 135 1.67 ryo stx->stx_blksize = st->st_blksize; 136 1.67 ryo 137 1.67 ryo stx->stx_nlink = st->st_nlink; 138 1.67 ryo stx->stx_uid = st->st_uid; 139 1.67 ryo stx->stx_gid = st->st_gid; 140 1.67 ryo stx->stx_mode |= st->st_mode & S_IFMT; 141 1.67 ryo stx->stx_mode |= st->st_mode & ~S_IFMT; 142 1.67 ryo stx->stx_ino = st->st_ino; 143 1.67 ryo stx->stx_size = st->st_size; 144 1.67 ryo stx->stx_blocks = st->st_blocks; 145 1.67 ryo 146 1.67 ryo stx->stx_atime.tv_sec = st->st_atime; 147 1.67 ryo stx->stx_atime.tv_nsec = st->st_atimensec; 148 1.67 ryo 149 1.67 ryo /* some filesystem has no birthtime returns 0 or -1 */ 150 1.67 ryo if ((st->st_birthtime == 0 && st->st_birthtimensec == 0) || 151 1.67 ryo (st->st_birthtime == (time_t)-1 && 152 1.67 ryo st->st_birthtimensec == (long)-1)) { 153 1.67 ryo rmask &= ~STATX_BTIME; 154 1.67 ryo } else { 155 1.67 ryo stx->stx_btime.tv_sec = st->st_birthtime; 156 1.67 ryo stx->stx_btime.tv_nsec = st->st_birthtimensec; 157 1.67 ryo } 158 1.67 ryo 159 1.67 ryo stx->stx_ctime.tv_sec = st->st_ctime; 160 1.67 ryo stx->stx_ctime.tv_nsec = st->st_ctimensec; 161 1.67 ryo 162 1.67 ryo stx->stx_mtime.tv_sec = st->st_mtime; 163 1.67 ryo stx->stx_mtime.tv_nsec = st->st_mtimensec; 164 1.67 ryo 165 1.67 ryo if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { 166 1.67 ryo stx->stx_rdev_major = major(st->st_rdev); 167 1.67 ryo stx->stx_rdev_minor = minor(st->st_rdev); 168 1.67 ryo } else { 169 1.67 ryo stx->stx_dev_major = major(st->st_rdev); 170 1.67 ryo stx->stx_dev_minor = minor(st->st_rdev); 171 1.67 ryo } 172 1.67 ryo 173 1.67 ryo stx->stx_mask = rmask; 174 1.67 ryo 175 1.67 ryo return 0; 176 1.67 ryo } 177 1.67 ryo 178 1.1 jdolecek /* 179 1.1 jdolecek * The stat functions below are plain sailing. stat and lstat are handled 180 1.1 jdolecek * by one function to avoid code duplication. 181 1.1 jdolecek */ 182 1.1 jdolecek int 183 1.44 dsl linux_sys_fstat64(struct lwp *l, const struct linux_sys_fstat64_args *uap, register_t *retval) 184 1.1 jdolecek { 185 1.44 dsl /* { 186 1.1 jdolecek syscallarg(int) fd; 187 1.5 manu syscallarg(struct linux_stat64 *) sp; 188 1.44 dsl } */ 189 1.1 jdolecek struct linux_stat64 tmplst; 190 1.37 dsl struct stat tmpst; 191 1.1 jdolecek int error; 192 1.1 jdolecek 193 1.46 ad error = do_sys_fstat(SCARG(uap, fd), &tmpst); 194 1.37 dsl if (error != 0) 195 1.1 jdolecek return error; 196 1.1 jdolecek 197 1.65 ryo bsd_to_linux_stat64(&tmpst, &tmplst); 198 1.1 jdolecek 199 1.37 dsl return copyout(&tmplst, SCARG(uap, sp), sizeof tmplst); 200 1.1 jdolecek } 201 1.1 jdolecek 202 1.64 ryo #if !defined(__aarch64__) 203 1.1 jdolecek static int 204 1.44 dsl linux_do_stat64(struct lwp *l, const struct linux_sys_stat64_args *uap, register_t *retval, int flags) 205 1.1 jdolecek { 206 1.1 jdolecek struct linux_stat64 tmplst; 207 1.37 dsl struct stat tmpst; 208 1.1 jdolecek int error; 209 1.1 jdolecek 210 1.46 ad error = do_sys_stat(SCARG(uap, path), flags, &tmpst); 211 1.37 dsl if (error != 0) 212 1.1 jdolecek return error; 213 1.1 jdolecek 214 1.65 ryo bsd_to_linux_stat64(&tmpst, &tmplst); 215 1.1 jdolecek 216 1.37 dsl return copyout(&tmplst, SCARG(uap, sp), sizeof tmplst); 217 1.1 jdolecek } 218 1.1 jdolecek 219 1.1 jdolecek int 220 1.44 dsl linux_sys_stat64(struct lwp *l, const struct linux_sys_stat64_args *uap, register_t *retval) 221 1.1 jdolecek { 222 1.44 dsl /* { 223 1.1 jdolecek syscallarg(const char *) path; 224 1.1 jdolecek syscallarg(struct linux_stat64 *) sp; 225 1.44 dsl } */ 226 1.1 jdolecek 227 1.37 dsl return linux_do_stat64(l, uap, retval, FOLLOW); 228 1.1 jdolecek } 229 1.1 jdolecek 230 1.1 jdolecek int 231 1.44 dsl linux_sys_lstat64(struct lwp *l, const struct linux_sys_lstat64_args *uap, register_t *retval) 232 1.1 jdolecek { 233 1.44 dsl /* { 234 1.1 jdolecek syscallarg(const char *) path; 235 1.1 jdolecek syscallarg(struct linux_stat64 *) sp; 236 1.44 dsl } */ 237 1.1 jdolecek 238 1.44 dsl return linux_do_stat64(l, (const void *)uap, retval, NOFOLLOW); 239 1.2 jdolecek } 240 1.64 ryo #endif 241 1.2 jdolecek 242 1.67 ryo /* 243 1.67 ryo * This is an internal function for the *statat() variant of linux, 244 1.67 ryo * which returns struct stat, but flags and other handling are 245 1.67 ryo * the same as in linux. 246 1.67 ryo */ 247 1.2 jdolecek int 248 1.67 ryo linux_statat(struct lwp *l, int fd, const char *path, int lflag, 249 1.67 ryo struct stat *st) 250 1.54 chs { 251 1.63 rin struct vnode *vp; 252 1.67 ryo int error, nd_flag; 253 1.63 rin uint8_t c; 254 1.63 rin 255 1.68 christos if (lflag & ~(LINUX_AT_EMPTY_PATH|LINUX_AT_NO_AUTOMOUNT 256 1.68 christos |LINUX_AT_SYMLINK_NOFOLLOW)) 257 1.68 christos return EINVAL; 258 1.68 christos 259 1.67 ryo if (lflag & LINUX_AT_EMPTY_PATH) { 260 1.63 rin /* 261 1.63 rin * If path is null string: 262 1.63 rin */ 263 1.67 ryo error = ufetch_8(path, &c); 264 1.63 rin if (error != 0) 265 1.63 rin return error; 266 1.63 rin if (c == '\0') { 267 1.67 ryo if (fd == LINUX_AT_FDCWD) { 268 1.63 rin /* 269 1.63 rin * operate on current directory 270 1.63 rin */ 271 1.63 rin vp = l->l_proc->p_cwdi->cwdi_cdir; 272 1.63 rin vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 273 1.67 ryo error = vn_stat(vp, st); 274 1.63 rin VOP_UNLOCK(vp); 275 1.63 rin } else { 276 1.63 rin /* 277 1.63 rin * operate on fd 278 1.63 rin */ 279 1.67 ryo error = do_sys_fstat(fd, st); 280 1.63 rin } 281 1.67 ryo return error; 282 1.63 rin } 283 1.63 rin } 284 1.54 chs 285 1.67 ryo if (lflag & LINUX_AT_SYMLINK_NOFOLLOW) 286 1.54 chs nd_flag = NOFOLLOW; 287 1.54 chs else 288 1.54 chs nd_flag = FOLLOW; 289 1.54 chs 290 1.67 ryo return do_sys_statat(l, fd, path, nd_flag, st); 291 1.67 ryo } 292 1.67 ryo 293 1.67 ryo int 294 1.67 ryo linux_sys_fstatat64(struct lwp *l, const struct linux_sys_fstatat64_args *uap, register_t *retval) 295 1.67 ryo { 296 1.67 ryo /* { 297 1.67 ryo syscallarg(int) fd; 298 1.67 ryo syscallarg(const char *) path; 299 1.67 ryo syscallarg(struct linux_stat64 *) sp; 300 1.67 ryo syscallarg(int) flag; 301 1.67 ryo } */ 302 1.67 ryo struct linux_stat64 tmplst; 303 1.67 ryo struct stat tmpst; 304 1.67 ryo int error; 305 1.67 ryo 306 1.67 ryo error = linux_statat(l, SCARG(uap, fd), SCARG(uap, path), 307 1.67 ryo SCARG(uap, flag), &tmpst); 308 1.54 chs if (error != 0) 309 1.54 chs return error; 310 1.54 chs 311 1.65 ryo bsd_to_linux_stat64(&tmpst, &tmplst); 312 1.54 chs 313 1.54 chs return copyout(&tmplst, SCARG(uap, sp), sizeof tmplst); 314 1.54 chs } 315 1.54 chs 316 1.67 ryo #ifdef LINUX_SYS_statx 317 1.67 ryo int 318 1.67 ryo linux_sys_statx(struct lwp *l, const struct linux_sys_statx_args *uap, 319 1.67 ryo register_t *retval) 320 1.67 ryo { 321 1.67 ryo /* { 322 1.67 ryo syscallarg(int) fd; 323 1.67 ryo syscallarg(const char *) path; 324 1.67 ryo syscallarg(int) flag; 325 1.67 ryo syscallarg(unsigned int) mask; 326 1.67 ryo syscallarg(struct linux_statx *) sp; 327 1.67 ryo } */ 328 1.67 ryo struct linux_statx stx; 329 1.67 ryo struct stat st; 330 1.67 ryo int error; 331 1.67 ryo 332 1.67 ryo error = linux_statat(l, SCARG(uap, fd), SCARG(uap, path), 333 1.67 ryo SCARG(uap, flag), &st); 334 1.67 ryo if (error != 0) 335 1.67 ryo return error; 336 1.67 ryo 337 1.67 ryo error = bsd_to_linux_statx(&st, &stx, SCARG(uap, mask)); 338 1.67 ryo if (error != 0) 339 1.67 ryo return error; 340 1.67 ryo 341 1.67 ryo return copyout(&stx, SCARG(uap, sp), sizeof stx); 342 1.67 ryo } 343 1.67 ryo #endif /* LINUX_SYS_statx */ 344 1.67 ryo 345 1.55 njoly #ifndef __alpha__ 346 1.54 chs int 347 1.44 dsl linux_sys_truncate64(struct lwp *l, const struct linux_sys_truncate64_args *uap, register_t *retval) 348 1.2 jdolecek { 349 1.44 dsl /* { 350 1.2 jdolecek syscallarg(const char *) path; 351 1.2 jdolecek syscallarg(off_t) length; 352 1.44 dsl } */ 353 1.22 jdolecek struct sys_truncate_args ta; 354 1.2 jdolecek 355 1.22 jdolecek /* Linux doesn't have the 'pad' pseudo-parameter */ 356 1.22 jdolecek SCARG(&ta, path) = SCARG(uap, path); 357 1.49 pooka SCARG(&ta, PAD) = 0; 358 1.22 jdolecek SCARG(&ta, length) = SCARG(uap, length); 359 1.22 jdolecek 360 1.22 jdolecek return sys_truncate(l, &ta, retval); 361 1.22 jdolecek } 362 1.22 jdolecek 363 1.22 jdolecek int 364 1.44 dsl linux_sys_ftruncate64(struct lwp *l, const struct linux_sys_ftruncate64_args *uap, register_t *retval) 365 1.22 jdolecek { 366 1.44 dsl /* { 367 1.22 jdolecek syscallarg(unsigned int) fd; 368 1.22 jdolecek syscallarg(off_t) length; 369 1.44 dsl } */ 370 1.22 jdolecek struct sys_ftruncate_args ta; 371 1.22 jdolecek 372 1.22 jdolecek /* Linux doesn't have the 'pad' pseudo-parameter */ 373 1.22 jdolecek SCARG(&ta, fd) = SCARG(uap, fd); 374 1.49 pooka SCARG(&ta, PAD) = 0; 375 1.22 jdolecek SCARG(&ta, length) = SCARG(uap, length); 376 1.22 jdolecek 377 1.22 jdolecek return sys_ftruncate(l, &ta, retval); 378 1.1 jdolecek } 379 1.55 njoly #endif /* __alpha__ */ 380 1.11 tron 381 1.11 tron /* 382 1.11 tron * Linux 'readdir' call. This code is mostly taken from the 383 1.11 tron * SunOS getdents call (see compat/sunos/sunos_misc.c), though 384 1.18 jdolecek * an attempt has been made to keep it a little cleaner. 385 1.11 tron * 386 1.18 jdolecek * The d_off field contains the offset of the next valid entry, 387 1.18 jdolecek * unless the older Linux getdents(2), which used to have it set 388 1.18 jdolecek * to the offset of the entry itself. This function also doesn't 389 1.18 jdolecek * need to deal with the old count == 1 glibc problem. 390 1.11 tron * 391 1.11 tron * Read in BSD-style entries, convert them, and copy them out. 392 1.11 tron * 393 1.11 tron * Note that this doesn't handle union-mounted filesystems. 394 1.11 tron */ 395 1.11 tron int 396 1.44 dsl linux_sys_getdents64(struct lwp *l, const struct linux_sys_getdents64_args *uap, register_t *retval) 397 1.11 tron { 398 1.44 dsl /* { 399 1.11 tron syscallarg(int) fd; 400 1.11 tron syscallarg(struct linux_dirent64 *) dent; 401 1.11 tron syscallarg(unsigned int) count; 402 1.44 dsl } */ 403 1.11 tron struct dirent *bdp; 404 1.11 tron struct vnode *vp; 405 1.36 christos char *inp, *tbuf; /* BSD-format */ 406 1.11 tron int len, reclen; /* BSD-format */ 407 1.36 christos char *outp; /* Linux-format */ 408 1.11 tron int resid, linux_reclen = 0; /* Linux-format */ 409 1.46 ad file_t *fp; 410 1.11 tron struct uio auio; 411 1.11 tron struct iovec aiov; 412 1.11 tron struct linux_dirent64 idb; 413 1.11 tron off_t off; /* true file offset */ 414 1.18 jdolecek int buflen, error, eofflag, nbytes; 415 1.11 tron struct vattr va; 416 1.11 tron off_t *cookiebuf = NULL, *cookie; 417 1.11 tron int ncookies; 418 1.11 tron 419 1.48 ad /* fd_getvnode() will use the descriptor for us */ 420 1.48 ad if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 421 1.11 tron return (error); 422 1.11 tron 423 1.11 tron if ((fp->f_flag & FREAD) == 0) { 424 1.11 tron error = EBADF; 425 1.11 tron goto out1; 426 1.11 tron } 427 1.11 tron 428 1.11 tron vp = (struct vnode *)fp->f_data; 429 1.11 tron if (vp->v_type != VDIR) { 430 1.52 njoly error = ENOTDIR; 431 1.11 tron goto out1; 432 1.11 tron } 433 1.11 tron 434 1.53 hannken vn_lock(vp, LK_SHARED | LK_RETRY); 435 1.53 hannken error = VOP_GETATTR(vp, &va, l->l_cred); 436 1.53 hannken VOP_UNLOCK(vp); 437 1.53 hannken if (error) 438 1.11 tron goto out1; 439 1.11 tron 440 1.11 tron nbytes = SCARG(uap, count); 441 1.60 riastrad buflen = uimin(MAXBSIZE, nbytes); 442 1.18 jdolecek if (buflen < va.va_blocksize) 443 1.18 jdolecek buflen = va.va_blocksize; 444 1.28 christos tbuf = malloc(buflen, M_TEMP, M_WAITOK); 445 1.11 tron 446 1.11 tron vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 447 1.11 tron off = fp->f_offset; 448 1.11 tron again: 449 1.28 christos aiov.iov_base = tbuf; 450 1.11 tron aiov.iov_len = buflen; 451 1.11 tron auio.uio_iov = &aiov; 452 1.11 tron auio.uio_iovcnt = 1; 453 1.11 tron auio.uio_rw = UIO_READ; 454 1.11 tron auio.uio_resid = buflen; 455 1.11 tron auio.uio_offset = off; 456 1.32 yamt UIO_SETUP_SYSSPACE(&auio); 457 1.11 tron /* 458 1.11 tron * First we read into the malloc'ed buffer, then 459 1.11 tron * we massage it into user space, one record at a time. 460 1.11 tron */ 461 1.11 tron error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf, 462 1.11 tron &ncookies); 463 1.11 tron if (error) 464 1.11 tron goto out; 465 1.11 tron 466 1.28 christos inp = tbuf; 467 1.36 christos outp = (void *)SCARG(uap, dent); 468 1.11 tron resid = nbytes; 469 1.11 tron if ((len = buflen - auio.uio_resid) == 0) 470 1.11 tron goto eof; 471 1.11 tron 472 1.11 tron for (cookie = cookiebuf; len > 0; len -= reclen) { 473 1.11 tron bdp = (struct dirent *)inp; 474 1.11 tron reclen = bdp->d_reclen; 475 1.59 riastrad if (reclen & 3) { 476 1.59 riastrad error = EIO; 477 1.59 riastrad goto out; 478 1.59 riastrad } 479 1.11 tron if (bdp->d_fileno == 0) { 480 1.11 tron inp += reclen; /* it is a hole; squish it out */ 481 1.26 christos if (cookie) 482 1.26 christos off = *cookie++; 483 1.26 christos else 484 1.26 christos off += reclen; 485 1.11 tron continue; 486 1.11 tron } 487 1.11 tron linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen); 488 1.11 tron if (reclen > len || resid < linux_reclen) { 489 1.11 tron /* entry too big for buffer, so just stop */ 490 1.11 tron outp++; 491 1.11 tron break; 492 1.11 tron } 493 1.26 christos if (cookie) 494 1.26 christos off = *cookie++; /* each entry points to next */ 495 1.26 christos else 496 1.26 christos off += reclen; 497 1.11 tron /* 498 1.11 tron * Massage in place to make a Linux-shaped dirent (otherwise 499 1.11 tron * we have to worry about touching user memory outside of 500 1.11 tron * the copyout() call). 501 1.11 tron */ 502 1.62 maxv memset(&idb, 0, sizeof(idb)); 503 1.11 tron idb.d_ino = bdp->d_fileno; 504 1.11 tron idb.d_type = bdp->d_type; 505 1.18 jdolecek idb.d_off = off; 506 1.18 jdolecek idb.d_reclen = (u_short)linux_reclen; 507 1.56 christos memcpy(idb.d_name, bdp->d_name, MIN(sizeof(idb.d_name), 508 1.58 christos bdp->d_namlen + 1)); 509 1.36 christos if ((error = copyout((void *)&idb, outp, linux_reclen))) 510 1.11 tron goto out; 511 1.11 tron /* advance past this real entry */ 512 1.11 tron inp += reclen; 513 1.11 tron /* advance output past Linux-shaped entry */ 514 1.11 tron outp += linux_reclen; 515 1.11 tron resid -= linux_reclen; 516 1.11 tron } 517 1.11 tron 518 1.11 tron /* if we squished out the whole block, try again */ 519 1.50 he if (outp == (void *)SCARG(uap, dent)) { 520 1.50 he if (cookiebuf) 521 1.50 he free(cookiebuf, M_TEMP); 522 1.50 he cookiebuf = NULL; 523 1.11 tron goto again; 524 1.50 he } 525 1.11 tron fp->f_offset = off; /* update the vnode offset */ 526 1.11 tron 527 1.11 tron eof: 528 1.11 tron *retval = nbytes - resid; 529 1.11 tron out: 530 1.51 hannken VOP_UNLOCK(vp); 531 1.11 tron if (cookiebuf) 532 1.11 tron free(cookiebuf, M_TEMP); 533 1.28 christos free(tbuf, M_TEMP); 534 1.11 tron out1: 535 1.46 ad fd_putfile(SCARG(uap, fd)); 536 1.3 manu return error; 537 1.3 manu } 538