Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / sys / emulation / linux / linux_file.c
1 /*-
2  * Copyright (c) 1994-1995 Søren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer 
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/compat/linux/linux_file.c,v 1.41.2.6 2003/01/06 09:19:43 fjoe Exp $
29  * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.18 2004/10/12 19:20:37 dillon Exp $
30  */
31
32 #include "opt_compat.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/dirent.h>
38 #include <sys/fcntl.h>
39 #include <sys/file.h>
40 #include <sys/filedesc.h>
41 #include <sys/kern_syscall.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/mount.h>
45 #include <sys/namei.h>
46 #include <sys/nlookup.h>
47 #include <sys/proc.h>
48 #include <sys/sysproto.h>
49 #include <sys/tty.h>
50 #include <sys/vnode.h>
51
52 #include <vfs/ufs/quota.h>
53 #include <vfs/ufs/ufsmount.h>
54
55 #include <sys/file2.h>
56
57 #include <arch_linux/linux.h>
58 #include <arch_linux/linux_proto.h>
59 #include "linux_util.h"
60
61 #ifndef __alpha__
62 int
63 linux_creat(struct linux_creat_args *args)
64 {
65         struct thread *td = curthread;
66         struct nameidata nd;
67         char *path;
68         int error;
69
70         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
71         if (error)
72                 return (error);
73 #ifdef DEBUG
74         if (ldebug(creat))
75                 printf(ARGS(creat, "%s, %d"), path, args->mode);
76 #endif
77         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
78
79         error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC, args->mode,
80             &args->sysmsg_result);
81
82         linux_free_path(&path);
83         return(error);
84 }
85 #endif /*!__alpha__*/
86
87 int
88 linux_open(struct linux_open_args *args)
89 {
90         struct thread *td = curthread;
91         struct proc *p = td->td_proc;
92         struct nameidata nd;
93         char *path;
94         int error, flags;
95
96         KKASSERT(p);
97
98         if (args->flags & LINUX_O_CREAT) {
99                 error = linux_copyin_path(args->path, &path,
100                     LINUX_PATH_CREATE);
101         } else {
102                 error = linux_copyin_path(args->path, &path,
103                     LINUX_PATH_EXISTS);
104         }
105         if (error)
106                 return (error);
107
108 #ifdef DEBUG
109         if (ldebug(open))
110                 printf(ARGS(open, "%s, 0x%x, 0x%x"), path, args->flags,
111                     args->mode);
112 #endif
113         flags = 0;
114         if (args->flags & LINUX_O_RDONLY)
115                 flags |= O_RDONLY;
116         if (args->flags & LINUX_O_WRONLY)
117                 flags |= O_WRONLY;
118         if (args->flags & LINUX_O_RDWR)
119                 flags |= O_RDWR;
120         if (args->flags & LINUX_O_NDELAY)
121                 flags |= O_NONBLOCK;
122         if (args->flags & LINUX_O_APPEND)
123                 flags |= O_APPEND;
124         if (args->flags & LINUX_O_SYNC)
125                 flags |= O_FSYNC;
126         if (args->flags & LINUX_O_NONBLOCK)
127                 flags |= O_NONBLOCK;
128         if (args->flags & LINUX_FASYNC)
129                 flags |= O_ASYNC;
130         if (args->flags & LINUX_O_CREAT)
131                 flags |= O_CREAT;
132         if (args->flags & LINUX_O_TRUNC)
133                 flags |= O_TRUNC;
134         if (args->flags & LINUX_O_EXCL)
135                 flags |= O_EXCL;
136         if (args->flags & LINUX_O_NOCTTY)
137                 flags |= O_NOCTTY;
138         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
139
140         error = kern_open(&nd, flags, args->mode, &args->sysmsg_result);
141
142         if (error == 0 && !(flags & O_NOCTTY) && 
143                 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
144                 struct filedesc *fdp = p->p_fd;
145                 struct file *fp = fdp->fd_ofiles[args->sysmsg_result];
146
147                 if (fp->f_type == DTYPE_VNODE)
148                         fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td);
149     }
150 #ifdef DEBUG
151         if (ldebug(open))
152                 printf(LMSG("open returns error %d"), error);
153 #endif
154         linux_free_path(&path);
155         return error;
156 }
157
158 int
159 linux_lseek(struct linux_lseek_args *args)
160 {
161         int error;
162
163 #ifdef DEBUG
164         if (ldebug(lseek))
165                 printf(ARGS(lseek, "%d, %ld, %d"),
166                     args->fdes, (long)args->off, args->whence);
167 #endif
168         error = kern_lseek(args->fdes, args->off, args->whence,
169             &args->sysmsg_offset);
170
171         return error;
172 }
173
174 #ifndef __alpha__
175 int
176 linux_llseek(struct linux_llseek_args *args)
177 {
178         int error;
179         off_t off, res;
180
181 #ifdef DEBUG
182         if (ldebug(llseek))
183                 printf(ARGS(llseek, "%d, %d:%d, %d"),
184                     args->fd, args->ohigh, args->olow, args->whence);
185 #endif
186         off = (args->olow) | (((off_t) args->ohigh) << 32);
187
188         error = kern_lseek(args->fd, off, args->whence, &res);
189
190         if (error == 0)
191                 error = copyout(&res, args->res, sizeof(res));
192         return (error);
193 }
194 #endif /*!__alpha__*/
195
196 #ifndef __alpha__
197 int
198 linux_readdir(struct linux_readdir_args *args)
199 {
200         struct linux_getdents_args lda;
201         int error;
202
203         lda.fd = args->fd;
204         lda.dent = args->dent;
205         lda.count = 1;
206         lda.sysmsg_result = 0;
207         error = linux_getdents(&lda);
208         args->sysmsg_result = lda.sysmsg_result;
209         return(error);
210 }
211 #endif /*!__alpha__*/
212
213 /*
214  * Note that linux_getdents(2) and linux_getdents64(2) have the same
215  * arguments. They only differ in the definition of struct dirent they
216  * operate on. We use this to common the code, with the exception of
217  * accessing struct dirent. Note that linux_readdir(2) is implemented
218  * by means of linux_getdents(2). In this case we never operate on
219  * struct dirent64 and thus don't need to handle it...
220  */
221
222 struct l_dirent {
223         l_long          d_ino;
224         l_off_t         d_off;
225         l_ushort        d_reclen;
226         char            d_name[LINUX_NAME_MAX + 1];
227 };
228
229 struct l_dirent64 {
230         uint64_t        d_ino;
231         int64_t         d_off;
232         l_ushort        d_reclen;
233         u_char          d_type;
234         char            d_name[LINUX_NAME_MAX + 1];
235 };
236
237 #define LINUX_RECLEN(de,namlen) \
238     ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
239
240 #define LINUX_DIRBLKSIZ         512
241
242 static int
243 getdents_common(struct linux_getdents64_args *args, int is64bit)
244 {
245         struct thread *td = curthread;
246         struct proc *p = td->td_proc;
247         struct dirent *bdp;
248         struct vnode *vp;
249         caddr_t inp, buf;               /* BSD-format */
250         int len, reclen;                /* BSD-format */
251         caddr_t outp;                   /* Linux-format */
252         int resid, linuxreclen=0;       /* Linux-format */
253         struct file *fp;
254         struct uio auio;
255         struct iovec aiov;
256         struct vattr va;
257         off_t off;
258         struct l_dirent linux_dirent;
259         struct l_dirent64 linux_dirent64;
260         int buflen, error, eofflag, nbytes, justone;
261         u_long *cookies = NULL, *cookiep;
262         int ncookies;
263
264         KKASSERT(p);
265
266         if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0)
267                 return (error);
268
269         if ((fp->f_flag & FREAD) == 0)
270                 return (EBADF);
271
272         vp = (struct vnode *) fp->f_data;
273         if (vp->v_type != VDIR)
274                 return (EINVAL);
275
276         if ((error = VOP_GETATTR(vp, &va, td)))
277                 return (error);
278
279         nbytes = args->count;
280         if (nbytes == 1) {
281                 /* readdir(2) case. Always struct dirent. */
282                 if (is64bit)
283                         return (EINVAL);
284                 nbytes = sizeof(linux_dirent);
285                 justone = 1;
286         } else
287                 justone = 0;
288
289         off = fp->f_offset;
290
291         buflen = max(LINUX_DIRBLKSIZ, nbytes);
292         buflen = min(buflen, MAXBSIZE);
293         buf = malloc(buflen, M_TEMP, M_WAITOK);
294         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
295
296 again:
297         aiov.iov_base = buf;
298         aiov.iov_len = buflen;
299         auio.uio_iov = &aiov;
300         auio.uio_iovcnt = 1;
301         auio.uio_rw = UIO_READ;
302         auio.uio_segflg = UIO_SYSSPACE;
303         auio.uio_td = td;
304         auio.uio_resid = buflen;
305         auio.uio_offset = off;
306
307         if (cookies) {
308                 free(cookies, M_TEMP);
309                 cookies = NULL;
310         }
311
312         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
313                  &cookies)))
314                 goto out;
315
316         inp = buf;
317         outp = (caddr_t)args->dirent;
318         resid = nbytes;
319         if ((len = buflen - auio.uio_resid) <= 0)
320                 goto eof;
321
322         cookiep = cookies;
323
324         if (cookies) {
325                 /*
326                  * When using cookies, the vfs has the option of reading from
327                  * a different offset than that supplied (UFS truncates the
328                  * offset to a block boundary to make sure that it never reads
329                  * partway through a directory entry, even if the directory
330                  * has been compacted).
331                  */
332                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
333                         bdp = (struct dirent *) inp;
334                         len -= bdp->d_reclen;
335                         inp += bdp->d_reclen;
336                         cookiep++;
337                         ncookies--;
338                 }
339         }
340
341         while (len > 0) {
342                 if (cookiep && ncookies == 0)
343                         break;
344                 bdp = (struct dirent *) inp;
345                 reclen = bdp->d_reclen;
346                 if (reclen & 3) {
347                         error = EFAULT;
348                         goto out;
349                 }
350
351                 if (bdp->d_fileno == 0) {
352                         inp += reclen;
353                         if (cookiep) {
354                                 off = *cookiep++;
355                                 ncookies--;
356                         } else
357                                 off += reclen;
358
359                         len -= reclen;
360                         continue;
361                 }
362
363                 linuxreclen = (is64bit)
364                     ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
365                     : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
366
367                 if (reclen > len || resid < linuxreclen) {
368                         outp++;
369                         break;
370                 }
371
372                 if (justone) {
373                         /* readdir(2) case. */
374                         linux_dirent.d_ino = (l_long)bdp->d_fileno;
375                         linux_dirent.d_off = (l_off_t)linuxreclen;
376                         linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
377                         strcpy(linux_dirent.d_name, bdp->d_name);
378                         error = copyout(&linux_dirent, outp, linuxreclen);
379                 } else {
380                         if (is64bit) {
381                                 linux_dirent64.d_ino = bdp->d_fileno;
382                                 linux_dirent64.d_off = (cookiep)
383                                     ? (l_off_t)*cookiep
384                                     : (l_off_t)(off + reclen);
385                                 linux_dirent64.d_reclen =
386                                     (l_ushort)linuxreclen;
387                                 linux_dirent64.d_type = bdp->d_type;
388                                 strcpy(linux_dirent64.d_name, bdp->d_name);
389                                 error = copyout(&linux_dirent64, outp,
390                                     linuxreclen);
391                         } else {
392                                 linux_dirent.d_ino = bdp->d_fileno;
393                                 linux_dirent.d_off = (cookiep)
394                                     ? (l_off_t)*cookiep
395                                     : (l_off_t)(off + reclen);
396                                 linux_dirent.d_reclen = (l_ushort)linuxreclen;
397                                 strcpy(linux_dirent.d_name, bdp->d_name);
398                                 error = copyout(&linux_dirent, outp,
399                                     linuxreclen);
400                         }
401                 }
402                 if (error)
403                         goto out;
404
405                 inp += reclen;
406                 if (cookiep) {
407                         off = *cookiep++;
408                         ncookies--;
409                 } else
410                         off += reclen;
411
412                 outp += linuxreclen;
413                 resid -= linuxreclen;
414                 len -= reclen;
415                 if (justone)
416                         break;
417         }
418
419         if (outp == (caddr_t)args->dirent)
420                 goto again;
421
422         fp->f_offset = off;
423         if (justone)
424                 nbytes = resid + linuxreclen;
425
426 eof:
427         args->sysmsg_result = nbytes - resid;
428
429 out:
430         if (cookies)
431                 free(cookies, M_TEMP);
432
433         VOP_UNLOCK(vp, 0, td);
434         free(buf, M_TEMP);
435         return (error);
436 }
437
438 int
439 linux_getdents(struct linux_getdents_args *args)
440 {
441 #ifdef DEBUG
442         if (ldebug(getdents))
443                 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
444 #endif
445         return (getdents_common((struct linux_getdents64_args*)args, 0));
446 }
447
448 int
449 linux_getdents64(struct linux_getdents64_args *args)
450 {
451 #ifdef DEBUG
452         if (ldebug(getdents64))
453                 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
454 #endif
455         return (getdents_common(args, 1));
456 }
457
458 /*
459  * These exist mainly for hooks for doing /compat/linux translation.
460  */
461
462 int
463 linux_access(struct linux_access_args *args)
464 {
465         struct thread *td = curthread;
466         struct nameidata nd;
467         char *path;
468         int error;
469
470         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
471         if (error)
472                 return (error);
473 #ifdef DEBUG
474         if (ldebug(access))
475                 printf(ARGS(access, "%s, %d"), path, args->flags);
476 #endif
477         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF | CNP_NOOBJ,
478             UIO_SYSSPACE, path, td);
479
480         error = kern_access(&nd, args->flags);
481
482         linux_free_path(&path);
483         return(error);
484 }
485
486 int
487 linux_unlink(struct linux_unlink_args *args)
488 {
489         struct thread *td = curthread;
490         struct nameidata nd;
491         char *path;
492         int error;
493
494         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
495         if (error)
496                 return (error);
497 #ifdef DEBUG
498         if (ldebug(unlink))
499                 printf(ARGS(unlink, "%s"), path);
500 #endif
501         NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT, UIO_SYSSPACE, path, td);
502
503         error = kern_unlink(&nd);
504
505         linux_free_path(&path);
506         return(error);
507 }
508
509 int
510 linux_chdir(struct linux_chdir_args *args)
511 {
512         struct nlookupdata nd;
513         char *path;
514         int error;
515
516         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
517         if (error)
518                 return (error);
519 #ifdef DEBUG
520         if (ldebug(chdir))
521                 printf(ARGS(chdir, "%s"), path);
522 #endif
523         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
524         if (error == 0) {
525                 error = kern_chdir(&nd);
526                 nlookup_done(&nd);
527         }
528         linux_free_path(&path);
529         return(error);
530 }
531
532 int
533 linux_chmod(struct linux_chmod_args *args)
534 {
535         struct thread *td = curthread;
536         struct nameidata nd;
537         char *path;
538         int error;
539
540         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
541         if (error)
542                 return (error);
543 #ifdef DEBUG
544         if (ldebug(chmod))
545                 printf(ARGS(chmod, "%s, %d"), path, args->mode);
546 #endif
547         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
548
549         error = kern_chmod(&nd, args->mode);
550
551         linux_free_path(&path);
552         return(error);
553 }
554
555 int
556 linux_mkdir(struct linux_mkdir_args *args)
557 {
558         struct thread *td = curthread;
559         struct nameidata nd;
560         char *path;
561         int error;
562
563         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
564         if (error)
565                 return (error);
566 #ifdef DEBUG
567         if (ldebug(mkdir))
568                 printf(ARGS(mkdir, "%s, %d"), path, args->mode);
569 #endif
570         NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_SYSSPACE, path, td);
571
572         error = kern_mkdir(&nd, args->mode);
573
574         linux_free_path(&path);
575         return(error);
576 }
577
578 int
579 linux_rmdir(struct linux_rmdir_args *args)
580 {
581         struct thread *td = curthread;
582         struct nameidata nd;
583         char *path;
584         int error;
585
586         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
587         if (error)
588                 return (error);
589 #ifdef DEBUG
590         if (ldebug(rmdir))
591                 printf(ARGS(rmdir, "%s"), path);
592 #endif
593         NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT | CNP_LOCKLEAF,
594             UIO_SYSSPACE, path, td);
595
596         error = kern_rmdir(&nd);
597
598         linux_free_path(&path);
599         return(error);
600 }
601
602 int
603 linux_rename(struct linux_rename_args *args)
604 {
605         struct thread *td = curthread;
606         struct nameidata fromnd, tond;
607         char *from, *to;
608         int error;
609
610         error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
611         if (error)
612                 return (error);
613         error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
614         if (error) {
615                 linux_free_path(&from);
616                 return (error);
617         }
618 #ifdef DEBUG
619         if (ldebug(rename))
620                 printf(ARGS(rename, "%s, %s"), from, to);
621 #endif
622         NDINIT(&fromnd, NAMEI_DELETE, CNP_WANTPARENT | CNP_SAVESTART,
623             UIO_SYSSPACE, from, td);
624         NDINIT(&tond, NAMEI_RENAME,
625             CNP_LOCKPARENT | CNP_LOCKLEAF | CNP_NOCACHE |
626             CNP_SAVESTART | CNP_NOOBJ,
627             UIO_SYSSPACE, to, td);
628
629         error = kern_rename(&fromnd, &tond);
630
631         linux_free_path(&from);
632         linux_free_path(&to);
633         return(error);
634 }
635
636 int
637 linux_symlink(struct linux_symlink_args *args)
638 {
639         struct thread *td = curthread;
640         struct nameidata nd;
641         char *path, *link;
642         int error;
643
644         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
645         if (error)
646                 return (error);
647         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
648         if (error) {
649                 linux_free_path(&path);
650                 return (error);
651         }
652 #ifdef DEBUG
653         if (ldebug(symlink))
654                 printf(ARGS(symlink, "%s, %s"), path, link);
655 #endif
656         NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ, UIO_SYSSPACE,
657             link, td);
658
659         error = kern_symlink(path, &nd);
660
661         linux_free_path(&path);
662         linux_free_path(&link);
663         return(error);
664 }
665
666 int
667 linux_readlink(struct linux_readlink_args *args)
668 {
669         struct thread *td = curthread;
670         struct nameidata nd;
671         char *path;
672         int error;
673
674         error = linux_copyin_path(args->name, &path, LINUX_PATH_EXISTS);
675         if (error)
676                 return (error);
677 #ifdef DEBUG
678         if (ldebug(readlink))
679                 printf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
680                     args->count);
681 #endif
682         NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_NOOBJ, UIO_SYSSPACE,
683            path, td);
684
685         error = kern_readlink(&nd, args->buf, args->count,
686             &args->sysmsg_result);
687
688         linux_free_path(&path);
689         return(error);
690 }
691
692 int
693 linux_truncate(struct linux_truncate_args *args)
694 {
695         struct thread *td = curthread;
696         struct nameidata nd;
697         char *path;
698         int error;
699
700         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
701         if (error)
702                 return (error);
703 #ifdef DEBUG
704         if (ldebug(truncate))
705                 printf(ARGS(truncate, "%s, %ld"), path,
706                     (long)args->length);
707 #endif
708         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
709
710         error = kern_truncate(&nd, args->length);
711
712         linux_free_path(&path);
713         return(error);
714 }
715
716 int
717 linux_truncate64(struct linux_truncate64_args *args)
718 {
719         struct thread *td = curthread;
720         struct nameidata nd;
721         char *path;
722         int error;
723
724         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
725         if (error)
726                 return (error);
727 #ifdef DEBUG
728         if (ldebug(truncate64))
729                 printf(ARGS(truncate64, "%s, %lld"), path,
730                     (off_t)args->length);
731 #endif
732         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
733
734         error = kern_truncate(&nd, args->length);
735
736         linux_free_path(&path);
737         return error;
738 }
739
740 int
741 linux_ftruncate(struct linux_ftruncate_args *args)
742 {
743         int error;
744
745 #ifdef DEBUG
746         if (ldebug(ftruncate))
747                 printf(ARGS(ftruncate, "%d, %ld"), args->fd,
748                     (long)args->length);
749 #endif
750         error = kern_ftruncate(args->fd, args->length);
751
752         return error;
753 }
754
755 int
756 linux_ftruncate64(struct linux_ftruncate64_args *args)
757 {
758         int error;
759
760 #ifdef DEBUG
761         if (ldebug(ftruncate))
762                 printf(ARGS(ftruncate64, "%d, %lld"), args->fd,
763                     (off_t)args->length);
764 #endif
765         error = kern_ftruncate(args->fd, args->length);
766
767         return error;
768 }
769
770 int
771 linux_link(struct linux_link_args *args)
772 {
773         struct thread *td = curthread;
774         struct nameidata nd, linknd;
775         char *path, *link;
776         int error;
777
778         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
779         if (error)
780                 return (error);
781         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
782         if (error) {
783                 linux_free_path(&path);
784                 return (error);
785         }
786 #ifdef DEBUG
787         if (ldebug(link))
788                 printf(ARGS(link, "%s, %s"), path, link);
789 #endif
790         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_NOOBJ, UIO_SYSSPACE,
791             path, td);
792         NDINIT(&linknd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ,
793             UIO_SYSSPACE, link, td);
794
795         error = kern_link(&nd, &linknd);
796
797         linux_free_path(&path);
798         linux_free_path(&link);
799         return(error);
800 }
801
802 #ifndef __alpha__
803 int
804 linux_fdatasync(struct linux_fdatasync_args *uap)
805 {
806         struct fsync_args bsd;
807         int error;
808
809         bsd.fd = uap->fd;
810         bsd.sysmsg_result = 0;
811
812         error = fsync(&bsd);
813         uap->sysmsg_result = bsd.sysmsg_result;
814         return(error);
815 }
816 #endif /*!__alpha__*/
817
818 int
819 linux_pread(struct linux_pread_args *uap)
820 {
821         struct thread *td = curthread;
822         struct uio auio;
823         struct iovec aiov;
824         int error;
825
826         aiov.iov_base = uap->buf;
827         aiov.iov_len = uap->nbyte;
828         auio.uio_iov = &aiov;
829         auio.uio_iovcnt = 1;
830         auio.uio_offset = uap->offset;
831         auio.uio_resid = uap->nbyte;
832         auio.uio_rw = UIO_READ;
833         auio.uio_segflg = UIO_USERSPACE;
834         auio.uio_td = td;
835
836         error = kern_readv(uap->fd, &auio, FOF_OFFSET, &uap->sysmsg_result);
837
838         return(error);
839 }
840
841 int
842 linux_pwrite(struct linux_pwrite_args *uap)
843 {
844         struct thread *td = curthread;
845         struct uio auio;
846         struct iovec aiov;
847         int error;
848
849         aiov.iov_base = uap->buf;
850         aiov.iov_len = uap->nbyte;
851         auio.uio_iov = &aiov;
852         auio.uio_iovcnt = 1;
853         auio.uio_offset = uap->offset;
854         auio.uio_resid = uap->nbyte;
855         auio.uio_rw = UIO_WRITE;
856         auio.uio_segflg = UIO_USERSPACE;
857         auio.uio_td = td;
858
859         error = kern_writev(uap->fd, &auio, FOF_OFFSET, &uap->sysmsg_result);
860
861         return(error);
862 }
863
864 int
865 linux_oldumount(struct linux_oldumount_args *args)
866 {
867         struct linux_umount_args args2;
868         int error;
869
870         args2.path = args->path;
871         args2.flags = 0;
872         args2.sysmsg_result = 0;
873         error = linux_umount(&args2);
874         args->sysmsg_result = args2.sysmsg_result;
875         return(error);
876 }
877
878 int
879 linux_umount(struct linux_umount_args *args)
880 {
881         struct unmount_args bsd;
882         int error;
883
884         bsd.path = args->path;
885         bsd.flags = args->flags;        /* XXX correct? */
886         bsd.sysmsg_result = 0;
887
888         error = unmount(&bsd);
889         args->sysmsg_result = bsd.sysmsg_result;
890         return(error);
891 }
892
893 /*
894  * fcntl family of syscalls
895  */
896
897 struct l_flock {
898         l_short         l_type;
899         l_short         l_whence;
900         l_off_t         l_start;
901         l_off_t         l_len;
902         l_pid_t         l_pid;
903 };
904
905 static void
906 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
907 {
908         switch (linux_flock->l_type) {
909         case LINUX_F_RDLCK:
910                 bsd_flock->l_type = F_RDLCK;
911                 break;
912         case LINUX_F_WRLCK:
913                 bsd_flock->l_type = F_WRLCK;
914                 break;
915         case LINUX_F_UNLCK:
916                 bsd_flock->l_type = F_UNLCK;
917                 break;
918         default:
919                 bsd_flock->l_type = -1;
920                 break;
921         }
922         bsd_flock->l_whence = linux_flock->l_whence;
923         bsd_flock->l_start = (off_t)linux_flock->l_start;
924         bsd_flock->l_len = (off_t)linux_flock->l_len;
925         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
926 }
927
928 static void
929 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
930 {
931         switch (bsd_flock->l_type) {
932         case F_RDLCK:
933                 linux_flock->l_type = LINUX_F_RDLCK;
934                 break;
935         case F_WRLCK:
936                 linux_flock->l_type = LINUX_F_WRLCK;
937                 break;
938         case F_UNLCK:
939                 linux_flock->l_type = LINUX_F_UNLCK;
940                 break;
941         }
942         linux_flock->l_whence = bsd_flock->l_whence;
943         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
944         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
945         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
946 }
947
948 #if defined(__i386__)
949 struct l_flock64 {
950         l_short         l_type;
951         l_short         l_whence;
952         l_loff_t        l_start;
953         l_loff_t        l_len;
954         l_pid_t         l_pid;
955 };
956
957 static void
958 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
959 {
960         switch (linux_flock->l_type) {
961         case LINUX_F_RDLCK:
962                 bsd_flock->l_type = F_RDLCK;
963                 break;
964         case LINUX_F_WRLCK:
965                 bsd_flock->l_type = F_WRLCK;
966                 break;
967         case LINUX_F_UNLCK:
968                 bsd_flock->l_type = F_UNLCK;
969                 break;
970         default:
971                 bsd_flock->l_type = -1;
972                 break;
973         }
974         bsd_flock->l_whence = linux_flock->l_whence;
975         bsd_flock->l_start = (off_t)linux_flock->l_start;
976         bsd_flock->l_len = (off_t)linux_flock->l_len;
977         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
978 }
979
980 static void
981 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
982 {
983         switch (bsd_flock->l_type) {
984         case F_RDLCK:
985                 linux_flock->l_type = LINUX_F_RDLCK;
986                 break;
987         case F_WRLCK:
988                 linux_flock->l_type = LINUX_F_WRLCK;
989                 break;
990         case F_UNLCK:
991                 linux_flock->l_type = LINUX_F_UNLCK;
992                 break;
993         }
994         linux_flock->l_whence = bsd_flock->l_whence;
995         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
996         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
997         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
998 }
999 #endif /* __i386__ */
1000
1001 #if defined(__alpha__)
1002 #define linux_fcntl64_args      linux_fcntl_args
1003 #endif
1004
1005 static int
1006 linux_fcntl_common(struct linux_fcntl64_args *args)
1007 {
1008         struct proc *p = curproc;
1009         struct l_flock linux_flock;
1010         struct filedesc *fdp;
1011         struct file *fp;
1012         union fcntl_dat dat;
1013         int error, cmd;
1014
1015         switch (args->cmd) {
1016         case LINUX_F_DUPFD:
1017                 cmd = F_DUPFD;
1018                 dat.fc_fd = args->arg;
1019                 break;
1020         case LINUX_F_GETFD:
1021                 cmd = F_GETFD;
1022                 break;
1023         case LINUX_F_SETFD:
1024                 cmd = F_SETFD;
1025                 dat.fc_cloexec = args->arg;
1026                 break;
1027         case LINUX_F_GETFL:
1028                 cmd = F_GETFL;
1029                 break;
1030         case LINUX_F_SETFL:
1031                 cmd = F_SETFL;
1032                 dat.fc_flags = 0;
1033                 if (args->arg & LINUX_O_NDELAY)
1034                         dat.fc_flags |= O_NONBLOCK;
1035                 if (args->arg & LINUX_O_APPEND)
1036                         dat.fc_flags |= O_APPEND;
1037                 if (args->arg & LINUX_O_SYNC)
1038                         dat.fc_flags |= O_FSYNC;
1039                 if (args->arg & LINUX_FASYNC)
1040                         dat.fc_flags |= O_ASYNC;
1041                 break;
1042         case LINUX_F_GETLK:
1043         case LINUX_F_SETLK:
1044         case LINUX_F_SETLKW:
1045                 cmd = F_GETLK;
1046                 error = copyin((caddr_t)args->arg, &linux_flock,
1047                     sizeof(linux_flock));
1048                 if (error)
1049                         return (error);
1050                 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
1051                 break;
1052         case LINUX_F_GETOWN:
1053                 cmd = F_GETOWN;
1054                 break;
1055         case LINUX_F_SETOWN:
1056                 /*
1057                  * XXX some Linux applications depend on F_SETOWN having no
1058                  * significant effect for pipes (SIGIO is not delivered for
1059                  * pipes under Linux-2.2.35 at least).
1060                  */
1061                 fdp = p->p_fd;
1062                 if ((u_int)args->fd >= fdp->fd_nfiles ||
1063                     (fp = fdp->fd_ofiles[args->fd]) == NULL)
1064                         return (EBADF);
1065                 if (fp->f_type == DTYPE_PIPE)
1066                         return (EINVAL);
1067                 cmd = F_SETOWN;
1068                 dat.fc_owner = args->arg;
1069                 break;
1070         default:
1071                 return (EINVAL);
1072         }
1073
1074         error = kern_fcntl(args->fd, cmd, &dat);
1075
1076         if (error == 0) {
1077                 switch (args->cmd) {
1078                 case LINUX_F_DUPFD:
1079                         args->sysmsg_result = dat.fc_fd;
1080                         break;
1081                 case LINUX_F_GETFD:
1082                         args->sysmsg_result = dat.fc_cloexec;
1083                         break;
1084                 case LINUX_F_SETFD:
1085                         break;
1086                 case LINUX_F_GETFL:
1087                         args->sysmsg_result = 0;
1088                         if (dat.fc_flags & O_RDONLY)
1089                                 args->sysmsg_result |= LINUX_O_RDONLY;
1090                         if (dat.fc_flags & O_WRONLY)
1091                                 args->sysmsg_result |= LINUX_O_WRONLY;
1092                         if (dat.fc_flags & O_RDWR)
1093                                 args->sysmsg_result |= LINUX_O_RDWR;
1094                         if (dat.fc_flags & O_NDELAY)
1095                                 args->sysmsg_result |= LINUX_O_NONBLOCK;
1096                         if (dat.fc_flags & O_APPEND)
1097                                 args->sysmsg_result |= LINUX_O_APPEND;
1098                         if (dat.fc_flags & O_FSYNC)
1099                                 args->sysmsg_result |= LINUX_O_SYNC;
1100                         if (dat.fc_flags & O_ASYNC)
1101                                 args->sysmsg_result |= LINUX_FASYNC;
1102                         break;
1103                 case LINUX_F_GETLK:
1104                         bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1105                         error = copyout(&linux_flock, (caddr_t)args->arg,
1106                             sizeof(linux_flock));
1107                         break;
1108                 case LINUX_F_SETLK:
1109                 case LINUX_F_SETLKW:
1110                         break;
1111                 case LINUX_F_GETOWN:
1112                         args->sysmsg_result = dat.fc_owner;
1113                         break;
1114                 case LINUX_F_SETOWN:
1115                         break;
1116                 }
1117         }
1118
1119         return(error);
1120 }
1121
1122 int
1123 linux_fcntl(struct linux_fcntl_args *args)
1124 {
1125         struct linux_fcntl64_args args64;
1126         int error;
1127
1128 #ifdef DEBUG
1129         if (ldebug(fcntl))
1130                 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1131 #endif
1132
1133         args64.fd = args->fd;
1134         args64.cmd = args->cmd;
1135         args64.arg = args->arg;
1136         args64.sysmsg_result = 0;
1137         error = linux_fcntl_common(&args64);
1138         args->sysmsg_result = args64.sysmsg_result;
1139         return(error);
1140 }
1141
1142 #if defined(__i386__)
1143 int
1144 linux_fcntl64(struct linux_fcntl64_args *args)
1145 {
1146         struct l_flock64 linux_flock;
1147         union fcntl_dat dat;
1148         int error, cmd = 0;
1149
1150 #ifdef DEBUG
1151         if (ldebug(fcntl64))
1152                 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1153 #endif
1154         if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1155             args->cmd == LINUX_F_SETLKW64) {
1156                 switch (args->cmd) {
1157                 case LINUX_F_GETLK64:
1158                         cmd = F_GETLK;
1159                         break;
1160                 case LINUX_F_SETLK64:
1161                         cmd = F_SETLK;
1162                         break;
1163                 case LINUX_F_SETLKW64:
1164                         cmd = F_SETLKW;
1165                         break;
1166                 }
1167
1168                 error = copyin((caddr_t)args->arg, &linux_flock,
1169                     sizeof(linux_flock));
1170                 if (error)
1171                         return (error);
1172                 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
1173
1174                 error = kern_fcntl(args->fd, cmd, &dat);
1175
1176                 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1177                         bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1178                         error = copyout(&linux_flock, (caddr_t)args->arg,
1179                             sizeof(linux_flock));
1180                 }
1181         } else {
1182                 error = linux_fcntl_common(args);
1183         }
1184
1185         return (error);
1186 }
1187 #endif /* __i386__ */
1188
1189 int
1190 linux_chown(struct linux_chown_args *args)
1191 {
1192         struct thread *td = curthread;
1193         struct nameidata nd;
1194         char *path;
1195         int error;
1196
1197         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1198         if (error)
1199                 return (error);
1200 #ifdef DEBUG
1201         if (ldebug(chown))
1202                 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1203 #endif
1204         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
1205
1206         error = kern_chown(&nd, args->uid, args->gid);
1207
1208         linux_free_path(&path);
1209         return(error);
1210 }
1211
1212 int
1213 linux_lchown(struct linux_lchown_args *args)
1214 {
1215         struct thread *td = curthread;
1216         struct nameidata nd;
1217         char *path;
1218         int error;
1219
1220         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1221         if (error)
1222                 return (error);
1223 #ifdef DEBUG
1224         if (ldebug(lchown))
1225                 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1226 #endif
1227         NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td);
1228
1229         error = kern_chown(&nd, args->uid, args->gid);
1230
1231         linux_free_path(&path);
1232         return(error);
1233 }
1234