1/* @title: VFS */
2#include <errno.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 errno (*read)(struct vfs_node *node, void *buf, uint64_t size,
112 uint64_t offset);
113
114 /* write data to file */
115 enum errno (*write)(struct vfs_node *node, const void *buf, uint64_t size,
116 uint64_t offset);
117
118 /* open file with flags */
119 enum errno (*open)(struct vfs_node *node, uint32_t flags);
120
121 /* close file */
122 enum errno (*close)(struct vfs_node *node);
123
124 /* create file with given name */
125 enum errno (*create)(struct vfs_node *parent, const char *name,
126 mode_t mode);
127
128 /* make node - special devices */
129 enum errno (*mknod)(struct vfs_node *parent, const char *name, mode_t mode,
130 uint32_t dev);
131
132 /* create symbolic link */
133 enum errno (*symlink)(struct vfs_node *parent, const char *target,
134 const char *link_name);
135
136 /* mount filesystem at mountpoint */
137 enum errno (*mount)(struct vfs_node *mountpoint, struct vfs_node *target,
138 const char *name);
139
140 /* unmount filesystem at mountpoint */
141 enum errno (*unmount)(struct vfs_mount *mountpoint);
142
143 /* get file metadata */
144 enum errno (*stat)(struct vfs_node *node, struct vfs_stat *out);
145
146 /* read directory entry at index */
147 enum errno (*readdir)(struct vfs_node *node, struct vfs_dirent *out,
148 uint64_t index);
149
150 /* create directory */
151 enum errno (*mkdir)(struct vfs_node *parent, const char *name, mode_t mode);
152
153 /* remove directory */
154 enum errno (*rmdir)(struct vfs_node *parent, const char *name);
155
156 /* delete file */
157 enum errno (*unlink)(struct vfs_node *parent, const char *name);
158
159 /* rename/move file or directory */
160 enum errno (*rename)(struct vfs_node *old_parent, const char *old_name,
161 struct vfs_node *new_parent, const char *new_name);
162
163 /* resize file to given length */
164 enum errno (*truncate)(struct vfs_node *node, uint64_t length);
165
166 /* read symlink into target buffer */
167 enum errno (*readlink)(struct vfs_node *node, char *buf, uint64_t size);
168
169 /* create hard link to target */
170 enum errno (*link)(struct vfs_node *parent, struct vfs_node *target,
171 const char *link_name);
172
173 /* change file permissions */
174 enum errno (*chmod)(struct vfs_node *node, mode_t mode);
175
176 /* change file ownership */
177 enum errno (*chown)(struct vfs_node *node, uid_t uid, gid_t gid);
178
179 /* update access times, unix time */
180 enum errno (*utime)(struct vfs_node *node, uint64_t atime, uint64_t mtime);
181
182 /* deallocate node */
183 enum errno (*destroy)(struct vfs_node *node);
184
185 /* find node by name */
186 enum errno (*finddir)(struct vfs_node *node, const char *name,
187 struct vfs_dirent *out);
188};
189
190struct vfs_mount {
191 struct vfs_node *mount_point; /* vfs_node of the mountpoint */
192 struct vfs_mount *mount_mount; /* mount representing mountpoint */
193 struct vfs_node *root; /* root of the mounted filesystem */
194 const struct vfs_ops *ops; /* filesystem operation interface */
195 char name[256];
196 void *fs_data; /* optional filesystem driver data */
197};
198
199struct vfs_node {
200 enum fs_type fs_type; /* filesystem type */
201 uint64_t open_handles; /* how many things have this open */
202 uint64_t unique_id; /* exclusively unique ID - one per node */
203 uint32_t flags;
204 mode_t mode;
205 uint64_t size;
206 uid_t uid;
207 gid_t gid;
208 uint64_t mtime;
209 uint64_t atime;
210
211 void *fs_data; /* optional filesystem driver data */
212 void *fs_node_data; /* optional filesystem driver data */
213 struct vfs_mount *child_mount; /* NULL if no child is mounted */
214
215 const struct vfs_ops *ops;
216};
217
218void vfs_node_print(const struct vfs_node *node);
219enum errno vfs_mount(struct vfs_node *mountpoint, struct vfs_node *target,
220 const char *name);
221enum errno vfs_unmount(struct vfs_mount *mountpoint);
222struct vfs_node *vfs_finddir(struct vfs_node *node, const char *fname);
223