4fc0f31553ec020ab56b9391440edc25e4ecd00e
[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 char    *NativeFS_ReadDir(tVFS_Node *Node, int Position);\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 \r
38 // === GLOBALS ===\r
39 tVFS_NodeType   gNativeFS_FileNodeType = {\r
40         .Read = NativeFS_Read,\r
41         .Write = NativeFS_Write,\r
42 };\r
43 tVFS_NodeType   gNativeFS_DirNodeType = {\r
44         .FindDir = NativeFS_FindDir,\r
45         .ReadDir = NativeFS_ReadDir,\r
46 };\r
47 tVFS_Driver     gNativeFS_Driver = {\r
48         "nativefs", 0,\r
49         NativeFS_Mount, NativeFS_Unmount,\r
50         NULL,\r
51 };\r
52 \r
53 // === CODE ===\r
54 int NativeFS_Install(char **Arguments)\r
55 {\r
56         VFS_AddDriver(&gNativeFS_Driver);\r
57         return 0;\r
58 }\r
59 \r
60 tVFS_Node *NativeFS_Mount(const char *Device, const char **Arguments)\r
61 {\r
62         tVFS_Node       *ret;\r
63         tNativeFS       *info;\r
64         DIR     *dp;\r
65         \r
66         dp = opendir(Device);\r
67         if(!dp) {\r
68                 Log_Warning("NativeFS", "ERROR: Unable to open device root '%s'", Device);\r
69                 return NULL;\r
70         }\r
71         \r
72         // Check if directory exists\r
73         // Parse flags from arguments\r
74         info = malloc(sizeof(tNativeFS));\r
75         info->InodeHandle = Inode_GetHandle();\r
76         info->bReadOnly = 0;\r
77         // Create node\r
78         ret = malloc(sizeof(tVFS_Node));\r
79         memset(ret, 0, sizeof(tVFS_Node));\r
80         ret->Data = strdup(Device);\r
81         ret->ImplInt = strlen(ret->Data);\r
82         ret->ImplPtr = info;\r
83         ret->Inode = (Uint64)(tVAddr)dp;\r
84         ret->Flags = VFS_FFLAG_DIRECTORY;\r
85 \r
86         ret->Type = &gNativeFS_DirNodeType;     \r
87 \r
88         return ret;\r
89 }\r
90 \r
91 void NativeFS_Unmount(tVFS_Node *Node)\r
92 {\r
93         tNativeFS       *info = Node->ImplPtr;\r
94         Inode_ClearCache( info->InodeHandle );\r
95         closedir( (void *)(tVAddr)Node->Inode );\r
96         free(Node->Data);\r
97         free(Node);\r
98         free(info);\r
99 }\r
100 \r
101 void NativeFS_Close(tVFS_Node *Node)\r
102 {\r
103         tNativeFS       *info = Node->ImplPtr;\r
104         Inode_UncacheNode( info->InodeHandle, Node->Inode );\r
105 }\r
106 \r
107 tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)\r
108 {\r
109         char    *path = malloc(Node->ImplInt + 1 + strlen(Name) + 1);\r
110         tNativeFS       *info = Node->ImplPtr;\r
111         tVFS_Node       baseRet;\r
112         struct stat statbuf;\r
113 \r
114         ENTER("pNode sName", Node, Name);\r
115         \r
116         // Create path\r
117         strcpy(path, Node->Data);\r
118         path[Node->ImplInt] = '/';\r
119         strcpy(path + Node->ImplInt + 1, Name);\r
120         \r
121         LOG("path = '%s'", path);\r
122         \r
123         // Check if file exists\r
124         if( stat(path, &statbuf) ) {\r
125                 free(path);\r
126                 LOG("Doesn't exist");\r
127                 LEAVE('n');\r
128                 return NULL;\r
129         }\r
130         \r
131         memset(&baseRet, 0, sizeof(tVFS_Node));\r
132         \r
133         // Check file type\r
134         if( S_ISDIR(statbuf.st_mode) )\r
135         {\r
136                 LOG("Directory");\r
137                 baseRet.Inode = (Uint64)(tVAddr) opendir(path);\r
138                 baseRet.Type = &gNativeFS_DirNodeType;\r
139                 baseRet.Flags |= VFS_FFLAG_DIRECTORY;\r
140                 baseRet.Size = -1;\r
141         }\r
142         else\r
143         {\r
144                 LOG("File");\r
145                 baseRet.Inode = (Uint64)(tVAddr) fopen(path, "r+");\r
146                 baseRet.Type = &gNativeFS_FileNodeType;\r
147                 \r
148                 fseek( (FILE*)(tVAddr)baseRet.Inode, 0, SEEK_END );\r
149                 baseRet.Size = ftell( (FILE*)(tVAddr)baseRet.Inode );\r
150         }\r
151         \r
152         // Create new node\r
153         baseRet.ImplPtr = info;\r
154         baseRet.ImplInt = strlen(path);\r
155         baseRet.Data = path;\r
156         \r
157         LEAVE('-');\r
158         return Inode_CacheNode(info->InodeHandle, &baseRet);\r
159 }\r
160 \r
161 char *NativeFS_ReadDir(tVFS_Node *Node, int Position)\r
162 {\r
163         struct dirent   *ent;\r
164         DIR     *dp = (void*)(tVAddr)Node->Inode;\r
165         char    *ret;\r
166 \r
167         ENTER("pNode iPosition", Node, Position);\r
168 \r
169         // TODO: Keep track of current position in the directory\r
170         // TODO: Lock node during this\r
171         rewinddir(dp);\r
172         do {\r
173                 ent = readdir(dp);\r
174         } while(Position-- && ent);\r
175 \r
176         if( !ent ) {\r
177                 LEAVE('n');\r
178                 return NULL;\r
179         }\r
180         \r
181         ret = strdup(ent->d_name);\r
182 \r
183         // TODO: Unlock node    \r
184 \r
185         LEAVE('s', ret);\r
186         return ret;\r
187 }\r
188 \r
189 size_t NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer)\r
190 {\r
191         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
192         if( fseek( (FILE *)(tVAddr)Node->Inode, Offset, SEEK_SET ) != 0 )\r
193         {\r
194                 LEAVE('i', 0);\r
195                 return 0;\r
196         }\r
197         LEAVE('-');\r
198         return fread( Buffer, 1, Length, (FILE *)(tVAddr)Node->Inode );\r
199 }\r
200 \r
201 size_t NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer)\r
202 {\r
203         FILE    *fp = (FILE *)(tVAddr)Node->Inode;\r
204         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
205         if( fseek( fp, Offset, SEEK_SET ) != 0 )\r
206         {\r
207                 LEAVE('i', 0);\r
208                 return 0;\r
209         }\r
210         size_t ret = fwrite( Buffer, 1, Length, fp );\r
211         fflush( fp );\r
212         LEAVE('i', ret);\r
213         return ret;\r
214 \r
215 }\r

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