Fixing a kernel #PF caused by an unitialised VFS method
[tpg/acess2.git] / Kernel / vfs / open.c
1 /*
2  * AcessMicro VFS
3  * - Open, Close and ChDir
4  */
5 #define DEBUG   0
6 #include <acess.h>
7 #include <mm_virt.h>
8 #include "vfs.h"
9 #include "vfs_int.h"
10 #include "vfs_ext.h"
11
12 // === CONSTANTS ===
13 #define OPEN_MOUNT_ROOT 1
14 #define MAX_KERNEL_FILES        128
15 #define MAX_PATH_SLASHES        256
16
17 // === IMPORTS ===
18 extern tVFS_Node        gVFS_MemRoot;
19 extern tVFS_Mount       *gVFS_RootMount;
20
21 // === GLOBALS ===
22 tVFS_Handle     *gaUserHandles = (void*)MM_PPD_VFS;
23 tVFS_Handle     *gaKernelHandles = (void*)MM_KERNEL_VFS;
24
25 // === CODE ===
26 /**
27  * \fn char *VFS_GetAbsPath(char *Path)
28  * \brief Create an absolute path from a relative one
29  */
30 char *VFS_GetAbsPath(char *Path)
31 {
32         char    *ret;
33          int    pathLen = strlen(Path);
34         char    *pathComps[MAX_PATH_SLASHES];
35         char    *tmpStr;
36         int             iPos = 0;
37         int             iPos2 = 0;
38         char    *chroot = CFGPTR(CFG_VFS_CHROOT);
39          int    chrootLen;
40         char    *cwd = CFGPTR(CFG_VFS_CWD);
41          int    cwdLen;
42         
43         ENTER("sPath", Path);
44         
45         // Memory File
46         if(Path[0] == '$') {
47                 ret = malloc(strlen(Path)+1);
48                 if(!ret) {
49                         Warning("VFS_GetAbsPath - malloc() returned NULL");
50                         return NULL;
51                 }
52                 strcpy(ret, Path);
53                 LEAVE('p', ret);
54                 return ret;
55         }
56         
57         // - Fetch ChRoot
58         if( chroot == NULL ) {
59                 chroot = "";
60                 chrootLen = 0;
61         } else {
62                 chrootLen = strlen(chroot);
63         }
64         
65         // Check if the path is already absolute
66         if(Path[0] == '/') {
67                 ret = malloc(pathLen + 1);
68                 if(!ret) {
69                         Warning("VFS_GetAbsPath - malloc() returned NULL");
70                         return NULL;
71                 }
72                 strcpy(ret, Path);
73         } else {
74                 if(cwd == NULL) {
75                         cwd = "/";
76                         cwdLen = 1;
77                 }
78                 else {
79                         cwdLen = strlen(cwd);
80                 }
81                 // Prepend the current directory
82                 ret = malloc( cwdLen + 1 + pathLen + 1 );
83                 strcpy(ret, cwd);
84                 ret[cwdLen] = '/';
85                 strcpy(&ret[cwdLen+1], Path);
86                 //Log("ret = '%s'\n", ret);
87         }
88         
89         // Parse Path
90         pathComps[iPos++] = tmpStr = ret+1;
91         while(*tmpStr)
92         {
93                 if(*tmpStr++ == '/')
94                 {
95                         pathComps[iPos++] = tmpStr;
96                         if(iPos == MAX_PATH_SLASHES) {
97                                 LOG("Path '%s' has too many elements", Path);
98                                 free(ret);
99                                 LEAVE('n');
100                                 return NULL;
101                         }
102                 }
103         }
104         pathComps[iPos] = NULL;
105         
106         // Cleanup
107         iPos2 = iPos = 0;
108         while(pathComps[iPos])
109         {
110                 tmpStr = pathComps[iPos];
111                 // Always Increment iPos
112                 iPos++;
113                 // ..
114                 if(tmpStr[0] == '.' && tmpStr[1] == '.' && (tmpStr[2] == '/' || tmpStr[2] == '\0') )
115                 {
116                         if(iPos2 != 0)
117                                 iPos2 --;
118                         continue;
119                 }
120                 // .
121                 if(tmpStr[0] == '.' && (tmpStr[1] == '/' || tmpStr[1] == '\0') )
122                 {
123                         continue;
124                 }
125                 // Empty
126                 if(tmpStr[0] == '/' || tmpStr[0] == '\0')
127                 {
128                         continue;
129                 }
130                 
131                 // Set New Position
132                 pathComps[iPos2] = tmpStr;
133                 iPos2++;
134         }
135         pathComps[iPos2] = NULL;
136         
137         // Build New Path
138         iPos2 = 1;      iPos = 0;
139         ret[0] = '/';
140         while(pathComps[iPos])
141         {
142                 tmpStr = pathComps[iPos];
143                 while(*tmpStr && *tmpStr != '/')
144                 {
145                         ret[iPos2++] = *tmpStr;
146                         tmpStr++;
147                 }
148                 ret[iPos2++] = '/';
149                 iPos++;
150         }
151         if(iPos2 > 1)
152                 ret[iPos2-1] = 0;
153         else
154                 ret[iPos2] = 0;
155         
156         
157         // Prepend the chroot
158         tmpStr = malloc(chrootLen + strlen(ret) + 1);
159         strcpy( tmpStr, chroot );
160         strcpy( tmpStr+chrootLen, ret );
161         free(ret);
162         ret = tmpStr;
163         
164         LEAVE('s', ret);
165         //Log("VFS_GetAbsPath: RETURN '%s'", ret);
166         return ret;
167 }
168
169 /**
170  * \fn char *VFS_ParsePath(char *Path, char **TruePath)
171  * \brief Parses a path, resolving sysmlinks and applying permissions
172  */
173 tVFS_Node *VFS_ParsePath(char *Path, char **TruePath)
174 {
175         tVFS_Mount      *mnt;
176         tVFS_Mount      *longestMount = gVFS_RootMount; // Root is first
177          int    cmp, retLength = 0;
178          int    ofs, nextSlash;
179         tVFS_Node       *curNode, *tmpNode;
180         char    *tmp;
181         
182         ENTER("sPath pTruePath", Path, TruePath);
183         
184         // Memory File
185         if(Path[0] == '$') {
186                 if(TruePath) {
187                         *TruePath = malloc(strlen(Path)+1);
188                         strcpy(*TruePath, Path);
189                 }
190                 curNode = gVFS_MemRoot.FindDir(&gVFS_MemRoot, Path);
191                 LEAVE('p', curNode);
192                 return curNode;
193         }
194         // For root we always fast return
195         
196         if(Path[0] == '/' && Path[1] == '\0') {
197                 if(TruePath) {
198                         *TruePath = malloc( gVFS_RootMount->MountPointLen+1 );
199                         strcpy(*TruePath, gVFS_RootMount->MountPoint);
200                 }
201                 LEAVE('p', gVFS_RootMount->RootNode);
202                 return gVFS_RootMount->RootNode;
203         }
204         
205         // Check if there is anything mounted
206         if(!gVFS_Mounts) {
207                 Warning("WTF! There's nothing mounted?");
208                 return NULL;
209         }
210         
211         // Find Mountpoint
212         for(mnt = gVFS_Mounts;
213                 mnt;
214                 mnt = mnt->Next)
215         {
216                 // Quick Check
217                 if( Path[mnt->MountPointLen] != '/' && Path[mnt->MountPointLen] != '\0')
218                         continue;
219                 // Length Check - If the length is smaller than the longest match sofar
220                 if(mnt->MountPointLen < longestMount->MountPointLen)    continue;
221                 // String Compare
222                 cmp = strcmp(Path, mnt->MountPoint);
223                 
224                 #if OPEN_MOUNT_ROOT
225                 // Fast Break - Request Mount Root
226                 if(cmp == 0) {
227                         if(TruePath) {
228                                 *TruePath = malloc( mnt->MountPointLen+1 );
229                                 strcpy(*TruePath, mnt->MountPoint);
230                         }
231                         LEAVE('p', mnt->RootNode);
232                         return mnt->RootNode;
233                 }
234                 #endif
235                 // Not a match, continue
236                 if(cmp != '/')  continue;
237                 longestMount = mnt;
238         }
239         
240         // Sanity Check
241         /*if(!longestMount) {
242                 Log("VFS_ParsePath - ERROR: No Root Node\n");
243                 return NULL;
244         }*/
245         
246         // Save to shorter variable
247         mnt = longestMount;
248         
249         LOG("mnt = {MountPoint:\"%s\"}", mnt->MountPoint);
250         
251         // Initialise String
252         if(TruePath)
253         {
254                 *TruePath = malloc( mnt->MountPointLen+1 );
255                 strcpy(*TruePath, mnt->MountPoint);
256                 retLength = mnt->MountPointLen;
257         }
258         
259         curNode = mnt->RootNode;
260         curNode->ReferenceCount ++;     
261         // Parse Path
262         ofs = mnt->MountPointLen+1;
263         for(; (nextSlash = strpos(&Path[ofs], '/')) != -1; Path[nextSlash]='/',ofs = nextSlash + 1)
264         {
265                 nextSlash += ofs;
266                 Path[nextSlash] = '\0';
267         
268                 // Check for empty string
269                 if( Path[ofs] == '\0' ) continue;
270         
271                 // Check permissions on root of filesystem
272                 if( !VFS_CheckACL(curNode, VFS_PERM_EXECUTE) ) {
273                         if(curNode->Close)      curNode->Close( curNode );
274                         if(TruePath) {
275                                 free(*TruePath);
276                                 *TruePath = NULL;
277                         }
278                         //Log("Permissions fail on '%s'", Path);
279                         LEAVE('n');
280                         return NULL;
281                 }
282                 
283                 // Check if the node has a FindDir method
284                 if( !curNode->FindDir )
285                 {
286                         if(curNode->Close)      curNode->Close(curNode);
287                         if(TruePath) {
288                                 free(*TruePath);
289                                 *TruePath = NULL;
290                         }
291                         Path[nextSlash] = '/';
292                         //Log("FindDir fail on '%s'", Path);
293                         LEAVE('n');
294                         return NULL;
295                 }
296                 LOG("FindDir(%p, '%s')", curNode, &Path[ofs]);
297                 // Get Child Node
298                 tmpNode = curNode->FindDir(curNode, &Path[ofs]);
299                 LOG("tmpNode = %p", tmpNode);
300                 if(curNode->Close)      curNode->Close(curNode);
301                 curNode = tmpNode;
302                 
303                 // Error Check
304                 if(!curNode) {
305                         LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
306                         if(TruePath) {
307                                 free(*TruePath);
308                                 *TruePath = NULL;
309                         }
310                         //Log("Child fail on '%s' ('%s)", Path, &Path[ofs]);
311                         Path[nextSlash] = '/';
312                         LEAVE('n');
313                         return NULL;
314                 }
315                 
316                 // Handle Symbolic Links
317                 if(curNode->Flags & VFS_FFLAG_SYMLINK) {
318                         if(TruePath) {
319                                 free(*TruePath);
320                                 *TruePath = NULL;
321                         }
322                         tmp = malloc( curNode->Size + 1 );
323                         if(!curNode->Read) {
324                                 Warning("VFS_ParsePath - Read of node %p is NULL (%s)",
325                                         curNode, Path);
326                                 if(curNode->Close)      curNode->Close(curNode);
327                                 LEAVE('n');
328                                 return NULL;
329                         }
330                         curNode->Read( curNode, 0, curNode->Size, tmp );
331                         tmp[ curNode->Size ] = '\0';
332                         
333                         // Parse Symlink Path
334                         curNode = VFS_ParsePath(tmp, TruePath);
335                         
336                         // Error Check
337                         if(!curNode) {
338                                 Log("Symlink fail '%s'", tmp);
339                                 free(tmp);      // Free temp string
340                                 LEAVE('n');
341                                 return NULL;
342                         }
343                         
344                         // Set Path Variable
345                         if(TruePath) {
346                                 *TruePath = tmp;
347                                 retLength = strlen(tmp);
348                         } else {
349                                 free(tmp);      // Free temp string
350                         }
351                         
352                         continue;
353                 }
354                 
355                 // Handle Non-Directories
356                 if( !(curNode->Flags & VFS_FFLAG_DIRECTORY) )
357                 {
358                         Warning("VFS_ParsePath - File in directory context");
359                         if(TruePath)    free(*TruePath);
360                         LEAVE('n');
361                         return NULL;
362                 }
363                 
364                 // Check if path needs extending
365                 if(!TruePath)   continue;
366                 
367                 // Increase buffer space
368                 tmp = realloc( *TruePath, retLength + strlen(&Path[ofs]) + 1 + 1 );
369                 // Check if allocation succeeded
370                 if(!tmp) {
371                         Warning("VFS_ParsePath -  Unable to reallocate true path buffer");
372                         free(*TruePath);
373                         if(curNode->Close)      curNode->Close(curNode);
374                         LEAVE('n');
375                         return NULL;
376                 }
377                 *TruePath = tmp;
378                 // Append to path
379                 (*TruePath)[retLength] = '/';
380                 strcpy(*TruePath+retLength+1, &Path[ofs]);
381                 // - Extend Path
382                 retLength += strlen(&Path[ofs])+1;
383         }
384         
385         // Get last node
386         LOG("VFS_ParsePath: FindDir(%p, '%s')", curNode, &Path[ofs]);
387         tmpNode = curNode->FindDir(curNode, &Path[ofs]);
388         LOG("tmpNode = %p", tmpNode);
389         if(curNode->Close)      curNode->Close(curNode);
390         // Check if file was found
391         if(!tmpNode) {
392                 LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
393                 //Log("Child fail '%s' ('%s')", Path, &Path[ofs]);
394                 if(TruePath)    free(*TruePath);
395                 if(curNode->Close)      curNode->Close(curNode);
396                 LEAVE('n');
397                 return NULL;
398         }
399         
400         if(TruePath)
401         {
402                 // Increase buffer space
403                 tmp = realloc(*TruePath, retLength + strlen(&Path[ofs]) + 1 + 1);
404                 // Check if allocation succeeded
405                 if(!tmp) {
406                         Warning("VFS_ParsePath -  Unable to reallocate true path buffer");
407                         free(*TruePath);
408                         if(tmpNode->Close)      tmpNode->Close(curNode);
409                         LEAVE('n');
410                         return NULL;
411                 }
412                 *TruePath = tmp;
413                 // Append to path
414                 (*TruePath)[retLength] = '/';
415                 strcpy(*TruePath + retLength + 1, &Path[ofs]);
416                 // - Extend Path
417                 //retLength += strlen(tmpNode->Name) + 1;
418         }
419         
420         LEAVE('p', tmpNode);
421         return tmpNode;
422 }
423
424 /**
425  * \fn int VFS_Open(char *Path, Uint Mode)
426  * \brief Open a file
427  */
428 int VFS_Open(char *Path, Uint Mode)
429 {
430         tVFS_Node       *node;
431         char    *absPath;
432          int    i;
433         
434         ENTER("sPath xMode", Path, Mode);
435         
436         // Get absolute path
437         absPath = VFS_GetAbsPath(Path);
438         LOG("absPath = \"%s\"", absPath);
439         // Parse path and get mount point
440         node = VFS_ParsePath(absPath, NULL);
441         // Free generated path
442         free(absPath);
443         
444         if(!node) {
445                 LOG("Cannot find node");
446                 LEAVE('i', -1);
447                 return -1;
448         }
449         
450         // Check for symlinks
451         if( !(Mode & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
452         {
453                 if( !node->Read ) {
454                         Warning("No read method on symlink");
455                         LEAVE('i', -1);
456                         return -1;
457                 }
458                 absPath = malloc(node->Size+1); // Allocate Buffer
459                 node->Read( node, 0, node->Size, absPath );     // Read Path
460                 
461                 absPath[ node->Size ] = '\0';   // End String
462                 if(node->Close) node->Close( node );    // Close old node
463                 node = VFS_ParsePath(absPath, NULL);    // Get new node
464                 free( absPath );        // Free allocated path
465         }
466         
467         if(!node) {
468                 LOG("Cannot find node");
469                 LEAVE('i', -1);
470                 return -1;
471         }
472         
473         i = 0;
474         i |= (Mode & VFS_OPENFLAG_EXEC) ? VFS_PERM_EXECUTE : 0;
475         i |= (Mode & VFS_OPENFLAG_READ) ? VFS_PERM_READ : 0;
476         i |= (Mode & VFS_OPENFLAG_WRITE) ? VFS_PERM_WRITE : 0;
477         
478         LOG("i = 0b%b", i);
479         
480         // Permissions Check
481         if( !VFS_CheckACL(node, i) ) {
482                 if(node->Close) node->Close( node );
483                 Log("VFS_Open: Permissions Failed");
484                 LEAVE('i', -1);
485                 return -1;
486         }
487         
488         // Check for a user open
489         if(Mode & VFS_OPENFLAG_USER)
490         {
491                 // Allocate Buffer
492                 if( MM_GetPhysAddr( (Uint)gaUserHandles ) == 0 )
493                 {
494                         Uint    addr, size;
495                         size = CFGINT(CFG_VFS_MAXFILES) * sizeof(tVFS_Handle);
496                         for(addr = 0; addr < size; addr += 0x1000)
497                                 MM_Allocate( (Uint)gaUserHandles + addr );
498                         memset( gaUserHandles, 0, size );
499                 }
500                 // Get a handle
501                 for(i=0;i<CFGINT(CFG_VFS_MAXFILES);i++)
502                 {
503                         if(gaUserHandles[i].Node)       continue;
504                         gaUserHandles[i].Node = node;
505                         gaUserHandles[i].Position = 0;
506                         gaUserHandles[i].Mode = Mode;
507                         LEAVE('i', i);
508                         return i;
509                 }
510         }
511         else
512         {
513                 // Allocate space if not already
514                 if( MM_GetPhysAddr( (Uint)gaKernelHandles ) == 0 )
515                 {
516                         Uint    addr, size;
517                         size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
518                         for(addr = 0; addr < size; addr += 0x1000)
519                                 MM_Allocate( (Uint)gaKernelHandles + addr );
520                         memset( gaKernelHandles, 0, size );
521                 }
522                 // Get a handle
523                 for(i=0;i<MAX_KERNEL_FILES;i++)
524                 {
525                         if(gaKernelHandles[i].Node)     continue;
526                         gaKernelHandles[i].Node = node;
527                         gaKernelHandles[i].Position = 0;
528                         gaKernelHandles[i].Mode = Mode;
529                         LEAVE('x', i|VFS_KERNEL_FLAG);
530                         return i|VFS_KERNEL_FLAG;
531                 }
532         }
533         
534         Log("VFS_Open: Out of handles");
535         LEAVE('i', -1);
536         return -1;
537 }
538
539
540 /**
541  * \brief Open a file from an open directory
542  */
543 int VFS_OpenChild(Uint *Errno, int FD, char *Name, Uint Mode)
544 {
545         tVFS_Handle     *h;
546         tVFS_Node       *node;
547          int    i;
548         
549         // Get handle
550         h = VFS_GetHandle(FD);
551         if(h == NULL) {
552                 Log_Warning("VFS", "VFS_OpenChild - Invalid file handle 0x%x", FD);
553                 if(Errno)       *Errno = EINVAL;
554                 LEAVE('i', -1);
555                 return -1;
556         }
557         
558         // Check for directory
559         if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
560                 Log_Warning("VFS", "VFS_OpenChild - Passed handle is not a directory", FD);
561                 if(Errno)       *Errno = ENOTDIR;
562                 LEAVE('i', -1);
563                 return -1;
564         }
565         
566         // Find Child
567         node = h->Node->FindDir(h->Node, Name);
568         if(!node) {
569                 if(Errno)       *Errno = ENOENT;
570                 LEAVE('i', -1);
571                 return -1;
572         }
573         
574         i = 0;
575         i |= (Mode & VFS_OPENFLAG_EXEC) ? VFS_PERM_EXECUTE : 0;
576         i |= (Mode & VFS_OPENFLAG_READ) ? VFS_PERM_READ : 0;
577         i |= (Mode & VFS_OPENFLAG_WRITE) ? VFS_PERM_WRITE : 0;
578         
579         // Permissions Check
580         if( !VFS_CheckACL(node, i) ) {
581                 if(node->Close) node->Close( node );
582                 Log_Notice("VFS", "VFS_OpenChild - Permissions Failed");
583                 if(Errno)       *Errno = EACCES;
584                 LEAVE('i', -1);
585                 return -1;
586         }
587         
588         // Check for a user open
589         if(Mode & VFS_OPENFLAG_USER)
590         {
591                 // Allocate Buffer
592                 if( MM_GetPhysAddr( (Uint)gaUserHandles ) == 0 )
593                 {
594                         Uint    addr, size;
595                         size = CFGINT(CFG_VFS_MAXFILES) * sizeof(tVFS_Handle);
596                         for(addr = 0; addr < size; addr += 0x1000)
597                                 MM_Allocate( (Uint)gaUserHandles + addr );
598                         memset( gaUserHandles, 0, size );
599                 }
600                 // Get a handle
601                 for(i=0;i<CFGINT(CFG_VFS_MAXFILES);i++)
602                 {
603                         if(gaUserHandles[i].Node)       continue;
604                         gaUserHandles[i].Node = node;
605                         gaUserHandles[i].Position = 0;
606                         gaUserHandles[i].Mode = Mode;
607                         LEAVE('i', i);
608                         return i;
609                 }
610         }
611         else
612         {
613                 // Allocate space if not already
614                 if( MM_GetPhysAddr( (Uint)gaKernelHandles ) == 0 )
615                 {
616                         Uint    addr, size;
617                         size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
618                         for(addr = 0; addr < size; addr += 0x1000)
619                                 MM_Allocate( (Uint)gaKernelHandles + addr );
620                         memset( gaKernelHandles, 0, size );
621                 }
622                 // Get a handle
623                 for(i=0;i<MAX_KERNEL_FILES;i++)
624                 {
625                         if(gaKernelHandles[i].Node)     continue;
626                         gaKernelHandles[i].Node = node;
627                         gaKernelHandles[i].Position = 0;
628                         gaKernelHandles[i].Mode = Mode;
629                         LEAVE('x', i|VFS_KERNEL_FLAG);
630                         return i|VFS_KERNEL_FLAG;
631                 }
632         }
633         
634         Log_Error("VFS", "VFS_OpenChild - Out of handles");
635         if(Errno)       *Errno = ENFILE;
636         LEAVE('i', -1);
637         return -1;
638 }
639
640 /**
641  * \fn void VFS_Close(int FD)
642  * \brief Closes an open file handle
643  */
644 void VFS_Close(int FD)
645 {
646         tVFS_Handle     *h;
647         
648         // Get handle
649         h = VFS_GetHandle(FD);
650         if(h == NULL) {
651                 Log_Warning("VFS", "Invalid file handle passed to VFS_Close, 0x%x\n", FD);
652                 return;
653         }
654         
655         #if VALIDATE_VFS_FUNCTIPONS
656         if(h->Node->Close && !MM_GetPhysAddr(h->Node->Close)) {
657                 Log_Warning("VFS", "Node %p's ->Close method is invalid (%p)",
658                         h->Node, h->Node->Close);
659                 return ;
660         }
661         #endif
662         
663         if(h->Node->Close)
664                 h->Node->Close( h->Node );
665         
666         h->Node = NULL;
667 }
668
669 /**
670  * \brief Change current working directory
671  */
672 int VFS_ChDir(char *Dest)
673 {
674         char    *buf;
675          int    fd;
676         tVFS_Handle     *h;
677         
678         // Create Absolute
679         buf = VFS_GetAbsPath(Dest);
680         if(buf == NULL) {
681                 Log("VFS_ChDir: Path expansion failed");
682                 return -1;
683         }
684         
685         // Check if path exists
686         fd = VFS_Open(buf, VFS_OPENFLAG_EXEC);
687         if(fd == -1) {
688                 Log("VFS_ChDir: Path is invalid");
689                 return -1;
690         }
691         
692         // Get node so we can check for directory
693         h = VFS_GetHandle(fd);
694         if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
695                 Log("VFS_ChDir: Path is not a directory");
696                 VFS_Close(fd);
697                 return -1;
698         }
699         
700         // Close file
701         VFS_Close(fd);
702         
703         // Free old working directory
704         if( CFGPTR(CFG_VFS_CWD) )
705                 free( CFGPTR(CFG_VFS_CWD) );
706         // Set new
707         CFGPTR(CFG_VFS_CWD) = buf;
708         
709         Log("Updated CWD to '%s'", buf);
710         
711         return 1;
712 }
713
714 /**
715  * \fn int VFS_ChRoot(char *New)
716  * \brief Change current root directory
717  */
718 int VFS_ChRoot(char *New)
719 {
720         char    *buf;
721          int    fd;
722         tVFS_Handle     *h;
723         
724         if(New[0] == '/' && New[1] == '\0')
725                 return 1;       // What a useless thing to ask!
726         
727         // Create Absolute
728         buf = VFS_GetAbsPath(New);
729         if(buf == NULL) {
730                 LOG("Path expansion failed");
731                 return -1;
732         }
733         
734         // Check if path exists
735         fd = VFS_Open(buf, VFS_OPENFLAG_EXEC);
736         if(fd == -1) {
737                 LOG("Path is invalid");
738                 return -1;
739         }
740         
741         // Get node so we can check for directory
742         h = VFS_GetHandle(fd);
743         if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
744                 LOG("Path is not a directory");
745                 VFS_Close(fd);
746                 return -1;
747         }
748         
749         // Close file
750         VFS_Close(fd);
751         
752         // Free old working directory
753         if( CFGPTR(CFG_VFS_CHROOT) )
754                 free( CFGPTR(CFG_VFS_CHROOT) );
755         // Set new
756         CFGPTR(CFG_VFS_CHROOT) = buf;
757         
758         LOG("Updated Root to '%s'", buf);
759         
760         return 1;
761 }
762
763 /**
764  * \fn tVFS_Handle *VFS_GetHandle(int FD)
765  * \brief Gets a pointer to the handle information structure
766  */
767 tVFS_Handle *VFS_GetHandle(int FD)
768 {
769         tVFS_Handle     *h;
770         
771         //Log_Debug("VFS", "VFS_GetHandle: (FD=0x%x)", FD);
772         
773         if(FD < 0)      return NULL;
774         
775         if(FD & VFS_KERNEL_FLAG) {
776                 FD &= (VFS_KERNEL_FLAG - 1);
777                 if(FD >= MAX_KERNEL_FILES)      return NULL;
778                 h = &gaKernelHandles[ FD ];
779         } else {
780                 if(FD >= CFGINT(CFG_VFS_MAXFILES))      return NULL;
781                 h = &gaUserHandles[ FD ];
782         }
783         
784         if(h->Node == NULL)     return NULL;
785         //Log_Debug("VFS", "VFS_GetHandle: RETURN %p", h);
786         return h;
787 }
788
789 // === EXPORTS ===
790 EXPORT(VFS_Open);
791 EXPORT(VFS_Close);

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