1 /*
2 * Copyright (c) 2013-2023 Ali Mashtizadeh
3 * All rights reserved.
4 */
5
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <errno.h>
10
11 #include <sys/kassert.h>
12 #include <sys/kdebug.h>
13 #include <sys/spinlock.h>
14 #include <sys/disk.h>
15 #include <sys/vfs.h>
16 #include <sys/handle.h>
17
18 extern VFS *O2FS_Mount(Disk *root);
19
20 static Spinlock vfsLock;
21 static VFS *rootFS;
22 static VNode *rootNode;
23
24 static Slab vfsSlab;
25 static Slab vnodeSlab;
26
27 DEFINE_SLAB(VFS, &vfsSlab);
28 DEFINE_SLAB(VNode, &vnodeSlab);
29
30 /**
31 * VFS_MountRoot --
32 *
33 * Mount the root file system from a specific disk.
34 */
35 int
VFS_MountRoot(Disk * rootDisk)36 VFS_MountRoot(Disk *rootDisk)
37 {
38 int status;
39
40 Spinlock_Init(&vfsLock, "VFS Lock", SPINLOCK_TYPE_NORMAL);
41
42 Slab_Init(&vfsSlab, "VFS Slab", sizeof(VFS), 16);
43 Slab_Init(&vnodeSlab, "VNode Slab", sizeof(VNode), 16);
44
45 rootFS = O2FS_Mount(rootDisk);
46 if (!rootFS)
47 return -1;
48
49 status = rootFS->op->getroot(rootFS, &rootNode);
50 if (status < 0)
51 Panic("Failed to get root VNode\n");
52
53 return 0;
54 }
55
56 /**
57 * VFS_Lookup --
58 *
59 * Lookup a VNode by a path. This function recursively searches the directory
60 * heirarchy until the given path is found otherwise returns NULL if not found.
61 */
62 VNode *
VFS_Lookup(const char * path)63 VFS_Lookup(const char *path)
64 {
65 int status;
66 const char *start = path + 1;
67 const char *end = path + 1;
68 uint64_t len;
69 VNode *curNode;
70 VNode *oldNode;
71 char curName[256];
72
73 if (path[0] != '/')
74 return NULL;
75
76 status = rootFS->op->getroot(rootFS, &curNode);
77 if (status < 0)
78 Panic("Failed to get root VNode\n");
79
80 while (1) {
81 while (*end != '\0' && *end != '/')
82 end++;
83
84 len = (size_t)(end - start);
85 if (len == 0) {
86 // Handle root and trailing slash
87 return curNode;
88 }
89 if (len > 256) {
90 // Release
91 return NULL;
92 }
93
94 memcpy(curName, start, len);
95 curName[len] = '\0';
96
97 oldNode = curNode;
98 curNode = NULL;
99 status = oldNode->op->lookup(oldNode, &curNode, curName);
100 if (status < 0) {
101 // Release
102 return NULL;
103 }
104
105 // Release oldNode
106
107 if (*end == '\0') {
108 Log(vfs, "%s %lx\n", path, curNode);
109 return curNode;
110 }
111
112 start = end + 1;
113 end = end + 1;
114 }
115 }
116
117 /**
118 * VFS_Stat --
119 *
120 * Return the struct stat that contains the file and directory information for
121 * a given VNode.
122 */
123 int
VFS_Stat(const char * path,struct stat * sb)124 VFS_Stat(const char *path, struct stat *sb)
125 {
126 VNode *vn = VFS_Lookup(path);
127 if (vn == NULL)
128 return -ENOENT;
129
130 vn->op->stat(vn, sb);
131
132 // Release
133
134 return 0;
135 }
136
137 /**
138 * VFS_Open --
139 *
140 * Open a vnode for reading and writing.
141 *
142 * @param [in] fn VNode to open.
143 *
144 * @return Return status
145 */
146 int
VFS_Open(VNode * fn)147 VFS_Open(VNode *fn)
148 {
149 return fn->op->open(fn);
150 }
151
152 /**
153 * VFS_Close --
154 *
155 * Close a vnode.
156 *
157 * @param [in] fn VNode to close.
158 *
159 * @return Return status
160 */
161 int
VFS_Close(VNode * fn)162 VFS_Close(VNode *fn)
163 {
164 return fn->op->close(fn);
165 }
166
167 /**
168 * VFS_Read --
169 *
170 * Read from a vnode.
171 *
172 * @param [in] fn VNode to read from.
173 * @param [in] buf Buffer to write the data to.
174 * @param [in] off File offset in bytes.
175 * @param [in] len Length to read in bytes.
176 *
177 * @return Return status
178 */
179 int
VFS_Read(VNode * fn,void * buf,uint64_t off,uint64_t len)180 VFS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len)
181 {
182 return fn->op->read(fn, buf, off, len);
183 }
184
185 /**
186 * VFS_Write --
187 *
188 * Write from a vnode.
189 *
190 * @param [in] fn VNode to write to.
191 * @param [in] buf Buffer to read the data from.
192 * @param [in] off File offset in bytes.
193 * @param [in] len Length to read in bytes.
194 *
195 * @return Return status
196 */
197 int
VFS_Write(VNode * fn,void * buf,uint64_t off,uint64_t len)198 VFS_Write(VNode *fn, void *buf, uint64_t off, uint64_t len)
199 {
200 return fn->op->write(fn, buf, off, len);
201 }
202
203 /**
204 * VFS_ReadDir --
205 *
206 * Read a directory entry from a vnode.
207 *
208 * @param [in] fn VNode to read from.
209 * @param [in] buf Buffer to write the data to.
210 * @param [in] off Directory offset in bytes.
211 * @param [in] len Length to read in bytes.
212 *
213 * @return Return status
214 */
215 int
VFS_ReadDir(VNode * fn,void * buf,uint64_t len,uint64_t * off)216 VFS_ReadDir(VNode *fn, void *buf, uint64_t len, uint64_t *off)
217 {
218 return fn->op->readdir(fn, buf, len, off);
219 }
220
221