e51f286215ae00c1b1bcb979c11267a411ed724f
[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 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         "nativefs", 0,\r
52         NativeFS_Mount, NativeFS_Unmount,\r
53         NULL,\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 char *NativeFS_ReadDir(tVFS_Node *Node, int Position)\r
172 {\r
173         struct dirent   *ent;\r
174         DIR     *dp = (void*)(tVAddr)Node->Inode;\r
175         char    *ret;\r
176 \r
177         ENTER("pNode iPosition", Node, Position);\r
178 \r
179         // TODO: Keep track of current position in the directory\r
180         // TODO: Lock node during this\r
181         rewinddir(dp);\r
182         do {\r
183                 ent = readdir(dp);\r
184         } while(Position-- && ent);\r
185 \r
186         if( !ent ) {\r
187                 LEAVE('n');\r
188                 return NULL;\r
189         }\r
190         \r
191         ret = strdup(ent->d_name);\r
192 \r
193         // TODO: Unlock node    \r
194 \r
195         LEAVE('s', ret);\r
196         return ret;\r
197 }\r
198 \r
199 size_t NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer)\r
200 {\r
201         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
202         if( fseek( (FILE *)(tVAddr)Node->Inode, Offset, SEEK_SET ) != 0 )\r
203         {\r
204                 LEAVE('i', 0);\r
205                 return 0;\r
206         }\r
207         LEAVE('-');\r
208         return fread( Buffer, 1, Length, (FILE *)(tVAddr)Node->Inode );\r
209 }\r
210 \r
211 size_t NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer)\r
212 {\r
213         FILE    *fp = (FILE *)(tVAddr)Node->Inode;\r
214         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
215         if( fseek( fp, Offset, SEEK_SET ) != 0 )\r
216         {\r
217                 LEAVE('i', 0);\r
218                 return 0;\r
219         }\r
220         size_t ret = fwrite( Buffer, 1, Length, fp );\r
221         fflush( fp );\r
222         LEAVE('i', ret);\r
223         return ret;\r
224 \r
225 }\r

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