Fixed VFS_ChDir to handle symlinks by using VFS_Open
[tpg/acess2.git] / Kernel / vfs / open.c
index f025e0d..eebaa82 100644 (file)
@@ -51,6 +51,10 @@ char *VFS_GetAbsPath(char *Path)
        // Memory File
        if(Path[0] == '$') {
                ret = malloc(strlen(Path)+1);
+               if(!ret) {
+                       Warning("VFS_GetAbsPath - malloc() returned NULL");
+                       return NULL;
+               }
                strcpy(ret, Path);
                LEAVE('p', ret);
                return ret;
@@ -59,6 +63,10 @@ char *VFS_GetAbsPath(char *Path)
        // Check if the path is already absolute
        if(Path[0] == '/') {
                ret = malloc(pathLen + 1);
+               if(!ret) {
+                       Warning("VFS_GetAbsPath - malloc() returned NULL");
+                       return NULL;
+               }
                strcpy(ret, Path);
                baseLen = 1;
        } else {
@@ -224,7 +232,10 @@ tVFS_Node *VFS_ParsePath(char *Path, char **TruePath)
                // Check permissions on root of filesystem
                if( !VFS_CheckACL(curNode, VFS_PERM_EXECUTE) ) {
                        curNode->Close( curNode );
-                       if(TruePath)    free(*TruePath);
+                       if(TruePath) {
+                               free(*TruePath);
+                               *TruePath = NULL;
+                       }
                        LEAVE('n');
                        return NULL;
                }
@@ -232,7 +243,10 @@ tVFS_Node *VFS_ParsePath(char *Path, char **TruePath)
                // Check if the node has a FindDir method
                if(!curNode->FindDir) {
                        if(curNode->Close)      curNode->Close(curNode);
-                       if(TruePath)    free(*TruePath);
+                       if(TruePath) {
+                               free(*TruePath);
+                               *TruePath = NULL;
+                       }
                        Path[nextSlash] = '/';
                        LEAVE('n');
                        return NULL;
@@ -248,8 +262,10 @@ tVFS_Node *VFS_ParsePath(char *Path, char **TruePath)
                // Error Check
                if(!curNode) {
                        LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
-                       if(TruePath)
+                       if(TruePath) {
                                free(*TruePath);
+                               *TruePath = NULL;
+                       }
                        Path[nextSlash] = '/';
                        LEAVE('n');
                        return NULL;
@@ -257,18 +273,20 @@ tVFS_Node *VFS_ParsePath(char *Path, char **TruePath)
                
                // Handle Symbolic Links
                if(curNode->Flags & VFS_FFLAG_SYMLINK) {
-                       if(TruePath)
+                       if(TruePath) {
                                free(*TruePath);
+                               *TruePath = NULL;
+                       }
                        tmp = malloc( curNode->Size + 1 );
                        curNode->Read( curNode, 0, curNode->Size, tmp );
                        tmp[ curNode->Size ] = '\0';
                        
                        // Parse Symlink Path
                        curNode = VFS_ParsePath(tmp, TruePath);
-                       free(tmp);      // Free temp string
                        
                        // Error Check
                        if(!curNode) {
+                               free(tmp);      // Free temp string
                                LEAVE('n');
                                return NULL;
                        }
@@ -277,6 +295,8 @@ tVFS_Node *VFS_ParsePath(char *Path, char **TruePath)
                        if(TruePath) {
                                *TruePath = tmp;
                                retLength = strlen(tmp);
+                       } else {
+                               free(tmp);      // Free temp string
                        }
                        
                        continue;
@@ -380,7 +400,7 @@ int VFS_Open(char *Path, Uint Mode)
        if( !(Mode & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
        {
                if( !node->Read ) {
-                       LOG("No read method on symlink");
+                       Warning("No read method on symlink");
                        LEAVE('i', -1);
                        return -1;
                }
@@ -483,20 +503,69 @@ void VFS_Close(int FD)
        h->Node = NULL;
 }
 
+/**
+ * \fn int VFS_ChDir(char *New)
+ * \brief Change current working directory
+ */
+int VFS_ChDir(char *New)
+{
+       char    *buf;
+        int    fd;
+       tVFS_Handle     *h;
+       
+       // Create Absolute
+       buf = VFS_GetAbsPath(New);
+       if(buf == NULL) {
+               Log("VFS_ChDir: Path expansion failed");
+               return -1;
+       }
+       
+       // Check if path exists
+       fd = VFS_Open(buf, VFS_OPENFLAG_EXEC);
+       if(fd == -1) {
+               Log("VFS_ChDir: Path is invalid");
+               return -1;
+       }
+       
+       // Get node so we can check for directory
+       h = VFS_GetHandle(fd);
+       if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
+               Log("VFS_ChDir: Path is not a directory");
+               VFS_Close(fd);
+               return -1;
+       }
+       
+       // Close file
+       VFS_Close(fd);
+       
+       // Free working directory and set new one
+       free( CFGPTR(CFG_VFS_CWD) );
+       CFGPTR(CFG_VFS_CWD) = buf;
+       
+       Log("Updated CWD to '%s'", buf);
+       
+       return 1;
+}
+
 /**
  * \fn tVFS_Handle *VFS_GetHandle(int FD)
  * \brief Gets a pointer to the handle information structure
  */
 tVFS_Handle *VFS_GetHandle(int FD)
 {
+       tVFS_Handle     *h;
+       
        if(FD < 0)      return NULL;
        
        if(FD & VFS_KERNEL_FLAG) {
                FD &= (VFS_KERNEL_FLAG - 1);
                if(FD >= MAX_KERNEL_FILES)      return NULL;
-               return &gaKernelHandles[ FD ];
+               h = &gaKernelHandles[ FD ];
        } else {
                if(FD >= CFGINT(CFG_VFS_MAXFILES))      return NULL;
-               return &gaUserHandles[ FD ];
+               h = &gaUserHandles[ FD ];
        }
+       
+       if(h->Node == NULL)     return NULL;
+       return h;
 }

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