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