3 * - Kernel Status Driver
12 #define VERSION ((0 << 8) | (1)) // 0.01
15 typedef struct sSysFS_Ent
17 struct sSysFS_Ent *Next;
18 struct sSysFS_Ent *ListNext;
19 struct sSysFS_Ent *Parent;
25 int SysFS_Install(char **Arguments);
26 int SysFS_IOCtl(tVFS_Node *Node, int Id, void *Data);
29 int SysFS_RegisterFile(const char *Path, const char *Data, int Length);
30 int SysFS_UpdateFile(int ID, const char *Data, int Length);
31 int SysFS_RemoveFile(int ID);
34 int SysFS_Comm_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]);
35 tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags);
36 size_t SysFS_Comm_ReadFile(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
37 void SysFS_Comm_CloseFile(tVFS_Node *Node);
40 extern tSysFS_Ent gSysFS_Version; // Defined Later
41 extern tSysFS_Ent gSysFS_Root; // Defined Later
42 MODULE_DEFINE(0, VERSION, SysFS, SysFS_Install, NULL, NULL);
43 tVFS_NodeType gSysFS_FileNodeType = {
44 .TypeName = "SysFS File",
45 .Read = SysFS_Comm_ReadFile
47 tVFS_NodeType gSysFS_DirNodeType = {
48 .TypeName = "SysFS Dir",
49 .ReadDir = SysFS_Comm_ReadDir,
50 .FindDir = SysFS_Comm_FindDir
52 tSysFS_Ent gSysFS_Version_Kernel = {
53 .Parent = &gSysFS_Version, // Parent
55 .Inode = 1, // File #1
57 .ImplInt = (Uint)&gSysFS_Version_Kernel, // Self-Link
60 .ACLs = &gVFS_ACL_EveryoneRO,
61 .Type = &gSysFS_FileNodeType
65 tSysFS_Ent gSysFS_Version = {
66 .Parent = &gSysFS_Root,
69 .ImplPtr = &gSysFS_Version_Kernel,
70 .ImplInt = (Uint)&gSysFS_Version, // Self-Link
72 .ACLs = &gVFS_ACL_EveryoneRX,
73 .Flags = VFS_FFLAG_DIRECTORY,
74 .Type = &gSysFS_DirNodeType
78 // Root of the SysFS tree (just used to keep the code clean)
79 tSysFS_Ent gSysFS_Root = {
84 .ImplPtr = &gSysFS_Version,
85 .ImplInt = (Uint)&gSysFS_Root // Self-Link
89 tDevFS_Driver gSysFS_DriverInfo = {
93 .ACLs = &gVFS_ACL_EveryoneRX,
94 .Flags = VFS_FFLAG_DIRECTORY,
95 .ImplPtr = &gSysFS_Version,
96 .Size = sizeof(gSysFS_Root)/sizeof(tSysFS_Ent),
97 .Type = &gSysFS_DirNodeType
100 int giSysFS_NextFileID = 2;
101 tSysFS_Ent *gSysFS_FileList;
105 * \fn int SysFS_Install(char **Options)
106 * \brief Installs the SysFS Driver
108 int SysFS_Install(char **Options)
110 gSysFS_Version_Kernel.Node.Size = strlen(gsBuildInfo);
111 gSysFS_Version_Kernel.Node.ImplPtr = (void*)gsBuildInfo;
113 DevFS_AddDevice( &gSysFS_DriverInfo );
114 return MODULE_ERR_OK;
118 * \fn int SysFS_RegisterFile(char *Path, char *Data, int Length)
119 * \brief Registers a file (buffer) for the user to be able to read from
120 * \param Path Path for the file to be accessable from (relative to SysFS root)
121 * \param Data Pointer to the data buffer (must be non-volatile)
122 * \param Length Length of the data buffer
123 * \return The file's identifier
125 int SysFS_RegisterFile(const char *Path, const char *Data, int Length)
129 tSysFS_Ent *ent = NULL;
130 tSysFS_Ent *child, *prev;
132 // Find parent directory
133 while( (tmp = strpos(&Path[start], '/')) != -1 )
138 child = ent->Node.ImplPtr;
140 child = gSysFS_DriverInfo.RootNode.ImplPtr;
141 for( ; child; prev = child, child = child->Next )
143 if( strncmp( &Path[start], child->Name, tmp+1 ) == '/' )
147 // Need a new directory?
150 child = calloc( 1, sizeof(tSysFS_Ent)+tmp+1 );
152 Log_Error("SysFS", "calloc(%i) failure", sizeof(tSysFS_Ent)+tmp+1);
156 memcpy(child->Name, &Path[start], tmp);
157 child->Name[tmp] = '\0';
159 child->Node.Inode = 0;
160 child->Node.ImplPtr = NULL;
161 child->Node.ImplInt = (Uint)child; // Uplink
162 child->Node.NumACLs = 1;
163 child->Node.ACLs = &gVFS_ACL_EveryoneRX;
164 child->Node.Flags = VFS_FFLAG_DIRECTORY;
165 child->Node.Type = &gSysFS_DirNodeType;
168 ent->Node.ImplPtr = child;
170 gSysFS_DriverInfo.RootNode.ImplPtr = child;
171 // ^^^ Impossible (There is already /Version)
178 gSysFS_DriverInfo.RootNode.Size ++;
179 Log_Log("SysFS", "Added directory '%.*s'", tmp, &Path[start]);
180 Log_Log("SysFS", "Added directory '%.*s'", tmp, child->Name);
188 // ent: Parent tSysFS_Ent or NULL
189 // start: beginning of last path element
191 // Check if the name is taken
194 child = ent->Node.ImplPtr;
196 child = gSysFS_DriverInfo.RootNode.ImplPtr;
197 for( ; child; child = child->Next )
199 if( strcmp( &Path[start], child->Name ) == 0 )
203 Log_Warning("SysFS", "'%s' is taken (in '%s')", &Path[start], Path);
208 child = calloc( 1, sizeof(tSysFS_Ent)+strlen(&Path[start])+1 );
210 strcpy(child->Name, &Path[start]);
213 child->Node.Inode = giSysFS_NextFileID++;
214 child->Node.ImplPtr = (void*)Data;
215 child->Node.ImplInt = (Uint)child; // Uplink
216 child->Node.Size = Length;
217 child->Node.NumACLs = 1;
218 child->Node.ACLs = &gVFS_ACL_EveryoneRO;
219 child->Node.Type = &gSysFS_FileNodeType;
221 // Add to parent's child list
224 child->Next = ent->Node.ImplPtr;
225 ent->Node.ImplPtr = child;
228 gSysFS_DriverInfo.RootNode.Size ++;
229 child->Next = gSysFS_DriverInfo.RootNode.ImplPtr;
230 gSysFS_DriverInfo.RootNode.ImplPtr = child;
232 // Add to global file list
233 child->ListNext = gSysFS_FileList;
234 gSysFS_FileList = child;
236 Log_Log("SysFS", "Added '%s' (%p)", Path, Data);
238 return child->Node.Inode;
242 * \fn int SysFS_UpdateFile(int ID, char *Data, int Length)
243 * \brief Updates a file
244 * \param ID Identifier returned by ::SysFS_RegisterFile
245 * \param Data Pointer to the data buffer
246 * \param Length Length of the data buffer
247 * \return Boolean Success
249 int SysFS_UpdateFile(int ID, const char *Data, int Length)
253 for( ent = gSysFS_FileList; ent; ent = ent->Next )
255 // It's a reverse sorted list
256 if(ent->Node.Inode < (Uint64)ID)
258 if(ent->Node.Inode == (Uint64)ID)
260 ent->Node.ImplPtr = (void*)Data;
261 ent->Node.Size = Length;
270 * \fn int SysFS_RemoveFile(int ID)
271 * \brief Removes a file from user access
272 * \param ID Identifier returned by ::SysFS_RegisterFile
273 * \return Boolean Success
274 * \note If a handle is still open to the file, it will be invalidated
276 int SysFS_RemoveFile(int ID)
279 tSysFS_Ent *ent, *parent, *prev;
282 for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->ListNext )
284 // It's a reverse sorted list
285 if(ent->Node.Inode <= (Uint64)ID) break;
287 if( !ent || ent->Node.Inode != (Uint64)ID) {
288 Log_Notice("SysFS", "ID %i not present", ID);
292 // Set up for next part
294 parent = file->Parent;
296 // Remove from file list
298 prev->ListNext = file->ListNext;
300 gSysFS_FileList = file->ListNext;
302 file->Node.ImplPtr = NULL;
304 // Clean out of parent directory
307 for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
309 if( ent == file ) break;
312 Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
316 // Remove from parent directory
318 prev->Next = ent->Next;
320 parent->Node.ImplPtr = ent->Next;
322 // Free if not in use
323 if(file->Node.ReferenceCount == 0) {
327 if( parent->Node.ImplPtr )
330 // Remove parent from the tree
332 parent = parent->Parent;
339 * \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
340 * \brief Reads from a SysFS directory
342 int SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
344 tSysFS_Ent *child = (tSysFS_Ent*)Node->ImplPtr;
345 if(Pos < 0 || (Uint64)Pos >= Node->Size)
348 for( ; child; child = child->Next, Pos-- )
351 strncpy(Dest, child->Name, FILENAME_MAX);
359 * \fn tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
360 * \brief Find a file in a SysFS directory
362 tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags)
364 tSysFS_Ent *child = (tSysFS_Ent*)Node->ImplPtr;
366 for( ; child; child = child->Next )
368 if( strcmp(child->Name, Filename) == 0 )
376 * \brief Read from an exposed buffer
378 size_t SysFS_Comm_ReadFile(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
380 if( Offset > Node->Size ) return -1;
381 if( Length > Node->Size ) Length = Node->Size;
382 if( Offset + Length > Node->Size) Length = Node->Size - Offset;
385 memcpy(Buffer, (void*)((Uint)Node->ImplPtr+(Uint)Offset), Length);
393 * \fn void SysFS_Comm_CloseFile(tVFS_Node *Node)
394 * \brief Closes an open file
395 * \param Node Node to close
397 void SysFS_Comm_CloseFile(tVFS_Node *Node)
400 Node->ReferenceCount --;
401 if( Node->ReferenceCount > 0 ) return;
403 // Check if it is still valid
404 if( Node->ImplPtr ) return;
407 free( (void*)Node->ImplInt );