X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Fvfs%2Fopen.c;h=e5a206fbe3a6376dcc8bb00500cd0c7c8dcf2232;hb=9c4eedf4893f851bd1ba60ce541c8d098a9ef7f7;hp=2bfb261232058562ed881b2be1cde57c7ea3cac2;hpb=015f48988e0ff398409d71dfc692005ab439490a;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/vfs/open.c b/KernelLand/Kernel/vfs/open.c index 2bfb2612..e5a206fb 100644 --- a/KernelLand/Kernel/vfs/open.c +++ b/KernelLand/Kernel/vfs/open.c @@ -15,16 +15,29 @@ #define MAX_PATH_SLASHES 256 #define MAX_NESTED_LINKS 4 #define MAX_PATH_LEN 255 +#define MAX_MARSHALLED_HANDLES 16 // Max outstanding // === IMPORTS === extern tVFS_Mount *gVFS_RootMount; extern tVFS_Node *VFS_MemFile_Create(const char *Path); +// === TYPES === +typedef struct sVFS_MarshaledHandle +{ + Uint32 Magic; + tTime AllocTime; + tVFS_Handle Handle; +} tVFS_MarshalledHandle; + // === PROTOTYPES === void _ReferenceMount(tVFS_Mount *Mount, const char *DebugTag); void _DereferenceMount(tVFS_Mount *Mount, const char *DebugTag); int VFS_int_CreateHandle(tVFS_Node *Node, tVFS_Mount *Mount, int Mode); +// === GLOBALS === +tMutex glVFS_MarshalledHandles; +tVFS_MarshalledHandle gaVFS_MarshalledHandles[MAX_MARSHALLED_HANDLES]; + // === CODE === void _ReferenceMount(tVFS_Mount *Mount, const char *DebugTag) { @@ -49,9 +62,9 @@ char *VFS_GetAbsPath(const char *Path) char *tmpStr; int iPos = 0; int iPos2 = 0; - const char *chroot = *Threads_GetChroot(); + const char *chroot = *Threads_GetChroot(NULL); int chrootLen; - const char *cwd = *Threads_GetCWD(); + const char *cwd = *Threads_GetCWD(NULL); int cwdLen; ENTER("sPath", Path); @@ -296,7 +309,7 @@ restart_parse: pathEle[nextSlash] = 0; // Check permissions on root of filesystem - if( !VFS_CheckACL(curNode, VFS_PERM_EXECUTE) ) { + if( !VFS_CheckACL(curNode, VFS_PERM_EXEC) ) { LOG("Permissions failure on '%s'", Path); errno = EPERM; goto _error; @@ -343,7 +356,7 @@ restart_parse: } if(iNestedLinks > MAX_NESTED_LINKS) { - Log_Notice("VFS", "VFS_ParsePath - Nested link limit exceeded"); + Log_Notice("VFS", "VFS_ParsePath - Nested link limit exceeded on '%.*s'", ofs, Path); errno = ENOENT; goto _error; } @@ -378,7 +391,8 @@ restart_parse: // Handle Non-Directories if( !(curNode->Flags & VFS_FFLAG_DIRECTORY) ) { - Log_Warning("VFS", "VFS_ParsePath - Path segment is not a directory"); + Log_Warning("VFS", "VFS_ParsePath - Path segment '%.*s' is not a directory (curNode{%p}->Flags = 0x%x)", + ofs+nextSlash, Path, curNode, curNode->Flags); errno = ENOTDIR; goto _error; } @@ -407,7 +421,7 @@ restart_parse: // Check final finddir call if( !curNode->Type || !curNode->Type->FindDir ) { - Log_Warning("VFS", "VFS_ParsePath - FindDir doesn't exist for element of '%s'", Path); + Log_Warning("VFS", "VFS_ParsePath - FindDir doesn't exist for leaf of '%s' (dir '%.*s')", Path, ofs, Path); errno = ENOENT; goto _error; } @@ -474,7 +488,7 @@ int VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode ) ENTER("pNode pMount xMode", Node, Mount, Mode); i = 0; - i |= (Mode & VFS_OPENFLAG_EXEC) ? VFS_PERM_EXECUTE : 0; + i |= (Mode & VFS_OPENFLAG_EXEC) ? VFS_PERM_EXEC : 0; i |= (Mode & VFS_OPENFLAG_READ) ? VFS_PERM_READ : 0; i |= (Mode & VFS_OPENFLAG_WRITE) ? VFS_PERM_WRITE : 0; @@ -557,7 +571,7 @@ int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode) } // Check ACLs on the parent - if( !VFS_CheckACL(pnode, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) { + if( !VFS_CheckACL(pnode, VFS_PERM_EXEC|VFS_PERM_WRITE) ) { errno = EACCES; goto _pnode_err; } @@ -706,7 +720,8 @@ int VFS_OpenInode(Uint32 Mount, Uint64 Inode, int Mode) // Does the filesystem support this? if( !mnt->Filesystem->GetNodeFromINode ) { - LOG("Filesystem does not support inode accesses"); + Log_Notice("VFS", "Filesystem '%s' does not support inode accesses", + mnt->Filesystem->Name); errno = ENOENT; LEAVE_RET('i', -1); } @@ -722,6 +737,31 @@ int VFS_OpenInode(Uint32 Mount, Uint64 Inode, int Mode) LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Mode)); } +int VFS_Reopen(int FD, const char *Path, int Flags) +{ + tVFS_Handle *h = VFS_GetHandle(FD); + if(!h) { + errno = EBADF; + return -1; + } + + int newf = VFS_Open(Path, Flags); + if( newf == -1 ) { + // errno = set by VFS_Open + return -1; + } + + _CloseNode(h->Node); + _DereferenceMount(h->Mount, "Reopen"); + memcpy(h, VFS_GetHandle(newf), sizeof(*h)); + _ReferenceNode(h->Node); + _ReferenceMount(h->Mount, "Reopen"); + + VFS_Close(newf); + + return FD; +} + /** * \fn void VFS_Close(int FD) * \brief Closes an open file handle @@ -734,11 +774,13 @@ void VFS_Close(int FD) h = VFS_GetHandle(FD); if(h == NULL) { Log_Warning("VFS", "Invalid file handle passed to VFS_Close, 0x%x", FD); + errno = EINVAL; return; } if( h->Node == NULL ) { Log_Warning("VFS", "Non-open handle passed to VFS_Close, 0x%x", FD); + errno = EINVAL; return ; } @@ -746,6 +788,7 @@ void VFS_Close(int FD) if(h->Node->Close && !MM_GetPhysAddr(h->Node->Close)) { Log_Warning("VFS", "Node %p's ->Close method is invalid (%p)", h->Node, h->Node->Close); + errno = EINTERNAL; return ; } #endif @@ -774,6 +817,8 @@ int VFS_DuplicateFD(int SrcFD, int DstFD) return -1; VFS_SetHandle(DstFD, src->Node, src->Mode); } + _ReferenceMount(src->Mount, "DuplicateFD"); + _ReferenceNode(src->Node); memcpy(VFS_GetHandle(DstFD), src, sizeof(tVFS_Handle)); return DstFD; } @@ -784,7 +829,10 @@ int VFS_DuplicateFD(int SrcFD, int DstFD) int VFS_SetFDFlags(int FD, int Mask, int Value) { tVFS_Handle *h = VFS_GetHandle(FD); - if(!FD) return -1; + if(!h) { + errno = EBADF; + return -1; + } int ret = h->Mode; Value &= Mask; @@ -828,7 +876,7 @@ int VFS_ChDir(const char *Dest) VFS_Close(fd); { - char **cwdptr = Threads_GetCWD(); + char **cwdptr = Threads_GetCWD(NULL); // Free old working directory if( *cwdptr ) free( *cwdptr ); // Set new @@ -880,7 +928,7 @@ int VFS_ChRoot(const char *New) // Update { - char **chroot_ptr = Threads_GetChroot(); + char **chroot_ptr = Threads_GetChroot(NULL); if( *chroot_ptr ) free( *chroot_ptr ); *chroot_ptr = buf; } @@ -890,6 +938,96 @@ int VFS_ChRoot(const char *New) return 1; } +/* + * Marshal a handle so that it can be transferred between processes + */ +Uint64 VFS_MarshalHandle(int FD) +{ + tVFS_Handle *h = VFS_GetHandle(FD); + if(!h || !h->Node) { + errno = EBADF; + return -1; + } + + // Allocate marshal location + int ret = -1; + Mutex_Acquire(&glVFS_MarshalledHandles); + for( int i = 0; i < MAX_MARSHALLED_HANDLES; i ++ ) + { + tVFS_MarshalledHandle* mh = &gaVFS_MarshalledHandles[i]; + if( mh->Handle.Node == NULL ) { + mh->Handle.Node = h->Node; + mh->AllocTime = now(); + ret = i; + } + if( now() - mh->AllocTime > 2000 ) { + Log_Notice("VFS", "TODO: Expire marshalled handle"); + } + } + Mutex_Release(&glVFS_MarshalledHandles); + if( ret < 0 ) { + // TODO: Need to clean up lost handles to avoid DOS + Log_Warning("VFS", "Out of marshaled handle slots"); + errno = EAGAIN; + return -1; + } + + // Populate + tVFS_MarshalledHandle* mh = &gaVFS_MarshalledHandles[ret]; + mh->Handle = *h; + _ReferenceMount(h->Mount, "MarshalHandle"); + _ReferenceNode(h->Node); + mh->Magic = rand(); + + return (Uint64)mh->Magic << 32 | ret; +} + +/* + * Un-marshal a handle into the current process + * NOTE: Does not support unmarshalling into kernel handle list + */ +int VFS_UnmarshalHandle(Uint64 Handle) +{ + Uint32 magic = Handle >> 32; + int id = Handle & 0xFFFFFFFF; + + // Range check + if( id >= MAX_MARSHALLED_HANDLES ) { + LOG("ID too high (%i > %i)", id, MAX_MARSHALLED_HANDLES); + errno = EINVAL; + return -1; + } + + + // Check validity + tVFS_MarshalledHandle *mh = &gaVFS_MarshalledHandles[id]; + if( mh->Handle.Node == NULL ) { + LOG("Target node is NULL"); + errno = EINVAL; + return -1; + } + if( mh->Magic != magic ) { + LOG("Magic mismatch (0x%08x != 0x%08x)", magic, mh->Magic); + errno = EACCES; + return -1; + } + + Mutex_Acquire(&glVFS_MarshalledHandles); + // - Create destination handle + int ret = VFS_AllocHandle(true, mh->Handle.Node, mh->Handle.Mode); + // - Clear allocation + mh->Handle.Node = NULL; + Mutex_Release(&glVFS_MarshalledHandles); + if( ret == -1 ) { + errno = ENFILE; + return -1; + } + + // No need to reference node/mount, new handle takes marshalled reference + + return ret; +} + // === EXPORTS === EXPORT(VFS_Open); EXPORT(VFS_Close);