1 //===-- Convert Statfs to Statvfs -------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_LIBC_SRC_SYS_STATVFS_LINUX_STATFS_TO_STATVFS_H
10 #define LLVM_LIBC_SRC_SYS_STATVFS_LINUX_STATFS_TO_STATVFS_H
11
12 #include "llvm-libc-types/struct_statvfs.h"
13 #include "src/__support/CPP/optional.h"
14 #include "src/__support/OSUtil/syscall.h"
15 #include "src/__support/macros/attributes.h"
16 #include "src/errno/libc_errno.h"
17 #include <asm/statfs.h>
18 #include <sys/syscall.h>
19 namespace LIBC_NAMESPACE {
20
21 namespace statfs_utils {
22 #ifdef SYS_statfs64
23 using LinuxStatFs = statfs64;
24 #else
25 using LinuxStatFs = statfs;
26 #endif
27
28 // Linux kernel set an additional flag to f_flags. Libc should mask it out.
29 LIBC_INLINE_VAR constexpr decltype(LinuxStatFs::f_flags) ST_VALID = 0x0020;
30
linux_statfs(const char * path)31 LIBC_INLINE cpp::optional<LinuxStatFs> linux_statfs(const char *path) {
32 // The kernel syscall routine checks the validity of the path before filling
33 // the statfs structure. So, it is possible that the result is not initialized
34 // after the syscall. Since the struct is trvial, the compiler will generate
35 // pattern filling for the struct.
36 LinuxStatFs result;
37 // On 32-bit platforms, original statfs cannot handle large file systems.
38 // In such cases, SYS_statfs64 is defined and should be used.
39 #ifdef SYS_statfs64
40 int ret = syscall_impl<int>(SYS_statfs64, path, sizeof(result), &result);
41 #else
42 int ret = syscall_impl<int>(SYS_statfs, path, &result);
43 #endif
44 if (ret < 0) {
45 libc_errno = -ret;
46 return cpp::nullopt;
47 }
48 result.f_flags &= ~ST_VALID;
49 return result;
50 }
51
linux_fstatfs(int fd)52 LIBC_INLINE cpp::optional<LinuxStatFs> linux_fstatfs(int fd) {
53 // The kernel syscall routine checks the validity of the path before filling
54 // the statfs structure. So, it is possible that the result is not initialized
55 // after the syscall. Since the struct is trvial, the compiler will generate
56 // pattern filling for the struct.
57 LinuxStatFs result;
58 // On 32-bit platforms, original fstatfs cannot handle large file systems.
59 // In such cases, SYS_fstatfs64 is defined and should be used.
60 #ifdef SYS_fstatfs64
61 int ret = syscall_impl<int>(SYS_fstatfs64, fd, sizeof(result), &result);
62 #else
63 int ret = syscall_impl<int>(SYS_fstatfs, fd, &result);
64 #endif
65 if (ret < 0) {
66 libc_errno = -ret;
67 return cpp::nullopt;
68 }
69 result.f_flags &= ~ST_VALID;
70 return result;
71 }
72
73 // must use 'struct' tag to refer to type 'statvfs' in this scope. There will be
74 // a function in the same namespace with the same name. For consistency, we use
75 // struct prefix for all statvfs/statfs related types.
statfs_to_statvfs(const LinuxStatFs & in)76 LIBC_INLINE struct statvfs statfs_to_statvfs(const LinuxStatFs &in) {
77 struct statvfs out;
78 out.f_bsize = in.f_bsize;
79 out.f_frsize = in.f_frsize;
80 out.f_blocks = in.f_blocks;
81 out.f_bfree = in.f_bfree;
82 out.f_bavail = in.f_bavail;
83 out.f_files = in.f_files;
84 out.f_ffree = in.f_ffree;
85 out.f_favail = in.f_ffree;
86 out.f_fsid = in.f_fsid.val[0] |
87 static_cast<decltype(out.f_fsid)>(in.f_fsid.val[1]) << 32;
88 out.f_flag = in.f_flags;
89 out.f_namemax = in.f_namelen;
90 return out;
91 }
92 } // namespace statfs_utils
93 } // namespace LIBC_NAMESPACE
94
95 #endif // LLVM_LIBC_SRC_SYS_STATVFS_LINUX_STATFS_TO_STATVFS_H
96