3 * - Kernel Status Driver
12 #define VERSION ((0 << 8) | (1)) // 0.01
13 #define KERNEL_VERSION_STRING ("Acess2 " EXPAND_STR(KERNEL_VERSION) " build " EXPAND_STR(BUILD_NUM))
16 typedef struct sSysFS_Ent
18 struct sSysFS_Ent *Next;
19 struct sSysFS_Ent *ListNext;
20 struct sSysFS_Ent *Parent;
26 int SysFS_Install(char **Arguments);
27 int SysFS_IOCtl(tVFS_Node *Node, int Id, void *Data);
30 int SysFS_RegisterFile(const char *Path, const char *Data, int Length);
31 int SysFS_UpdateFile(int ID, const char *Data, int Length);
32 int SysFS_RemoveFile(int ID);
35 char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Id);
36 tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename);
37 Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
38 void SysFS_Comm_CloseFile(tVFS_Node *Node);
41 extern tSysFS_Ent gSysFS_Version; // Defined Later
42 extern tSysFS_Ent gSysFS_Root; // Defined Later
43 MODULE_DEFINE(0, VERSION, SysFS, SysFS_Install, NULL, NULL);
44 tSysFS_Ent gSysFS_Version_Kernel = {
46 &gSysFS_Version, // Parent
48 .Inode = 1, // File #1
49 .ImplPtr = (void*)KERNEL_VERSION_STRING,
50 .ImplInt = (Uint)&gSysFS_Version_Kernel, // Self-Link
51 .Size = sizeof(KERNEL_VERSION_STRING)-1,
53 .ACLs = &gVFS_ACL_EveryoneRO,
54 .Read = SysFS_Comm_ReadFile
58 tSysFS_Ent gSysFS_Version = {
63 .ImplPtr = &gSysFS_Version_Kernel,
64 .ImplInt = (Uint)&gSysFS_Version, // Self-Link
66 .ACLs = &gVFS_ACL_EveryoneRX,
67 .Flags = VFS_FFLAG_DIRECTORY,
68 .ReadDir = SysFS_Comm_ReadDir,
69 .FindDir = SysFS_Comm_FindDir
73 // Root of the SysFS tree (just used to keep the code clean)
74 tSysFS_Ent gSysFS_Root = {
79 .ImplPtr = &gSysFS_Version,
80 .ImplInt = (Uint)&gSysFS_Root // Self-Link
84 tDevFS_Driver gSysFS_DriverInfo = {
88 .ACLs = &gVFS_ACL_EveryoneRX,
89 .Flags = VFS_FFLAG_DIRECTORY,
90 .ImplPtr = &gSysFS_Version,
91 .Size = sizeof(gSysFS_Root)/sizeof(tSysFS_Ent),
92 .ReadDir = SysFS_Comm_ReadDir,
93 .FindDir = SysFS_Comm_FindDir,
97 int giSysFS_NextFileID = 2;
98 tSysFS_Ent *gSysFS_FileList;
102 * \fn int SysFS_Install(char **Options)
103 * \brief Installs the SysFS Driver
105 int SysFS_Install(char **Options)
107 DevFS_AddDevice( &gSysFS_DriverInfo );
108 return MODULE_ERR_OK;
112 * \fn int SysFS_RegisterFile(char *Path, char *Data, int Length)
113 * \brief Registers a file (buffer) for the user to be able to read from
114 * \param Path Path for the file to be accessable from (relative to SysFS root)
115 * \param Data Pointer to the data buffer (must be non-volatile)
116 * \param Length Length of the data buffer
117 * \return The file's identifier
119 int SysFS_RegisterFile(const char *Path, const char *Data, int Length)
123 tSysFS_Ent *ent = NULL;
124 tSysFS_Ent *child, *prev;
126 // Find parent directory
127 while( (tmp = strpos(&Path[start], '/')) != -1 )
132 child = ent->Node.ImplPtr;
134 child = gSysFS_DriverInfo.RootNode.ImplPtr;
135 for( ; child; prev = child, child = child->Next )
137 if( strncmp( &Path[start], child->Name, tmp+1 ) == '/' )
141 // Need a new directory?
144 child = calloc( 1, sizeof(tSysFS_Ent)+tmp+1 );
146 memcpy(child->Name, &Path[start], tmp);
147 child->Name[tmp] = '\0';
149 child->Node.Inode = 0;
150 child->Node.ImplPtr = NULL;
151 child->Node.ImplInt = (Uint)child; // Uplink
152 child->Node.NumACLs = 1;
153 child->Node.ACLs = &gVFS_ACL_EveryoneRX;
154 child->Node.Flags = VFS_FFLAG_DIRECTORY;
155 child->Node.ReadDir = SysFS_Comm_ReadDir;
156 child->Node.FindDir = SysFS_Comm_FindDir;
159 ent->Node.ImplPtr = child;
161 gSysFS_DriverInfo.RootNode.ImplPtr = child;
162 // ^^^ Impossible (There is already /Version)
169 gSysFS_DriverInfo.RootNode.Size ++;
170 Log_Log("SysFS", "Added directory '%s'", child->Name);
178 // ent: Parent tSysFS_Ent or NULL
179 // start: beginning of last path element
181 // Check if the name is taken
184 child = ent->Node.ImplPtr;
186 child = gSysFS_DriverInfo.RootNode.ImplPtr;
187 for( ; child; child = child->Next )
189 if( strcmp( &Path[start], child->Name ) == 0 )
193 Log_Warning("SysFS", "'%s' is taken (in '%s')\n", &Path[start], Path);
198 child = calloc( 1, sizeof(tSysFS_Ent)+strlen(&Path[start])+1 );
200 strcpy(child->Name, &Path[start]);
203 child->Node.Inode = giSysFS_NextFileID++;
204 child->Node.ImplPtr = (void*)Data;
205 child->Node.ImplInt = (Uint)child; // Uplink
206 child->Node.Size = Length;
207 child->Node.NumACLs = 1;
208 child->Node.ACLs = &gVFS_ACL_EveryoneRO;
209 child->Node.Read = SysFS_Comm_ReadFile;
210 child->Node.Close = SysFS_Comm_CloseFile;
212 // Add to parent's child list
215 child->Next = ent->Node.ImplPtr;
216 ent->Node.ImplPtr = child;
219 gSysFS_DriverInfo.RootNode.Size ++;
220 child->Next = gSysFS_DriverInfo.RootNode.ImplPtr;
221 gSysFS_DriverInfo.RootNode.ImplPtr = child;
223 // Add to global file list
224 child->ListNext = gSysFS_FileList;
225 gSysFS_FileList = child;
227 Log_Log("SysFS", "Added '%s' (%p)", Path, Data);
229 return child->Node.Inode;
233 * \fn int SysFS_UpdateFile(int ID, char *Data, int Length)
234 * \brief Updates a file
235 * \param ID Identifier returned by ::SysFS_RegisterFile
236 * \param Data Pointer to the data buffer
237 * \param Length Length of the data buffer
238 * \return Boolean Success
240 int SysFS_UpdateFile(int ID, const char *Data, int Length)
244 for( ent = gSysFS_FileList; ent; ent = ent->Next )
246 // It's a reverse sorted list
247 if(ent->Node.Inode < ID) return 0;
248 if(ent->Node.Inode == ID)
250 ent->Node.ImplPtr = (void*)Data;
251 ent->Node.Size = Length;
260 * \fn int SysFS_RemoveFile(int ID)
261 * \brief Removes a file from user access
262 * \param ID Identifier returned by ::SysFS_RegisterFile
263 * \return Boolean Success
264 * \note If a handle is still open to the file, it will be invalidated
266 int SysFS_RemoveFile(int ID)
269 tSysFS_Ent *ent, *parent, *prev;
272 for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->Next )
274 // It's a reverse sorted list
275 if(ent->Node.Inode < ID) return 0;
276 if(ent->Node.Inode == ID) break;
281 // Set up for next part
283 parent = file->Parent;
285 // Remove from file list
287 prev->ListNext = file->ListNext;
289 gSysFS_FileList = file->ListNext;
291 file->Node.ImplPtr = NULL;
293 // Search parent directory
294 for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
296 if( ent == file ) break;
299 Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
303 // Remove from parent directory
305 prev->Next = ent->Next;
307 parent->Node.ImplPtr = ent->Next;
309 // Free if not in use
310 if(file->Node.ReferenceCount == 0)
317 * \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
318 * \brief Reads from a SysFS directory
320 char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
322 tSysFS_Ent *child = (tSysFS_Ent*)Node->ImplPtr;
323 if(Pos < 0 || Pos >= Node->Size) return NULL;
325 for( ; child; child = child->Next, Pos-- )
327 if( Pos == 0 ) return strdup(child->Name);
333 * \fn tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
334 * \brief Find a file in a SysFS directory
336 tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
338 tSysFS_Ent *child = (tSysFS_Ent*)Node->ImplPtr;
340 for( ; child; child = child->Next )
342 if( strcmp(child->Name, Filename) == 0 )
350 * \fn Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
351 * \brief Read from an exposed buffer
353 Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
355 if( Offset > Node->Size ) return -1;
356 if( Length > Node->Size ) Length = Node->Size;
357 if( Offset + Length > Node->Size) Length = Node->Size - Offset;
360 memcpy(Buffer, (void*)((Uint)Node->ImplPtr+(Uint)Offset), Length);
368 * \fn void SysFS_Comm_CloseFile(tVFS_Node *Node)
369 * \brief Closes an open file
370 * \param Node Node to close
372 void SysFS_Comm_CloseFile(tVFS_Node *Node)
375 Node->ReferenceCount --;
376 if( Node->ReferenceCount > 0 ) return;
378 // Check if it is still valid
379 if( Node->ImplPtr ) return;
382 free( (void*)Node->ImplInt );