Kernel - VFS API Update - ReadDir caller provided buffer
[tpg/acess2.git] / AcessNative / acesskernel_src / nativefs.c
1 /*\r
2  * Acess2 Native Kernel\r
3  * - Acess kernel emulation on another OS using SDL and UDP\r
4  *\r
5  * nativefs.c\r
6  * - Host filesystem access\r
7  */\r
8 #define DEBUG   0\r
9 #define off_t   _acess_off_t\r
10 #include <acess.h>      // Acess\r
11 #include <vfs.h>        // Acess\r
12 #undef off_t\r
13 #include <dirent.h>     // Posix\r
14 #include <sys/stat.h>   // Posix\r
15 #include <stdio.h>      // Posix\r
16 \r
17 //NOTES:\r
18 // tVFS_Node->ImplPtr is a pointer to the filesystem flags (tNativeFS)\r
19 // tVFS_Node->Data is the path string (heap string)\r
20 // tVFS_Node->ImplInt is the path length\r
21 \r
22 // === STRUCTURES ===\r
23 typedef struct\r
24 {\r
25          int    InodeHandle;\r
26          int    bReadOnly;\r
27 }       tNativeFS;\r
28 \r
29 // === PROTOTYPES ===\r
30  int    NativeFS_Install(char **Arguments);\r
31 tVFS_Node       *NativeFS_Mount(const char *Device, const char **Arguments);\r
32 void    NativeFS_Unmount(tVFS_Node *Node);\r
33 tVFS_Node       *NativeFS_FindDir(tVFS_Node *Node, const char *Name);\r
34  int    NativeFS_ReadDir(tVFS_Node *Node, int Position, char Dest[FILENAME_MAX]);\r
35 size_t  NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer);\r
36 size_t  NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer);\r
37 void    NativeFS_Close(tVFS_Node *Node);\r
38 \r
39 // === GLOBALS ===\r
40 tVFS_NodeType   gNativeFS_FileNodeType = {\r
41         .Read = NativeFS_Read,\r
42         .Write = NativeFS_Write,\r
43         .Close = NativeFS_Close\r
44 };\r
45 tVFS_NodeType   gNativeFS_DirNodeType = {\r
46         .FindDir = NativeFS_FindDir,\r
47         .ReadDir = NativeFS_ReadDir,\r
48         .Close = NativeFS_Close\r
49 };\r
50 tVFS_Driver     gNativeFS_Driver = {\r
51         .Name = "nativefs",\r
52         .InitDevice = NativeFS_Mount,\r
53         .Unmount = NativeFS_Unmount\r
54 };\r
55 \r
56 // === CODE ===\r
57 int NativeFS_Install(char **Arguments)\r
58 {\r
59         VFS_AddDriver(&gNativeFS_Driver);\r
60         return 0;\r
61 }\r
62 \r
63 tVFS_Node *NativeFS_Mount(const char *Device, const char **Arguments)\r
64 {\r
65         tVFS_Node       *ret;\r
66         tNativeFS       *info;\r
67         DIR     *dp;\r
68         \r
69         dp = opendir(Device);\r
70         if(!dp) {\r
71                 Log_Warning("NativeFS", "ERROR: Unable to open device root '%s'", Device);\r
72                 return NULL;\r
73         }\r
74         \r
75         // Check if directory exists\r
76         // Parse flags from arguments\r
77         info = malloc(sizeof(tNativeFS));\r
78         info->InodeHandle = Inode_GetHandle();\r
79         info->bReadOnly = 0;\r
80         // Create node\r
81         ret = malloc(sizeof(tVFS_Node));\r
82         memset(ret, 0, sizeof(tVFS_Node));\r
83         ret->Data = strdup(Device);\r
84         ret->ImplInt = strlen(ret->Data);\r
85         ret->ImplPtr = info;\r
86         ret->Inode = (Uint64)(tVAddr)dp;\r
87         ret->Flags = VFS_FFLAG_DIRECTORY;\r
88 \r
89         ret->Type = &gNativeFS_DirNodeType;     \r
90 \r
91         return ret;\r
92 }\r
93 \r
94 void NativeFS_Unmount(tVFS_Node *Node)\r
95 {\r
96         tNativeFS       *info = Node->ImplPtr;\r
97         Inode_ClearCache( info->InodeHandle );\r
98         closedir( (void *)(tVAddr)Node->Inode );\r
99         free(Node->Data);\r
100         free(Node);\r
101         free(info);\r
102 }\r
103 \r
104 void NativeFS_Close(tVFS_Node *Node)\r
105 {\r
106         tNativeFS       *info = Node->ImplPtr;\r
107         DIR     *dp = (Node->Flags & VFS_FFLAG_DIRECTORY) ? (DIR*)(tVAddr)Node->Inode : 0;\r
108         FILE    *fp = (Node->Flags & VFS_FFLAG_DIRECTORY) ? 0 : (FILE*)(tVAddr)Node->Inode;\r
109         \r
110         if( Inode_UncacheNode( info->InodeHandle, Node->Inode ) == 1 ) {\r
111                 if(dp)  closedir(dp);\r
112                 if(fp)  fclose(fp);\r
113         }\r
114 }\r
115 \r
116 tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)\r
117 {\r
118         char    *path;\r
119         tNativeFS       *info = Node->ImplPtr;\r
120         tVFS_Node       baseRet;\r
121         struct stat statbuf;\r
122 \r
123         ENTER("pNode sName", Node, Name);\r
124         \r
125         // Create path\r
126         path = malloc(Node->ImplInt + 1 + strlen(Name) + 1);\r
127         strcpy(path, Node->Data);\r
128         path[Node->ImplInt] = '/';\r
129         strcpy(path + Node->ImplInt + 1, Name);\r
130         \r
131         LOG("path = '%s'", path);\r
132         \r
133         // Check if file exists\r
134         if( stat(path, &statbuf) ) {\r
135                 free(path);\r
136                 LOG("Doesn't exist");\r
137                 LEAVE('n');\r
138                 return NULL;\r
139         }\r
140         \r
141         memset(&baseRet, 0, sizeof(tVFS_Node));\r
142         \r
143         // Check file type\r
144         if( S_ISDIR(statbuf.st_mode) )\r
145         {\r
146                 LOG("Directory");\r
147                 baseRet.Inode = (Uint64)(tVAddr) opendir(path);\r
148                 baseRet.Type = &gNativeFS_DirNodeType;\r
149                 baseRet.Flags |= VFS_FFLAG_DIRECTORY;\r
150                 baseRet.Size = -1;\r
151         }\r
152         else\r
153         {\r
154                 LOG("File");\r
155                 baseRet.Inode = (Uint64)(tVAddr) fopen(path, "r+");\r
156                 baseRet.Type = &gNativeFS_FileNodeType;\r
157                 \r
158                 fseek( (FILE*)(tVAddr)baseRet.Inode, 0, SEEK_END );\r
159                 baseRet.Size = ftell( (FILE*)(tVAddr)baseRet.Inode );\r
160         }\r
161         \r
162         // Create new node\r
163         baseRet.ImplPtr = info;\r
164         baseRet.ImplInt = strlen(path);\r
165         baseRet.Data = path;\r
166         \r
167         LEAVE('-');\r
168         return Inode_CacheNode(info->InodeHandle, &baseRet);\r
169 }\r
170 \r
171 int NativeFS_ReadDir(tVFS_Node *Node, int Position, char Dest[FILENAME_MAX])\r
172 {\r
173         struct dirent   *ent;\r
174         DIR     *dp = (void*)(tVAddr)Node->Inode;\r
175 \r
176         ENTER("pNode iPosition", Node, Position);\r
177 \r
178         // TODO: Keep track of current position in the directory\r
179         // TODO: Lock node during this\r
180         rewinddir(dp);\r
181         do {\r
182                 ent = readdir(dp);\r
183         } while(Position-- && ent);\r
184 \r
185         if( !ent ) {\r
186                 LEAVE('i', -ENOENT);\r
187                 return -ENOENT;\r
188         }\r
189         \r
190         strncpy(Dest, ent->d_name, FILENAME_MAX);\r
191 \r
192         // TODO: Unlock node    \r
193 \r
194         LEAVE('i', 0);\r
195         return 0;\r
196 }\r
197 \r
198 size_t NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer)\r
199 {\r
200         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
201         if( fseek( (FILE *)(tVAddr)Node->Inode, Offset, SEEK_SET ) != 0 )\r
202         {\r
203                 LEAVE('i', 0);\r
204                 return 0;\r
205         }\r
206         LEAVE('-');\r
207         return fread( Buffer, 1, Length, (FILE *)(tVAddr)Node->Inode );\r
208 }\r
209 \r
210 size_t NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer)\r
211 {\r
212         FILE    *fp = (FILE *)(tVAddr)Node->Inode;\r
213         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
214         if( fseek( fp, Offset, SEEK_SET ) != 0 )\r
215         {\r
216                 LEAVE('i', 0);\r
217                 return 0;\r
218         }\r
219         size_t ret = fwrite( Buffer, 1, Length, fp );\r
220         fflush( fp );\r
221         LEAVE('i', ret);\r
222         return ret;\r
223 \r
224 }\r

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