Merge branch 'master' of git://ted.mutabah.net/acess2
[tpg/acess2.git] / KernelLand / Kernel / vfs / fs / root.c
1 /* 
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * vfs/fs/root.c
6  * - Root Filesystem Driver
7  *
8  * TODO: Restrict to directories+symlinks only
9  */
10 #define DEBUG   0
11 #include <acess.h>
12 #include <vfs.h>
13 #include <vfs_ramfs.h>
14
15 // === CONSTANTS ===
16 #define MAX_FILES       64
17 #define MAX_FILE_SIZE   10*1024*1024
18
19 // === PROTOTYPES ===
20 tVFS_Node       *Root_InitDevice(const char *Device, const char **Options);
21 tVFS_Node       *Root_GetByINode(tVFS_Node *RootNode, Uint64 Inode);
22 tVFS_Node       *Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
23 tVFS_Node       *Root_FindDir(tVFS_Node *Node, const char *Name, Uint Flags);
24  int    Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
25 size_t  Root_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
26 size_t  Root_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
27 tRamFS_File     *Root_int_AllocFile(void);
28
29 // === GLOBALS ===
30 tVFS_Driver     gRootFS_Info = {
31         .Name = "rootfs", 
32         .InitDevice = Root_InitDevice,
33         .GetNodeFromINode = Root_GetByINode
34         };
35 tRamFS_File     RootFS_Files[MAX_FILES];
36 tVFS_ACL        RootFS_DirACLs[3] = {
37         {{0,0}, {0,VFS_PERM_ALL}},      // Owner (Root)
38         {{1,0}, {0,VFS_PERM_ALL}},      // Group (Root)
39         {{0,-1}, {0,VFS_PERM_ALL^VFS_PERM_WRITE}}       // World (Nobody)
40 };
41 tVFS_ACL        RootFS_FileACLs[3] = {
42         {{0,0}, {0,VFS_PERM_ALL^VFS_PERM_EXEC}},        // Owner (Root)
43         {{1,0}, {0,VFS_PERM_ALL^VFS_PERM_EXEC}},        // Group (Root)
44         {{0,-1}, {0,VFS_PERM_READ}}     // World (Nobody)
45 };
46 tVFS_NodeType   gRootFS_DirType = {
47         .TypeName = "RootFS-Dir",
48         .ReadDir = Root_ReadDir,
49         .FindDir = Root_FindDir,
50         .MkNod = Root_MkNod
51 };
52 tVFS_NodeType   gRootFS_FileType = {
53         .TypeName = "RootFS-File",
54         .Read = Root_Read,
55         .Write = Root_Write,
56 };
57
58 // === CODE ===
59 /**
60  * \brief Initialise the root filesystem
61  */
62 tVFS_Node *Root_InitDevice(const char *Device, const char **Options)
63 {
64         tRamFS_File     *root;
65         if(strcmp(Device, "root") != 0) {
66                 return NULL;
67         }
68         
69         // Create Root Node
70         root = &RootFS_Files[0];
71
72         root->Name[0] = '/';
73         root->Name[1] = '\0';
74         root->Node.ImplPtr = root;
75         
76         root->Node.CTime
77                 = root->Node.MTime
78                 = root->Node.ATime = now();
79         root->Node.NumACLs = 3;
80         root->Node.ACLs = RootFS_DirACLs;
81
82         root->Node.Flags = VFS_FFLAG_DIRECTORY;
83         root->Node.Type = &gRootFS_DirType;
84         
85         return &root->Node;
86 }
87
88 tVFS_Node *Root_GetByINode(tVFS_Node *RootNode, Uint64 Inode)
89 {
90         if( Inode >= MAX_FILES )
91                 return NULL;
92         if( RootFS_Files[Inode].Name[0] == '\0' )
93                 return NULL;
94         Debug("Root_GetByINode: (%llx) = '%s' %p",
95                 Inode,
96                 RootFS_Files[Inode].Name, &RootFS_Files[Inode].Node
97                 );
98         return &RootFS_Files[Inode].Node;
99 }
100
101 /**
102  * \fn int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
103  * \brief Create an entry in the root directory
104  */
105 tVFS_Node *Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
106 {
107         tRamFS_File     *parent = Node->ImplPtr;
108         tRamFS_File     *child;
109         tRamFS_File     *prev = NULL;
110         
111         ENTER("pNode sName xFlags", Node, Name, Flags);
112         
113         LOG("Sanity check name length - %i > %i", strlen(Name)+1, sizeof(child->Name));
114         if(strlen(Name) + 1 > sizeof(child->Name)) {
115                 errno = EINVAL;
116                 LEAVE_RET('n', NULL);
117         }
118         
119         // Find last child, while we're at it, check for duplication
120         for( child = parent->Data.FirstChild; child; prev = child, child = child->Next )
121         {
122                 if(strcmp(child->Name, Name) == 0) {
123                         LOG("Duplicate");
124                         errno = EEXIST;
125                         LEAVE_RET('n', NULL);
126                 }
127         }
128         
129         child = Root_int_AllocFile();
130         
131         strcpy(child->Name, Name);
132         LOG("Name = '%s'", child->Name);
133         
134         child->Parent = parent;
135         child->Next = NULL;
136         child->Data.FirstChild = NULL;
137         
138         child->Node.ImplPtr = child;
139         child->Node.Flags = Flags;
140         child->Node.NumACLs = 3;
141         child->Node.Size = 0;
142         
143         if(Flags & VFS_FFLAG_DIRECTORY)
144         {
145                 child->Node.ACLs = RootFS_DirACLs;
146                 child->Node.Type = &gRootFS_DirType;
147         } else {
148                 if(Flags & VFS_FFLAG_SYMLINK)
149                         child->Node.ACLs = RootFS_DirACLs;
150                 else
151                         child->Node.ACLs = RootFS_FileACLs;
152                 child->Node.Type = &gRootFS_FileType;
153         }
154         
155         // Append!
156         if( prev )
157                 prev->Next = child;
158         else
159                 parent->Data.FirstChild = child;
160         
161         parent->Node.Size ++;
162         
163         LEAVE('n', &child->Node);
164         return &child->Node;
165 }
166
167 /**
168  * \fn tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name)
169  * \brief Find an entry in the filesystem
170  */
171 tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
172 {
173         tRamFS_File     *parent = Node->ImplPtr;
174         tRamFS_File     *child = parent->Data.FirstChild;
175         
176         ENTER("pNode sName", Node, Name);
177         
178         for( child = parent->Data.FirstChild; child; child = child->Next )
179         {
180                 LOG("child->Name = '%s'", child->Name);
181                 if(strcmp(child->Name, Name) == 0)
182                 {
183                         LEAVE('p', &child->Node);
184                         return &child->Node;
185                 }
186         }
187         
188         LEAVE('n');
189         return NULL;
190 }
191
192 /**
193  * \fn char *Root_ReadDir(tVFS_Node *Node, int Pos)
194  * \brief Get an entry from the filesystem
195  */
196 int Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
197 {
198         tRamFS_File     *parent = Node->ImplPtr;
199         tRamFS_File     *child = parent->Data.FirstChild;
200         
201         for( ; child && Pos--; child = child->Next ) ;
202         
203         if(child) {
204                 strncpy(Dest, child->Name, FILENAME_MAX);
205                 return 0;
206         }
207         
208         return -ENOENT;
209 }
210
211 /**
212  * \brief Read from a file in the root directory
213  */
214 size_t Root_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
215 {
216         tRamFS_File     *file = Node->ImplPtr;
217         
218         if(Offset > Node->Size) return 0;
219
220         if(Length > Node->Size)
221                 Length = Node->Size;
222         if(Offset+Length > Node->Size)
223                 Length = Node->Size - Offset;
224         
225         memcpy(Buffer, file->Data.Bytes+Offset, Length);
226         
227         return Length;
228 }
229
230 /**
231  * \brief Write to a file in the root directory
232  */
233 size_t Root_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
234 {
235         tRamFS_File     *file = Node->ImplPtr;
236
237         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
238
239         if(Offset > Node->Size) {
240                 LEAVE('i', -1);
241                 return -1;
242         }       
243
244         if(Offset + Length > MAX_FILE_SIZE)
245         {
246                 Length = MAX_FILE_SIZE - Offset;
247                 ASSERTC(Length, <=, MAX_FILE_SIZE);
248         }
249
250         LOG("Length = %x", Length);
251         
252         // Check if buffer needs to be expanded
253         if(Offset + Length > Node->Size)
254         {
255                 size_t  newsize = Offset + Length;
256                 void *tmp = realloc( file->Data.Bytes, newsize );
257                 if(tmp == NULL) {
258                         Warning("Root_Write - Increasing buffer size failed (0x%x)",
259                                 newsize);
260                         LEAVE('i', -1);
261                         return -1;
262                 }
263                 file->Data.Bytes = tmp;
264                 Node->Size = Offset + Length;
265                 LOG("Expanded buffer to %i bytes", (int)Node->Size);
266         }
267         
268         memcpy(file->Data.Bytes+Offset, Buffer, Length);
269         LOG("File - '%.*s'", Node->Size, file->Data.Bytes);
270         
271         LEAVE('i', Length);
272         return Length;
273 }
274
275 /**
276  * \fn tRamFS_File *Root_int_AllocFile(void)
277  * \brief Allocates a file from the pool
278  */
279 tRamFS_File *Root_int_AllocFile(void)
280 {
281          int    i;
282         for( i = 0; i < MAX_FILES; i ++ )
283         {
284                 if( RootFS_Files[i].Name[0] == '\0' )
285                 {
286                         RootFS_Files[i].Node.Inode = i;
287                         return &RootFS_Files[i];
288                 }
289         }
290         return NULL;
291 }

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