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