1/* @title: VFS */
2#include <err.h>
3#include <fs/detect.h>
4#include <stdbool.h>
5#include <stdint.h>
6#include <types/types.h>
7#pragma once
8
9// TODO: flags on file creation
10
11struct vfs_node;
12struct vfs_mount;
13
14#define VFS_NAME_MAX 256 // this because of ext2
15
16/* mode stuff */
17#define VFS_MODE_FILE 0x8000U // 1000 << 12
18#define VFS_MODE_DIR 0x4000U // 0100 << 12
19#define VFS_MODE_SYMLINK 0xA000U // 1010 << 12
20#define VFS_MODE_CHARDEV 0x2000U // 0010 << 12
21#define VFS_MODE_BLOCKDEV 0x6000U // 0110 << 12
22#define VFS_MODE_PIPE 0x1000U // 0001 << 12
23#define VFS_MODE_SOCKET 0xC000U // 1100 << 12
24
25#define VFS_MODE_O_READ 0x0100U // 0400 (bit 8)
26#define VFS_MODE_O_WRITE 0x0080U // 0200 (bit 7)
27#define VFS_MODE_O_EXEC 0x0040U // 0100 (bit 6)
28
29#define VFS_MODE_G_READ 0x0020U // 0040 (bit 5)
30#define VFS_MODE_G_WRITE 0x0010U // 0020 (bit 4)
31#define VFS_MODE_G_EXEC 0x0008U // 0010 (bit 3)
32
33#define VFS_MODE_R_READ 0x0004U // 0004 (bit 2)
34#define VFS_MODE_R_WRITE 0x0002U // 0002 (bit 1)
35#define VFS_MODE_R_EXEC 0x0001U // 0001 (bit 0)
36
37#define VFS_MODE_READ (VFS_MODE_O_READ | VFS_MODE_G_READ | VFS_MODE_R_READ)
38#define VFS_MODE_WRITE (VFS_MODE_O_WRITE | VFS_MODE_G_WRITE | VFS_MODE_R_WRITE)
39#define VFS_MODE_EXEC (VFS_MODE_O_EXEC | VFS_MODE_G_EXEC | VFS_MODE_R_EXEC)
40
41#define VFS_MODE_TYPE_MASK 0xF000U
42
43/* clang-format off */
44enum vfs_node_flags : uint32_t {
45 VFS_NODE_NONE = 0x0000, // No flags
46 VFS_NODE_MOUNTPOINT = 0x0001, // This node is a mountpoint
47 VFS_NODE_SYMLINK = 0x0002, // This node is a symlink
48 VFS_NODE_HIDDEN = 0x0004, // Should be hidden from directory listings
49 VFS_NODE_DEVICE = 0x0008, // This node represents a device (char/block)
50 VFS_NODE_PIPE = 0x0010, // Pipe or FIFO
51 VFS_NODE_SOCKET = 0x0020, // Unix domain socket
52 VFS_NODE_SYNC = 0x0030,
53 VFS_NODE_TEMPORARY = 0x0040, // Temporary/in-memory (e.g., tmpfs)
54 VFS_NODE_NOATIME = 0x0080, // Access time updates disabled
55 VFS_NODE_APPENDONLY = 0x0100, // Only allows appending
56 VFS_NODE_IMMUTABLE = 0x0200, // Cannot be modified
57 VFS_NODE_NOFOLLOW = 0x0400, // Symlink should not be followed
58 VFS_NODE_IN_USE = 0x0800, // Open count > 0 (used internally)
59 VFS_NODE_DIRSYNC = 0x1000,
60};
61/* clang-format on */
62
63enum vfs_open_opts : uint32_t {
64 VFS_OPEN_READ = 0x01, // Open for reading
65 VFS_OPEN_WRITE = 0x02, // Open for writing
66 VFS_OPEN_RDWR = VFS_OPEN_READ | VFS_OPEN_WRITE,
67
68 VFS_OPEN_APPEND = 0x04, // Writes go to end of file
69 VFS_OPEN_CREAT = 0x08, // Create if it doesn't exist
70 VFS_OPEN_TRUNC = 0x10, // Truncate to 0 size if it exists
71 VFS_OPEN_EXCL = 0x20, // Fail if file exists (with CREAT)
72 VFS_OPEN_DIR = 0x40, // Must be a directory
73 VFS_OPEN_SYMLINK_NOFOLLOW = 0x80, // Don’t follow final symlink
74
75 VFS_OPEN_NONBLOCK = 0x100, // Non-blocking I/O (device nodes/pipes)
76 VFS_OPEN_SYNC = 0x200, // Synchronous writes
77 VFS_OPEN_NOATIME = 0x400, // Don’t update access time
78};
79
80struct vfs_stat {
81 mode_t mode;
82 uint64_t size;
83
84 uint64_t inode; // inode number
85 uint32_t nlink; // Link count
86
87 /* access time */
88 uint64_t atime;
89
90 /* modification time */
91 uint64_t mtime;
92
93 /* creation time */
94 uint64_t ctime;
95
96 /* what fields here are actually real */
97 uint16_t present_mask;
98};
99
100struct vfs_dirent {
101 char name[VFS_NAME_MAX];
102 mode_t mode;
103 struct vfs_node *node;
104 void *dirent_data;
105};
106
107struct vfs_node;
108struct vfs_ops {
109
110 /* read data from file */
111 enum err (*read)(struct vfs_node *node, void *buf, uint64_t size,
112 uint64_t offset);
113
114 /* write data to file */
115 enum err (*write)(struct vfs_node *node, const void *buf, uint64_t size,
116 uint64_t offset);
117
118 /* open file with flags */
119 enum err (*open)(struct vfs_node *node, uint32_t flags);
120
121 /* close file */
122 enum err (*close)(struct vfs_node *node);
123
124 /* create file with given name */
125 enum err (*create)(struct vfs_node *parent, const char *name, mode_t mode);
126
127 /* make node - special devices */
128 enum err (*mknod)(struct vfs_node *parent, const char *name, mode_t mode,
129 uint32_t dev);
130
131 /* create symbolic link */
132 enum err (*symlink)(struct vfs_node *parent, const char *target,
133 const char *link_name);
134
135 /* mount filesystem at mountpoint */
136 enum err (*mount)(struct vfs_node *mountpoint, struct vfs_node *target,
137 const char *name);
138
139 /* unmount filesystem at mountpoint */
140 enum err (*unmount)(struct vfs_mount *mountpoint);
141
142 /* get file metadata */
143 enum err (*stat)(struct vfs_node *node, struct vfs_stat *out);
144
145 /* read directory entry at index */
146 enum err (*readdir)(struct vfs_node *node, struct vfs_dirent *out,
147 uint64_t index);
148
149 /* create directory */
150 enum err (*mkdir)(struct vfs_node *parent, const char *name, mode_t mode);
151
152 /* remove directory */
153 enum err (*rmdir)(struct vfs_node *parent, const char *name);
154
155 /* delete file */
156 enum err (*unlink)(struct vfs_node *parent, const char *name);
157
158 /* rename/move file or directory */
159 enum err (*rename)(struct vfs_node *old_parent, const char *old_name,
160 struct vfs_node *new_parent, const char *new_name);
161
162 /* resize file to given length */
163 enum err (*truncate)(struct vfs_node *node, uint64_t length);
164
165 /* read symlink into target buffer */
166 enum err (*readlink)(struct vfs_node *node, char *buf, uint64_t size);
167
168 /* create hard link to target */
169 enum err (*link)(struct vfs_node *parent, struct vfs_node *target,
170 const char *link_name);
171
172 /* change file permissions */
173 enum err (*chmod)(struct vfs_node *node, mode_t mode);
174
175 /* change file ownership */
176 enum err (*chown)(struct vfs_node *node, uid_t uid, gid_t gid);
177
178 /* update access times, unix time */
179 enum err (*utime)(struct vfs_node *node, uint64_t atime, uint64_t mtime);
180
181 /* deallocate node */
182 enum err (*destroy)(struct vfs_node *node);
183
184 /* find node by name */
185 enum err (*finddir)(struct vfs_node *node, const char *name,
186 struct vfs_dirent *out);
187};
188
189struct vfs_mount {
190 struct vfs_node *mount_point; /* vfs_node of the mountpoint */
191 struct vfs_mount *mount_mount; /* mount representing mountpoint */
192 struct vfs_node *root; /* root of the mounted filesystem */
193 const struct vfs_ops *ops; /* filesystem operation interface */
194 char name[256];
195 void *fs_data; /* optional filesystem driver data */
196};
197
198struct vfs_node {
199 enum fs_type fs_type; /* filesystem type */
200 uint64_t open_handles; /* how many things have this open */
201 uint64_t unique_id; /* exclusively unique ID - one per node */
202 uint32_t flags;
203 mode_t mode;
204 uint64_t size;
205 uid_t uid;
206 gid_t gid;
207 uint64_t mtime;
208 uint64_t atime;
209
210 void *fs_data; /* optional filesystem driver data */
211 void *fs_node_data; /* optional filesystem driver data */
212 struct vfs_mount *child_mount; /* NULL if no child is mounted */
213
214 const struct vfs_ops *ops;
215};
216
217void vfs_node_print(const struct vfs_node *node);
218enum err vfs_mount(struct vfs_node *mountpoint, struct vfs_node *target,
219 const char *name);
220enum err vfs_unmount(struct vfs_mount *mountpoint);
221struct vfs_node *vfs_finddir(struct vfs_node *node, const char *fname);
222
223void vfs_clear_mounts(void);
224