[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/linux_file.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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 without 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 
 29 #include <sys/cdefs.h>
 30 __FBSDID("$FreeBSD: src/sys/compat/linux/linux_file.c,v 1.115 2008/09/09 16:00:17 rdivacky Exp $");
 31 
 32 #include "opt_compat.h"
 33 #include "opt_mac.h"
 34 
 35 #include <sys/param.h>
 36 #include <sys/systm.h>
 37 #include <sys/conf.h>
 38 #include <sys/dirent.h>
 39 #include <sys/fcntl.h>
 40 #include <sys/file.h>
 41 #include <sys/filedesc.h>
 42 #include <sys/lock.h>
 43 #include <sys/malloc.h>
 44 #include <sys/mount.h>
 45 #include <sys/mutex.h>
 46 #include <sys/namei.h>
 47 #include <sys/proc.h>
 48 #include <sys/stat.h>
 49 #include <sys/sx.h>
 50 #include <sys/syscallsubr.h>
 51 #include <sys/sysproto.h>
 52 #include <sys/tty.h>
 53 #include <sys/unistd.h>
 54 #include <sys/vnode.h>
 55 
 56 #include <security/mac/mac_framework.h>
 57 
 58 #include <ufs/ufs/extattr.h>
 59 #include <ufs/ufs/quota.h>
 60 #include <ufs/ufs/ufsmount.h>
 61 
 62 #ifdef COMPAT_LINUX32
 63 #include <machine/../linux32/linux.h>
 64 #include <machine/../linux32/linux32_proto.h>
 65 #else
 66 #include <machine/../linux/linux.h>
 67 #include <machine/../linux/linux_proto.h>
 68 #endif
 69 #include <compat/linux/linux_util.h>
 70 #include <compat/linux/linux_file.h>
 71 
 72 int
 73 linux_creat(struct thread *td, struct linux_creat_args *args)
 74 {
 75     char *path;
 76     int error;
 77 
 78     LCONVPATHEXIST(td, args->path, &path);
 79 
 80 #ifdef DEBUG
 81         if (ldebug(creat))
 82                 printf(ARGS(creat, "%s, %d"), path, args->mode);
 83 #endif
 84     error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
 85         args->mode);
 86     LFREEPATH(path);
 87     return (error);
 88 }
 89 
 90 
 91 static int
 92 linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
 93 {
 94     struct proc *p = td->td_proc;
 95     struct file *fp;
 96     int fd;
 97     int bsd_flags, error;
 98 
 99     bsd_flags = 0;
100     switch (l_flags & LINUX_O_ACCMODE) {
101     case LINUX_O_WRONLY:
102         bsd_flags |= O_WRONLY;
103         break;
104     case LINUX_O_RDWR:
105         bsd_flags |= O_RDWR;
106         break;
107     default:
108         bsd_flags |= O_RDONLY;
109     }
110     if (l_flags & LINUX_O_NDELAY)
111         bsd_flags |= O_NONBLOCK;
112     if (l_flags & LINUX_O_APPEND)
113         bsd_flags |= O_APPEND;
114     if (l_flags & LINUX_O_SYNC)
115         bsd_flags |= O_FSYNC;
116     if (l_flags & LINUX_O_NONBLOCK)
117         bsd_flags |= O_NONBLOCK;
118     if (l_flags & LINUX_FASYNC)
119         bsd_flags |= O_ASYNC;
120     if (l_flags & LINUX_O_CREAT)
121         bsd_flags |= O_CREAT;
122     if (l_flags & LINUX_O_TRUNC)
123         bsd_flags |= O_TRUNC;
124     if (l_flags & LINUX_O_EXCL)
125         bsd_flags |= O_EXCL;
126     if (l_flags & LINUX_O_NOCTTY)
127         bsd_flags |= O_NOCTTY;
128     if (l_flags & LINUX_O_DIRECT)
129         bsd_flags |= O_DIRECT;
130     if (l_flags & LINUX_O_NOFOLLOW)
131         bsd_flags |= O_NOFOLLOW;
132     /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
133 
134     error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
135 
136     if (!error) {
137             fd = td->td_retval[0];
138             /*
139              * XXX In between kern_open() and fget(), another process
140              * having the same filedesc could use that fd without
141              * checking below.
142              */
143             error = fget(td, fd, &fp);
144             if (!error) {
145                     sx_slock(&proctree_lock);
146                     PROC_LOCK(p);
147                     if (!(bsd_flags & O_NOCTTY) &&
148                         SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
149                             PROC_UNLOCK(p);
150                             sx_unlock(&proctree_lock);
151                             if (fp->f_type == DTYPE_VNODE)
152                                     (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
153                                              td->td_ucred, td);
154                     } else {
155                             PROC_UNLOCK(p);
156                             sx_sunlock(&proctree_lock);
157                     }
158                     if (l_flags & LINUX_O_DIRECTORY) {
159                             if (fp->f_type != DTYPE_VNODE ||
160                                 fp->f_vnode->v_type != VDIR) {
161                                     error = ENOTDIR;
162                             }
163                     }
164                     fdrop(fp, td);
165                     /*
166                      * XXX as above, fdrop()/kern_close() pair is racy.
167                      */
168                     if (error)
169                             kern_close(td, fd);
170             }
171     }
172 
173 #ifdef DEBUG
174     if (ldebug(open))
175             printf(LMSG("open returns error %d"), error);
176 #endif
177     LFREEPATH(path);
178     return (error);
179 }
180 
181 int
182 linux_openat(struct thread *td, struct linux_openat_args *args)
183 {
184         char *path;
185         int dfd;
186 
187         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
188         if (args->flags & LINUX_O_CREAT)
189                 LCONVPATH_AT(td, args->filename, &path, 1, dfd);
190         else
191                 LCONVPATH_AT(td, args->filename, &path, 0, dfd);
192 #ifdef DEBUG
193         if (ldebug(openat))
194                 printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
195                     path, args->flags, args->mode);
196 #endif
197         return (linux_common_open(td, dfd, path, args->flags, args->mode));
198 }
199 
200 int
201 linux_open(struct thread *td, struct linux_open_args *args)
202 {
203     char *path;
204 
205     if (args->flags & LINUX_O_CREAT)
206         LCONVPATHCREAT(td, args->path, &path);
207     else
208         LCONVPATHEXIST(td, args->path, &path);
209 
210 #ifdef DEBUG
211         if (ldebug(open))
212                 printf(ARGS(open, "%s, 0x%x, 0x%x"),
213                     path, args->flags, args->mode);
214 #endif
215 
216         return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
217 }
218 
219 int
220 linux_lseek(struct thread *td, struct linux_lseek_args *args)
221 {
222 
223     struct lseek_args /* {
224         int fd;
225         int pad;
226         off_t offset;
227         int whence;
228     } */ tmp_args;
229     int error;
230 
231 #ifdef DEBUG
232         if (ldebug(lseek))
233                 printf(ARGS(lseek, "%d, %ld, %d"),
234                     args->fdes, (long)args->off, args->whence);
235 #endif
236     tmp_args.fd = args->fdes;
237     tmp_args.offset = (off_t)args->off;
238     tmp_args.whence = args->whence;
239     error = lseek(td, &tmp_args);
240     return error;
241 }
242 
243 int
244 linux_llseek(struct thread *td, struct linux_llseek_args *args)
245 {
246         struct lseek_args bsd_args;
247         int error;
248         off_t off;
249 
250 #ifdef DEBUG
251         if (ldebug(llseek))
252                 printf(ARGS(llseek, "%d, %d:%d, %d"),
253                     args->fd, args->ohigh, args->olow, args->whence);
254 #endif
255         off = (args->olow) | (((off_t) args->ohigh) << 32);
256 
257         bsd_args.fd = args->fd;
258         bsd_args.offset = off;
259         bsd_args.whence = args->whence;
260 
261         if ((error = lseek(td, &bsd_args)))
262                 return error;
263 
264         if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
265                 return error;
266 
267         td->td_retval[0] = 0;
268         return 0;
269 }
270 
271 int
272 linux_readdir(struct thread *td, struct linux_readdir_args *args)
273 {
274         struct linux_getdents_args lda;
275 
276         lda.fd = args->fd;
277         lda.dent = args->dent;
278         lda.count = 1;
279         return linux_getdents(td, &lda);
280 }
281 
282 /*
283  * Note that linux_getdents(2) and linux_getdents64(2) have the same
284  * arguments. They only differ in the definition of struct dirent they
285  * operate on. We use this to common the code, with the exception of
286  * accessing struct dirent. Note that linux_readdir(2) is implemented
287  * by means of linux_getdents(2). In this case we never operate on
288  * struct dirent64 and thus don't need to handle it...
289  */
290 
291 struct l_dirent {
292         l_ulong         d_ino;
293         l_off_t         d_off;
294         l_ushort        d_reclen;
295         char            d_name[LINUX_NAME_MAX + 1];
296 };
297 
298 struct l_dirent64 {
299         uint64_t        d_ino;
300         int64_t         d_off;
301         l_ushort        d_reclen;
302         u_char          d_type;
303         char            d_name[LINUX_NAME_MAX + 1];
304 };
305 
306 /*
307  * Linux uses the last byte in the dirent buffer to store d_type,
308  * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
309  */
310 #define LINUX_RECLEN(namlen)                                            \
311     roundup((offsetof(struct l_dirent, d_name) + (namlen) + 2),         \
312     sizeof(l_ulong))
313 
314 #define LINUX_RECLEN64(namlen)                                          \
315     roundup((offsetof(struct l_dirent64, d_name) + (namlen) + 1),       \
316     sizeof(uint64_t))
317 
318 #define LINUX_MAXRECLEN         max(LINUX_RECLEN(LINUX_NAME_MAX),       \
319                                     LINUX_RECLEN64(LINUX_NAME_MAX))
320 #define LINUX_DIRBLKSIZ         512
321 
322 static int
323 getdents_common(struct thread *td, struct linux_getdents64_args *args,
324     int is64bit)
325 {
326         struct dirent *bdp;
327         struct vnode *vp;
328         caddr_t inp, buf;               /* BSD-format */
329         int len, reclen;                /* BSD-format */
330         caddr_t outp;                   /* Linux-format */
331         int resid, linuxreclen=0;       /* Linux-format */
332         caddr_t lbuf;                   /* Linux-format */
333         struct file *fp;
334         struct uio auio;
335         struct iovec aiov;
336         off_t off;
337         struct l_dirent *linux_dirent;
338         struct l_dirent64 *linux_dirent64;
339         int buflen, error, eofflag, nbytes, justone;
340         u_long *cookies = NULL, *cookiep;
341         int ncookies, vfslocked;
342 
343         nbytes = args->count;
344         if (nbytes == 1) {
345                 /* readdir(2) case. Always struct dirent. */
346                 if (is64bit)
347                         return (EINVAL);
348                 nbytes = sizeof(linux_dirent);
349                 justone = 1;
350         } else
351                 justone = 0;
352 
353         if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0)
354                 return (error);
355 
356         if ((fp->f_flag & FREAD) == 0) {
357                 fdrop(fp, td);
358                 return (EBADF);
359         }
360 
361         vp = fp->f_vnode;
362         vfslocked = VFS_LOCK_GIANT(vp->v_mount);
363         if (vp->v_type != VDIR) {
364                 VFS_UNLOCK_GIANT(vfslocked);
365                 fdrop(fp, td);
366                 return (EINVAL);
367         }
368 
369         off = fp->f_offset;
370 
371         buflen = max(LINUX_DIRBLKSIZ, nbytes);
372         buflen = min(buflen, MAXBSIZE);
373         buf = malloc(buflen, M_TEMP, M_WAITOK);
374         lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO);
375         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
376 
377 again:
378         aiov.iov_base = buf;
379         aiov.iov_len = buflen;
380         auio.uio_iov = &aiov;
381         auio.uio_iovcnt = 1;
382         auio.uio_rw = UIO_READ;
383         auio.uio_segflg = UIO_SYSSPACE;
384         auio.uio_td = td;
385         auio.uio_resid = buflen;
386         auio.uio_offset = off;
387 
388         if (cookies) {
389                 free(cookies, M_TEMP);
390                 cookies = NULL;
391         }
392 
393 #ifdef MAC
394         /*
395          * Do directory search MAC check using non-cached credentials.
396          */
397         if ((error = mac_vnode_check_readdir(td->td_ucred, vp)))
398                 goto out;
399 #endif /* MAC */
400         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
401                  &cookies)))
402                 goto out;
403 
404         inp = buf;
405         outp = (caddr_t)args->dirent;
406         resid = nbytes;
407         if ((len = buflen - auio.uio_resid) <= 0)
408                 goto eof;
409 
410         cookiep = cookies;
411 
412         if (cookies) {
413                 /*
414                  * When using cookies, the vfs has the option of reading from
415                  * a different offset than that supplied (UFS truncates the
416                  * offset to a block boundary to make sure that it never reads
417                  * partway through a directory entry, even if the directory
418                  * has been compacted).
419                  */
420                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
421                         bdp = (struct dirent *) inp;
422                         len -= bdp->d_reclen;
423                         inp += bdp->d_reclen;
424                         cookiep++;
425                         ncookies--;
426                 }
427         }
428 
429         while (len > 0) {
430                 if (cookiep && ncookies == 0)
431                         break;
432                 bdp = (struct dirent *) inp;
433                 reclen = bdp->d_reclen;
434                 if (reclen & 3) {
435                         error = EFAULT;
436                         goto out;
437                 }
438 
439                 if (bdp->d_fileno == 0) {
440                         inp += reclen;
441                         if (cookiep) {
442                                 off = *cookiep++;
443                                 ncookies--;
444                         } else
445                                 off += reclen;
446 
447                         len -= reclen;
448                         continue;
449                 }
450 
451                 linuxreclen = (is64bit)
452                     ? LINUX_RECLEN64(bdp->d_namlen)
453                     : LINUX_RECLEN(bdp->d_namlen);
454 
455                 if (reclen > len || resid < linuxreclen) {
456                         outp++;
457                         break;
458                 }
459 
460                 if (justone) {
461                         /* readdir(2) case. */
462                         linux_dirent = (struct l_dirent*)lbuf;
463                         linux_dirent->d_ino = bdp->d_fileno;
464                         linux_dirent->d_off = (l_off_t)linuxreclen;
465                         linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
466                         strlcpy(linux_dirent->d_name, bdp->d_name,
467                             linuxreclen - offsetof(struct l_dirent, d_name));
468                         error = copyout(linux_dirent, outp, linuxreclen);
469                 }
470                 if (is64bit) {
471                         linux_dirent64 = (struct l_dirent64*)lbuf;
472                         linux_dirent64->d_ino = bdp->d_fileno;
473                         linux_dirent64->d_off = (cookiep)
474                             ? (l_off_t)*cookiep
475                             : (l_off_t)(off + reclen);
476                         linux_dirent64->d_reclen = (l_ushort)linuxreclen;
477                         linux_dirent64->d_type = bdp->d_type;
478                         strlcpy(linux_dirent64->d_name, bdp->d_name,
479                             linuxreclen - offsetof(struct l_dirent64, d_name));
480                         error = copyout(linux_dirent64, outp, linuxreclen);
481                 } else if (!justone) {
482                         linux_dirent = (struct l_dirent*)lbuf;
483                         linux_dirent->d_ino = bdp->d_fileno;
484                         linux_dirent->d_off = (cookiep)
485                             ? (l_off_t)*cookiep
486                             : (l_off_t)(off + reclen);
487                         linux_dirent->d_reclen = (l_ushort)linuxreclen;
488                         /*
489                          * Copy d_type to last byte of l_dirent buffer
490                          */
491                         lbuf[linuxreclen-1] = bdp->d_type;
492                         strlcpy(linux_dirent->d_name, bdp->d_name,
493                             linuxreclen - offsetof(struct l_dirent, d_name)-1);
494                         error = copyout(linux_dirent, outp, linuxreclen);
495                 }
496 
497                 if (error)
498                         goto out;
499 
500                 inp += reclen;
501                 if (cookiep) {
502                         off = *cookiep++;
503                         ncookies--;
504                 } else
505                         off += reclen;
506 
507                 outp += linuxreclen;
508                 resid -= linuxreclen;
509                 len -= reclen;
510                 if (justone)
511                         break;
512         }
513 
514         if (outp == (caddr_t)args->dirent)
515                 goto again;
516 
517         fp->f_offset = off;
518         if (justone)
519                 nbytes = resid + linuxreclen;
520 
521 eof:
522         td->td_retval[0] = nbytes - resid;
523 
524 out:
525         if (cookies)
526                 free(cookies, M_TEMP);
527 
528         VOP_UNLOCK(vp, 0);
529         VFS_UNLOCK_GIANT(vfslocked);
530         fdrop(fp, td);
531         free(buf, M_TEMP);
532         free(lbuf, M_TEMP);
533         return (error);
534 }
535 
536 int
537 linux_getdents(struct thread *td, struct linux_getdents_args *args)
538 {
539 
540 #ifdef DEBUG
541         if (ldebug(getdents))
542                 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
543 #endif
544 
545         return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
546 }
547 
548 int
549 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
550 {
551 
552 #ifdef DEBUG
553         if (ldebug(getdents64))
554                 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
555 #endif
556 
557         return (getdents_common(td, args, 1));
558 }
559 
560 /*
561  * These exist mainly for hooks for doing /compat/linux translation.
562  */
563 
564 int
565 linux_access(struct thread *td, struct linux_access_args *args)
566 {
567         char *path;
568         int error;
569 
570         /* linux convention */
571         if (args->flags & ~(F_OK | X_OK | W_OK | R_OK))
572                 return (EINVAL);
573 
574         LCONVPATHEXIST(td, args->path, &path);
575 
576 #ifdef DEBUG
577         if (ldebug(access))
578                 printf(ARGS(access, "%s, %d"), path, args->flags);
579 #endif
580         error = kern_access(td, path, UIO_SYSSPACE, args->flags);
581         LFREEPATH(path);
582 
583         return (error);
584 }
585 
586 int
587 linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
588 {
589         char *path;
590         int error, dfd;
591 
592         /* linux convention */
593         if (args->mode & ~(F_OK | X_OK | W_OK | R_OK))
594                 return (EINVAL);
595 
596         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
597         LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
598 
599 #ifdef DEBUG
600         if (ldebug(access))
601                 printf(ARGS(access, "%s, %d"), path, args->mode);
602 #endif
603 
604         error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0 /* XXX */,
605             args->mode);
606         LFREEPATH(path);
607 
608         return (error);
609 }
610 
611 int
612 linux_unlink(struct thread *td, struct linux_unlink_args *args)
613 {
614         char *path;
615         int error;
616         struct stat st;
617 
618         LCONVPATHEXIST(td, args->path, &path);
619 
620 #ifdef DEBUG
621         if (ldebug(unlink))
622                 printf(ARGS(unlink, "%s"), path);
623 #endif
624 
625         error = kern_unlink(td, path, UIO_SYSSPACE);
626         if (error == EPERM)
627                 /* Introduce POSIX noncompliant behaviour of Linux */
628                 if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0)
629                         if (S_ISDIR(st.st_mode))
630                                 error = EISDIR;
631         LFREEPATH(path);
632         return (error);
633 }
634 
635 int
636 linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
637 {
638         char *path;
639         int error, dfd;
640         struct stat st;
641 
642         if (args->flag & ~LINUX_AT_REMOVEDIR)
643                 return (EINVAL);
644 
645         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
646         LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
647 
648 #ifdef DEBUG
649         if (ldebug(unlinkat))
650                 printf(ARGS(unlinkat, "%s"), path);
651 #endif
652 
653         if (args->flag & LINUX_AT_REMOVEDIR)
654                 error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
655         else
656                 error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE);
657         if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
658                 /* Introduce POSIX noncompliant behaviour of Linux */
659                 if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
660                     UIO_SYSSPACE, &st) == 0 && S_ISDIR(st.st_mode))
661                         error = EISDIR;
662         }
663         LFREEPATH(path);
664         return (error);
665 }
666 int
667 linux_chdir(struct thread *td, struct linux_chdir_args *args)
668 {
669         char *path;
670         int error;
671 
672         LCONVPATHEXIST(td, args->path, &path);
673 
674 #ifdef DEBUG
675         if (ldebug(chdir))
676                 printf(ARGS(chdir, "%s"), path);
677 #endif
678         error = kern_chdir(td, path, UIO_SYSSPACE);
679         LFREEPATH(path);
680         return (error);
681 }
682 
683 int
684 linux_chmod(struct thread *td, struct linux_chmod_args *args)
685 {
686         char *path;
687         int error;
688 
689         LCONVPATHEXIST(td, args->path, &path);
690 
691 #ifdef DEBUG
692         if (ldebug(chmod))
693                 printf(ARGS(chmod, "%s, %d"), path, args->mode);
694 #endif
695         error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
696         LFREEPATH(path);
697         return (error);
698 }
699 
700 int
701 linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
702 {
703         char *path;
704         int error, dfd;
705 
706         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
707         LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
708 
709 #ifdef DEBUG
710         if (ldebug(fchmodat))
711                 printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
712 #endif
713 
714         error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
715         LFREEPATH(path);
716         return (error);
717 }
718 
719 int
720 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
721 {
722         char *path;
723         int error;
724 
725         LCONVPATHCREAT(td, args->path, &path);
726 
727 #ifdef DEBUG
728         if (ldebug(mkdir))
729                 printf(ARGS(mkdir, "%s, %d"), path, args->mode);
730 #endif
731         error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
732         LFREEPATH(path);
733         return (error);
734 }
735 
736 int
737 linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
738 {
739         char *path;
740         int error, dfd;
741 
742         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
743         LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
744 
745 #ifdef DEBUG
746         if (ldebug(mkdirat))
747                 printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
748 #endif
749         error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
750         LFREEPATH(path);
751         return (error);
752 }
753 
754 int
755 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
756 {
757         char *path;
758         int error;
759 
760         LCONVPATHEXIST(td, args->path, &path);
761 
762 #ifdef DEBUG
763         if (ldebug(rmdir))
764                 printf(ARGS(rmdir, "%s"), path);
765 #endif
766         error = kern_rmdir(td, path, UIO_SYSSPACE);
767         LFREEPATH(path);
768         return (error);
769 }
770 
771 int
772 linux_rename(struct thread *td, struct linux_rename_args *args)
773 {
774         char *from, *to;
775         int error;
776 
777         LCONVPATHEXIST(td, args->from, &from);
778         /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
779         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
780         if (to == NULL) {
781                 LFREEPATH(from);
782                 return (error);
783         }
784 
785 #ifdef DEBUG
786         if (ldebug(rename))
787                 printf(ARGS(rename, "%s, %s"), from, to);
788 #endif
789         error = kern_rename(td, from, to, UIO_SYSSPACE);
790         LFREEPATH(from);
791         LFREEPATH(to);
792         return (error);
793 }
794 
795 int
796 linux_renameat(struct thread *td, struct linux_renameat_args *args)
797 {
798         char *from, *to;
799         int error, olddfd, newdfd;
800 
801         olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
802         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
803         LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
804         /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
805         error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
806         if (to == NULL) {
807                 LFREEPATH(from);
808                 return (error);
809         }
810 
811 #ifdef DEBUG
812         if (ldebug(renameat))
813                 printf(ARGS(renameat, "%s, %s"), from, to);
814 #endif
815         error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
816         LFREEPATH(from);
817         LFREEPATH(to);
818         return (error);
819 }
820 
821 int
822 linux_symlink(struct thread *td, struct linux_symlink_args *args)
823 {
824         char *path, *to;
825         int error;
826 
827         LCONVPATHEXIST(td, args->path, &path);
828         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
829         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
830         if (to == NULL) {
831                 LFREEPATH(path);
832                 return (error);
833         }
834 
835 #ifdef DEBUG
836         if (ldebug(symlink))
837                 printf(ARGS(symlink, "%s, %s"), path, to);
838 #endif
839         error = kern_symlink(td, path, to, UIO_SYSSPACE);
840         LFREEPATH(path);
841         LFREEPATH(to);
842         return (error);
843 }
844 
845 int
846 linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
847 {
848         char *path, *to;
849         int error, dfd;
850 
851         dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
852         LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
853         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
854         error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
855         if (to == NULL) {
856                 LFREEPATH(path);
857                 return (error);
858         }
859 
860 #ifdef DEBUG
861         if (ldebug(symlinkat))
862                 printf(ARGS(symlinkat, "%s, %s"), path, to);
863 #endif
864 
865         error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
866         LFREEPATH(path);
867         LFREEPATH(to);
868         return (error);
869 }
870 
871 int
872 linux_readlink(struct thread *td, struct linux_readlink_args *args)
873 {
874         char *name;
875         int error;
876 
877         LCONVPATHEXIST(td, args->name, &name);
878 
879 #ifdef DEBUG
880         if (ldebug(readlink))
881                 printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
882                     args->count);
883 #endif
884         error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
885             args->count);
886         LFREEPATH(name);
887         return (error);
888 }
889 
890 int
891 linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
892 {
893         char *name;
894         int error, dfd;
895 
896         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
897         LCONVPATHEXIST_AT(td, args->path, &name, dfd);
898 
899 #ifdef DEBUG
900         if (ldebug(readlinkat))
901                 printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
902                     args->bufsiz);
903 #endif
904 
905         error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
906             UIO_USERSPACE, args->bufsiz);
907         LFREEPATH(name);
908         return (error);
909 }
910 
911 int
912 linux_truncate(struct thread *td, struct linux_truncate_args *args)
913 {
914         char *path;
915         int error;