X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Fvfs%2Fio.c;h=35c1ebf88bec10504cd8fc974da690c3e75f5e4c;hb=e47f509e07718893b837826f981085829cf16c84;hp=f5b16cc1cc39f58f18a37e3c43fc5408ca442250;hpb=015f48988e0ff398409d71dfc692005ab439490a;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/vfs/io.c b/KernelLand/Kernel/vfs/io.c index f5b16cc1..35c1ebf8 100644 --- a/KernelLand/Kernel/vfs/io.c +++ b/KernelLand/Kernel/vfs/io.c @@ -23,43 +23,40 @@ size_t VFS_Read(int FD, size_t Length, void *Buffer) tVFS_Handle *h; size_t ret; - ENTER("xFD xLength pBuffer", FD, Length, Buffer); - h = VFS_GetHandle(FD); if(!h) { - LOG("Bad Handle"); - LEAVE_RET('i', -1); + LOG("FD%i is a bad Handle", FD); + return -1; } if( !(h->Mode & VFS_OPENFLAG_READ) ) { - LOG("Bad mode"); - LEAVE_RET('i', -1); + LOG("FD%i not open for reading", FD); + return -1; } if( (h->Node->Flags & VFS_FFLAG_DIRECTORY) ) { - LOG("Reading directory"); - LEAVE_RET('i', -1); + LOG("FD%i is a directory", FD); + return -1; } if(!h->Node->Type || !h->Node->Type->Read) { - LOG("No read method"); - LEAVE_RET('i', -1); + LOG("FD%i has no read method", FD); + return -1; } if( !MM_GetPhysAddr(h->Node->Type->Read) ) { Log_Error("VFS", "Node type %p(%s) read method is junk %p", h->Node->Type, h->Node, h->Node->Type->TypeName, h->Node->Type->Read); - LEAVE_RET('i', -1); + return -1; } - LOG("Position=%llx", h->Position); Uint flags = 0; flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0; ret = h->Node->Type->Read(h->Node, h->Position, Length, Buffer, flags); - if(ret == (size_t)-1) LEAVE_RET('i', -1); + if(ret != Length) LOG("%i/%i read", ret, Length); + if(ret == (size_t)-1) return -1; h->Position += ret; - LEAVE('x', ret); return ret; } @@ -87,12 +84,12 @@ size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer) Log_Error("VFS", "Node type %p(%s) read method is junk %p", h->Node->Type, h->Node->Type->TypeName, h->Node->Type->Read); - LEAVE_RET('i', -1); } Uint flags = 0; flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0; ret = h->Node->Type->Read(h->Node, Offset, Length, Buffer, flags); + if(ret != Length) LOG("%i/%i read", ret, Length); if(ret == (size_t)-1) return -1; return ret; } @@ -103,39 +100,18 @@ size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer) */ size_t VFS_Write(int FD, size_t Length, const void *Buffer) { - tVFS_Handle *h; - size_t ret; - - h = VFS_GetHandle(FD); - if(!h) return -1; - - if( !(h->Mode & VFS_OPENFLAG_WRITE) ) { - LOG("FD%i not opened for writing", FD); - return -1; - } - if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) { - LOG("FD%i is a director", FD); - return -1; - } - - if( !h->Node->Type || !h->Node->Type->Write ) { - LOG("FD%i has no write method", FD); - return 0; - } - - if( !MM_GetPhysAddr(h->Node->Type->Write) ) { - Log_Error("VFS", "Node type %p(%s) write method is junk %p", - h->Node->Type, h->Node->Type->TypeName, - h->Node->Type->Write); + tVFS_Handle *h = VFS_GetHandle(FD); + if(!h) { + LOG("FD%i is not open", FD); + errno = EBADF; return -1; } - Uint flags = 0; - flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0; - ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer, flags); + size_t ret = VFS_WriteAt(FD, h->Position, Length, Buffer); if(ret == (size_t)-1) return -1; - h->Position += ret; + if( !(h->Node->Type->Flags & VFS_NODETYPEFLAG_STREAM) ) + h->Position += ret; return ret; } @@ -145,27 +121,79 @@ size_t VFS_Write(int FD, size_t Length, const void *Buffer) */ size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer) { - tVFS_Handle *h; - size_t ret; - - h = VFS_GetHandle(FD); + LOG("FD=%i,Offset=%lli,Length=%i,Buffer=%p", + FD, Offset, Length, Buffer); + tVFS_Handle *h = VFS_GetHandle(FD); if(!h) return -1; - if( !(h->Mode & VFS_OPENFLAG_WRITE) ) return -1; - if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) return -1; - - if(!h->Node->Type || !h->Node->Type->Write) return 0; + if( !(h->Mode & VFS_OPENFLAG_WRITE) ) { + LOG("FD%i not opened for writing", FD); + errno = EBADF; + return -1; + } + if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) { + LOG("FD%i is a directory", FD); + errno = EISDIR; + return -1; + } - if( !MM_GetPhysAddr(h->Node->Type->Write) ) { + const tVFS_NodeType* nodetype = h->Node->Type; + if(!nodetype || !nodetype->Write) { + LOG("FD%i has no write method", FD); + errno = EINTERNAL; + return 0; + } + + if( !MM_GetPhysAddr(nodetype->Write) ) { Log_Error("VFS", "Node type %p(%s) write method is junk %p", - h->Node->Type, h->Node->Type->TypeName, - h->Node->Type->Write); + nodetype, nodetype->TypeName, nodetype->Write); + errno = EINTERNAL; return -1; } + + // Bounds checks + if( h->Node->Size != (Uint64)-1 && Offset > h->Node->Size ) { + Log_Notice("VFS", "Write starting past EOF of FD%x (%lli > %lli)", + FD, Offset, h->Node->Size); + //errno = ESPIPE; + return 0; + } + if( Offset + Length > h->Node->Size ) + { + // Going OOB + if( !nodetype->Truncate ) + { + LOG("No .Truncate method, emiting write past EOF"); + } + else if( nodetype->Flags & VFS_NODETYPEFLAG_NOAUTOEXPAND ) + { + LOG("NOAUTOEXPAND set, truncating length from %i to %i", + Length, h->Node->Size - Offset); + Length = h->Node->Size - Offset; + } + else if( nodetype->Truncate(h->Node, Offset + Length) != Offset + Length ) + { + // oh... fail? Truncate to current size + LOG(".Truncate failed, truncating length from %i to %i", + Length, h->Node->Size - Offset); + Length = h->Node->Size - Offset; + } + else + { + // Expansion, node size should now fit + LOG("Expanded file"); + } + } + + // Create flag set Uint flags = 0; flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0; - ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer, flags); + + // Dispatch the read! + size_t ret = nodetype->Write(h->Node, Offset, Length, Buffer, flags); if(ret == (size_t)-1) return -1; + if(ret != Length) LOG("%i/%i written", ret, Length); + return ret; } @@ -192,11 +220,14 @@ Uint64 VFS_Tell(int FD) */ int VFS_Seek(int FD, Sint64 Offset, int Whence) { - tVFS_Handle *h; - - h = VFS_GetHandle(FD); + tVFS_Handle *h = VFS_GetHandle(FD); if(!h) return -1; + if( (h->Node->Type->Flags & VFS_NODETYPEFLAG_STREAM) ) { + LOG("Seeking in stream"); + return -1; + } + // Set relative to current position if(Whence == 0) { LOG("(FD%x)->Position += %lli", FD, Offset); @@ -219,18 +250,45 @@ int VFS_Seek(int FD, Sint64 Offset, int Whence) return 0; } +/* + * Truncate/Expand a file's allocation + */ +off_t VFS_Truncate(int FD, off_t Size) +{ + tVFS_Handle *h = VFS_GetHandle(FD); + if(!h) { + errno = EBADF; + return -1; + } + + if( !h->Node->Type->Truncate) + { + Log_Notice("VFS", "Nodetype '%s' doesn't have a Truncate method", h->Node->Type->TypeName); + errno = ENOTIMPL; + return -1; + } + + return h->Node->Type->Truncate(h->Node, Size); +} + /** * \fn int VFS_IOCtl(int FD, int ID, void *Buffer) * \brief Call an IO Control on a file */ int VFS_IOCtl(int FD, int ID, void *Buffer) { - tVFS_Handle *h; - - h = VFS_GetHandle(FD); - if(!h) return -1; + tVFS_Handle *h = VFS_GetHandle(FD); + if(!h) { + LOG("FD%i is invalid", FD); + errno = EINVAL; + return -1; + } - if(!h->Node->Type || !h->Node->Type->IOCtl) return -1; + if(!h->Node->Type || !h->Node->Type->IOCtl) { + LOG("FD%i does not have an IOCtl method"); + errno = EINVAL; + return -1; + } return h->Node->Type->IOCtl(h->Node, ID, Buffer); }