]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linux/linux_stats.c
Fix the encoding of major and minor numbers in 64-bit dev_t by restoring
[FreeBSD/FreeBSD.git] / sys / compat / linux / linux_stats.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1994-1995 Søren Schmidt
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "opt_compat.h"
33
34 #include <sys/param.h>
35 #include <sys/capsicum.h>
36 #include <sys/dirent.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 #include <sys/proc.h>
40 #include <sys/malloc.h>
41 #include <sys/mount.h>
42 #include <sys/namei.h>
43 #include <sys/stat.h>
44 #include <sys/syscallsubr.h>
45 #include <sys/systm.h>
46 #include <sys/tty.h>
47 #include <sys/vnode.h>
48 #include <sys/conf.h>
49 #include <sys/fcntl.h>
50
51 #ifdef COMPAT_LINUX32
52 #include <machine/../linux32/linux.h>
53 #include <machine/../linux32/linux32_proto.h>
54 #else
55 #include <machine/../linux/linux.h>
56 #include <machine/../linux/linux_proto.h>
57 #endif
58
59 #include <compat/linux/linux_util.h>
60 #include <compat/linux/linux_file.h>
61
62
63 static void
64 translate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
65 {
66         int major, minor;
67
68         if (vp->v_type == VCHR && vp->v_rdev != NULL &&
69             linux_driver_get_major_minor(devtoname(vp->v_rdev),
70             &major, &minor) == 0) {
71                 sb->st_rdev = (major << 8 | minor);
72         }
73 }
74
75 static int
76 linux_kern_statat(struct thread *td, int flag, int fd, char *path,
77     enum uio_seg pathseg, struct stat *sbp)
78 {
79
80         return (kern_statat(td, flag, fd, path, pathseg, sbp,
81             translate_vnhook_major_minor));
82 }
83
84 static int
85 linux_kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
86     struct stat *sbp)
87 {
88
89         return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
90 }
91
92 static int
93 linux_kern_lstat(struct thread *td, char *path, enum uio_seg pathseg,
94     struct stat *sbp)
95 {
96
97         return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
98             pathseg, sbp));
99 }
100
101 static void
102 translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
103 {
104         struct file *fp;
105         struct vnode *vp;
106         int major, minor;
107
108         /*
109          * No capability rights required here.
110          */
111         if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
112             fget(td, fd, &cap_no_rights, &fp) != 0)
113                 return;
114         vp = fp->f_vnode;
115         if (vp != NULL && vp->v_rdev != NULL &&
116             linux_driver_get_major_minor(devtoname(vp->v_rdev),
117                                          &major, &minor) == 0) {
118                 buf->st_rdev = (major << 8 | minor);
119         } else if (fp->f_type == DTYPE_PTS) {
120                 struct tty *tp = fp->f_data;
121
122                 /* Convert the numbers for the slave device. */
123                 if (linux_driver_get_major_minor(devtoname(tp->t_dev),
124                                          &major, &minor) == 0) {
125                         buf->st_rdev = (major << 8 | minor);
126                 }
127         }
128         fdrop(fp, td);
129 }
130
131 /*
132  * l_dev_t has the same encoding as dev_t in the latter's low 16 bits, so
133  * don't bother going through major() and minor().  Keep doing blind
134  * truncation, as for other fields.  The previous version didn't even do
135  * blind truncation after dev_t was expanded to 64 bits.  It failed to
136  * mask out bits 8-15 in minor().  These bits can only be nonzero in th
137  * 64-bit version.
138  *
139  * This is only used for st_dev.  st_dev is for the mounted-on device so
140  * it can't be a device that needs very special translation.  The translation
141  * of blind truncation is done here.  st_rdev is supposed to be specially
142  * translated in callers, with the blind truncation done there too and
143  * st_rdev in the native struct state abused to hold the linux st_rdev.
144  * Callers do the last step using an open-coded Linux makedev().
145  */
146 #define dev_to_ldev(d)  ((uint16_t)(d))
147
148 static int
149 newstat_copyout(struct stat *buf, void *ubuf)
150 {
151         struct l_newstat tbuf;
152
153         bzero(&tbuf, sizeof(tbuf));
154         tbuf.st_dev = dev_to_ldev(buf->st_dev);
155         tbuf.st_ino = buf->st_ino;
156         tbuf.st_mode = buf->st_mode;
157         tbuf.st_nlink = buf->st_nlink;
158         tbuf.st_uid = buf->st_uid;
159         tbuf.st_gid = buf->st_gid;
160         tbuf.st_rdev = buf->st_rdev;
161         tbuf.st_size = buf->st_size;
162         tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
163         tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
164         tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
165         tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
166         tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
167         tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
168         tbuf.st_blksize = buf->st_blksize;
169         tbuf.st_blocks = buf->st_blocks;
170
171         return (copyout(&tbuf, ubuf, sizeof(tbuf)));
172 }
173
174 int
175 linux_newstat(struct thread *td, struct linux_newstat_args *args)
176 {
177         struct stat buf;
178         char *path;
179         int error;
180
181         LCONVPATHEXIST(td, args->path, &path);
182
183 #ifdef DEBUG
184         if (ldebug(newstat))
185                 printf(ARGS(newstat, "%s, *"), path);
186 #endif
187
188         error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
189         LFREEPATH(path);
190         if (error)
191                 return (error);
192         return (newstat_copyout(&buf, args->buf));
193 }
194
195 int
196 linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
197 {
198         struct stat sb;
199         char *path;
200         int error;
201
202         LCONVPATHEXIST(td, args->path, &path);
203
204 #ifdef DEBUG
205         if (ldebug(newlstat))
206                 printf(ARGS(newlstat, "%s, *"), path);
207 #endif
208
209         error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
210         LFREEPATH(path);
211         if (error)
212                 return (error);
213         return (newstat_copyout(&sb, args->buf));
214 }
215
216 int
217 linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
218 {
219         struct stat buf;
220         int error;
221
222 #ifdef DEBUG
223         if (ldebug(newfstat))
224                 printf(ARGS(newfstat, "%d, *"), args->fd);
225 #endif
226
227         error = kern_fstat(td, args->fd, &buf);
228         translate_fd_major_minor(td, args->fd, &buf);
229         if (!error)
230                 error = newstat_copyout(&buf, args->buf);
231
232         return (error);
233 }
234
235 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
236 static int
237 stat_copyout(struct stat *buf, void *ubuf)
238 {
239         struct l_stat lbuf;
240
241         bzero(&lbuf, sizeof(lbuf));
242         lbuf.st_dev = dev_to_ldev(buf->st_dev);
243         lbuf.st_ino = buf->st_ino;
244         lbuf.st_mode = buf->st_mode;
245         lbuf.st_nlink = buf->st_nlink;
246         lbuf.st_uid = buf->st_uid;
247         lbuf.st_gid = buf->st_gid;
248         lbuf.st_rdev = buf->st_rdev;
249         lbuf.st_size = MIN(buf->st_size, INT32_MAX);
250         lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
251         lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
252         lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
253         lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
254         lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
255         lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
256         lbuf.st_blksize = buf->st_blksize;
257         lbuf.st_blocks = buf->st_blocks;
258         lbuf.st_flags = buf->st_flags;
259         lbuf.st_gen = buf->st_gen;
260
261         return (copyout(&lbuf, ubuf, sizeof(lbuf)));
262 }
263
264 int
265 linux_stat(struct thread *td, struct linux_stat_args *args)
266 {
267         struct stat buf;
268         char *path;
269         int error;
270
271         LCONVPATHEXIST(td, args->path, &path);
272
273 #ifdef DEBUG
274         if (ldebug(stat))
275                 printf(ARGS(stat, "%s, *"), path);
276 #endif
277         error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
278         if (error) {
279                 LFREEPATH(path);
280                 return (error);
281         }
282         LFREEPATH(path);
283         return (stat_copyout(&buf, args->up));
284 }
285
286 int
287 linux_lstat(struct thread *td, struct linux_lstat_args *args)
288 {
289         struct stat buf;
290         char *path;
291         int error;
292
293         LCONVPATHEXIST(td, args->path, &path);
294
295 #ifdef DEBUG
296         if (ldebug(lstat))
297                 printf(ARGS(lstat, "%s, *"), path);
298 #endif
299         error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
300         if (error) {
301                 LFREEPATH(path);
302                 return (error);
303         }
304         LFREEPATH(path);
305         return (stat_copyout(&buf, args->up));
306 }
307 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
308
309 struct l_statfs {
310         l_long          f_type;
311         l_long          f_bsize;
312         l_long          f_blocks;
313         l_long          f_bfree;
314         l_long          f_bavail;
315         l_long          f_files;
316         l_long          f_ffree;
317         l_fsid_t        f_fsid;
318         l_long          f_namelen;
319         l_long          f_frsize;
320         l_long          f_flags;
321         l_long          f_spare[4];
322 };
323
324 #define LINUX_CODA_SUPER_MAGIC  0x73757245L
325 #define LINUX_EXT2_SUPER_MAGIC  0xEF53L
326 #define LINUX_HPFS_SUPER_MAGIC  0xf995e849L
327 #define LINUX_ISOFS_SUPER_MAGIC 0x9660L
328 #define LINUX_MSDOS_SUPER_MAGIC 0x4d44L
329 #define LINUX_NCP_SUPER_MAGIC   0x564cL
330 #define LINUX_NFS_SUPER_MAGIC   0x6969L
331 #define LINUX_NTFS_SUPER_MAGIC  0x5346544EL
332 #define LINUX_PROC_SUPER_MAGIC  0x9fa0L
333 #define LINUX_UFS_SUPER_MAGIC   0x00011954L     /* XXX - UFS_MAGIC in Linux */
334 #define LINUX_ZFS_SUPER_MAGIC   0x2FC12FC1
335 #define LINUX_DEVFS_SUPER_MAGIC 0x1373L
336 #define LINUX_SHMFS_MAGIC       0x01021994
337
338 static long
339 bsd_to_linux_ftype(const char *fstypename)
340 {
341         int i;
342         static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
343                 {"ufs",     LINUX_UFS_SUPER_MAGIC},
344                 {"zfs",     LINUX_ZFS_SUPER_MAGIC},
345                 {"cd9660",  LINUX_ISOFS_SUPER_MAGIC},
346                 {"nfs",     LINUX_NFS_SUPER_MAGIC},
347                 {"ext2fs",  LINUX_EXT2_SUPER_MAGIC},
348                 {"procfs",  LINUX_PROC_SUPER_MAGIC},
349                 {"msdosfs", LINUX_MSDOS_SUPER_MAGIC},
350                 {"ntfs",    LINUX_NTFS_SUPER_MAGIC},
351                 {"nwfs",    LINUX_NCP_SUPER_MAGIC},
352                 {"hpfs",    LINUX_HPFS_SUPER_MAGIC},
353                 {"coda",    LINUX_CODA_SUPER_MAGIC},
354                 {"devfs",   LINUX_DEVFS_SUPER_MAGIC},
355                 {"tmpfs",   LINUX_SHMFS_MAGIC},
356                 {NULL,      0L}};
357
358         for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
359                 if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
360                         return (b2l_tbl[i].linux_type);
361
362         return (0L);
363 }
364
365 static int
366 bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
367 {
368 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
369         uint64_t tmp;
370
371 #define LINUX_HIBITS    0xffffffff00000000ULL
372
373         tmp = bsd_statfs->f_blocks | bsd_statfs->f_bfree | bsd_statfs->f_files |
374             bsd_statfs->f_bsize;
375         if ((bsd_statfs->f_bavail != -1 && (bsd_statfs->f_bavail & LINUX_HIBITS)) ||
376             (bsd_statfs->f_ffree != -1 && (bsd_statfs->f_ffree & LINUX_HIBITS)) ||
377             (tmp & LINUX_HIBITS))
378                 return (EOVERFLOW);
379 #undef  LINUX_HIBITS
380 #endif
381         linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
382         linux_statfs->f_bsize = bsd_statfs->f_bsize;
383         linux_statfs->f_blocks = bsd_statfs->f_blocks;
384         linux_statfs->f_bfree = bsd_statfs->f_bfree;
385         linux_statfs->f_bavail = bsd_statfs->f_bavail;
386         linux_statfs->f_ffree = bsd_statfs->f_ffree;
387         linux_statfs->f_files = bsd_statfs->f_files;
388         linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
389         linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
390         linux_statfs->f_namelen = MAXNAMLEN;
391         linux_statfs->f_frsize = bsd_statfs->f_bsize;
392         linux_statfs->f_flags = 0;
393         memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
394
395         return (0);
396 }
397
398 int
399 linux_statfs(struct thread *td, struct linux_statfs_args *args)
400 {
401         struct l_statfs linux_statfs;
402         struct statfs *bsd_statfs;
403         char *path;
404         int error;
405
406         LCONVPATHEXIST(td, args->path, &path);
407
408 #ifdef DEBUG
409         if (ldebug(statfs))
410                 printf(ARGS(statfs, "%s, *"), path);
411 #endif
412         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
413         error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
414         LFREEPATH(path);
415         if (error == 0)
416                 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
417         free(bsd_statfs, M_STATFS);
418         if (error != 0)
419                 return (error);
420         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
421 }
422
423 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
424 static void
425 bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
426 {
427
428         linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
429         linux_statfs->f_bsize = bsd_statfs->f_bsize;
430         linux_statfs->f_blocks = bsd_statfs->f_blocks;
431         linux_statfs->f_bfree = bsd_statfs->f_bfree;
432         linux_statfs->f_bavail = bsd_statfs->f_bavail;
433         linux_statfs->f_ffree = bsd_statfs->f_ffree;
434         linux_statfs->f_files = bsd_statfs->f_files;
435         linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
436         linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
437         linux_statfs->f_namelen = MAXNAMLEN;
438         linux_statfs->f_frsize = bsd_statfs->f_bsize;
439         linux_statfs->f_flags = 0;
440         memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
441 }
442
443 int
444 linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
445 {
446         struct l_statfs64 linux_statfs;
447         struct statfs *bsd_statfs;
448         char *path;
449         int error;
450
451         if (args->bufsize != sizeof(struct l_statfs64))
452                 return (EINVAL);
453
454         LCONVPATHEXIST(td, args->path, &path);
455
456 #ifdef DEBUG
457         if (ldebug(statfs64))
458                 printf(ARGS(statfs64, "%s, *"), path);
459 #endif
460         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
461         error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
462         LFREEPATH(path);
463         if (error == 0)
464                 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
465         free(bsd_statfs, M_STATFS);
466         if (error != 0)
467                 return (error);
468         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
469 }
470
471 int
472 linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
473 {
474         struct l_statfs64 linux_statfs;
475         struct statfs *bsd_statfs;
476         int error;
477
478 #ifdef DEBUG
479         if (ldebug(fstatfs64))
480                 printf(ARGS(fstatfs64, "%d, *"), args->fd);
481 #endif
482         if (args->bufsize != sizeof(struct l_statfs64))
483                 return (EINVAL);
484
485         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
486         error = kern_fstatfs(td, args->fd, bsd_statfs);
487         if (error == 0)
488                 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
489         free(bsd_statfs, M_STATFS);
490         if (error != 0)
491                 return (error);
492         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
493 }
494 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
495
496 int
497 linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
498 {
499         struct l_statfs linux_statfs;
500         struct statfs *bsd_statfs;
501         int error;
502
503 #ifdef DEBUG
504         if (ldebug(fstatfs))
505                 printf(ARGS(fstatfs, "%d, *"), args->fd);
506 #endif
507         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
508         error = kern_fstatfs(td, args->fd, bsd_statfs);
509         if (error == 0)
510                 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
511         free(bsd_statfs, M_STATFS);
512         if (error != 0)
513                 return (error);
514         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
515 }
516
517 struct l_ustat
518 {
519         l_daddr_t       f_tfree;
520         l_ino_t         f_tinode;
521         char            f_fname[6];
522         char            f_fpack[6];
523 };
524
525 int
526 linux_ustat(struct thread *td, struct linux_ustat_args *args)
527 {
528 #ifdef DEBUG
529         if (ldebug(ustat))
530                 printf(ARGS(ustat, "%ju, *"), (uintmax_t)args->dev);
531 #endif
532
533         return (EOPNOTSUPP);
534 }
535
536 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
537
538 static int
539 stat64_copyout(struct stat *buf, void *ubuf)
540 {
541         struct l_stat64 lbuf;
542
543         bzero(&lbuf, sizeof(lbuf));
544         lbuf.st_dev = dev_to_ldev(buf->st_dev);
545         lbuf.st_ino = buf->st_ino;
546         lbuf.st_mode = buf->st_mode;
547         lbuf.st_nlink = buf->st_nlink;
548         lbuf.st_uid = buf->st_uid;
549         lbuf.st_gid = buf->st_gid;
550         lbuf.st_rdev = buf->st_rdev;
551         lbuf.st_size = buf->st_size;
552         lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
553         lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
554         lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
555         lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
556         lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
557         lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
558         lbuf.st_blksize = buf->st_blksize;
559         lbuf.st_blocks = buf->st_blocks;
560
561         /*
562          * The __st_ino field makes all the difference. In the Linux kernel
563          * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
564          * but without the assignment to __st_ino the runtime linker refuses
565          * to mmap(2) any shared libraries. I guess it's broken alright :-)
566          */
567         lbuf.__st_ino = buf->st_ino;
568
569         return (copyout(&lbuf, ubuf, sizeof(lbuf)));
570 }
571
572 int
573 linux_stat64(struct thread *td, struct linux_stat64_args *args)
574 {
575         struct stat buf;
576         char *filename;
577         int error;
578
579         LCONVPATHEXIST(td, args->filename, &filename);
580
581 #ifdef DEBUG
582         if (ldebug(stat64))
583                 printf(ARGS(stat64, "%s, *"), filename);
584 #endif
585
586         error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
587         LFREEPATH(filename);
588         if (error)
589                 return (error);
590         return (stat64_copyout(&buf, args->statbuf));
591 }
592
593 int
594 linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
595 {
596         struct stat sb;
597         char *filename;
598         int error;
599
600         LCONVPATHEXIST(td, args->filename, &filename);
601
602 #ifdef DEBUG
603         if (ldebug(lstat64))
604                 printf(ARGS(lstat64, "%s, *"), args->filename);
605 #endif
606
607         error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
608         LFREEPATH(filename);
609         if (error)
610                 return (error);
611         return (stat64_copyout(&sb, args->statbuf));
612 }
613
614 int
615 linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
616 {
617         struct stat buf;
618         int error;
619
620 #ifdef DEBUG
621         if (ldebug(fstat64))
622                 printf(ARGS(fstat64, "%d, *"), args->fd);
623 #endif
624
625         error = kern_fstat(td, args->fd, &buf);
626         translate_fd_major_minor(td, args->fd, &buf);
627         if (!error)
628                 error = stat64_copyout(&buf, args->statbuf);
629
630         return (error);
631 }
632
633 int
634 linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
635 {
636         char *path;
637         int error, dfd, flag;
638         struct stat buf;
639
640         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
641                 return (EINVAL);
642         flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
643             AT_SYMLINK_NOFOLLOW : 0;
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(fstatat64))
650                 printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag);
651 #endif
652
653         error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
654         if (!error)
655                 error = stat64_copyout(&buf, args->statbuf);
656         LFREEPATH(path);
657
658         return (error);
659 }
660
661 #else /* __amd64__ && !COMPAT_LINUX32 */
662
663 int
664 linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
665 {
666         char *path;
667         int error, dfd, flag;
668         struct stat buf;
669
670         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
671                 return (EINVAL);
672         flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
673             AT_SYMLINK_NOFOLLOW : 0;
674
675         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
676         LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
677
678 #ifdef DEBUG
679         if (ldebug(newfstatat))
680                 printf(ARGS(newfstatat, "%i, %s, %i"), args->dfd, path, args->flag);
681 #endif
682
683         error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
684         if (error == 0)
685                 error = newstat_copyout(&buf, args->statbuf);
686         LFREEPATH(path);
687
688         return (error);
689 }
690
691 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
692
693 int
694 linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
695 {
696         struct mount *mp;
697         struct vnode *vp;
698         int error, save;
699
700         error = fgetvp(td, args->fd, &cap_fsync_rights, &vp);
701         if (error != 0)
702                 /*
703                  * Linux syncfs() returns only EBADF, however fgetvp()
704                  * can return EINVAL in case of file descriptor does
705                  * not represent a vnode. XXX.
706                  */
707                 return (error);
708
709         mp = vp->v_mount;
710         mtx_lock(&mountlist_mtx);
711         error = vfs_busy(mp, MBF_MNTLSTLOCK);
712         if (error != 0) {
713                 /* See comment above. */
714                 mtx_unlock(&mountlist_mtx);
715                 goto out;
716         }
717         if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
718             vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
719                 save = curthread_pflags_set(TDP_SYNCIO);
720                 vfs_msync(mp, MNT_NOWAIT);
721                 VFS_SYNC(mp, MNT_NOWAIT);
722                 curthread_pflags_restore(save);
723                 vn_finished_write(mp);
724         }
725         vfs_unbusy(mp);
726
727  out:
728         vrele(vp);
729         return (error);
730 }