Kernel - Added 'Flags' param to VFS Read/Write/FindDir
[tpg/acess2.git] / KernelLand / Kernel / drv / proc.c
1 /*
2  * Acess2
3  * - Kernel Status Driver
4  */
5 #define DEBUG   1
6 #include <acess.h>
7 #include <modules.h>
8 #include <fs_devfs.h>
9 #include <fs_sysfs.h>
10
11 // === CONSTANTS ===
12 #define VERSION ((0 << 8) | (1))        // 0.01
13
14 // === TYPES ===
15 typedef struct sSysFS_Ent
16 {
17         struct sSysFS_Ent       *Next;
18         struct sSysFS_Ent       *ListNext;
19         struct sSysFS_Ent       *Parent;
20         tVFS_Node       Node;
21         char    Name[];
22 } tSysFS_Ent;
23
24 // === PROTOTYPES ===
25  int    SysFS_Install(char **Arguments);
26  int    SysFS_IOCtl(tVFS_Node *Node, int Id, void *Data);
27
28 #if 0
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);
32 #endif
33
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);
38
39 // === GLOBALS ===
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
46         };
47 tVFS_NodeType   gSysFS_DirNodeType = {
48         .TypeName = "SysFS Dir",
49         .ReadDir = SysFS_Comm_ReadDir,
50         .FindDir = SysFS_Comm_FindDir
51         };
52 tSysFS_Ent      gSysFS_Version_Kernel = {
53         NULL, NULL,     // Nexts
54         &gSysFS_Version,        // Parent
55         {
56                 .Inode = 1,     // File #1
57                 .ImplPtr = NULL,
58                 .ImplInt = (Uint)&gSysFS_Version_Kernel,        // Self-Link
59                 .Size = 0,
60                 .NumACLs = 1,
61                 .ACLs = &gVFS_ACL_EveryoneRO,
62                 .Type = &gSysFS_FileNodeType
63         },
64         "Kernel"
65 };
66 tSysFS_Ent      gSysFS_Version = {
67         NULL, NULL,
68         &gSysFS_Root,
69         {
70                 .Size = 1,
71                 .ImplPtr = &gSysFS_Version_Kernel,
72                 .ImplInt = (Uint)&gSysFS_Version,       // Self-Link
73                 .NumACLs = 1,
74                 .ACLs = &gVFS_ACL_EveryoneRX,
75                 .Flags = VFS_FFLAG_DIRECTORY,
76                 .Type = &gSysFS_DirNodeType
77         },
78         "Version"
79 };
80 // Root of the SysFS tree (just used to keep the code clean)
81 tSysFS_Ent      gSysFS_Root = {
82         NULL, NULL,
83         NULL,
84         {
85                 .Size = 1,
86                 .ImplPtr = &gSysFS_Version,
87                 .ImplInt = (Uint)&gSysFS_Root   // Self-Link
88         },
89         "/"
90 };
91 tDevFS_Driver   gSysFS_DriverInfo = {
92         NULL, "system",
93         {
94         .NumACLs = 1,
95         .ACLs = &gVFS_ACL_EveryoneRX,
96         .Flags = VFS_FFLAG_DIRECTORY,
97         .ImplPtr = &gSysFS_Version,
98         .Size = sizeof(gSysFS_Root)/sizeof(tSysFS_Ent),
99         .Type = &gSysFS_DirNodeType
100         }
101 };
102  int    giSysFS_NextFileID = 2;
103 tSysFS_Ent      *gSysFS_FileList;
104
105 // === CODE ===
106 /**
107  * \fn int SysFS_Install(char **Options)
108  * \brief Installs the SysFS Driver
109  */
110 int SysFS_Install(char **Options)
111 {
112         gSysFS_Version_Kernel.Node.Size = strlen(gsBuildInfo);
113         gSysFS_Version_Kernel.Node.ImplPtr = (void*)gsBuildInfo;
114
115         DevFS_AddDevice( &gSysFS_DriverInfo );
116         return MODULE_ERR_OK;
117 }
118
119 /**
120  * \fn int SysFS_RegisterFile(char *Path, char *Data, int Length)
121  * \brief Registers a file (buffer) for the user to be able to read from
122  * \param Path  Path for the file to be accessable from (relative to SysFS root)
123  * \param Data  Pointer to the data buffer (must be non-volatile)
124  * \param Length        Length of the data buffer
125  * \return The file's identifier
126  */
127 int SysFS_RegisterFile(const char *Path, const char *Data, int Length)
128 {
129          int    start = 0;
130          int    tmp;
131         tSysFS_Ent      *ent = NULL;
132         tSysFS_Ent      *child, *prev;
133         
134         // Find parent directory
135         while( (tmp = strpos(&Path[start], '/')) != -1 )
136         {
137                 prev = NULL;
138                 
139                 if(ent)
140                         child = ent->Node.ImplPtr;
141                 else
142                         child = gSysFS_DriverInfo.RootNode.ImplPtr;
143                 for( ; child; prev = child, child = child->Next )
144                 {
145                         if( strncmp( &Path[start], child->Name, tmp+1 ) == '/' )
146                                 break;
147                 }
148                 
149                 // Need a new directory?
150                 if( !child )
151                 {
152                         child = calloc( 1, sizeof(tSysFS_Ent)+tmp+1 );
153                         if( !child ) {
154                                 Log_Error("SysFS", "calloc(%i) failure", sizeof(tSysFS_Ent)+tmp+1);
155                                 return -1;
156                         }
157                         child->Next = NULL;
158                         memcpy(child->Name, &Path[start], tmp);
159                         child->Name[tmp] = '\0';
160                         child->Parent = ent;
161                         child->Node.Inode = 0;
162                         child->Node.ImplPtr = NULL;
163                         child->Node.ImplInt = (Uint)child;      // Uplink
164                         child->Node.NumACLs = 1;
165                         child->Node.ACLs = &gVFS_ACL_EveryoneRX;
166                         child->Node.Flags = VFS_FFLAG_DIRECTORY;
167                         child->Node.Type = &gSysFS_DirNodeType;
168                         if( !prev ) {
169                                 if(ent)
170                                         ent->Node.ImplPtr = child;
171                                 else
172                                         gSysFS_DriverInfo.RootNode.ImplPtr = child;
173                                 // ^^^ Impossible (There is already /Version)
174                         }
175                         else
176                                 prev->Next = child;
177                         if(ent)
178                                 ent->Node.Size ++;
179                         else
180                                 gSysFS_DriverInfo.RootNode.Size ++;
181                         Log_Log("SysFS", "Added directory '%.*s'", tmp, &Path[start]);
182                         Log_Log("SysFS", "Added directory '%.*s'", tmp, child->Name);
183                 }
184                 
185                 ent = child;
186                 
187                 start = tmp+1;
188         }
189         
190         // ent: Parent tSysFS_Ent or NULL
191         // start: beginning of last path element
192         
193         // Check if the name is taken
194         prev = NULL;
195         if(ent)
196                 child = ent->Node.ImplPtr;
197         else
198                 child = gSysFS_DriverInfo.RootNode.ImplPtr;
199         for( ; child; child = child->Next )
200         {
201                 if( strcmp( &Path[start], child->Name ) == 0 )
202                         break;
203         }
204         if( child ) {
205                 Log_Warning("SysFS", "'%s' is taken (in '%s')\n", &Path[start], Path);
206                 return 0;
207         }
208         
209         // Create new node
210         child = calloc( 1, sizeof(tSysFS_Ent)+strlen(&Path[start])+1 );
211         child->Next = NULL;
212         strcpy(child->Name, &Path[start]);
213         child->Parent = ent;
214         
215         child->Node.Inode = giSysFS_NextFileID++;
216         child->Node.ImplPtr = (void*)Data;
217         child->Node.ImplInt = (Uint)child;      // Uplink
218         child->Node.Size = Length;
219         child->Node.NumACLs = 1;
220         child->Node.ACLs = &gVFS_ACL_EveryoneRO;
221         child->Node.Type = &gSysFS_FileNodeType;
222         
223         // Add to parent's child list
224         if(ent) {
225                 ent->Node.Size ++;
226                 child->Next = ent->Node.ImplPtr;
227                 ent->Node.ImplPtr = child;
228         }
229         else {
230                 gSysFS_DriverInfo.RootNode.Size ++;
231                 child->Next = gSysFS_DriverInfo.RootNode.ImplPtr;
232                 gSysFS_DriverInfo.RootNode.ImplPtr = child;
233         }
234         // Add to global file list
235         child->ListNext = gSysFS_FileList;
236         gSysFS_FileList = child;
237         
238         Log_Log("SysFS", "Added '%s' (%p)", Path, Data);
239         
240         return child->Node.Inode;
241 }
242
243 /**
244  * \fn int SysFS_UpdateFile(int ID, char *Data, int Length)
245  * \brief Updates a file
246  * \param ID    Identifier returned by ::SysFS_RegisterFile
247  * \param Data  Pointer to the data buffer
248  * \param Length        Length of the data buffer
249  * \return Boolean Success
250  */
251 int SysFS_UpdateFile(int ID, const char *Data, int Length)
252 {
253         tSysFS_Ent      *ent;
254         
255         for( ent = gSysFS_FileList; ent; ent = ent->Next )
256         {
257                 // It's a reverse sorted list
258                 if(ent->Node.Inode < (Uint64)ID)
259                         return 0;
260                 if(ent->Node.Inode == (Uint64)ID)
261                 {
262                         ent->Node.ImplPtr = (void*)Data;
263                         ent->Node.Size = Length;
264                         return 1;
265                 }
266         }
267         
268         return 0;
269 }
270
271 /**
272  * \fn int SysFS_RemoveFile(int ID)
273  * \brief Removes a file from user access
274  * \param ID    Identifier returned by ::SysFS_RegisterFile
275  * \return Boolean Success
276  * \note If a handle is still open to the file, it will be invalidated
277  */
278 int SysFS_RemoveFile(int ID)
279 {
280         tSysFS_Ent      *file;
281         tSysFS_Ent      *ent, *parent, *prev;
282         
283         prev = NULL;
284         for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->ListNext )
285         {
286                 // It's a reverse sorted list
287                 if(ent->Node.Inode <= (Uint64)ID)       break;
288         }
289         if( !ent || ent->Node.Inode != (Uint64)ID) {
290                 Log_Notice("SysFS", "ID %i not present", ID);
291                 return 0;
292         }
293         
294         // Set up for next part
295         file = ent;
296         parent = file->Parent;
297         
298         // Remove from file list
299         if(prev)
300                 prev->ListNext = file->ListNext;
301         else
302                 gSysFS_FileList = file->ListNext;
303         file->Node.Size = 0;
304         file->Node.ImplPtr = NULL;
305         
306         // Clean out of parent directory
307         while(parent)
308         {
309                 for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
310                 {
311                         if( ent == file )       break;
312                 }
313                 if(!ent) {
314                         Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
315                         return 0;
316                 }
317                 
318                 // Remove from parent directory
319                 if(prev)
320                         prev->Next = ent->Next;
321                 else
322                         parent->Node.ImplPtr = ent->Next;
323
324                 // Free if not in use
325                 if(file->Node.ReferenceCount == 0) {
326                         free(file);
327                 }
328
329                 if( parent->Node.ImplPtr )
330                         break;
331
332                 // Remove parent from the tree
333                 file = parent;
334                 parent = parent->Parent;
335         }
336         
337         return 1;
338 }
339
340 /**
341  * \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
342  * \brief Reads from a SysFS directory
343  */
344 int SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
345 {
346         tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
347         if(Pos < 0 || (Uint64)Pos >= Node->Size)
348                 return -EINVAL;
349         
350         for( ; child; child = child->Next, Pos-- )
351         {
352                 if( Pos == 0 ) {
353                         strncpy(Dest, child->Name, FILENAME_MAX);
354                         return 0;
355                 }
356         }
357         return -ENOENT;
358 }
359
360 /**
361  * \fn tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
362  * \brief Find a file in a SysFS directory
363  */
364 tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags)
365 {
366         tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
367         
368         for( ; child; child = child->Next )
369         {
370                 if( strcmp(child->Name, Filename) == 0 )
371                         return &child->Node;
372         }
373         
374         return NULL;
375 }
376
377 /**
378  * \brief Read from an exposed buffer
379  */
380 size_t SysFS_Comm_ReadFile(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
381 {
382         if( Offset > Node->Size )       return -1;
383         if( Length > Node->Size )       Length = Node->Size;
384         if( Offset + Length > Node->Size)       Length = Node->Size - Offset;
385         
386         if( Node->ImplPtr )
387                 memcpy(Buffer, (void*)((Uint)Node->ImplPtr+(Uint)Offset), Length);
388         else
389                 return -1;
390         
391         return Length;
392 }
393
394 /**
395  * \fn void SysFS_Comm_CloseFile(tVFS_Node *Node)
396  * \brief Closes an open file
397  * \param Node  Node to close
398  */
399 void SysFS_Comm_CloseFile(tVFS_Node *Node)
400 {
401         // Dereference
402         Node->ReferenceCount --;
403         if( Node->ReferenceCount > 0 )  return;
404         
405         // Check if it is still valid
406         if( Node->ImplPtr )     return;
407         
408         // Delete
409         free( (void*)Node->ImplInt );
410 }

UCC git Repository :: git.ucc.asn.au