linux_file.c revision 49662
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 *
2849662Smarcel *  $Id: linux_file.c,v 1.27 1999/07/18 14:31:01 phk Exp $
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
4712458Sbde#include <i386/linux/linux.h>
4814331Speter#include <i386/linux/linux_proto.h>
4914331Speter#include <i386/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)
1319313Ssos	    (fp->f_ops->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;
1619313Ssos    }
1629313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1639313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1649313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1659313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1669313Ssos}
1679313Ssos
1689313Ssosstatic void
1699313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1709313Ssos{
1719313Ssos    switch (bsd_flock->l_type) {
1729313Ssos    case F_RDLCK:
1739313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1749313Ssos	break;
1759313Ssos    case F_WRLCK:
1769313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1779313Ssos	break;
1789313Ssos    case F_UNLCK:
1799313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1809313Ssos	break;
1819313Ssos    }
1829313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1839313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1849313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
1859313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
1869313Ssos}
1879313Ssos
1889313Ssosint
18930994Sphklinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
1909313Ssos{
1919313Ssos    int error, result;
19212858Speter    struct fcntl_args /* {
1939313Ssos	int fd;
1949313Ssos	int cmd;
1959313Ssos	int arg;
19612858Speter    } */ fcntl_args;
1979313Ssos    struct linux_flock linux_flock;
19814331Speter    struct flock *bsd_flock;
19914331Speter    struct filedesc *fdp;
20014331Speter    struct file *fp;
20114331Speter    struct vnode *vp;
20214331Speter    long pgid;
20314331Speter    struct pgrp *pgrp;
20414331Speter    struct tty *tp, *(*d_tty) __P((dev_t));
20514331Speter    caddr_t sg;
20647028Sphk    dev_t dev;
2079313Ssos
20814331Speter    sg = stackgap_init();
20914331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
21014331Speter    d_tty = NULL;
21114331Speter
2129313Ssos#ifdef DEBUG
2139313Ssos    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
2149313Ssos	   p->p_pid, args->fd, args->cmd);
2159313Ssos#endif
2169313Ssos    fcntl_args.fd = args->fd;
2179313Ssos    fcntl_args.arg = 0;
2189313Ssos
2199313Ssos    switch (args->cmd) {
2209313Ssos    case LINUX_F_DUPFD:
2219313Ssos	fcntl_args.cmd = F_DUPFD;
22230994Sphk	return fcntl(p, &fcntl_args);
2239313Ssos
2249313Ssos    case LINUX_F_GETFD:
2259313Ssos	fcntl_args.cmd = F_GETFD;
22630994Sphk	return fcntl(p, &fcntl_args);
2279313Ssos
2289313Ssos    case LINUX_F_SETFD:
2299313Ssos	fcntl_args.cmd = F_SETFD;
23030994Sphk	return fcntl(p, &fcntl_args);
2319313Ssos
2329313Ssos    case LINUX_F_GETFL:
2339313Ssos	fcntl_args.cmd = F_GETFL;
23430994Sphk	error = fcntl(p, &fcntl_args);
23530994Sphk	result = p->p_retval[0];
23630994Sphk	p->p_retval[0] = 0;
23730994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
23830994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
23930994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
24030994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
24130994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
24230994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
24339978Sjfieber	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
2449313Ssos	return error;
2459313Ssos
2469313Ssos    case LINUX_F_SETFL:
2479313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2489313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2499313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
25039978Sjfieber	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
2519313Ssos	fcntl_args.cmd = F_SETFL;
25230994Sphk	return fcntl(p, &fcntl_args);
2539313Ssos
2549313Ssos    case LINUX_F_GETLK:
2559313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2569313Ssos		   	    sizeof(struct linux_flock))))
2579313Ssos	    return error;
2589313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2599313Ssos	fcntl_args.cmd = F_GETLK;
2609313Ssos	fcntl_args.arg = (int)bsd_flock;
26146571Speter	error = fcntl(p, &fcntl_args);
26246571Speter	if (error)
2639313Ssos	    return error;
2649313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2659313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2669313Ssos		       sizeof(struct linux_flock));
2679313Ssos
2689313Ssos    case LINUX_F_SETLK:
2699313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2709313Ssos		   	    sizeof(struct linux_flock))))
2719313Ssos	    return error;
2729313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2739313Ssos	fcntl_args.cmd = F_SETLK;
2749313Ssos	fcntl_args.arg = (int)bsd_flock;
27530994Sphk	return fcntl(p, &fcntl_args);
2769313Ssos
2779313Ssos    case LINUX_F_SETLKW:
2789313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2799313Ssos		   	    sizeof(struct linux_flock))))
2809313Ssos	    return error;
2819313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2829313Ssos	fcntl_args.cmd = F_SETLKW;
2839313Ssos	fcntl_args.arg = (int)bsd_flock;
28430994Sphk	return fcntl(p, &fcntl_args);
2859313Ssos
2869313Ssos    case LINUX_F_SETOWN:
28714331Speter    case LINUX_F_GETOWN:
28814331Speter	/*
28914331Speter	 * We need to route around the normal fcntl() for these calls,
29014331Speter	 * since it uses TIOC{G,S}PGRP, which is too restrictive for
29114331Speter	 * Linux F_{G,S}ETOWN semantics. For sockets, this problem
29214331Speter	 * does not exist.
29314331Speter	 */
29414331Speter	fdp = p->p_fd;
29514331Speter	if ((u_int)args->fd >= fdp->fd_nfiles ||
29614331Speter		(fp = fdp->fd_ofiles[args->fd]) == NULL)
29714331Speter	    return EBADF;
29814331Speter	if (fp->f_type == DTYPE_SOCKET) {
29914331Speter	    fcntl_args.cmd = args->cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
30039978Sjfieber    	    fcntl_args.arg = args->arg;
30130994Sphk	    return fcntl(p, &fcntl_args);
30214331Speter	}
30314331Speter	vp = (struct vnode *)fp->f_data;
30448885Sphk	dev = vn_todev(vp);
30548885Sphk	if (vp->v_type != VCHR || dev == NODEV)
30614331Speter	    return EINVAL;
30747028Sphk	d_tty = devsw(dev)->d_devtotty;
30847028Sphk	if (!d_tty || (!(tp = (*d_tty)(dev))))
30914331Speter	    return EINVAL;
31014331Speter	if (args->cmd == LINUX_F_GETOWN) {
31130994Sphk	    p->p_retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
31214331Speter	    return 0;
31314331Speter	}
31414331Speter	if ((long)args->arg <= 0) {
31514331Speter	    pgid = -(long)args->arg;
31614331Speter	} else {
31714331Speter	    struct proc *p1 = pfind((long)args->arg);
31814331Speter	    if (p1 == 0)
31914331Speter		return (ESRCH);
32014331Speter	    pgid = (long)p1->p_pgrp->pg_id;
32114331Speter	}
32214331Speter	pgrp = pgfind(pgid);
32314331Speter	if (pgrp == NULL || pgrp->pg_session != p->p_session)
32414331Speter	    return EPERM;
32514331Speter	tp->t_pgrp = pgrp;
32614331Speter	return 0;
3279313Ssos    }
3289313Ssos    return EINVAL;
3299313Ssos}
3309313Ssos
3319313Ssosint
33230994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
3339313Ssos{
3349313Ssos
33512858Speter    struct lseek_args /* {
33612858Speter	int fd;
3379313Ssos	int pad;
33812858Speter	off_t offset;
3399313Ssos	int whence;
34012858Speter    } */ tmp_args;
3419313Ssos    int error;
3429313Ssos
3439313Ssos#ifdef DEBUG
34437950Sbde    printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n",
34537950Sbde	   (long)p->p_pid, args->fdes, args->off, args->whence);
3469313Ssos#endif
34712858Speter    tmp_args.fd = args->fdes;
34812858Speter    tmp_args.offset = (off_t)args->off;
3499313Ssos    tmp_args.whence = args->whence;
35030994Sphk    error = lseek(p, &tmp_args);
3519313Ssos    return error;
3529313Ssos}
3539313Ssos
35414331Speterint
35530994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
35614331Speter{
35714331Speter	struct lseek_args bsd_args;
35814331Speter	int error;
35914331Speter	off_t off;
36014331Speter
36114331Speter#ifdef DEBUG
36214331Speter        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
36314331Speter	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
36414331Speter#endif
36514331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
36614331Speter
36714331Speter	bsd_args.fd = args->fd;
36814331Speter	bsd_args.offset = off;
36914331Speter	bsd_args.whence = args->whence;
37014331Speter
37130994Sphk	if ((error = lseek(p, &bsd_args)))
37214331Speter		return error;
37314331Speter
37430994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
37514331Speter		return error;
37614331Speter
37730994Sphk	p->p_retval[0] = 0;
37814331Speter	return 0;
37914331Speter}
38014331Speter
38114331Speter
3829313Ssosstruct linux_dirent {
3839313Ssos    long dino;
3849313Ssos    linux_off_t doff;
3859313Ssos    unsigned short dreclen;
3869313Ssos    char dname[LINUX_NAME_MAX + 1];
3879313Ssos};
3889313Ssos
3899313Ssos#define LINUX_RECLEN(de,namlen) \
3909313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3919313Ssos
3929313Ssosint
39330994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3949313Ssos{
39514331Speter	struct linux_getdents_args lda;
39614331Speter
39714331Speter	lda.fd = args->fd;
39814331Speter	lda.dent = args->dent;
39914331Speter	lda.count = 1;
40030994Sphk	return linux_getdents(p, &lda);
40114331Speter}
40214331Speter
40314331Speterint
40430994Sphklinux_getdents(struct proc *p, struct linux_getdents_args *args)
40514331Speter{
4069313Ssos    register struct dirent *bdp;
4079313Ssos    struct vnode *vp;
4089313Ssos    caddr_t inp, buf;		/* BSD-format */
4099313Ssos    int len, reclen;		/* BSD-format */
4109313Ssos    caddr_t outp;		/* Linux-format */
4119313Ssos    int resid, linuxreclen=0;	/* Linux-format */
4129313Ssos    struct file *fp;
4139313Ssos    struct uio auio;
4149313Ssos    struct iovec aiov;
4159313Ssos    struct vattr va;
4169313Ssos    off_t off;
4179313Ssos    struct linux_dirent linux_dirent;
41824654Sdfr    int buflen, error, eofflag, nbytes, justone;
41924654Sdfr    u_long *cookies = NULL, *cookiep;
42024654Sdfr    int ncookies;
4219313Ssos
4229313Ssos#ifdef DEBUG
42314331Speter    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
4249313Ssos	   p->p_pid, args->fd, args->count);
4259313Ssos#endif
42610355Sswallace    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
4279313Ssos	return (error);
42814331Speter    }
4299313Ssos
4309313Ssos    if ((fp->f_flag & FREAD) == 0)
4319313Ssos	return (EBADF);
4329313Ssos
4339313Ssos    vp = (struct vnode *) fp->f_data;
4349313Ssos
4359313Ssos    if (vp->v_type != VDIR)
4369313Ssos	return (EINVAL);
4379313Ssos
43810355Sswallace    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
4399313Ssos	return error;
44011418Sswallace    }
4419313Ssos
4429313Ssos    nbytes = args->count;
4439313Ssos    if (nbytes == 1) {
4449313Ssos	nbytes = sizeof (struct linux_dirent);
4459313Ssos	justone = 1;
4469313Ssos    }
4479313Ssos    else
4489313Ssos	justone = 0;
4499313Ssos
45010355Sswallace    off = fp->f_offset;
45124672Sdfr#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
45224654Sdfr    buflen = max(DIRBLKSIZ, nbytes);
45311418Sswallace    buflen = min(buflen, MAXBSIZE);
4549313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
45522521Sdyson    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4569313Ssosagain:
4579313Ssos    aiov.iov_base = buf;
4589313Ssos    aiov.iov_len = buflen;
4599313Ssos    auio.uio_iov = &aiov;
4609313Ssos    auio.uio_iovcnt = 1;
4619313Ssos    auio.uio_rw = UIO_READ;
4629313Ssos    auio.uio_segflg = UIO_SYSSPACE;
4639313Ssos    auio.uio_procp = p;
4649313Ssos    auio.uio_resid = buflen;
46524654Sdfr    auio.uio_offset = off;
4669313Ssos
46724654Sdfr    if (cookies) {
46824654Sdfr	free(cookies, M_TEMP);
46924654Sdfr	cookies = NULL;
47024654Sdfr    }
47124654Sdfr
47224654Sdfr    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
47310355Sswallace    if (error) {
4749313Ssos	goto out;
47514331Speter    }
4769313Ssos
4779313Ssos    inp = buf;
4789313Ssos    outp = (caddr_t) args->dent;
4799313Ssos    resid = nbytes;
48024654Sdfr    if ((len = buflen - auio.uio_resid) <= 0) {
4819313Ssos	goto eof;
48214331Speter    }
4839313Ssos
48424654Sdfr    cookiep = cookies;
48524654Sdfr
48624654Sdfr    if (cookies) {
48724654Sdfr	/*
48824654Sdfr	 * When using cookies, the vfs has the option of reading from
48924654Sdfr	 * a different offset than that supplied (UFS truncates the
49024654Sdfr	 * offset to a block boundary to make sure that it never reads
49124654Sdfr	 * partway through a directory entry, even if the directory
49224654Sdfr	 * has been compacted).
49324654Sdfr	 */
49424654Sdfr	while (len > 0 && ncookies > 0 && *cookiep <= off) {
49524654Sdfr	    bdp = (struct dirent *) inp;
49624654Sdfr	    len -= bdp->d_reclen;
49724654Sdfr	    inp += bdp->d_reclen;
49824654Sdfr	    cookiep++;
49924654Sdfr	    ncookies--;
50024654Sdfr	}
50124654Sdfr    }
50224654Sdfr
5039313Ssos    while (len > 0) {
50424654Sdfr	if (cookiep && ncookies == 0)
50524654Sdfr	    break;
50610355Sswallace	bdp = (struct dirent *) inp;
50710355Sswallace	reclen = bdp->d_reclen;
50810355Sswallace	if (reclen & 3) {
50910355Sswallace	    printf("linux_readdir: reclen=%d\n", reclen);
51010355Sswallace	    error = EFAULT;
51110355Sswallace	    goto out;
51210355Sswallace	}
51310355Sswallace
5149313Ssos	if (bdp->d_fileno == 0) {
5159313Ssos	    inp += reclen;
51624654Sdfr	    if (cookiep) {
51724654Sdfr		off = *cookiep++;
51824654Sdfr		ncookies--;
51924654Sdfr	    } else
52024654Sdfr		off += reclen;
52110355Sswallace	    len -= reclen;
5229313Ssos	    continue;
5239313Ssos	}
5249313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
5259313Ssos	if (reclen > len || resid < linuxreclen) {
5269313Ssos	    outp++;
5279313Ssos	    break;
5289313Ssos	}
5299313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
53014465Speter	if (justone) {
53114465Speter	    /*
53214465Speter	     * old linux-style readdir usage.
53314465Speter	     */
53414465Speter	    linux_dirent.doff = (linux_off_t) linuxreclen;
53514465Speter	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
53614465Speter	} else {
53714465Speter	    linux_dirent.doff = (linux_off_t) off;
53814465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
53914465Speter	}
5409313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
54110355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5429313Ssos	    goto out;
54314331Speter	}
5449313Ssos	inp += reclen;
54524654Sdfr	if (cookiep) {
54624654Sdfr	    off = *cookiep++;
54724654Sdfr	    ncookies--;
54824654Sdfr	} else
54924654Sdfr	    off += reclen;
5509313Ssos	outp += linuxreclen;
5519313Ssos	resid -= linuxreclen;
5529313Ssos	len -= reclen;
5539313Ssos	if (justone)
5549313Ssos	    break;
5559313Ssos    }
5569313Ssos
5579313Ssos    if (outp == (caddr_t) args->dent)
5589313Ssos	goto again;
5599313Ssos    fp->f_offset = off;
5609313Ssos
5619313Ssos    if (justone)
5629313Ssos	nbytes = resid + linuxreclen;
56310355Sswallace
5649313Ssoseof:
56530994Sphk    p->p_retval[0] = nbytes - resid;
5669313Ssosout:
56724654Sdfr    if (cookies)
56824654Sdfr	free(cookies, M_TEMP);
56922543Smpp    VOP_UNLOCK(vp, 0, p);
5709313Ssos    free(buf, M_TEMP);
5719313Ssos    return error;
5729313Ssos}
57314331Speter
57414331Speter/*
57514331Speter * These exist mainly for hooks for doing /compat/linux translation.
57614331Speter */
57714331Speter
57814331Speterint
57930994Sphklinux_access(struct proc *p, struct linux_access_args *args)
58014331Speter{
58114331Speter	struct access_args bsd;
58214331Speter	caddr_t sg;
58314331Speter
58414331Speter	sg = stackgap_init();
58514331Speter	CHECKALTEXIST(p, &sg, args->path);
58614331Speter
58714331Speter#ifdef DEBUG
58814331Speter        printf("Linux-emul(%d): access(%s, %d)\n",
58914331Speter	    p->p_pid, args->path, args->flags);
59014331Speter#endif
59114331Speter	bsd.path = args->path;
59214331Speter	bsd.flags = args->flags;
59314331Speter
59430994Sphk	return access(p, &bsd);
59514331Speter}
59614331Speter
59714331Speterint
59830994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
59914331Speter{
60014331Speter	struct unlink_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): unlink(%s)\n",
60814331Speter	   p->p_pid, args->path);
60914331Speter#endif
61014331Speter	bsd.path = args->path;
61114331Speter
61230994Sphk	return unlink(p, &bsd);
61314331Speter}
61414331Speter
61514331Speterint
61630994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
61714331Speter{
61814331Speter	struct chdir_args bsd;
61914331Speter	caddr_t sg;
62014331Speter
62114331Speter	sg = stackgap_init();
62214331Speter	CHECKALTEXIST(p, &sg, args->path);
62314331Speter
62414331Speter#ifdef DEBUG
62514331Speter	printf("Linux-emul(%d): chdir(%s)\n",
62614331Speter	   p->p_pid, args->path);
62714331Speter#endif
62814331Speter	bsd.path = args->path;
62914331Speter
63030994Sphk	return chdir(p, &bsd);
63114331Speter}
63214331Speter
63314331Speterint
63430994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
63514331Speter{
63614331Speter	struct chmod_args bsd;
63714331Speter	caddr_t sg;
63814331Speter
63914331Speter	sg = stackgap_init();
64014331Speter	CHECKALTEXIST(p, &sg, args->path);
64114331Speter
64214331Speter#ifdef DEBUG
64314331Speter        printf("Linux-emul(%d): chmod(%s, %d)\n",
64414331Speter	    p->p_pid, args->path, args->mode);
64514331Speter#endif
64614331Speter	bsd.path = args->path;
64714331Speter	bsd.mode = args->mode;
64814331Speter
64930994Sphk	return chmod(p, &bsd);
65014331Speter}
65114331Speter
65214331Speterint
65330994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
65414331Speter{
65514331Speter	struct chown_args bsd;
65614331Speter	caddr_t sg;
65714331Speter
65814331Speter	sg = stackgap_init();
65914331Speter	CHECKALTEXIST(p, &sg, args->path);
66014331Speter
66114331Speter#ifdef DEBUG
66214331Speter        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
66314331Speter	    p->p_pid, args->path, args->uid, args->gid);
66414331Speter#endif
66514331Speter	bsd.path = args->path;
66614331Speter	/* XXX size casts here */
66714331Speter	bsd.uid = args->uid;
66814331Speter	bsd.gid = args->gid;
66914331Speter
67030994Sphk	return chown(p, &bsd);
67114331Speter}
67214331Speter
67314331Speterint
67434941Speterlinux_lchown(struct proc *p, struct linux_lchown_args *args)
67534941Speter{
67634941Speter	struct lchown_args bsd;
67734941Speter	caddr_t sg;
67834941Speter
67934941Speter	sg = stackgap_init();
68034941Speter	CHECKALTEXIST(p, &sg, args->path);
68134941Speter
68234941Speter#ifdef DEBUG
68334941Speter        printf("Linux-emul(%d): lchown(%s, %d, %d)\n",
68434941Speter	    p->p_pid, args->path, args->uid, args->gid);
68534941Speter#endif
68634941Speter	bsd.path = args->path;
68734941Speter	/* XXX size casts here */
68834941Speter	bsd.uid = args->uid;
68934941Speter	bsd.gid = args->gid;
69034941Speter
69134941Speter	return lchown(p, &bsd);
69234941Speter}
69334941Speter
69434941Speterint
69530994Sphklinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
69614331Speter{
69714331Speter	struct mkdir_args bsd;
69814331Speter	caddr_t sg;
69914331Speter
70014331Speter	sg = stackgap_init();
70114331Speter	CHECKALTCREAT(p, &sg, args->path);
70214331Speter
70314331Speter#ifdef DEBUG
70414331Speter        printf("Linux-emul(%d): mkdir(%s, %d)\n",
70514331Speter	    p->p_pid, args->path, args->mode);
70614331Speter#endif
70714331Speter	bsd.path = args->path;
70814331Speter	bsd.mode = args->mode;
70914331Speter
71030994Sphk	return mkdir(p, &bsd);
71114331Speter}
71214331Speter
71314331Speterint
71430994Sphklinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
71514331Speter{
71614331Speter	struct rmdir_args bsd;
71714331Speter	caddr_t sg;
71814331Speter
71914331Speter	sg = stackgap_init();
72014331Speter	CHECKALTEXIST(p, &sg, args->path);
72114331Speter
72214331Speter#ifdef DEBUG
72314331Speter        printf("Linux-emul(%d): rmdir(%s)\n",
72414331Speter	    p->p_pid, args->path);
72514331Speter#endif
72614331Speter	bsd.path = args->path;
72714331Speter
72830994Sphk	return rmdir(p, &bsd);
72914331Speter}
73014331Speter
73114331Speterint
73230994Sphklinux_rename(struct proc *p, struct linux_rename_args *args)
73314331Speter{
73414331Speter	struct rename_args bsd;
73514331Speter	caddr_t sg;
73614331Speter
73714331Speter	sg = stackgap_init();
73814331Speter	CHECKALTEXIST(p, &sg, args->from);
73914331Speter	CHECKALTCREAT(p, &sg, args->to);
74014331Speter
74114331Speter#ifdef DEBUG
74214331Speter        printf("Linux-emul(%d): rename(%s, %s)\n",
74314331Speter	    p->p_pid, args->from, args->to);
74414331Speter#endif
74514331Speter	bsd.from = args->from;
74614331Speter	bsd.to = args->to;
74714331Speter
74830994Sphk	return rename(p, &bsd);
74914331Speter}
75014331Speter
75114331Speterint
75230994Sphklinux_symlink(struct proc *p, struct linux_symlink_args *args)
75314331Speter{
75414331Speter	struct symlink_args bsd;
75514331Speter	caddr_t sg;
75614331Speter
75714331Speter	sg = stackgap_init();
75814331Speter	CHECKALTEXIST(p, &sg, args->path);
75914331Speter	CHECKALTCREAT(p, &sg, args->to);
76014331Speter
76114331Speter#ifdef DEBUG
76214331Speter        printf("Linux-emul(%d): symlink(%s, %s)\n",
76314331Speter	    p->p_pid, args->path, args->to);
76414331Speter#endif
76514331Speter	bsd.path = args->path;
76614331Speter	bsd.link = args->to;
76714331Speter
76830994Sphk	return symlink(p, &bsd);
76914331Speter}
77014331Speter
77114331Speterint
77230994Sphklinux_execve(struct proc *p, struct linux_execve_args *args)
77314331Speter{
77414331Speter	struct execve_args bsd;
77514331Speter	caddr_t sg;
77614331Speter
77714331Speter	sg = stackgap_init();
77814331Speter	CHECKALTEXIST(p, &sg, args->path);
77914331Speter
78014331Speter#ifdef DEBUG
78114331Speter        printf("Linux-emul(%d): execve(%s)\n",
78214331Speter	    p->p_pid, args->path);
78314331Speter#endif
78414331Speter	bsd.fname = args->path;
78514331Speter	bsd.argv = args->argp;
78614331Speter	bsd.envv = args->envp;
78714331Speter
78830994Sphk	return execve(p, &bsd);
78914331Speter}
79014331Speter
79114331Speterint
79230994Sphklinux_readlink(struct proc *p, struct linux_readlink_args *args)
79314331Speter{
79414331Speter	struct readlink_args bsd;
79514331Speter	caddr_t sg;
79614331Speter
79714331Speter	sg = stackgap_init();
79814331Speter	CHECKALTEXIST(p, &sg, args->name);
79914331Speter
80014331Speter#ifdef DEBUG
80137950Sbde        printf("Linux-emul(%ld): readlink(%s, %p, %d)\n",
80237950Sbde	    (long)p->p_pid, args->name, (void *)args->buf, args->count);
80314331Speter#endif
80414331Speter	bsd.path = args->name;
80514331Speter	bsd.buf = args->buf;
80614331Speter	bsd.count = args->count;
80714331Speter
80830994Sphk	return readlink(p, &bsd);
80914331Speter}
81014331Speter
81114331Speterint
81230994Sphklinux_truncate(struct proc *p, struct linux_truncate_args *args)
81314331Speter{
81442499Seivind	struct truncate_args bsd;
81514331Speter	caddr_t sg;
81614331Speter
81714331Speter	sg = stackgap_init();
81814331Speter	CHECKALTEXIST(p, &sg, args->path);
81914331Speter
82014331Speter#ifdef DEBUG
82132266Sjmb        printf("Linux-emul(%d): truncate(%s, %ld)\n",
82232266Sjmb	    p->p_pid, args->path, args->length);
82314331Speter#endif
82414331Speter	bsd.path = args->path;
82532265Sjmb	bsd.length = args->length;
82614331Speter
82742499Seivind	return truncate(p, &bsd);
82814331Speter}
82914331Speter
83049662Smarcelint
83149662Smarcellinux_link(struct proc *p, struct linux_link_args *args)
83249662Smarcel{
83349662Smarcel    struct link_args bsd;
83449662Smarcel    caddr_t sg;
83549662Smarcel
83649662Smarcel    sg = stackgap_init();
83749662Smarcel    CHECKALTEXIST(p, &sg, args->path);
83849662Smarcel    CHECKALTCREAT(p, &sg, args->to);
83949662Smarcel
84049662Smarcel#ifdef DEBUG
84149662Smarcel    printf("Linux-emul(%d): link(%s, %s)\n", p->p_pid, args->path, args->to);
84249662Smarcel#endif
84349662Smarcel
84449662Smarcel    bsd.path = args->path;
84549662Smarcel    bsd.link = args->to;
84649662Smarcel
84749662Smarcel    return link(p, &bsd);
84849662Smarcel}
849