AcessNative - Fixed windows symlink derps
[tpg/acess2.git] / AcessNative / ld-acess_src / syscalls.c
1 /*
2  */
3 #define DONT_INCLUDE_SYSCALL_NAMES 1
4 #include "common.h"
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include <stddef.h>
11 #include <unistd.h>
12 #include "request.h"
13
14 #define DEBUG(str, x...)        Debug(str, x)
15
16 #define MAX_FPS 16
17
18 // === Types ===
19
20 // === IMPORTS ===
21
22 // === GLOBALS ===
23 FILE    *gaSyscall_LocalFPs[MAX_FPS];
24
25 // === CODE ===
26 const char *ReadEntry(tRequestValue *Dest, void *DataDest, void **PtrDest, const char *ArgTypes, va_list *Args)
27 {
28         uint64_t        val64;
29         uint32_t        val32;
30          int    direction = 0;  // 0: Invalid, 1: Out, 2: In, 3: Out
31         char    *str;
32          int    len;
33
34         // Eat whitespace
35         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
36         if( *ArgTypes == '\0' ) return ArgTypes;
37         
38 //      DEBUG("ArgTypes = '%s'", ArgTypes);
39         
40         // Get direction
41         switch(*ArgTypes)
42         {
43         default:        // Defaults to output
44         case '>':       direction = 1;  break;
45         case '<':       direction = 2;  break;
46         case '?':       direction = 3;  break;
47         }
48         ArgTypes ++;
49         
50         // Eat whitespace
51         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
52         if( *ArgTypes == '\0' ) return ArgTypes;
53         
54         // Get type
55         switch(*ArgTypes)
56         {
57         // 32-bit integer
58         case 'i':
59                 
60                 if( direction != 1 ) {
61                         Warning("ReadEntry: Recieving an integer is not defined");
62                         return NULL;
63                 }
64                 
65                 val32 = va_arg(*Args, uint32_t);
66                 
67                 Dest->Type = ARG_TYPE_INT32;
68                 Dest->Length = sizeof(uint32_t);
69                 Dest->Flags = 0;
70                 
71                 if( DataDest )
72                         *(uint32_t*)DataDest = val32;
73                 break;
74         // 64-bit integer
75         case 'I':
76                 
77                 if( direction != 1 ) {
78                         fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
79                         return NULL;
80                 }
81                 
82                 val64 = va_arg(*Args, uint64_t);
83                 
84                 Dest->Type = ARG_TYPE_INT64;
85                 Dest->Length = sizeof(uint64_t);
86                 Dest->Flags = 0;
87                 if( DataDest )
88                         *(uint64_t*)DataDest = val64;
89                 break;
90         // String
91         case 's':
92                 // Input string makes no sense!
93                 if( direction != 1 ) {
94                         fprintf(stderr, "ReadEntry: Recieving a string is not defined\n");
95                         return NULL;
96                 }
97                 
98                 str = va_arg(*Args, char*);
99                 
100                 Dest->Type = ARG_TYPE_STRING;
101                 Dest->Length = strlen(str) + 1;
102                 Dest->Flags = 0;
103                 
104                 if( DataDest )
105                 {
106                         memcpy(DataDest, str, Dest->Length);
107                 }
108                 break;
109         // Data (special handling)
110         case 'd':
111                 len = va_arg(*Args, size_t);
112                 str = va_arg(*Args, char*);
113                 
114                 // Save the pointer for later
115                 if( PtrDest )   *PtrDest = str;
116                 
117                 // Create parameter block
118                 Dest->Type = ARG_TYPE_DATA;
119                 Dest->Length = str ? len : 0;
120                 Dest->Flags = 0;
121                 if( direction & 2 )
122                         Dest->Flags |= ARG_FLAG_RETURN;
123                 
124                 // Has data?
125                 if( direction & 1 )
126                 {
127                         if( DataDest && str )
128                                 memcpy(DataDest, str, len);
129                 }
130                 else
131                         Dest->Flags |= ARG_FLAG_ZEROED;
132                 break;
133         
134         default:
135                 return NULL;
136         }
137         ArgTypes ++;
138         
139         return ArgTypes;
140 }
141
142 /**
143  * \param ArgTypes
144  *
145  * Whitespace is ignored
146  * >i:  Input Integer (32-bits)
147  * >I:  Input Long Integer (64-bits)
148  * >s:  Input String
149  * >d:  Input Buffer (Preceded by valid size)
150  * <I:  Output long integer
151  * <d:  Output Buffer (Preceded by valid size)
152  * ?d:  Bi-directional buffer (Preceded by valid size), buffer contents
153  *      are returned
154  */
155 uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...)
156 {
157         va_list args;
158          int    paramCount, dataLength;
159          int    retCount = 1, retLength = sizeof(uint64_t);
160         void    **retPtrs;      // Pointers to return buffers
161         const char      *str;
162         tRequestHeader  *req;
163         void    *dataPtr;
164         uint64_t        retValue;
165          int    i;
166         
167         // DEBUG!
168 //      printf("&tRequestHeader->Params = %i\n", offsetof(tRequestHeader, Params));
169 //      printf("&tRequestValue->Flags = %i\n", offsetof(tRequestValue, Flags));
170 //      printf("&tRequestValue->Length = %i\n", offsetof(tRequestValue, Length));
171         
172         // Get data size
173         va_start(args, ArgTypes);
174         str = ArgTypes;
175         paramCount = 0;
176         dataLength = 0;
177         while(*str)
178         {
179                 tRequestValue   tmpVal;
180                 
181                 str = ReadEntry(&tmpVal, NULL, NULL, str, &args);
182                 if( !str ) {
183                         fprintf(stderr, "syscalls.c: ReadEntry failed (SyscallID = %i)\n", SyscallID);
184                         exit(127);
185                 }
186                 paramCount ++;
187                 if( !(tmpVal.Flags & ARG_FLAG_ZEROED) )
188                         dataLength += tmpVal.Length;
189                 
190                 if( tmpVal.Flags & ARG_FLAG_RETURN ) {
191                         retLength += tmpVal.Length;
192                         retCount ++;
193                 }
194         }
195         va_end(args);
196         
197         dataLength += sizeof(tRequestHeader) + paramCount*sizeof(tRequestValue);
198         retLength += sizeof(tRequestHeader) + retCount*sizeof(tRequestValue);
199         
200         // Allocate buffers
201         retPtrs = malloc( sizeof(void*) * (retCount+1) );
202         if( dataLength > retLength)
203                 req = malloc( dataLength );
204         else
205                 req = malloc( retLength );
206         req->ClientID = 0;      //< Filled later
207         req->CallID = SyscallID;
208         req->NParams = paramCount;
209         dataPtr = &req->Params[paramCount];
210         
211         // Fill `output` and `input`
212         va_start(args, ArgTypes);
213         str = ArgTypes;
214         // - re-zero so they can be used as indicies
215         paramCount = 0;
216         retCount = 0;
217         while(*str)
218         {               
219                 str = ReadEntry(&req->Params[paramCount], dataPtr, &retPtrs[retCount], str, &args);
220                 if( !str )      break;
221                 
222                 if( !(req->Params[paramCount].Flags & ARG_FLAG_ZEROED) )
223                         dataPtr += req->Params[paramCount].Length;
224                 if( req->Params[paramCount].Flags & ARG_FLAG_RETURN )
225                         retCount ++;
226                 
227                 paramCount ++;
228         }
229         va_end(args);
230         
231         // Send syscall request
232         if( SendRequest(req, dataLength, retLength) < 0 ) {
233                 fprintf(stderr, "syscalls.c: SendRequest failed (SyscallID = %i)\n", SyscallID);
234                 exit(127);
235         }
236         
237         // Parse return value
238         dataPtr = &req->Params[req->NParams];
239         retValue = 0;
240         if( req->NParams >= 1 )
241         {
242                 switch(req->Params[0].Type)
243                 {
244                 case ARG_TYPE_INT64:
245                         retValue = *(uint64_t*)dataPtr;
246                         dataPtr += req->Params[0].Length;
247                         break;
248                 case ARG_TYPE_INT32:
249                         retValue = *(uint32_t*)dataPtr;
250                         dataPtr += req->Params[0].Length;
251                         break;
252                 }       
253         }
254         
255         // Write changes to buffers
256         retCount = 0;
257         for( i = 1; i < req->NParams; i ++ )
258         {
259                 #if 0
260                  int     j;
261                 printf("Return Data %i: (%i)", i, req->Params[i].Length);
262                 for( j = 0; j < req->Params[i].Length; j ++ )
263                         printf(" %02x", ((uint8_t*)dataPtr)[j]);
264                 printf("\n");
265                 #endif
266                 memcpy( retPtrs[retCount++], dataPtr, req->Params[i].Length );
267                 dataPtr += req->Params[i].Length;
268         }
269         
270         free( req );
271         free( retPtrs );
272         
273         DEBUG(": %i 0x%llx", SyscallID, retValue);
274         
275         return retValue;
276 }
277
278
279 int native_open(const char *Path, int Flags)
280 {
281         int     ret;
282        for(ret = 0; ret < MAX_FPS && gaSyscall_LocalFPs[ret]; ret ++ )  ;
283        if(ret == MAX_FPS)       return -1;
284        // TODO: Handle directories
285        gaSyscall_LocalFPs[ret] = fopen(&Path[4], "r+");
286        if(!gaSyscall_LocalFPs[ret])     return -1;
287        return ret;
288 }
289
290 void native_close(int FD)
291 {
292         fclose( gaSyscall_LocalFPs[FD] );
293         gaSyscall_LocalFPs[FD] = NULL;
294 }
295
296 size_t native_read(int FD, void *Dest, size_t Bytes)
297 {
298         return fread( Dest, Bytes, 1, gaSyscall_LocalFPs[FD] );
299 }
300
301 size_t native_write(int FD, const void *Src, size_t Bytes)
302 {
303         return fwrite( Src, Bytes, 1, gaSyscall_LocalFPs[FD] );
304 }
305
306 int native_seek(int FD, int64_t Ofs, int Dir)
307 {
308         if(Dir == 0)
309                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_CUR );
310         else if(Dir > 0)
311                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_SET );
312         else
313                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_END );
314 }
315
316 uint64_t native_tell(int FD)
317 {
318         return ftell( gaSyscall_LocalFPs[FD] );
319 }
320
321 int native_execve(const char *filename, const char *const argv[], const char *const envp[])
322 {
323         int ret;
324         ret = execve(filename, (void*)argv, (void*)envp);
325         perror("native_execve");
326         return ret;
327 }

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