linux_file.c revision 227693
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
9111798Sdes *    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
1597748Sschweikh *    derived from this software without 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 */
289313Ssos
29116173Sobrien#include <sys/cdefs.h>
30116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linux/linux_file.c 227693 2011-11-19 07:19:37Z ed $");
31116173Sobrien
32156874Sru#include "opt_compat.h"
3331784Seivind
349313Ssos#include <sys/param.h>
359313Ssos#include <sys/systm.h>
36224778Srwatson#include <sys/capability.h>
3776166Smarkm#include <sys/conf.h>
3876166Smarkm#include <sys/dirent.h>
399313Ssos#include <sys/fcntl.h>
409313Ssos#include <sys/file.h>
419313Ssos#include <sys/filedesc.h>
4231561Sbde#include <sys/lock.h>
439313Ssos#include <sys/malloc.h>
4472538Sjlemon#include <sys/mount.h>
4576166Smarkm#include <sys/mutex.h>
46168014Sjulian#include <sys/namei.h>
4776166Smarkm#include <sys/proc.h>
48162201Snetchild#include <sys/stat.h>
49166085Skib#include <sys/sx.h>
50102814Siedowse#include <sys/syscallsubr.h>
5176166Smarkm#include <sys/sysproto.h>
5214331Speter#include <sys/tty.h>
53162585Snetchild#include <sys/unistd.h>
5476166Smarkm#include <sys/vnode.h>
5512458Sbde
56163606Srwatson#include <security/mac/mac_framework.h>
57163606Srwatson
5872538Sjlemon#include <ufs/ufs/extattr.h>
5972538Sjlemon#include <ufs/ufs/quota.h>
6072538Sjlemon#include <ufs/ufs/ufsmount.h>
6172538Sjlemon
62140214Sobrien#ifdef COMPAT_LINUX32
63140214Sobrien#include <machine/../linux32/linux.h>
64140214Sobrien#include <machine/../linux32/linux32_proto.h>
65140214Sobrien#else
6664905Smarcel#include <machine/../linux/linux.h>
6768583Smarcel#include <machine/../linux/linux_proto.h>
68133816Stjr#endif
6964905Smarcel#include <compat/linux/linux_util.h>
70177997Skib#include <compat/linux/linux_file.h>
719313Ssos
729313Ssosint
7383366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args)
749313Ssos{
75102814Siedowse    char *path;
76102814Siedowse    int error;
779313Ssos
78102814Siedowse    LCONVPATHEXIST(td, args->path, &path);
7914331Speter
809313Ssos#ifdef DEBUG
8172543Sjlemon	if (ldebug(creat))
82102814Siedowse		printf(ARGS(creat, "%s, %d"), path, args->mode);
839313Ssos#endif
84102814Siedowse    error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
85102814Siedowse	args->mode);
86102814Siedowse    LFREEPATH(path);
87102814Siedowse    return (error);
889313Ssos}
899313Ssos
90168014Sjulian
91168014Sjulianstatic int
92177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
939313Ssos{
9483382Sjhb    struct proc *p = td->td_proc;
95166085Skib    struct file *fp;
96166085Skib    int fd;
97102814Siedowse    int bsd_flags, error;
9814331Speter
99102814Siedowse    bsd_flags = 0;
100168014Sjulian    switch (l_flags & LINUX_O_ACCMODE) {
101168014Sjulian    case LINUX_O_WRONLY:
102102814Siedowse	bsd_flags |= O_WRONLY;
103168014Sjulian	break;
104168014Sjulian    case LINUX_O_RDWR:
105102814Siedowse	bsd_flags |= O_RDWR;
106168014Sjulian	break;
107168014Sjulian    default:
108168014Sjulian	bsd_flags |= O_RDONLY;
109168014Sjulian    }
110168014Sjulian    if (l_flags & LINUX_O_NDELAY)
111102814Siedowse	bsd_flags |= O_NONBLOCK;
112168014Sjulian    if (l_flags & LINUX_O_APPEND)
113102814Siedowse	bsd_flags |= O_APPEND;
114168014Sjulian    if (l_flags & LINUX_O_SYNC)
115102814Siedowse	bsd_flags |= O_FSYNC;
116168014Sjulian    if (l_flags & LINUX_O_NONBLOCK)
117102814Siedowse	bsd_flags |= O_NONBLOCK;
118168014Sjulian    if (l_flags & LINUX_FASYNC)
119102814Siedowse	bsd_flags |= O_ASYNC;
120168014Sjulian    if (l_flags & LINUX_O_CREAT)
121102814Siedowse	bsd_flags |= O_CREAT;
122168014Sjulian    if (l_flags & LINUX_O_TRUNC)
123102814Siedowse	bsd_flags |= O_TRUNC;
124168014Sjulian    if (l_flags & LINUX_O_EXCL)
125102814Siedowse	bsd_flags |= O_EXCL;
126168014Sjulian    if (l_flags & LINUX_O_NOCTTY)
127102814Siedowse	bsd_flags |= O_NOCTTY;
128168014Sjulian    if (l_flags & LINUX_O_DIRECT)
129166085Skib	bsd_flags |= O_DIRECT;
130168014Sjulian    if (l_flags & LINUX_O_NOFOLLOW)
131166085Skib	bsd_flags |= O_NOFOLLOW;
132205423Sed    if (l_flags & LINUX_O_DIRECTORY)
133205423Sed	bsd_flags |= O_DIRECTORY;
134166085Skib    /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
1359313Ssos
136178036Srdivacky    error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
137178036Srdivacky
138166085Skib    if (!error) {
139166085Skib	    fd = td->td_retval[0];
140166085Skib	    /*
141166085Skib	     * XXX In between kern_open() and fget(), another process
142166085Skib	     * having the same filedesc could use that fd without
143166085Skib	     * checking below.
144166085Skib	     */
145224778Srwatson	    error = fget(td, fd, CAP_IOCTL, &fp);
146166085Skib	    if (!error) {
147166085Skib		    sx_slock(&proctree_lock);
148166085Skib		    PROC_LOCK(p);
149166085Skib		    if (!(bsd_flags & O_NOCTTY) &&
150166085Skib			SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
151166085Skib			    PROC_UNLOCK(p);
152166085Skib			    sx_unlock(&proctree_lock);
153166085Skib			    if (fp->f_type == DTYPE_VNODE)
154166085Skib				    (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
155166085Skib					     td->td_ucred, td);
156166085Skib		    } else {
157166085Skib			    PROC_UNLOCK(p);
158166085Skib			    sx_sunlock(&proctree_lock);
159166085Skib		    }
160166085Skib		    fdrop(fp, td);
161166085Skib		    /*
162166085Skib		     * XXX as above, fdrop()/kern_close() pair is racy.
163166085Skib		     */
164166085Skib		    if (error)
165166085Skib			    kern_close(td, fd);
166166085Skib	    }
167166085Skib    }
1689313Ssos
16914331Speter#ifdef DEBUG
170166085Skib    if (ldebug(open))
171166085Skib	    printf(LMSG("open returns error %d"), error);
17214331Speter#endif
173177997Skib    LFREEPATH(path);
174177997Skib    return (error);
1759313Ssos}
1769313Ssos
1779313Ssosint
178168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args)
179168014Sjulian{
180177997Skib	char *path;
181177997Skib	int dfd;
182168014Sjulian
183177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
184177997Skib	if (args->flags & LINUX_O_CREAT)
185177997Skib		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
186177997Skib	else
187177997Skib		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
188168014Sjulian#ifdef DEBUG
189168014Sjulian	if (ldebug(openat))
190168014Sjulian		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
191177997Skib		    path, args->flags, args->mode);
192168014Sjulian#endif
193177997Skib	return (linux_common_open(td, dfd, path, args->flags, args->mode));
194168014Sjulian}
195168014Sjulian
196168014Sjulianint
197168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args)
198168014Sjulian{
199168014Sjulian    char *path;
200168014Sjulian
201168014Sjulian    if (args->flags & LINUX_O_CREAT)
202168014Sjulian	LCONVPATHCREAT(td, args->path, &path);
203168014Sjulian    else
204168014Sjulian	LCONVPATHEXIST(td, args->path, &path);
205168014Sjulian
206168014Sjulian#ifdef DEBUG
207168014Sjulian	if (ldebug(open))
208168014Sjulian		printf(ARGS(open, "%s, 0x%x, 0x%x"),
209168014Sjulian		    path, args->flags, args->mode);
210168014Sjulian#endif
211168014Sjulian
212178036Srdivacky	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
213168014Sjulian}
214168014Sjulian
215168014Sjulianint
21683366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args)
2179313Ssos{
2189313Ssos
21912858Speter    struct lseek_args /* {
22012858Speter	int fd;
2219313Ssos	int pad;
22212858Speter	off_t offset;
2239313Ssos	int whence;
22412858Speter    } */ tmp_args;
2259313Ssos    int error;
2269313Ssos
2279313Ssos#ifdef DEBUG
22872543Sjlemon	if (ldebug(lseek))
22972543Sjlemon		printf(ARGS(lseek, "%d, %ld, %d"),
23083221Smarcel		    args->fdes, (long)args->off, args->whence);
2319313Ssos#endif
23212858Speter    tmp_args.fd = args->fdes;
23312858Speter    tmp_args.offset = (off_t)args->off;
2349313Ssos    tmp_args.whence = args->whence;
235225617Skmacy    error = sys_lseek(td, &tmp_args);
2369313Ssos    return error;
2379313Ssos}
2389313Ssos
23914331Speterint
24083366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args)
24114331Speter{
24214331Speter	struct lseek_args bsd_args;
24314331Speter	int error;
24414331Speter	off_t off;
24514331Speter
24614331Speter#ifdef DEBUG
24772543Sjlemon	if (ldebug(llseek))
24872543Sjlemon		printf(ARGS(llseek, "%d, %d:%d, %d"),
24972543Sjlemon		    args->fd, args->ohigh, args->olow, args->whence);
25014331Speter#endif
25114331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
25214331Speter
25314331Speter	bsd_args.fd = args->fd;
25414331Speter	bsd_args.offset = off;
25514331Speter	bsd_args.whence = args->whence;
25614331Speter
257225617Skmacy	if ((error = sys_lseek(td, &bsd_args)))
25814331Speter		return error;
25914331Speter
260111797Sdes	if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
26114331Speter		return error;
26214331Speter
26383366Sjulian	td->td_retval[0] = 0;
26414331Speter	return 0;
26514331Speter}
26614331Speter
2679313Ssosint
26883366Sjulianlinux_readdir(struct thread *td, struct linux_readdir_args *args)
2699313Ssos{
27014331Speter	struct linux_getdents_args lda;
27114331Speter
27214331Speter	lda.fd = args->fd;
27314331Speter	lda.dent = args->dent;
27414331Speter	lda.count = 1;
27583366Sjulian	return linux_getdents(td, &lda);
27614331Speter}
27714331Speter
27883221Smarcel/*
27983221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same
28083221Smarcel * arguments. They only differ in the definition of struct dirent they
28183221Smarcel * operate on. We use this to common the code, with the exception of
28283221Smarcel * accessing struct dirent. Note that linux_readdir(2) is implemented
28383221Smarcel * by means of linux_getdents(2). In this case we never operate on
28483221Smarcel * struct dirent64 and thus don't need to handle it...
28583221Smarcel */
28683221Smarcel
28783221Smarcelstruct l_dirent {
288179651Srdivacky	l_ulong		d_ino;
28983221Smarcel	l_off_t		d_off;
29083221Smarcel	l_ushort	d_reclen;
29183221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
29283221Smarcel};
29383221Smarcel
29483221Smarcelstruct l_dirent64 {
29583221Smarcel	uint64_t	d_ino;
29683221Smarcel	int64_t		d_off;
29783221Smarcel	l_ushort	d_reclen;
29883221Smarcel	u_char		d_type;
29983221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
30083221Smarcel};
30183221Smarcel
302182892Srdivacky/*
303182892Srdivacky * Linux uses the last byte in the dirent buffer to store d_type,
304182892Srdivacky * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
305182892Srdivacky */
306182892Srdivacky#define LINUX_RECLEN(namlen)						\
307182892Srdivacky    roundup((offsetof(struct l_dirent, d_name) + (namlen) + 2),		\
308182892Srdivacky    sizeof(l_ulong))
30983221Smarcel
310182892Srdivacky#define LINUX_RECLEN64(namlen)						\
311182892Srdivacky    roundup((offsetof(struct l_dirent64, d_name) + (namlen) + 1),	\
312182892Srdivacky    sizeof(uint64_t))
313182892Srdivacky
314182892Srdivacky#define LINUX_MAXRECLEN		max(LINUX_RECLEN(LINUX_NAME_MAX),	\
315182892Srdivacky				    LINUX_RECLEN64(LINUX_NAME_MAX))
31683221Smarcel#define	LINUX_DIRBLKSIZ		512
31783221Smarcel
31883221Smarcelstatic int
31983366Sjuliangetdents_common(struct thread *td, struct linux_getdents64_args *args,
32083221Smarcel    int is64bit)
32114331Speter{
322111798Sdes	struct dirent *bdp;
32383221Smarcel	struct vnode *vp;
32483221Smarcel	caddr_t inp, buf;		/* BSD-format */
32583221Smarcel	int len, reclen;		/* BSD-format */
32683221Smarcel	caddr_t outp;			/* Linux-format */
32783221Smarcel	int resid, linuxreclen=0;	/* Linux-format */
328182892Srdivacky	caddr_t lbuf;			/* Linux-format */
32983221Smarcel	struct file *fp;
33083221Smarcel	struct uio auio;
33183221Smarcel	struct iovec aiov;
33283221Smarcel	off_t off;
333182892Srdivacky	struct l_dirent *linux_dirent;
334182892Srdivacky	struct l_dirent64 *linux_dirent64;
33583221Smarcel	int buflen, error, eofflag, nbytes, justone;
33683221Smarcel	u_long *cookies = NULL, *cookiep;
337160276Sjhb	int ncookies, vfslocked;
3389313Ssos
339160276Sjhb	nbytes = args->count;
340160276Sjhb	if (nbytes == 1) {
341160276Sjhb		/* readdir(2) case. Always struct dirent. */
342160276Sjhb		if (is64bit)
343160276Sjhb			return (EINVAL);
344188572Snetchild		nbytes = sizeof(*linux_dirent);
345160276Sjhb		justone = 1;
346160276Sjhb	} else
347160276Sjhb		justone = 0;
348160276Sjhb
349224778Srwatson	if ((error = getvnode(td->td_proc->p_fd, args->fd, CAP_READ, &fp)) != 0)
35083221Smarcel		return (error);
3519313Ssos
35289306Salfred	if ((fp->f_flag & FREAD) == 0) {
35389306Salfred		fdrop(fp, td);
35483221Smarcel		return (EBADF);
35589306Salfred	}
3569313Ssos
357116678Sphk	vp = fp->f_vnode;
358160276Sjhb	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
35989306Salfred	if (vp->v_type != VDIR) {
360160276Sjhb		VFS_UNLOCK_GIANT(vfslocked);
36189306Salfred		fdrop(fp, td);
36283221Smarcel		return (EINVAL);
36389306Salfred	}
3649313Ssos
36583221Smarcel	off = fp->f_offset;
3669313Ssos
36783221Smarcel	buflen = max(LINUX_DIRBLKSIZ, nbytes);
36883221Smarcel	buflen = min(buflen, MAXBSIZE);
369111119Simp	buf = malloc(buflen, M_TEMP, M_WAITOK);
370182892Srdivacky	lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO);
371188588Sjhb	vn_lock(vp, LK_SHARED | LK_RETRY);
37283221Smarcel
37383221Smarcel	aiov.iov_base = buf;
37483221Smarcel	aiov.iov_len = buflen;
37583221Smarcel	auio.uio_iov = &aiov;
37683221Smarcel	auio.uio_iovcnt = 1;
37783221Smarcel	auio.uio_rw = UIO_READ;
37883221Smarcel	auio.uio_segflg = UIO_SYSSPACE;
37983366Sjulian	auio.uio_td = td;
38083221Smarcel	auio.uio_resid = buflen;
38183221Smarcel	auio.uio_offset = off;
3829313Ssos
38383221Smarcel	if (cookies) {
38483221Smarcel		free(cookies, M_TEMP);
38583221Smarcel		cookies = NULL;
38683221Smarcel	}
38724654Sdfr
388101189Srwatson#ifdef MAC
389101189Srwatson	/*
390101189Srwatson	 * Do directory search MAC check using non-cached credentials.
391101189Srwatson	 */
392172930Srwatson	if ((error = mac_vnode_check_readdir(td->td_ucred, vp)))
393101189Srwatson		goto out;
394101189Srwatson#endif /* MAC */
39583221Smarcel	if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
39683221Smarcel		 &cookies)))
39783221Smarcel		goto out;
3989313Ssos
39983221Smarcel	inp = buf;
40083221Smarcel	outp = (caddr_t)args->dirent;
40183221Smarcel	resid = nbytes;
40283221Smarcel	if ((len = buflen - auio.uio_resid) <= 0)
40383221Smarcel		goto eof;
4049313Ssos
40583221Smarcel	cookiep = cookies;
40624654Sdfr
40783221Smarcel	if (cookies) {
40883221Smarcel		/*
40983221Smarcel		 * When using cookies, the vfs has the option of reading from
41083221Smarcel		 * a different offset than that supplied (UFS truncates the
41183221Smarcel		 * offset to a block boundary to make sure that it never reads
41283221Smarcel		 * partway through a directory entry, even if the directory
41383221Smarcel		 * has been compacted).
41483221Smarcel		 */
41583221Smarcel		while (len > 0 && ncookies > 0 && *cookiep <= off) {
41683221Smarcel			bdp = (struct dirent *) inp;
41783221Smarcel			len -= bdp->d_reclen;
41883221Smarcel			inp += bdp->d_reclen;
41983221Smarcel			cookiep++;
42083221Smarcel			ncookies--;
42183221Smarcel		}
42224654Sdfr	}
42324654Sdfr
42483221Smarcel	while (len > 0) {
42583221Smarcel		if (cookiep && ncookies == 0)
42683221Smarcel			break;
42783221Smarcel		bdp = (struct dirent *) inp;
42883221Smarcel		reclen = bdp->d_reclen;
42983221Smarcel		if (reclen & 3) {
43083221Smarcel			error = EFAULT;
43183221Smarcel			goto out;
43283221Smarcel		}
43383221Smarcel
43483221Smarcel		if (bdp->d_fileno == 0) {
43583221Smarcel			inp += reclen;
43683221Smarcel			if (cookiep) {
43783221Smarcel				off = *cookiep++;
43883221Smarcel				ncookies--;
43983221Smarcel			} else
44083221Smarcel				off += reclen;
44183221Smarcel
44283221Smarcel			len -= reclen;
44383221Smarcel			continue;
44483221Smarcel		}
44583221Smarcel
44683221Smarcel		linuxreclen = (is64bit)
447182892Srdivacky		    ? LINUX_RECLEN64(bdp->d_namlen)
448182892Srdivacky		    : LINUX_RECLEN(bdp->d_namlen);
44983221Smarcel
45083221Smarcel		if (reclen > len || resid < linuxreclen) {
45183221Smarcel			outp++;
45283221Smarcel			break;
45383221Smarcel		}
45483221Smarcel
45583221Smarcel		if (justone) {
45683221Smarcel			/* readdir(2) case. */
457182892Srdivacky			linux_dirent = (struct l_dirent*)lbuf;
458182892Srdivacky			linux_dirent->d_ino = bdp->d_fileno;
459182892Srdivacky			linux_dirent->d_off = (l_off_t)linuxreclen;
460182892Srdivacky			linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
461182892Srdivacky			strlcpy(linux_dirent->d_name, bdp->d_name,
462182892Srdivacky			    linuxreclen - offsetof(struct l_dirent, d_name));
463182892Srdivacky			error = copyout(linux_dirent, outp, linuxreclen);
46483221Smarcel		}
465182892Srdivacky		if (is64bit) {
466182892Srdivacky			linux_dirent64 = (struct l_dirent64*)lbuf;
467182892Srdivacky			linux_dirent64->d_ino = bdp->d_fileno;
468182892Srdivacky			linux_dirent64->d_off = (cookiep)
469182892Srdivacky			    ? (l_off_t)*cookiep
470182892Srdivacky			    : (l_off_t)(off + reclen);
471182892Srdivacky			linux_dirent64->d_reclen = (l_ushort)linuxreclen;
472182892Srdivacky			linux_dirent64->d_type = bdp->d_type;
473182892Srdivacky			strlcpy(linux_dirent64->d_name, bdp->d_name,
474182892Srdivacky			    linuxreclen - offsetof(struct l_dirent64, d_name));
475182892Srdivacky			error = copyout(linux_dirent64, outp, linuxreclen);
476182892Srdivacky		} else if (!justone) {
477182892Srdivacky			linux_dirent = (struct l_dirent*)lbuf;
478182892Srdivacky			linux_dirent->d_ino = bdp->d_fileno;
479182892Srdivacky			linux_dirent->d_off = (cookiep)
480182892Srdivacky			    ? (l_off_t)*cookiep
481182892Srdivacky			    : (l_off_t)(off + reclen);
482182892Srdivacky			linux_dirent->d_reclen = (l_ushort)linuxreclen;
483182892Srdivacky			/*
484182892Srdivacky			 * Copy d_type to last byte of l_dirent buffer
485182892Srdivacky			 */
486182892Srdivacky			lbuf[linuxreclen-1] = bdp->d_type;
487182892Srdivacky			strlcpy(linux_dirent->d_name, bdp->d_name,
488182892Srdivacky			    linuxreclen - offsetof(struct l_dirent, d_name)-1);
489182892Srdivacky			error = copyout(linux_dirent, outp, linuxreclen);
490182892Srdivacky		}
491182892Srdivacky
49283221Smarcel		if (error)
49383221Smarcel			goto out;
49483221Smarcel
49583221Smarcel		inp += reclen;
49683221Smarcel		if (cookiep) {
49783221Smarcel			off = *cookiep++;
49883221Smarcel			ncookies--;
49983221Smarcel		} else
50083221Smarcel			off += reclen;
50183221Smarcel
50283221Smarcel		outp += linuxreclen;
50383221Smarcel		resid -= linuxreclen;
50483221Smarcel		len -= reclen;
50583221Smarcel		if (justone)
50683221Smarcel			break;
50710355Sswallace	}
5089313Ssos
509217578Skib	if (outp == (caddr_t)args->dirent) {
510217578Skib		nbytes = resid;
511217578Skib		goto eof;
512217578Skib	}
5139313Ssos
51483221Smarcel	fp->f_offset = off;
51583221Smarcel	if (justone)
51683221Smarcel		nbytes = resid + linuxreclen;
51710355Sswallace
5189313Ssoseof:
51983366Sjulian	td->td_retval[0] = nbytes - resid;
52083221Smarcel
5219313Ssosout:
52283221Smarcel	if (cookies)
52383221Smarcel		free(cookies, M_TEMP);
52483221Smarcel
525175294Sattilio	VOP_UNLOCK(vp, 0);
526160276Sjhb	VFS_UNLOCK_GIANT(vfslocked);
52789306Salfred	fdrop(fp, td);
52883221Smarcel	free(buf, M_TEMP);
529182892Srdivacky	free(lbuf, M_TEMP);
53083221Smarcel	return (error);
5319313Ssos}
53214331Speter
53383221Smarcelint
53483366Sjulianlinux_getdents(struct thread *td, struct linux_getdents_args *args)
53583221Smarcel{
53683221Smarcel
53783221Smarcel#ifdef DEBUG
53883221Smarcel	if (ldebug(getdents))
53983221Smarcel		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
54083221Smarcel#endif
54183221Smarcel
54283366Sjulian	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
54383221Smarcel}
54483221Smarcel
54583221Smarcelint
54683366Sjulianlinux_getdents64(struct thread *td, struct linux_getdents64_args *args)
54783221Smarcel{
54883221Smarcel
54983221Smarcel#ifdef DEBUG
55083221Smarcel	if (ldebug(getdents64))
55183221Smarcel		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
55283221Smarcel#endif
55383221Smarcel
55483366Sjulian	return (getdents_common(td, args, 1));
55583221Smarcel}
55683221Smarcel
55714331Speter/*
55814331Speter * These exist mainly for hooks for doing /compat/linux translation.
55914331Speter */
56014331Speter
56114331Speterint
56283366Sjulianlinux_access(struct thread *td, struct linux_access_args *args)
56314331Speter{
564102814Siedowse	char *path;
565102814Siedowse	int error;
56614331Speter
567162585Snetchild	/* linux convention */
568227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
569162585Snetchild		return (EINVAL);
570162585Snetchild
571102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
57214331Speter
57314331Speter#ifdef DEBUG
57472543Sjlemon	if (ldebug(access))
575227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
57614331Speter#endif
577227691Sed	error = kern_access(td, path, UIO_SYSSPACE, args->amode);
578102814Siedowse	LFREEPATH(path);
579162585Snetchild
580102814Siedowse	return (error);
58114331Speter}
58214331Speter
58314331Speterint
584177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args)
585177997Skib{
586177997Skib	char *path;
587227693Sed	int error, dfd, flag;
588177997Skib
589227693Sed	if (args->flag & ~LINUX_AT_EACCESS)
590227693Sed		return (EINVAL);
591177997Skib	/* linux convention */
592227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
593177997Skib		return (EINVAL);
594177997Skib
595177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
596177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
597177997Skib
598177997Skib#ifdef DEBUG
599177997Skib	if (ldebug(access))
600227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
601177997Skib#endif
602177997Skib
603227693Sed	flag = (args->flag & LINUX_AT_EACCESS) == 0 ? 0 : AT_EACCESS;
604227693Sed	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, flag, args->amode);
605177997Skib	LFREEPATH(path);
606177997Skib
607177997Skib	return (error);
608177997Skib}
609177997Skib
610177997Skibint
61183366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args)
61214331Speter{
613102814Siedowse	char *path;
614102814Siedowse	int error;
615162201Snetchild	struct stat st;
61614331Speter
617102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
61814331Speter
61914331Speter#ifdef DEBUG
62072543Sjlemon	if (ldebug(unlink))
621102814Siedowse		printf(ARGS(unlink, "%s"), path);
62214331Speter#endif
62314331Speter
624102814Siedowse	error = kern_unlink(td, path, UIO_SYSSPACE);
625162201Snetchild	if (error == EPERM)
626162201Snetchild		/* Introduce POSIX noncompliant behaviour of Linux */
627162201Snetchild		if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0)
628162201Snetchild			if (S_ISDIR(st.st_mode))
629162201Snetchild				error = EISDIR;
630102814Siedowse	LFREEPATH(path);
631102814Siedowse	return (error);
63214331Speter}
63314331Speter
63414331Speterint
635177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
636177997Skib{
637177997Skib	char *path;
638177997Skib	int error, dfd;
639177997Skib	struct stat st;
640177997Skib
641177997Skib	if (args->flag & ~LINUX_AT_REMOVEDIR)
642177997Skib		return (EINVAL);
643177997Skib
644177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
645177997Skib	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
646177997Skib
647177997Skib#ifdef DEBUG
648177997Skib	if (ldebug(unlinkat))
649177997Skib		printf(ARGS(unlinkat, "%s"), path);
650177997Skib#endif
651177997Skib
652177997Skib	if (args->flag & LINUX_AT_REMOVEDIR)
653177997Skib		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
654177997Skib	else
655202113Smckusick		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
656177997Skib	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
657177997Skib		/* Introduce POSIX noncompliant behaviour of Linux */
658177997Skib		if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
659177997Skib		    UIO_SYSSPACE, &st) == 0 && S_ISDIR(st.st_mode))
660177997Skib			error = EISDIR;
661177997Skib	}
662177997Skib	LFREEPATH(path);
663177997Skib	return (error);
664177997Skib}
665177997Skibint
66683366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args)
66714331Speter{
668102814Siedowse	char *path;
669102814Siedowse	int error;
67014331Speter
671102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
67214331Speter
67314331Speter#ifdef DEBUG
67472543Sjlemon	if (ldebug(chdir))
675102814Siedowse		printf(ARGS(chdir, "%s"), path);
67614331Speter#endif
677102814Siedowse	error = kern_chdir(td, path, UIO_SYSSPACE);
678102814Siedowse	LFREEPATH(path);
679102814Siedowse	return (error);
68014331Speter}
68114331Speter
68214331Speterint
68383366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args)
68414331Speter{
685102814Siedowse	char *path;
686102814Siedowse	int error;
68714331Speter
688102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
68914331Speter
69014331Speter#ifdef DEBUG
69172543Sjlemon	if (ldebug(chmod))
692102814Siedowse		printf(ARGS(chmod, "%s, %d"), path, args->mode);
69314331Speter#endif
694102814Siedowse	error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
695102814Siedowse	LFREEPATH(path);
696102814Siedowse	return (error);
69714331Speter}
69814331Speter
69914331Speterint
700177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
701177997Skib{
702177997Skib	char *path;
703177997Skib	int error, dfd;
704177997Skib
705177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
706177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
707177997Skib
708177997Skib#ifdef DEBUG
709177997Skib	if (ldebug(fchmodat))
710177997Skib		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
711177997Skib#endif
712177997Skib
713177997Skib	error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
714177997Skib	LFREEPATH(path);
715177997Skib	return (error);
716177997Skib}
717177997Skib
718177997Skibint
71983366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args)
72014331Speter{
721102814Siedowse	char *path;
722102814Siedowse	int error;
72314331Speter
724102814Siedowse	LCONVPATHCREAT(td, args->path, &path);
72514331Speter
72614331Speter#ifdef DEBUG
72772543Sjlemon	if (ldebug(mkdir))
728102814Siedowse		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
72914331Speter#endif
730102814Siedowse	error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
731102814Siedowse	LFREEPATH(path);
732102814Siedowse	return (error);
73314331Speter}
73414331Speter
73514331Speterint
736177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
737177997Skib{
738177997Skib	char *path;
739177997Skib	int error, dfd;
740177997Skib
741177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
742177997Skib	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
743177997Skib
744177997Skib#ifdef DEBUG
745177997Skib	if (ldebug(mkdirat))
746177997Skib		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
747177997Skib#endif
748177997Skib	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
749177997Skib	LFREEPATH(path);
750177997Skib	return (error);
751177997Skib}
752177997Skib
753177997Skibint
75483366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args)
75514331Speter{
756102814Siedowse	char *path;
757102814Siedowse	int error;
75814331Speter
759102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
76014331Speter
76114331Speter#ifdef DEBUG
76272543Sjlemon	if (ldebug(rmdir))
763102814Siedowse		printf(ARGS(rmdir, "%s"), path);
76414331Speter#endif
765102814Siedowse	error = kern_rmdir(td, path, UIO_SYSSPACE);
766102814Siedowse	LFREEPATH(path);
767102814Siedowse	return (error);
76814331Speter}
76914331Speter
77014331Speterint
77183366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args)
77214331Speter{
773102814Siedowse	char *from, *to;
774102814Siedowse	int error;
77514331Speter
776102814Siedowse	LCONVPATHEXIST(td, args->from, &from);
777102814Siedowse	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
778177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
779102814Siedowse	if (to == NULL) {
780102814Siedowse		LFREEPATH(from);
781102814Siedowse		return (error);
782102814Siedowse	}
78314331Speter
78414331Speter#ifdef DEBUG
78572543Sjlemon	if (ldebug(rename))
786102814Siedowse		printf(ARGS(rename, "%s, %s"), from, to);
78714331Speter#endif
788102814Siedowse	error = kern_rename(td, from, to, UIO_SYSSPACE);
789102814Siedowse	LFREEPATH(from);
790102814Siedowse	LFREEPATH(to);
791102814Siedowse	return (error);
79214331Speter}
79314331Speter
79414331Speterint
795177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args)
796177997Skib{
797177997Skib	char *from, *to;
798177997Skib	int error, olddfd, newdfd;
799177997Skib
800177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
801177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
802177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
803177997Skib	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
804177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
805177997Skib	if (to == NULL) {
806177997Skib		LFREEPATH(from);
807177997Skib		return (error);
808177997Skib	}
809177997Skib
810177997Skib#ifdef DEBUG
811177997Skib	if (ldebug(renameat))
812177997Skib		printf(ARGS(renameat, "%s, %s"), from, to);
813177997Skib#endif
814177997Skib	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
815177997Skib	LFREEPATH(from);
816177997Skib	LFREEPATH(to);
817177997Skib	return (error);
818177997Skib}
819177997Skib
820177997Skibint
82183366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args)
82214331Speter{
823102814Siedowse	char *path, *to;
824102814Siedowse	int error;
82514331Speter
826102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
827102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
828177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
829102814Siedowse	if (to == NULL) {
830102814Siedowse		LFREEPATH(path);
831102814Siedowse		return (error);
832102814Siedowse	}
83314331Speter
83414331Speter#ifdef DEBUG
83572543Sjlemon	if (ldebug(symlink))
836102814Siedowse		printf(ARGS(symlink, "%s, %s"), path, to);
83714331Speter#endif
838102814Siedowse	error = kern_symlink(td, path, to, UIO_SYSSPACE);
839102814Siedowse	LFREEPATH(path);
840102814Siedowse	LFREEPATH(to);
841102814Siedowse	return (error);
84214331Speter}
84314331Speter
84414331Speterint
845177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
846177997Skib{
847177997Skib	char *path, *to;
848177997Skib	int error, dfd;
849177997Skib
850177997Skib	dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
851177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
852177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
853177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
854177997Skib	if (to == NULL) {
855177997Skib		LFREEPATH(path);
856177997Skib		return (error);
857177997Skib	}
858177997Skib
859177997Skib#ifdef DEBUG
860177997Skib	if (ldebug(symlinkat))
861177997Skib		printf(ARGS(symlinkat, "%s, %s"), path, to);
862177997Skib#endif
863177997Skib
864177997Skib	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
865177997Skib	LFREEPATH(path);
866177997Skib	LFREEPATH(to);
867177997Skib	return (error);
868177997Skib}
869177997Skib
870177997Skibint
87183366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args)
87214331Speter{
873102814Siedowse	char *name;
874102814Siedowse	int error;
87514331Speter
876102814Siedowse	LCONVPATHEXIST(td, args->name, &name);
87714331Speter
87814331Speter#ifdef DEBUG
87972543Sjlemon	if (ldebug(readlink))
880102814Siedowse		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
881102814Siedowse		    args->count);
88214331Speter#endif
883102814Siedowse	error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
884102814Siedowse	    args->count);
885102814Siedowse	LFREEPATH(name);
886102814Siedowse	return (error);
88714331Speter}
88814331Speter
88914331Speterint
890177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
891177997Skib{
892177997Skib	char *name;
893177997Skib	int error, dfd;
894177997Skib
895177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
896177997Skib	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
897177997Skib
898177997Skib#ifdef DEBUG
899177997Skib	if (ldebug(readlinkat))
900177997Skib		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
901177997Skib		    args->bufsiz);
902177997Skib#endif
903177997Skib
904177997Skib	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
905177997Skib	    UIO_USERSPACE, args->bufsiz);
906177997Skib	LFREEPATH(name);
907177997Skib	return (error);
908177997Skib}
909178439Srdivacky
910177997Skibint
91183366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args)
91214331Speter{
913102814Siedowse	char *path;
914102814Siedowse	int error;
91514331Speter
916102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
91714331Speter
91814331Speter#ifdef DEBUG
91972543Sjlemon	if (ldebug(truncate))
920102814Siedowse		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
92114331Speter#endif
92214331Speter
923102814Siedowse	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
924102814Siedowse	LFREEPATH(path);
925102814Siedowse	return (error);
92614331Speter}
92714331Speter
92849662Smarcelint
929178439Srdivackylinux_truncate64(struct thread *td, struct linux_truncate64_args *args)
930178439Srdivacky{
931178439Srdivacky	char *path;
932178439Srdivacky	int error;
933178439Srdivacky
934178439Srdivacky	LCONVPATHEXIST(td, args->path, &path);
935178439Srdivacky
936178439Srdivacky#ifdef DEBUG
937178439Srdivacky	if (ldebug(truncate64))
938178439Srdivacky		printf(ARGS(truncate64, "%s, %jd"), path, args->length);
939178439Srdivacky#endif
940178439Srdivacky
941178439Srdivacky	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
942178439Srdivacky	LFREEPATH(path);
943178439Srdivacky	return (error);
944178439Srdivacky}
945178439Srdivackyint
946156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
947156842Snetchild{
948156842Snetchild	struct ftruncate_args /* {
949156842Snetchild		int fd;
950156842Snetchild		int pad;
951156842Snetchild		off_t length;
952156842Snetchild		} */ nuap;
953156842Snetchild
954156842Snetchild	nuap.fd = args->fd;
955156842Snetchild	nuap.length = args->length;
956225617Skmacy	return (sys_ftruncate(td, &nuap));
957156842Snetchild}
958156842Snetchild
959156842Snetchildint
96083366Sjulianlinux_link(struct thread *td, struct linux_link_args *args)
96149662Smarcel{
962102814Siedowse	char *path, *to;
963102814Siedowse	int error;
96449662Smarcel
965102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
966102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
967177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
968102814Siedowse	if (to == NULL) {
969102814Siedowse		LFREEPATH(path);
970102814Siedowse		return (error);
971102814Siedowse	}
97249662Smarcel
97349662Smarcel#ifdef DEBUG
97472543Sjlemon	if (ldebug(link))
975102814Siedowse		printf(ARGS(link, "%s, %s"), path, to);
97649662Smarcel#endif
977102814Siedowse	error = kern_link(td, path, to, UIO_SYSSPACE);
978102814Siedowse	LFREEPATH(path);
979102814Siedowse	LFREEPATH(to);
980102814Siedowse	return (error);
98149662Smarcel}
98249788Smarcel
98353713Smarcelint
984177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args)
985177997Skib{
986177997Skib	char *path, *to;
987227693Sed	int error, olddfd, newdfd, follow;
988177997Skib
989227693Sed	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
990177997Skib		return (EINVAL);
991177997Skib
992177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
993177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
994177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
995177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
996177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
997177997Skib	if (to == NULL) {
998177997Skib		LFREEPATH(path);
999177997Skib		return (error);
1000177997Skib	}
1001177997Skib
1002177997Skib#ifdef DEBUG
1003177997Skib	if (ldebug(linkat))
1004177997Skib		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
1005227693Sed			args->newdfd, to, args->flag);
1006177997Skib#endif
1007177997Skib
1008227693Sed	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
1009227693Sed	    FOLLOW;
1010227693Sed	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
1011177997Skib	LFREEPATH(path);
1012177997Skib	LFREEPATH(to);
1013177997Skib	return (error);
1014177997Skib}
1015177997Skib
1016177997Skibint
101783366Sjulianlinux_fdatasync(td, uap)
101883366Sjulian	struct thread *td;
101953713Smarcel	struct linux_fdatasync_args *uap;
102053713Smarcel{
102153713Smarcel	struct fsync_args bsd;
102253713Smarcel
102353713Smarcel	bsd.fd = uap->fd;
1024225617Skmacy	return sys_fsync(td, &bsd);
102553713Smarcel}
102663285Smarcel
102763285Smarcelint
102883366Sjulianlinux_pread(td, uap)
102983366Sjulian	struct thread *td;
103063285Smarcel	struct linux_pread_args *uap;
103163285Smarcel{
103263285Smarcel	struct pread_args bsd;
1033162585Snetchild	struct vnode *vp;
1034162585Snetchild	int error;
103563285Smarcel
103663285Smarcel	bsd.fd = uap->fd;
103763285Smarcel	bsd.buf = uap->buf;
103863285Smarcel	bsd.nbyte = uap->nbyte;
103963285Smarcel	bsd.offset = uap->offset;
1040162585Snetchild
1041225617Skmacy	error = sys_pread(td, &bsd);
1042162585Snetchild
1043162585Snetchild	if (error == 0) {
1044162585Snetchild   	   	/* This seems to violate POSIX but linux does it */
1045224778Srwatson		if ((error = fgetvp(td, uap->fd, CAP_READ, &vp)) != 0)
1046162585Snetchild   		   	return (error);
1047162585Snetchild		if (vp->v_type == VDIR) {
1048162585Snetchild   		   	vrele(vp);
1049162585Snetchild			return (EISDIR);
1050162585Snetchild		}
1051162585Snetchild		vrele(vp);
1052162585Snetchild	}
1053162585Snetchild
1054162585Snetchild	return (error);
105563285Smarcel}
105663285Smarcel
105763285Smarcelint
105883366Sjulianlinux_pwrite(td, uap)
105983366Sjulian	struct thread *td;
106063285Smarcel	struct linux_pwrite_args *uap;
106163285Smarcel{
106263285Smarcel	struct pwrite_args bsd;
106363285Smarcel
106463285Smarcel	bsd.fd = uap->fd;
106563285Smarcel	bsd.buf = uap->buf;
106663285Smarcel	bsd.nbyte = uap->nbyte;
106763285Smarcel	bsd.offset = uap->offset;
1068225617Skmacy	return sys_pwrite(td, &bsd);
106963285Smarcel}
107072538Sjlemon
107172538Sjlemonint
107283366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args)
107372538Sjlemon{
107472538Sjlemon	struct ufs_args ufs;
1075111798Sdes	char fstypename[MFSNAMELEN];
1076111798Sdes	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
107773286Sadrian	int error;
107873286Sadrian	int fsflags;
107973286Sadrian	void *fsdata;
108072538Sjlemon
1081111798Sdes	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
108273286Sadrian	    NULL);
108372538Sjlemon	if (error)
1084111798Sdes		return (error);
1085127057Stjr	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
108672538Sjlemon	if (error)
1087111798Sdes		return (error);
1088127057Stjr	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
108972538Sjlemon	if (error)
1090111798Sdes		return (error);
109172538Sjlemon
109272538Sjlemon#ifdef DEBUG
109372538Sjlemon	if (ldebug(mount))
109472538Sjlemon		printf(ARGS(mount, "%s, %s, %s"),
109572538Sjlemon		    fstypename, mntfromname, mntonname);
109672538Sjlemon#endif
109772538Sjlemon
109872538Sjlemon	if (strcmp(fstypename, "ext2") == 0) {
1099127059Stjr		strcpy(fstypename, "ext2fs");
110073286Sadrian		fsdata = &ufs;
110172538Sjlemon		ufs.fspec = mntfromname;
110272538Sjlemon#define DEFAULT_ROOTID		-2
110372538Sjlemon		ufs.export.ex_root = DEFAULT_ROOTID;
110472538Sjlemon		ufs.export.ex_flags =
110572538Sjlemon		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
110672538Sjlemon	} else if (strcmp(fstypename, "proc") == 0) {
1107127059Stjr		strcpy(fstypename, "linprocfs");
110873286Sadrian		fsdata = NULL;
1109190445Sambrisko	} else if (strcmp(fstypename, "vfat") == 0) {
1110190445Sambrisko		strcpy(fstypename, "msdosfs");
1111190445Sambrisko		fsdata = NULL;
111272538Sjlemon	} else {
111372538Sjlemon		return (ENODEV);
111472538Sjlemon	}
111572538Sjlemon
111673286Sadrian	fsflags = 0;
111772538Sjlemon
111872538Sjlemon	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
111972538Sjlemon		/*
112072538Sjlemon		 * Linux SYNC flag is not included; the closest equivalent
112172538Sjlemon		 * FreeBSD has is !ASYNC, which is our default.
112272538Sjlemon		 */
112372538Sjlemon		if (args->rwflag & LINUX_MS_RDONLY)
1124111798Sdes			fsflags |= MNT_RDONLY;
112572538Sjlemon		if (args->rwflag & LINUX_MS_NOSUID)
1126111798Sdes			fsflags |= MNT_NOSUID;
112772538Sjlemon		if (args->rwflag & LINUX_MS_NOEXEC)
1128111798Sdes			fsflags |= MNT_NOEXEC;
112972538Sjlemon		if (args->rwflag & LINUX_MS_REMOUNT)
1130111798Sdes			fsflags |= MNT_UPDATE;
113172538Sjlemon	}
113272538Sjlemon
1133127059Stjr	if (strcmp(fstypename, "linprocfs") == 0) {
1134132708Sphk		error = kernel_vmount(fsflags,
1135132708Sphk			"fstype", fstypename,
1136132708Sphk			"fspath", mntonname,
1137132708Sphk			NULL);
1138190445Sambrisko	} else if (strcmp(fstypename, "msdosfs") == 0) {
1139190445Sambrisko		error = kernel_vmount(fsflags,
1140190445Sambrisko			"fstype", fstypename,
1141190445Sambrisko			"fspath", mntonname,
1142190445Sambrisko			"from", mntfromname,
1143190445Sambrisko			NULL);
1144127059Stjr	} else
1145138353Sphk		error = EOPNOTSUPP;
1146127059Stjr	return (error);
114772538Sjlemon}
114872538Sjlemon
114972538Sjlemonint
115083366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args)
115172538Sjlemon{
115283221Smarcel	struct linux_umount_args args2;
115372538Sjlemon
115472538Sjlemon	args2.path = args->path;
115572538Sjlemon	args2.flags = 0;
115683366Sjulian	return (linux_umount(td, &args2));
115772538Sjlemon}
115872538Sjlemon
115972538Sjlemonint
116083366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args)
116172538Sjlemon{
116272538Sjlemon	struct unmount_args bsd;
116372538Sjlemon
116472538Sjlemon	bsd.path = args->path;
116572538Sjlemon	bsd.flags = args->flags;	/* XXX correct? */
1166225617Skmacy	return (sys_unmount(td, &bsd));
116772538Sjlemon}
116883221Smarcel
116983221Smarcel/*
117083221Smarcel * fcntl family of syscalls
117183221Smarcel */
117283221Smarcel
117383221Smarcelstruct l_flock {
117483221Smarcel	l_short		l_type;
117583221Smarcel	l_short		l_whence;
117683221Smarcel	l_off_t		l_start;
117783221Smarcel	l_off_t		l_len;
117883221Smarcel	l_pid_t		l_pid;
1179133816Stjr}
1180140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1181133816Stjr__packed
1182133816Stjr#endif
1183133816Stjr;
118483221Smarcel
118583221Smarcelstatic void
118683221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
118783221Smarcel{
118883221Smarcel	switch (linux_flock->l_type) {
118983221Smarcel	case LINUX_F_RDLCK:
119083221Smarcel		bsd_flock->l_type = F_RDLCK;
119183221Smarcel		break;
119283221Smarcel	case LINUX_F_WRLCK:
119383221Smarcel		bsd_flock->l_type = F_WRLCK;
119483221Smarcel		break;
119583221Smarcel	case LINUX_F_UNLCK:
119683221Smarcel		bsd_flock->l_type = F_UNLCK;
119783221Smarcel		break;
119883221Smarcel	default:
119983221Smarcel		bsd_flock->l_type = -1;
120083221Smarcel		break;
120183221Smarcel	}
120283221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
120383221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
120483221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
120583221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1206177633Sdfr	bsd_flock->l_sysid = 0;
120783221Smarcel}
120883221Smarcel
120983221Smarcelstatic void
121083221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
121183221Smarcel{
121283221Smarcel	switch (bsd_flock->l_type) {
121383221Smarcel	case F_RDLCK:
121483221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
121583221Smarcel		break;
121683221Smarcel	case F_WRLCK:
121783221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
121883221Smarcel		break;
121983221Smarcel	case F_UNLCK:
122083221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
122183221Smarcel		break;
122283221Smarcel	}
122383221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
122483221Smarcel	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
122583221Smarcel	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
122683221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
122783221Smarcel}
122883221Smarcel
1229140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
123083221Smarcelstruct l_flock64 {
123183221Smarcel	l_short		l_type;
123283221Smarcel	l_short		l_whence;
123383221Smarcel	l_loff_t	l_start;
123483221Smarcel	l_loff_t	l_len;
123583221Smarcel	l_pid_t		l_pid;
1236133816Stjr}
1237140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1238133816Stjr__packed
1239133816Stjr#endif
1240133816Stjr;
124183221Smarcel
124283221Smarcelstatic void
124383221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
124483221Smarcel{
124583221Smarcel	switch (linux_flock->l_type) {
124683221Smarcel	case LINUX_F_RDLCK:
124783221Smarcel		bsd_flock->l_type = F_RDLCK;
124883221Smarcel		break;
124983221Smarcel	case LINUX_F_WRLCK:
125083221Smarcel		bsd_flock->l_type = F_WRLCK;
125183221Smarcel		break;
125283221Smarcel	case LINUX_F_UNLCK:
125383221Smarcel		bsd_flock->l_type = F_UNLCK;
125483221Smarcel		break;
125583221Smarcel	default:
125683221Smarcel		bsd_flock->l_type = -1;
125783221Smarcel		break;
125883221Smarcel	}
125983221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
126083221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
126183221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
126283221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1263177633Sdfr	bsd_flock->l_sysid = 0;
126483221Smarcel}
126583221Smarcel
126683221Smarcelstatic void
126783221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
126883221Smarcel{
126983221Smarcel	switch (bsd_flock->l_type) {
127083221Smarcel	case F_RDLCK:
127183221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
127283221Smarcel		break;
127383221Smarcel	case F_WRLCK:
127483221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
127583221Smarcel		break;
127683221Smarcel	case F_UNLCK:
127783221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
127883221Smarcel		break;
127983221Smarcel	}
128083221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
128183221Smarcel	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
128283221Smarcel	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
128383221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
128483221Smarcel}
1285133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
128683221Smarcel
128783221Smarcelstatic int
128883366Sjulianfcntl_common(struct thread *td, struct linux_fcntl64_args *args)
128983221Smarcel{
1290107680Siedowse	struct l_flock linux_flock;
1291107680Siedowse	struct flock bsd_flock;
129283221Smarcel	struct file *fp;
1293102872Siedowse	long arg;
129483221Smarcel	int error, result;
129583221Smarcel
129683221Smarcel	switch (args->cmd) {
129783221Smarcel	case LINUX_F_DUPFD:
1298102872Siedowse		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
129983221Smarcel
130083221Smarcel	case LINUX_F_GETFD:
1301102872Siedowse		return (kern_fcntl(td, args->fd, F_GETFD, 0));
130283221Smarcel
130383221Smarcel	case LINUX_F_SETFD:
1304102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
130583221Smarcel
130683221Smarcel	case LINUX_F_GETFL:
1307102872Siedowse		error = kern_fcntl(td, args->fd, F_GETFL, 0);
130883366Sjulian		result = td->td_retval[0];
130983366Sjulian		td->td_retval[0] = 0;
131083221Smarcel		if (result & O_RDONLY)
131183366Sjulian			td->td_retval[0] |= LINUX_O_RDONLY;
131283221Smarcel		if (result & O_WRONLY)
131383366Sjulian			td->td_retval[0] |= LINUX_O_WRONLY;
131483221Smarcel		if (result & O_RDWR)
131583366Sjulian			td->td_retval[0] |= LINUX_O_RDWR;
131683221Smarcel		if (result & O_NDELAY)
131783366Sjulian			td->td_retval[0] |= LINUX_O_NONBLOCK;
131883221Smarcel		if (result & O_APPEND)
131983366Sjulian			td->td_retval[0] |= LINUX_O_APPEND;
132083221Smarcel		if (result & O_FSYNC)
132183366Sjulian			td->td_retval[0] |= LINUX_O_SYNC;
132283221Smarcel		if (result & O_ASYNC)
132383366Sjulian			td->td_retval[0] |= LINUX_FASYNC;
1324144987Smdodd#ifdef LINUX_O_NOFOLLOW
1325144987Smdodd		if (result & O_NOFOLLOW)
1326144987Smdodd			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1327144987Smdodd#endif
1328144987Smdodd#ifdef LINUX_O_DIRECT
1329144987Smdodd		if (result & O_DIRECT)
1330144987Smdodd			td->td_retval[0] |= LINUX_O_DIRECT;
1331144987Smdodd#endif
133283221Smarcel		return (error);
133383221Smarcel
133483221Smarcel	case LINUX_F_SETFL:
1335102872Siedowse		arg = 0;
133683221Smarcel		if (args->arg & LINUX_O_NDELAY)
1337102872Siedowse			arg |= O_NONBLOCK;
133883221Smarcel		if (args->arg & LINUX_O_APPEND)
1339102872Siedowse			arg |= O_APPEND;
134083221Smarcel		if (args->arg & LINUX_O_SYNC)
1341102872Siedowse			arg |= O_FSYNC;
134283221Smarcel		if (args->arg & LINUX_FASYNC)
1343102872Siedowse			arg |= O_ASYNC;
1344144987Smdodd#ifdef LINUX_O_NOFOLLOW
1345144987Smdodd		if (args->arg & LINUX_O_NOFOLLOW)
1346144987Smdodd			arg |= O_NOFOLLOW;
1347144987Smdodd#endif
1348144987Smdodd#ifdef LINUX_O_DIRECT
1349144987Smdodd		if (args->arg & LINUX_O_DIRECT)
1350144987Smdodd			arg |= O_DIRECT;
1351144987Smdodd#endif
1352102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFL, arg));
135383221Smarcel
1354107680Siedowse	case LINUX_F_GETLK:
1355111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1356107680Siedowse		    sizeof(linux_flock));
1357107680Siedowse		if (error)
1358107680Siedowse			return (error);
1359107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1360107680Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1361107680Siedowse		if (error)
1362107680Siedowse			return (error);
1363107680Siedowse		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1364111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1365107680Siedowse		    sizeof(linux_flock)));
1366107680Siedowse
1367107680Siedowse	case LINUX_F_SETLK:
1368111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1369107680Siedowse		    sizeof(linux_flock));
1370107680Siedowse		if (error)
1371107680Siedowse			return (error);
1372107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1373107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1374107680Siedowse		    (intptr_t)&bsd_flock));
1375107680Siedowse
1376107680Siedowse	case LINUX_F_SETLKW:
1377111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1378107680Siedowse		    sizeof(linux_flock));
1379107680Siedowse		if (error)
1380107680Siedowse			return (error);
1381107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1382107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLKW,
1383107680Siedowse		     (intptr_t)&bsd_flock));
1384107680Siedowse
138583221Smarcel	case LINUX_F_GETOWN:
1386102872Siedowse		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
138783221Smarcel
138883221Smarcel	case LINUX_F_SETOWN:
138983221Smarcel		/*
139083221Smarcel		 * XXX some Linux applications depend on F_SETOWN having no
139183221Smarcel		 * significant effect for pipes (SIGIO is not delivered for
139283221Smarcel		 * pipes under Linux-2.2.35 at least).
139383221Smarcel		 */
1394224778Srwatson		error = fget(td, args->fd, CAP_FCNTL, &fp);
139589319Salfred		if (error)
139689319Salfred			return (error);
139789306Salfred		if (fp->f_type == DTYPE_PIPE) {
139889306Salfred			fdrop(fp, td);
139983221Smarcel			return (EINVAL);
140089306Salfred		}
140189306Salfred		fdrop(fp, td);
140283221Smarcel
1403102872Siedowse		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
140483221Smarcel	}
140583221Smarcel
140683221Smarcel	return (EINVAL);
140783221Smarcel}
140883221Smarcel
140983221Smarcelint
141083366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args)
141183221Smarcel{
141283221Smarcel	struct linux_fcntl64_args args64;
141383221Smarcel
141483221Smarcel#ifdef DEBUG
141583221Smarcel	if (ldebug(fcntl))
141683221Smarcel		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
141783221Smarcel#endif
141883221Smarcel
141983221Smarcel	args64.fd = args->fd;
142083221Smarcel	args64.cmd = args->cmd;
142183221Smarcel	args64.arg = args->arg;
142283366Sjulian	return (fcntl_common(td, &args64));
142383221Smarcel}
142483221Smarcel
1425140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
142683221Smarcelint
142783366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
142883221Smarcel{
142983221Smarcel	struct l_flock64 linux_flock;
1430102872Siedowse	struct flock bsd_flock;
143183221Smarcel	int error;
143283221Smarcel
143383221Smarcel#ifdef DEBUG
143483221Smarcel	if (ldebug(fcntl64))
143583221Smarcel		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
143683221Smarcel#endif
143783221Smarcel
143883221Smarcel	switch (args->cmd) {
143999687Srobert	case LINUX_F_GETLK64:
1440111797Sdes		error = copyin((void *)args->arg, &linux_flock,
144183221Smarcel		    sizeof(linux_flock));
144283221Smarcel		if (error)
144383221Smarcel			return (error);
1444102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1445102872Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
144683221Smarcel		if (error)
144783221Smarcel			return (error);
1448102872Siedowse		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1449111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1450111797Sdes			    sizeof(linux_flock)));
145183221Smarcel
145299687Srobert	case LINUX_F_SETLK64:
1453111797Sdes		error = copyin((void *)args->arg, &linux_flock,
145483221Smarcel		    sizeof(linux_flock));
145583221Smarcel		if (error)
145683221Smarcel			return (error);
1457102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1458102872Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1459102872Siedowse		    (intptr_t)&bsd_flock));
146083221Smarcel
146199687Srobert	case LINUX_F_SETLKW64:
1462111797Sdes		error = copyin((void *)args->arg, &linux_flock,
146383221Smarcel		    sizeof(linux_flock));
146483221Smarcel		if (error)
146583221Smarcel			return (error);
1466102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1467102872Siedowse		return (kern_fcntl(td, args->fd, F_SETLKW,
1468102872Siedowse		    (intptr_t)&bsd_flock));
146983221Smarcel	}
147083221Smarcel
147183366Sjulian	return (fcntl_common(td, args));
147283221Smarcel}
1473133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
147485022Smarcel
147585022Smarcelint
147685022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args)
147785022Smarcel{
1478102814Siedowse	char *path;
1479102814Siedowse	int error;
148085022Smarcel
1481102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
148285022Smarcel
148385022Smarcel#ifdef DEBUG
148485022Smarcel	if (ldebug(chown))
1485102814Siedowse		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
148685022Smarcel#endif
1487102814Siedowse	error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1488102814Siedowse	LFREEPATH(path);
1489102814Siedowse	return (error);
149085022Smarcel}
149185022Smarcel
149285022Smarcelint
1493177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1494177997Skib{
1495177997Skib	char *path;
1496227693Sed	int error, dfd, flag;
1497177997Skib
1498177997Skib	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1499177997Skib		return (EINVAL);
1500177997Skib
1501177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1502177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1503177997Skib
1504177997Skib#ifdef DEBUG
1505177997Skib	if (ldebug(fchownat))
1506177997Skib		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
1507177997Skib#endif
1508177997Skib
1509227693Sed	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1510177997Skib	    AT_SYMLINK_NOFOLLOW;
1511177997Skib	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1512227693Sed	    flag);
1513177997Skib	LFREEPATH(path);
1514177997Skib	return (error);
1515177997Skib}
1516177997Skib
1517177997Skibint
151885022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args)
151985022Smarcel{
1520102814Siedowse	char *path;
1521102814Siedowse	int error;
152285022Smarcel
1523102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
152485022Smarcel
152585022Smarcel#ifdef DEBUG
152685022Smarcel	if (ldebug(lchown))
1527102814Siedowse		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
152885022Smarcel#endif
1529102814Siedowse	error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1530102814Siedowse	LFREEPATH(path);
1531102814Siedowse	return (error);
153285022Smarcel}
1533