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>
19namespace LIBC_NAMESPACE {
20
21namespace statfs_utils {
22#ifdef SYS_statfs64
23using LinuxStatFs = statfs64;
24#else
25using LinuxStatFs = statfs;
26#endif
27
28// Linux kernel set an additional flag to f_flags. Libc should mask it out.
29LIBC_INLINE_VAR constexpr decltype(LinuxStatFs::f_flags) ST_VALID = 0x0020;
30
31LIBC_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, ts: path, ts: &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
52LIBC_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, ts: fd, ts: &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.
76LIBC_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

source code of libc/src/sys/statvfs/linux/statfs_utils.h