linux_file.c revision 64905
19313Ssos/*-
29313Ssos * Copyright (c) 1994-1995 S�ren Schmidt
39313Ssos * All rights reserved.
49313Ssos *
59313Ssos * Redistribution and use in source and binary forms, with or without
69313Ssos * modification, are permitted provided that the following conditions
79313Ssos * are met:
89313Ssos * 1. Redistributions of source code must retain the above copyright
99313Ssos *    notice, this list of conditions and the following disclaimer
109313Ssos *    in this position and unchanged.
119313Ssos * 2. Redistributions in binary form must reproduce the above copyright
129313Ssos *    notice, this list of conditions and the following disclaimer in the
139313Ssos *    documentation and/or other materials provided with the distribution.
149313Ssos * 3. The name of the author may not be used to endorse or promote products
159313Ssos *    derived from this software withough specific prior written permission
169313Ssos *
179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279313Ssos *
2850477Speter * $FreeBSD: head/sys/compat/linux/linux_file.c 64905 2000-08-22 01:27:36Z marcel $
299313Ssos */
309313Ssos
3131784Seivind#include "opt_compat.h"
3231784Seivind
339313Ssos#include <sys/param.h>
349313Ssos#include <sys/systm.h>
3512458Sbde#include <sys/sysproto.h>
369313Ssos#include <sys/fcntl.h>
379313Ssos#include <sys/file.h>
389313Ssos#include <sys/filedesc.h>
3931561Sbde#include <sys/lock.h>
409313Ssos#include <sys/proc.h>
419313Ssos#include <sys/vnode.h>
429313Ssos#include <sys/malloc.h>
439313Ssos#include <sys/dirent.h>
4414331Speter#include <sys/conf.h>
4514331Speter#include <sys/tty.h>
4612458Sbde
4764905Smarcel#include <machine/../linux/linux.h>
4864905Smarcel#include <machine/../linux/linux_proto.h>
4964905Smarcel#include <compat/linux/linux_util.h>
509313Ssos
519313Ssosint
5230994Sphklinux_creat(struct proc *p, struct linux_creat_args *args)
539313Ssos{
5412858Speter    struct open_args /* {
559313Ssos	char *path;
569313Ssos	int flags;
579313Ssos	int mode;
5812858Speter    } */ bsd_open_args;
5914331Speter    caddr_t sg;
609313Ssos
6114331Speter    sg = stackgap_init();
6214331Speter    CHECKALTCREAT(p, &sg, args->path);
6314331Speter
649313Ssos#ifdef DEBUG
659313Ssos    printf("Linux-emul(%d): creat(%s, %d)\n",
669313Ssos	   p->p_pid, args->path, args->mode);
679313Ssos#endif
689313Ssos    bsd_open_args.path = args->path;
699313Ssos    bsd_open_args.mode = args->mode;
709313Ssos    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
7130994Sphk    return open(p, &bsd_open_args);
729313Ssos}
739313Ssos
749313Ssosint
7530994Sphklinux_open(struct proc *p, struct linux_open_args *args)
769313Ssos{
7712858Speter    struct open_args /* {
789313Ssos	char *path;
799313Ssos	int flags;
809313Ssos	int mode;
8112858Speter    } */ bsd_open_args;
829313Ssos    int error;
8314331Speter    caddr_t sg;
8414331Speter
8514331Speter    sg = stackgap_init();
869313Ssos
8714331Speter    if (args->flags & LINUX_O_CREAT)
8814331Speter	CHECKALTCREAT(p, &sg, args->path);
8914331Speter    else
9014331Speter	CHECKALTEXIST(p, &sg, args->path);
9114331Speter
929313Ssos#ifdef DEBUG
939313Ssos    printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n",
949313Ssos	   p->p_pid, args->path, args->flags, args->mode);
959313Ssos#endif
969313Ssos    bsd_open_args.flags = 0;
979313Ssos    if (args->flags & LINUX_O_RDONLY)
989313Ssos	bsd_open_args.flags |= O_RDONLY;
999313Ssos    if (args->flags & LINUX_O_WRONLY)
1009313Ssos	bsd_open_args.flags |= O_WRONLY;
1019313Ssos    if (args->flags & LINUX_O_RDWR)
1029313Ssos	bsd_open_args.flags |= O_RDWR;
1039313Ssos    if (args->flags & LINUX_O_NDELAY)
1049313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1059313Ssos    if (args->flags & LINUX_O_APPEND)
1069313Ssos	bsd_open_args.flags |= O_APPEND;
1079313Ssos    if (args->flags & LINUX_O_SYNC)
1089313Ssos	bsd_open_args.flags |= O_FSYNC;
1099313Ssos    if (args->flags & LINUX_O_NONBLOCK)
1109313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1119313Ssos    if (args->flags & LINUX_FASYNC)
1129313Ssos	bsd_open_args.flags |= O_ASYNC;
1139313Ssos    if (args->flags & LINUX_O_CREAT)
1149313Ssos	bsd_open_args.flags |= O_CREAT;
1159313Ssos    if (args->flags & LINUX_O_TRUNC)
1169313Ssos	bsd_open_args.flags |= O_TRUNC;
1179313Ssos    if (args->flags & LINUX_O_EXCL)
1189313Ssos	bsd_open_args.flags |= O_EXCL;
1199313Ssos    if (args->flags & LINUX_O_NOCTTY)
1209313Ssos	bsd_open_args.flags |= O_NOCTTY;
1219313Ssos    bsd_open_args.path = args->path;
1229313Ssos    bsd_open_args.mode = args->mode;
1239313Ssos
12430994Sphk    error = open(p, &bsd_open_args);
1259313Ssos    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
1269313Ssos	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
1279313Ssos	struct filedesc *fdp = p->p_fd;
12830994Sphk	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
1299313Ssos
1309313Ssos	if (fp->f_type == DTYPE_VNODE)
13151418Sgreen	    fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, p);
1329313Ssos    }
13314331Speter#ifdef DEBUG
13414331Speter    printf("Linux-emul(%d): open returns error %d\n",
13514331Speter	   p->p_pid, error);
13614331Speter#endif
1379313Ssos    return error;
1389313Ssos}
1399313Ssos
1409313Ssosstruct linux_flock {
1419313Ssos    short l_type;
1429313Ssos    short l_whence;
1439313Ssos    linux_off_t l_start;
1449313Ssos    linux_off_t l_len;
1459313Ssos    linux_pid_t l_pid;
1469313Ssos};
1479313Ssos
1489313Ssosstatic void
1499313Ssoslinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
1509313Ssos{
1519313Ssos    switch (linux_flock->l_type) {
1529313Ssos    case LINUX_F_RDLCK:
1539313Ssos	bsd_flock->l_type = F_RDLCK;
1549313Ssos	break;
1559313Ssos    case LINUX_F_WRLCK:
1569313Ssos	bsd_flock->l_type = F_WRLCK;
1579313Ssos	break;
1589313Ssos    case LINUX_F_UNLCK:
1599313Ssos	bsd_flock->l_type = F_UNLCK;
1609313Ssos	break;
16149676Smarcel    default:
16249676Smarcel        bsd_flock->l_type = -1;
16349676Smarcel        break;
1649313Ssos    }
1659313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1669313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1679313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1689313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1699313Ssos}
1709313Ssos
1719313Ssosstatic void
1729313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1739313Ssos{
1749313Ssos    switch (bsd_flock->l_type) {
1759313Ssos    case F_RDLCK:
1769313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1779313Ssos	break;
1789313Ssos    case F_WRLCK:
1799313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1809313Ssos	break;
1819313Ssos    case F_UNLCK:
1829313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1839313Ssos	break;
1849313Ssos    }
1859313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1869313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1879313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
1889313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
1899313Ssos}
1909313Ssos
1919313Ssosint
19230994Sphklinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
1939313Ssos{
1949313Ssos    int error, result;
19512858Speter    struct fcntl_args /* {
1969313Ssos	int fd;
1979313Ssos	int cmd;
1989313Ssos	int arg;
19912858Speter    } */ fcntl_args;
2009313Ssos    struct linux_flock linux_flock;
20114331Speter    struct flock *bsd_flock;
20214331Speter    caddr_t sg;
2039313Ssos
20414331Speter    sg = stackgap_init();
20514331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
20614331Speter
2079313Ssos#ifdef DEBUG
2089313Ssos    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
2099313Ssos	   p->p_pid, args->fd, args->cmd);
2109313Ssos#endif
2119313Ssos    fcntl_args.fd = args->fd;
2129313Ssos
2139313Ssos    switch (args->cmd) {
2149313Ssos    case LINUX_F_DUPFD:
2159313Ssos	fcntl_args.cmd = F_DUPFD;
21649845Smarcel	fcntl_args.arg = args->arg;
21730994Sphk	return fcntl(p, &fcntl_args);
2189313Ssos
2199313Ssos    case LINUX_F_GETFD:
2209313Ssos	fcntl_args.cmd = F_GETFD;
22130994Sphk	return fcntl(p, &fcntl_args);
2229313Ssos
2239313Ssos    case LINUX_F_SETFD:
2249313Ssos	fcntl_args.cmd = F_SETFD;
22549845Smarcel	fcntl_args.arg = args->arg;
22630994Sphk	return fcntl(p, &fcntl_args);
2279313Ssos
2289313Ssos    case LINUX_F_GETFL:
2299313Ssos	fcntl_args.cmd = F_GETFL;
23030994Sphk	error = fcntl(p, &fcntl_args);
23130994Sphk	result = p->p_retval[0];
23230994Sphk	p->p_retval[0] = 0;
23330994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
23430994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
23530994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
23630994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
23730994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
23830994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
23939978Sjfieber	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
2409313Ssos	return error;
2419313Ssos
2429313Ssos    case LINUX_F_SETFL:
24349845Smarcel	fcntl_args.arg = 0;
2449313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2459313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2469313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
24739978Sjfieber	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
2489313Ssos	fcntl_args.cmd = F_SETFL;
24930994Sphk	return fcntl(p, &fcntl_args);
25049676Smarcel
2519313Ssos    case LINUX_F_GETLK:
2529313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2539313Ssos		   	    sizeof(struct linux_flock))))
2549313Ssos	    return error;
2559313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2569313Ssos	fcntl_args.cmd = F_GETLK;
2579313Ssos	fcntl_args.arg = (int)bsd_flock;
25846571Speter	error = fcntl(p, &fcntl_args);
25946571Speter	if (error)
2609313Ssos	    return error;
2619313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2629313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2639313Ssos		       sizeof(struct linux_flock));
2649313Ssos
2659313Ssos    case LINUX_F_SETLK:
2669313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2679313Ssos		   	    sizeof(struct linux_flock))))
2689313Ssos	    return error;
2699313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2709313Ssos	fcntl_args.cmd = F_SETLK;
2719313Ssos	fcntl_args.arg = (int)bsd_flock;
27230994Sphk	return fcntl(p, &fcntl_args);
2739313Ssos
2749313Ssos    case LINUX_F_SETLKW:
2759313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2769313Ssos		   	    sizeof(struct linux_flock))))
2779313Ssos	    return error;
2789313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2799313Ssos	fcntl_args.cmd = F_SETLKW;
2809313Ssos	fcntl_args.arg = (int)bsd_flock;
28130994Sphk	return fcntl(p, &fcntl_args);
2829313Ssos
28363233Smarcel    case LINUX_F_GETOWN:
28463233Smarcel	fcntl_args.cmd = F_GETOWN;
28563233Smarcel	return fcntl(p, &fcntl_args);
28663233Smarcel
2879313Ssos    case LINUX_F_SETOWN:
28863233Smarcel	fcntl_args.cmd = F_SETOWN;
28963233Smarcel	fcntl_args.arg = args->arg;
29063233Smarcel	return fcntl(p, &fcntl_args);
2919313Ssos    }
2929313Ssos    return EINVAL;
2939313Ssos}
2949313Ssos
2959313Ssosint
29630994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
2979313Ssos{
2989313Ssos
29912858Speter    struct lseek_args /* {
30012858Speter	int fd;
3019313Ssos	int pad;
30212858Speter	off_t offset;
3039313Ssos	int whence;
30412858Speter    } */ tmp_args;
3059313Ssos    int error;
3069313Ssos
3079313Ssos#ifdef DEBUG
30837950Sbde    printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n",
30937950Sbde	   (long)p->p_pid, args->fdes, args->off, args->whence);
3109313Ssos#endif
31112858Speter    tmp_args.fd = args->fdes;
31212858Speter    tmp_args.offset = (off_t)args->off;
3139313Ssos    tmp_args.whence = args->whence;
31430994Sphk    error = lseek(p, &tmp_args);
3159313Ssos    return error;
3169313Ssos}
3179313Ssos
31814331Speterint
31930994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
32014331Speter{
32114331Speter	struct lseek_args bsd_args;
32214331Speter	int error;
32314331Speter	off_t off;
32414331Speter
32514331Speter#ifdef DEBUG
32614331Speter        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
32714331Speter	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
32814331Speter#endif
32914331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
33014331Speter
33114331Speter	bsd_args.fd = args->fd;
33214331Speter	bsd_args.offset = off;
33314331Speter	bsd_args.whence = args->whence;
33414331Speter
33530994Sphk	if ((error = lseek(p, &bsd_args)))
33614331Speter		return error;
33714331Speter
33830994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
33914331Speter		return error;
34014331Speter
34130994Sphk	p->p_retval[0] = 0;
34214331Speter	return 0;
34314331Speter}
34414331Speter
34514331Speter
3469313Ssosstruct linux_dirent {
3479313Ssos    long dino;
3489313Ssos    linux_off_t doff;
3499313Ssos    unsigned short dreclen;
3509313Ssos    char dname[LINUX_NAME_MAX + 1];
3519313Ssos};
3529313Ssos
3539313Ssos#define LINUX_RECLEN(de,namlen) \
3549313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3559313Ssos
3569313Ssosint
35730994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3589313Ssos{
35914331Speter	struct linux_getdents_args lda;
36014331Speter
36114331Speter	lda.fd = args->fd;
36214331Speter	lda.dent = args->dent;
36314331Speter	lda.count = 1;
36430994Sphk	return linux_getdents(p, &lda);
36514331Speter}
36614331Speter
36714331Speterint
36830994Sphklinux_getdents(struct proc *p, struct linux_getdents_args *args)
36914331Speter{
3709313Ssos    register struct dirent *bdp;
3719313Ssos    struct vnode *vp;
3729313Ssos    caddr_t inp, buf;		/* BSD-format */
3739313Ssos    int len, reclen;		/* BSD-format */
3749313Ssos    caddr_t outp;		/* Linux-format */
3759313Ssos    int resid, linuxreclen=0;	/* Linux-format */
3769313Ssos    struct file *fp;
3779313Ssos    struct uio auio;
3789313Ssos    struct iovec aiov;
3799313Ssos    struct vattr va;
3809313Ssos    off_t off;
3819313Ssos    struct linux_dirent linux_dirent;
38224654Sdfr    int buflen, error, eofflag, nbytes, justone;
38324654Sdfr    u_long *cookies = NULL, *cookiep;
38424654Sdfr    int ncookies;
3859313Ssos
3869313Ssos#ifdef DEBUG
38714331Speter    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
3889313Ssos	   p->p_pid, args->fd, args->count);
3899313Ssos#endif
39010355Sswallace    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
3919313Ssos	return (error);
39214331Speter    }
3939313Ssos
3949313Ssos    if ((fp->f_flag & FREAD) == 0)
3959313Ssos	return (EBADF);
3969313Ssos
3979313Ssos    vp = (struct vnode *) fp->f_data;
3989313Ssos
3999313Ssos    if (vp->v_type != VDIR)
4009313Ssos	return (EINVAL);
4019313Ssos
40210355Sswallace    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
4039313Ssos	return error;
40411418Sswallace    }
4059313Ssos
4069313Ssos    nbytes = args->count;
4079313Ssos    if (nbytes == 1) {
4089313Ssos	nbytes = sizeof (struct linux_dirent);
4099313Ssos	justone = 1;
4109313Ssos    }
4119313Ssos    else
4129313Ssos	justone = 0;
4139313Ssos
41410355Sswallace    off = fp->f_offset;
41524672Sdfr#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
41624654Sdfr    buflen = max(DIRBLKSIZ, nbytes);
41711418Sswallace    buflen = min(buflen, MAXBSIZE);
4189313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
41922521Sdyson    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4209313Ssosagain:
4219313Ssos    aiov.iov_base = buf;
4229313Ssos    aiov.iov_len = buflen;
4239313Ssos    auio.uio_iov = &aiov;
4249313Ssos    auio.uio_iovcnt = 1;
4259313Ssos    auio.uio_rw = UIO_READ;
4269313Ssos    auio.uio_segflg = UIO_SYSSPACE;
4279313Ssos    auio.uio_procp = p;
4289313Ssos    auio.uio_resid = buflen;
42924654Sdfr    auio.uio_offset = off;
4309313Ssos
43124654Sdfr    if (cookies) {
43224654Sdfr	free(cookies, M_TEMP);
43324654Sdfr	cookies = NULL;
43424654Sdfr    }
43524654Sdfr
43624654Sdfr    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
43710355Sswallace    if (error) {
4389313Ssos	goto out;
43914331Speter    }
4409313Ssos
4419313Ssos    inp = buf;
4429313Ssos    outp = (caddr_t) args->dent;
4439313Ssos    resid = nbytes;
44424654Sdfr    if ((len = buflen - auio.uio_resid) <= 0) {
4459313Ssos	goto eof;
44614331Speter    }
4479313Ssos
44824654Sdfr    cookiep = cookies;
44924654Sdfr
45024654Sdfr    if (cookies) {
45124654Sdfr	/*
45224654Sdfr	 * When using cookies, the vfs has the option of reading from
45324654Sdfr	 * a different offset than that supplied (UFS truncates the
45424654Sdfr	 * offset to a block boundary to make sure that it never reads
45524654Sdfr	 * partway through a directory entry, even if the directory
45624654Sdfr	 * has been compacted).
45724654Sdfr	 */
45824654Sdfr	while (len > 0 && ncookies > 0 && *cookiep <= off) {
45924654Sdfr	    bdp = (struct dirent *) inp;
46024654Sdfr	    len -= bdp->d_reclen;
46124654Sdfr	    inp += bdp->d_reclen;
46224654Sdfr	    cookiep++;
46324654Sdfr	    ncookies--;
46424654Sdfr	}
46524654Sdfr    }
46624654Sdfr
4679313Ssos    while (len > 0) {
46824654Sdfr	if (cookiep && ncookies == 0)
46924654Sdfr	    break;
47010355Sswallace	bdp = (struct dirent *) inp;
47110355Sswallace	reclen = bdp->d_reclen;
47210355Sswallace	if (reclen & 3) {
47310355Sswallace	    printf("linux_readdir: reclen=%d\n", reclen);
47410355Sswallace	    error = EFAULT;
47510355Sswallace	    goto out;
47610355Sswallace	}
47710355Sswallace
4789313Ssos	if (bdp->d_fileno == 0) {
4799313Ssos	    inp += reclen;
48024654Sdfr	    if (cookiep) {
48124654Sdfr		off = *cookiep++;
48224654Sdfr		ncookies--;
48324654Sdfr	    } else
48424654Sdfr		off += reclen;
48510355Sswallace	    len -= reclen;
4869313Ssos	    continue;
4879313Ssos	}
4889313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
4899313Ssos	if (reclen > len || resid < linuxreclen) {
4909313Ssos	    outp++;
4919313Ssos	    break;
4929313Ssos	}
4939313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
49414465Speter	if (justone) {
49514465Speter	    /*
49614465Speter	     * old linux-style readdir usage.
49714465Speter	     */
49814465Speter	    linux_dirent.doff = (linux_off_t) linuxreclen;
49914465Speter	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
50014465Speter	} else {
50152421Smarcel	    linux_dirent.doff = (linux_off_t)(off + reclen);
50214465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
50314465Speter	}
5049313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
50510355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5069313Ssos	    goto out;
50714331Speter	}
5089313Ssos	inp += reclen;
50924654Sdfr	if (cookiep) {
51024654Sdfr	    off = *cookiep++;
51124654Sdfr	    ncookies--;
51224654Sdfr	} else
51324654Sdfr	    off += reclen;
5149313Ssos	outp += linuxreclen;
5159313Ssos	resid -= linuxreclen;
5169313Ssos	len -= reclen;
5179313Ssos	if (justone)
5189313Ssos	    break;
5199313Ssos    }
5209313Ssos
5219313Ssos    if (outp == (caddr_t) args->dent)
5229313Ssos	goto again;
5239313Ssos    fp->f_offset = off;
5249313Ssos
5259313Ssos    if (justone)
5269313Ssos	nbytes = resid + linuxreclen;
52710355Sswallace
5289313Ssoseof:
52930994Sphk    p->p_retval[0] = nbytes - resid;
5309313Ssosout:
53124654Sdfr    if (cookies)
53224654Sdfr	free(cookies, M_TEMP);
53322543Smpp    VOP_UNLOCK(vp, 0, p);
5349313Ssos    free(buf, M_TEMP);
5359313Ssos    return error;
5369313Ssos}
53714331Speter
53814331Speter/*
53914331Speter * These exist mainly for hooks for doing /compat/linux translation.
54014331Speter */
54114331Speter
54214331Speterint
54330994Sphklinux_access(struct proc *p, struct linux_access_args *args)
54414331Speter{
54514331Speter	struct access_args bsd;
54614331Speter	caddr_t sg;
54714331Speter
54814331Speter	sg = stackgap_init();
54914331Speter	CHECKALTEXIST(p, &sg, args->path);
55014331Speter
55114331Speter#ifdef DEBUG
55214331Speter        printf("Linux-emul(%d): access(%s, %d)\n",
55314331Speter	    p->p_pid, args->path, args->flags);
55414331Speter#endif
55514331Speter	bsd.path = args->path;
55614331Speter	bsd.flags = args->flags;
55714331Speter
55830994Sphk	return access(p, &bsd);
55914331Speter}
56014331Speter
56114331Speterint
56230994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
56314331Speter{
56414331Speter	struct unlink_args bsd;
56514331Speter	caddr_t sg;
56614331Speter
56714331Speter	sg = stackgap_init();
56814331Speter	CHECKALTEXIST(p, &sg, args->path);
56914331Speter
57014331Speter#ifdef DEBUG
57114331Speter	printf("Linux-emul(%d): unlink(%s)\n",
57214331Speter	   p->p_pid, args->path);
57314331Speter#endif
57414331Speter	bsd.path = args->path;
57514331Speter
57630994Sphk	return unlink(p, &bsd);
57714331Speter}
57814331Speter
57914331Speterint
58030994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
58114331Speter{
58214331Speter	struct chdir_args bsd;
58314331Speter	caddr_t sg;
58414331Speter
58514331Speter	sg = stackgap_init();
58614331Speter	CHECKALTEXIST(p, &sg, args->path);
58714331Speter
58814331Speter#ifdef DEBUG
58914331Speter	printf("Linux-emul(%d): chdir(%s)\n",
59014331Speter	   p->p_pid, args->path);
59114331Speter#endif
59214331Speter	bsd.path = args->path;
59314331Speter
59430994Sphk	return chdir(p, &bsd);
59514331Speter}
59614331Speter
59714331Speterint
59830994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
59914331Speter{
60014331Speter	struct chmod_args bsd;
60114331Speter	caddr_t sg;
60214331Speter
60314331Speter	sg = stackgap_init();
60414331Speter	CHECKALTEXIST(p, &sg, args->path);
60514331Speter
60614331Speter#ifdef DEBUG
60714331Speter        printf("Linux-emul(%d): chmod(%s, %d)\n",
60814331Speter	    p->p_pid, args->path, args->mode);
60914331Speter#endif
61014331Speter	bsd.path = args->path;
61114331Speter	bsd.mode = args->mode;
61214331Speter
61330994Sphk	return chmod(p, &bsd);
61414331Speter}
61514331Speter
61614331Speterint
61730994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
61814331Speter{
61914331Speter	struct chown_args bsd;
62014331Speter	caddr_t sg;
62114331Speter
62214331Speter	sg = stackgap_init();
62314331Speter	CHECKALTEXIST(p, &sg, args->path);
62414331Speter
62514331Speter#ifdef DEBUG
62614331Speter        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
62714331Speter	    p->p_pid, args->path, args->uid, args->gid);
62814331Speter#endif
62914331Speter	bsd.path = args->path;
63014331Speter	/* XXX size casts here */
63114331Speter	bsd.uid = args->uid;
63214331Speter	bsd.gid = args->gid;
63314331Speter
63430994Sphk	return chown(p, &bsd);
63514331Speter}
63614331Speter
63714331Speterint
63834941Speterlinux_lchown(struct proc *p, struct linux_lchown_args *args)
63934941Speter{
64034941Speter	struct lchown_args bsd;
64134941Speter	caddr_t sg;
64234941Speter
64334941Speter	sg = stackgap_init();
64434941Speter	CHECKALTEXIST(p, &sg, args->path);
64534941Speter
64634941Speter#ifdef DEBUG
64734941Speter        printf("Linux-emul(%d): lchown(%s, %d, %d)\n",
64834941Speter	    p->p_pid, args->path, args->uid, args->gid);
64934941Speter#endif
65034941Speter	bsd.path = args->path;
65134941Speter	/* XXX size casts here */
65234941Speter	bsd.uid = args->uid;
65334941Speter	bsd.gid = args->gid;
65434941Speter
65534941Speter	return lchown(p, &bsd);
65634941Speter}
65734941Speter
65834941Speterint
65930994Sphklinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
66014331Speter{
66114331Speter	struct mkdir_args bsd;
66214331Speter	caddr_t sg;
66314331Speter
66414331Speter	sg = stackgap_init();
66514331Speter	CHECKALTCREAT(p, &sg, args->path);
66614331Speter
66714331Speter#ifdef DEBUG
66814331Speter        printf("Linux-emul(%d): mkdir(%s, %d)\n",
66914331Speter	    p->p_pid, args->path, args->mode);
67014331Speter#endif
67114331Speter	bsd.path = args->path;
67214331Speter	bsd.mode = args->mode;
67314331Speter
67430994Sphk	return mkdir(p, &bsd);
67514331Speter}
67614331Speter
67714331Speterint
67830994Sphklinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
67914331Speter{
68014331Speter	struct rmdir_args bsd;
68114331Speter	caddr_t sg;
68214331Speter
68314331Speter	sg = stackgap_init();
68414331Speter	CHECKALTEXIST(p, &sg, args->path);
68514331Speter
68614331Speter#ifdef DEBUG
68714331Speter        printf("Linux-emul(%d): rmdir(%s)\n",
68814331Speter	    p->p_pid, args->path);
68914331Speter#endif
69014331Speter	bsd.path = args->path;
69114331Speter
69230994Sphk	return rmdir(p, &bsd);
69314331Speter}
69414331Speter
69514331Speterint
69630994Sphklinux_rename(struct proc *p, struct linux_rename_args *args)
69714331Speter{
69814331Speter	struct rename_args bsd;
69914331Speter	caddr_t sg;
70014331Speter
70114331Speter	sg = stackgap_init();
70214331Speter	CHECKALTEXIST(p, &sg, args->from);
70314331Speter	CHECKALTCREAT(p, &sg, args->to);
70414331Speter
70514331Speter#ifdef DEBUG
70614331Speter        printf("Linux-emul(%d): rename(%s, %s)\n",
70714331Speter	    p->p_pid, args->from, args->to);
70814331Speter#endif
70914331Speter	bsd.from = args->from;
71014331Speter	bsd.to = args->to;
71114331Speter
71230994Sphk	return rename(p, &bsd);
71314331Speter}
71414331Speter
71514331Speterint
71630994Sphklinux_symlink(struct proc *p, struct linux_symlink_args *args)
71714331Speter{
71814331Speter	struct symlink_args bsd;
71914331Speter	caddr_t sg;
72014331Speter
72114331Speter	sg = stackgap_init();
72214331Speter	CHECKALTEXIST(p, &sg, args->path);
72314331Speter	CHECKALTCREAT(p, &sg, args->to);
72414331Speter
72514331Speter#ifdef DEBUG
72614331Speter        printf("Linux-emul(%d): symlink(%s, %s)\n",
72714331Speter	    p->p_pid, args->path, args->to);
72814331Speter#endif
72914331Speter	bsd.path = args->path;
73014331Speter	bsd.link = args->to;
73114331Speter
73230994Sphk	return symlink(p, &bsd);
73314331Speter}
73414331Speter
73514331Speterint
73630994Sphklinux_readlink(struct proc *p, struct linux_readlink_args *args)
73714331Speter{
73814331Speter	struct readlink_args bsd;
73914331Speter	caddr_t sg;
74014331Speter
74114331Speter	sg = stackgap_init();
74214331Speter	CHECKALTEXIST(p, &sg, args->name);
74314331Speter
74414331Speter#ifdef DEBUG
74537950Sbde        printf("Linux-emul(%ld): readlink(%s, %p, %d)\n",
74637950Sbde	    (long)p->p_pid, args->name, (void *)args->buf, args->count);
74714331Speter#endif
74814331Speter	bsd.path = args->name;
74914331Speter	bsd.buf = args->buf;
75014331Speter	bsd.count = args->count;
75114331Speter
75230994Sphk	return readlink(p, &bsd);
75314331Speter}
75414331Speter
75514331Speterint
75630994Sphklinux_truncate(struct proc *p, struct linux_truncate_args *args)
75714331Speter{
75842499Seivind	struct truncate_args bsd;
75914331Speter	caddr_t sg;
76014331Speter
76114331Speter	sg = stackgap_init();
76214331Speter	CHECKALTEXIST(p, &sg, args->path);
76314331Speter
76414331Speter#ifdef DEBUG
76532266Sjmb        printf("Linux-emul(%d): truncate(%s, %ld)\n",
76632266Sjmb	    p->p_pid, args->path, args->length);
76714331Speter#endif
76814331Speter	bsd.path = args->path;
76932265Sjmb	bsd.length = args->length;
77014331Speter
77142499Seivind	return truncate(p, &bsd);
77214331Speter}
77314331Speter
77449662Smarcelint
77549662Smarcellinux_link(struct proc *p, struct linux_link_args *args)
77649662Smarcel{
77749662Smarcel    struct link_args bsd;
77849662Smarcel    caddr_t sg;
77949662Smarcel
78049662Smarcel    sg = stackgap_init();
78149662Smarcel    CHECKALTEXIST(p, &sg, args->path);
78249662Smarcel    CHECKALTCREAT(p, &sg, args->to);
78349662Smarcel
78449662Smarcel#ifdef DEBUG
78549662Smarcel    printf("Linux-emul(%d): link(%s, %s)\n", p->p_pid, args->path, args->to);
78649662Smarcel#endif
78749662Smarcel
78849662Smarcel    bsd.path = args->path;
78949662Smarcel    bsd.link = args->to;
79049662Smarcel
79149662Smarcel    return link(p, &bsd);
79249662Smarcel}
79349788Smarcel
79449788Smarcelint
79549788Smarcellinux_getcwd(struct proc *p, struct linux_getcwd_args *args)
79649788Smarcel{
79751348Smarcel	struct __getcwd_args bsd;
79851348Smarcel	caddr_t sg;
79951348Smarcel	int error, len;
80049788Smarcel
80149788Smarcel#ifdef DEBUG
80251348Smarcel	printf("Linux-emul(%ld): getcwd(%p, %ld)\n", (long)p->p_pid,
80351348Smarcel	       args->buf, args->bufsize);
80449788Smarcel#endif
80549788Smarcel
80651348Smarcel	sg = stackgap_init();
80751348Smarcel	bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE);
80851348Smarcel	bsd.buflen = SPARE_USRSPACE;
80951348Smarcel	error = __getcwd(p, &bsd);
81051348Smarcel	if (!error) {
81151348Smarcel		len = strlen(bsd.buf) + 1;
81251348Smarcel		if (len <= args->bufsize) {
81351348Smarcel			p->p_retval[0] = len;
81451348Smarcel			error = copyout(bsd.buf, args->buf, len);
81551348Smarcel		}
81651348Smarcel		else
81751348Smarcel			error = ERANGE;
81851348Smarcel	}
81951348Smarcel	return (error);
82049788Smarcel}
82153713Smarcel
82253713Smarcelint
82353713Smarcellinux_fdatasync(p, uap)
82453713Smarcel	struct proc *p;
82553713Smarcel	struct linux_fdatasync_args *uap;
82653713Smarcel{
82753713Smarcel	struct fsync_args bsd;
82853713Smarcel
82953713Smarcel	bsd.fd = uap->fd;
83053713Smarcel	return fsync(p, &bsd);
83153713Smarcel}
83263285Smarcel
83363285Smarcelint
83463285Smarcellinux_pread(p, uap)
83563285Smarcel	struct proc *p;
83663285Smarcel	struct linux_pread_args *uap;
83763285Smarcel{
83863285Smarcel	struct pread_args bsd;
83963285Smarcel
84063285Smarcel	bsd.fd = uap->fd;
84163285Smarcel	bsd.buf = uap->buf;
84263285Smarcel	bsd.nbyte = uap->nbyte;
84363285Smarcel	bsd.offset = uap->offset;
84463285Smarcel	return pread(p, &bsd);
84563285Smarcel}
84663285Smarcel
84763285Smarcelint
84863285Smarcellinux_pwrite(p, uap)
84963285Smarcel	struct proc *p;
85063285Smarcel	struct linux_pwrite_args *uap;
85163285Smarcel{
85263285Smarcel	struct pwrite_args bsd;
85363285Smarcel
85463285Smarcel	bsd.fd = uap->fd;
85563285Smarcel	bsd.buf = uap->buf;
85663285Smarcel	bsd.nbyte = uap->nbyte;
85763285Smarcel	bsd.offset = uap->offset;
85863285Smarcel	return pwrite(p, &bsd);
85963285Smarcel}
860