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

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