linux_file.c revision 72543
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 72543 2001-02-16 16:40:43Z jlemon $
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>
4372538Sjlemon#include <sys/mount.h>
449313Ssos#include <sys/dirent.h>
4514331Speter#include <sys/conf.h>
4614331Speter#include <sys/tty.h>
4712458Sbde
4872538Sjlemon#include <ufs/ufs/extattr.h>
4972538Sjlemon#include <ufs/ufs/quota.h>
5072538Sjlemon#include <ufs/ufs/ufsmount.h>
5172538Sjlemon
5264905Smarcel#include <machine/../linux/linux.h>
5368583Smarcel#include <machine/../linux/linux_proto.h>
5464905Smarcel#include <compat/linux/linux_util.h>
559313Ssos
5668201Sobrien#ifndef __alpha__
579313Ssosint
5830994Sphklinux_creat(struct proc *p, struct linux_creat_args *args)
599313Ssos{
6012858Speter    struct open_args /* {
619313Ssos	char *path;
629313Ssos	int flags;
639313Ssos	int mode;
6412858Speter    } */ bsd_open_args;
6514331Speter    caddr_t sg;
669313Ssos
6714331Speter    sg = stackgap_init();
6814331Speter    CHECKALTCREAT(p, &sg, args->path);
6914331Speter
709313Ssos#ifdef DEBUG
7172543Sjlemon	if (ldebug(creat))
7272543Sjlemon		printf(ARGS(creat, "%s, %d"), args->path, args->mode);
739313Ssos#endif
749313Ssos    bsd_open_args.path = args->path;
759313Ssos    bsd_open_args.mode = args->mode;
769313Ssos    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
7730994Sphk    return open(p, &bsd_open_args);
789313Ssos}
7968201Sobrien#endif /*!__alpha__*/
809313Ssos
819313Ssosint
8230994Sphklinux_open(struct proc *p, struct linux_open_args *args)
839313Ssos{
8412858Speter    struct open_args /* {
859313Ssos	char *path;
869313Ssos	int flags;
879313Ssos	int mode;
8812858Speter    } */ bsd_open_args;
899313Ssos    int error;
9014331Speter    caddr_t sg;
9114331Speter
9214331Speter    sg = stackgap_init();
939313Ssos
9414331Speter    if (args->flags & LINUX_O_CREAT)
9514331Speter	CHECKALTCREAT(p, &sg, args->path);
9614331Speter    else
9714331Speter	CHECKALTEXIST(p, &sg, args->path);
9814331Speter
999313Ssos#ifdef DEBUG
10072543Sjlemon	if (ldebug(open))
10172543Sjlemon		printf(ARGS(open, "%s, 0x%x, 0x%x"),
10272543Sjlemon		    args->path, args->flags, args->mode);
1039313Ssos#endif
1049313Ssos    bsd_open_args.flags = 0;
1059313Ssos    if (args->flags & LINUX_O_RDONLY)
1069313Ssos	bsd_open_args.flags |= O_RDONLY;
1079313Ssos    if (args->flags & LINUX_O_WRONLY)
1089313Ssos	bsd_open_args.flags |= O_WRONLY;
1099313Ssos    if (args->flags & LINUX_O_RDWR)
1109313Ssos	bsd_open_args.flags |= O_RDWR;
1119313Ssos    if (args->flags & LINUX_O_NDELAY)
1129313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1139313Ssos    if (args->flags & LINUX_O_APPEND)
1149313Ssos	bsd_open_args.flags |= O_APPEND;
1159313Ssos    if (args->flags & LINUX_O_SYNC)
1169313Ssos	bsd_open_args.flags |= O_FSYNC;
1179313Ssos    if (args->flags & LINUX_O_NONBLOCK)
1189313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1199313Ssos    if (args->flags & LINUX_FASYNC)
1209313Ssos	bsd_open_args.flags |= O_ASYNC;
1219313Ssos    if (args->flags & LINUX_O_CREAT)
1229313Ssos	bsd_open_args.flags |= O_CREAT;
1239313Ssos    if (args->flags & LINUX_O_TRUNC)
1249313Ssos	bsd_open_args.flags |= O_TRUNC;
1259313Ssos    if (args->flags & LINUX_O_EXCL)
1269313Ssos	bsd_open_args.flags |= O_EXCL;
1279313Ssos    if (args->flags & LINUX_O_NOCTTY)
1289313Ssos	bsd_open_args.flags |= O_NOCTTY;
1299313Ssos    bsd_open_args.path = args->path;
1309313Ssos    bsd_open_args.mode = args->mode;
1319313Ssos
13230994Sphk    error = open(p, &bsd_open_args);
13370061Sjhb    PROC_LOCK(p);
1349313Ssos    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
1359313Ssos	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
1369313Ssos	struct filedesc *fdp = p->p_fd;
13730994Sphk	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
1389313Ssos
13970061Sjhb	PROC_UNLOCK(p);
1409313Ssos	if (fp->f_type == DTYPE_VNODE)
14151418Sgreen	    fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, p);
14270061Sjhb    } else
14370061Sjhb	PROC_UNLOCK(p);
14414331Speter#ifdef DEBUG
14572543Sjlemon	if (ldebug(open))
14672543Sjlemon		printf(LMSG("open returns error %d"), error);
14714331Speter#endif
1489313Ssos    return error;
1499313Ssos}
1509313Ssos
1519313Ssosstruct linux_flock {
1529313Ssos    short l_type;
1539313Ssos    short l_whence;
1549313Ssos    linux_off_t l_start;
1559313Ssos    linux_off_t l_len;
1569313Ssos    linux_pid_t l_pid;
1579313Ssos};
1589313Ssos
1599313Ssosstatic void
1609313Ssoslinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
1619313Ssos{
1629313Ssos    switch (linux_flock->l_type) {
1639313Ssos    case LINUX_F_RDLCK:
1649313Ssos	bsd_flock->l_type = F_RDLCK;
1659313Ssos	break;
1669313Ssos    case LINUX_F_WRLCK:
1679313Ssos	bsd_flock->l_type = F_WRLCK;
1689313Ssos	break;
1699313Ssos    case LINUX_F_UNLCK:
1709313Ssos	bsd_flock->l_type = F_UNLCK;
1719313Ssos	break;
17249676Smarcel    default:
17349676Smarcel        bsd_flock->l_type = -1;
17449676Smarcel        break;
1759313Ssos    }
1769313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1779313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1789313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1799313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1809313Ssos}
1819313Ssos
1829313Ssosstatic void
1839313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1849313Ssos{
1859313Ssos    switch (bsd_flock->l_type) {
1869313Ssos    case F_RDLCK:
1879313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1889313Ssos	break;
1899313Ssos    case F_WRLCK:
1909313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1919313Ssos	break;
1929313Ssos    case F_UNLCK:
1939313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1949313Ssos	break;
1959313Ssos    }
1969313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1979313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1989313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
1999313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
2009313Ssos}
2019313Ssos
2029313Ssosint
20330994Sphklinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
2049313Ssos{
2059313Ssos    int error, result;
20612858Speter    struct fcntl_args /* {
2079313Ssos	int fd;
2089313Ssos	int cmd;
20968662Smarcel	long arg;
21068662Smarcel    } */ fcntl_args;
2119313Ssos    struct linux_flock linux_flock;
21214331Speter    struct flock *bsd_flock;
21368662Smarcel    struct filedesc *fdp;
21468662Smarcel    struct file *fp;
21514331Speter    caddr_t sg;
2169313Ssos
21714331Speter    sg = stackgap_init();
21814331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
21914331Speter
2209313Ssos#ifdef DEBUG
22172543Sjlemon	if (ldebug(fcntl))
22272543Sjlemon		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
2239313Ssos#endif
2249313Ssos    fcntl_args.fd = args->fd;
2259313Ssos
2269313Ssos    switch (args->cmd) {
2279313Ssos    case LINUX_F_DUPFD:
2289313Ssos	fcntl_args.cmd = F_DUPFD;
22949845Smarcel	fcntl_args.arg = args->arg;
23030994Sphk	return fcntl(p, &fcntl_args);
2319313Ssos
2329313Ssos    case LINUX_F_GETFD:
2339313Ssos	fcntl_args.cmd = F_GETFD;
23430994Sphk	return fcntl(p, &fcntl_args);
2359313Ssos
2369313Ssos    case LINUX_F_SETFD:
2379313Ssos	fcntl_args.cmd = F_SETFD;
23849845Smarcel	fcntl_args.arg = args->arg;
23930994Sphk	return fcntl(p, &fcntl_args);
2409313Ssos
2419313Ssos    case LINUX_F_GETFL:
2429313Ssos	fcntl_args.cmd = F_GETFL;
24330994Sphk	error = fcntl(p, &fcntl_args);
24430994Sphk	result = p->p_retval[0];
24530994Sphk	p->p_retval[0] = 0;
24630994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
24730994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
24830994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
24930994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
25030994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
25130994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
25239978Sjfieber	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
2539313Ssos	return error;
2549313Ssos
2559313Ssos    case LINUX_F_SETFL:
25649845Smarcel	fcntl_args.arg = 0;
2579313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2589313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2599313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
26039978Sjfieber	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
2619313Ssos	fcntl_args.cmd = F_SETFL;
26230994Sphk	return fcntl(p, &fcntl_args);
26349676Smarcel
2649313Ssos    case LINUX_F_GETLK:
2659313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2669313Ssos		   	    sizeof(struct linux_flock))))
2679313Ssos	    return error;
2689313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2699313Ssos	fcntl_args.cmd = F_GETLK;
27068201Sobrien	fcntl_args.arg = (long)bsd_flock;
27146571Speter	error = fcntl(p, &fcntl_args);
27246571Speter	if (error)
2739313Ssos	    return error;
2749313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2759313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2769313Ssos		       sizeof(struct linux_flock));
2779313Ssos
2789313Ssos    case LINUX_F_SETLK:
2799313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2809313Ssos		   	    sizeof(struct linux_flock))))
2819313Ssos	    return error;
2829313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2839313Ssos	fcntl_args.cmd = F_SETLK;
28468201Sobrien	fcntl_args.arg = (long)bsd_flock;
28530994Sphk	return fcntl(p, &fcntl_args);
2869313Ssos
2879313Ssos    case LINUX_F_SETLKW:
2889313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2899313Ssos		   	    sizeof(struct linux_flock))))
2909313Ssos	    return error;
2919313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2929313Ssos	fcntl_args.cmd = F_SETLKW;
29368201Sobrien	fcntl_args.arg = (long)bsd_flock;
29430994Sphk	return fcntl(p, &fcntl_args);
2959313Ssos
29663233Smarcel    case LINUX_F_GETOWN:
29763233Smarcel	fcntl_args.cmd = F_GETOWN;
29863233Smarcel	return fcntl(p, &fcntl_args);
29963233Smarcel
3009313Ssos    case LINUX_F_SETOWN:
30168662Smarcel	/*
30268662Smarcel	 * XXX some Linux applications depend on F_SETOWN having no
30368662Smarcel	 * significant effect for pipes (SIGIO is not delivered for
30468662Smarcel	 * pipes under Linux-2.2.35 at least).
30568662Smarcel	 */
30668662Smarcel	fdp = p->p_fd;
30768662Smarcel	if ((u_int)args->fd >= fdp->fd_nfiles ||
30868662Smarcel	  (fp = fdp->fd_ofiles[args->fd]) == NULL)
30968662Smarcel	    return EBADF;
31068662Smarcel	if (fp->f_type == DTYPE_PIPE)
31168662Smarcel	    return EINVAL;
31268662Smarcel
31368662Smarcel 	fcntl_args.cmd = F_SETOWN;
31463233Smarcel	fcntl_args.arg = args->arg;
31563233Smarcel	return fcntl(p, &fcntl_args);
3169313Ssos    }
3179313Ssos    return EINVAL;
3189313Ssos}
3199313Ssos
3209313Ssosint
32130994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
3229313Ssos{
3239313Ssos
32412858Speter    struct lseek_args /* {
32512858Speter	int fd;
3269313Ssos	int pad;
32712858Speter	off_t offset;
3289313Ssos	int whence;
32912858Speter    } */ tmp_args;
3309313Ssos    int error;
3319313Ssos
3329313Ssos#ifdef DEBUG
33372543Sjlemon	if (ldebug(lseek))
33472543Sjlemon		printf(ARGS(lseek, "%d, %ld, %d"),
33572543Sjlemon		    args->fdes, args->off, args->whence);
3369313Ssos#endif
33712858Speter    tmp_args.fd = args->fdes;
33812858Speter    tmp_args.offset = (off_t)args->off;
3399313Ssos    tmp_args.whence = args->whence;
34030994Sphk    error = lseek(p, &tmp_args);
3419313Ssos    return error;
3429313Ssos}
3439313Ssos
34468201Sobrien#ifndef __alpha__
34514331Speterint
34630994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
34714331Speter{
34814331Speter	struct lseek_args bsd_args;
34914331Speter	int error;
35014331Speter	off_t off;
35114331Speter
35214331Speter#ifdef DEBUG
35372543Sjlemon	if (ldebug(llseek))
35472543Sjlemon		printf(ARGS(llseek, "%d, %d:%d, %d"),
35572543Sjlemon		    args->fd, args->ohigh, args->olow, args->whence);
35614331Speter#endif
35714331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
35814331Speter
35914331Speter	bsd_args.fd = args->fd;
36014331Speter	bsd_args.offset = off;
36114331Speter	bsd_args.whence = args->whence;
36214331Speter
36330994Sphk	if ((error = lseek(p, &bsd_args)))
36414331Speter		return error;
36514331Speter
36630994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
36714331Speter		return error;
36814331Speter
36930994Sphk	p->p_retval[0] = 0;
37014331Speter	return 0;
37114331Speter}
37268201Sobrien#endif /*!__alpha__*/
37314331Speter
37414331Speter
3759313Ssosstruct linux_dirent {
3769313Ssos    long dino;
3779313Ssos    linux_off_t doff;
3789313Ssos    unsigned short dreclen;
3799313Ssos    char dname[LINUX_NAME_MAX + 1];
3809313Ssos};
3819313Ssos
3829313Ssos#define LINUX_RECLEN(de,namlen) \
3839313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3849313Ssos
38568201Sobrien#ifndef __alpha__
3869313Ssosint
38730994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3889313Ssos{
38914331Speter	struct linux_getdents_args lda;
39014331Speter
39114331Speter	lda.fd = args->fd;
39214331Speter	lda.dent = args->dent;
39314331Speter	lda.count = 1;
39430994Sphk	return linux_getdents(p, &lda);
39514331Speter}
39668201Sobrien#endif /*!__alpha__*/
39714331Speter
39814331Speterint
39930994Sphklinux_getdents(struct proc *p, struct linux_getdents_args *args)
40014331Speter{
4019313Ssos    register struct dirent *bdp;
4029313Ssos    struct vnode *vp;
4039313Ssos    caddr_t inp, buf;		/* BSD-format */
4049313Ssos    int len, reclen;		/* BSD-format */
4059313Ssos    caddr_t outp;		/* Linux-format */
4069313Ssos    int resid, linuxreclen=0;	/* Linux-format */
4079313Ssos    struct file *fp;
4089313Ssos    struct uio auio;
4099313Ssos    struct iovec aiov;
4109313Ssos    struct vattr va;
4119313Ssos    off_t off;
4129313Ssos    struct linux_dirent linux_dirent;
41324654Sdfr    int buflen, error, eofflag, nbytes, justone;
41424654Sdfr    u_long *cookies = NULL, *cookiep;
41524654Sdfr    int ncookies;
4169313Ssos
4179313Ssos#ifdef DEBUG
41872543Sjlemon	if (ldebug(getdents))
41972543Sjlemon		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
4209313Ssos#endif
42110355Sswallace    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
4229313Ssos	return (error);
42314331Speter    }
4249313Ssos
4259313Ssos    if ((fp->f_flag & FREAD) == 0)
4269313Ssos	return (EBADF);
4279313Ssos
4289313Ssos    vp = (struct vnode *) fp->f_data;
4299313Ssos
4309313Ssos    if (vp->v_type != VDIR)
4319313Ssos	return (EINVAL);
4329313Ssos
43371699Sjhb    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
4349313Ssos	return error;
43511418Sswallace    }
4369313Ssos
4379313Ssos    nbytes = args->count;
4389313Ssos    if (nbytes == 1) {
4399313Ssos	nbytes = sizeof (struct linux_dirent);
4409313Ssos	justone = 1;
4419313Ssos    }
4429313Ssos    else
4439313Ssos	justone = 0;
4449313Ssos
44510355Sswallace    off = fp->f_offset;
44624672Sdfr#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
44724654Sdfr    buflen = max(DIRBLKSIZ, nbytes);
44811418Sswallace    buflen = min(buflen, MAXBSIZE);
4499313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
45022521Sdyson    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4519313Ssosagain:
4529313Ssos    aiov.iov_base = buf;
4539313Ssos    aiov.iov_len = buflen;
4549313Ssos    auio.uio_iov = &aiov;
4559313Ssos    auio.uio_iovcnt = 1;
4569313Ssos    auio.uio_rw = UIO_READ;
4579313Ssos    auio.uio_segflg = UIO_SYSSPACE;
4589313Ssos    auio.uio_procp = p;
4599313Ssos    auio.uio_resid = buflen;
46024654Sdfr    auio.uio_offset = off;
4619313Ssos
46224654Sdfr    if (cookies) {
46324654Sdfr	free(cookies, M_TEMP);
46424654Sdfr	cookies = NULL;
46524654Sdfr    }
46624654Sdfr
46724654Sdfr    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
46810355Sswallace    if (error) {
4699313Ssos	goto out;
47014331Speter    }
4719313Ssos
4729313Ssos    inp = buf;
4739313Ssos    outp = (caddr_t) args->dent;
4749313Ssos    resid = nbytes;
47524654Sdfr    if ((len = buflen - auio.uio_resid) <= 0) {
4769313Ssos	goto eof;
47714331Speter    }
4789313Ssos
47924654Sdfr    cookiep = cookies;
48024654Sdfr
48124654Sdfr    if (cookies) {
48224654Sdfr	/*
48324654Sdfr	 * When using cookies, the vfs has the option of reading from
48424654Sdfr	 * a different offset than that supplied (UFS truncates the
48524654Sdfr	 * offset to a block boundary to make sure that it never reads
48624654Sdfr	 * partway through a directory entry, even if the directory
48724654Sdfr	 * has been compacted).
48824654Sdfr	 */
48924654Sdfr	while (len > 0 && ncookies > 0 && *cookiep <= off) {
49024654Sdfr	    bdp = (struct dirent *) inp;
49124654Sdfr	    len -= bdp->d_reclen;
49224654Sdfr	    inp += bdp->d_reclen;
49324654Sdfr	    cookiep++;
49424654Sdfr	    ncookies--;
49524654Sdfr	}
49624654Sdfr    }
49724654Sdfr
4989313Ssos    while (len > 0) {
49924654Sdfr	if (cookiep && ncookies == 0)
50024654Sdfr	    break;
50110355Sswallace	bdp = (struct dirent *) inp;
50210355Sswallace	reclen = bdp->d_reclen;
50310355Sswallace	if (reclen & 3) {
50410355Sswallace	    printf("linux_readdir: reclen=%d\n", reclen);
50510355Sswallace	    error = EFAULT;
50610355Sswallace	    goto out;
50710355Sswallace	}
50810355Sswallace
5099313Ssos	if (bdp->d_fileno == 0) {
5109313Ssos	    inp += reclen;
51124654Sdfr	    if (cookiep) {
51224654Sdfr		off = *cookiep++;
51324654Sdfr		ncookies--;
51424654Sdfr	    } else
51524654Sdfr		off += reclen;
51610355Sswallace	    len -= reclen;
5179313Ssos	    continue;
5189313Ssos	}
5199313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
5209313Ssos	if (reclen > len || resid < linuxreclen) {
5219313Ssos	    outp++;
5229313Ssos	    break;
5239313Ssos	}
5249313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
52514465Speter	if (justone) {
52614465Speter	    /*
52714465Speter	     * old linux-style readdir usage.
52814465Speter	     */
52914465Speter	    linux_dirent.doff = (linux_off_t) linuxreclen;
53014465Speter	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
53114465Speter	} else {
53268347Smarcel	    if (cookiep)
53368347Smarcel		linux_dirent.doff = (linux_off_t)*cookiep;
53468347Smarcel	    else
53568347Smarcel		linux_dirent.doff = (linux_off_t)(off + reclen);
53614465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
53714465Speter	}
5389313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
53910355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5409313Ssos	    goto out;
54114331Speter	}
5429313Ssos	inp += reclen;
54324654Sdfr	if (cookiep) {
54424654Sdfr	    off = *cookiep++;
54524654Sdfr	    ncookies--;
54624654Sdfr	} else
54724654Sdfr	    off += reclen;
5489313Ssos	outp += linuxreclen;
5499313Ssos	resid -= linuxreclen;
5509313Ssos	len -= reclen;
5519313Ssos	if (justone)
5529313Ssos	    break;
5539313Ssos    }
5549313Ssos
5559313Ssos    if (outp == (caddr_t) args->dent)
5569313Ssos	goto again;
5579313Ssos    fp->f_offset = off;
5589313Ssos
5599313Ssos    if (justone)
5609313Ssos	nbytes = resid + linuxreclen;
56110355Sswallace
5629313Ssoseof:
56330994Sphk    p->p_retval[0] = nbytes - resid;
5649313Ssosout:
56524654Sdfr    if (cookies)
56624654Sdfr	free(cookies, M_TEMP);
56722543Smpp    VOP_UNLOCK(vp, 0, p);
5689313Ssos    free(buf, M_TEMP);
5699313Ssos    return error;
5709313Ssos}
57114331Speter
57214331Speter/*
57314331Speter * These exist mainly for hooks for doing /compat/linux translation.
57414331Speter */
57514331Speter
57614331Speterint
57730994Sphklinux_access(struct proc *p, struct linux_access_args *args)
57814331Speter{
57914331Speter	struct access_args bsd;
58014331Speter	caddr_t sg;
58114331Speter
58214331Speter	sg = stackgap_init();
58314331Speter	CHECKALTEXIST(p, &sg, args->path);
58414331Speter
58514331Speter#ifdef DEBUG
58672543Sjlemon	if (ldebug(access))
58772543Sjlemon		printf(ARGS(access, "%s, %d"), args->path, args->flags);
58814331Speter#endif
58914331Speter	bsd.path = args->path;
59014331Speter	bsd.flags = args->flags;
59114331Speter
59230994Sphk	return access(p, &bsd);
59314331Speter}
59414331Speter
59514331Speterint
59630994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
59714331Speter{
59814331Speter	struct unlink_args bsd;
59914331Speter	caddr_t sg;
60014331Speter
60114331Speter	sg = stackgap_init();
60214331Speter	CHECKALTEXIST(p, &sg, args->path);
60314331Speter
60414331Speter#ifdef DEBUG
60572543Sjlemon	if (ldebug(unlink))
60672543Sjlemon		printf(ARGS(unlink, "%s"), args->path);
60714331Speter#endif
60814331Speter	bsd.path = args->path;
60914331Speter
61030994Sphk	return unlink(p, &bsd);
61114331Speter}
61214331Speter
61314331Speterint
61430994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
61514331Speter{
61614331Speter	struct chdir_args bsd;
61714331Speter	caddr_t sg;
61814331Speter
61914331Speter	sg = stackgap_init();
62014331Speter	CHECKALTEXIST(p, &sg, args->path);
62114331Speter
62214331Speter#ifdef DEBUG
62372543Sjlemon	if (ldebug(chdir))
62472543Sjlemon		printf(ARGS(chdir, "%s"), args->path);
62514331Speter#endif
62614331Speter	bsd.path = args->path;
62714331Speter
62830994Sphk	return chdir(p, &bsd);
62914331Speter}
63014331Speter
63114331Speterint
63230994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
63314331Speter{
63414331Speter	struct chmod_args bsd;
63514331Speter	caddr_t sg;
63614331Speter
63714331Speter	sg = stackgap_init();
63814331Speter	CHECKALTEXIST(p, &sg, args->path);
63914331Speter
64014331Speter#ifdef DEBUG
64172543Sjlemon	if (ldebug(chmod))
64272543Sjlemon		printf(ARGS(chmod, "%s, %d"), args->path, args->mode);
64314331Speter#endif
64414331Speter	bsd.path = args->path;
64514331Speter	bsd.mode = args->mode;
64614331Speter
64730994Sphk	return chmod(p, &bsd);
64814331Speter}
64914331Speter
65014331Speterint
65130994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
65214331Speter{
65314331Speter	struct chown_args bsd;
65414331Speter	caddr_t sg;
65514331Speter
65614331Speter	sg = stackgap_init();
65714331Speter	CHECKALTEXIST(p, &sg, args->path);
65814331Speter
65914331Speter#ifdef DEBUG
66072543Sjlemon	if (ldebug(chown))
66172543Sjlemon		printf(ARGS(chown, "%s, %d, %d"),
66272543Sjlemon		    args->path, args->uid, args->gid);
66314331Speter#endif
66414331Speter	bsd.path = args->path;
66514331Speter	/* XXX size casts here */
66614331Speter	bsd.uid = args->uid;
66714331Speter	bsd.gid = args->gid;
66814331Speter
66930994Sphk	return chown(p, &bsd);
67014331Speter}
67114331Speter
67214331Speterint
67334941Speterlinux_lchown(struct proc *p, struct linux_lchown_args *args)
67434941Speter{
67534941Speter	struct lchown_args bsd;
67634941Speter	caddr_t sg;
67734941Speter
67834941Speter	sg = stackgap_init();
67934941Speter	CHECKALTEXIST(p, &sg, args->path);
68034941Speter
68134941Speter#ifdef DEBUG
68272543Sjlemon	if (ldebug(lchown))
68372543Sjlemon		printf(ARGS(lchown, "%s, %d, %d"),
68472543Sjlemon		    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
70472543Sjlemon	if (ldebug(mkdir))
70572543Sjlemon		printf(ARGS(mkdir, "%s, %d"), 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
72372543Sjlemon	if (ldebug(rmdir))
72472543Sjlemon		printf(ARGS(rmdir, "%s"), 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
74272543Sjlemon	if (ldebug(rename))
74372543Sjlemon		printf(ARGS(rename, "%s, %s"), 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
76272543Sjlemon	if (ldebug(symlink))
76372543Sjlemon		printf(ARGS(symlink, "%s, %s"), 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_readlink(struct proc *p, struct linux_readlink_args *args)
77314331Speter{
77414331Speter	struct readlink_args bsd;
77514331Speter	caddr_t sg;
77614331Speter
77714331Speter	sg = stackgap_init();
77814331Speter	CHECKALTEXIST(p, &sg, args->name);
77914331Speter
78014331Speter#ifdef DEBUG
78172543Sjlemon	if (ldebug(readlink))
78272543Sjlemon		printf(ARGS(readlink, "%s, %p, %d"),
78372543Sjlemon		    args->name, (void *)args->buf, args->count);
78414331Speter#endif
78514331Speter	bsd.path = args->name;
78614331Speter	bsd.buf = args->buf;
78714331Speter	bsd.count = args->count;
78814331Speter
78930994Sphk	return readlink(p, &bsd);
79014331Speter}
79114331Speter
79214331Speterint
79330994Sphklinux_truncate(struct proc *p, struct linux_truncate_args *args)
79414331Speter{
79542499Seivind	struct truncate_args bsd;
79614331Speter	caddr_t sg;
79714331Speter
79814331Speter	sg = stackgap_init();
79914331Speter	CHECKALTEXIST(p, &sg, args->path);
80014331Speter
80114331Speter#ifdef DEBUG
80272543Sjlemon	if (ldebug(truncate))
80372543Sjlemon		printf(ARGS(truncate, "%s, %ld"), args->path, args->length);
80414331Speter#endif
80514331Speter	bsd.path = args->path;
80632265Sjmb	bsd.length = args->length;
80714331Speter
80842499Seivind	return truncate(p, &bsd);
80914331Speter}
81014331Speter
81149662Smarcelint
81249662Smarcellinux_link(struct proc *p, struct linux_link_args *args)
81349662Smarcel{
81449662Smarcel    struct link_args bsd;
81549662Smarcel    caddr_t sg;
81649662Smarcel
81749662Smarcel    sg = stackgap_init();
81849662Smarcel    CHECKALTEXIST(p, &sg, args->path);
81949662Smarcel    CHECKALTCREAT(p, &sg, args->to);
82049662Smarcel
82149662Smarcel#ifdef DEBUG
82272543Sjlemon	if (ldebug(link))
82372543Sjlemon		printf(ARGS(link, "%s, %s"), args->path, args->to);
82449662Smarcel#endif
82549662Smarcel
82649662Smarcel    bsd.path = args->path;
82749662Smarcel    bsd.link = args->to;
82849662Smarcel
82949662Smarcel    return link(p, &bsd);
83049662Smarcel}
83149788Smarcel
83249788Smarcelint
83349788Smarcellinux_getcwd(struct proc *p, struct linux_getcwd_args *args)
83449788Smarcel{
83551348Smarcel	struct __getcwd_args bsd;
83651348Smarcel	caddr_t sg;
83751348Smarcel	int error, len;
83849788Smarcel
83949788Smarcel#ifdef DEBUG
84072543Sjlemon	if (ldebug(getcwd))
84172543Sjlemon		printf(ARGS(getcwd, "%p, %ld"), args->buf, args->bufsize);
84249788Smarcel#endif
84349788Smarcel
84451348Smarcel	sg = stackgap_init();
84551348Smarcel	bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE);
84651348Smarcel	bsd.buflen = SPARE_USRSPACE;
84751348Smarcel	error = __getcwd(p, &bsd);
84851348Smarcel	if (!error) {
84951348Smarcel		len = strlen(bsd.buf) + 1;
85051348Smarcel		if (len <= args->bufsize) {
85151348Smarcel			p->p_retval[0] = len;
85251348Smarcel			error = copyout(bsd.buf, args->buf, len);
85351348Smarcel		}
85451348Smarcel		else
85551348Smarcel			error = ERANGE;
85651348Smarcel	}
85751348Smarcel	return (error);
85849788Smarcel}
85953713Smarcel
86068201Sobrien#ifndef __alpha__
86153713Smarcelint
86253713Smarcellinux_fdatasync(p, uap)
86353713Smarcel	struct proc *p;
86453713Smarcel	struct linux_fdatasync_args *uap;
86553713Smarcel{
86653713Smarcel	struct fsync_args bsd;
86753713Smarcel
86853713Smarcel	bsd.fd = uap->fd;
86953713Smarcel	return fsync(p, &bsd);
87053713Smarcel}
87168201Sobrien#endif /*!__alpha__*/
87263285Smarcel
87363285Smarcelint
87463285Smarcellinux_pread(p, uap)
87563285Smarcel	struct proc *p;
87663285Smarcel	struct linux_pread_args *uap;
87763285Smarcel{
87863285Smarcel	struct pread_args bsd;
87963285Smarcel
88063285Smarcel	bsd.fd = uap->fd;
88163285Smarcel	bsd.buf = uap->buf;
88263285Smarcel	bsd.nbyte = uap->nbyte;
88363285Smarcel	bsd.offset = uap->offset;
88463285Smarcel	return pread(p, &bsd);
88563285Smarcel}
88663285Smarcel
88763285Smarcelint
88863285Smarcellinux_pwrite(p, uap)
88963285Smarcel	struct proc *p;
89063285Smarcel	struct linux_pwrite_args *uap;
89163285Smarcel{
89263285Smarcel	struct pwrite_args bsd;
89363285Smarcel
89463285Smarcel	bsd.fd = uap->fd;
89563285Smarcel	bsd.buf = uap->buf;
89663285Smarcel	bsd.nbyte = uap->nbyte;
89763285Smarcel	bsd.offset = uap->offset;
89863285Smarcel	return pwrite(p, &bsd);
89963285Smarcel}
90072538Sjlemon
90172538Sjlemonint
90272538Sjlemonlinux_mount(struct proc *p, struct linux_mount_args *args)
90372538Sjlemon{
90472538Sjlemon	struct mount_args bsd_args;
90572538Sjlemon	struct ufs_args ufs;
90672538Sjlemon        char fstypename[MFSNAMELEN];
90772538Sjlemon        char mntonname[MNAMELEN], mntfromname[MNAMELEN];
90872538Sjlemon	int error = 0;
90972538Sjlemon
91072538Sjlemon        error = copyinstr(args->filesystemtype, fstypename,
91172538Sjlemon	    MFSNAMELEN - 1, NULL);
91272538Sjlemon	if (error)
91372538Sjlemon                return (error);
91472538Sjlemon        error = copyinstr(args->specialfile, mntfromname, MFSNAMELEN - 1, NULL);
91572538Sjlemon	if (error)
91672538Sjlemon                return (error);
91772538Sjlemon        error = copyinstr(args->dir, mntonname, MFSNAMELEN - 1, NULL);
91872538Sjlemon	if (error)
91972538Sjlemon                return (error);
92072538Sjlemon
92172538Sjlemon#ifdef DEBUG
92272538Sjlemon	if (ldebug(mount))
92372538Sjlemon		printf(ARGS(mount, "%s, %s, %s"),
92472538Sjlemon		    fstypename, mntfromname, mntonname);
92572538Sjlemon#endif
92672538Sjlemon
92772538Sjlemon	if (strcmp(fstypename, "ext2") == 0) {
92872538Sjlemon		bsd_args.type = "ext2fs";
92972538Sjlemon		bsd_args.data = (void *)&ufs;
93072538Sjlemon		ufs.fspec = mntfromname;
93172538Sjlemon#define DEFAULT_ROOTID		-2
93272538Sjlemon		ufs.export.ex_root = DEFAULT_ROOTID;
93372538Sjlemon		ufs.export.ex_flags =
93472538Sjlemon		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
93572538Sjlemon	} else if (strcmp(fstypename, "proc") == 0) {
93672538Sjlemon		bsd_args.type = "linprocfs";
93772538Sjlemon		bsd_args.data = NULL;
93872538Sjlemon	} else {
93972538Sjlemon		return (ENODEV);
94072538Sjlemon	}
94172538Sjlemon
94272538Sjlemon	bsd_args.path = mntonname;
94372538Sjlemon	bsd_args.flags = 0;
94472538Sjlemon
94572538Sjlemon	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
94672538Sjlemon		/*
94772538Sjlemon		 * Linux SYNC flag is not included; the closest equivalent
94872538Sjlemon		 * FreeBSD has is !ASYNC, which is our default.
94972538Sjlemon		 */
95072538Sjlemon		if (args->rwflag & LINUX_MS_RDONLY)
95172538Sjlemon			bsd_args.flags |= MNT_RDONLY;
95272538Sjlemon		if (args->rwflag & LINUX_MS_NOSUID)
95372538Sjlemon			bsd_args.flags |= MNT_NOSUID;
95472538Sjlemon		if (args->rwflag & LINUX_MS_NODEV)
95572538Sjlemon			bsd_args.flags |= MNT_NODEV;
95672538Sjlemon		if (args->rwflag & LINUX_MS_NOEXEC)
95772538Sjlemon			bsd_args.flags |= MNT_NOEXEC;
95872538Sjlemon		if (args->rwflag & LINUX_MS_REMOUNT)
95972538Sjlemon			bsd_args.flags |= MNT_UPDATE;
96072538Sjlemon	}
96172538Sjlemon
96272538Sjlemon	return (mount1(p, &bsd_args, UIO_SYSSPACE));
96372538Sjlemon}
96472538Sjlemon
96572538Sjlemonint
96672538Sjlemonlinux_umount(struct proc *p, struct linux_umount_args *args)
96772538Sjlemon{
96872538Sjlemon	struct linux_umount2_args args2;
96972538Sjlemon
97072538Sjlemon	args2.path = args->path;
97172538Sjlemon	args2.flags = 0;
97272538Sjlemon	return (linux_umount2(p, &args2));
97372538Sjlemon}
97472538Sjlemon
97572538Sjlemonint
97672538Sjlemonlinux_umount2(struct proc *p, struct linux_umount2_args *args)
97772538Sjlemon{
97872538Sjlemon	struct unmount_args bsd;
97972538Sjlemon
98072538Sjlemon	bsd.path = args->path;
98172538Sjlemon	bsd.flags = args->flags;	/* XXX correct? */
98272538Sjlemon	return (unmount(p, &bsd));
98372538Sjlemon}
984