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