Usermode/libc - Fix strchr and strrchr behavior
[tpg/acess2.git] / KernelLand / Kernel / vfs / handle.c
1 /*
2  * Acess2 VFS
3  * - AllocHandle, GetHandle
4  */
5 #define SANITY  1
6 #define DEBUG   0
7 #include <acess.h>
8 #include <mm_virt.h>
9 #include "vfs.h"
10 #include "vfs_int.h"
11 #include "vfs_ext.h"
12 #include <threads.h>    // GetMaxFD
13 #include <vfs_threads.h>        // Handle maintainance
14
15 // === CONSTANTS ===
16 #define MAX_KERNEL_FILES        128
17
18 // === PROTOTYPES ===
19
20 // === GLOBALS ===
21 tVFS_Handle     *gaUserHandles = (void*)MM_PPD_HANDLES;
22 tVFS_Handle     *gaKernelHandles = (void*)MM_KERNEL_VFS;
23
24 // === CODE ===
25 /**
26  * \fn tVFS_Handle *VFS_GetHandle(int FD)
27  * \brief Gets a pointer to the handle information structure
28  */
29 tVFS_Handle *VFS_GetHandle(int FD)
30 {
31         tVFS_Handle     *h;
32         
33         //Log_Debug("VFS", "VFS_GetHandle: (FD=0x%x)", FD);
34         
35         if(FD < 0)      return NULL;
36         
37         if(FD & VFS_KERNEL_FLAG) {
38                 FD &= (VFS_KERNEL_FLAG - 1);
39                 if(FD >= MAX_KERNEL_FILES)      return NULL;
40                 h = &gaKernelHandles[ FD ];
41         } else {
42                 if(FD >= *Threads_GetMaxFD(NULL))       return NULL;
43                 h = &gaUserHandles[ FD ];
44         }
45         
46         if(h->Node == NULL)     return NULL;
47         //Log_Debug("VFS", "VFS_GetHandle: RETURN %p", h);
48         return h;
49 }
50
51 int VFS_SetHandle(int FD, tVFS_Node *Node, int Mode)
52 {
53         tVFS_Handle     *h;
54         if(FD < 0)      return -1;
55         
56         if( FD & VFS_KERNEL_FLAG ) {
57                 FD &= (VFS_KERNEL_FLAG -1);
58                 if( FD >= MAX_KERNEL_FILES )    return -1;
59                 h = &gaKernelHandles[FD];
60         }
61         else {
62                 if( FD >= *Threads_GetMaxFD(NULL))      return -1;
63                 h = &gaUserHandles[FD];
64         }
65         h->Node = Node;
66         h->Mode = Mode;
67         return FD;
68 }
69
70 int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
71 {
72         // Check for a user open
73         if(bIsUser)
74         {
75                  int    max_handles = *Threads_GetMaxFD(NULL);
76                 // Allocate Buffer
77                 if( MM_GetPhysAddr( gaUserHandles ) == 0 )
78                 {
79                         tPage   *pageptr = (void*)gaUserHandles;
80                         size_t  size = max_handles * sizeof(tVFS_Handle);
81                         for( size_t ofs = 0; ofs < size; ofs ++)
82                         {
83                                 if( !MM_Allocate( pageptr ) )
84                                 {
85                                         Warning("OOM - VFS_AllocHandle");
86                                         Threads_Exit(0, 0xFF);  // Terminate user
87                                 }
88                                 pageptr ++;
89                         }
90                         memset( gaUserHandles, 0, size );
91                 }
92                 // Get a handle
93                 for( int i = 0; i < max_handles; i ++ )
94                 {
95                         if(gaUserHandles[i].Node)       continue;
96                         gaUserHandles[i].Node = Node;
97                         gaUserHandles[i].Position = 0;
98                         gaUserHandles[i].Mode = Mode;
99                         return i;
100                 }
101         }
102         else
103         {
104                 // Allocate space if not already
105                 if( MM_GetPhysAddr( gaKernelHandles ) == 0 )
106                 {
107                         tPage   *pageptr = (void*)gaKernelHandles;
108                         size_t  size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
109                         for(size_t ofs = 0; ofs < size; ofs += size)
110                         {
111                                 if( !MM_Allocate( pageptr ) )
112                                 {
113                                         Panic("OOM - VFS_AllocHandle");
114                                 }
115                                 pageptr ++;
116                         }
117                         memset( gaKernelHandles, 0, size );
118                 }
119                 // Get a handle
120                 for(int i=0;i<MAX_KERNEL_FILES;i++)
121                 {
122                         if(gaKernelHandles[i].Node)     continue;
123                         gaKernelHandles[i].Node = Node;
124                         gaKernelHandles[i].Position = 0;
125                         gaKernelHandles[i].Mode = Mode;
126                         return i|VFS_KERNEL_FLAG;
127                 }
128         }
129         
130         return -1;
131 }
132
133 void VFS_ReferenceUserHandles(void)
134 {
135         const int       max_handles = *Threads_GetMaxFD(NULL);
136
137         // Check if this process has any handles
138         if( MM_GetPhysAddr( gaUserHandles ) == 0 )
139                 return ;
140         
141         for( int i = 0; i < max_handles; i ++ )
142         {
143                 tVFS_Handle     *h;
144                 h = &gaUserHandles[i];
145                 if( !h->Node )
146                         continue ;
147                 _ReferenceNode(h->Node);
148                 h->Mount->OpenHandleCount ++;
149         }
150 }
151
152 void VFS_CloseAllUserHandles(struct sProcess *Process)
153 {
154         const int       max_handles = *Threads_GetMaxFD(Process);
155         ENTER("pProcess", Process);
156
157         if( max_handles >= PAGE_SIZE / sizeof(tVFS_Handle) )
158                 TODO("More than a page of handles");
159
160         tVFS_Handle     *handles = MM_MapTempFromProc(Process, gaUserHandles);
161         LOG("handles=%p", handles);
162         // Check if this process has any handles
163         if( !handles ) {
164                 LEAVE('-');
165                 return ;
166         }
167         
168         for( int i = 0; i < max_handles; i ++ )
169         {
170                 tVFS_Handle     *h = &handles[i];
171                 LOG("handles[%i].Node = %p", i, h->Node);
172                 if( !h->Node )
173                         continue ;
174                 _CloseNode(h->Node);
175                 h->Node = NULL;
176         }
177         
178         MM_FreeTemp(handles);
179         LEAVE('-');
180 }
181
182 /**
183  * \brief Take a backup of a set of file descriptors
184  */
185 void *VFS_SaveHandles(int NumFDs, int *FDs)
186 {
187         tVFS_Handle     *ret;
188         const int       max_handles = *Threads_GetMaxFD(NULL);
189         
190         // Check if this process has any handles
191         if( MM_GetPhysAddr( gaUserHandles ) == 0 )
192                 return NULL;
193
194         // Allocate
195         ret = malloc( NumFDs * sizeof(tVFS_Handle) );
196         if( !ret )
197                 return NULL;    
198
199         if( NumFDs > max_handles )
200                 NumFDs = max_handles;
201
202         // Take copies of the handles
203         if( FDs == NULL ) {
204                 memcpy(ret, gaUserHandles, NumFDs * sizeof(tVFS_Handle));
205         }
206         else
207         {
208                 for( int i = 0; i < NumFDs; i ++ )
209                 {
210                         if( FDs[i] < -1 )
211                         {
212                                 Log_Warning("VFS", "VFS_SaveHandles - Slot %i error FD (%i<0), ignorning",
213                                         i, FDs[i]);
214                                 memset(&ret[i], 0, sizeof(tVFS_Handle));
215                                 continue ;
216                         }
217                         
218                         int fd = FDs[i] & (VFS_KERNEL_FLAG - 1);
219                         tVFS_Handle *h = VFS_GetHandle(fd);
220                         if(!h) {
221                                 Log_Warning("VFS", "VFS_SaveHandles - Invalid FD 0x%x (%i) in slot %i",
222                                         fd, FDs[i], i );
223                                 free(ret);
224                                 return NULL;
225                         }
226 //                      Log("%i: Duplicate FD %i (%p)", i, fd, h->Node);
227                         memcpy( &ret[i], h, sizeof(tVFS_Handle) );
228                 }
229         }
230         
231         // Reference nodes/mounts
232         for( int i = 0; i < NumFDs; i ++ )
233         {
234                 tVFS_Handle *h = &ret[i];
235                 // Reference node
236                 if( !h->Node )
237                         continue ;
238 //              Debug("VFS_SaveHandles: %i %p", i, h->Node);
239                 _ReferenceNode(h->Node);
240                 h->Mount->OpenHandleCount ++;
241         }       
242
243         return ret;
244 }
245
246 void VFS_RestoreHandles(int NumFDs, void *Handles)
247 {
248         tVFS_Handle     *handles = Handles;
249         const int       max_handles = *Threads_GetMaxFD(NULL);
250
251         // NULL = nothing to do
252         if( !Handles )
253                 return ;
254         
255         if( NumFDs > max_handles ) {
256                 Log_Notice("VFS", "RestoreHandles: Capping from %i FDs to %i", NumFDs, max_handles);
257                 NumFDs = max_handles;
258         }
259
260         // Allocate user handle area (and dereference existing handles)
261         for( int i = 0; i < NumFDs; i ++ )
262         {
263                 tVFS_Handle *h = &gaUserHandles[i];
264                 
265                 if( !MM_GetPhysAddr(h) )
266                 {
267                         void    *pg = (void*)( (tVAddr)h & ~(PAGE_SIZE-1) );
268                         if( !MM_Allocate( pg ) ) 
269                         {
270                                 // OOM?
271                                 return ;
272                         }
273                         memset(pg, 0, PAGE_SIZE);
274                 }
275                 // Safe to dereference, as Threads_CloneTCB references handles
276                 #if 1
277                 else
278                 {
279                         if(h->Node)
280                         {
281                                 _CloseNode(h->Node);
282                                 h->Mount->OpenHandleCount --;
283                         }
284                 }
285                 #endif
286         }
287         
288         // Clean up existing
289         // Restore handles
290         memcpy( gaUserHandles, handles, NumFDs * sizeof(tVFS_Handle) );
291         // Reference when copied
292         for( int i = 0; i < NumFDs; i ++ )
293         {
294                 tVFS_Handle     *h = &gaUserHandles[i];
295         
296                 if( !h->Node )
297                         continue ;
298 //              Debug("VFS_RestoreHandles: %i %p", i, h->Node);
299                 _ReferenceNode(h->Node);
300                 h->Mount->OpenHandleCount ++;
301         }
302         for( int i = NumFDs; i < max_handles; i ++ )
303         {
304                 gaUserHandles[i].Node = NULL;
305         }
306 }
307
308 void VFS_FreeSavedHandles(int NumFDs, void *Handles)
309 {
310         tVFS_Handle     *handles = Handles;
311          int    i;
312
313         // NULL = nothing to do
314         if( !Handles )
315                 return ;        
316         
317         // Dereference all saved nodes
318         for( i = 0; i < NumFDs; i ++ )
319         {
320                 tVFS_Handle     *h = &handles[i];
321         
322                 if( !h->Node )
323                         continue ;
324                 _CloseNode(h->Node);
325                 
326                 ASSERT(h->Mount->OpenHandleCount > 0);
327                 LOG("dec. mntpt '%s' to %i", h->Mount->MountPoint, h->Mount->OpenHandleCount-1);
328                 h->Mount->OpenHandleCount --;
329         }
330         free( Handles );
331 }

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