Usermode/libaxwin4 - Handle demarshal failure
[tpg/acess2.git] / KernelLand / Kernel / vfs / io.c
index e7a2a06..35c1ebf 100644 (file)
@@ -1,37 +1,62 @@
 /*
- * AcessMicro VFS
- * - File IO Passthru's
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * vfs/io.c
+ * - VFS IO Handling (Read/Write)
+ *
+ * TODO: VFS-level caching to support non-blocking IO?
  */
 #define DEBUG  0
 #include <acess.h>
-#include "vfs.h"
-#include "vfs_int.h"
+#include <vfs.h>
+#include <vfs_ext.h>
+#include <vfs_int.h>
 
 // === CODE ===
 /**
  * \fn Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
  * \brief Read data from a node (file)
  */
-Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
+size_t VFS_Read(int FD, size_t Length, void *Buffer)
 {
        tVFS_Handle     *h;
-       Uint64  ret;
-       
-       ENTER("iFD XLength pBuffer", FD, Length, Buffer);
+       size_t  ret;
        
        h = VFS_GetHandle(FD);
-       if(!h)  LEAVE_RET('i', -1);
+       if(!h) {
+               LOG("FD%i is a bad Handle", FD);
+               return -1;
+       }
        
-       if( !(h->Mode & VFS_OPENFLAG_READ) || h->Node->Flags & VFS_FFLAG_DIRECTORY )
-               LEAVE_RET('i', -1);
+       if( !(h->Mode & VFS_OPENFLAG_READ) ) {
+               LOG("FD%i not open for reading", FD);
+               return -1;
+       }
+       if( (h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
+               LOG("FD%i is a directory", FD);
+               return -1;
+       }
 
-       if(!h->Node->Type || !h->Node->Type->Read)      LEAVE_RET('i', 0);
+       if(!h->Node->Type || !h->Node->Type->Read) {
+               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);
+               return -1;
+       }
        
-       ret = h->Node->Type->Read(h->Node, h->Position, Length, Buffer);
-       if(ret == -1)   LEAVE_RET('i', -1);
+       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 != Length)       LOG("%i/%i read", ret, Length);
+       if(ret == (size_t)-1)   return -1;
        
        h->Position += ret;
-       LEAVE('X', ret);
        return ret;
 }
 
@@ -39,10 +64,10 @@ Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
  * \fn Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
  * \brief Read data from a given offset (atomic)
  */
-Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
+size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer)
 {
        tVFS_Handle     *h;
-       Uint64  ret;
+       size_t  ret;
        
        h = VFS_GetHandle(FD);
        if(!h)  return -1;
@@ -54,8 +79,18 @@ Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
                Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
                return 0;
        }
-       ret = h->Node->Type->Read(h->Node, Offset, Length, Buffer);
-       if(ret == -1)   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->Type->TypeName,
+                       h->Node->Type->Read);
+       }
+       
+       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;
 }
 
@@ -63,23 +98,20 @@ Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
  * \fn Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
  * \brief Read data from a node (file)
  */
-Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
+size_t VFS_Write(int FD, size_t Length, const void *Buffer)
 {
-       tVFS_Handle     *h;
-       Uint64  ret;
-       
-       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;
+       tVFS_Handle     *h = VFS_GetHandle(FD);
+       if(!h) {
+               LOG("FD%i is not open", FD);
+               errno = EBADF;
+               return -1;
+       }
        
-       ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer);
-       if(ret == -1)   return -1;
+       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;
 }
 
@@ -87,21 +119,81 @@ Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
  * \fn Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
  * \brief Write data to a file at a given offset
  */
-Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
+size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer)
 {
-       tVFS_Handle     *h;
-       Uint64  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->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(!h->Node->Type || !h->Node->Type->Write)     return 0;
-       ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer);
+       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",
+                       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;
+       
+       // 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);
 
-       if(ret == -1)   return -1;
        return ret;
 }
 
@@ -128,45 +220,75 @@ 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;
        
-       //Log_Debug("VFS", "VFS_Seek: (fd=0x%x, Offset=0x%llx, Whence=%i)",
-       //      FD, Offset, Whence);
+       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);
                h->Position += Offset;
                return 0;
        }
        
        // Set relative to end of file
        if(Whence < 0) {
-               if( h->Node->Size == -1 )       return -1;
+               if( h->Node->Size == (Uint64)-1 )       return -1;
 
+               LOG("(FD%x)->Position = %llx - %llx", FD, h->Node->Size, Offset);
                h->Position = h->Node->Size - Offset;
                return 0;
        }
        
        // Set relative to start of file
+       LOG("(FD%x)->Position = %llx", FD, Offset);
        h->Position = Offset;
        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);
 }
 

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