linux_file.c revision 68583
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 68583 2000-11-10 21:30:19Z 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>
4868583Smarcel#ifdef __alpha__
4968201Sobrien#include <linux_proto.h>
5068583Smarcel#else
5168583Smarcel#include <machine/../linux/linux_proto.h>
5268583Smarcel#endif
5364905Smarcel#include <compat/linux/linux_util.h>
549313Ssos
5568201Sobrien#ifndef __alpha__
569313Ssosint
5730994Sphklinux_creat(struct proc *p, struct linux_creat_args *args)
589313Ssos{
5912858Speter    struct open_args /* {
609313Ssos	char *path;
619313Ssos	int flags;
629313Ssos	int mode;
6312858Speter    } */ bsd_open_args;
6414331Speter    caddr_t sg;
659313Ssos
6614331Speter    sg = stackgap_init();
6714331Speter    CHECKALTCREAT(p, &sg, args->path);
6814331Speter
699313Ssos#ifdef DEBUG
709313Ssos    printf("Linux-emul(%d): creat(%s, %d)\n",
719313Ssos	   p->p_pid, args->path, args->mode);
729313Ssos#endif
739313Ssos    bsd_open_args.path = args->path;
749313Ssos    bsd_open_args.mode = args->mode;
759313Ssos    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
7630994Sphk    return open(p, &bsd_open_args);
779313Ssos}
7868201Sobrien#endif /*!__alpha__*/
799313Ssos
809313Ssosint
8130994Sphklinux_open(struct proc *p, struct linux_open_args *args)
829313Ssos{
8312858Speter    struct open_args /* {
849313Ssos	char *path;
859313Ssos	int flags;
869313Ssos	int mode;
8712858Speter    } */ bsd_open_args;
889313Ssos    int error;
8914331Speter    caddr_t sg;
9014331Speter
9114331Speter    sg = stackgap_init();
929313Ssos
9314331Speter    if (args->flags & LINUX_O_CREAT)
9414331Speter	CHECKALTCREAT(p, &sg, args->path);
9514331Speter    else
9614331Speter	CHECKALTEXIST(p, &sg, args->path);
9714331Speter
989313Ssos#ifdef DEBUG
999313Ssos    printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n",
1009313Ssos	   p->p_pid, args->path, args->flags, args->mode);
1019313Ssos#endif
1029313Ssos    bsd_open_args.flags = 0;
1039313Ssos    if (args->flags & LINUX_O_RDONLY)
1049313Ssos	bsd_open_args.flags |= O_RDONLY;
1059313Ssos    if (args->flags & LINUX_O_WRONLY)
1069313Ssos	bsd_open_args.flags |= O_WRONLY;
1079313Ssos    if (args->flags & LINUX_O_RDWR)
1089313Ssos	bsd_open_args.flags |= O_RDWR;
1099313Ssos    if (args->flags & LINUX_O_NDELAY)
1109313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1119313Ssos    if (args->flags & LINUX_O_APPEND)
1129313Ssos	bsd_open_args.flags |= O_APPEND;
1139313Ssos    if (args->flags & LINUX_O_SYNC)
1149313Ssos	bsd_open_args.flags |= O_FSYNC;
1159313Ssos    if (args->flags & LINUX_O_NONBLOCK)
1169313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1179313Ssos    if (args->flags & LINUX_FASYNC)
1189313Ssos	bsd_open_args.flags |= O_ASYNC;
1199313Ssos    if (args->flags & LINUX_O_CREAT)
1209313Ssos	bsd_open_args.flags |= O_CREAT;
1219313Ssos    if (args->flags & LINUX_O_TRUNC)
1229313Ssos	bsd_open_args.flags |= O_TRUNC;
1239313Ssos    if (args->flags & LINUX_O_EXCL)
1249313Ssos	bsd_open_args.flags |= O_EXCL;
1259313Ssos    if (args->flags & LINUX_O_NOCTTY)
1269313Ssos	bsd_open_args.flags |= O_NOCTTY;
1279313Ssos    bsd_open_args.path = args->path;
1289313Ssos    bsd_open_args.mode = args->mode;
1299313Ssos
13030994Sphk    error = open(p, &bsd_open_args);
1319313Ssos    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
1329313Ssos	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
1339313Ssos	struct filedesc *fdp = p->p_fd;
13430994Sphk	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
1359313Ssos
1369313Ssos	if (fp->f_type == DTYPE_VNODE)
13751418Sgreen	    fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, p);
1389313Ssos    }
13914331Speter#ifdef DEBUG
14014331Speter    printf("Linux-emul(%d): open returns error %d\n",
14114331Speter	   p->p_pid, error);
14214331Speter#endif
1439313Ssos    return error;
1449313Ssos}
1459313Ssos
1469313Ssosstruct linux_flock {
1479313Ssos    short l_type;
1489313Ssos    short l_whence;
1499313Ssos    linux_off_t l_start;
1509313Ssos    linux_off_t l_len;
1519313Ssos    linux_pid_t l_pid;
1529313Ssos};
1539313Ssos
1549313Ssosstatic void
1559313Ssoslinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
1569313Ssos{
1579313Ssos    switch (linux_flock->l_type) {
1589313Ssos    case LINUX_F_RDLCK:
1599313Ssos	bsd_flock->l_type = F_RDLCK;
1609313Ssos	break;
1619313Ssos    case LINUX_F_WRLCK:
1629313Ssos	bsd_flock->l_type = F_WRLCK;
1639313Ssos	break;
1649313Ssos    case LINUX_F_UNLCK:
1659313Ssos	bsd_flock->l_type = F_UNLCK;
1669313Ssos	break;
16749676Smarcel    default:
16849676Smarcel        bsd_flock->l_type = -1;
16949676Smarcel        break;
1709313Ssos    }
1719313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1729313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1739313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1749313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1759313Ssos}
1769313Ssos
1779313Ssosstatic void
1789313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1799313Ssos{
1809313Ssos    switch (bsd_flock->l_type) {
1819313Ssos    case F_RDLCK:
1829313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1839313Ssos	break;
1849313Ssos    case F_WRLCK:
1859313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1869313Ssos	break;
1879313Ssos    case F_UNLCK:
1889313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1899313Ssos	break;
1909313Ssos    }
1919313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1929313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1939313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
1949313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
1959313Ssos}
1969313Ssos
1979313Ssosint
19830994Sphklinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
1999313Ssos{
2009313Ssos    int error, result;
20112858Speter    struct fcntl_args /* {
2029313Ssos	int fd;
2039313Ssos	int cmd;
2049313Ssos	int arg;
20512858Speter    } */ fcntl_args;
2069313Ssos    struct linux_flock linux_flock;
20714331Speter    struct flock *bsd_flock;
20814331Speter    caddr_t sg;
2099313Ssos
21014331Speter    sg = stackgap_init();
21114331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
21214331Speter
2139313Ssos#ifdef DEBUG
2149313Ssos    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
2159313Ssos	   p->p_pid, args->fd, args->cmd);
2169313Ssos#endif
2179313Ssos    fcntl_args.fd = args->fd;
2189313Ssos
2199313Ssos    switch (args->cmd) {
2209313Ssos    case LINUX_F_DUPFD:
2219313Ssos	fcntl_args.cmd = F_DUPFD;
22249845Smarcel	fcntl_args.arg = args->arg;
22330994Sphk	return fcntl(p, &fcntl_args);
2249313Ssos
2259313Ssos    case LINUX_F_GETFD:
2269313Ssos	fcntl_args.cmd = F_GETFD;
22730994Sphk	return fcntl(p, &fcntl_args);
2289313Ssos
2299313Ssos    case LINUX_F_SETFD:
2309313Ssos	fcntl_args.cmd = F_SETFD;
23149845Smarcel	fcntl_args.arg = args->arg;
23230994Sphk	return fcntl(p, &fcntl_args);
2339313Ssos
2349313Ssos    case LINUX_F_GETFL:
2359313Ssos	fcntl_args.cmd = F_GETFL;
23630994Sphk	error = fcntl(p, &fcntl_args);
23730994Sphk	result = p->p_retval[0];
23830994Sphk	p->p_retval[0] = 0;
23930994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
24030994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
24130994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
24230994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
24330994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
24430994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
24539978Sjfieber	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
2469313Ssos	return error;
2479313Ssos
2489313Ssos    case LINUX_F_SETFL:
24949845Smarcel	fcntl_args.arg = 0;
2509313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2519313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2529313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
25339978Sjfieber	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
2549313Ssos	fcntl_args.cmd = F_SETFL;
25530994Sphk	return fcntl(p, &fcntl_args);
25649676Smarcel
2579313Ssos    case LINUX_F_GETLK:
2589313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2599313Ssos		   	    sizeof(struct linux_flock))))
2609313Ssos	    return error;
2619313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2629313Ssos	fcntl_args.cmd = F_GETLK;
26368201Sobrien	fcntl_args.arg = (long)bsd_flock;
26446571Speter	error = fcntl(p, &fcntl_args);
26546571Speter	if (error)
2669313Ssos	    return error;
2679313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2689313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2699313Ssos		       sizeof(struct linux_flock));
2709313Ssos
2719313Ssos    case LINUX_F_SETLK:
2729313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2739313Ssos		   	    sizeof(struct linux_flock))))
2749313Ssos	    return error;
2759313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2769313Ssos	fcntl_args.cmd = F_SETLK;
27768201Sobrien	fcntl_args.arg = (long)bsd_flock;
27830994Sphk	return fcntl(p, &fcntl_args);
2799313Ssos
2809313Ssos    case LINUX_F_SETLKW:
2819313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2829313Ssos		   	    sizeof(struct linux_flock))))
2839313Ssos	    return error;
2849313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2859313Ssos	fcntl_args.cmd = F_SETLKW;
28668201Sobrien	fcntl_args.arg = (long)bsd_flock;
28730994Sphk	return fcntl(p, &fcntl_args);
2889313Ssos
28963233Smarcel    case LINUX_F_GETOWN:
29063233Smarcel	fcntl_args.cmd = F_GETOWN;
29163233Smarcel	return fcntl(p, &fcntl_args);
29263233Smarcel
2939313Ssos    case LINUX_F_SETOWN:
29463233Smarcel	fcntl_args.cmd = F_SETOWN;
29563233Smarcel	fcntl_args.arg = args->arg;
29663233Smarcel	return fcntl(p, &fcntl_args);
2979313Ssos    }
2989313Ssos    return EINVAL;
2999313Ssos}
3009313Ssos
3019313Ssosint
30230994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
3039313Ssos{
3049313Ssos
30512858Speter    struct lseek_args /* {
30612858Speter	int fd;
3079313Ssos	int pad;
30812858Speter	off_t offset;
3099313Ssos	int whence;
31012858Speter    } */ tmp_args;
3119313Ssos    int error;
3129313Ssos
3139313Ssos#ifdef DEBUG
31437950Sbde    printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n",
31537950Sbde	   (long)p->p_pid, args->fdes, args->off, args->whence);
3169313Ssos#endif
31712858Speter    tmp_args.fd = args->fdes;
31812858Speter    tmp_args.offset = (off_t)args->off;
3199313Ssos    tmp_args.whence = args->whence;
32030994Sphk    error = lseek(p, &tmp_args);
3219313Ssos    return error;
3229313Ssos}
3239313Ssos
32468201Sobrien#ifndef __alpha__
32514331Speterint
32630994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
32714331Speter{
32814331Speter	struct lseek_args bsd_args;
32914331Speter	int error;
33014331Speter	off_t off;
33114331Speter
33214331Speter#ifdef DEBUG
33314331Speter        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
33414331Speter	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
33514331Speter#endif
33614331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
33714331Speter
33814331Speter	bsd_args.fd = args->fd;
33914331Speter	bsd_args.offset = off;
34014331Speter	bsd_args.whence = args->whence;
34114331Speter
34230994Sphk	if ((error = lseek(p, &bsd_args)))
34314331Speter		return error;
34414331Speter
34530994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
34614331Speter		return error;
34714331Speter
34830994Sphk	p->p_retval[0] = 0;
34914331Speter	return 0;
35014331Speter}
35168201Sobrien#endif /*!__alpha__*/
35214331Speter
35314331Speter
3549313Ssosstruct linux_dirent {
3559313Ssos    long dino;
3569313Ssos    linux_off_t doff;
3579313Ssos    unsigned short dreclen;
3589313Ssos    char dname[LINUX_NAME_MAX + 1];
3599313Ssos};
3609313Ssos
3619313Ssos#define LINUX_RECLEN(de,namlen) \
3629313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3639313Ssos
36468201Sobrien#ifndef __alpha__
3659313Ssosint
36630994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3679313Ssos{
36814331Speter	struct linux_getdents_args lda;
36914331Speter
37014331Speter	lda.fd = args->fd;
37114331Speter	lda.dent = args->dent;
37214331Speter	lda.count = 1;
37330994Sphk	return linux_getdents(p, &lda);
37414331Speter}
37568201Sobrien#endif /*!__alpha__*/
37614331Speter
37714331Speterint
37830994Sphklinux_getdents(struct proc *p, struct linux_getdents_args *args)
37914331Speter{
3809313Ssos    register struct dirent *bdp;
3819313Ssos    struct vnode *vp;
3829313Ssos    caddr_t inp, buf;		/* BSD-format */
3839313Ssos    int len, reclen;		/* BSD-format */
3849313Ssos    caddr_t outp;		/* Linux-format */
3859313Ssos    int resid, linuxreclen=0;	/* Linux-format */
3869313Ssos    struct file *fp;
3879313Ssos    struct uio auio;
3889313Ssos    struct iovec aiov;
3899313Ssos    struct vattr va;
3909313Ssos    off_t off;
3919313Ssos    struct linux_dirent linux_dirent;
39224654Sdfr    int buflen, error, eofflag, nbytes, justone;
39324654Sdfr    u_long *cookies = NULL, *cookiep;
39424654Sdfr    int ncookies;
3959313Ssos
3969313Ssos#ifdef DEBUG
39714331Speter    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
3989313Ssos	   p->p_pid, args->fd, args->count);
3999313Ssos#endif
40010355Sswallace    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
4019313Ssos	return (error);
40214331Speter    }
4039313Ssos
4049313Ssos    if ((fp->f_flag & FREAD) == 0)
4059313Ssos	return (EBADF);
4069313Ssos
4079313Ssos    vp = (struct vnode *) fp->f_data;
4089313Ssos
4099313Ssos    if (vp->v_type != VDIR)
4109313Ssos	return (EINVAL);
4119313Ssos
41210355Sswallace    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
4139313Ssos	return error;
41411418Sswallace    }
4159313Ssos
4169313Ssos    nbytes = args->count;
4179313Ssos    if (nbytes == 1) {
4189313Ssos	nbytes = sizeof (struct linux_dirent);
4199313Ssos	justone = 1;
4209313Ssos    }
4219313Ssos    else
4229313Ssos	justone = 0;
4239313Ssos
42410355Sswallace    off = fp->f_offset;
42524672Sdfr#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
42624654Sdfr    buflen = max(DIRBLKSIZ, nbytes);
42711418Sswallace    buflen = min(buflen, MAXBSIZE);
4289313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
42922521Sdyson    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4309313Ssosagain:
4319313Ssos    aiov.iov_base = buf;
4329313Ssos    aiov.iov_len = buflen;
4339313Ssos    auio.uio_iov = &aiov;
4349313Ssos    auio.uio_iovcnt = 1;
4359313Ssos    auio.uio_rw = UIO_READ;
4369313Ssos    auio.uio_segflg = UIO_SYSSPACE;
4379313Ssos    auio.uio_procp = p;
4389313Ssos    auio.uio_resid = buflen;
43924654Sdfr    auio.uio_offset = off;
4409313Ssos
44124654Sdfr    if (cookies) {
44224654Sdfr	free(cookies, M_TEMP);
44324654Sdfr	cookies = NULL;
44424654Sdfr    }
44524654Sdfr
44624654Sdfr    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
44710355Sswallace    if (error) {
4489313Ssos	goto out;
44914331Speter    }
4509313Ssos
4519313Ssos    inp = buf;
4529313Ssos    outp = (caddr_t) args->dent;
4539313Ssos    resid = nbytes;
45424654Sdfr    if ((len = buflen - auio.uio_resid) <= 0) {
4559313Ssos	goto eof;
45614331Speter    }
4579313Ssos
45824654Sdfr    cookiep = cookies;
45924654Sdfr
46024654Sdfr    if (cookies) {
46124654Sdfr	/*
46224654Sdfr	 * When using cookies, the vfs has the option of reading from
46324654Sdfr	 * a different offset than that supplied (UFS truncates the
46424654Sdfr	 * offset to a block boundary to make sure that it never reads
46524654Sdfr	 * partway through a directory entry, even if the directory
46624654Sdfr	 * has been compacted).
46724654Sdfr	 */
46824654Sdfr	while (len > 0 && ncookies > 0 && *cookiep <= off) {
46924654Sdfr	    bdp = (struct dirent *) inp;
47024654Sdfr	    len -= bdp->d_reclen;
47124654Sdfr	    inp += bdp->d_reclen;
47224654Sdfr	    cookiep++;
47324654Sdfr	    ncookies--;
47424654Sdfr	}
47524654Sdfr    }
47624654Sdfr
4779313Ssos    while (len > 0) {
47824654Sdfr	if (cookiep && ncookies == 0)
47924654Sdfr	    break;
48010355Sswallace	bdp = (struct dirent *) inp;
48110355Sswallace	reclen = bdp->d_reclen;
48210355Sswallace	if (reclen & 3) {
48310355Sswallace	    printf("linux_readdir: reclen=%d\n", reclen);
48410355Sswallace	    error = EFAULT;
48510355Sswallace	    goto out;
48610355Sswallace	}
48710355Sswallace
4889313Ssos	if (bdp->d_fileno == 0) {
4899313Ssos	    inp += reclen;
49024654Sdfr	    if (cookiep) {
49124654Sdfr		off = *cookiep++;
49224654Sdfr		ncookies--;
49324654Sdfr	    } else
49424654Sdfr		off += reclen;
49510355Sswallace	    len -= reclen;
4969313Ssos	    continue;
4979313Ssos	}
4989313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
4999313Ssos	if (reclen > len || resid < linuxreclen) {
5009313Ssos	    outp++;
5019313Ssos	    break;
5029313Ssos	}
5039313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
50414465Speter	if (justone) {
50514465Speter	    /*
50614465Speter	     * old linux-style readdir usage.
50714465Speter	     */
50814465Speter	    linux_dirent.doff = (linux_off_t) linuxreclen;
50914465Speter	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
51014465Speter	} else {
51168347Smarcel	    if (cookiep)
51268347Smarcel		linux_dirent.doff = (linux_off_t)*cookiep;
51368347Smarcel	    else
51468347Smarcel		linux_dirent.doff = (linux_off_t)(off + reclen);
51514465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
51614465Speter	}
5179313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
51810355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5199313Ssos	    goto out;
52014331Speter	}
5219313Ssos	inp += reclen;
52224654Sdfr	if (cookiep) {
52324654Sdfr	    off = *cookiep++;
52424654Sdfr	    ncookies--;
52524654Sdfr	} else
52624654Sdfr	    off += reclen;
5279313Ssos	outp += linuxreclen;
5289313Ssos	resid -= linuxreclen;
5299313Ssos	len -= reclen;
5309313Ssos	if (justone)
5319313Ssos	    break;
5329313Ssos    }
5339313Ssos
5349313Ssos    if (outp == (caddr_t) args->dent)
5359313Ssos	goto again;
5369313Ssos    fp->f_offset = off;
5379313Ssos
5389313Ssos    if (justone)
5399313Ssos	nbytes = resid + linuxreclen;
54010355Sswallace
5419313Ssoseof:
54230994Sphk    p->p_retval[0] = nbytes - resid;
5439313Ssosout:
54424654Sdfr    if (cookies)
54524654Sdfr	free(cookies, M_TEMP);
54622543Smpp    VOP_UNLOCK(vp, 0, p);
5479313Ssos    free(buf, M_TEMP);
5489313Ssos    return error;
5499313Ssos}
55014331Speter
55114331Speter/*
55214331Speter * These exist mainly for hooks for doing /compat/linux translation.
55314331Speter */
55414331Speter
55514331Speterint
55630994Sphklinux_access(struct proc *p, struct linux_access_args *args)
55714331Speter{
55814331Speter	struct access_args bsd;
55914331Speter	caddr_t sg;
56014331Speter
56114331Speter	sg = stackgap_init();
56214331Speter	CHECKALTEXIST(p, &sg, args->path);
56314331Speter
56414331Speter#ifdef DEBUG
56514331Speter        printf("Linux-emul(%d): access(%s, %d)\n",
56614331Speter	    p->p_pid, args->path, args->flags);
56714331Speter#endif
56814331Speter	bsd.path = args->path;
56914331Speter	bsd.flags = args->flags;
57014331Speter
57130994Sphk	return access(p, &bsd);
57214331Speter}
57314331Speter
57414331Speterint
57530994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
57614331Speter{
57714331Speter	struct unlink_args bsd;
57814331Speter	caddr_t sg;
57914331Speter
58014331Speter	sg = stackgap_init();
58114331Speter	CHECKALTEXIST(p, &sg, args->path);
58214331Speter
58314331Speter#ifdef DEBUG
58414331Speter	printf("Linux-emul(%d): unlink(%s)\n",
58514331Speter	   p->p_pid, args->path);
58614331Speter#endif
58714331Speter	bsd.path = args->path;
58814331Speter
58930994Sphk	return unlink(p, &bsd);
59014331Speter}
59114331Speter
59214331Speterint
59330994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
59414331Speter{
59514331Speter	struct chdir_args bsd;
59614331Speter	caddr_t sg;
59714331Speter
59814331Speter	sg = stackgap_init();
59914331Speter	CHECKALTEXIST(p, &sg, args->path);
60014331Speter
60114331Speter#ifdef DEBUG
60214331Speter	printf("Linux-emul(%d): chdir(%s)\n",
60314331Speter	   p->p_pid, args->path);
60414331Speter#endif
60514331Speter	bsd.path = args->path;
60614331Speter
60730994Sphk	return chdir(p, &bsd);
60814331Speter}
60914331Speter
61014331Speterint
61130994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
61214331Speter{
61314331Speter	struct chmod_args bsd;
61414331Speter	caddr_t sg;
61514331Speter
61614331Speter	sg = stackgap_init();
61714331Speter	CHECKALTEXIST(p, &sg, args->path);
61814331Speter
61914331Speter#ifdef DEBUG
62014331Speter        printf("Linux-emul(%d): chmod(%s, %d)\n",
62114331Speter	    p->p_pid, args->path, args->mode);
62214331Speter#endif
62314331Speter	bsd.path = args->path;
62414331Speter	bsd.mode = args->mode;
62514331Speter
62630994Sphk	return chmod(p, &bsd);
62714331Speter}
62814331Speter
62914331Speterint
63030994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
63114331Speter{
63214331Speter	struct chown_args bsd;
63314331Speter	caddr_t sg;
63414331Speter
63514331Speter	sg = stackgap_init();
63614331Speter	CHECKALTEXIST(p, &sg, args->path);
63714331Speter
63814331Speter#ifdef DEBUG
63914331Speter        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
64014331Speter	    p->p_pid, args->path, args->uid, args->gid);
64114331Speter#endif
64214331Speter	bsd.path = args->path;
64314331Speter	/* XXX size casts here */
64414331Speter	bsd.uid = args->uid;
64514331Speter	bsd.gid = args->gid;
64614331Speter
64730994Sphk	return chown(p, &bsd);
64814331Speter}
64914331Speter
65014331Speterint
65134941Speterlinux_lchown(struct proc *p, struct linux_lchown_args *args)
65234941Speter{
65334941Speter	struct lchown_args bsd;
65434941Speter	caddr_t sg;
65534941Speter
65634941Speter	sg = stackgap_init();
65734941Speter	CHECKALTEXIST(p, &sg, args->path);
65834941Speter
65934941Speter#ifdef DEBUG
66034941Speter        printf("Linux-emul(%d): lchown(%s, %d, %d)\n",
66134941Speter	    p->p_pid, args->path, args->uid, args->gid);
66234941Speter#endif
66334941Speter	bsd.path = args->path;
66434941Speter	/* XXX size casts here */
66534941Speter	bsd.uid = args->uid;
66634941Speter	bsd.gid = args->gid;
66734941Speter
66834941Speter	return lchown(p, &bsd);
66934941Speter}
67034941Speter
67134941Speterint
67230994Sphklinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
67314331Speter{
67414331Speter	struct mkdir_args bsd;
67514331Speter	caddr_t sg;
67614331Speter
67714331Speter	sg = stackgap_init();
67814331Speter	CHECKALTCREAT(p, &sg, args->path);
67914331Speter
68014331Speter#ifdef DEBUG
68114331Speter        printf("Linux-emul(%d): mkdir(%s, %d)\n",
68214331Speter	    p->p_pid, args->path, args->mode);
68314331Speter#endif
68414331Speter	bsd.path = args->path;
68514331Speter	bsd.mode = args->mode;
68614331Speter
68730994Sphk	return mkdir(p, &bsd);
68814331Speter}
68914331Speter
69014331Speterint
69130994Sphklinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
69214331Speter{
69314331Speter	struct rmdir_args bsd;
69414331Speter	caddr_t sg;
69514331Speter
69614331Speter	sg = stackgap_init();
69714331Speter	CHECKALTEXIST(p, &sg, args->path);
69814331Speter
69914331Speter#ifdef DEBUG
70014331Speter        printf("Linux-emul(%d): rmdir(%s)\n",
70114331Speter	    p->p_pid, args->path);
70214331Speter#endif
70314331Speter	bsd.path = args->path;
70414331Speter
70530994Sphk	return rmdir(p, &bsd);
70614331Speter}
70714331Speter
70814331Speterint
70930994Sphklinux_rename(struct proc *p, struct linux_rename_args *args)
71014331Speter{
71114331Speter	struct rename_args bsd;
71214331Speter	caddr_t sg;
71314331Speter
71414331Speter	sg = stackgap_init();
71514331Speter	CHECKALTEXIST(p, &sg, args->from);
71614331Speter	CHECKALTCREAT(p, &sg, args->to);
71714331Speter
71814331Speter#ifdef DEBUG
71914331Speter        printf("Linux-emul(%d): rename(%s, %s)\n",
72014331Speter	    p->p_pid, args->from, args->to);
72114331Speter#endif
72214331Speter	bsd.from = args->from;
72314331Speter	bsd.to = args->to;
72414331Speter
72530994Sphk	return rename(p, &bsd);
72614331Speter}
72714331Speter
72814331Speterint
72930994Sphklinux_symlink(struct proc *p, struct linux_symlink_args *args)
73014331Speter{
73114331Speter	struct symlink_args bsd;
73214331Speter	caddr_t sg;
73314331Speter
73414331Speter	sg = stackgap_init();
73514331Speter	CHECKALTEXIST(p, &sg, args->path);
73614331Speter	CHECKALTCREAT(p, &sg, args->to);
73714331Speter
73814331Speter#ifdef DEBUG
73914331Speter        printf("Linux-emul(%d): symlink(%s, %s)\n",
74014331Speter	    p->p_pid, args->path, args->to);
74114331Speter#endif
74214331Speter	bsd.path = args->path;
74314331Speter	bsd.link = args->to;
74414331Speter
74530994Sphk	return symlink(p, &bsd);
74614331Speter}
74714331Speter
74814331Speterint
74930994Sphklinux_readlink(struct proc *p, struct linux_readlink_args *args)
75014331Speter{
75114331Speter	struct readlink_args bsd;
75214331Speter	caddr_t sg;
75314331Speter
75414331Speter	sg = stackgap_init();
75514331Speter	CHECKALTEXIST(p, &sg, args->name);
75614331Speter
75714331Speter#ifdef DEBUG
75837950Sbde        printf("Linux-emul(%ld): readlink(%s, %p, %d)\n",
75937950Sbde	    (long)p->p_pid, args->name, (void *)args->buf, args->count);
76014331Speter#endif
76114331Speter	bsd.path = args->name;
76214331Speter	bsd.buf = args->buf;
76314331Speter	bsd.count = args->count;
76414331Speter
76530994Sphk	return readlink(p, &bsd);
76614331Speter}
76714331Speter
76814331Speterint
76930994Sphklinux_truncate(struct proc *p, struct linux_truncate_args *args)
77014331Speter{
77142499Seivind	struct truncate_args bsd;
77214331Speter	caddr_t sg;
77314331Speter
77414331Speter	sg = stackgap_init();
77514331Speter	CHECKALTEXIST(p, &sg, args->path);
77614331Speter
77714331Speter#ifdef DEBUG
77832266Sjmb        printf("Linux-emul(%d): truncate(%s, %ld)\n",
77932266Sjmb	    p->p_pid, args->path, args->length);
78014331Speter#endif
78114331Speter	bsd.path = args->path;
78232265Sjmb	bsd.length = args->length;
78314331Speter
78442499Seivind	return truncate(p, &bsd);
78514331Speter}
78614331Speter
78749662Smarcelint
78849662Smarcellinux_link(struct proc *p, struct linux_link_args *args)
78949662Smarcel{
79049662Smarcel    struct link_args bsd;
79149662Smarcel    caddr_t sg;
79249662Smarcel
79349662Smarcel    sg = stackgap_init();
79449662Smarcel    CHECKALTEXIST(p, &sg, args->path);
79549662Smarcel    CHECKALTCREAT(p, &sg, args->to);
79649662Smarcel
79749662Smarcel#ifdef DEBUG
79849662Smarcel    printf("Linux-emul(%d): link(%s, %s)\n", p->p_pid, args->path, args->to);
79949662Smarcel#endif
80049662Smarcel
80149662Smarcel    bsd.path = args->path;
80249662Smarcel    bsd.link = args->to;
80349662Smarcel
80449662Smarcel    return link(p, &bsd);
80549662Smarcel}
80649788Smarcel
80749788Smarcelint
80849788Smarcellinux_getcwd(struct proc *p, struct linux_getcwd_args *args)
80949788Smarcel{
81051348Smarcel	struct __getcwd_args bsd;
81151348Smarcel	caddr_t sg;
81251348Smarcel	int error, len;
81349788Smarcel
81449788Smarcel#ifdef DEBUG
81551348Smarcel	printf("Linux-emul(%ld): getcwd(%p, %ld)\n", (long)p->p_pid,
81651348Smarcel	       args->buf, args->bufsize);
81749788Smarcel#endif
81849788Smarcel
81951348Smarcel	sg = stackgap_init();
82051348Smarcel	bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE);
82151348Smarcel	bsd.buflen = SPARE_USRSPACE;
82251348Smarcel	error = __getcwd(p, &bsd);
82351348Smarcel	if (!error) {
82451348Smarcel		len = strlen(bsd.buf) + 1;
82551348Smarcel		if (len <= args->bufsize) {
82651348Smarcel			p->p_retval[0] = len;
82751348Smarcel			error = copyout(bsd.buf, args->buf, len);
82851348Smarcel		}
82951348Smarcel		else
83051348Smarcel			error = ERANGE;
83151348Smarcel	}
83251348Smarcel	return (error);
83349788Smarcel}
83453713Smarcel
83568201Sobrien#ifndef __alpha__
83653713Smarcelint
83753713Smarcellinux_fdatasync(p, uap)
83853713Smarcel	struct proc *p;
83953713Smarcel	struct linux_fdatasync_args *uap;
84053713Smarcel{
84153713Smarcel	struct fsync_args bsd;
84253713Smarcel
84353713Smarcel	bsd.fd = uap->fd;
84453713Smarcel	return fsync(p, &bsd);
84553713Smarcel}
84668201Sobrien#endif /*!__alpha__*/
84763285Smarcel
84863285Smarcelint
84963285Smarcellinux_pread(p, uap)
85063285Smarcel	struct proc *p;
85163285Smarcel	struct linux_pread_args *uap;
85263285Smarcel{
85363285Smarcel	struct pread_args bsd;
85463285Smarcel
85563285Smarcel	bsd.fd = uap->fd;
85663285Smarcel	bsd.buf = uap->buf;
85763285Smarcel	bsd.nbyte = uap->nbyte;
85863285Smarcel	bsd.offset = uap->offset;
85963285Smarcel	return pread(p, &bsd);
86063285Smarcel}
86163285Smarcel
86263285Smarcelint
86363285Smarcellinux_pwrite(p, uap)
86463285Smarcel	struct proc *p;
86563285Smarcel	struct linux_pwrite_args *uap;
86663285Smarcel{
86763285Smarcel	struct pwrite_args bsd;
86863285Smarcel
86963285Smarcel	bsd.fd = uap->fd;
87063285Smarcel	bsd.buf = uap->buf;
87163285Smarcel	bsd.nbyte = uap->nbyte;
87263285Smarcel	bsd.offset = uap->offset;
87363285Smarcel	return pwrite(p, &bsd);
87463285Smarcel}
875