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 char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Id);
35 tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename);
36 Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
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 tSysFS_Ent gSysFS_Version_Kernel = {
45 &gSysFS_Version, // Parent
47 .Inode = 1, // File #1
49 .ImplInt = (Uint)&gSysFS_Version_Kernel, // Self-Link
52 .ACLs = &gVFS_ACL_EveryoneRO,
53 .Read = SysFS_Comm_ReadFile
57 tSysFS_Ent gSysFS_Version = {
62 .ImplPtr = &gSysFS_Version_Kernel,
63 .ImplInt = (Uint)&gSysFS_Version, // Self-Link
65 .ACLs = &gVFS_ACL_EveryoneRX,
66 .Flags = VFS_FFLAG_DIRECTORY,
67 .ReadDir = SysFS_Comm_ReadDir,
68 .FindDir = SysFS_Comm_FindDir
72 // Root of the SysFS tree (just used to keep the code clean)
73 tSysFS_Ent gSysFS_Root = {
78 .ImplPtr = &gSysFS_Version,
79 .ImplInt = (Uint)&gSysFS_Root // Self-Link
83 tDevFS_Driver gSysFS_DriverInfo = {
87 .ACLs = &gVFS_ACL_EveryoneRX,
88 .Flags = VFS_FFLAG_DIRECTORY,
89 .ImplPtr = &gSysFS_Version,
90 .Size = sizeof(gSysFS_Root)/sizeof(tSysFS_Ent),
91 .ReadDir = SysFS_Comm_ReadDir,
92 .FindDir = SysFS_Comm_FindDir,
96 int giSysFS_NextFileID = 2;
97 tSysFS_Ent *gSysFS_FileList;
101 * \fn int SysFS_Install(char **Options)
102 * \brief Installs the SysFS Driver
104 int SysFS_Install(char **Options)
107 const char *fmt = "Acess2 "EXPAND_STR(KERNEL_VERSION)" "EXPAND_STR(ARCHDIR)" build %i, hash %s";
108 gSysFS_Version_Kernel.Node.Size = sprintf(NULL, fmt, BUILD_NUM, gsGitHash);
109 gSysFS_Version_Kernel.Node.ImplPtr = malloc( gSysFS_Version_Kernel.Node.Size + 1 );
110 sprintf(gSysFS_Version_Kernel.Node.ImplPtr, fmt, BUILD_NUM, gsGitHash);
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 memcpy(child->Name, &Path[start], tmp);
153 child->Name[tmp] = '\0';
155 child->Node.Inode = 0;
156 child->Node.ImplPtr = NULL;
157 child->Node.ImplInt = (Uint)child; // Uplink
158 child->Node.NumACLs = 1;
159 child->Node.ACLs = &gVFS_ACL_EveryoneRX;
160 child->Node.Flags = VFS_FFLAG_DIRECTORY;
161 child->Node.ReadDir = SysFS_Comm_ReadDir;
162 child->Node.FindDir = SysFS_Comm_FindDir;
165 ent->Node.ImplPtr = child;
167 gSysFS_DriverInfo.RootNode.ImplPtr = child;
168 // ^^^ Impossible (There is already /Version)
175 gSysFS_DriverInfo.RootNode.Size ++;
176 Log_Log("SysFS", "Added directory '%s'", child->Name);
184 // ent: Parent tSysFS_Ent or NULL
185 // start: beginning of last path element
187 // Check if the name is taken
190 child = ent->Node.ImplPtr;
192 child = gSysFS_DriverInfo.RootNode.ImplPtr;
193 for( ; child; child = child->Next )
195 if( strcmp( &Path[start], child->Name ) == 0 )
199 Log_Warning("SysFS", "'%s' is taken (in '%s')\n", &Path[start], Path);
204 child = calloc( 1, sizeof(tSysFS_Ent)+strlen(&Path[start])+1 );
206 strcpy(child->Name, &Path[start]);
209 child->Node.Inode = giSysFS_NextFileID++;
210 child->Node.ImplPtr = (void*)Data;
211 child->Node.ImplInt = (Uint)child; // Uplink
212 child->Node.Size = Length;
213 child->Node.NumACLs = 1;
214 child->Node.ACLs = &gVFS_ACL_EveryoneRO;
215 child->Node.Read = SysFS_Comm_ReadFile;
216 child->Node.Close = SysFS_Comm_CloseFile;
218 // Add to parent's child list
221 child->Next = ent->Node.ImplPtr;
222 ent->Node.ImplPtr = child;
225 gSysFS_DriverInfo.RootNode.Size ++;
226 child->Next = gSysFS_DriverInfo.RootNode.ImplPtr;
227 gSysFS_DriverInfo.RootNode.ImplPtr = child;
229 // Add to global file list
230 child->ListNext = gSysFS_FileList;
231 gSysFS_FileList = child;
233 Log_Log("SysFS", "Added '%s' (%p)", Path, Data);
235 return child->Node.Inode;
239 * \fn int SysFS_UpdateFile(int ID, char *Data, int Length)
240 * \brief Updates a file
241 * \param ID Identifier returned by ::SysFS_RegisterFile
242 * \param Data Pointer to the data buffer
243 * \param Length Length of the data buffer
244 * \return Boolean Success
246 int SysFS_UpdateFile(int ID, const char *Data, int Length)
250 for( ent = gSysFS_FileList; ent; ent = ent->Next )
252 // It's a reverse sorted list
253 if(ent->Node.Inode < ID) return 0;
254 if(ent->Node.Inode == ID)
256 ent->Node.ImplPtr = (void*)Data;
257 ent->Node.Size = Length;
266 * \fn int SysFS_RemoveFile(int ID)
267 * \brief Removes a file from user access
268 * \param ID Identifier returned by ::SysFS_RegisterFile
269 * \return Boolean Success
270 * \note If a handle is still open to the file, it will be invalidated
272 int SysFS_RemoveFile(int ID)
275 tSysFS_Ent *ent, *parent, *prev;
278 for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->Next )
280 // It's a reverse sorted list
281 if(ent->Node.Inode < ID) return 0;
282 if(ent->Node.Inode == ID) break;
287 // Set up for next part
289 parent = file->Parent;
291 // Remove from file list
293 prev->ListNext = file->ListNext;
295 gSysFS_FileList = file->ListNext;
297 file->Node.ImplPtr = NULL;
299 // Search parent directory
300 for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
302 if( ent == file ) break;
305 Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
309 // Remove from parent directory
311 prev->Next = ent->Next;
313 parent->Node.ImplPtr = ent->Next;
315 // Free if not in use
316 if(file->Node.ReferenceCount == 0)
323 * \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
324 * \brief Reads from a SysFS directory
326 char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
328 tSysFS_Ent *child = (tSysFS_Ent*)Node->ImplPtr;
329 if(Pos < 0 || Pos >= Node->Size) return NULL;
331 for( ; child; child = child->Next, Pos-- )
333 if( Pos == 0 ) return strdup(child->Name);
339 * \fn tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
340 * \brief Find a file in a SysFS directory
342 tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
344 tSysFS_Ent *child = (tSysFS_Ent*)Node->ImplPtr;
346 for( ; child; child = child->Next )
348 if( strcmp(child->Name, Filename) == 0 )
356 * \fn Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
357 * \brief Read from an exposed buffer
359 Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
361 if( Offset > Node->Size ) return -1;
362 if( Length > Node->Size ) Length = Node->Size;
363 if( Offset + Length > Node->Size) Length = Node->Size - Offset;
366 memcpy(Buffer, (void*)((Uint)Node->ImplPtr+(Uint)Offset), Length);
374 * \fn void SysFS_Comm_CloseFile(tVFS_Node *Node)
375 * \brief Closes an open file
376 * \param Node Node to close
378 void SysFS_Comm_CloseFile(tVFS_Node *Node)
381 Node->ReferenceCount --;
382 if( Node->ReferenceCount > 0 ) return;
384 // Check if it is still valid
385 if( Node->ImplPtr ) return;
388 free( (void*)Node->ImplInt );