X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fvfs%2Fopen.c;h=ed79ba11dfdbb31a601cd06d6f22dcedeb231b5e;hb=0f8226381e0a19e8e8e11eafbf4589532e45d430;hp=5d1d9fa7cd114af74644ef1e1ccbd50b2a955894;hpb=425494c449d668bf4728eef3a45f890432fd9999;p=tpg%2Facess2.git diff --git a/Kernel/vfs/open.c b/Kernel/vfs/open.c index 5d1d9fa7..ed79ba11 100644 --- a/Kernel/vfs/open.c +++ b/Kernel/vfs/open.c @@ -11,6 +11,8 @@ // === CONSTANTS === #define OPEN_MOUNT_ROOT 1 #define MAX_PATH_SLASHES 256 +#define MAX_NESTED_LINKS 4 +#define MAX_PATH_LEN 255 // === IMPORTS === extern tVFS_Node gVFS_MemRoot; @@ -59,13 +61,14 @@ char *VFS_GetAbsPath(const char *Path) // Check if the path is already absolute if(Path[0] == '/') { - ret = malloc(pathLen + 1); + ret = malloc(chrootLen + pathLen + 1); if(!ret) { Log_Warning("VFS", "VFS_GetAbsPath: malloc() returned NULL"); return NULL; } - strcpy(ret, Path); - } else { + strcpy(ret + chrootLen, Path); + } + else { if(cwd == NULL) { cwd = "/"; cwdLen = 1; @@ -74,15 +77,15 @@ char *VFS_GetAbsPath(const char *Path) cwdLen = strlen(cwd); } // Prepend the current directory - ret = malloc( cwdLen + 1 + pathLen + 1 ); - strcpy(ret, cwd); + ret = malloc(chrootLen + cwdLen + 1 + pathLen + 1 ); + strcpy(ret+chrootLen, cwd); ret[cwdLen] = '/'; - strcpy(&ret[cwdLen+1], Path); + strcpy(ret+chrootLen+cwdLen+1, Path); //Log("ret = '%s'", ret); } // Parse Path - pathComps[iPos++] = tmpStr = ret+1; + pathComps[iPos++] = tmpStr = ret+chrootLen+1; while(*tmpStr) { if(*tmpStr++ == '/') @@ -130,7 +133,7 @@ char *VFS_GetAbsPath(const char *Path) pathComps[iPos2] = NULL; // Build New Path - iPos2 = 1; iPos = 0; + iPos2 = chrootLen + 1; iPos = 0; ret[0] = '/'; while(pathComps[iPos]) { @@ -147,17 +150,12 @@ char *VFS_GetAbsPath(const char *Path) ret[iPos2-1] = 0; else ret[iPos2] = 0; - - + // Prepend the chroot - tmpStr = malloc(chrootLen + strlen(ret) + 1); - strcpy( tmpStr, chroot ); - strcpy( tmpStr+chrootLen, ret ); - free(ret); - ret = tmpStr; + memcpy( ret, chroot, chrootLen ); LEAVE('s', ret); - //Log("VFS_GetAbsPath: RETURN '%s'", ret); +// Log_Debug("VFS", "VFS_GetAbsPath: RETURN '%s'", ret); return ret; } @@ -167,12 +165,13 @@ char *VFS_GetAbsPath(const char *Path) */ tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath) { - tVFS_Mount *mnt; - tVFS_Mount *longestMount = gVFS_RootMount; // Root is first + tVFS_Mount *mnt, *longestMount; int cmp, retLength = 0; int ofs, nextSlash; + int iNestedLinks = 0; tVFS_Node *curNode, *tmpNode; char *tmp; + char path_buffer[MAX_PATH_LEN+1]; ENTER("sPath pTruePath", Path, TruePath); @@ -186,7 +185,8 @@ tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath) LEAVE('p', curNode); return curNode; } - + +restart_parse: // For root we always fast return if(Path[0] == '/' && Path[1] == '\0') { if(TruePath) { @@ -197,16 +197,15 @@ tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath) return gVFS_RootMount->RootNode; } - // Check if there is an`ything mounted + // Check if there is anything mounted if(!gVFS_Mounts) { - Warning("WTF! There's nothing mounted?"); + Log_Error("VFS", "VFS_ParsePath - No filesystems mounted"); return NULL; } // Find Mountpoint - for(mnt = gVFS_Mounts; - mnt; - mnt = mnt->Next) + longestMount = gVFS_RootMount; + for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next) { // Quick Check if( Path[mnt->MountPointLen] != '/' && Path[mnt->MountPointLen] != '\0') @@ -240,7 +239,8 @@ tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath) // Initialise String if(TruePath) { - *TruePath = malloc( mnt->MountPointLen+1 ); + // Assumes that the resultant path (here) will not be > strlen(Path) + 1 + *TruePath = malloc( strlen(Path) + 1 ); strcpy(*TruePath, mnt->MountPoint); retLength = mnt->MountPointLen; } @@ -312,53 +312,48 @@ tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath) *TruePath = NULL; } if(!curNode->Read) { - Warning("VFS_ParsePath - Read of node %p is NULL (%s)", + Log_Warning("VFS", "VFS_ParsePath - Read of symlink node %p'%s' is NULL", curNode, Path); if(curNode->Close) curNode->Close(curNode); - // No need to free *TruePath, see above + // No need to free *TruePath, it should already be NULL LEAVE('n'); return NULL; } - tmp = malloc( curNode->Size + 1 ); - if(!tmp) { - Log_Warning("VFS", "VFS_ParsePath - Malloc failure"); - // No need to free *TruePath, see above + if(iNestedLinks > MAX_NESTED_LINKS) { + if(curNode->Close) curNode->Close(curNode); LEAVE('n'); return NULL; } - curNode->Read( curNode, 0, curNode->Size, tmp ); - tmp[ curNode->Size ] = '\0'; // Parse Symlink Path - curNode = VFS_ParsePath(tmp, TruePath); - if(TruePath) - LOG("VFS", "*TruePath='%s'", *TruePath); - - // Error Check - if(!curNode) { - Log_Debug("VFS", "Symlink fail '%s'", tmp); - free(tmp); // Free temp string - if(TruePath) free(TruePath); - LEAVE('n'); - return NULL; + // - Just update the path variable and restart the function + // > Count nested symlinks and limit to some value (counteracts loops) + { + int remlen = strlen(Path) - (ofs + nextSlash); + if( curNode->Size + remlen > MAX_PATH_LEN ) { + if(curNode->Close) curNode->Close(curNode); + Log_Warning("VFS", "VFS_ParsePath - Symlinked path too long"); + LEAVE('n'); + return NULL; + } + curNode->Read( curNode, 0, curNode->Size, path_buffer ); + path_buffer[ curNode->Size ] = '\0'; + strcat(path_buffer, Path + ofs+nextSlash); + + Path = path_buffer; +// Log_Debug("VFS", "VFS_ParsePath: Symlink translated to '%s'", Path); + iNestedLinks ++; } - - // Free temp link - free(tmp); - - // Set Path Variable - if(TruePath) { - retLength = strlen(*TruePath); - } - - continue; + + // EVIL: Goto :) + goto restart_parse; } // Handle Non-Directories if( !(curNode->Flags & VFS_FFLAG_DIRECTORY) ) { - Warning("VFS_ParsePath - File in directory context"); + Log_Warning("VFS", "VFS_ParsePath - Path segment is not a directory"); if(TruePath) free(*TruePath); LEAVE('n'); return NULL; @@ -371,7 +366,7 @@ tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath) tmp = realloc( *TruePath, retLength + strlen(pathEle) + 1 + 1 ); // Check if allocation succeeded if(!tmp) { - Warning("VFS_ParsePath - Unable to reallocate true path buffer"); + Log_Warning("VFS", "VFS_ParsePath - Unable to reallocate true path buffer"); free(*TruePath); *TruePath = NULL; if(curNode->Close) curNode->Close(curNode); @@ -395,7 +390,7 @@ tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath) free(*TruePath); *TruePath = NULL; } - Log("FindDir fail on '%s'", Path); + Log_Warning("VFS", "VFS_ParsePath - FindDir doesn't exist for element of '%s'", Path); LEAVE('n'); return NULL; } @@ -421,7 +416,7 @@ tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath) tmp = realloc(*TruePath, retLength + strlen(&Path[ofs]) + 1 + 1); // Check if allocation succeeded if(!tmp) { - Warning("VFS_ParsePath - Unable to reallocate true path buffer"); + Log_Warning("VFS", "VFS_ParsePath - Unable to reallocate true path buffer"); free(*TruePath); if(tmpNode->Close) tmpNode->Close(curNode); LEAVE('n'); @@ -455,7 +450,7 @@ int VFS_Open(const char *Path, Uint Mode) absPath = VFS_GetAbsPath(Path); if(absPath == NULL) { Log_Warning("VFS", "VFS_Open: Path expansion failed '%s'", Path); - return -1; + LEAVE_RET('i', -1); } LOG("absPath = \"%s\"", absPath); // Parse path and get mount point @@ -465,31 +460,31 @@ int VFS_Open(const char *Path, Uint Mode) if(!node) { LOG("Cannot find node"); - LEAVE('i', -1); - return -1; + LEAVE_RET('i', -1); } // Check for symlinks if( !(Mode & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) ) { + char tmppath[node->Size+1]; + if( node->Size > MAX_PATH_LEN ) { + Log_Warning("VFS", "VFS_Open - Symlink is too long (%i)", node->Size); + LEAVE_RET('i', -1); + } if( !node->Read ) { - Warning("No read method on symlink"); - LEAVE('i', -1); - return -1; + Log_Warning("VFS", "VFS_Open - No read method on symlink"); + LEAVE_RET('i', -1); + } + // Read symlink's path + node->Read( node, 0, node->Size, tmppath ); + tmppath[ node->Size ] = '\0'; + if(node->Close) node->Close( node ); + // Open the target + node = VFS_ParsePath(tmppath, NULL); + if(!node) { + LOG("Cannot find symlink target node (%s)", tmppath); + LEAVE_RET('i', -1); } - absPath = malloc(node->Size+1); // Allocate Buffer - node->Read( node, 0, node->Size, absPath ); // Read Path - - absPath[ node->Size ] = '\0'; // End String - if(node->Close) node->Close( node ); // Close old node - node = VFS_ParsePath(absPath, NULL); // Get new node - free( absPath ); // Free allocated path - } - - if(!node) { - LOG("Cannot find node"); - LEAVE('i', -1); - return -1; } i = 0; @@ -502,20 +497,17 @@ int VFS_Open(const char *Path, Uint Mode) // Permissions Check if( !VFS_CheckACL(node, i) ) { if(node->Close) node->Close( node ); - Log("VFS_Open: Permissions Failed"); - LEAVE('i', -1); - return -1; + Log_Log("VFS", "VFS_Open: Permissions Failed"); + LEAVE_RET('i', -1); } i = VFS_AllocHandle( !!(Mode & VFS_OPENFLAG_USER), node, Mode ); - if( i >= 0 ) { - LEAVE('x', i); - return i; + if( i < 0 ) { + Log_Notice("VFS", "VFS_Open: Out of handles"); + LEAVE_RET('i', -1); } - Log("VFS_Open: Out of handles"); - LEAVE('i', -1); - return -1; + LEAVE_RET('x', i); } @@ -533,24 +525,21 @@ int VFS_OpenChild(Uint *Errno, int FD, const char *Name, Uint Mode) if(h == NULL) { Log_Warning("VFS", "VFS_OpenChild - Invalid file handle 0x%x", FD); if(Errno) *Errno = EINVAL; - LEAVE('i', -1); - return -1; + LEAVE_RET('i', -1); } // Check for directory if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) { Log_Warning("VFS", "VFS_OpenChild - Passed handle is not a directory", FD); if(Errno) *Errno = ENOTDIR; - LEAVE('i', -1); - return -1; + LEAVE_RET('i', -1); } // Find Child node = h->Node->FindDir(h->Node, Name); if(!node) { if(Errno) *Errno = ENOENT; - LEAVE('i', -1); - return -1; + LEAVE_RET('i', -1); } i = 0; @@ -563,20 +552,17 @@ int VFS_OpenChild(Uint *Errno, int FD, const char *Name, Uint Mode) if(node->Close) node->Close( node ); Log_Notice("VFS", "VFS_OpenChild - Permissions Failed"); if(Errno) *Errno = EACCES; - LEAVE('i', -1); - return -1; + LEAVE_RET('i', -1); } i = VFS_AllocHandle( !!(Mode & VFS_OPENFLAG_USER), node, Mode ); if( i >= 0 ) { - LEAVE('x', i); - return i; + LEAVE_RET('x', i); } Log_Error("VFS", "VFS_OpenChild - Out of handles"); if(Errno) *Errno = ENFILE; - LEAVE('i', -1); - return -1; + LEAVE_RET('i', -1); } /**