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