Merge branch 'master' of ted.mutabah.net:acess2
authorJohn Hodge <[email protected]>
Sat, 14 Jul 2012 09:23:32 +0000 (17:23 +0800)
committerJohn Hodge <[email protected]>
Sat, 14 Jul 2012 09:23:32 +0000 (17:23 +0800)
Conflicts:
KernelLand/Kernel/Makefile

67 files changed:
.gitignore
AcessNative/acesskernel_src/nativefs.c
BuildConf/armv7/Makefile.cfg
BuildConf/armv7/realview_pb.mk
BuildConf/armv7/tegra2.mk
KernelLand/Kernel/Makefile
KernelLand/Kernel/drv/proc.c
KernelLand/Kernel/drvutil.c [deleted file]
KernelLand/Kernel/drvutil_disk.c [new file with mode: 0644]
KernelLand/Kernel/drvutil_video.c [new file with mode: 0644]
KernelLand/Kernel/include/acess.h
KernelLand/Kernel/include/ctype.h [new file with mode: 0644]
KernelLand/Kernel/include/errno.h
KernelLand/Kernel/include/modules.h
KernelLand/Kernel/include/rwlock.h [new file with mode: 0644]
KernelLand/Kernel/include/threads_int.h
KernelLand/Kernel/include/vfs.h
KernelLand/Kernel/include/vfs_ext.h
KernelLand/Kernel/include/vfs_int.h
KernelLand/Kernel/lib.c
KernelLand/Kernel/libc.c [new file with mode: 0644]
KernelLand/Kernel/rwlock.c [new file with mode: 0644]
KernelLand/Kernel/vfs/dir.c
KernelLand/Kernel/vfs/fs/devfs.c
KernelLand/Kernel/vfs/fs/root.c
KernelLand/Kernel/vfs/handle.c
KernelLand/Kernel/vfs/mount.c
KernelLand/Kernel/vfs/nodecache.c
KernelLand/Kernel/vfs/open.c
KernelLand/Modules/Filesystems/Ext2/ext2.c
KernelLand/Modules/Filesystems/FAT/Makefile
KernelLand/Modules/Filesystems/FAT/common.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/FAT/dir.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/FAT/fat.c
KernelLand/Modules/Filesystems/FAT/fatio.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/FAT/fs_fat.h
KernelLand/Modules/Filesystems/FAT/nodecache.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/InitRD/files.lst
KernelLand/Modules/IPStack/ipv6.c
KernelLand/Modules/IPStack/link.c
KernelLand/Modules/Input/Keyboard/main.c
KernelLand/Modules/Input/Mouse/main.c
KernelLand/Modules/Storage/LVM/include/lvm.h
KernelLand/Modules/Storage/LVM/main.c
KernelLand/Modules/Storage/LVM/volumes.c
KernelLand/Modules/USB/Core/usb_lowlevel.c
KernelLand/Modules/USB/MSC/main.c
KernelLand/Modules/x86/VGAText/vga.c
RunQemuArm
Tools/DiskTool/src/Makefile [new file with mode: 0644]
Tools/DiskTool/src/actions.c [new file with mode: 0644]
Tools/DiskTool/src/helpers.c [new file with mode: 0644]
Tools/DiskTool/src/include/acess.h [new file with mode: 0644]
Tools/DiskTool/src/include/acess_logging.h [new file with mode: 0644]
Tools/DiskTool/src/include/arch.h [new file with mode: 0644]
Tools/DiskTool/src/include/disktool_common.h [new file with mode: 0644]
Tools/DiskTool/src/include/modules.h [new file with mode: 0644]
Tools/DiskTool/src/include/rwlock.h [new file with mode: 0644]
Tools/DiskTool/src/logging.c [new file with mode: 0644]
Tools/DiskTool/src/main.c [new file with mode: 0644]
Tools/DiskTool/src/nativefs.c [new symlink]
Tools/DiskTool/src/script.c [new file with mode: 0644]
Tools/DiskTool/src/threads.c [new file with mode: 0644]
Tools/DiskTool/src/time.c [new file with mode: 0644]
Tools/DiskTool/src/vfs_handles.c [new file with mode: 0644]
Usermode/Applications/axwin3_src/WM/ipc.c
Usermode/Applications/axwin3_src/WM/video.c

index c2b6411..fe240ee 100644 (file)
@@ -42,3 +42,7 @@ obj-*/
 Makefile.user.cfg
 QemuLog.txt
 Screenshots/
+
+Tools/*/src/obj/
+Tools/*/src/Makefile.BuildNum
+Tools/DiskTool/DiskTool
index 4f1b377..e51f286 100644 (file)
@@ -5,7 +5,7 @@
  * nativefs.c\r
  * - Host filesystem access\r
  */\r
-#define DEBUG  1\r
+#define DEBUG  0\r
 #define off_t  _acess_off_t\r
 #include <acess.h>     // Acess\r
 #include <vfs.h>       // Acess\r
@@ -32,15 +32,20 @@ tVFS_Node   *NativeFS_Mount(const char *Device, const char **Arguments);
 void   NativeFS_Unmount(tVFS_Node *Node);\r
 tVFS_Node      *NativeFS_FindDir(tVFS_Node *Node, const char *Name);\r
 char   *NativeFS_ReadDir(tVFS_Node *Node, int Position);\r
-Uint64 NativeFS_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+size_t NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer);\r
+size_t NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer);\r
+void   NativeFS_Close(tVFS_Node *Node);\r
 \r
 // === GLOBALS ===\r
 tVFS_NodeType  gNativeFS_FileNodeType = {\r
-       .Read = NativeFS_Read\r
+       .Read = NativeFS_Read,\r
+       .Write = NativeFS_Write,\r
+       .Close = NativeFS_Close\r
 };\r
 tVFS_NodeType  gNativeFS_DirNodeType = {\r
        .FindDir = NativeFS_FindDir,\r
        .ReadDir = NativeFS_ReadDir,\r
+       .Close = NativeFS_Close\r
 };\r
 tVFS_Driver    gNativeFS_Driver = {\r
        "nativefs", 0,\r
@@ -63,7 +68,7 @@ tVFS_Node *NativeFS_Mount(const char *Device, const char **Arguments)
        \r
        dp = opendir(Device);\r
        if(!dp) {\r
-               Log_Warning("NativeFS", "ERRO: Unable to open device root '%s'", Device);\r
+               Log_Warning("NativeFS", "ERROR: Unable to open device root '%s'", Device);\r
                return NULL;\r
        }\r
        \r
@@ -78,11 +83,11 @@ tVFS_Node *NativeFS_Mount(const char *Device, const char **Arguments)
        ret->Data = strdup(Device);\r
        ret->ImplInt = strlen(ret->Data);\r
        ret->ImplPtr = info;\r
-       ret->Inode = (Uint64)dp;\r
+       ret->Inode = (Uint64)(tVAddr)dp;\r
        ret->Flags = VFS_FFLAG_DIRECTORY;\r
 \r
        ret->Type = &gNativeFS_DirNodeType;     \r
-       \r
+\r
        return ret;\r
 }\r
 \r
@@ -90,7 +95,7 @@ void NativeFS_Unmount(tVFS_Node *Node)
 {\r
        tNativeFS       *info = Node->ImplPtr;\r
        Inode_ClearCache( info->InodeHandle );\r
-       closedir( (void *)Node->Inode );\r
+       closedir( (void *)(tVAddr)Node->Inode );\r
        free(Node->Data);\r
        free(Node);\r
        free(info);\r
@@ -99,12 +104,18 @@ void NativeFS_Unmount(tVFS_Node *Node)
 void NativeFS_Close(tVFS_Node *Node)\r
 {\r
        tNativeFS       *info = Node->ImplPtr;\r
-       Inode_UncacheNode( info->InodeHandle, Node->Inode );\r
+       DIR     *dp = (Node->Flags & VFS_FFLAG_DIRECTORY) ? (DIR*)(tVAddr)Node->Inode : 0;\r
+       FILE    *fp = (Node->Flags & VFS_FFLAG_DIRECTORY) ? 0 : (FILE*)(tVAddr)Node->Inode;\r
+       \r
+       if( Inode_UncacheNode( info->InodeHandle, Node->Inode ) == 1 ) {\r
+               if(dp)  closedir(dp);\r
+               if(fp)  fclose(fp);\r
+       }\r
 }\r
 \r
 tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)\r
 {\r
-       char    *path = malloc(Node->ImplInt + 1 + strlen(Name) + 1);\r
+       char    *path;\r
        tNativeFS       *info = Node->ImplPtr;\r
        tVFS_Node       baseRet;\r
        struct stat statbuf;\r
@@ -112,6 +123,7 @@ tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)
        ENTER("pNode sName", Node, Name);\r
        \r
        // Create path\r
+       path = malloc(Node->ImplInt + 1 + strlen(Name) + 1);\r
        strcpy(path, Node->Data);\r
        path[Node->ImplInt] = '/';\r
        strcpy(path + Node->ImplInt + 1, Name);\r
@@ -132,7 +144,7 @@ tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)
        if( S_ISDIR(statbuf.st_mode) )\r
        {\r
                LOG("Directory");\r
-               baseRet.Inode = (Uint64) opendir(path);\r
+               baseRet.Inode = (Uint64)(tVAddr) opendir(path);\r
                baseRet.Type = &gNativeFS_DirNodeType;\r
                baseRet.Flags |= VFS_FFLAG_DIRECTORY;\r
                baseRet.Size = -1;\r
@@ -140,7 +152,7 @@ tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)
        else\r
        {\r
                LOG("File");\r
-               baseRet.Inode = (Uint64) fopen(path, "r+");\r
+               baseRet.Inode = (Uint64)(tVAddr) fopen(path, "r+");\r
                baseRet.Type = &gNativeFS_FileNodeType;\r
                \r
                fseek( (FILE*)(tVAddr)baseRet.Inode, 0, SEEK_END );\r
@@ -184,14 +196,30 @@ char *NativeFS_ReadDir(tVFS_Node *Node, int Position)
        return ret;\r
 }\r
 \r
-Uint64 NativeFS_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+size_t NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer)\r
 {\r
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);\r
-       if( fseek( (void *)Node->Inode, Offset, SEEK_SET ) != 0 )\r
+       ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
+       if( fseek( (FILE *)(tVAddr)Node->Inode, Offset, SEEK_SET ) != 0 )\r
        {\r
                LEAVE('i', 0);\r
                return 0;\r
        }\r
        LEAVE('-');\r
-       return fread( Buffer, 1, Length, (void *)Node->Inode );\r
+       return fread( Buffer, 1, Length, (FILE *)(tVAddr)Node->Inode );\r
+}\r
+\r
+size_t NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer)\r
+{\r
+       FILE    *fp = (FILE *)(tVAddr)Node->Inode;\r
+       ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
+       if( fseek( fp, Offset, SEEK_SET ) != 0 )\r
+       {\r
+               LEAVE('i', 0);\r
+               return 0;\r
+       }\r
+       size_t ret = fwrite( Buffer, 1, Length, fp );\r
+       fflush( fp );\r
+       LEAVE('i', ret);\r
+       return ret;\r
+\r
 }\r
index 9be93a7..4114eb0 100644 (file)
@@ -1,5 +1,6 @@
 
-CC = arm-elf-gcc
+ARM_CPUNAME = gerneric-armv7
+CC = arm-elf-gcc -mcpu=$(ARM_CPUNAME)
 AS = arm-elf-gcc -c
 LD = arm-elf-ld
 OBJDUMP = arm-elf-objdump
index 4b284ee..abb08e2 100644 (file)
@@ -1,5 +1,6 @@
 
 include $(ACESSDIR)/BuildConf/armv7/default.mk
 
+ARM_CPUNAME = cortex-a8
 MODULES += Input/PS2KbMouse
 MODULES += Display/PL110
index 4abc5c8..1bac800 100644 (file)
@@ -1,4 +1,5 @@
 
 include $(ACESSDIR)/BuildConf/armv7/default.mk
 
+ARM_CPUNAME = cortex-a9
 MODULES += Display/Tegra2Vid
index a5a5c03..706ae3f 100644 (file)
@@ -51,9 +51,10 @@ BUILDINFO_OBJ := $(OBJDIR)buildinfo.o$(OBJSUFFIX)
 BUILDINFO_SRC := $(OBJDIR)buildinfo.c$(OBJSUFFIX)
 
 OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
-OBJ += heap.o drvutil.o logging.o debug.o lib.o adt.o time.o
+OBJ += heap.o logging.o debug.o lib.o libc.o adt.o time.o
+OBJ += drvutil_video.o drvutil_disk.o
 OBJ += messages.o modules.o syscalls.o system.o
-OBJ += threads.o mutex.o semaphore.o workqueue.o events.o
+OBJ += threads.o mutex.o semaphore.o workqueue.o events.o rwlock.o
 OBJ += drv/zero-one.o drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
 OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_vt100.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o
 OBJ += binary.o bin/elf.o bin/pe.o
index 4f52f5c..954cab6 100644 (file)
@@ -111,7 +111,7 @@ int SysFS_Install(char **Options)
 {
        {
                const char      *fmt = "Acess2 "EXPAND_STR(KERNEL_VERSION)" "EXPAND_STR(ARCHDIR)" build %i, hash %s";
-               gSysFS_Version_Kernel.Node.Size = sprintf(NULL, fmt, BUILD_NUM, gsGitHash);
+               gSysFS_Version_Kernel.Node.Size = snprintf(NULL, 0, fmt, BUILD_NUM, gsGitHash);
                gSysFS_Version_Kernel.Node.ImplPtr = malloc( gSysFS_Version_Kernel.Node.Size + 1 );
                sprintf(gSysFS_Version_Kernel.Node.ImplPtr, fmt, BUILD_NUM, gsGitHash);
        }
diff --git a/KernelLand/Kernel/drvutil.c b/KernelLand/Kernel/drvutil.c
deleted file mode 100644 (file)
index 750ea7c..0000000
+++ /dev/null
@@ -1,743 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge
- *
- * drvutil.c
- * - Common Driver/Filesystem Helper Functions
- */
-#define DEBUG  0
-#include <acess.h>
-#include <api_drv_disk.h>
-#include <api_drv_video.h>
-
-// === TYPES ===
-
-// === PROTOTYPES ===
-//int  DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
-//size_t       DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
-//void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
-//void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
-void   DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
-//void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
-void   DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
-void   DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
-
-// === GLOBALS ===
-tDrvUtil_Video_2DHandlers      gDrvUtil_Stub_2DFunctions = {
-       NULL,
-       DrvUtil_Video_2D_Fill,
-       DrvUtil_Video_2D_Blit
-};
-tVideo_IOCtl_Bitmap    gDrvUtil_TextModeCursor = {
-       8, 16,
-       0, 0,
-       {
-               0, 0, 0         , 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0, 0, 0         , 0, 0, 0, 0, 0,
-               0, 0, 0         , 0, 0, 0, 0, 0
-       }
-};
-
-// === CODE ===
-// --- Video Driver Helpers ---
-int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
-       tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
-{
-       const Uint8     *stream = Buffer;
-        int    rem = Length;
-        int    op;
-
-       Uint16  tmp[6];
-
-       while( rem )
-       {
-               rem --;
-               op = *stream;
-               stream ++;
-               
-               if(op > NUM_VIDEO_2DOPS) {
-                       Log_Warning("DrvUtil",
-                               "DrvUtil_Video_2DStream: Unknown operation %i",
-                               op);
-                       return Length-rem;
-               }
-               
-               if(op*sizeof(void*) > SizeofHandlers) {
-                       Log_Warning("DrvUtil",
-                               "DrvUtil_Video_2DStream: Driver does not support op %i",
-                               op);
-                       return Length-rem;
-               }
-               
-               switch(op)
-               {
-               case VIDEO_2DOP_NOP:    break;
-               
-               case VIDEO_2DOP_FILL:
-                       if(rem < 12)    return Length-rem;
-                       memcpy(tmp, stream, 6*2);
-                       
-                       if(!Handlers->Fill) {
-                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
-                                       " does not support VIDEO_2DOP_FILL");
-                               return Length-rem;
-                       }
-                       
-                       Handlers->Fill(
-                               Ent, 
-                               tmp[0], tmp[1], tmp[2], tmp[3],
-                               tmp[4] | ((Uint32)tmp[5] << 16)
-                               );
-                       
-                       rem -= 12;
-                       stream += 12;
-                       break;
-               
-               case VIDEO_2DOP_BLIT:
-                       if(rem < 12)    return Length-rem;
-                       memcpy(tmp, stream, 6*2);
-                       
-                       if(!Handlers->Blit) {
-                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
-                                       " does not support VIDEO_2DOP_BLIT");
-                               return Length-rem;
-                       }
-                       
-                       Handlers->Blit(
-                               Ent,
-                               tmp[0], tmp[1], tmp[2], tmp[3],
-                               tmp[4], tmp[5]
-                               );
-                       
-                       rem -= 12;
-                       stream += 12;
-                       break;
-               
-               }
-       }
-       return 0;
-}
-
-int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
-{
-       Uint8   *dest;
-       const Uint32    *src = Buffer;
-        int    csr_x, csr_y;
-        int    x, y;
-        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
-       ENTER("pFBInfo xOffset xLength pBuffer",
-               FBInfo, Offset, Length, Buffer);
-
-       csr_x = FBInfo->CursorX;
-       csr_y = FBInfo->CursorY;
-
-       DrvUtil_Video_RemoveCursor(FBInfo);
-
-       switch( FBInfo->BufferFormat )
-       {
-       case VIDEO_BUFFMT_TEXT:
-               {
-               const tVT_Char  *chars = Buffer;
-                int    widthInChars = FBInfo->Width/giVT_CharWidth;
-                int    heightInChars = FBInfo->Height/giVT_CharHeight;
-                int    i;
-       
-               LOG("bytes_per_px = %i", bytes_per_px);
-               LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
-       
-               Length /= sizeof(tVT_Char);     Offset /= sizeof(tVT_Char);
-               
-               x = Offset % widthInChars;      y = Offset / widthInChars;
-               LOG("x = %i, y = %i", x, y);    
-       
-               // Sanity Check
-               if(Offset > heightInChars * widthInChars)       LEAVE_RET('i', 0);
-               if(y >= heightInChars)  LEAVE_RET('i', 0);
-               
-               if( Offset + Length > heightInChars*widthInChars )
-               {
-                       Length = heightInChars*widthInChars - Offset;
-               }
-               
-               dest = FBInfo->Framebuffer;
-               LOG("dest = %p", dest);
-               dest += y * giVT_CharHeight * FBInfo->Pitch;
-               LOG("dest = %p", dest);
-               
-               for( i = 0; i < Length; i++ )
-               {
-                       if( y >= heightInChars )
-                       {
-                               Log_Notice("DrvUtil", "Stopped at %i", i);
-                               break;
-                       }
-
-                       VT_Font_Render(
-                               chars->Ch,
-                               dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
-                               VT_Colour12toN(chars->BGCol, FBInfo->Depth),
-                               VT_Colour12toN(chars->FGCol, FBInfo->Depth)
-                               );
-                       
-                       chars ++;
-                       x ++;
-                       if( x >= widthInChars )
-                       {
-                               x = 0;
-                               y ++;
-                               dest += FBInfo->Pitch*giVT_CharHeight;
-                               LOG("dest = %p", dest);
-                       }
-               }
-               Length = i * sizeof(tVT_Char);
-               }
-               break;
-       
-       case VIDEO_BUFFMT_FRAMEBUFFER:
-               if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
-               {
-                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
-                       return 0;
-               }
-               
-               switch(FBInfo->Depth)
-               {
-               case 15:
-               case 16:
-                       Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
-                       break;
-               case 24:
-                       x = Offset % FBInfo->Width;
-                       y = Offset / FBInfo->Width;
-                       dest = (Uint8*)FBInfo->Framebuffer + y*FBInfo->Pitch;
-                       for( ; Length >= 4; Length -= 4 )
-                       {
-                               dest[x*3+0] = *src & 0xFF;
-                               dest[x*3+1] = (*src >> 8) & 0xFF;
-                               dest[x*3+2] = (*src >> 16) & 0xFF;
-                               x ++;
-                               if(x == FBInfo->Width) {
-                                       dest += FBInfo->Pitch;
-                                       x = 0;
-                               }
-                       }
-                       break;
-               case 32:
-                       // Copy to Frambuffer
-                       if( FBInfo->Pitch != FBInfo->Width*4 )
-                       {
-                               Uint32  *px;
-                               // Pitch isn't 4*Width
-                               x = Offset % FBInfo->Width;
-                               y = Offset / FBInfo->Height;
-                               
-                               px = (Uint32*)FBInfo->Framebuffer + y*FBInfo->Pitch/4;
-
-                               for( ; Length >= 4; Length -= 4, x )
-                               {
-                                       px[x++] = *src ++;
-                                       if( x == FBInfo->Width ) {
-                                               x = 0;
-                                               px += FBInfo->Pitch;
-                                       }
-                               }
-                       }
-                       else
-                       {
-                               dest = (Uint8 *)FBInfo->Framebuffer + Offset;
-                               memcpy(dest, Buffer, Length);
-                       }
-                       break;
-               default:
-                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depthn %i", FBInfo->Depth);
-                       break;
-               }
-               break;
-       
-       case VIDEO_BUFFMT_2DSTREAM:
-               Length = DrvUtil_Video_2DStream(
-                       FBInfo, Buffer, Length,
-                       &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
-                       );
-               break;
-       
-       default:
-               LEAVE('i', -1);
-               return -1;
-       }
-
-       DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
-
-       LEAVE('x', Length);
-       return Length;
-}
-
-int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
-{
-        int    csrX = Buf->CursorX, csrY = Buf->CursorY;
-       size_t  size;
-
-       ENTER("pBuf pBitmap", Buf, Bitmap);
-
-       // Clear old bitmap
-       if( Buf->CursorBitmap )
-       {
-               LOG("Clearing old cursor");
-               DrvUtil_Video_RemoveCursor(Buf);
-               if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
-               {
-                       free( Buf->CursorSaveBuf );
-                       Buf->CursorSaveBuf = NULL;
-               }
-               if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
-                       free(Buf->CursorBitmap);
-               Buf->CursorBitmap = NULL;
-       }
-       
-       // If the new bitmap is null, disable drawing
-       if( !Bitmap )
-       {
-               Buf->CursorX = -1;
-               Buf->CursorY = -1;
-               LEAVE('i', 0);
-               return 0;
-       }
-
-       // Sanity check the bitmap
-       LOG("Sanity checking plox");
-       if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
-       {
-               Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
-               errno = -EINVAL;
-               LEAVE('i', -1);
-               return -1;
-       }
-
-       // Don't take a copy of the DrvUtil provided cursor
-       if( Bitmap == &gDrvUtil_TextModeCursor )
-       {
-               LOG("No copy (provided cursor)");
-               Buf->CursorBitmap = Bitmap;
-       }
-       else
-       {
-               LOG("Make copy");
-               size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
-               
-               // Take a copy
-               Buf->CursorBitmap = malloc( size );
-               memcpy(Buf->CursorBitmap, Bitmap, size);
-       }
-       
-       // Restore cursor position
-       LOG("Drawing");
-       DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
-       LEAVE('i', 0);
-       return 0;
-}
-
-void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
-{
-        int    render_ox=0, render_oy=0, render_w, render_h;
-
-       ENTER("pBuf iX iY", Buf, X, Y);
-       DrvUtil_Video_RemoveCursor(Buf);
-
-       // X < 0 disables the cursor
-       if( X < 0 ) {
-               Buf->CursorX = -1;
-               LEAVE('-');
-               return ;
-       }
-
-       // Sanity checking
-       if( X < 0 || Y < 0 || X >= Buf->Width || Y >= Buf->Height ) {
-               LEAVE('-');
-               return ;
-       }
-
-       // Ensure the cursor is enabled
-       if( !Buf->CursorBitmap ) {
-               LEAVE('-');
-               return ;
-       }
-       
-       // Save cursor position (for changing the bitmap)
-       Buf->CursorX = X;       Buf->CursorY = Y;
-       // Apply cursor's center offset
-       X -= Buf->CursorBitmap->XOfs;
-       Y -= Buf->CursorBitmap->YOfs;
-       
-       // Get the width of the cursor on screen (clipping to right/bottom edges)
-       render_w = X > Buf->Width  - Buf->CursorBitmap->W ? Buf->Width  - X : Buf->CursorBitmap->W;
-       render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
-
-       // Clipp to left/top edges
-       if(X < 0) {     render_ox = -X; X = 0;  }
-       if(Y < 0) {     render_oy = -Y; Y = 0;  }
-
-       // Save values
-       Buf->CursorRenderW = render_w;  Buf->CursorRenderH = render_h;
-       Buf->CursorDestX   = X;         Buf->CursorDestY = Y;
-       Buf->CursorReadX   = render_ox; Buf->CursorReadY = render_oy;
-
-       LOG("%ix%i at %i,%i offset %i,%i",
-               render_w, render_h, X, Y, render_ox, render_oy);
-
-       // Call render routine
-       DrvUtil_Video_RenderCursor(Buf);
-       LEAVE('-');
-}
-
-void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
-{
-        int    src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
-        int    render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
-        int    dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
-        int    bytes_per_px = (Buf->Depth + 7) / 8;
-        int    save_pitch = Buf->CursorBitmap->W * bytes_per_px;
-       void    *dest;
-       Uint32  *src;
-        int    x, y;
-
-       dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
-       src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
-       
-       LOG("dest = %p, src = %p", dest, src);
-
-       // Allocate save buffer if not already
-       if( !Buf->CursorSaveBuf )
-               Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
-
-       LOG("Saving back");
-       // Save behind the cursor
-       for( y = 0; y < render_h; y ++ )
-               memcpy(
-                       (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
-                       (Uint8*)dest + y*Buf->Pitch,
-                       render_w*bytes_per_px
-                       );
-
-       // Draw the cursor
-       switch(Buf->Depth)
-       {
-       case 15:
-       case 16:
-               Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
-               break;
-       case 24:
-               LOG("24-bit render");
-               for( y = 0; y < render_h; y ++ )
-               {
-                       Uint8   *px;
-                       px = dest;
-                       for(x = 0; x < render_w; x ++, px += 3)
-                       {
-                               Uint32  value = src[x];
-                               // TODO: Should I implement alpha blending?
-                               if(value & 0xFF000000)
-                               {
-                                       px[0] = value & 0xFF;
-                                       px[1] = (value >> 8) & 0xFF;
-                                       px[2] = (value >> 16) & 0xFF;
-                               }
-                               else
-                                       ;
-                       }
-                       src += Buf->CursorBitmap->W;
-                       dest = (Uint8*)dest + Buf->Pitch;
-               }
-               break;
-       case 32:
-               LOG("32-bit render");
-               for( y = 0; y < render_h; y ++ )
-               {
-                       Uint32  *px;
-                       px = dest;
-                       for(x = 0; x < render_w; x ++, px ++)
-                       {
-                               Uint32  value = src[x];
-                               // TODO: Should I implement alpha blending?
-                               if(value & 0xFF000000)
-                                       *px = value;
-                               else
-                                       ;       // NOP, completely transparent
-                       }
-                       LOG("row %i/%i (%p-%P) done", y+1, render_h, dest, MM_GetPhysAddr(dest));
-                       src += Buf->CursorBitmap->W;
-                       dest = (Uint8*)dest + Buf->Pitch;
-               }
-               break;
-       default:
-               Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
-               Buf->CursorX = -1;
-               break;
-       }
-}
-
-void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
-{
-        int    bytes_per_px = (Buf->Depth + 7) / 8;
-        int    y, save_pitch;
-       Uint8   *dest, *src;
-
-       // Just a little sanity
-       if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
-       if( !Buf->CursorSaveBuf )       return ;
-
-//     Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
-
-       // Set up
-       save_pitch = Buf->CursorBitmap->W * bytes_per_px;
-       dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
-       src = Buf->CursorSaveBuf;
-       
-       // Copy each line back
-       for( y = 0; y < Buf->CursorRenderH; y ++ )
-       {
-               memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
-               src += save_pitch;
-               dest += Buf->Pitch;
-       }
-       
-       // Set the cursor as removed
-       Buf->CursorX = -1;
-}
-
-void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
-{
-       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
-
-       // TODO: Handle non-32bit modes
-       if( FBInfo->Depth != 32 )       return;
-
-       // TODO: Be less hacky
-        int    pitch = FBInfo->Pitch/4;
-       Uint32  *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
-       while( H -- ) {
-               Uint32 *tmp;
-                int    i;
-               tmp = buf;
-               for(i=W;i--;tmp++)      *tmp = Colour;
-               buf += pitch;
-       }
-}
-
-void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
-{
-       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
-        int    scrnpitch = FBInfo->Pitch;
-        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
-        int    dst = DstY*scrnpitch + DstX;
-        int    src = SrcY*scrnpitch + SrcX;
-        int    tmp;
-       
-       //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
-       //      Ent, DstX, DstY, SrcX, SrcY, W, H);
-       
-       if(SrcX + W > FBInfo->Width)    W = FBInfo->Width - SrcX;
-       if(DstX + W > FBInfo->Width)    W = FBInfo->Width - DstX;
-       if(SrcY + H > FBInfo->Height)   H = FBInfo->Height - SrcY;
-       if(DstY + H > FBInfo->Height)   H = FBInfo->Height - DstY;
-       
-       //Debug("W = %i, H = %i", W, H);
-       
-       if( dst > src ) {
-               // Reverse copy
-               dst += H*scrnpitch;
-               src += H*scrnpitch;
-               while( H -- ) {
-                       dst -= scrnpitch;
-                       src -= scrnpitch;
-                       tmp = W*bytes_per_px;
-                       for( tmp = W; tmp --; ) {
-                               *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
-                       }
-               }
-       }
-       else if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px) {
-               memmove((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, H*FBInfo->Pitch);
-       }
-       else {
-               // Normal copy is OK
-               while( H -- ) {
-                       memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
-                       dst += scrnpitch;
-                       src += scrnpitch;
-               }
-       }
-       //Log("Vesa_2D_Blit: RETURN");
-}
-       
-
-// --- Disk Driver Helpers ---
-Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
-       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, void *Argument)
-{
-       Uint8   tmp[BlockSize]; // C99
-       Uint64  block = Start / BlockSize;
-        int    offset = Start - block * BlockSize;
-        int    leading = BlockSize - offset;
-       Uint64  num;
-        int    tailings;
-       Uint64  ret;
-       
-       ENTER("XStart XLength pBuffer pReadBlocks XBlockSize pArgument",
-               Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
-       
-       // Non aligned start, let's fix that!
-       if(offset != 0)
-       {
-               if(leading > Length)    leading = Length;
-               LOG("Reading %i bytes from Block1+%i", leading, offset);
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               memcpy( Buffer, &tmp[offset], leading );
-               
-               if(leading == Length) {
-                       LEAVE('i', leading);
-                       return leading;
-               }
-               
-               Buffer = (Uint8*)Buffer + leading;
-               block ++;
-               num = ( Length - leading ) / BlockSize;
-               tailings = Length - num * BlockSize - leading;
-       }
-       else {
-               num = Length / BlockSize;
-               tailings = Length % BlockSize;
-       }
-       
-       // Read central blocks
-       if(num)
-       {
-               LOG("Reading %i blocks", num);
-               ret = ReadBlocks(block, num, Buffer, Argument);
-               if(ret != num ) {
-                       LEAVE('X', leading + ret * BlockSize);
-                       return leading + ret * BlockSize;
-               }
-       }
-       
-       // Read last tailing block
-       if(tailings != 0)
-       {
-               LOG("Reading %i bytes from last block", tailings);
-               block += num;
-               Buffer = (Uint8*)Buffer + num * BlockSize;
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('X', leading + num * BlockSize);
-                       return leading + num * BlockSize;
-               }
-               memcpy( Buffer, tmp, tailings );
-       }
-       
-       LEAVE('X', Length);
-       return Length;
-}
-
-Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,
-       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
-       Uint64 BlockSize, void *Argument)
-{
-       Uint8   tmp[BlockSize]; // C99
-       Uint64  block = Start / BlockSize;
-        int    offset = Start - block * BlockSize;
-        int    leading = BlockSize - offset;
-       Uint64  num;
-        int    tailings;
-       Uint64  ret;
-       
-       ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize pArgument",
-               Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
-       
-       // Non aligned start, let's fix that!
-       if(offset != 0)
-       {
-               if(leading > Length)    leading = Length;
-               LOG("Writing %i bytes to Block1+%i", leading, offset);
-               // Read a copy of the block
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               // Modify
-               memcpy( &tmp[offset], Buffer, leading );
-               // Write Back
-               ret = WriteBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               
-               if(leading == Length) {
-                       LEAVE('i', leading);
-                       return leading;
-               }
-               
-               Buffer = (Uint8*)Buffer + leading;
-               block ++;
-               num = ( Length - leading ) / BlockSize;
-               tailings = Length - num * BlockSize - leading;
-       }
-       else {
-               num = Length / BlockSize;
-               tailings = Length % BlockSize;
-       }
-       
-       // Read central blocks
-       if(num)
-       {
-               LOG("Writing %i blocks", num);
-               ret = WriteBlocks(block, num, Buffer, Argument);
-               if(ret != num ) {
-                       LEAVE('X', leading + ret * BlockSize);
-                       return leading + ret * BlockSize;
-               }
-       }
-       
-       // Read last tailing block
-       if(tailings != 0)
-       {
-               LOG("Writing %i bytes to last block", tailings);
-               block += num;
-               Buffer = (Uint8*)Buffer + num * BlockSize;
-               // Read
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('X', leading + num * BlockSize);
-                       return leading + num * BlockSize;
-               }
-               // Modify
-               memcpy( tmp, Buffer, tailings );
-               // Write
-               ret = WriteBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('X', leading + num * BlockSize);
-                       return leading + num * BlockSize;
-               }
-               
-       }
-       
-       LEAVE('X', Length);
-       return Length;
-}
diff --git a/KernelLand/Kernel/drvutil_disk.c b/KernelLand/Kernel/drvutil_disk.c
new file mode 100644 (file)
index 0000000..db4d631
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge
+ *
+ * drvutil_disk.c
+ * - Storage Driver Helper Functions
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <api_drv_disk.h>
+
+// --- Disk Driver Helpers ---
+Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
+       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, void *Argument)
+{
+       Uint8   tmp[BlockSize]; // C99
+       Uint64  block = Start / BlockSize;
+        int    offset = Start - block * BlockSize;
+        int    leading = BlockSize - offset;
+       Uint64  num;
+        int    tailings;
+       Uint64  ret;
+       
+       ENTER("XStart XLength pBuffer pReadBlocks XBlockSize pArgument",
+               Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
+       
+       // Non aligned start, let's fix that!
+       if(offset != 0)
+       {
+               if(leading > Length)    leading = Length;
+               LOG("Reading %i bytes from Block1+%i", leading, offset);
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               memcpy( Buffer, &tmp[offset], leading );
+               
+               if(leading == Length) {
+                       LEAVE('i', leading);
+                       return leading;
+               }
+               
+               Buffer = (Uint8*)Buffer + leading;
+               block ++;
+               num = ( Length - leading ) / BlockSize;
+               tailings = Length - num * BlockSize - leading;
+       }
+       else {
+               num = Length / BlockSize;
+               tailings = Length % BlockSize;
+       }
+       
+       // Read central blocks
+       if(num)
+       {
+               LOG("Reading %i blocks", num);
+               ret = ReadBlocks(block, num, Buffer, Argument);
+               if(ret != num ) {
+                       LEAVE('X', leading + ret * BlockSize);
+                       return leading + ret * BlockSize;
+               }
+       }
+       
+       // Read last tailing block
+       if(tailings != 0)
+       {
+               LOG("Reading %i bytes from last block", tailings);
+               block += num;
+               Buffer = (Uint8*)Buffer + num * BlockSize;
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('X', leading + num * BlockSize);
+                       return leading + num * BlockSize;
+               }
+               memcpy( Buffer, tmp, tailings );
+       }
+       
+       LEAVE('X', Length);
+       return Length;
+}
+
+Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,
+       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
+       Uint64 BlockSize, void *Argument)
+{
+       Uint8   tmp[BlockSize]; // C99
+       Uint64  block = Start / BlockSize;
+        int    offset = Start - block * BlockSize;
+        int    leading = BlockSize - offset;
+       Uint64  num;
+        int    tailings;
+       Uint64  ret;
+       
+       ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize pArgument",
+               Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
+       
+       // Non aligned start, let's fix that!
+       if(offset != 0)
+       {
+               if(leading > Length)    leading = Length;
+               LOG("Writing %i bytes to Block1+%i", leading, offset);
+               // Read a copy of the block
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               // Modify
+               memcpy( &tmp[offset], Buffer, leading );
+               // Write Back
+               ret = WriteBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               
+               if(leading == Length) {
+                       LEAVE('i', leading);
+                       return leading;
+               }
+               
+               Buffer = (Uint8*)Buffer + leading;
+               block ++;
+               num = ( Length - leading ) / BlockSize;
+               tailings = Length - num * BlockSize - leading;
+       }
+       else {
+               num = Length / BlockSize;
+               tailings = Length % BlockSize;
+       }
+       
+       // Read central blocks
+       if(num)
+       {
+               LOG("Writing %i blocks", num);
+               ret = WriteBlocks(block, num, Buffer, Argument);
+               if(ret != num ) {
+                       LEAVE('X', leading + ret * BlockSize);
+                       return leading + ret * BlockSize;
+               }
+       }
+       
+       // Read last tailing block
+       if(tailings != 0)
+       {
+               LOG("Writing %i bytes to last block", tailings);
+               block += num;
+               Buffer = (Uint8*)Buffer + num * BlockSize;
+               // Read
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('X', leading + num * BlockSize);
+                       return leading + num * BlockSize;
+               }
+               // Modify
+               memcpy( tmp, Buffer, tailings );
+               // Write
+               ret = WriteBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('X', leading + num * BlockSize);
+                       return leading + num * BlockSize;
+               }
+               
+       }
+       
+       LEAVE('X', Length);
+       return Length;
+}
diff --git a/KernelLand/Kernel/drvutil_video.c b/KernelLand/Kernel/drvutil_video.c
new file mode 100644 (file)
index 0000000..094f0b1
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge
+ *
+ * drvutil.c
+ * - Video Driver Helper Functions
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <api_drv_video.h>
+
+// === TYPES ===
+
+// === PROTOTYPES ===
+//int  DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
+//size_t       DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
+//void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
+//void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
+void   DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
+//void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
+void   DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
+void   DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
+
+// === GLOBALS ===
+tDrvUtil_Video_2DHandlers      gDrvUtil_Stub_2DFunctions = {
+       NULL,
+       DrvUtil_Video_2D_Fill,
+       DrvUtil_Video_2D_Blit
+};
+tVideo_IOCtl_Bitmap    gDrvUtil_TextModeCursor = {
+       8, 16,
+       0, 0,
+       {
+               0, 0, 0         , 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0, 0, 0         , 0, 0, 0, 0, 0,
+               0, 0, 0         , 0, 0, 0, 0, 0
+       }
+};
+
+// === CODE ===
+// --- Video Driver Helpers ---
+int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
+       tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
+{
+       const Uint8     *stream = Buffer;
+        int    rem = Length;
+        int    op;
+
+       Uint16  tmp[6];
+
+       while( rem )
+       {
+               rem --;
+               op = *stream;
+               stream ++;
+               
+               if(op > NUM_VIDEO_2DOPS) {
+                       Log_Warning("DrvUtil",
+                               "DrvUtil_Video_2DStream: Unknown operation %i",
+                               op);
+                       return Length-rem;
+               }
+               
+               if(op*sizeof(void*) > SizeofHandlers) {
+                       Log_Warning("DrvUtil",
+                               "DrvUtil_Video_2DStream: Driver does not support op %i",
+                               op);
+                       return Length-rem;
+               }
+               
+               switch(op)
+               {
+               case VIDEO_2DOP_NOP:    break;
+               
+               case VIDEO_2DOP_FILL:
+                       if(rem < 12)    return Length-rem;
+                       memcpy(tmp, stream, 6*2);
+                       
+                       if(!Handlers->Fill) {
+                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
+                                       " does not support VIDEO_2DOP_FILL");
+                               return Length-rem;
+                       }
+                       
+                       Handlers->Fill(
+                               Ent, 
+                               tmp[0], tmp[1], tmp[2], tmp[3],
+                               tmp[4] | ((Uint32)tmp[5] << 16)
+                               );
+                       
+                       rem -= 12;
+                       stream += 12;
+                       break;
+               
+               case VIDEO_2DOP_BLIT:
+                       if(rem < 12)    return Length-rem;
+                       memcpy(tmp, stream, 6*2);
+                       
+                       if(!Handlers->Blit) {
+                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
+                                       " does not support VIDEO_2DOP_BLIT");
+                               return Length-rem;
+                       }
+                       
+                       Handlers->Blit(
+                               Ent,
+                               tmp[0], tmp[1], tmp[2], tmp[3],
+                               tmp[4], tmp[5]
+                               );
+                       
+                       rem -= 12;
+                       stream += 12;
+                       break;
+               
+               }
+       }
+       return 0;
+}
+
+int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
+{
+       Uint8   *dest;
+       const Uint32    *src = Buffer;
+        int    csr_x, csr_y;
+        int    x, y;
+        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
+       ENTER("pFBInfo xOffset xLength pBuffer",
+               FBInfo, Offset, Length, Buffer);
+
+       csr_x = FBInfo->CursorX;
+       csr_y = FBInfo->CursorY;
+
+       DrvUtil_Video_RemoveCursor(FBInfo);
+
+       switch( FBInfo->BufferFormat )
+       {
+       case VIDEO_BUFFMT_TEXT:
+               {
+               const tVT_Char  *chars = Buffer;
+                int    widthInChars = FBInfo->Width/giVT_CharWidth;
+                int    heightInChars = FBInfo->Height/giVT_CharHeight;
+                int    i;
+       
+               LOG("bytes_per_px = %i", bytes_per_px);
+               LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
+       
+               Length /= sizeof(tVT_Char);     Offset /= sizeof(tVT_Char);
+               
+               x = Offset % widthInChars;      y = Offset / widthInChars;
+               LOG("x = %i, y = %i", x, y);    
+       
+               // Sanity Check
+               if(Offset > heightInChars * widthInChars)       LEAVE_RET('i', 0);
+               if(y >= heightInChars)  LEAVE_RET('i', 0);
+               
+               if( Offset + Length > heightInChars*widthInChars )
+               {
+                       Length = heightInChars*widthInChars - Offset;
+               }
+               
+               dest = FBInfo->Framebuffer;
+               LOG("dest = %p", dest);
+               dest += y * giVT_CharHeight * FBInfo->Pitch;
+               LOG("dest = %p", dest);
+               
+               for( i = 0; i < Length; i++ )
+               {
+                       if( y >= heightInChars )
+                       {
+                               Log_Notice("DrvUtil", "Stopped at %i", i);
+                               break;
+                       }
+
+                       VT_Font_Render(
+                               chars->Ch,
+                               dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
+                               VT_Colour12toN(chars->BGCol, FBInfo->Depth),
+                               VT_Colour12toN(chars->FGCol, FBInfo->Depth)
+                               );
+                       
+                       chars ++;
+                       x ++;
+                       if( x >= widthInChars )
+                       {
+                               x = 0;
+                               y ++;
+                               dest += FBInfo->Pitch*giVT_CharHeight;
+                               LOG("dest = %p", dest);
+                       }
+               }
+               Length = i * sizeof(tVT_Char);
+               }
+               break;
+       
+       case VIDEO_BUFFMT_FRAMEBUFFER:
+               if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
+               {
+                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
+                       return 0;
+               }
+               
+               switch(FBInfo->Depth)
+               {
+               case 15:
+               case 16:
+                       Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
+                       break;
+               case 24:
+                       x = Offset % FBInfo->Width;
+                       y = Offset / FBInfo->Width;
+                       dest = (Uint8*)FBInfo->Framebuffer + y*FBInfo->Pitch;
+                       for( ; Length >= 4; Length -= 4 )
+                       {
+                               dest[x*3+0] = *src & 0xFF;
+                               dest[x*3+1] = (*src >> 8) & 0xFF;
+                               dest[x*3+2] = (*src >> 16) & 0xFF;
+                               x ++;
+                               if(x == FBInfo->Width) {
+                                       dest += FBInfo->Pitch;
+                                       x = 0;
+                               }
+                       }
+                       break;
+               case 32:
+                       // Copy to Frambuffer
+                       if( FBInfo->Pitch != FBInfo->Width*4 )
+                       {
+                               Uint32  *px;
+                               // Pitch isn't 4*Width
+                               x = Offset % FBInfo->Width;
+                               y = Offset / FBInfo->Height;
+                               
+                               px = (Uint32*)FBInfo->Framebuffer + y*FBInfo->Pitch/4;
+
+                               for( ; Length >= 4; Length -= 4, x )
+                               {
+                                       px[x++] = *src ++;
+                                       if( x == FBInfo->Width ) {
+                                               x = 0;
+                                               px += FBInfo->Pitch;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               dest = (Uint8 *)FBInfo->Framebuffer + Offset;
+                               memcpy(dest, Buffer, Length);
+                       }
+                       break;
+               default:
+                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depthn %i", FBInfo->Depth);
+                       break;
+               }
+               break;
+       
+       case VIDEO_BUFFMT_2DSTREAM:
+               Length = DrvUtil_Video_2DStream(
+                       FBInfo, Buffer, Length,
+                       &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
+                       );
+               break;
+       
+       default:
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
+
+       LEAVE('x', Length);
+       return Length;
+}
+
+int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
+{
+        int    csrX = Buf->CursorX, csrY = Buf->CursorY;
+       size_t  size;
+
+       ENTER("pBuf pBitmap", Buf, Bitmap);
+
+       // Clear old bitmap
+       if( Buf->CursorBitmap )
+       {
+               LOG("Clearing old cursor");
+               DrvUtil_Video_RemoveCursor(Buf);
+               if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
+               {
+                       free( Buf->CursorSaveBuf );
+                       Buf->CursorSaveBuf = NULL;
+               }
+               if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
+                       free(Buf->CursorBitmap);
+               Buf->CursorBitmap = NULL;
+       }
+       
+       // If the new bitmap is null, disable drawing
+       if( !Bitmap )
+       {
+               Buf->CursorX = -1;
+               Buf->CursorY = -1;
+               LEAVE('i', 0);
+               return 0;
+       }
+
+       // Sanity check the bitmap
+       LOG("Sanity checking plox");
+       if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
+       {
+               Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
+               errno = -EINVAL;
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       // Don't take a copy of the DrvUtil provided cursor
+       if( Bitmap == &gDrvUtil_TextModeCursor )
+       {
+               LOG("No copy (provided cursor)");
+               Buf->CursorBitmap = Bitmap;
+       }
+       else
+       {
+               LOG("Make copy");
+               size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
+               
+               // Take a copy
+               Buf->CursorBitmap = malloc( size );
+               memcpy(Buf->CursorBitmap, Bitmap, size);
+       }
+       
+       // Restore cursor position
+       LOG("Drawing");
+       DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
+       LEAVE('i', 0);
+       return 0;
+}
+
+void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
+{
+        int    render_ox=0, render_oy=0, render_w, render_h;
+
+       ENTER("pBuf iX iY", Buf, X, Y);
+       DrvUtil_Video_RemoveCursor(Buf);
+
+       // X < 0 disables the cursor
+       if( X < 0 ) {
+               Buf->CursorX = -1;
+               LEAVE('-');
+               return ;
+       }
+
+       // Sanity checking
+       if( X < 0 || Y < 0 || X >= Buf->Width || Y >= Buf->Height ) {
+               LEAVE('-');
+               return ;
+       }
+
+       // Ensure the cursor is enabled
+       if( !Buf->CursorBitmap ) {
+               LEAVE('-');
+               return ;
+       }
+       
+       // Save cursor position (for changing the bitmap)
+       Buf->CursorX = X;       Buf->CursorY = Y;
+       // Apply cursor's center offset
+       X -= Buf->CursorBitmap->XOfs;
+       Y -= Buf->CursorBitmap->YOfs;
+       
+       // Get the width of the cursor on screen (clipping to right/bottom edges)
+       render_w = X > Buf->Width  - Buf->CursorBitmap->W ? Buf->Width  - X : Buf->CursorBitmap->W;
+       render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
+
+       // Clipp to left/top edges
+       if(X < 0) {     render_ox = -X; X = 0;  }
+       if(Y < 0) {     render_oy = -Y; Y = 0;  }
+
+       // Save values
+       Buf->CursorRenderW = render_w;  Buf->CursorRenderH = render_h;
+       Buf->CursorDestX   = X;         Buf->CursorDestY = Y;
+       Buf->CursorReadX   = render_ox; Buf->CursorReadY = render_oy;
+
+       LOG("%ix%i at %i,%i offset %i,%i",
+               render_w, render_h, X, Y, render_ox, render_oy);
+
+       // Call render routine
+       DrvUtil_Video_RenderCursor(Buf);
+       LEAVE('-');
+}
+
+void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
+{
+        int    src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
+        int    render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
+        int    dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
+        int    bytes_per_px = (Buf->Depth + 7) / 8;
+        int    save_pitch = Buf->CursorBitmap->W * bytes_per_px;
+       void    *dest;
+       Uint32  *src;
+        int    x, y;
+
+       dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
+       src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
+       
+       LOG("dest = %p, src = %p", dest, src);
+
+       // Allocate save buffer if not already
+       if( !Buf->CursorSaveBuf )
+               Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
+
+       LOG("Saving back");
+       // Save behind the cursor
+       for( y = 0; y < render_h; y ++ )
+               memcpy(
+                       (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
+                       (Uint8*)dest + y*Buf->Pitch,
+                       render_w*bytes_per_px
+                       );
+
+       // Draw the cursor
+       switch(Buf->Depth)
+       {
+       case 15:
+       case 16:
+               Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
+               break;
+       case 24:
+               LOG("24-bit render");
+               for( y = 0; y < render_h; y ++ )
+               {
+                       Uint8   *px;
+                       px = dest;
+                       for(x = 0; x < render_w; x ++, px += 3)
+                       {
+                               Uint32  value = src[x];
+                               // TODO: Should I implement alpha blending?
+                               if(value & 0xFF000000)
+                               {
+                                       px[0] = value & 0xFF;
+                                       px[1] = (value >> 8) & 0xFF;
+                                       px[2] = (value >> 16) & 0xFF;
+                               }
+                               else
+                                       ;
+                       }
+                       src += Buf->CursorBitmap->W;
+                       dest = (Uint8*)dest + Buf->Pitch;
+               }
+               break;
+       case 32:
+               LOG("32-bit render");
+               for( y = 0; y < render_h; y ++ )
+               {
+                       Uint32  *px;
+                       px = dest;
+                       for(x = 0; x < render_w; x ++, px ++)
+                       {
+                               Uint32  value = src[x];
+                               // TODO: Should I implement alpha blending?
+                               if(value & 0xFF000000)
+                                       *px = value;
+                               else
+                                       ;       // NOP, completely transparent
+                       }
+                       LOG("row %i/%i (%p-%P) done", y+1, render_h, dest, MM_GetPhysAddr(dest));
+                       src += Buf->CursorBitmap->W;
+                       dest = (Uint8*)dest + Buf->Pitch;
+               }
+               break;
+       default:
+               Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
+               Buf->CursorX = -1;
+               break;
+       }
+}
+
+void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
+{
+        int    bytes_per_px = (Buf->Depth + 7) / 8;
+        int    y, save_pitch;
+       Uint8   *dest, *src;
+
+       // Just a little sanity
+       if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
+       if( !Buf->CursorSaveBuf )       return ;
+
+//     Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
+
+       // Set up
+       save_pitch = Buf->CursorBitmap->W * bytes_per_px;
+       dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
+       src = Buf->CursorSaveBuf;
+       
+       // Copy each line back
+       for( y = 0; y < Buf->CursorRenderH; y ++ )
+       {
+               memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
+               src += save_pitch;
+               dest += Buf->Pitch;
+       }
+       
+       // Set the cursor as removed
+       Buf->CursorX = -1;
+}
+
+void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
+{
+       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
+
+       // TODO: Handle non-32bit modes
+       if( FBInfo->Depth != 32 )       return;
+
+       // TODO: Be less hacky
+        int    pitch = FBInfo->Pitch/4;
+       Uint32  *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
+       while( H -- ) {
+               Uint32 *tmp;
+                int    i;
+               tmp = buf;
+               for(i=W;i--;tmp++)      *tmp = Colour;
+               buf += pitch;
+       }
+}
+
+void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
+{
+       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
+        int    scrnpitch = FBInfo->Pitch;
+        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
+        int    dst = DstY*scrnpitch + DstX;
+        int    src = SrcY*scrnpitch + SrcX;
+        int    tmp;
+       
+       //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
+       //      Ent, DstX, DstY, SrcX, SrcY, W, H);
+       
+       if(SrcX + W > FBInfo->Width)    W = FBInfo->Width - SrcX;
+       if(DstX + W > FBInfo->Width)    W = FBInfo->Width - DstX;
+       if(SrcY + H > FBInfo->Height)   H = FBInfo->Height - SrcY;
+       if(DstY + H > FBInfo->Height)   H = FBInfo->Height - DstY;
+       
+       //Debug("W = %i, H = %i", W, H);
+       
+       if( dst > src ) {
+               // Reverse copy
+               dst += H*scrnpitch;
+               src += H*scrnpitch;
+               while( H -- ) {
+                       dst -= scrnpitch;
+                       src -= scrnpitch;
+                       tmp = W*bytes_per_px;
+                       for( tmp = W; tmp --; ) {
+                               *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
+                       }
+               }
+       }
+       else if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px) {
+               memmove((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, H*FBInfo->Pitch);
+       }
+       else {
+               // Normal copy is OK
+               while( H -- ) {
+                       memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
+                       dst += scrnpitch;
+                       src += scrnpitch;
+               }
+       }
+       //Log("Vesa_2D_Blit: RETURN");
+}
+       
+
index e673290..1a982fe 100644 (file)
@@ -442,6 +442,8 @@ extern int  UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
  * \}
  */
 
+#include <ctype.h>
+
 /**
  * \brief Get a random number
  * \return Random number
@@ -482,10 +484,12 @@ extern int        Module_LoadFile(const char *Path, const char *ArgStr);
  */
 /**
  * \brief Create a timestamp from a time
+ * \note Days/Months are zero-based (e.g. December is 11, and has a day range of 0-30)
  */
 extern tTime   timestamp(int sec, int mins, int hrs, int day, int month, int year);
 /**
  * \brief Extract the date/time from a timestamp
+ * \note Days/Months are zero-based (e.g. December is 11, and has a day range of 0-30)
  */
 extern void    format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
 /**
diff --git a/KernelLand/Kernel/include/ctype.h b/KernelLand/Kernel/include/ctype.h
new file mode 100644 (file)
index 0000000..2db66c9
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Acess2 Kernel 
+ * - By John Hodge (thePowersGang)
+ * 
+ * ctype.h
+ * - 
+ */
+#ifndef _ACESS__CTYPE_H_
+#define _ACESS__CTYPE_H_
+
+extern int     isalnum(int c);
+extern int     isalpha(int c);
+extern int     isascii(int c);
+extern int     isblank(int c);
+extern int     iscntrl(int c);
+extern int     isdigit(int c);
+extern int     isgraph(int c);
+extern int     islower(int c);
+extern int     isprint(int c);
+extern int     ispunct(int c);
+extern int     isspace(int c);
+extern int     isupper(int c);
+extern int     isxdigit(int c);
+
+extern int     toupper(int c);
+extern int     tolower(int c);
+
+#endif
+
index 3652f19..7c2e97a 100644 (file)
@@ -13,6 +13,7 @@ enum eErrorNums
        EINVAL, // Invalid Paramater
        ENOMEM, // No free memory
        EACCES, // Not permitted
+       EBUSY,  // Resource is busy
        ENOTFOUND,      // Item not found
        EREADONLY,      // Read only
        ENOTIMPL,       // Not implemented
index d728133..1c56146 100644 (file)
@@ -73,7 +73,7 @@ typedef struct sModule
        struct sModule  *Next;  //!< Next module in list (not to be touched by the driver)
        const char      *Name;  //!< Module Name/Identifier
         int    (*Init)(char **Arguments);      //!< Module initialiser / entrypoint
-       void    (*Deinit)(void);        //!< Cleanup Function
+        int    (*Deinit)(void);        //!< Cleanup Function
        const char      **Dependencies; //!< NULL terminated list of dependencies
 } PACKED tModule;
 
diff --git a/KernelLand/Kernel/include/rwlock.h b/KernelLand/Kernel/include/rwlock.h
new file mode 100644 (file)
index 0000000..a6f46b5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Acess2 Kernel
+ * 
+ * rwmutex.c
+ * - Reader-Writer Mutex (Multiple Readers, One Writer)
+ */
+#ifndef _RWLOCK_H
+#define _RWLOCK_H
+
+#include <acess.h>
+
+typedef struct sRWLock tRWLock;
+
+struct sRWLock
+{
+       tShortSpinlock  Protector;      //!< Protector for the lock strucure
+       const char      *Name;  //!< Human-readable name
+        int    Level;  // Number of readers active
+       struct sThread  *volatile Owner;        //!< Owner of the lock (set upon getting the lock)
+       struct sThread  *ReaderWaiting;         //!< Waiting threads (readers)
+       struct sThread  *ReaderWaitingLast;     //!< Waiting threads
+       
+       struct sThread  *WriterWaiting;         //!< Waiting threads (writers)
+       struct sThread  *WriterWaitingLast;     //!< Waiting threads
+};
+
+/**
+ * \brief Acquire a heavy mutex
+ * \param Mutex        Mutex to acquire
+ * \return zero on success, -1 if terminated
+ * 
+ * This type of mutex checks if the mutex is avaliable, and acquires it
+ * if it is. Otherwise, the current thread is added to the mutex's wait
+ * queue and the thread suspends. When the holder of the mutex completes,
+ * the oldest thread (top thread) on the queue is given the lock and
+ * restarted.
+ */
+extern int     RWLock_AcquireRead(tRWLock *Lock);
+
+extern int     RWLock_AcquireWrite(tRWLock *LOck);
+
+/**
+ * \brief Release a held mutex
+ * \param Mutex        Mutex to release
+ * \note Releasing a non-held mutex has no effect
+ */
+extern void    RWLock_Release(tRWLock *Lock);
+
+#endif
index 6e345d0..2f15a72 100644 (file)
@@ -100,6 +100,7 @@ enum {
        THREAD_STAT_ACTIVE,     // Running and schedulable process
        THREAD_STAT_SLEEPING,   // Message Sleep
        THREAD_STAT_MUTEXSLEEP, // Mutex Sleep
+       THREAD_STAT_RWLOCKSLEEP,        // Read-Writer lock Sleep
        THREAD_STAT_SEMAPHORESLEEP,     // Semaphore Sleep
        THREAD_STAT_QUEUESLEEP, // Queue
        THREAD_STAT_EVENTSLEEP, // Event sleep
index f2bf321..91dcd69 100644 (file)
@@ -486,8 +486,9 @@ extern tVFS_Node    *Inode_CacheNode(int Handle, tVFS_Node *Node);
  * \brief Dereferences (and removes if needed) a node from the cache
  * \param Handle       A handle returned by Inode_GetHandle()
  * \param Inode        Value of the Inode field of the ::tVFS_Node you want to remove
+ * \return -1: Error (not present), 0: Not freed, 1: Freed
  */
-extern void    Inode_UncacheNode(int Handle, Uint64 Inode);
+extern int     Inode_UncacheNode(int Handle, Uint64 Inode);
 /**
  * \fn void Inode_ClearCache(int Handle)
  * \brief Clears the cache for a handle
index b4d5e2a..8cabfa1 100644 (file)
@@ -29,6 +29,8 @@ typedef Uint32        tMount;
 #define        VFS_OPENFLAG_NOLINK     0x40
 //! Create the file if it doesn't exist
 #define VFS_OPENFLAG_CREATE    0x80
+//! Treat as a directory
+#define VFS_OPENFLAG_DIRECTORY 0x100
 //! Open as a user
 #define        VFS_OPENFLAG_USER       0x8000
 /**
@@ -336,6 +338,19 @@ extern char        *VFS_GetTruePath(const char *Path);
  * \return 1 on succes, -1 on error
  */
 extern int     VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
+/**
+ * \brief Unmount a mounted filesystem
+ * \param Mountpoint   Location of the mount
+ * \return 0 on success, errno on error
+ */
+extern int     VFS_Unmount(const char *Mountpoint);
+/**
+ * \brief Attemt to unmount all fileystems
+ * \return Number of unmounted filesytems, -1 if none left to unmount
+ * \note Can return 0 when there are stil volumes mounted if there are open handles
+ */
+extern int     VFS_UnmountAll(void);
+
 /**
  * \brief Create a new directory
  * \param Path Path to new directory (absolute or relative)
index a8eadb6..f48e277 100644 (file)
@@ -5,6 +5,7 @@
 #define _VFS_INT_H
 
 #include "vfs.h"
+#include <rwlock.h>
 
 // === TYPES ===
 typedef struct sVFS_Mount {
@@ -16,6 +17,9 @@ typedef struct sVFS_Mount {
        char    *Options;
        tVFS_Driver     *Filesystem;
        tVFS_Node       *RootNode;
+       
+        int    OpenHandleCount;
+       
        char    StrData[];
 } tVFS_Mount;
 
@@ -42,6 +46,7 @@ typedef struct sVFS_MMapPage {
 } tVFS_MMapPage;
 
 // === GLOBALS ===
+extern tRWLock         glVFS_MountList;
 extern tVFS_Mount      *gVFS_Mounts;
 
 // === PROTOTYPES ===
index f07e9f3..68d2032 100644 (file)
@@ -3,38 +3,15 @@
  * Common Library Functions
  */
 #include <acess.h>
-#include <hal_proc.h>
 
 // === CONSTANTS ===
-#define        RANDOM_SEED     0xACE55052
-#define        RANDOM_A        0x00731ADE
-#define        RANDOM_C        12345
-#define        RANDOM_SPRUCE   0xf12b039
 //                          Jan Feb Mar Apr May  Jun  Jul  Aug  Sept Oct  Nov  Dec
 const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
 #define UNIX_TO_2K     ((30*365*3600*24) + (7*3600*24))        //Normal years + leap years
 
 // === PROTOTYPES ===
 #if 0
- int   atoi(const char *string);
- int   ParseInt(const char *string, int *Val);
-void   itoa(char *buf, Uint64 num, int base, int minLength, char pad);
- int   vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
- int   snprintf(char *__s, size_t __n, const char *__format, ...);
- int   sprintf(char *__s, const char *__format, ...);
-#endif
- int   tolower(int c);
-#if 0
- int   strucmp(const char *Str1, const char *Str2);
-char   *strchr(const char *__s, int __c);
- int   strpos(const char *Str, char Ch);
  Uint8 ByteSum(void *Ptr, int Size);
-size_t strlen(const char *__s);
-char   *strcpy(char *__str1, const char *__str2);
-char   *strncpy(char *__str1, const char *__str2, size_t max);
- int   strcmp(const char *str1, const char *str2);
- int   strncmp(const char *str1, const char *str2, size_t num);
-char   *_strdup(const char *File, int Line, const char *Str);
 char   **str_split(const char *__str, char __ch);
  int   strpos8(const char *str, Uint32 Search);
  int   ReadUTF8(Uint8 *str, Uint32 *Val);
@@ -42,452 +19,35 @@ char       **str_split(const char *__str, char __ch);
  int   DivUp(int num, int dem);
 Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year);
 void   format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
- int   rand(void);
- int   CheckString(char *String);
- int   CheckMem(void *Mem, int NumBytes);
  
  int   ModUtil_LookupString(char **Array, char *Needle);
  int   ModUtil_SetIdent(char *Dest, char *Value);
  
  int   Hex(char *Dest, size_t Size, const Uint8 *SourceData);
  int   UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
+
+Uint16 SwapEndian16(Uint16 Val);
+Uint32 SwapEndian32(Uint16 Val);
+Uint64 SwapEndian64(Uint16 Val);
 #endif
 
 // === EXPORTS ===
-EXPORT(atoi);
-EXPORT(itoa);
-EXPORT(vsnprintf);
-EXPORT(snprintf);
-EXPORT(sprintf);
-EXPORT(tolower);
-EXPORT(strucmp);
-EXPORT(strchr);
-EXPORT(strpos);
 EXPORT(ByteSum);
-EXPORT(strlen);
-EXPORT(strcpy);
-EXPORT(strncpy);
-EXPORT(strcat);
-EXPORT(strncat);
-EXPORT(strcmp);
-EXPORT(strncmp);
-//EXPORT(strdup);
-EXPORT(_strdup);       // Takes File/Line too
 EXPORT(str_split);
 EXPORT(strpos8);
 EXPORT(DivUp);
 EXPORT(ReadUTF8);
 EXPORT(WriteUTF8);
 EXPORT(timestamp);
-EXPORT(CheckString);
-EXPORT(CheckMem);
 EXPORT(ModUtil_LookupString);
 EXPORT(ModUtil_SetIdent);
+EXPORT(Hex);
 EXPORT(UnHex);
 EXPORT(SwapEndian16);
 EXPORT(SwapEndian32);
 EXPORT(SwapEndian64);
-EXPORT(memmove);
 
 // === CODE ===
-/**
- * \brief Convert a string into an integer
- */
-int atoi(const char *string)
-{
-       int ret = 0;
-       ParseInt(string, &ret);
-       return ret;
-}
-int ParseInt(const char *string, int *Val)
-{
-        int    ret = 0;
-        int    bNeg = 0;
-       const char *orig_string = string;
-       
-       //Log("atoi: (string='%s')", string);
-       
-       // Clear non-numeric characters
-       while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
-       if( *string == '-' ) {
-               bNeg = 1;
-               while( !('0' <= *string && *string <= '9') )    string++;
-       }
-       
-       if(*string == '0')
-       {
-               string ++;
-               if(*string == 'x')
-               {
-                       // Hex
-                       string ++;
-                       for( ;; string ++ )
-                       {
-                               if('0' <= *string && *string <= '9') {
-                                       ret *= 16;
-                                       ret += *string - '0';
-                               }
-                               else if('A' <= *string && *string <= 'F') {
-                                       ret *= 16;
-                                       ret += *string - 'A' + 10;
-                               }
-                               else if('a' <= *string && *string <= 'f') {
-                                       ret *= 16;
-                                       ret += *string - 'a' + 10;
-                               }
-                               else
-                                       break;
-                       }
-               }
-               else    // Octal
-               {
-                       for( ; '0' <= *string && *string <= '7'; string ++ )
-                       {
-                               ret *= 8;
-                               ret += *string - '0';
-                       }
-               }
-       }
-       else    // Decimal
-       {
-               for( ; '0' <= *string && *string <= '9'; string++)
-               {
-                       ret *= 10;
-                       ret += *string - '0';
-               }
-               // Error check
-               if( ret == 0 )  return 0;
-       }
-       
-       if(bNeg)        ret = -ret;
-       
-       //Log("atoi: RETURN %i", ret);
-       
-       if(Val) *Val = ret;
-       
-       return string - orig_string;
-}
-
-static const char cUCDIGITS[] = "0123456789ABCDEF";
-/**
- * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
- * \brief Convert an integer into a character string
- */
-void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
-{
-       char    tmpBuf[64+1];
-        int    pos=0, i;
-       Uint64  rem;
-
-       // Sanity check
-       if(!buf)        return;
-       
-       // Sanity Check
-       if(base > 16 || base < 2) {
-               buf[0] = 0;
-               return;
-       }
-       
-       // Convert 
-       while(num > base-1) {
-               num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
-               tmpBuf[pos] = cUCDIGITS[ rem ];
-               pos++;
-       }
-       tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
-       
-       // Put in reverse
-       i = 0;
-       minLength -= pos;
-       while(minLength-- > 0)  buf[i++] = pad;
-       while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
-       buf[i] = 0;
-}
-
-/**
- * \brief Append a character the the vsnprintf output
- */
-#define PUTCH(c)       _putch(c)
-#define GETVAL()       do {\
-       if(isLongLong)  val = va_arg(args, Uint64);\
-       else    val = va_arg(args, unsigned int);\
-       }while(0)
-/**
- * \brief VArg String Number Print Formatted
- */
-int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
-{
-       char    c, pad = ' ';
-        int    minSize = 0, precision = -1, len;
-       char    tmpBuf[34];     // For Integers
-       const char      *p = NULL;
-        int    isLongLong = 0;
-       Uint64  val;
-       size_t  pos = 0;
-       // Flags
-        int    bPadLeft = 0;
-       
-       auto void _putch(char ch);
-
-       void _putch(char ch)
-       {
-               if(pos < __maxlen)
-               {
-                       if(__s) __s[pos] = ch;
-                       pos ++;
-               }
-       }
-
-       while((c = *__format++) != 0)
-       {
-               // Non control character
-               if(c != '%') { PUTCH(c); continue; }
-
-               c = *__format++;
-               if(c == '\0')   break;
-               
-               // Literal %
-               if(c == '%') { PUTCH('%'); continue; }
-               
-               // Pointer - Done first for debugging
-               if(c == 'p') {
-                       Uint    ptr = va_arg(args, Uint);
-                       PUTCH('*');     PUTCH('0');     PUTCH('x');
-                       for( len = BITS/4; len --; )
-                               PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
-                       continue ;
-               }
-               
-               // - Padding Side Flag
-               if(c == '-') {
-                       bPadLeft = 1;
-                       c = *__format++;
-               }
-               
-               // - Padding
-               if(c == '0') {
-                       pad = '0';
-                       c = *__format++;
-               }
-               else
-                       pad = ' ';
-               
-               // - Minimum length
-               if(c == '*') {  // Dynamic length
-                       minSize = va_arg(args, unsigned int);
-                       c = *__format++;
-               }
-               else if('1' <= c && c <= '9')
-               {
-                       minSize = 0;
-                       while('0' <= c && c <= '9')
-                       {
-                               minSize *= 10;
-                               minSize += c - '0';
-                               c = *__format++;
-                       }
-               }
-               else
-                       minSize = 0;
-               
-               // - Precision
-               precision = -1;
-               if( c == '.' ) {
-                       c = *__format++;
-                       
-                       if(c == '*') {  // Dynamic length
-                               precision = va_arg(args, unsigned int);
-                               c = *__format++;
-                       }
-                       else if('1' <= c && c <= '9')
-                       {
-                               precision = 0;
-                               while('0' <= c && c <= '9')
-                               {
-                                       precision *= 10;
-                                       precision += c - '0';
-                                       c = *__format++;
-                               }
-                       }
-               }
-               
-               // - Default, Long or LongLong?
-               isLongLong = 0;
-               if(c == 'l')    // Long is actually the default on x86
-               {
-                       c = *__format++;
-                       if(c == 'l') {
-                               c = *__format++;
-                               isLongLong = 1;
-                       }
-               }
-               
-               // - Now get the format code
-               p = tmpBuf;
-               switch(c)
-               {
-               case 'd':
-               case 'i':
-                       GETVAL();
-                       if( isLongLong && val >> 63 ) {
-                               PUTCH('-');
-                               val = -val;
-                       }
-                       else if( !isLongLong && val >> 31 ) {
-                               PUTCH('-');
-                               val = -(Sint32)val;
-                       }
-                       itoa(tmpBuf, val, 10, minSize, pad);
-                       goto printString;
-               case 'u':       // Unsigned
-                       GETVAL();
-                       itoa(tmpBuf, val, 10, minSize, pad);
-                       goto printString;
-               case 'P':       // Physical Address
-                       PUTCH('0');
-                       PUTCH('x');
-                       if(sizeof(tPAddr) > 4)  isLongLong = 1;
-                       GETVAL();
-                       itoa(tmpBuf, val, 16, minSize, pad);
-                       goto printString;
-               case 'X':       // Hex
-                       if(BITS == 64)
-                               isLongLong = 1; // TODO: Handle non-x86 64-bit archs
-                       GETVAL();
-                       itoa(tmpBuf, val, 16, minSize, pad);
-                       goto printString;
-                       
-               case 'x':       // Lower case hex
-                       GETVAL();
-                       itoa(tmpBuf, val, 16, minSize, pad);
-                       goto printString;
-               case 'o':       // Octal
-                       GETVAL();
-                       itoa(tmpBuf, val, 8, minSize, pad);
-                       goto printString;
-               case 'b':
-                       GETVAL();
-                       itoa(tmpBuf, val, 2, minSize, pad);
-                       goto printString;
-
-               case 'B':       //Boolean
-                       val = va_arg(args, unsigned int);
-                       if(val) p = "True";
-                       else    p = "False";
-                       goto printString;
-               
-               // String - Null Terminated Array
-               case 's':
-                       p = va_arg(args, char*);        // Get Argument
-                       if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
-               printString:
-                       if(!p)          p = "(null)";
-                       len = strlen(p);
-                       if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
-                       while(*p && precision--)        PUTCH(*p++);
-                       if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
-                       break;
-               
-               case 'C':       // Non-Null Terminated Character Array
-                       p = va_arg(args, char*);
-                       if( !CheckMem(p, minSize) )     continue;       // No #PFs please
-                       if(!p)  goto printString;
-                       while(minSize--)        PUTCH(*p++);
-                       break;
-               
-               // Single Character
-               case 'c':
-               default:
-                       GETVAL();
-                       PUTCH( (Uint8)val );
-                       break;
-               }
-       }
-       
-       if(__s && pos != __maxlen)
-               __s[pos] = '\0';
-       
-       return pos;
-}
-#undef PUTCH
-
-/**
- */
-int snprintf(char *__s, size_t __n, const char *__format, ...)
-{
-       va_list args;
-        int    ret;
-       
-       va_start(args, __format);
-       ret = vsnprintf(__s, __n, __format, args);
-       va_end(args);
-       
-       return ret;
-}
-
-/**
- */
-int sprintf(char *__s, const char *__format, ...)
-{
-       va_list args;
-        int    ret;
-       
-       va_start(args, __format);
-       ret = vsnprintf(__s, -1, __format, args);
-       va_end(args);
-       
-       return ret;
-}
-
-/**
- * \fn int tolower(int c)
- * \brief Converts a character to lower case
- */
-int tolower(int c)
-{
-       if('A' <= c && c <= 'Z')
-               return c - 'A' + 'a';
-       return c;
-}
-
-/**
- * \fn int strucmp(const char *Str1, const char *Str2)
- * \brief Compare \a Str1 and \a Str2 case-insensitively
- */
-int strucmp(const char *Str1, const char *Str2)
-{
-       while(*Str1 && tolower(*Str1) == tolower(*Str2))
-               Str1++, Str2++;
-       return tolower(*Str1) - tolower(*Str2);
-}
-
-/**
- * \brief Locate a byte in a string
- */
-char *strchr(const char *__s, int __c)
-{
-       for( ; *__s; __s ++ )
-       {
-               if( *__s == __c )       return (char*)__s;
-       }
-       return NULL;
-}
-
-/**
- * \fn int strpos(const char *Str, char Ch)
- * \brief Search a string for an ascii character
- */
-int strpos(const char *Str, char Ch)
-{
-        int    pos;
-       for(pos=0;Str[pos];pos++)
-       {
-               if(Str[pos] == Ch)      return pos;
-       }
-       return -1;
-}
-
 /**
  * \fn Uint8 ByteSum(void *Ptr, int Size)
  * \brief Adds the bytes in a memory region and returns the sum
@@ -500,120 +60,6 @@ Uint8 ByteSum(const void *Ptr, int Size)
        return sum;
 }
 
-/**
- * \fn size_t strlen(const char *__str)
- * \brief Get the length of string
- */
-size_t strlen(const char *__str)
-{
-       size_t  ret = 0;
-       while(*__str++) ret++;
-       return ret;
-}
-
-/**
- * \brief Copy a string to a new location
- */
-char *strcpy(char *__str1, const char *__str2)
-{
-       while(*__str2)
-               *__str1++ = *__str2++;
-       *__str1 = '\0'; // Terminate String
-       return __str1;
-}
-
-/**
- * \brief Copy a string to a new location
- * \note Copies at most `max` chars
- */
-char *strncpy(char *__str1, const char *__str2, size_t __max)
-{
-       while(*__str2 && __max-- >= 1)
-               *__str1++ = *__str2++;
-       if(__max)
-               *__str1 = '\0'; // Terminate String
-       return __str1;
-}
-
-/**
- * \brief Append a string to another
- */
-char *strcat(char *__dest, const char *__src)
-{
-       while(*__dest++);
-       __dest--;
-       while(*__src)
-               *__dest++ = *__src++;
-       *__dest = '\0';
-       return __dest;
-}
-
-/**
- * \brief Append at most \a n chars to a string from another
- * \note At most n+1 chars are written (the dest is always zero terminated)
- */
-char *strncat(char *__dest, const char *__src, size_t n)
-{
-       while(*__dest++);
-       while(*__src && n-- >= 1)
-               *__dest++ = *__src++;
-       *__dest = '\0';
-       return __dest;
-}
-
-/**
- * \fn int strcmp(const char *str1, const char *str2)
- * \brief Compare two strings return the difference between
- *        the first non-matching characters.
- */
-int strcmp(const char *str1, const char *str2)
-{
-       while(*str1 && *str1 == *str2)
-               str1++, str2++;
-       return *str1 - *str2;
-}
-
-/**
- * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
- * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
- */
-int strncmp(const char *Str1, const char *Str2, size_t num)
-{
-       if(num == 0)    return 0;       // TODO: Check what should officially happen here
-       while(--num && *Str1 && *Str1 == *Str2)
-               Str1++, Str2++;
-       return *Str1-*Str2;
-}
-
-#if 0
-/**
- * \fn char *strdup(const char *Str)
- * \brief Duplicates a string
- */
-char *strdup(const char *Str)
-{
-       char    *ret;
-       ret = malloc(strlen(Str)+1);
-       if( !ret )      return NULL;
-       strcpy(ret, Str);
-       return ret;
-}
-#else
-
-/**
- * \fn char *_strdup(const char *File, int Line, const char *Str)
- * \brief Duplicates a string
- */
-char *_strdup(const char *File, int Line, const char *Str)
-{
-       char    *ret;
-       ret = Heap_Allocate(File, Line, strlen(Str)+1);
-       if( !ret )      return NULL;
-       strcpy(ret, Str);
-       return ret;
-}
-#endif
-
 /**
  * \brief Split a string using the passed character
  * \return NULL terminated array of strings on the heap
@@ -695,6 +141,8 @@ int strpos8(const char *str, Uint32 Search)
  */
 int ReadUTF8(const Uint8 *str, Uint32 *Val)
 {
+       Uint32  outval;
+       
        *Val = 0xFFFD;  // Assume invalid character
        
        // ASCII
@@ -710,37 +158,40 @@ int ReadUTF8(const Uint8 *str, Uint32 *Val)
        
        // Two Byte
        if( (*str & 0xE0) == 0xC0 ) {
-               *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
+               outval = (*str & 0x1F) << 6;    // Upper 6 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 2;       // Validity check
+               outval |= (*str & 0x3F);        // Lower 6 Bits
+               *Val = outval;
                return 2;
        }
        
        // Three Byte
        if( (*str & 0xF0) == 0xE0 ) {
-               *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
+               outval = (*str & 0x0F) << 12;   // Upper 4 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 2;       // Validity check
+               outval |= (*str & 0x3F) << 6;   // Middle 6 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 3;       // Validity check
+               outval |= (*str & 0x3F);        // Lower 6 Bits
+               *Val = outval;
                return 3;
        }
        
        // Four Byte
        if( (*str & 0xF1) == 0xF0 ) {
-               *Val = (*str & 0x07) << 18;     // Upper 3 Bits
+               outval = (*str & 0x07) << 18;   // Upper 3 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 2;       // Validity check
+               outval |= (*str & 0x3F) << 12;  // Middle-upper 6 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 3;       // Validity check
+               outval |= (*str & 0x3F) << 6;   // Middle-lower 6 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 4;       // Validity check
+               outval |= (*str & 0x3F);        // Lower 6 Bits
+               *Val = outval;
                return 4;
        }
        
@@ -912,81 +363,6 @@ void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins,
        *day += TS;     // Plus offset from leap handling above
 }
 
-/**
- * \fn int rand()
- * \brief Pseudo random number generator
- */
-int rand(void)
-{
-       #if 0
-       static Uint     state = RANDOM_SEED;
-       Uint    old = state;
-       // Get the next state value
-       giRandomState = (RANDOM_A*state + RANDOM_C);
-       // Check if it has changed, and if it hasn't, change it
-       if(state == old)        state += RANDOM_SPRUCE;
-       return state;
-       #else
-       // http://en.wikipedia.org/wiki/Xorshift
-       // 2010-10-03
-       static Uint32   x = 123456789;
-       static Uint32   y = 362436069;
-       static Uint32   z = 521288629;
-       static Uint32   w = 88675123; 
-       Uint32  t;
-       t = x ^ (x << 11);
-       x = y; y = z; z = w;
-       return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
-       #endif
-}
-
-/* *
- * \name Memory Validation
- * \{
- */
-/**
- * \brief Checks if a string resides fully in valid memory
- */
-int CheckString(const char *String)
-{
-       tVAddr  addr;
-        int    bUser;
-
-       addr = (tVAddr)String;
-
-       if( !MM_GetPhysAddr( addr ) )
-               return 0;
-       
-       // Check 1st page
-       bUser = MM_IsUser( addr );
-       
-       while( *(char*)addr )
-       {
-               if( (addr & (PAGE_SIZE-1)) == 0 )
-               {
-                       if(bUser && !MM_IsUser(addr) )
-                               return 0;
-                       if(!bUser && !MM_GetPhysAddr(addr) )
-                               return 0;
-               }
-               addr ++;
-       }
-       return 1;
-}
-
-/**
- * \brief Check if a sized memory region is valid memory
- * \return Boolean success
- */
-int CheckMem(const void *Mem, int NumBytes)
-{
-       return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
-}
-/* *
- * \}
- */
-
 /**
  * \brief Search a string array for \a Needle
  * \note Helper function for eTplDrv_IOCtl::DRV_IOCTL_LOOKUP
@@ -1065,42 +441,3 @@ Uint64 SwapEndian64(Uint64 Val)
 {
        return SwapEndian32(Val >> 32) | ((Uint64)SwapEndian32(Val) << 32);
 }
-
-void *memmove(void *__dest, const void *__src, size_t len)
-{
-       size_t  block_size;
-       char    *dest = __dest;
-       const char      *src = __src;
-       void    *ret = __dest;
-
-       if( len == 0 || dest == src )
-               return dest;
-       
-       if( (tVAddr)dest > (tVAddr)src + len )
-               return memcpy(dest, src, len);
-       if( (tVAddr)dest + len < (tVAddr)src )
-               return memcpy(dest, src, len);
-       
-       // NOTE: Assumes memcpy works forward
-       if( (tVAddr)dest < (tVAddr)src )
-               return memcpy(dest, src, len);
-
-       if( (tVAddr)dest < (tVAddr)src )
-               block_size = (tVAddr)src - (tVAddr)dest;
-       else
-               block_size = (tVAddr)dest - (tVAddr)src;
-       
-       block_size &= ~0xF;
-       
-       while(len >= block_size)
-       {
-               memcpy(dest, src, block_size);
-               len -= block_size;
-               dest += block_size;
-               src += block_size;
-       }
-       memcpy(dest, src, len);
-       return ret;
-       
-}
-
diff --git a/KernelLand/Kernel/libc.c b/KernelLand/Kernel/libc.c
new file mode 100644 (file)
index 0000000..bd34973
--- /dev/null
@@ -0,0 +1,773 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * libc.c
+ * - Kernel-land C Library
+ */
+#include <acess.h>
+#include <hal_proc.h>  // For MM_*
+
+// === CONSTANTS ===
+#define        RANDOM_SEED     0xACE55052
+#define        RANDOM_A        0x00731ADE
+#define        RANDOM_C        12345
+#define        RANDOM_SPRUCE   0xf12b039
+
+// === PROTOTYPES ===
+#if 0
+ int   atoi(const char *string);
+ int   ParseInt(const char *string, int *Val);
+void   itoa(char *buf, Uint64 num, int base, int minLength, char pad);
+ int   vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
+ int   snprintf(char *__s, size_t __n, const char *__format, ...);
+ int   sprintf(char *__s, const char *__format, ...);
+ int   strucmp(const char *Str1, const char *Str2);
+char   *strchr(const char *__s, int __c);
+ int   strpos(const char *Str, char Ch);
+size_t strlen(const char *__s);
+char   *strcpy(char *__str1, const char *__str2);
+char   *strncpy(char *__str1, const char *__str2, size_t max);
+char   *strcat(char *dest, const char *source);
+ int   strcmp(const char *str1, const char *str2);
+ int   strncmp(const char *str1, const char *str2, size_t num);
+char   *_strdup(const char *File, int Line, const char *Str);
+ int   rand(void);
+void   *memmove(void *__dest, const void *__src, size_t len);
+
+ int   CheckString(char *String);
+ int   CheckMem(void *Mem, int NumBytes); 
+#endif
+
+// === EXPORTS ===
+EXPORT(atoi);
+EXPORT(itoa);
+EXPORT(vsnprintf);
+EXPORT(snprintf);
+EXPORT(sprintf);
+EXPORT(tolower);
+
+EXPORT(strucmp);
+EXPORT(strchr);
+EXPORT(strpos);
+EXPORT(strlen);
+EXPORT(strcpy);
+EXPORT(strncpy);
+EXPORT(strcat);
+EXPORT(strncat);
+EXPORT(strcmp);
+EXPORT(strncmp);
+//EXPORT(strdup);
+EXPORT(_strdup);       // Takes File/Line too
+EXPORT(rand);
+EXPORT(memmove);
+
+EXPORT(CheckString);
+EXPORT(CheckMem);
+
+// === CODE ===
+/**
+ * \brief Convert a string into an integer
+ */
+int atoi(const char *string)
+{
+       int ret = 0;
+       ParseInt(string, &ret);
+       return ret;
+}
+int ParseInt(const char *string, int *Val)
+{
+        int    ret = 0;
+        int    bNeg = 0;
+       const char *orig_string = string;
+       
+       //Log("atoi: (string='%s')", string);
+       
+       // Clear non-numeric characters
+       while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
+       if( *string == '-' ) {
+               bNeg = 1;
+               while( !('0' <= *string && *string <= '9') )    string++;
+       }
+       
+       if(*string == '0')
+       {
+               string ++;
+               if(*string == 'x')
+               {
+                       // Hex
+                       string ++;
+                       for( ;; string ++ )
+                       {
+                               if('0' <= *string && *string <= '9') {
+                                       ret *= 16;
+                                       ret += *string - '0';
+                               }
+                               else if('A' <= *string && *string <= 'F') {
+                                       ret *= 16;
+                                       ret += *string - 'A' + 10;
+                               }
+                               else if('a' <= *string && *string <= 'f') {
+                                       ret *= 16;
+                                       ret += *string - 'a' + 10;
+                               }
+                               else
+                                       break;
+                       }
+               }
+               else    // Octal
+               {
+                       for( ; '0' <= *string && *string <= '7'; string ++ )
+                       {
+                               ret *= 8;
+                               ret += *string - '0';
+                       }
+               }
+       }
+       else    // Decimal
+       {
+               for( ; '0' <= *string && *string <= '9'; string++)
+               {
+                       ret *= 10;
+                       ret += *string - '0';
+               }
+               // Error check
+               if( ret == 0 )  return 0;
+       }
+       
+       if(bNeg)        ret = -ret;
+       
+       //Log("atoi: RETURN %i", ret);
+       
+       if(Val) *Val = ret;
+       
+       return string - orig_string;
+}
+
+static const char cUCDIGITS[] = "0123456789ABCDEF";
+/**
+ * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
+ * \brief Convert an integer into a character string
+ */
+void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
+{
+       char    tmpBuf[64+1];
+        int    pos=0, i;
+       Uint64  rem;
+
+       // Sanity check
+       if(!buf)        return;
+       
+       // Sanity Check
+       if(base > 16 || base < 2) {
+               buf[0] = 0;
+               return;
+       }
+       
+       // Convert 
+       while(num > base-1) {
+               num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
+               tmpBuf[pos] = cUCDIGITS[ rem ];
+               pos++;
+       }
+       tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
+       
+       // Put in reverse
+       i = 0;
+       minLength -= pos;
+       while(minLength-- > 0)  buf[i++] = pad;
+       while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
+       buf[i] = 0;
+}
+
+/**
+ * \brief Append a character the the vsnprintf output
+ */
+#define PUTCH(c)       _putch(c)
+#define GETVAL()       do {\
+       if(isLongLong)  val = va_arg(args, Uint64);\
+       else    val = va_arg(args, unsigned int);\
+       }while(0)
+/**
+ * \brief VArg String Number Print Formatted
+ */
+int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
+{
+       char    c, pad = ' ';
+        int    minSize = 0, precision = -1, len;
+       char    tmpBuf[34];     // For Integers
+       const char      *p = NULL;
+        int    isLongLong = 0;
+       Uint64  val;
+       size_t  pos = 0;
+       // Flags
+        int    bPadLeft = 0;
+       
+       auto void _putch(char ch);
+
+       void _putch(char ch)
+       {
+               if(pos < __maxlen)
+               {
+                       if(__s) __s[pos] = ch;
+                       pos ++;
+               }
+       }
+
+       while((c = *__format++) != 0)
+       {
+               // Non control character
+               if(c != '%') { PUTCH(c); continue; }
+
+               c = *__format++;
+               if(c == '\0')   break;
+               
+               // Literal %
+               if(c == '%') { PUTCH('%'); continue; }
+               
+               // Pointer - Done first for debugging
+               if(c == 'p') {
+                       Uint    ptr = va_arg(args, Uint);
+                       PUTCH('*');     PUTCH('0');     PUTCH('x');
+                       for( len = BITS/4; len --; )
+                               PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
+                       continue ;
+               }
+               
+               // - Padding Side Flag
+               if(c == '-') {
+                       bPadLeft = 1;
+                       c = *__format++;
+               }
+               
+               // - Padding
+               if(c == '0') {
+                       pad = '0';
+                       c = *__format++;
+               }
+               else
+                       pad = ' ';
+               
+               // - Minimum length
+               if(c == '*') {  // Dynamic length
+                       minSize = va_arg(args, unsigned int);
+                       c = *__format++;
+               }
+               else if('1' <= c && c <= '9')
+               {
+                       minSize = 0;
+                       while('0' <= c && c <= '9')
+                       {
+                               minSize *= 10;
+                               minSize += c - '0';
+                               c = *__format++;
+                       }
+               }
+               else
+                       minSize = 0;
+               
+               // - Precision
+               precision = -1;
+               if( c == '.' ) {
+                       c = *__format++;
+                       
+                       if(c == '*') {  // Dynamic length
+                               precision = va_arg(args, unsigned int);
+                               c = *__format++;
+                       }
+                       else if('1' <= c && c <= '9')
+                       {
+                               precision = 0;
+                               while('0' <= c && c <= '9')
+                               {
+                                       precision *= 10;
+                                       precision += c - '0';
+                                       c = *__format++;
+                               }
+                       }
+               }
+               
+               // - Default, Long or LongLong?
+               isLongLong = 0;
+               if(c == 'l')    // Long is actually the default on x86
+               {
+                       c = *__format++;
+                       if(c == 'l') {
+                               c = *__format++;
+                               isLongLong = 1;
+                       }
+               }
+               
+               // - Now get the format code
+               p = tmpBuf;
+               switch(c)
+               {
+               case 'd':
+               case 'i':
+                       GETVAL();
+                       if( isLongLong && val >> 63 ) {
+                               PUTCH('-');
+                               val = -val;
+                       }
+                       else if( !isLongLong && val >> 31 ) {
+                               PUTCH('-');
+                               val = -(Sint32)val;
+                       }
+                       itoa(tmpBuf, val, 10, minSize, pad);
+                       goto printString;
+               case 'u':       // Unsigned
+                       GETVAL();
+                       itoa(tmpBuf, val, 10, minSize, pad);
+                       goto printString;
+               case 'P':       // Physical Address
+                       PUTCH('0');
+                       PUTCH('x');
+                       if(sizeof(tPAddr) > 4)  isLongLong = 1;
+                       GETVAL();
+                       itoa(tmpBuf, val, 16, minSize, pad);
+                       goto printString;
+               case 'X':       // Hex
+                       if(BITS == 64)
+                               isLongLong = 1; // TODO: Handle non-x86 64-bit archs
+                       GETVAL();
+                       itoa(tmpBuf, val, 16, minSize, pad);
+                       goto printString;
+                       
+               case 'x':       // Lower case hex
+                       GETVAL();
+                       itoa(tmpBuf, val, 16, minSize, pad);
+                       goto printString;
+               case 'o':       // Octal
+                       GETVAL();
+                       itoa(tmpBuf, val, 8, minSize, pad);
+                       goto printString;
+               case 'b':
+                       GETVAL();
+                       itoa(tmpBuf, val, 2, minSize, pad);
+                       goto printString;
+
+               case 'B':       //Boolean
+                       val = va_arg(args, unsigned int);
+                       if(val) p = "True";
+                       else    p = "False";
+                       goto printString;
+               
+               // String - Null Terminated Array
+               case 's':
+                       p = va_arg(args, char*);        // Get Argument
+                       if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
+               printString:
+                       if(!p)          p = "(null)";
+                       len = strlen(p);
+                       if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
+                       while(*p && precision--)        PUTCH(*p++);
+                       if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
+                       break;
+               
+               case 'C':       // Non-Null Terminated Character Array
+                       p = va_arg(args, char*);
+                       if( !CheckMem(p, minSize) )     continue;       // No #PFs please
+                       if(!p)  goto printString;
+                       while(minSize--)        PUTCH(*p++);
+                       break;
+               
+               // Single Character
+               case 'c':
+               default:
+                       GETVAL();
+                       PUTCH( (Uint8)val );
+                       break;
+               }
+       }
+       
+       if(__s && pos != __maxlen)
+               __s[pos] = '\0';
+       
+       return pos;
+}
+#undef PUTCH
+
+/**
+ */
+int snprintf(char *__s, size_t __n, const char *__format, ...)
+{
+       va_list args;
+        int    ret;
+       
+       va_start(args, __format);
+       ret = vsnprintf(__s, __n, __format, args);
+       va_end(args);
+       
+       return ret;
+}
+
+/**
+ */
+int sprintf(char *__s, const char *__format, ...)
+{
+       va_list args;
+        int    ret;
+       
+       va_start(args, __format);
+       ret = vsnprintf(__s, -1, __format, args);
+       va_end(args);
+       
+       return ret;
+}
+
+/*
+ * ==================
+ * ctype.h
+ * ==================
+ */
+int isalnum(int c)
+{
+       return isalpha(c) || isdigit(c);
+}
+int isalpha(int c)
+{
+       return isupper(c) || islower(c);
+}
+int isascii(int c)
+{
+       return (0 <= c && c < 128);
+}
+int isblank(int c)
+{
+       if(c == '\t')   return 1;
+       if(c == ' ')    return 1;
+       return 0;
+}
+int iscntrl(int c)
+{
+       // TODO: Check iscntrl
+       if(c < ' ')     return 1;
+       return 0;
+}
+int isdigit(int c)
+{
+       return ('0' <= c && c <= '9');
+}
+int isgraph(int c)
+{
+       // TODO: Check isgraph
+       return 0;
+}
+int islower(int c)
+{
+       return ('a' <= c && c <= 'z');
+}
+int isprint(int c)
+{
+       if( ' ' <= c && c <= 0x7F )     return 1;
+       return 0;
+}
+int ispunct(int c)
+{
+       switch(c)
+       {
+       case '.':       case ',':
+       case '?':       case '!':
+               return 1;
+       default:
+               return 0;
+       }
+}
+int isspace(int c)
+{
+       if(c == ' ')    return 1;
+       if(c == '\t')   return 1;
+       if(c == '\v')   return 1;
+       if(c == '\n')   return 1;
+       if(c == '\r')   return 1;
+       return 0;
+}
+int isupper(int c)
+{
+       return ('a' <= c && c <= 'z');
+}
+int isxdigit(int c)
+{
+       return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+}
+
+int toupper(int c)
+{
+       if( islower(c) )
+               return c - 0x20;
+       else
+               return c;
+}
+int tolower(int c)
+{
+       if( isupper(c) )
+               return c + 0x20;
+       else
+               return c;
+}
+
+/**
+ * \fn int strucmp(const char *Str1, const char *Str2)
+ * \brief Compare \a Str1 and \a Str2 case-insensitively
+ */
+int strucmp(const char *Str1, const char *Str2)
+{
+       while(*Str1 && tolower(*Str1) == tolower(*Str2))
+               Str1++, Str2++;
+       return tolower(*Str1) - tolower(*Str2);
+}
+
+/**
+ * \brief Locate a byte in a string
+ */
+char *strchr(const char *__s, int __c)
+{
+       for( ; *__s; __s ++ )
+       {
+               if( *__s == __c )       return (char*)__s;
+       }
+       return NULL;
+}
+
+/**
+ * \fn int strpos(const char *Str, char Ch)
+ * \brief Search a string for an ascii character
+ */
+int strpos(const char *Str, char Ch)
+{
+        int    pos;
+       for(pos=0;Str[pos];pos++)
+       {
+               if(Str[pos] == Ch)      return pos;
+       }
+       return -1;
+}
+
+/**
+ * \fn size_t strlen(const char *__str)
+ * \brief Get the length of string
+ */
+size_t strlen(const char *__str)
+{
+       size_t  ret = 0;
+       while(*__str++) ret++;
+       return ret;
+}
+
+/**
+ * \brief Copy a string to a new location
+ */
+char *strcpy(char *__str1, const char *__str2)
+{
+       while(*__str2)
+               *__str1++ = *__str2++;
+       *__str1 = '\0'; // Terminate String
+       return __str1;
+}
+
+/**
+ * \brief Copy a string to a new location
+ * \note Copies at most `max` chars
+ */
+char *strncpy(char *__str1, const char *__str2, size_t __max)
+{
+       while(*__str2 && __max-- >= 1)
+               *__str1++ = *__str2++;
+       if(__max)
+               *__str1 = '\0'; // Terminate String
+       return __str1;
+}
+
+/**
+ * \brief Append a string to another
+ */
+char *strcat(char *__dest, const char *__src)
+{
+       while(*__dest++);
+       __dest--;
+       while(*__src)
+               *__dest++ = *__src++;
+       *__dest = '\0';
+       return __dest;
+}
+
+/**
+ * \brief Append at most \a n chars to a string from another
+ * \note At most n+1 chars are written (the dest is always zero terminated)
+ */
+char *strncat(char *__dest, const char *__src, size_t n)
+{
+       while(*__dest++);
+       while(*__src && n-- >= 1)
+               *__dest++ = *__src++;
+       *__dest = '\0';
+       return __dest;
+}
+
+/**
+ * \fn int strcmp(const char *str1, const char *str2)
+ * \brief Compare two strings return the difference between
+ *        the first non-matching characters.
+ */
+int strcmp(const char *str1, const char *str2)
+{
+       while(*str1 && *str1 == *str2)
+               str1++, str2++;
+       return *str1 - *str2;
+}
+
+/**
+ * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
+ * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
+ */
+int strncmp(const char *Str1, const char *Str2, size_t num)
+{
+       if(num == 0)    return 0;       // TODO: Check what should officially happen here
+       while(--num && *Str1 && *Str1 == *Str2)
+               Str1++, Str2++;
+       return *Str1-*Str2;
+}
+
+#if 0
+/**
+ * \fn char *strdup(const char *Str)
+ * \brief Duplicates a string
+ */
+char *strdup(const char *Str)
+{
+       char    *ret;
+       ret = malloc(strlen(Str)+1);
+       if( !ret )      return NULL;
+       strcpy(ret, Str);
+       return ret;
+}
+#else
+
+/**
+ * \fn char *_strdup(const char *File, int Line, const char *Str)
+ * \brief Duplicates a string
+ */
+char *_strdup(const char *File, int Line, const char *Str)
+{
+       char    *ret;
+       ret = Heap_Allocate(File, Line, strlen(Str)+1);
+       if( !ret )      return NULL;
+       strcpy(ret, Str);
+       return ret;
+}
+#endif
+
+/**
+ * \fn int rand()
+ * \brief Pseudo random number generator
+ */
+int rand(void)
+{
+       #if 0
+       static Uint     state = RANDOM_SEED;
+       Uint    old = state;
+       // Get the next state value
+       giRandomState = (RANDOM_A*state + RANDOM_C);
+       // Check if it has changed, and if it hasn't, change it
+       if(state == old)        state += RANDOM_SPRUCE;
+       return state;
+       #else
+       // http://en.wikipedia.org/wiki/Xorshift
+       // 2010-10-03
+       static Uint32   x = 123456789;
+       static Uint32   y = 362436069;
+       static Uint32   z = 521288629;
+       static Uint32   w = 88675123; 
+       Uint32  t;
+       t = x ^ (x << 11);
+       x = y; y = z; z = w;
+       return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
+       #endif
+}
+
+void *memmove(void *__dest, const void *__src, size_t len)
+{
+       size_t  block_size;
+       char    *dest = __dest;
+       const char      *src = __src;
+       void    *ret = __dest;
+
+       if( len == 0 || dest == src )
+               return dest;
+       
+       if( (tVAddr)dest > (tVAddr)src + len )
+               return memcpy(dest, src, len);
+       if( (tVAddr)dest + len < (tVAddr)src )
+               return memcpy(dest, src, len);
+       
+       // NOTE: Assumes memcpy works forward
+       if( (tVAddr)dest < (tVAddr)src )
+               return memcpy(dest, src, len);
+
+       if( (tVAddr)dest < (tVAddr)src )
+               block_size = (tVAddr)src - (tVAddr)dest;
+       else
+               block_size = (tVAddr)dest - (tVAddr)src;
+       
+       block_size &= ~0xF;
+       
+       while(len >= block_size)
+       {
+               memcpy(dest, src, block_size);
+               len -= block_size;
+               dest += block_size;
+               src += block_size;
+       }
+       memcpy(dest, src, len);
+       return ret;
+       
+}
+
+// NOTE: Strictly not libc, but lib.c is used by userland code too
+/**
+ * \name Memory Validation
+ * \{
+ */
+/**
+ * \brief Checks if a string resides fully in valid memory
+ */
+int CheckString(const char *String)
+{
+       tVAddr  addr;
+        int    bUser;
+
+       addr = (tVAddr)String;
+
+       if( !MM_GetPhysAddr( addr ) )
+               return 0;
+       
+       // Check 1st page
+       bUser = MM_IsUser( addr );
+       
+       while( *(char*)addr )
+       {
+               if( (addr & (PAGE_SIZE-1)) == 0 )
+               {
+                       if(bUser && !MM_IsUser(addr) )
+                               return 0;
+                       if(!bUser && !MM_GetPhysAddr(addr) )
+                               return 0;
+               }
+               addr ++;
+       }
+       return 1;
+}
+
+/**
+ * \brief Check if a sized memory region is valid memory
+ * \return Boolean success
+ */
+int CheckMem(const void *Mem, int NumBytes)
+{
+       return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
+}
+/* *
+ * \}
+ */
+
diff --git a/KernelLand/Kernel/rwlock.c b/KernelLand/Kernel/rwlock.c
new file mode 100644 (file)
index 0000000..6706bb2
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * rwlock.c
+ * - Reader-Writer Lockes
+ */
+#include <acess.h>
+#include <threads_int.h>
+#include <rwlock.h>
+
+// === PROTOTYPES ===
+//
+// Acquire as a reader (see rwlock.h for documentation)
+//
+int RWLock_AcquireRead(tRWLock *Lock)
+{
+       tThread *us;
+       // Get protector
+       SHORTLOCK( &Lock->Protector );
+       
+       // Check if the lock is already held by a writer
+       if( Lock->Owner )
+       {
+               SHORTLOCK( &glThreadListLock );
+               
+               // - Remove from active list
+               us = Threads_RemActive();
+               us->Next = NULL;
+               // - Mark as sleeping
+               us->Status = THREAD_STAT_RWLOCKSLEEP;
+               us->WaitPointer = Lock;
+               
+               // - Add to waiting
+               if(Lock->ReaderWaiting)
+                       Lock->ReaderWaitingLast->Next = us;
+               else
+                       Lock->ReaderWaiting = us;
+               Lock->ReaderWaitingLast = us;
+               
+               #if DEBUG_TRACE_STATE
+               Log("%p (%i %s) waiting on rwlock %p",
+                       us, us->TID, us->ThreadName, Lock);
+               #endif
+               
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &Lock->Protector );
+               while(us->Status == THREAD_STAT_RWLOCKSLEEP)    Threads_Yield();
+               // We're only woken when we get the lock
+               // TODO: Handle when this isn't the case
+               us->WaitPointer = NULL;
+       }
+       // Ooh, no problems then!
+       else
+       {
+               Lock->Level++;
+               SHORTREL( & Lock->Protector );
+       }
+       
+       return 0;
+}
+
+int RWLock_AcquireWrite(tRWLock *Lock)
+{
+       tThread *us;
+       
+       SHORTLOCK(&Lock->Protector);
+       if( Lock->Owner || Lock->Level != 0 )
+       {
+               SHORTLOCK(&glThreadListLock);
+               
+               us = Threads_RemActive();
+               us->Next = NULL;
+               us->Status = THREAD_STAT_RWLOCKSLEEP;
+               us->WaitPointer = Lock;
+               
+               if( Lock->WriterWaiting )
+                       Lock->WriterWaitingLast->Next = us;
+               else
+                       Lock->WriterWaiting = us;
+               Lock->WriterWaitingLast = us;
+               
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &Lock->Protector );
+               
+               while(us->Status == THREAD_STAT_RWLOCKSLEEP)    Threads_Yield();
+               us->WaitPointer = NULL;
+       }
+       else
+       {
+               // Nothing else is using the lock, nice :)
+               Lock->Owner = Proc_GetCurThread();
+               SHORTREL(&Lock->Protector);
+       }
+       return 0;
+}
+
+// Release a mutex
+void RWLock_Release(tRWLock *Lock)
+{
+       SHORTLOCK( &Lock->Protector );
+
+       if( Lock->Owner == Proc_GetCurThread() )
+               Lock->Level --;
+       
+       // Writers first
+       if( Lock->WriterWaiting )
+       {
+               Lock->Owner = Lock->WriterWaiting;      // Set owner
+               Lock->WriterWaiting = Lock->WriterWaiting->Next;        // Next!
+               
+               // Wake new owner
+               if( Lock->Owner->Status != THREAD_STAT_ACTIVE )
+                       Threads_AddActive(Lock->Owner);
+       }
+       else
+       {
+               Lock->Owner = NULL;
+               
+               while( Lock->ReaderWaiting ) {
+                       Lock->Level ++;
+                       Threads_AddActive(Lock->ReaderWaiting);
+                       Lock->ReaderWaiting = Lock->ReaderWaiting->Next;
+               }
+       }
+       SHORTREL( &Lock->Protector );
+}
+
+// === EXPORTS ===
+EXPORT(RWLock_AcquireRead);
+EXPORT(RWLock_AcquireWrite);
+EXPORT(RWLock_Release);
index d4c1530..fcf361e 100644 (file)
@@ -36,6 +36,7 @@ int VFS_MkDir(const char *Path)
  */
 int VFS_MkNod(const char *Path, Uint Flags)
 {
+       tVFS_Mount      *mountpt;
        char    *absPath, *name;
         int    pos = 0, oldpos = 0;
         int    next = 0;
@@ -60,9 +61,9 @@ int VFS_MkNod(const char *Path, Uint Flags)
        
        // Check for root
        if(absPath[0] == '\0')
-               parent = VFS_ParsePath("/", NULL, NULL);
+               parent = VFS_ParsePath("/", NULL, &mountpt);
        else
-               parent = VFS_ParsePath(absPath, NULL, NULL);
+               parent = VFS_ParsePath(absPath, NULL, &mountpt);
        
        LOG("parent = %p", parent);
        
@@ -70,10 +71,11 @@ int VFS_MkNod(const char *Path, Uint Flags)
                LEAVE('i', -1);
                return -1;      // Error Check
        }
-       
+
        // Permissions Check
        if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
                _CloseNode(parent);
+               mountpt->OpenHandleCount --;
                free(absPath);
                LEAVE('i', -1);
                return -1;
@@ -82,7 +84,8 @@ int VFS_MkNod(const char *Path, Uint Flags)
        LOG("parent = %p", parent);
        
        if(!parent->Type || !parent->Type->MkNod) {
-               Warning("VFS_MkNod - Directory has no MkNod method");
+               Log_Warning("VFS", "VFS_MkNod - Directory has no MkNod method");
+               mountpt->OpenHandleCount --;
                LEAVE('i', -1);
                return -1;
        }
@@ -94,10 +97,11 @@ int VFS_MkNod(const char *Path, Uint Flags)
        free(absPath);
        
        // Free Parent
+       mountpt->OpenHandleCount --;
        _CloseNode(parent);
        
        // Error Check
-       if(ret == 0) {
+       if(ret != 0) {
                LEAVE('i', -1);
                return -1;
        }
index 1355226..354f402 100644 (file)
 void   DevFS_DelDevice(tDevFS_Driver *Device);
 #endif
 tVFS_Node      *DevFS_InitDevice(const char *Device, const char **Options);
+void   DevFS_Unmount(tVFS_Node *RootNode);
 char   *DevFS_ReadDir(tVFS_Node *Node, int Pos);
 tVFS_Node      *DevFS_FindDir(tVFS_Node *Node, const char *Name);
 
 // === GLOBALS ===
 tVFS_Driver    gDevFS_Info = {
-       "devfs", 0, DevFS_InitDevice, NULL, NULL
+       "devfs", 0, DevFS_InitDevice, DevFS_Unmount, NULL
        };
 tVFS_NodeType  gDevFS_DirType = {
        .TypeName = "DevFS-Dir",
@@ -117,6 +118,11 @@ tVFS_Node *DevFS_InitDevice(const char *Device, const char **Options)
        return &gDevFS_RootNode;
 }
 
+void DevFS_Unmount(tVFS_Node *RootNode)
+{
+       
+}
+
 /**
  * \fn char *DevFS_ReadDir(tVFS_Node *Node, int Pos)
  */
index 00829ed..4416750 100644 (file)
@@ -60,7 +60,9 @@ tVFS_Node *Root_InitDevice(const char *Device, const char **Options)
        
        // Create Root Node
        root = &RootFS_Files[0];
-       
+
+       root->Name[0] = '/';
+       root->Name[1] = '\0';
        root->Node.ImplPtr = root;
        
        root->Node.CTime
@@ -82,11 +84,11 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
 {
        tRamFS_File     *parent = Node->ImplPtr;
        tRamFS_File     *child;
-       tRamFS_File     *prev = (tRamFS_File *) &parent->Data.FirstChild;
+       tRamFS_File     *prev = NULL;
        
        ENTER("pNode sName xFlags", Node, Name, Flags);
        
-       LOG("%i > %i", strlen(Name)+1, sizeof(child->Name));
+       LOG("Sanity check name length - %i > %i", strlen(Name)+1, sizeof(child->Name));
        if(strlen(Name) + 1 > sizeof(child->Name))
                LEAVE_RET('i', 0);
        
@@ -94,6 +96,7 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
        for( child = parent->Data.FirstChild; child; prev = child, child = child->Next )
        {
                if(strcmp(child->Name, Name) == 0) {
+                       LOG("Duplicate");
                        LEAVE('i', 0);
                        return 0;
                }
@@ -103,6 +106,7 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
        memset(child, 0, sizeof(tRamFS_File));
        
        strcpy(child->Name, Name);
+       LOG("Name = '%s'", child->Name);
        
        child->Parent = parent;
        child->Next = NULL;
@@ -125,7 +129,11 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
                child->Node.Type = &gRootFS_FileType;
        }
        
-       prev->Next = child;
+       // Append!
+       if( prev )
+               prev->Next = child;
+       else
+               parent->Data.FirstChild = child;
        
        parent->Node.Size ++;
        
@@ -143,13 +151,12 @@ tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name)
        tRamFS_File     *child = parent->Data.FirstChild;
        
        ENTER("pNode sName", Node, Name);
-       //Log("Root_FindDir: (Node=%p, Name='%s')", Node, Name);
        
-       for(;child;child = child->Next)
+       for( child = parent->Data.FirstChild; child; child = child->Next )
        {
-               //Log(" Root_FindDir: strcmp('%s', '%s')", child->Node.Name, Name);
                LOG("child->Name = '%s'", child->Name);
-               if(strcmp(child->Name, Name) == 0) {
+               if(strcmp(child->Name, Name) == 0)
+               {
                        LEAVE('p', &child->Node);
                        return &child->Node;
                }
index d22f965..6d2b83f 100644 (file)
@@ -198,6 +198,7 @@ void *VFS_SaveHandles(int NumFDs, int *FDs)
                        continue ;
                if( h->Node->Type && h->Node->Type->Reference )
                        h->Node->Type->Reference( h->Node );
+               h->Mount->OpenHandleCount ++;
        }       
 
        return ret;
@@ -244,6 +245,7 @@ void VFS_RestoreHandles(int NumFDs, void *Handles)
                        continue ;
                if( h->Node->Type && h->Node->Type->Reference )
                        h->Node->Type->Reference( h->Node );
+               h->Mount->OpenHandleCount ++;
        }
 }
 
@@ -265,6 +267,7 @@ void VFS_FreeSavedHandles(int NumFDs, void *Handles)
                        continue ;
                if( h->Node->Type && h->Node->Type->Close )
                        h->Node->Type->Close( h->Node );
+               h->Mount->OpenHandleCount --;
        }
        free( Handles );
 }
index f281247..c49e6d9 100644 (file)
@@ -1,6 +1,7 @@
 /* 
  * Acess Micro - VFS Server version 1
  */
+#define DEBUG  1
 #include <acess.h>
 #include <vfs.h>
 #include <vfs_int.h>
@@ -17,7 +18,7 @@ extern char   *gsVFS_MountFile;
 void   VFS_UpdateMountFile(void);
 
 // === GLOBALS ===
-tMutex glVFS_MountList;
+tRWLock        glVFS_MountList;
 tVFS_Mount     *gVFS_Mounts;
 tVFS_Mount     *gVFS_RootMount = NULL;
 Uint32 giVFS_NextMountIdent = 1;
@@ -37,7 +38,7 @@ Uint32        giVFS_NextMountIdent = 1;
  */
 int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options)
 {
-       tVFS_Mount      *mnt;
+       tVFS_Mount      *mnt, *parent_mnt;
        tVFS_Driver     *fs;
         int    deviceLen = strlen(Device);
         int    mountLen = strlen(MountPoint);
@@ -55,6 +56,24 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
        if(!mnt) {
                return -2;
        }
+
+       // Validate the mountpoint target
+       // - Only if / is mounted
+       if( gVFS_Mounts )
+       {
+               tVFS_Node *mpnode = VFS_ParsePath(MountPoint, NULL, &parent_mnt);
+               if( !mpnode ) {
+                       Log_Warning("VFS", "VFS_Mount - Mountpoint '%s' does not exist", MountPoint);
+                       return -1;
+               }
+               if( mpnode->Type->Close )
+                       mpnode->Type->Close(mpnode);
+               if( parent_mnt->RootNode == mpnode ) {
+                       Log_Warning("VFS", "VFS_Mount - Attempt to mount over '%s' (%s)",
+                               MountPoint, parent_mnt->MountPoint);
+                       return -1;
+               }
+       }
        
        // HACK: Forces VFS_ParsePath to fall back on root  
        if(mountLen == 1 && MountPoint[0] == '/')
@@ -64,6 +83,7 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
        
        // Fill Structure
        mnt->Filesystem = fs;
+       mnt->OpenHandleCount = 0;
        
        mnt->Device = &mnt->StrData[0];
        memcpy( mnt->Device, Device, deviceLen+1 );
@@ -90,11 +110,12 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
                if(str) *str = '\0';
        } while( str );
        args[nArg] = 0; // NULL terminal
-
+       
        // Initialise Volume
        mnt->RootNode = fs->InitDevice(Device, (const char **)args);
        if(!mnt->RootNode) {
                free(mnt);
+               parent_mnt->OpenHandleCount --;
                return -2;
        }
 
@@ -114,11 +135,11 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
        if(!gVFS_RootMount)     gVFS_RootMount = mnt;
        
        // Add to mount list
-       Mutex_Acquire( &glVFS_MountList );
+       RWLock_AcquireWrite( &glVFS_MountList );
        {
-               tVFS_Mount      *tmp;
                mnt->Next = NULL;
                if(gVFS_Mounts) {
+                       tVFS_Mount      *tmp;
                        for( tmp = gVFS_Mounts; tmp->Next; tmp = tmp->Next );
                        tmp->Next = mnt;
                }
@@ -126,7 +147,7 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
                        gVFS_Mounts = mnt;
                }
        }
-       Mutex_Release( &glVFS_MountList );
+       RWLock_Release( &glVFS_MountList );
        
        Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
        
@@ -135,18 +156,107 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
        return 0;
 }
 
+int VFS_Unmount(const char *Mountpoint)
+{
+       tVFS_Mount      *mount, *prev = NULL;
+       RWLock_AcquireWrite( &glVFS_MountList );
+       for( mount = gVFS_Mounts; mount; prev = mount, mount = mount->Next )
+       {
+               if( strcmp(Mountpoint, mount->MountPoint) == 0 ) {
+                       if( mount->OpenHandleCount ) {
+                               LOG("Mountpoint busy");
+                               RWLock_Release(&glVFS_MountList);
+                               return EBUSY;
+                       }
+                       if(prev)
+                               prev->Next = mount->Next;
+                       else
+                               gVFS_Mounts = mount->Next;
+                       break;
+               }
+       }
+       RWLock_Release( &glVFS_MountList );
+       if( !mount ) {
+               LOG("Mountpoint not found");
+               return ENOENT;
+       }
+       
+       Log_Warning("VFS", "TODO: Impliment unmount");
+
+       // Decrease the open handle count for the mountpoint filesystem.
+       tVFS_Mount      *mpmnt;
+       tVFS_Node *mpnode = VFS_ParsePath(mount->MountPoint, NULL, &mpmnt);
+       if(mpnode)
+       {
+               mpmnt->OpenHandleCount -= 2;    // -1 for _ParsePath here, -1 for in _Mount
+       }
+
+       mount->Filesystem->Unmount( mount->RootNode );
+       free(mount);
+
+       return EOK;
+}
+
+int VFS_UnmountAll(void)
+{
+        int    nUnmounted = 0;
+       tVFS_Mount      *mount, *prev = NULL, *next;
+
+       RWLock_AcquireWrite( &glVFS_MountList );
+       // If we've unmounted the final filesystem, all good
+       if( gVFS_Mounts == NULL) {
+               RWLock_Release( &glVFS_MountList );
+               return -1;
+       }
+
+       for( mount = gVFS_Mounts; mount; prev = mount, mount = next )
+       {
+               next = mount->Next;
+               // Can't unmount stuff with open handles
+               if( mount->OpenHandleCount > 0 ) {
+                       LOG("%p (%s) has open handles (%i of them)",
+                               mount, mount->MountPoint, mount->OpenHandleCount);
+                       continue;
+               }
+               
+               if(prev)
+                       prev->Next = mount->Next;
+               else
+                       gVFS_Mounts = mount->Next;
+               
+               if( mount->Filesystem->Unmount ) {
+                       mount->Filesystem->Unmount( mount->RootNode );
+               }
+               else {
+                       Log_Error("VFS", "%s (%s) does not have an unmount method, not calling it",
+                               mount->MountPoint, mount->Filesystem->Name);
+               }
+               free(mount);
+               mount = prev;
+               nUnmounted ++;
+       }
+       RWLock_Release( &glVFS_MountList );
+
+       return nUnmounted;
+}
+
 /**
  * \brief Gets a mount point given the identifier
  */
 tVFS_Mount *VFS_GetMountByIdent(Uint32 MountID)
 {
        tVFS_Mount      *mnt;
+       
+       RWLock_AcquireRead(&glVFS_MountList);
        for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
        {
                if(mnt->Identifier == MountID)
-                       return mnt;
+                       break;
        }
-       return NULL;
+       if(mnt)
+               mnt->OpenHandleCount ++;
+       RWLock_Release(&glVFS_MountList);
+       return mnt;
 }
 
 /**
@@ -163,14 +273,17 @@ void VFS_UpdateMountFile(void)
        // Format:
        // <device>\t<location>\t<type>\t<options>\n
        
+       RWLock_AcquireRead( &glVFS_MountList );
        for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
        {
                len += 4 + strlen(mnt->Device) + strlen(mnt->MountPoint)
                        + strlen(mnt->Filesystem->Name) + strlen(mnt->Options);
        }
+       RWLock_Release( &glVFS_MountList );
        
        buf = malloc( len + 1 );
        len = 0;
+       RWLock_AcquireRead( &glVFS_MountList );
        for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
        {
                strcpy( &buf[len], mnt->Device );
@@ -189,6 +302,7 @@ void VFS_UpdateMountFile(void)
                len += strlen(mnt->Options);
                buf[len++] = '\n';
        }
+       RWLock_Release( &glVFS_MountList );
        buf[len] = 0;
        
        SysFS_UpdateFile( giVFS_MountFileID, buf, len );
index d2796c1..ffad243 100644 (file)
@@ -1,7 +1,11 @@
 /*
- * AcessMicro VFS
- * - File IO Passthru's
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * vfs/nodecache.c
+ * - VFS Node Caching facility
  */
+#define DEBUG  0
 #include <acess.h>
 #include "vfs.h"
 #include "vfs_int.h"
@@ -45,7 +49,7 @@ int Inode_GetHandle()
        gVFS_InodeCache = ent;
        SHORTREL( &glVFS_InodeCache );
        
-       return gVFS_NextInodeHandle-1;
+       return ent->Handle;
 }
 
 /**
@@ -107,7 +111,10 @@ tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
        newEnt->Next = ent;
        memcpy(&newEnt->Node, Node, sizeof(tVFS_Node));
        prev->Next = newEnt;
-               
+       newEnt->Node.ReferenceCount = 1;
+
+       LOG("Cached %llx as %p", Node->Inode, &newEnt->Node);
+
        return &newEnt->Node;
 }
 
@@ -115,15 +122,23 @@ tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
  * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
  * \brief Dereferences/Removes a cached node
  */
-void Inode_UncacheNode(int Handle, Uint64 Inode)
+int Inode_UncacheNode(int Handle, Uint64 Inode)
 {
        tInodeCache     *cache;
        tCachedInode    *ent, *prev;
        
        cache = Inode_int_GetFSCache(Handle);
-       if(!cache)      return ;
-       
-       if(Inode > cache->MaxCached)    return ;
+       if(!cache) {
+               Log_Notice("Inode", "Invalid cache handle %i used", Handle);
+               return -1;
+       }
+
+       ENTER("iHandle XInode", Handle, Inode);
+
+       if(Inode > cache->MaxCached) {
+               LEAVE('i', -1);
+               return -1;
+       }
        
        // Search Cache
        ent = cache->FirstNode;
@@ -131,26 +146,45 @@ void Inode_UncacheNode(int Handle, Uint64 Inode)
        for( ; ent; prev = ent, ent = ent->Next )
        {
                if(ent->Node.Inode < Inode)     continue;
-               if(ent->Node.Inode > Inode)     return;
-               ent->Node.ReferenceCount --;
-               // Check if node needs to be freed
-               if(ent->Node.ReferenceCount == 0)
+               if(ent->Node.Inode > Inode) {
+                       LEAVE('i', -1);
+                       return -1;
+               }
+               break;
+       }
+
+       LOG("ent = %p", ent);
+
+       if( !ent ) {
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       ent->Node.ReferenceCount --;
+       // Check if node needs to be freed
+       if(ent->Node.ReferenceCount == 0)
+       {
+               prev->Next = ent->Next;
+               if(ent->Node.Inode == cache->MaxCached)
                {
-                       prev->Next = ent->Next;
-                       if(ent->Node.Inode == cache->MaxCached)
-                       {
-                               if(ent != cache->FirstNode)
-                                       cache->MaxCached = prev->Node.Inode;
-                               else
-                                       cache->MaxCached = 0;
-                       }
-                               
-                       free(ent);
+                       if(ent != cache->FirstNode)
+                               cache->MaxCached = prev->Node.Inode;
+                       else
+                               cache->MaxCached = 0;
                }
-               return ;
+               
+               if(ent->Node.Data)
+                       free(ent->Node.Data);   
+               free(ent);
+               LOG("Freed");
+               LEAVE('i', 1);
+               return 1;
+       }
+       else
+       {
+               LEAVE('i', 0);
+               return 0;
        }
-       
-       return ;
 }
 
 /**
index cfb296b..e7d6e1e 100644 (file)
@@ -214,6 +214,7 @@ restart_parse:
        
        // Find Mountpoint
        longestMount = gVFS_RootMount;
+       RWLock_AcquireRead( &glVFS_MountList );
        for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
        {
                // Quick Check
@@ -222,25 +223,29 @@ restart_parse:
                // Length Check - If the length is smaller than the longest match sofar
                if(mnt->MountPointLen < longestMount->MountPointLen)    continue;
                // String Compare
-               cmp = strcmp(Path, mnt->MountPoint);
+               cmp = strncmp(Path, mnt->MountPoint, mnt->MountPointLen);
+               // Not a match, continue
+               if(cmp != 0)    continue;
                
                #if OPEN_MOUNT_ROOT
                // Fast Break - Request Mount Root
-               if(cmp == 0) {
+               if(Path[mnt->MountPointLen] == '\0') {
                        if(TruePath) {
                                *TruePath = malloc( mnt->MountPointLen+1 );
                                strcpy(*TruePath, mnt->MountPoint);
                        }
                        if(MountPoint)
                                *MountPoint = mnt;
+                       RWLock_Release( &glVFS_MountList );
+                       LOG("Mount %p root", mnt);
                        LEAVE('p', mnt->RootNode);
                        return mnt->RootNode;
                }
                #endif
-               // Not a match, continue
-               if(cmp != '/')  continue;
                longestMount = mnt;
        }
+       longestMount->OpenHandleCount ++;       // Increment assuimg it worked
+       RWLock_Release( &glVFS_MountList );
        
        // Save to shorter variable
        mnt = longestMount;
@@ -333,6 +338,7 @@ restart_parse:
 
                        // EVIL: Goto :)
                        LOG("Symlink -> '%s', restart", Path);
+                       mnt->OpenHandleCount --;        // Not in this mountpoint
                        goto restart_parse;
                }
                
@@ -402,6 +408,8 @@ restart_parse:
                *MountPoint = mnt;
        }
        
+       // Leave the mointpoint's count increased
+       
        LEAVE('p', tmpNode);
        return tmpNode;
 
@@ -412,6 +420,9 @@ _error:
                free(*TruePath);
                *TruePath = NULL;
        }
+       // Open failed, so decrement the open handle count
+       mnt->OpenHandleCount --;
+       
        LEAVE('n');
        return NULL;
 }
@@ -485,7 +496,10 @@ int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode)
        {
                // TODO: Translate `Mode` into ACL and node flags
                // Get parent, create node
-               VFS_MkNod(absPath, 0);
+               if( VFS_MkNod(absPath, 0) ) {
+                       free(absPath);
+                       return -1;
+               }
                node = VFS_ParsePath(absPath, NULL, &mnt);
        }
        
@@ -568,6 +582,9 @@ int VFS_OpenChild(int FD, const char *Name, Uint Mode)
                LEAVE_RET('i', -1);
        }
 
+       // Increment open handle count, no problems with the mount going away as `h` is already open on it
+       h->Mount->OpenHandleCount ++;
+
        LEAVE_RET('x', VFS_int_CreateHandle(node, h->Mount, Mode));
 }
 
@@ -628,7 +645,9 @@ void VFS_Close(int FD)
        #endif
        
        _CloseNode(h->Node);
-       
+
+       h->Mount->OpenHandleCount --;   
+
        h->Node = NULL;
 }
 
index 6379a9d..f40689e 100644 (file)
@@ -15,7 +15,7 @@ extern tVFS_NodeType  gExt2_DirType;
 \r
 // === PROTOTYPES ===\r
  int   Ext2_Install(char **Arguments);\r
-void   Ext2_Cleanup(void);\r
+ int   Ext2_Cleanup(void);\r
 // - Interface Functions\r
 tVFS_Node      *Ext2_InitDevice(const char *Device, const char **Options);\r
 void           Ext2_Unmount(tVFS_Node *Node);\r
@@ -48,9 +48,9 @@ int Ext2_Install(char **Arguments)
 /**\r
  * \brief Clean up driver state before unload\r
  */\r
-void Ext2_Cleanup(void)\r
+int Ext2_Cleanup(void)\r
 {\r
-       \r
+       return 0;\r
 }\r
 \r
 /**\r
index dfa290b..cde4c72 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-OBJ = fat.o
+OBJ = fat.o dir.o fatio.o nodecache.o
 NAME = FAT
 
 -include ../Makefile.tpl
diff --git a/KernelLand/Modules/Filesystems/FAT/common.h b/KernelLand/Modules/Filesystems/FAT/common.h
new file mode 100644 (file)
index 0000000..79513a9
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Acess2 FAT Filesystem Driver
+ * - By John Hodge (thePowersGang)
+ * 
+ * common.h
+ * - FAT internal common header
+ */
+#ifndef _FS__FAT__COMMON_H_
+#define _FS__FAT__COMMON_H_
+
+#include "fs_fat.h"
+#include <vfs.h>
+
+#define CACHE_FAT      0       //!< Caches the FAT in memory
+#define USE_LFN                1       //!< Enables the use of Long File Names
+#define        SUPPORT_WRITE   1       //!< Enables write support
+
+#define FAT_FLAG_DIRTY 0x10000
+#define FAT_FLAG_DELETE        0x20000
+
+typedef struct sFAT_VolInfo tFAT_VolInfo;
+#if USE_LFN
+typedef struct sFAT_LFNCacheEnt        tFAT_LFNCacheEnt;
+typedef struct sFAT_LFNCache   tFAT_LFNCache;
+#endif
+typedef struct sFAT_CachedNode tFAT_CachedNode;
+
+/**
+ * \brief Internal IDs for FAT types
+ */
+enum eFatType
+{
+       FAT12,  //!< FAT12 Volume
+       FAT16,  //!< FAT16 Volume
+       FAT32,  //!< FAT32 Volume
+};
+
+// === TYPES ===
+struct sFAT_VolInfo
+{
+        int    fileHandle;     //!< File Handle
+       enum eFatType   type;   //!< FAT Variant
+       char    name[12];       //!< Volume Name (With NULL Terminator)
+       Uint32  firstDataSect;  //!< First data sector
+       Uint32  rootOffset;     //!< Root Offset (clusters)
+       Uint32  ClusterCount;   //!< Total Cluster Count
+       fat_bootsect    bootsect;       //!< Boot Sector
+       tVFS_Node       rootNode;       //!< Root Node
+        int    BytesPerCluster;
+       
+       tMutex  lNodeCache;
+       tFAT_CachedNode *NodeCache;
+       
+       tMutex  lFAT;           //!< Lock to prevent double-writing to the FAT
+       #if CACHE_FAT
+       Uint32  *FATCache;      //!< FAT Cache
+       #endif
+};
+
+#if USE_LFN
+/**
+ * \brief Long-Filename cache entry
+ */
+struct sFAT_LFNCacheEnt
+{
+        int    ID;
+       Uint16  Data[256];
+};
+/**
+ * \brief Long-Filename cache
+ */
+struct sFAT_LFNCache
+{
+        int    NumEntries;
+       tFAT_LFNCacheEnt        Entries[];
+};
+#endif
+
+struct sFAT_CachedNode
+{
+       struct sFAT_CachedNode  *Next;
+       tVFS_Node       Node;
+};
+
+// --- General Helpers ---
+extern int     FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster);
+extern tTime   FAT_int_GetAcessTimestamp(Uint16 Date, Uint16 Time, Uint8 MS);
+extern void    FAT_int_GetFATTimestamp(tTime AcessTimestamp, Uint16 *Date, Uint16 *Time, Uint8 *MS);
+
+// --- Node Caching ---
+// NOTE: FAT uses its own node cache that references by cluster (not the inode value that the Inode_* cache uses)
+//       because tVFS_Node.Inode contains the parent directory inode
+extern tVFS_Node       *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry);
+extern tVFS_Node       *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster);
+extern tVFS_Node       *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster);
+extern int     FAT_int_DerefNode(tVFS_Node *Node);
+extern void    FAT_int_ClearNodeCache(tFAT_VolInfo *Disk);
+
+// --- FAT Access ---
+extern Uint32  FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);
+#if SUPPORT_WRITE
+extern Uint32  FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);
+extern Uint32  FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster);
+#endif
+extern void    FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);
+extern void    FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, const void *Buffer);
+
+// --- Directory Access ---
+extern char    *FAT_ReadDir(tVFS_Node *Node, int ID);
+extern tVFS_Node       *FAT_FindDir(tVFS_Node *Node, const char *Name);
+extern tVFS_Node       *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
+extern int     FAT_int_GetEntryByCluster(tVFS_Node *DirNode, Uint32 Cluster, fat_filetable *Entry);
+#if SUPPORT_WRITE
+extern int     FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry);
+extern int     FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);
+extern int     FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *Node);
+extern int     FAT_Unlink(tVFS_Node *DirNode, const char *OldName);
+#endif
+extern void    FAT_CloseFile(tVFS_Node *node);
+
+// === GLOBALS ===
+extern tVFS_NodeType   gFAT_DirType;
+extern tVFS_NodeType   gFAT_FileType;
+
+#endif
+
diff --git a/KernelLand/Modules/Filesystems/FAT/dir.c b/KernelLand/Modules/Filesystems/FAT/dir.c
new file mode 100644 (file)
index 0000000..910b337
--- /dev/null
@@ -0,0 +1,1145 @@
+/*
+ * Acess2 FAT12/16/32 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * dir.c
+ * - Directory access/manipulation code
+ */
+#define DEBUG  1
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+
+// === PROTOTYPES ===
+void   FAT_int_ProperFilename(char *dest, const char *src);
+char   *FAT_int_CreateName(fat_filetable *ft, const Uint16 *LongFileName);
+ int   FAT_int_ConvertUTF16_to_UTF8(Uint8 *Dest, const Uint16 *Source);
+ int   FAT_int_ConvertUTF8_to_UTF16(Uint16 *Dest, const Uint8 *Source);
+
+ int   FAT_int_GetEntryByName(tVFS_Node *DirNode, const char *Name, fat_filetable *Entry);
+ int   FAT_int_GetEntryByCluster(tVFS_Node *DirNode, Uint32 Cluster, fat_filetable *Entry);
+ int   FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer);
+#if SUPPORT_WRITE
+ int   FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry);
+#endif
+#if USE_LFN
+Uint16 *FAT_int_GetLFN(tVFS_Node *Node, int ID);
+void   FAT_int_DelLFN(tVFS_Node *Node, int ID);
+#endif
+char   *FAT_ReadDir(tVFS_Node *Node, int ID);
+tVFS_Node      *FAT_FindDir(tVFS_Node *Node, const char *Name);
+tVFS_Node      *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
+#if SUPPORT_WRITE
+ int   FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int   FAT_int_IsValid83Filename(const char *Name);
+ int   FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *Node);
+ int   FAT_Relink(tVFS_Node *node, const char *OldName, const char *NewName);
+#endif
+
+// === CODE ===
+
+/**
+ * \brief Converts a FAT directory entry name into a proper filename
+ * \param dest Destination array (must be at least 13 bytes in size)
+ * \param src  8.3 filename (concatenated, e.g 'FILE1   TXT')
+ */
+void FAT_int_ProperFilename(char *dest, const char *src)
+{
+        int    inpos, outpos;
+       
+       // Name
+       outpos = 0;
+       for( inpos = 0; inpos < 8; inpos++ ) {
+               if(src[inpos] == ' ')   break;
+               dest[outpos++] = src[inpos];
+       }
+       inpos = 8;
+       // Check for empty extensions
+       if(src[8] != ' ')
+       {
+               dest[outpos++] = '.';
+               for( ; inpos < 11; inpos++)     {
+                       if(src[inpos] == ' ')   break;
+                       dest[outpos++] = src[inpos];
+               }
+       }
+       dest[outpos++] = '\0';
+       
+       //LOG("dest='%s'", dest);
+}
+
+/**
+ * \fn char *FAT_int_CreateName(fat_filetable *ft, Uint8 *LongFileName)
+ * \brief Converts either a LFN or a 8.3 Name into a proper name
+ * \param ft   Pointer to the file's entry in the parent directory
+ * \param LongFileName Long file name pointer
+ * \return Filename as a heap string
+ */
+char *FAT_int_CreateName(fat_filetable *ft, const Uint16 *LongFileName)
+{
+       char    *ret;
+       ENTER("pft sLongFileName", ft, LongFileName);
+       //Log_Debug("FAT", "FAT_int_CreateName(ft=%p, LongFileName=%p'%s')", ft, LongFileName);
+       #if USE_LFN
+       if(LongFileName && LongFileName[0] != 0)
+       {
+                int    len = FAT_int_ConvertUTF16_to_UTF8(NULL, LongFileName);
+               ret = malloc( len + 1 );
+               FAT_int_ConvertUTF16_to_UTF8((Uint8*)ret, LongFileName);
+       }
+       else
+       {
+       #endif
+               ret = (char*) malloc(13);
+               if( !ret ) {
+                       Log_Warning("FAT", "FAT_int_CreateName: malloc(13) failed");
+                       return NULL;
+               }
+               FAT_int_ProperFilename(ret, ft->name);
+       #if USE_LFN
+       }
+       #endif
+       LEAVE('s', ret);
+       return ret;
+}
+
+#if USE_LFN
+int FAT_int_CompareUTF16_UTF8(const Uint16 *Str16, const char *Str8)
+{
+        int    pos16 = 0, pos8 = 0;
+       const Uint8     *str8 = (const Uint8 *)Str8;
+       
+       while( Str16[pos16] && str8[pos8] )
+       {
+               Uint32  cp8, cp16;
+               if( Str16[pos16] & 0x8000 ) {
+                       // Do something!
+                       cp16 = 0;
+               }
+               else {
+                       cp16 = Str16[pos16];
+                       pos16 ++;
+               }
+               pos8 += ReadUTF8(str8 + pos8, &cp8);
+       
+               if(cp16 == cp8) continue ;
+               
+               if(cp16 < cp8)
+                       return -1;
+               else
+                       return 1;
+       }
+       if(Str16[pos16] == str8[pos8])
+               return 0;
+       if(Str16[pos16] < str8[pos8])
+               return -1;
+       else
+               return 1;
+}
+
+int FAT_int_ConvertUTF16_to_UTF8(Uint8 *Dest, const Uint16 *Source)
+{
+        int    len = 0;
+       for( ; *Source; Source ++ )
+       {
+               // TODO: Decode/Reencode
+               if( Dest )
+                       Dest[len] = *Source;
+               len += 1;
+       }
+       if( Dest )
+               Dest[len] = 0;
+       return len;
+}
+
+int FAT_int_ConvertUTF8_to_UTF16(Uint16 *Dest, const Uint8 *Source)
+{
+        int    len = 0;
+       while( *Source )
+       {
+               Uint32  cp;
+               int cpl;
+               
+               cpl = ReadUTF8(Source, &cp);
+               if(cp < 0x8000) {
+                       if( Dest )
+                               Dest[len] = cp;
+                       len ++;
+               }
+               else {
+                       // TODO!
+               }
+               Source += cpl;
+       }
+       Dest[len] = 0;
+       return len;
+}
+
+int FAT_int_ParseLFN(const fat_filetable *Entry, Uint16 *Buffer)
+{
+       const fat_longfilename  *lfnInfo;
+        int    ofs;
+       
+       lfnInfo = (const void*)Entry;
+       
+       if(lfnInfo->id & 0x40) {
+               memset(Buffer, 0, 256*2);
+       }
+       ofs = (lfnInfo->id & 0x3F) * 13 - 1;
+       if( ofs >= 255 )
+               return -1;
+       
+       Buffer[ofs--] = lfnInfo->name3[1];      Buffer[ofs--] = lfnInfo->name3[0];
+       Buffer[ofs--] = lfnInfo->name2[5];      Buffer[ofs--] = lfnInfo->name2[4];
+       Buffer[ofs--] = lfnInfo->name2[3];      Buffer[ofs--] = lfnInfo->name2[2];
+       Buffer[ofs--] = lfnInfo->name2[1];      Buffer[ofs--] = lfnInfo->name2[0];
+       Buffer[ofs--] = lfnInfo->name1[4];      Buffer[ofs--] = lfnInfo->name1[3];
+       Buffer[ofs--] = lfnInfo->name1[2];      Buffer[ofs--] = lfnInfo->name1[1];
+       Buffer[ofs--] = lfnInfo->name1[0];
+       
+       if((lfnInfo->id&0x3F) == 1)
+               return 1;
+       return 0;
+}
+#endif
+
+int FAT_int_GetEntryByName(tVFS_Node *DirNode, const char *Name, fat_filetable *Entry)
+{
+       fat_filetable   fileinfo[16];
+       char    tmpName[13];
+       #if USE_LFN
+       Uint16  lfn[256];
+        int    lfnId = -1;
+       #endif
+
+       ENTER("pDirNode sName pEntry", DirNode, Name, Entry);
+
+       for( int i = 0; ; i++ )
+       {
+               if((i & 0xF) == 0) {
+                       if(FAT_int_ReadDirSector(DirNode, i/16, fileinfo))
+                       {
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+               }
+               
+               //Check if the files are free
+               if(fileinfo[i&0xF].name[0] == '\0')     break;  // End of List marker
+               if(fileinfo[i&0xF].name[0] == '\xE5')   continue;       // Free entry
+               
+               
+               #if USE_LFN
+               // Long File Name Entry
+               if(fileinfo[i & 0xF].attrib == ATTR_LFN)
+               {
+                       if( FAT_int_ParseLFN(&fileinfo[i&0xF], lfn) )
+                               lfnId = i+1;
+                       continue ;
+               }
+               // Remove LFN if it does not apply
+               if(lfnId != i)  lfn[0] = 0;
+               #else
+               if(fileinfo[i&0xF].attrib == ATTR_LFN)  continue;
+               #endif
+
+               // Get Real Filename
+               FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);
+//             LOG("tmpName = '%s'", tmpName);
+//             #if DEBUG
+//             Debug_HexDump("FAT tmpName", tmpName, strlen(tmpName));
+//             #endif
+/*
+               #if DEBUG && USE_LFN
+               if(lfnId == i)
+               {
+                       Uint8 lfntmp[256*3+1];
+                       FAT_int_ConvertUTF16_to_UTF8(lfntmp, lfn);
+                       LOG("lfntmp = '%s'", lfntmp);
+               }
+               #endif
+*/
+       
+               // Only the long name is case sensitive, 8.3 is not
+               #if USE_LFN
+               if(strucmp(tmpName, Name) == 0 || FAT_int_CompareUTF16_UTF8(lfn, Name) == 0)
+               #else
+               if(strucmp(tmpName, Name) == 0)
+               #endif
+               {
+                       memcpy(Entry, fileinfo + (i&0xF), sizeof(*Entry));
+                       LOG("Found %s at %i", Name, i);
+                       LEAVE('i', i);
+                       return i;
+               }
+       }
+       
+       LEAVE('i', -1);
+       return -1;
+}
+
+int FAT_int_GetEntryByCluster(tVFS_Node *DirNode, Uint32 Cluster, fat_filetable *Entry)
+{
+        int    ents_per_sector = 512 / sizeof(fat_filetable); 
+       fat_filetable   fileinfo[ents_per_sector];
+        int    i, sector;
+
+       Mutex_Acquire(&DirNode->Lock);
+       sector = 0;
+       for( i = 0; ; i ++ )
+       {
+               if( i == 0 || i == ents_per_sector )
+               {
+                       if(FAT_int_ReadDirSector(DirNode, sector, fileinfo))
+                       {
+                               LOG("ReadDirSector failed");
+                               break ;
+                       }
+                       i = 0;
+                       sector ++;
+               }
+       
+               // Check for free/end of list
+               if(fileinfo[i].name[0] == '\0') break;  // End of List marker
+               if(fileinfo[i].name[0] == '\xE5')       continue;       // Free entry
+               
+               if(fileinfo[i].attrib == ATTR_LFN)      continue;
+
+               LOG("fileinfo[i].cluster = %x:%04x", fileinfo[i].clusterHi, fileinfo[i].cluster);
+               #if DEBUG
+               {
+                       char    tmpName[13];
+                       FAT_int_ProperFilename(tmpName, fileinfo[i].name);
+                       LOG("tmpName = '%s'", tmpName);
+               }
+               #endif
+               
+       
+               if(fileinfo[i].cluster != (Cluster & 0xFFFF))   continue;
+               if(fileinfo[i].clusterHi != ((Cluster >> 16) & 0xFFFF)) continue;
+       
+               memcpy(Entry, &fileinfo[i], sizeof(*Entry));
+               Mutex_Release(&DirNode->Lock);
+               return i;
+       }
+       
+       Mutex_Release(&DirNode->Lock);
+       return -1;
+}
+
+/* 
+ * ====================
+ *     Directory IO
+ * ====================
+ */
+
+/**
+ * \brief Reads a sector from the disk
+ * \param Node Directory node to read
+ * \param Sector       Sector number in the directory to read
+ * \param Buffer       Destination buffer for the read data
+ */
+int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)
+{
+       Uint64  addr;
+       tFAT_VolInfo    *disk = Node->ImplPtr;
+       
+       ENTER("pNode iSector pEntry", Node, Sector, Buffer);
+       
+       // Parse address
+       if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))
+       {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       LOG("addr = 0x%llx", addr);
+       // Read Sector
+       if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512)
+       {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       LEAVE('i', 0);
+       return 0;
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Write a sector to the disk
+ * \param Node Directory node to write
+ * \param Sector       Sector number in the directory to write
+ * \param Buffer       Source data
+ */
+int FAT_int_WriteDirSector(tVFS_Node *Node, int Sector, const fat_filetable *Buffer)
+{
+       Uint64  addr;
+       tFAT_VolInfo    *disk = Node->ImplPtr;
+       
+       ENTER("pNode iSector pEntry", Node, Sector, Buffer);
+       
+       // Parse address
+       if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))
+       {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       // Read Sector
+       if(VFS_WriteAt(disk->fileHandle, addr, 512, Buffer) != 512)
+       {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \brief Writes an entry to the disk
+ * \todo Support expanding a directory
+ * \param Node Directory node
+ * \param ID   ID of entry to update
+ * \param Entry        Entry data
+ * \return Zero on success, non-zero on error
+ */
+int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)
+{
+       Uint64  addr = 0;
+        int    tmp;
+       Uint32  cluster = 0;
+       tFAT_VolInfo    *disk = Node->ImplPtr;
+       
+       ENTER("pNode iID pEntry", Node, ID, Entry);
+       
+       tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);
+       if( tmp )
+       {
+               //TODO: Allocate a cluster
+               cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);
+               if(cluster == -1) {
+                       Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);
+                       LEAVE('i', 1);
+                       return 1;
+               }
+               FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);
+       }
+       
+
+       LOG("addr = 0x%llx", addr);
+       
+       // Wriet data to disk
+       VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry);
+       
+       LEAVE('i', 0);
+       return 0;
+}
+#endif
+
+#if USE_LFN    
+/**
+ * \fn Uint16 *FAT_int_GetLFN(tVFS_Node *node)
+ * \brief Return pointer to LFN cache entry
+ * \param Node Directory node
+ * \param ID   ID of the short name
+ * \return Pointer to the LFN cache entry
+ */
+Uint16 *FAT_int_GetLFN(tVFS_Node *Node, int ID)
+{
+       tFAT_LFNCache   *cache;
+        int    i, firstFree;
+       
+       Mutex_Acquire( &Node->Lock );
+       
+       // TODO: Thread Safety (Lock things)
+       cache = Node->Data;
+       
+       // Create a cache if it isn't there
+       if(!cache) {
+               cache = Node->Data = malloc( sizeof(tFAT_LFNCache) + sizeof(tFAT_LFNCacheEnt) );
+               cache->NumEntries = 1;
+               cache->Entries[0].ID = ID;
+               cache->Entries[0].Data[0] = 0;
+               Mutex_Release( &Node->Lock );
+               //Log_Debug("FAT", "Return = %p (new)", cache->Entries[0].Data);
+               return cache->Entries[0].Data;
+       }
+       
+       // Scan for this entry
+       firstFree = -1;
+       for( i = 0; i < cache->NumEntries; i++ )
+       {
+               if( cache->Entries[i].ID == ID ) {
+                       Mutex_Release( &Node->Lock );
+                       //Log_Debug("FAT", "Return = %p (match)", cache->Entries[i].Data);
+                       return cache->Entries[i].Data;
+               }
+               if( cache->Entries[i].ID == -1 && firstFree == -1 )
+                       firstFree = i;
+       }
+       
+       if(firstFree == -1) {
+               // Use `i` for temp length
+               i = sizeof(tFAT_LFNCache) + (cache->NumEntries+1)*sizeof(tFAT_LFNCacheEnt);
+               Node->Data = realloc( Node->Data, i );
+               if( !Node->Data ) {
+                       Log_Error("FAT", "realloc() fail, unable to allocate %i for LFN cache", i);
+                       Mutex_Release( &Node->Lock );
+                       return NULL;
+               }
+               //Log_Debug("FAT", "Realloc (%i)\n", i);
+               cache = Node->Data;
+               i = cache->NumEntries;
+               cache->NumEntries ++;
+       }
+       else {
+               i = firstFree;
+       }
+       
+       // Create new entry
+       cache->Entries[ i ].ID = ID;
+       cache->Entries[ i ].Data[0] = '\0';
+       
+       Mutex_Release( &Node->Lock );
+       //Log_Debug("FAT", "Return = %p (firstFree, i = %i)", cache->Entries[i].Data, i);
+       return cache->Entries[ i ].Data;
+}
+
+/**
+ * \fn void FAT_int_DelLFN(tVFS_Node *node)
+ * \brief Delete a LFN cache entry
+ * \param Node Directory node
+ * \param ID   File Entry ID
+ */
+void FAT_int_DelLFN(tVFS_Node *Node, int ID)
+{
+       tFAT_LFNCache   *cache = Node->Data;
+        int    i;
+       
+       // Fast return
+       if(!cache)      return;
+       
+       // Scan for a current entry
+       for( i = 0; i < cache->NumEntries; i++ )
+       {
+               if( cache->Entries[i].ID == ID )
+                       cache->Entries[i].ID = -1;
+       }
+       return ;
+}
+#endif
+
+/**
+ * \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)
+ * \param Node Node structure of directory
+ * \param ID   Directory position
+ * \return Filename as a heap string, NULL or VFS_SKIP
+ */
+char *FAT_ReadDir(tVFS_Node *Node, int ID)
+{
+       fat_filetable   fileinfo[16];   // sizeof(fat_filetable)=32, so 16 per sector
+        int    a;
+       char    *ret;
+       #if USE_LFN
+       Uint16  *lfn = NULL;
+       #endif
+       
+       ENTER("pNode iID", Node, ID);
+       
+       if(FAT_int_ReadDirSector(Node, ID/16, fileinfo))
+       {
+               LOG("End of chain, end of dir");
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Offset in sector
+       a = ID % 16;
+
+       LOG("fileinfo[%i].name[0] = 0x%x", a, (Uint8)fileinfo[a].name[0]);
+       
+       // Check if this is the last entry
+       if( fileinfo[a].name[0] == '\0' ) {
+               Node->Size = ID;
+               LOG("End of list");
+               LEAVE('n');
+               return NULL;    // break
+       }
+       
+       // Check for empty entry
+       if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {
+               LOG("Empty Entry");
+               #if 0   // Stop on empty entry?
+               LEAVE('n');
+               return NULL;    // Stop
+               #else
+               LEAVE('p', VFS_SKIP);
+               return VFS_SKIP;        // Skip
+               #endif
+       }
+       
+       #if USE_LFN
+       // Get Long File Name Cache
+       if(fileinfo[a].attrib == ATTR_LFN)
+       {
+               fat_longfilename        *lfnInfo;
+               
+               lfnInfo = (fat_longfilename *) &fileinfo[a];
+               
+               // Get cache for corresponding file
+               // > ID + Index gets the corresponding short node
+               lfn = FAT_int_GetLFN( Node, ID + (lfnInfo->id & 0x3F) );
+
+               a = FAT_int_ParseLFN(&fileinfo[a], lfn);
+               if( a < 0 ) {
+                       LOG("Invalid LFN, error");
+                       LEAVE('n');
+                       return NULL;
+               }
+
+//             LOG("lfn = '%s'", lfn);
+               //Log_Debug("FAT", "lfn = '%s'", lfn);
+               LEAVE('p', VFS_SKIP);
+               return VFS_SKIP;
+       }
+       #endif
+       
+       // Check if it is a volume entry
+       if(fileinfo[a].attrib & 0x08) {
+               LEAVE('p', VFS_SKIP);
+               return VFS_SKIP;
+       }
+       // Ignore .
+       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == ' ') {
+               LEAVE('p', VFS_SKIP);
+               return VFS_SKIP;
+       }
+       // and ..
+       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == '.' && fileinfo[a].name[2] == ' ') {
+               LEAVE('p', VFS_SKIP);
+               return VFS_SKIP;
+       }
+       
+       LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'",
+               fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],
+               fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],
+               fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );
+       
+       #if USE_LFN
+       lfn = FAT_int_GetLFN(Node, ID);
+       //Log_Debug("FAT", "lfn = %p'%s'", lfn, lfn);
+       ret = FAT_int_CreateName(&fileinfo[a], lfn);
+       #else
+       ret = FAT_int_CreateName(&fileinfo[a], NULL);
+       #endif
+       
+       LEAVE('s', ret);
+       return ret;
+}
+
+/**
+ * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)
+ * \brief Finds an entry in the current directory
+ */
+tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name)
+{
+       fat_filetable   fileent;
+       
+       ENTER("pNode sname", Node, Name);       
+
+       // Fast Returns
+       if(!Name || Name[0] == '\0') {
+               LEAVE('n');
+               return NULL;
+       }
+
+       if( FAT_int_GetEntryByName(Node, Name, &fileent) == -1 ) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+
+       tVFS_Node *ret = FAT_int_CreateNode(Node, &fileent);
+       LOG("Found %s as %p", Name, ret);
+       LEAVE('p', ret);
+       return ret;
+}
+
+tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)
+{
+       tFAT_VolInfo    *disk = Root->ImplPtr;
+       tVFS_Node       *dirnode, *ret;
+       fat_filetable   ft;
+
+       ENTER("pRoot XInode", Root, Inode);
+
+       ret = FAT_int_GetNode(disk, Inode & 0xFFFFFFFF);
+       if( ret ) {
+               if( (ret->Inode >> 32) != 0 ) {
+                       LOG("Node in cache, quick return");
+                       return ret;
+               }
+               else {
+                       LOG("Node cached, but incomplete");
+                       // Fall on through
+               }
+               ret = NULL;
+       }
+       
+       dirnode = FAT_int_CreateIncompleteDirNode(disk, Inode >> 32);
+
+       int id = FAT_int_GetEntryByCluster(dirnode, Inode & 0xFFFFFFFF, &ft);
+       if( id != -1 ) {
+               ret = FAT_int_CreateNode(dirnode, &ft);
+       }
+
+       dirnode->Type->Close(dirnode);
+
+       LEAVE('p', ret);
+       return ret;
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Create a new node
+ */
+int FAT_Mknod(tVFS_Node *DirNode, const char *Name, Uint Flags)
+{
+       tFAT_VolInfo    *disk = DirNode->ImplPtr;
+        int    rv;
+       fat_filetable   ft;
+       memset(&ft, 0, sizeof(ft));
+
+       ENTER("pDirNode sName xFlags", DirNode, Name, Flags);
+       
+       // Allocate a cluster
+       Uint32 cluster = FAT_int_AllocateCluster(disk, -1);
+       LOG("Cluster 0x%07x allocated", cluster);
+       
+       // Create a temporary file table entry for an empty node
+       ft.cluster = cluster & 0xFFFF;
+       ft.clusterHi = cluster >> 16;
+       ft.size = 0;
+       if( Flags & VFS_FFLAG_DIRECTORY )
+               ft.attrib = ATTR_DIRECTORY;
+       else
+               ft.attrib = 0;
+       
+       tVFS_Node *newnode = FAT_int_CreateNode(DirNode, &ft);
+       if( !newnode ) {
+               return -1;
+       }
+       LOG("newnode = %p", newnode);
+
+       // Call link
+       if( (rv = FAT_Link(DirNode, Name, newnode)) ) {
+               newnode->ImplInt |= FAT_FLAG_DELETE;
+       }
+       FAT_CloseFile(newnode);
+       LEAVE('i', rv);
+       return rv;
+}
+
+/**
+ * \brief Internal - Checks if a character is valid in an 8.3 filename
+ */
+static inline int is_valid_83_char(char ch)
+{
+       if( '0' <= ch && ch <= '9' )
+               return 1;
+       if( 'A' <= ch && ch <= 'Z' )
+               return 1;
+       if( 'a' <= ch && ch <= 'z' )
+               return 1;
+       if( strchr("$%'-_@~`#!(){}^#&", ch) )
+               return 1;
+       if( ch > 128 )
+               return 1;
+       return 0;
+}
+
+Uint8 FAT_int_UnicodeTo83(Uint32 Input)
+{
+       Input = toupper(Input);
+       // Input = unicode_to_oem(Input);
+       if( Input > 256 )
+               Input = '_';
+       if(!is_valid_83_char(Input))
+               Input = '_';
+       return Input;
+}
+
+/**
+ * \brief Internal - Determines if a filename is a valid 8.3 filename
+ */
+int FAT_int_IsValid83Filename(const char *Name)
+{
+        int    i, j;
+
+       if( !Name[0] || Name[0] == '.' )
+               return 0;
+
+       // Check filename portion
+       for( i = 0; Name[i] && i < 8; i ++ )
+       {
+               if( Name[i] == '.' )
+                       break;
+               if( !is_valid_83_char(Name[i]) )
+                       return 0;
+       }
+       // If the next char is not \0 or '.', it's not valid
+       if( Name[i] && Name[i++] != '.' )
+               return 0;
+       
+       // Check the extension portion
+       for( j = 0; Name[i+j] && j < 3; j ++ )
+       {
+               if( !is_valid_83_char(Name[i+j]) )
+                       return 0;
+       }
+       
+       // After the extension must be the end
+       if( Name[i+j] )
+               return 0;
+       
+       return 1;
+}
+
+Uint8 FAT_int_MakeLFNChecksum(const char *ShortName)
+{
+       Uint8 ret = 0;
+       for( int i = 0; i < 11; i++ )
+       {
+               // ret = (ret >>> 1) + ShortName[i]
+               // where >>> is rotate right
+               ret = ((ret & 1) ? 0x80 : 0x00) + (ret >> 1) + ShortName[i];
+       }
+       return ret;
+}
+
+/**
+ * \brief Create a new name for a file
+ * \note Since FAT doesn't support reference counting, this will cause double-references if
+ *       a file is hardlinked and not unlinked
+ */
+int FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *NewNode)
+{
+       Uint16  lfn[256];
+       fat_filetable   ft;
+        int    nLFNEnt = 0;
+       const int eps = 512 / sizeof(fat_filetable);
+       fat_filetable   fileinfo[eps];
+       
+       Mutex_Acquire( &DirNode->Lock );
+
+       // -- Ensure duplicates aren't created --
+       if( FAT_int_GetEntryByName(DirNode, NewName, &ft) >= 0 ) {
+               Mutex_Release( &DirNode->Lock );
+               return EEXIST;
+       }
+       
+       // -- Create filetable entry --
+       #if 0
+       {
+                int    bDirty = 0;
+                int    inofs = 0;
+               while( NewName[inofs] && NewName[inofs] == '.' )
+                       inofs ++, bDirty = 1;
+               for( int i = 0; i < 8 && NewName[inofs] && NewName[inofs] != '.'; i ++ )
+               {
+                       Uint32  cp;
+                       inofs += ReadUTF8(NewName + inofs, &cp);
+                       // Spaces are silently skipped
+                       if(isspace(cp)) {
+                               i --, bDirty = 1;
+                               continue ;
+                       }
+                       ft.name[i] = FAT_int_UnicodeTo83(cp);
+                       if(ft.name[i] != cp)
+                               bDirty = 1;
+               }
+               while( NewName[inofs] && NewName[inofs] != '.' )
+                       inofs ++, bDirty = 1;
+               for( ; i < 8+3 && NewName[inofs]; i ++ )
+               {
+                       Uint32  cp;
+                       inofs += ReadUTF8(NewName + inofs, &cp);
+                       // Spaces are silently skipped
+                       if(isspace(cp)) {
+                               i --, bDirty = 1;
+                               continue ;
+                       }
+                       ft.name[i] = FAT_int_UnicodeTo83(cp);
+                       if(ft.name[i] != cp)
+                               bDirty = 1;
+               }
+               if( !NewName[inofs] )   bDirty = 1;
+               
+               if( bDirty )
+               {
+                       int lfnlen = FAT_int_ConvertUTF8_to_UTF16(lfn, (const Uint8*)NewName);
+                       lfn[lfnlen] = 0;
+                       nLFNEnt = DivUp(lfnlen, 13);
+               }
+       }
+       #endif
+        int    bNeedsLFN = !FAT_int_IsValid83Filename(NewName);
+       if( bNeedsLFN )
+       {
+               int lfnlen = FAT_int_ConvertUTF8_to_UTF16(lfn, (const Uint8*)NewName);
+               lfn[lfnlen] = 0;
+               nLFNEnt = DivUp(lfnlen, 13);
+       
+               // Create a base mangled filetable entry
+               int i, j = 0;
+               while(NewName[j] == '.')        j ++;   // Eat leading dots
+               for( i = 0; i < 6 && NewName[j] && NewName[j] != '.'; i ++, j ++ )
+               {
+                       if( !isalpha(NewName[j]) && !is_valid_83_char(NewName[j]) )
+                               ft.name[i] = '_';
+                       else
+                               ft.name[i] = toupper(NewName[j]);
+               }
+               ft.name[i++] = '~';
+               ft.name[i++] = '1';
+               while(i < 8)    ft.name[i++] = ' ';
+               while(NewName[j] && NewName[j] != '.')  j ++;
+               for( ; i < 8+3 && NewName[j]; i ++, j ++ )
+               {
+                       if( NewName[j] == '.' )
+                               i --;
+                       else if( !is_valid_83_char(NewName[j]) )
+                               ft.name[i] = '_';
+                       else
+                               ft.name[i] = toupper(NewName[j]);
+               }
+               while(i < 8+3)  ft.name[i++] = ' ';
+               
+               // - Ensure there isn't a duplicate short-name
+                int    bIsDuplicate = 1;
+               while( bIsDuplicate )
+               {
+                       bIsDuplicate = 0;       // Assume none                  
+
+                       // Scan directory
+                       for( int id = 0; ; id ++ )
+                       {
+                               if( id % eps == 0 )
+                               {
+                                       if(FAT_int_ReadDirSector(DirNode, id/eps, fileinfo))
+                                               break;  // end of cluster chain
+                               }
+                               
+                               // End of file list
+                               if( fileinfo[id%eps].name[0] == '\0' )  break;
+                               // Empty entry
+                               if( fileinfo[id%eps].name[0] == '\xE5' )        continue;
+                               // LFN entry
+                               if( fileinfo[id%eps].attrib == ATTR_LFN )       continue;
+                               
+                               // Is this a duplicate?
+                               if( memcmp(ft.name, fileinfo[id%eps].name, 8+3) == 0 ) {
+                                       bIsDuplicate = 1;
+                                       break;
+                               }
+                               
+                               // No - move a long
+                       }
+                       
+                       // If a duplicate was found, increment the suffix
+                       if( bIsDuplicate )
+                       {
+                               if( ft.name[7] == '9' ) {
+                                       // TODO: Expand into ~00
+                                       Log_Error("FAT", "TODO: Use two digit LFN suffixes");
+                                       Mutex_Release(&DirNode->Lock);
+                                       return ENOTIMPL;
+                               }
+                               
+                               ft.name[7] += 1;
+                       }
+               }
+       }
+       else
+       {
+               // Create pure filetable entry
+                int    i;
+               // - Copy filename
+               for( i = 0; i < 8 && *NewName && *NewName != '.'; i ++, NewName++ )
+                       ft.name[i] = *NewName;
+               // - Pad with spaces
+               for( ; i < 8; i ++ )
+                       ft.name[i] = ' ';
+               // - Eat '.'
+               if(*NewName)
+                       NewName ++;
+               // - Copy extension
+               for( ; i < 8+3 && *NewName; i ++, NewName++ )
+                       ft.name[i] = *NewName;
+               // - Pad with spaces
+               for( ; i < 8+3; i ++ )
+                       ft.name[i] = ' ';
+       }
+
+       ft.attrib = 0;
+       if(NewNode->Flags & VFS_FFLAG_DIRECTORY )
+               ft.attrib |= ATTR_DIRECTORY;    
+       ft.ntres     = 0;
+       FAT_int_GetFATTimestamp(NewNode->CTime, &ft.cdate, &ft.ctime, &ft.ctimems);
+//     ft.ctimems   = ft.ctimems;
+       ft.ctime     = LittleEndian16(ft.ctime);
+       ft.cdate     = LittleEndian16(ft.cdate);
+       FAT_int_GetFATTimestamp(NewNode->MTime, &ft.mdate, &ft.mtime, NULL);
+       ft.mtime     = LittleEndian16(ft.mtime);
+       ft.mdate     = LittleEndian16(ft.mdate);
+       FAT_int_GetFATTimestamp(NewNode->ATime, &ft.adate, NULL, NULL);
+       ft.adate     = LittleEndian16(ft.adate);
+       ft.clusterHi = LittleEndian16((NewNode->Inode >> 16) & 0xFFFF);
+       ft.cluster   = LittleEndian16(NewNode->Inode & 0xFFFF);
+       ft.size      = LittleEndian32(NewNode->Size);
+
+       LOG("ft.name = '%.11s'", ft.name);
+
+       // -- Add entry to the directory --
+       // Locate a range of nLFNEnt + 1 free entries
+        int    end_id = -1;
+        int    range_first = 0, range_last = -1;
+       for( int id = 0; ; id ++ )
+       {
+               if( id % eps == 0 )
+               {
+                       if(FAT_int_ReadDirSector(DirNode, id/eps, fileinfo))
+                               break;  // end of cluster chain
+               }
+               
+               // End of file list, break out
+               if( fileinfo[id%eps].name[0] == '\0' ) {
+                       if( id - range_first == nLFNEnt )
+                               range_last = id;
+                       end_id = id;
+                       break;
+               }
+               
+               // If an entry is occupied, clear the range
+               if( fileinfo[id%eps].name[0] != '\xE5' ) {
+                       range_first = id + 1;
+                       continue ;
+               }
+               
+               // Free entry, check if we have enough
+               if( id - range_first == nLFNEnt ) {
+                       range_last = id;
+                       break;
+               }
+               // Check the next one
+       }
+       if( range_last == -1 )
+       {
+               // - If there are none, defragment the directory?
+               
+               // - Else, expand the directory
+               if( end_id == -1 ) {
+                       // End of cluster chain
+               }
+               else {
+                       // Just end of block
+               }
+               // - and if that fails, return an error
+               Log_Warning("FAT", "TODO: Impliment directory expansion / defragmenting");
+               Mutex_Release(&DirNode->Lock);
+               return ENOTIMPL;
+       }
+
+       // Calculate the checksum used for LFN
+       Uint8   lfn_checksum = 0;
+       if( nLFNEnt )
+       {
+               lfn_checksum = FAT_int_MakeLFNChecksum(ft.name);
+       }
+
+       // Insert entries       
+       if( range_first % eps != 0 )
+               FAT_int_ReadDirSector(DirNode, range_first/eps, fileinfo);
+       for( int id = range_first; id <= range_last; id ++ )
+       {
+               if( id % eps == 0 ) {
+                       if( id != range_first )
+                               FAT_int_WriteDirSector(DirNode, (id-1)/eps, fileinfo);
+                       FAT_int_ReadDirSector(DirNode, id/eps, fileinfo);
+               }
+               
+               if( id == range_last ) {
+                       // Actual entry
+                       memcpy(fileinfo + id % eps, &ft, sizeof(fat_filetable));
+               }
+               else {
+                       // Long filename
+                       int lfnid = (nLFNEnt - (id - range_first));
+                       int ofs = (lfnid-1) * 13;
+                        int    i=0, j=0;
+                       fat_longfilename *lfnent = (void*)( fileinfo + id%eps );
+                       
+                       lfnent->id = 0x40 | lfnid;
+                       lfnent->attrib = ATTR_LFN;
+                       lfnent->type = 0;
+                       lfnent->firstCluster = 0;
+                       lfnent->checksum = lfn_checksum;        // ???
+
+                       for( i = 0; i < 13; i ++ )
+                       {
+                               Uint16  wd;
+                               if( (wd = lfn[ofs+j]) ) j ++;
+                               wd = LittleEndian16(wd);
+                               if(i < 5)
+                                       lfnent->name1[i    ] = wd;
+                               else if( i < 5+6 )
+                                       lfnent->name2[i-5  ] = wd;
+                               else
+                                       lfnent->name3[i-5-6] = wd;
+                       }
+               }
+       }
+       FAT_int_WriteDirSector(DirNode, range_last/eps, fileinfo);
+
+       Mutex_Release( &DirNode->Lock );
+       return 0;
+}
+
+/**
+ * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)
+ * \brief Rename / Delete a file
+ */
+int FAT_Unlink(tVFS_Node *Node, const char *OldName)
+{
+       tVFS_Node       *child;
+       fat_filetable   ft;
+       
+       Mutex_Acquire(&Node->Lock);
+
+       int id = FAT_int_GetEntryByName(Node, OldName, &ft);
+       if(id == -1) {
+               Mutex_Release(&Node->Lock);
+               return ENOTFOUND;
+       }
+
+       child = FAT_int_CreateNode(Node->ImplPtr, &ft);
+       if( !child ) {
+               Mutex_Release(&Node->Lock);
+               return EINVAL;
+       }
+       child->ImplInt |= FAT_FLAG_DELETE;      // Mark for deletion on close
+
+       // TODO: If it has a LFN, remove that too
+
+       // Delete from the directory
+       ft.name[0] = '\xE5';
+       FAT_int_WriteDirEntry(Node, id, &ft);
+
+       // Close child
+       child->Type->Close( child );
+       Mutex_Release( &Node->Lock );
+       return EOK;
+}
+#endif
index c69a063..d602510 100644 (file)
  * \todo Implement changing of the parent directory when a file is written to\r
  * \todo Implement file creation / deletion\r
  */\r
-#define DEBUG  0\r
+#define DEBUG  1\r
 #define VERBOSE        1\r
 \r
-#define CACHE_FAT      0       //!< Caches the FAT in memory\r
-#define USE_LFN                1       //!< Enables the use of Long File Names\r
-#define        SUPPORT_WRITE   0       //!< Enables write support\r
-\r
 #include <acess.h>\r
 #include <modules.h>\r
-#include <vfs.h>\r
-#include "fs_fat.h"\r
-\r
-#define FAT_FLAG_DIRTY 0x10000\r
-#define FAT_FLAG_DELETE        0x20000\r
-\r
-// === TYPES ===\r
-#if USE_LFN\r
-/**\r
- * \brief Long-Filename cache entry\r
- */\r
-typedef struct sFAT_LFNCacheEnt\r
-{\r
-        int    ID;\r
-       // TODO: Handle UTF16 names correctly\r
-       char    Data[256];\r
-}      tFAT_LFNCacheEnt;\r
-/**\r
- * \brief Long-Filename cache\r
- */\r
-typedef struct sFAT_LFNCache\r
-{\r
-        int    NumEntries;\r
-       tFAT_LFNCacheEnt        Entries[];\r
-}      tFAT_LFNCache;\r
-#endif\r
+#include "common.h"\r
 \r
 // === PROTOTYPES ===\r
 // --- Driver Core\r
@@ -60,33 +31,19 @@ tVFS_Node   *FAT_InitDevice(const char *device, const char **options);
 void   FAT_Unmount(tVFS_Node *Node);\r
 // --- Helpers\r
  int   FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster);\r
-Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);\r
-#if SUPPORT_WRITE\r
-Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);\r
-Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster);\r
-#endif\r
-void   FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);\r
 // --- File IO\r
 size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);\r
 #if SUPPORT_WRITE\r
-void   FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer);\r
-size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);\r
-#endif\r
-// --- Directory IO\r
-char   *FAT_ReadDir(tVFS_Node *Node, int ID);\r
-tVFS_Node      *FAT_FindDir(tVFS_Node *Node, const char *Name);\r
-tVFS_Node      *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);\r
-#if SUPPORT_WRITE\r
- int   FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);\r
- int   FAT_Relink(tVFS_Node *node, const char *OldName, const char *NewName);\r
+size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);\r
 #endif\r
 void   FAT_CloseFile(tVFS_Node *node);\r
 \r
+\r
 // === Options ===\r
  int   giFAT_MaxCachedClusters = 1024*512/4;\r
 \r
 // === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL);\r
+MODULE_DEFINE(0, VER2(0,80) /*v0.80*/, VFAT, FAT_Install, NULL, NULL);\r
 tFAT_VolInfo   gFAT_Disks[8];\r
  int   giFAT_PartCount = 0;\r
 tVFS_Driver    gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, FAT_GetNodeFromINode, NULL};\r
@@ -96,7 +53,8 @@ tVFS_NodeType gFAT_DirType = {
        .FindDir = FAT_FindDir,\r
        #if SUPPORT_WRITE\r
        .MkNod = FAT_Mknod,\r
-       .Relink = FAT_Relink,\r
+       .Link = FAT_Link,\r
+       .Unlink = FAT_Unlink,\r
        #endif\r
        .Close = FAT_CloseFile\r
        };\r
@@ -130,6 +88,8 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
        Uint32  FATSz, RootDirSectors, TotSec;\r
        tVFS_Node       *node = NULL;\r
        tFAT_VolInfo    *diskInfo = &gFAT_Disks[giFAT_PartCount];\r
+\r
+       memset(diskInfo, 0, sizeof(*diskInfo));\r
        \r
        // Temporary Pointer\r
        bs = &diskInfo->bootsect;\r
@@ -144,7 +104,8 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
        VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);\r
        \r
        if(bs->bps == 0 || bs->spc == 0) {\r
-               Log_Notice("FAT", "Error in FAT Boot Sector");\r
+               Log_Notice("FAT", "Error in FAT Boot Sector (zero BPS/SPC)");\r
+               VFS_Close(diskInfo->fileHandle);\r
                return NULL;\r
        }\r
        \r
@@ -164,9 +125,9 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
        \r
        diskInfo->ClusterCount = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;\r
        \r
-       if(diskInfo->ClusterCount < 4085)\r
+       if(diskInfo->ClusterCount < FAT16_MIN_SECTORS)\r
                diskInfo->type = FAT12;\r
-       else if(diskInfo->ClusterCount < 65525)\r
+       else if(diskInfo->ClusterCount < FAT32_MIN_CLUSTERS)\r
                diskInfo->type = FAT16;\r
        else\r
                diskInfo->type = FAT32;\r
@@ -225,6 +186,7 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
                diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount);\r
                if(diskInfo->FATCache == NULL) {\r
                        Log_Warning("FAT", "Heap Exhausted");\r
+                       VFS_Cose(diskInfo->fileHandle);\r
                        return NULL;\r
                }\r
                Ofs = bs->resvSectCount*512;\r
@@ -272,10 +234,6 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
        \r
        diskInfo->BytesPerCluster = bs->spc * bs->bps;\r
        \r
-       // Initalise inode cache for filesystem\r
-       diskInfo->inodeHandle = Inode_GetHandle();\r
-       LOG("Inode Cache handle is %i", diskInfo->inodeHandle);\r
-       \r
        // == VFS Interface\r
        node = &diskInfo->rootNode;\r
        //node->Size = bs->files_in_root;\r
@@ -313,7 +271,7 @@ void FAT_Unmount(tVFS_Node *Node)
        // Close Disk Handle\r
        VFS_Close( disk->fileHandle );\r
        // Clear Node Cache\r
-       Inode_ClearCache(disk->inodeHandle);\r
+       FAT_int_ClearNodeCache(disk);\r
        // Mark as unused\r
        disk->fileHandle = -2;\r
        return;\r
@@ -331,15 +289,15 @@ void FAT_Unmount(tVFS_Node *Node)
  */\r
 int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster)\r
 {\r
-       Uint32  cluster;\r
+       Uint32  cluster, base_cluster;\r
        Uint64  addr;\r
         int    skip;\r
        tFAT_VolInfo    *disk = Node->ImplPtr;\r
        \r
        ENTER("pNode XOffset", Node, Offset);\r
        \r
-       cluster = Node->Inode & 0xFFFFFFF;      // Cluster ID\r
-       LOG("cluster = 0x%07x", cluster);\r
+       cluster = base_cluster = Node->Inode & 0xFFFFFFF;       // Cluster ID\r
+//     LOG("base cluster = 0x%07x", cluster);\r
        \r
        // Do Cluster Skip\r
        // - Pre FAT32 had a reserved area for the root.\r
@@ -358,11 +316,13 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu
                if(Cluster)     *Cluster = cluster;\r
        }\r
        else {\r
+               // TODO: Bounds checking on root\r
+//             LOG("Root cluster count %i", disk->bootsect.files_in_root*32/disk->BytesPerCluster);\r
                // Increment by clusters in offset\r
                cluster += Offset / disk->BytesPerCluster;\r
        }\r
        \r
-       LOG("cluster = %08x", cluster);\r
+//     LOG("cluster = 0x%07x", cluster);\r
        \r
        // Bounds Checking (Used to spot corruption)\r
        if(cluster > disk->ClusterCount + 2)\r
@@ -375,7 +335,7 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu
        \r
        // Compute Offsets\r
        // - Pre FAT32 cluster base (in sectors)\r
-       if( cluster == disk->rootOffset && disk->type != FAT32 ) {\r
+       if( base_cluster == disk->rootOffset && disk->type != FAT32 ) {\r
                addr = disk->bootsect.resvSectCount * disk->bootsect.bps;\r
                addr += cluster * disk->BytesPerCluster;\r
        }\r
@@ -392,225 +352,6 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu
        return 0;\r
 }\r
 \r
-/*\r
- * ====================\r
- *   FAT Manipulation\r
- * ====================\r
- */\r
-/**\r
- * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
- * \brief Fetches a value from the FAT\r
- */\r
-Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
-{\r
-       Uint32  val = 0;\r
-       Uint32  ofs;\r
-       ENTER("pDisk xCluster", Disk, cluster);\r
-       Mutex_Acquire( &Disk->lFAT );\r
-       #if CACHE_FAT\r
-       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               val = Disk->FATCache[cluster];\r
-               if(Disk->type == FAT12 && val == EOC_FAT12)     val = -1;\r
-               if(Disk->type == FAT16 && val == EOC_FAT16)     val = -1;\r
-               if(Disk->type == FAT32 && val == EOC_FAT32)     val = -1;\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               ofs = Disk->bootsect.resvSectCount*512;\r
-               if(Disk->type == FAT12) {\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);\r
-                       val = (cluster & 1 ? val>>12 : val & 0xFFF);\r
-                       if(val == EOC_FAT12)    val = -1;\r
-               } else if(Disk->type == FAT16) {\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);\r
-                       if(val == EOC_FAT16)    val = -1;\r
-               } else {\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);\r
-                       if(val == EOC_FAT32)    val = -1;\r
-               }\r
-       #if CACHE_FAT\r
-       }\r
-       #endif /*CACHE_FAT*/\r
-       Mutex_Release( &Disk->lFAT );\r
-       LEAVE('x', val);\r
-       return val;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \brief Allocate a new cluster\r
- */\r
-Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)\r
-{\r
-       Uint32  ret = Previous;\r
-       #if CACHE_FAT\r
-       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               Uint32  eoc;\r
-               \r
-               LOCK(Disk->lFAT);\r
-               for(ret = Previous; ret < Disk->ClusterCount; ret++)\r
-               {\r
-                       if(Disk->FATCache[ret] == 0)\r
-                               goto append;\r
-               }\r
-               for(ret = 0; ret < Previous; ret++)\r
-               {\r
-                       if(Disk->FATCache[ret] == 0)\r
-                               goto append;\r
-               }\r
-               \r
-               RELEASE(Disk->lFAT);\r
-               return 0;\r
-       \r
-       append:\r
-               switch(Disk->type)\r
-               {\r
-               case FAT12:     eoc = EOC_FAT12;        break;\r
-               case FAT16:     eoc = EOC_FAT16;        break;\r
-               case FAT32:     eoc = EOC_FAT32;        break;\r
-               default:        return 0;\r
-               }\r
-               \r
-               Disk->FATCache[ret] = eoc;\r
-               Disk->FATCache[Previous] = ret;\r
-               \r
-               RELEASE(Disk->lFAT);\r
-               return ret;\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               Uint32  val;\r
-               Uint32  ofs = Disk->bootsect.resvSectCount*512;\r
-               Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT");\r
-               return 0;\r
-               \r
-               switch(Disk->type)\r
-               {\r
-               case FAT12:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
-                       if( Previous & 1 ) {\r
-                               val &= 0xFFF000;\r
-                               val |= ret;\r
-                       }\r
-                       else {\r
-                               val &= 0xFFF;\r
-                               val |= ret<<12;\r
-                       }\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
-                       \r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
-                       if( Cluster & 1 ) {\r
-                               val &= 0xFFF000;\r
-                               val |= eoc;\r
-                       }\r
-                       else {\r
-                               val &= 0x000FFF;\r
-                               val |= eoc<<12;\r
-                       }\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
-                       break;\r
-               case FAT16:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);\r
-                       break;\r
-               case FAT32:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);\r
-                       break;\r
-               }\r
-               return ret;\r
-       #if CACHE_FAT\r
-       }\r
-       #endif\r
-}\r
-\r
-/**\r
- * \brief Free's a cluster\r
- * \return The original contents of the cluster\r
- */\r
-Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)\r
-{\r
-       Uint32  ret;\r
-       #if CACHE_FAT\r
-       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               LOCK(Disk->lFAT);\r
-               \r
-               ret = Disk->FATCache[Cluster];\r
-               Disk->FATCache[Cluster] = 0;\r
-               \r
-               RELEASE(Disk->lFAT);\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               Uint32  val;\r
-               Uint32  ofs = Disk->bootsect.resvSectCount*512;\r
-               LOCK(Disk->lFAT);\r
-               switch(Disk->type)\r
-               {\r
-               case FAT12:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
-                       if( Cluster & 1 ) {\r
-                               ret = val & 0xFFF0000;\r
-                               val &= 0xFFF;\r
-                       }\r
-                       else {\r
-                               ret = val & 0xFFF;\r
-                               val &= 0xFFF000;\r
-                       }\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
-                       break;\r
-               case FAT16:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
-                       val = 0;\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
-                       break;\r
-               case FAT32:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
-                       val = 0;\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
-                       break;\r
-               }\r
-               RELEASE(Disk->lFAT);\r
-       #if CACHE_FAT\r
-       }\r
-       #endif\r
-       if(Disk->type == FAT12 && ret == EOC_FAT12)     ret = -1;\r
-       if(Disk->type == FAT16 && ret == EOC_FAT16)     ret = -1;\r
-       if(Disk->type == FAT32 && ret == EOC_FAT32)     ret = -1;\r
-       return ret;\r
-}\r
-#endif\r
-\r
-/*\r
- * ====================\r
- *      Cluster IO\r
- * ====================\r
- */\r
-/**\r
- * \brief Read a cluster\r
- * \param Disk Disk (Volume) to read from\r
- * \param Length       Length to read\r
- * \param Buffer       Destination for read data\r
- */\r
-void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)\r
-{\r
-       ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);\r
-       VFS_ReadAt(\r
-               Disk->fileHandle,\r
-               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
-                       * Disk->bootsect.bps,\r
-               Length,\r
-               Buffer\r
-               );\r
-       LEAVE('-');\r
-}\r
-\r
 /* ====================\r
  *       File IO\r
  * ====================\r
@@ -730,22 +471,6 @@ size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
 }\r
 \r
 #if SUPPORT_WRITE\r
-/**\r
- * \brief Write a cluster to disk\r
- */\r
-void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)\r
-{\r
-       ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);\r
-       VFS_ReadAt(\r
-               Disk->fileHandle,\r
-               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
-                       * Disk->bootsect.bps,\r
-               Disk->BytesPerCluster,\r
-               Buffer\r
-               );\r
-       LEAVE('-');\r
-}\r
-\r
 /**\r
  * \brief Write to a file\r
  * \param Node File Node\r
@@ -753,16 +478,19 @@ void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)
  * \param Length       Size of data to write\r
  * \param Buffer       Data source\r
  */\r
-size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)\r
+size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)\r
 {\r
        tFAT_VolInfo    *disk = Node->ImplPtr;\r
        char    tmpBuf[disk->BytesPerCluster];\r
         int    remLength = Length;\r
        Uint32  cluster, tmpCluster;\r
         int    bNewCluster = 0;\r
+       off_t   original_offset = Offset;\r
        \r
        if(Offset > Node->Size) return 0;\r
        \r
+       ENTER("pNode Xoffset xlength pbuffer", Node, Offset, Length, Buffer);\r
+       \r
        // Seek Clusters\r
        cluster = Node->Inode & 0xFFFFFFFF;\r
        while( Offset > disk->BytesPerCluster )\r
@@ -770,6 +498,7 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
                cluster = FAT_int_GetFatValue( disk, cluster );\r
                if(cluster == -1) {\r
                        Log_Warning("FAT", "EOC Unexpectedly Reached");\r
+                       LEAVE('i', 0);\r
                        return 0;\r
                }\r
                Offset -= disk->BytesPerCluster;\r
@@ -777,7 +506,10 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
        if( Offset == disk->BytesPerCluster )\r
        {\r
                Uint32  tmp = FAT_int_AllocateCluster(disk, cluster);\r
-               if(!tmp)        return 0;\r
+               if(!tmp) {\r
+                       LEAVE('i', 0);\r
+                       return 0;\r
+               }\r
                cluster = tmp;\r
                Offset -= disk->BytesPerCluster;\r
        }\r
@@ -786,17 +518,20 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
        {\r
                char    tmpBuf[disk->BytesPerCluster];\r
                \r
+               LOG("Read-Modify-Write single");\r
+               \r
                // Read-Modify-Write\r
                FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
                memcpy( tmpBuf + Offset, Buffer, Length );\r
                FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
-               \r
-               return Length;\r
+               goto return_full;\r
        }\r
        \r
        // Clean up changes within a cluster\r
        if( Offset )\r
        {       \r
+               LOG("Read-Modify-Write first");\r
+\r
                // Read-Modify-Write\r
                FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
                memcpy( tmpBuf + Offset, Buffer, disk->BytesPerCluster - Offset );\r
@@ -809,9 +544,8 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
                tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
                if(tmpCluster == -1) {\r
                        tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
-                       if( tmpCluster == 0 ) {\r
-                               return Length - remLength;\r
-                       }\r
+                       if( tmpCluster == 0 )\r
+                               goto ret_incomplete;\r
                }\r
                cluster = tmpCluster;\r
        }\r
@@ -820,674 +554,48 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
        {\r
                FAT_int_WriteCluster( disk, cluster, Buffer );\r
                Buffer += disk->BytesPerCluster;\r
+               remLength -= disk->BytesPerCluster;\r
                \r
                // Get next cluster (allocating if needed)\r
                tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
                if(tmpCluster == -1) {\r
                        bNewCluster = 1;\r
                        tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
-                       if( tmpCluster == 0 ) {\r
-                               return Length - remLength;\r
-                       }\r
+                       if( tmpCluster == 0 )\r
+                               goto ret_incomplete;\r
                }\r
                cluster = tmpCluster;\r
        }\r
        \r
        // Finish off\r
-       tmpBuf = malloc( disk->BytesPerCluster );\r
-       if( bNewCluster )\r
-               memset(tmpBuf, 0, disk->BytesPerCluster);\r
-       else\r
-               FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
-       memcpy( tmpBuf, Buffer, remLength );\r
-       FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
-       free( tmpBuf );\r
-       \r
-       return Length;\r
-}\r
-#endif\r
-\r
-/* ====================\r
- *  File Names & Nodes\r
- * ====================\r
- */\r
-/**\r
- * \brief Converts a FAT directory entry name into a proper filename\r
- * \param dest Destination array (must be at least 13 bytes in size)\r
- * \param src  8.3 filename (concatenated, e.g 'FILE1   TXT')\r
- */\r
-void FAT_int_ProperFilename(char *dest, const char *src)\r
-{\r
-        int    inpos, outpos;\r
-       \r
-       // Name\r
-       outpos = 0;\r
-       for( inpos = 0; inpos < 8; inpos++ ) {\r
-               if(src[inpos] == ' ')   break;\r
-               dest[outpos++] = src[inpos];\r
-       }\r
-       inpos = 8;\r
-       // Check for empty extensions\r
-       if(src[8] != ' ')\r
-       {\r
-               dest[outpos++] = '.';\r
-               for( ; inpos < 11; inpos++)     {\r
-                       if(src[inpos] == ' ')   break;\r
-                       dest[outpos++] = src[inpos];\r
-               }\r
-       }\r
-       dest[outpos++] = '\0';\r
-       \r
-       //LOG("dest='%s'", dest);\r
-}\r
-\r
-/**\r
- * \fn char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
- * \brief Converts either a LFN or a 8.3 Name into a proper name\r
- * \param ft   Pointer to the file's entry in the parent directory\r
- * \param LongFileName Long file name pointer\r
- * \return Filename as a heap string\r
- */\r
-char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
-{\r
-       char    *ret;\r
-       ENTER("pft sLongFileName", ft, LongFileName);\r
-       //Log_Debug("FAT", "FAT_int_CreateName(ft=%p, LongFileName=%p'%s')", ft, LongFileName);\r
-       #if USE_LFN\r
-       if(LongFileName && LongFileName[0] != '\0')\r
-       {       \r
-               ret = strdup(LongFileName);\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               ret = (char*) malloc(13);\r
-               if( !ret ) {\r
-                       Log_Warning("FAT", "FAT_int_CreateName: malloc(13) failed");\r
-                       return NULL;\r
-               }\r
-               FAT_int_ProperFilename(ret, ft->name);\r
-       #if USE_LFN\r
-       }\r
-       #endif\r
-       LEAVE('s', ret);\r
-       return ret;\r
-}\r
-\r
-/**\r
- * \brief Creates a tVFS_Node structure for a given file entry\r
- * \param Parent       Parent directory VFS node\r
- * \param Entry        File table entry for the new node\r
- * \param Pos  Position in the parent of the new node\r
- */\r
-tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry, int Pos)\r
-{\r
-       tVFS_Node       node;\r
-       tVFS_Node       *ret;\r
-       tFAT_VolInfo    *disk = Parent->ImplPtr;\r
-       \r
-       ENTER("pParent pFT", Parent, Entry);\r
-       LOG("disk = %p", disk);\r
-       \r
-       memset(&node, 0, sizeof(tVFS_Node));\r
-       \r
-       // Set Other Data\r
-       // 0-27: Cluster, 32-59: Parent Cluster\r
-       node.Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);\r
-       LOG("node.Inode = %llx", node.Inode);\r
-       // Position in parent directory\r
-       node.ImplInt = Pos & 0xFFFF;\r
-       // Disk Pointer\r
-       node.ImplPtr = disk;\r
-       node.Size = Entry->size;\r
-       LOG("Entry->size = %i", Entry->size);\r
-       // root:root\r
-       node.UID = 0;   node.GID = 0;\r
-       node.NumACLs = 1;\r
-       \r
-       node.Flags = 0;\r
-       if(Entry->attrib & ATTR_DIRECTORY)      node.Flags |= VFS_FFLAG_DIRECTORY;\r
-       if(Entry->attrib & ATTR_READONLY) {\r
-               node.Flags |= VFS_FFLAG_READONLY;\r
-               node.ACLs = &gVFS_ACL_EveryoneRX;       // R-XR-XR-X\r
-       }\r
-       else {\r
-               node.ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX\r
-       }\r
-       \r
-       // Create timestamps\r
-       node.ATime = timestamp(0,0,0,\r
-                       ((Entry->adate&0x1F) - 1),      // Days\r
-                       ((Entry->adate&0x1E0) - 1),     // Months\r
-                       1980+((Entry->adate&0xFF00)>>8) // Years\r
-                       );\r
-       \r
-       node.CTime = Entry->ctimems * 10;       // Miliseconds\r
-       node.CTime += timestamp(\r
-                       ((Entry->ctime&0x1F)<<1),       // Seconds\r
-                       ((Entry->ctime&0x3F0)>>5),      // Minutes\r
-                       ((Entry->ctime&0xF800)>>11),    // Hours\r
-                       ((Entry->cdate&0x1F)-1),                // Days\r
-                       ((Entry->cdate&0x1E0)-1),               // Months\r
-                       1980+((Entry->cdate&0xFF00)>>8) // Years\r
-                       );\r
-                       \r
-       node.MTime = timestamp(\r
-                       ((Entry->mtime&0x1F)<<1),       // Seconds\r
-                       ((Entry->mtime&0x3F0)>>5),      // Minutes\r
-                       ((Entry->mtime&0xF800)>>11),    // Hours\r
-                       ((Entry->mdate&0x1F)-1),                // Days\r
-                       ((Entry->mdate&0x1E0)-1),               // Months\r
-                       1980+((Entry->mdate&0xFF00)>>8) // Years\r
-                       );\r
-       \r
-       // Set pointers\r
-       if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
-               //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);\r
-               node.Type = &gFAT_DirType;      \r
-               node.Size = -1;\r
-       }\r
-       else {\r
-               node.Type = &gFAT_FileType;\r
-       }\r
-       \r
-       ret = Inode_CacheNode(disk->inodeHandle, &node);\r
-       LEAVE('p', ret);\r
-       return ret;\r
-}\r
-\r
-/* \r
- * ====================\r
- *     Directory IO\r
- * ====================\r
- */\r
-\r
-/**\r
- * \brief Reads a sector from the disk\r
- * \param Node Directory node to read\r
- * \param Sector       Sector number in the directory to read\r
- * \param Buffer       Destination buffer for the read data\r
- */\r
-int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)\r
-{\r
-       Uint64  addr;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       \r
-       ENTER("pNode iSector pEntry", Node, Sector, Buffer);\r
-       \r
-       // Parse address\r
-       if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))\r
-       {\r
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-       \r
-       LOG("addr = 0x%llx", addr);\r
-       // Read Sector\r
-       if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512)\r
-       {\r
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-       \r
-       LEAVE('i', 0);\r
-       return 0;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \brief Writes an entry to the disk\r
- * \todo Support expanding a directory\r
- * \param Node Directory node\r
- * \param ID   ID of entry to update\r
- * \param Entry        Entry data\r
- * \return Zero on success, non-zero on error\r
- */\r
-int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)\r
-{\r
-       Uint64  addr = 0;\r
-        int    tmp;\r
-       Uint32  cluster = 0;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       \r
-       ENTER("pNode iID pEntry", Node, ID, Entry);\r
-       \r
-       tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
-       if( tmp )\r
-       {\r
-               //TODO: Allocate a cluster\r
-               cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);\r
-               if(cluster == -1) {\r
-                       Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);\r
-                       LEAVE('i', 1);\r
-                       return 1;\r
-               }\r
-               FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
-       }\r
-       \r
-\r
-       LOG("addr = 0x%llx", addr);\r
-       \r
-       // Read Sector\r
-       VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry);      // Read Dir Data\r
-       \r
-       LEAVE('i', 0);\r
-       return 0;\r
-}\r
-#endif\r
-\r
-#if USE_LFN    \r
-/**\r
- * \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
- * \brief Return pointer to LFN cache entry\r
- * \param Node Directory node\r
- * \param ID   ID of the short name\r
- * \return Pointer to the LFN cache entry\r
- */\r
-char *FAT_int_GetLFN(tVFS_Node *Node, int ID)\r
-{\r
-       tFAT_LFNCache   *cache;\r
-        int    i, firstFree;\r
-       \r
-       Mutex_Acquire( &Node->Lock );\r
-       \r
-       // TODO: Thread Safety (Lock things)\r
-       cache = Node->Data;\r
-       \r
-       // Create a cache if it isn't there\r
-       if(!cache) {\r
-               cache = Node->Data = malloc( sizeof(tFAT_LFNCache) + sizeof(tFAT_LFNCacheEnt) );\r
-               cache->NumEntries = 1;\r
-               cache->Entries[0].ID = ID;\r
-               cache->Entries[0].Data[0] = '\0';\r
-               Mutex_Release( &Node->Lock );\r
-               //Log_Debug("FAT", "Return = %p (new)", cache->Entries[0].Data);\r
-               return cache->Entries[0].Data;\r
-       }\r
-       \r
-       // Scan for this entry\r
-       firstFree = -1;\r
-       for( i = 0; i < cache->NumEntries; i++ )\r
-       {\r
-               if( cache->Entries[i].ID == ID ) {\r
-                       Mutex_Release( &Node->Lock );\r
-                       //Log_Debug("FAT", "Return = %p (match)", cache->Entries[i].Data);\r
-                       return cache->Entries[i].Data;\r
-               }\r
-               if( cache->Entries[i].ID == -1 && firstFree == -1 )\r
-                       firstFree = i;\r
-       }\r
-       \r
-       if(firstFree == -1) {\r
-               // Use `i` for temp length\r
-               i = sizeof(tFAT_LFNCache) + (cache->NumEntries+1)*sizeof(tFAT_LFNCacheEnt);\r
-               Node->Data = realloc( Node->Data, i );\r
-               if( !Node->Data ) {\r
-                       Log_Error("FAT", "realloc() fail, unable to allocate %i for LFN cache", i);\r
-                       Mutex_Release( &Node->Lock );\r
-                       return NULL;\r
-               }\r
-               //Log_Debug("FAT", "Realloc (%i)\n", i);\r
-               cache = Node->Data;\r
-               i = cache->NumEntries;\r
-               cache->NumEntries ++;\r
-       }\r
-       else {\r
-               i = firstFree;\r
-       }\r
-       \r
-       // Create new entry\r
-       cache->Entries[ i ].ID = ID;\r
-       cache->Entries[ i ].Data[0] = '\0';\r
-       \r
-       Mutex_Release( &Node->Lock );\r
-       //Log_Debug("FAT", "Return = %p (firstFree, i = %i)", cache->Entries[i].Data, i);\r
-       return cache->Entries[ i ].Data;\r
-}\r
-\r
-/**\r
- * \fn void FAT_int_DelLFN(tVFS_Node *node)\r
- * \brief Delete a LFN cache entry\r
- * \param Node Directory node\r
- * \param ID   File Entry ID\r
- */\r
-void FAT_int_DelLFN(tVFS_Node *Node, int ID)\r
-{\r
-       tFAT_LFNCache   *cache = Node->Data;\r
-        int    i;\r
-       \r
-       // Fast return\r
-       if(!cache)      return;\r
-       \r
-       // Scan for a current entry\r
-       for( i = 0; i < cache->NumEntries; i++ )\r
-       {\r
-               if( cache->Entries[i].ID == ID )\r
-                       cache->Entries[i].ID = -1;\r
-       }\r
-       return ;\r
-}\r
-#endif\r
-\r
-/**\r
- * \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
- * \param Node Node structure of directory\r
- * \param ID   Directory position\r
- * \return Filename as a heap string, NULL or VFS_SKIP\r
- */\r
-char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
-{\r
-       fat_filetable   fileinfo[16];   // sizeof(fat_filetable)=32, so 16 per sector\r
-        int    a = 0;\r
-       char    *ret;\r
-       #if USE_LFN\r
-       char    *lfn = NULL;\r
-       #endif\r
-       \r
-       ENTER("pNode iID", Node, ID);\r
-       \r
-       if(FAT_int_ReadDirSector(Node, ID/16, fileinfo))\r
-       {\r
-               LOG("End of chain, end of dir");\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Offset in sector\r
-       a = ID % 16;\r
-\r
-       LOG("fileinfo[%i].name[0] = 0x%x", a, (Uint8)fileinfo[a].name[0]);\r
-       \r
-       // Check if this is the last entry\r
-       if( fileinfo[a].name[0] == '\0' ) {\r
-               Node->Size = ID;\r
-               LOG("End of list");\r
-               LEAVE('n');\r
-               return NULL;    // break\r
-       }\r
-       \r
-       // Check for empty entry\r
-       if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {\r
-               LOG("Empty Entry");\r
-               #if 0   // Stop on empty entry?\r
-               LEAVE('n');\r
-               return NULL;    // Stop\r
-               #else\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;        // Skip\r
-               #endif\r
-       }\r
-       \r
-       #if USE_LFN\r
-       // Get Long File Name Cache\r
-       if(fileinfo[a].attrib == ATTR_LFN)\r
-       {\r
-               fat_longfilename        *lfnInfo;\r
-               \r
-               lfnInfo = (fat_longfilename *) &fileinfo[a];\r
-               \r
-               // Get cache for corresponding file\r
-               // > ID + Index gets the corresponding short node\r
-               lfn = FAT_int_GetLFN( Node, ID + (lfnInfo->id & 0x3F) );\r
-               \r
-               // Bit 6 indicates the start of an entry\r
-               if(lfnInfo->id & 0x40)  memset(lfn, 0, 256);\r
-               \r
-               a = ((lfnInfo->id & 0x3F) - 1) * 13;\r
-               //Log_Debug("FAT", "ID = 0x%02x, a = %i", lfnInfo->id, a);\r
-               \r
-               // Sanity Check (FAT implementations should not allow >255 character names)\r
-               if(a > 255)     return VFS_SKIP;\r
-               \r
-               // Append new bytes\r
-               lfn[a+ 0] = lfnInfo->name1[0];  lfn[a+ 1] = lfnInfo->name1[1];\r
-               lfn[a+ 2] = lfnInfo->name1[2];  lfn[a+ 3] = lfnInfo->name1[3];\r
-               lfn[a+ 4] = lfnInfo->name1[4];  \r
-               lfn[a+ 5] = lfnInfo->name2[0];  lfn[a+ 6] = lfnInfo->name2[1];\r
-               lfn[a+ 7] = lfnInfo->name2[2];  lfn[a+ 8] = lfnInfo->name2[3];\r
-               lfn[a+ 9] = lfnInfo->name2[4];  lfn[a+10] = lfnInfo->name2[5];\r
-               lfn[a+11] = lfnInfo->name3[0];  lfn[a+12] = lfnInfo->name3[1];\r
-               LOG("lfn = '%s'", lfn);\r
-               //Log_Debug("FAT", "lfn = '%s'", lfn);\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       #endif\r
-       \r
-       // Check if it is a volume entry\r
-       if(fileinfo[a].attrib & 0x08) {\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       // Ignore .\r
-       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == ' ') {\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       // and ..\r
-       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == '.' && fileinfo[a].name[2] == ' ') {\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       \r
-       LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'",\r
-               fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],\r
-               fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],\r
-               fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );\r
-       \r
-       #if USE_LFN\r
-       lfn = FAT_int_GetLFN(Node, ID);\r
-       //Log_Debug("FAT", "lfn = %p'%s'", lfn, lfn);\r
-       ret = FAT_int_CreateName(&fileinfo[a], lfn);\r
-       #else\r
-       ret = FAT_int_CreateName(&fileinfo[a], NULL);\r
-       #endif\r
-       \r
-       LEAVE('s', ret);\r
-       return ret;\r
-}\r
-\r
-/**\r
- * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)\r
- * \brief Finds an entry in the current directory\r
- */\r
-tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name)\r
-{\r
-       fat_filetable   fileinfo[16];\r
-       char    tmpName[13];\r
-       #if USE_LFN\r
-       fat_longfilename        *lfnInfo;\r
-       char    lfn[256];\r
-        int    lfnPos=255, lfnId = -1;\r
-       #endif\r
-        int    i;\r
-       tVFS_Node       *tmpNode;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       Uint32  cluster;\r
-       \r
-       ENTER("pNode sname", Node, Name);       \r
-\r
-       // Fast Returns\r
-       if(!Name || Name[0] == '\0') {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       for( i = 0; ; i++ )\r
+       if( remLength )\r
        {\r
-               if((i & 0xF) == 0) {\r
-                       if(FAT_int_ReadDirSector(Node, i/16, fileinfo))\r
-                       {\r
-                               LEAVE('n');\r
-                               return NULL;\r
-                       }\r
-               }\r
-               \r
-               //Check if the files are free\r
-               if(fileinfo[i&0xF].name[0] == '\0')     break;  // End of List marker\r
-               if(fileinfo[i&0xF].name[0] == '\xE5')   continue;       // Free entry\r
-               \r
-               \r
-               #if USE_LFN\r
-               // Long File Name Entry\r
-               if(fileinfo[i & 0xF].attrib == ATTR_LFN)\r
-               {\r
-                       lfnInfo = (fat_longfilename *) &fileinfo[i&0xF];\r
-                       if(lfnInfo->id & 0x40) {\r
-                               memset(lfn, 0, 256);\r
-                               lfnPos = (lfnInfo->id & 0x3F) * 13 - 1;\r
-                       }\r
-                       // Sanity check the position so we don't overflow\r
-                       if( lfnPos < 12 )\r
-                               continue ;\r
-                       lfn[lfnPos--] = lfnInfo->name3[1];      lfn[lfnPos--] = lfnInfo->name3[0];\r
-                       lfn[lfnPos--] = lfnInfo->name2[5];      lfn[lfnPos--] = lfnInfo->name2[4];\r
-                       lfn[lfnPos--] = lfnInfo->name2[3];      lfn[lfnPos--] = lfnInfo->name2[2];\r
-                       lfn[lfnPos--] = lfnInfo->name2[1];      lfn[lfnPos--] = lfnInfo->name2[0];\r
-                       lfn[lfnPos--] = lfnInfo->name1[4];      lfn[lfnPos--] = lfnInfo->name1[3];\r
-                       lfn[lfnPos--] = lfnInfo->name1[2];      lfn[lfnPos--] = lfnInfo->name1[1];\r
-                       lfn[lfnPos--] = lfnInfo->name1[0];\r
-                       if((lfnInfo->id&0x3F) == 1)\r
-                       {\r
-                               lfnId = i+1;\r
-                       }\r
-               }\r
+               if( bNewCluster )\r
+                       memset(tmpBuf, 0, disk->BytesPerCluster);\r
                else\r
-               {\r
-                       // Remove LFN if it does not apply\r
-                       if(lfnId != i)  lfn[0] = '\0';\r
-               #else\r
-               if(fileinfo[i&0xF].attrib == ATTR_LFN)  continue;\r
-               #endif\r
-                       // Get Real Filename\r
-                       FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
-                       LOG("tmpName = '%s'", tmpName);\r
-               \r
-                       // Only the long name is case sensitive, 8.3 is not\r
-                       #if USE_LFN\r
-                       if(strucmp(tmpName, Name) == 0 || strcmp(lfn, Name) == 0)\r
-                       #else\r
-                       if(strucmp(tmpName, Name) == 0)\r
-                       #endif\r
-                       {\r
-                               cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16);\r
-                               tmpNode = Inode_GetCache(disk->inodeHandle, cluster);\r
-                               if(tmpNode == NULL)     // Node is not cached\r
-                               {\r
-                                       tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], i);\r
-                               }\r
-                               LEAVE('p', tmpNode);\r
-                               return tmpNode;\r
-                       }\r
-               #if USE_LFN\r
-               }\r
-               #endif\r
+                       FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
+               memcpy( tmpBuf, Buffer, remLength );\r
+               FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
        }\r
-       \r
-       LEAVE('n');\r
-       return NULL;\r
-}\r
-\r
-tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)\r
-{\r
-       tFAT_VolInfo    *disk = Root->ImplPtr;\r
-        int    ents_per_sector = 512 / sizeof(fat_filetable); \r
-       fat_filetable   fileinfo[ents_per_sector];\r
-        int    sector = 0, i;\r
-       tVFS_Node       stub_node;\r
-\r
-       ENTER("pRoot XInode", Root, Inode);\r
-\r
-       stub_node.ImplPtr = disk;\r
-       stub_node.Size = -1;\r
-       stub_node.Inode = Inode >> 32;\r
-\r
-       for( i = 0; ; i ++ )\r
-       {\r
-               if( i == 0 || i == ents_per_sector )\r
-               {\r
-                       if(FAT_int_ReadDirSector(&stub_node, sector, fileinfo))\r
-                       {\r
-                               LOG("ReadDirSector failed");\r
-                               LEAVE('n');\r
-                               return NULL;\r
-                       }\r
-                       i = 0;\r
-                       sector ++;\r
-               }\r
-       \r
-               // Check for free/end of list\r
-               if(fileinfo[i].name[0] == '\0') break;  // End of List marker\r
-               if(fileinfo[i].name[0] == '\xE5')       continue;       // Free entry\r
-               \r
-               if(fileinfo[i].attrib == ATTR_LFN)      continue;\r
-\r
-               LOG("fileinfo[i].cluster = %x %04x", fileinfo[i].clusterHi, fileinfo[i].cluster);\r
-               #if DEBUG\r
-               {\r
-                       char    tmpName[13];\r
-                       FAT_int_ProperFilename(tmpName, fileinfo[i].name);\r
-                       LOG("tmpName = '%s'", tmpName);\r
-               }\r
-               #endif\r
-               \r
-       \r
-               if(fileinfo[i].cluster != (Inode & 0xFFFF))     continue;\r
-               if(fileinfo[i].clusterHi != ((Inode >> 16) & 0xFFFF))   continue;\r
 \r
-               LEAVE_RET('p', FAT_int_CreateNode(&stub_node, &fileinfo[i], sector*ents_per_sector+i));\r
+return_full:\r
+       if( original_offset + Length > Node->Size ) {\r
+               Node->Size = original_offset + Length;\r
+               LOG("Updated size to %x", Node->Size);\r
+               Node->ImplInt |= FAT_FLAG_DIRTY;\r
        }\r
-       LOG("sector = %i, i = %i", sector, i);\r
-       LEAVE('n');\r
-       return NULL;\r
-}\r
 \r
-#if SUPPORT_WRITE\r
-/**\r
- * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
- * \brief Create a new node\r
- */\r
-int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
-{\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
- * \brief Rename / Delete a file\r
- */\r
-int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
-{\r
-       tVFS_Node       *child;\r
-       fat_filetable   ft = {0};\r
-        int    ret;\r
-       \r
-       child = FAT_FindDir(Node, OldName);\r
-       if(!child)      return ENOTFOUND;\r
-       \r
-       // Delete?\r
-       if( NewName == NULL )\r
-       {\r
-               child->ImplInt |= FAT_FLAG_DELETE;      // Mark for deletion on close\r
-               \r
-               // Delete from the directory\r
-               ft.name[0] = '\xE9';\r
-               FAT_int_WriteDirEntry(Node, child->ImplInt & 0xFFFF, &ft);\r
-               \r
-               // Return success\r
-               ret = EOK;\r
-       }\r
-       // Rename\r
-       else\r
-       {\r
-               Log_Warning("FAT", "Renaming no yet supported %p ('%s' => '%s')",\r
-                       Node, OldName, NewName);\r
-               ret = ENOTIMPL;\r
-       }\r
-       \r
-       // Close child\r
-       child->Close( child );\r
-       return ret;\r
+       LEAVE('i', Length);\r
+       return Length;\r
+ret_incomplete:\r
+       LOG("Write incomplete");\r
+       Length -= remLength;\r
+       if( original_offset + Length > Node->Size ) {\r
+               Node->Size = original_offset + Length;  \r
+               Node->ImplInt |= FAT_FLAG_DIRTY;\r
+       }\r
+       LEAVE('i', Length);\r
+       return Length;\r
 }\r
 #endif\r
 \r
@@ -1499,39 +607,50 @@ void FAT_CloseFile(tVFS_Node *Node)
 {\r
        tFAT_VolInfo    *disk = Node->ImplPtr;\r
        if(Node == NULL)        return ;\r
-       \r
+\r
+       ENTER("pNode", Node);   \r
+\r
        #if SUPPORT_WRITE\r
        // Update the node if it's dirty (don't bother if it's marked for\r
        // deletion)\r
        if( (Node->ImplInt & FAT_FLAG_DIRTY) && !(Node->ImplInt & FAT_FLAG_DELETE) )\r
        {\r
-               tFAT_VolInfo    buf[16];\r
-               tFAT_VolInfo    *ft = &buf[ (Node->ImplInt & 0xFFFF) % 16 ];\r
-               \r
-               FAT_int_ReadDirSector(Node, (Node->ImplInt & 0xFFFF)/16, buf);\r
-               ft->size = Node->Size;\r
+               fat_filetable   ft;\r
+               tVFS_Node       *dirnode;\r
+\r
+               dirnode = FAT_int_CreateIncompleteDirNode(disk, Node->Inode >> 32);\r
+               if( !dirnode ) {\r
+                       Log_Error("FAT", "Can't get node for directory cluster #0x%x", Node->Inode>>32);\r
+                       LEAVE('-');\r
+                       return ;\r
+               }\r
+\r
+               int id = FAT_int_GetEntryByCluster(dirnode, Node->Inode & 0xFFFFFFFF, &ft);\r
+               ft.size = Node->Size;\r
                // TODO: update adate, mtime, mdate\r
-               FAT_int_WriteDirEntry(Node, Node->ImplInt & 0xFFFF, ft);\r
+               FAT_int_WriteDirEntry(dirnode, id, &ft);\r
+               \r
+               dirnode->Type->Close(dirnode);\r
                \r
                Node->ImplInt &= ~FAT_FLAG_DIRTY;\r
        }\r
        #endif\r
+\r
+       Uint32  cluster = Node->Inode;\r
+       Uint32  implint = Node->ImplInt;\r
        \r
-       // TODO: Make this more thread safe somehow, probably by moving the\r
-       // Inode_UncacheNode higher up and saving the cluster value somewhere\r
-       if( Node->ReferenceCount == 1 )\r
-       {               \r
-               #if SUPPORT_WRITE\r
+       #if SUPPORT_WRITE\r
+       if( FAT_int_DerefNode(Node) == 1 )\r
+       {\r
+               LOG("implint = %x", implint);\r
                // Delete File\r
-               if( Node->ImplInt & FAT_FLAG_DELETE ) {\r
+               if( implint & FAT_FLAG_DELETE ) {\r
+                       Log_Debug("FAT", "Deallocating chain stating at 0x%07x", cluster);\r
                        // Since the node is marked, we only need to remove it's data\r
-                       Uint32  cluster = Node->Inode & 0xFFFFFFFF;\r
                        while( cluster != -1 )\r
-                               cluster = FAT_int_FreeCluster(Node->ImplPtr, cluster);\r
+                               cluster = FAT_int_FreeCluster(disk, cluster);\r
                }\r
-               #endif\r
        }\r
-       \r
-       Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
-       return ;\r
+       #endif\r
+       LEAVE('-');\r
 }\r
diff --git a/KernelLand/Modules/Filesystems/FAT/fatio.c b/KernelLand/Modules/Filesystems/FAT/fatio.c
new file mode 100644 (file)
index 0000000..0652f0f
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Acess2 FAT12/16/32 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * fatio.c
+ * - FAT Manipulation and Cluster IO
+ */
+#define DEBUG  1
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+
+// === CODE ===
+/**
+ * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
+ * \brief Fetches a value from the FAT
+ */
+Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
+{
+       Uint32  val = 0;
+       Uint32  ofs;
+       ENTER("pDisk xCluster", Disk, cluster);
+       Mutex_Acquire( &Disk->lFAT );
+       #if CACHE_FAT
+       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
+       {
+               val = Disk->FATCache[cluster];
+               if(Disk->type == FAT12 && val == EOC_FAT12)     val = -1;
+               if(Disk->type == FAT16 && val == EOC_FAT16)     val = -1;
+               if(Disk->type == FAT32 && val == EOC_FAT32)     val = -1;
+       }
+       else
+       {
+       #endif
+               ofs = Disk->bootsect.resvSectCount*512;
+               if(Disk->type == FAT12) {
+                       VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);
+                       LOG("3 bytes at 0x%x are (Uint32)0x%x", ofs+(cluster/2)*3, val);
+                       val = (cluster & 1) ? (val>>12) : (val & 0xFFF);
+                       if(val == EOC_FAT12)    val = -1;
+               } else if(Disk->type == FAT16) {
+                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);
+                       if(val == EOC_FAT16)    val = -1;
+               } else {
+                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);
+                       if(val == EOC_FAT32)    val = -1;
+               }
+       #if CACHE_FAT
+       }
+       #endif /*CACHE_FAT*/
+       Mutex_Release( &Disk->lFAT );
+       LEAVE('x', val);
+       return val;
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Allocate a new cluster
+ */
+Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)
+{
+       Uint32  ret = -1;
+       
+       #if CACHE_FAT
+       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
+       {
+                int    bFoundCluster = 0;
+               Uint32  eoc;
+
+               switch(Disk->type)
+               {
+               case FAT12:     eoc = EOC_FAT12;        break;
+               case FAT16:     eoc = EOC_FAT16;        break;
+               case FAT32:     eoc = EOC_FAT32;        break;
+                       default:        return 0;
+               }
+               
+               Mutex_Acquire(&Disk->lFAT);
+               if( Previous != -1 )
+               {
+                       for(ret = Previous; ret < Disk->ClusterCount; ret++)
+                       {
+                               if(Disk->FATCache[ret] != 0) {
+                                       bFoundCluster = 1;
+                                       break;
+                               }
+                       }
+               }
+               if( !bFoundCluster )
+               {
+                       for(ret = 0; ret < Previous; ret++)
+                       {
+                               if(Disk->FATCache[ret] == 0) {
+                                       bFoundCluster = 1;
+                                       break;
+                               }
+                       }
+               }
+               
+               if(bFoundCluster)
+               { 
+                       Disk->FATCache[ret] = eoc;
+                       if( Previous != -1 )
+                               Disk->FATCache[Previous] = ret;
+               }
+               else
+               {
+                       ret = 0;
+               }
+                       
+               Mutex_Release(&Disk->lFAT);
+               LOG("Allocated cluster %x", ret);
+               return ret;
+       }
+       else
+       {
+       #endif
+               Uint32  val = 0;
+               Uint32  base = Disk->bootsect.resvSectCount*512;
+                int    block = 0, block_ofs = 0;
+                int    first_block;
+               const int       block_size = 512*3;
+               const int       ents_per_block_12 = block_size * 2 / 3; // 1.5 bytes per entry
+//             const int       ents_per_block_16 = block_size / 2;     // 2 bytes per entry
+//             const int       ents_per_block_32 = block_size / 4;     // 4 bytes per entry
+                int    block_count_12 = DivUp(Disk->ClusterCount, ents_per_block_12);
+               Uint8   sector_data[block_size+1];
+               sector_data[block_size] = 0;
+               
+               Mutex_Acquire(&Disk->lFAT);
+               switch(Disk->type)
+               {
+               case FAT12:
+                       if( Previous != -1 )
+                               block = Previous / ents_per_block_12;
+                       else
+                               block = 0;
+                       first_block = block;
+                       
+                       // Search within the same block as the previous cluster first
+                       do {
+                               VFS_ReadAt(Disk->fileHandle, base + block*block_size, block_size, sector_data);
+                               for( block_ofs = 0; block_ofs < ents_per_block_12; block_ofs ++ )
+                               {
+                                       Uint32  *valptr = (void*)( sector_data + block_ofs / 2 * 3 );
+                                        int    bitofs = 12 * (block_ofs % 2);
+//                                     LOG("%i:%i - FAT Ent 0x%03x", block, block_ofs, (*valptr>>bitofs) & 0xFFF);
+                                       if( ((*valptr >> bitofs) & 0xFFF) == 0 ) {
+                                               // Found a free cluster
+                                               *valptr |= EOC_FAT12 << bitofs;
+                                               ret = block * ents_per_block_12 + block_ofs;
+                                               break;
+                                       }
+                               }
+                               // Check for early break from the above loop
+                               if( block_ofs != ents_per_block_12 )
+                                       break;
+
+                               // Next block please
+                               block ++;
+                               if( block == block_count_12 )
+                                       block = 0;
+                       } while( block != first_block );
+                       
+                       if( ret != 0 )  // TODO: Could cluster 0 be valid?
+                       {
+                               // Write back changes to this part of the FAT
+                               VFS_WriteAt(Disk->fileHandle, base + block, block_size, sector_data);
+       
+                               // Note the new cluster in the chain
+                               if( Previous != -1 )
+                               {
+                                       LOG("Updating cluster %x to point to %x (offset %x)", Previous, ret,
+                                               base + (Previous>>1)*3);
+                                       VFS_ReadAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val); 
+                                       if( Previous & 1 ) {
+                                               val &= 0x000FFF;
+                                               val |= ret << 12;
+                                       }
+                                       else {
+                                               val &= 0xFFF000;
+                                               val |= ret << 0;
+                                       }
+                                       VFS_WriteAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val);
+                               }
+                       }
+                       break;
+               case FAT16:
+                       Log_Warning("FAT", "TODO: Implement cluster allocation with FAT16");
+//                     VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);
+//                     VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);
+                       break;
+               case FAT32:
+                       Log_Warning("FAT", "TODO: Implement cluster allocation with FAT32");
+//                     VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);
+//                     VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);
+                       break;
+               }
+               Mutex_Release(&Disk->lFAT);
+               LOG("Allocated cluster %x", ret);
+               return ret;
+       #if CACHE_FAT
+       }
+       #endif
+}
+
+/**
+ * \brief Free's a cluster
+ * \return The original contents of the cluster
+ */
+Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)
+{
+       Uint32  ret;
+
+       if( Cluster < 2 || Cluster > Disk->ClusterCount )       // oops?
+       {
+               Log_Notice("FAT", "Cluster 0x%x is out of range (2 ... 0x%x)", 
+                       Cluster, Disk->ClusterCount-1);
+               return -1;
+       }
+       
+       Mutex_Acquire(&Disk->lFAT);
+       #if CACHE_FAT
+       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
+       {
+               
+               ret = Disk->FATCache[Cluster];
+               Disk->FATCache[Cluster] = 0;
+       }
+       else
+       {
+       #endif
+               Uint32  val = 0;
+               Uint32  ofs = Disk->bootsect.resvSectCount*512;
+               switch(Disk->type)
+               {
+               case FAT12:
+                       VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
+                       val = LittleEndian32(val);
+                       if( Cluster & 1 ) {
+                               ret = (val >> 12) & 0xFFF;
+                               val &= 0xFFF;
+                       }
+                       else {
+                               ret = val & 0xFFF;
+                               val &= 0xFFF000;
+                       }
+                       val = LittleEndian32(val);
+                       VFS_WriteAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
+                       break;
+               case FAT16:
+                       VFS_ReadAt(Disk->fileHandle, ofs+Cluster*2, 2, &ret);
+                       ret = LittleEndian16(ret);
+                       val = 0;
+                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);
+                       break;
+               case FAT32:
+                       VFS_ReadAt(Disk->fileHandle, ofs+Cluster*4, 4, &ret);
+                       ret = LittleEndian32(ret);
+                       val = 0;
+                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 4, &val);
+                       break;
+               }
+       #if CACHE_FAT
+       }
+       #endif
+       Mutex_Release(&Disk->lFAT);
+       LOG("ret = %07x, eoc = %07x", ret, EOC_FAT12);
+       if(ret == 0) {
+               Log_Notice("FAT", "Cluster 0x%x was already free", Cluster);
+               return -1;
+       }
+       if(Disk->type == FAT12 && ret == EOC_FAT12)     ret = -1;
+       if(Disk->type == FAT16 && ret == EOC_FAT16)     ret = -1;
+       if(Disk->type == FAT32 && ret == EOC_FAT32)     ret = -1;
+       LOG("ret = %07x", ret);
+       return ret;
+}
+#endif
+
+/*
+ * ====================
+ *      Cluster IO
+ * ====================
+ */
+/**
+ * \brief Read a cluster
+ * \param Disk Disk (Volume) to read from
+ * \param Length       Length to read
+ * \param Buffer       Destination for read data
+ */
+void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)
+{
+       ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);
+       VFS_ReadAt(
+               Disk->fileHandle,
+               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
+                       * Disk->bootsect.bps,
+               Length,
+               Buffer
+               );
+       LEAVE('-');
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Write a cluster to disk
+ */
+void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, const void *Buffer)
+{
+       ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);
+       VFS_WriteAt(
+               Disk->fileHandle,
+               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
+                       * Disk->bootsect.bps,
+               Disk->BytesPerCluster,
+               Buffer
+               );
+       LEAVE('-');
+}
+#endif
index 6896945..9911563 100644 (file)
@@ -6,6 +6,9 @@
 #ifndef _FS_FAT_H_\r
 #define _FS_FAT_H_\r
 \r
+#define FAT16_MIN_SECTORS      4085\r
+#define FAT32_MIN_CLUSTERS     65525\r
+\r
 // === On Disk Structures ===\r
 /**\r
  * \struct fat_bootsect_s\r
@@ -116,16 +119,6 @@ struct fat_longfilename_s {
  * \}\r
  */\r
 \r
-/**\r
- * \brief Internal IDs for FAT types\r
- */\r
-enum eFatType\r
-{\r
-       FAT12,  //!< FAT12 Volume\r
-       FAT16,  //!< FAT16 Volume\r
-       FAT32,  //!< FAT32 Volume\r
-};\r
-\r
 /**\r
  * \name End of Cluster marks\r
  * \brief FAT values that indicate the end of a cluster chain in\r
@@ -143,29 +136,4 @@ typedef struct fat_bootsect_s fat_bootsect;
 typedef struct fat_filetable_s fat_filetable;\r
 typedef struct fat_longfilename_s fat_longfilename;\r
 \r
-// === Memory Structures ===\r
-/**\r
- * \struct drv_fat_volinfo_s\r
- * \brief Representation of a volume in memory\r
- */\r
-struct drv_fat_volinfo_s\r
-{\r
-        int    fileHandle;     //!< File Handle\r
-        int    type;   //!< FAT Type. See eFatType\r
-       char    name[12];       //!< Volume Name (With NULL Terminator)\r
-       tMutex  lFAT;   //!< Lock to prevent double-writing to the FAT\r
-       Uint32  firstDataSect;  //!< First data sector\r
-       Uint32  rootOffset;     //!< Root Offset (clusters)\r
-       Uint32  ClusterCount;   //!< Total Cluster Count\r
-       fat_bootsect    bootsect;       //!< Boot Sector\r
-       tVFS_Node       rootNode;       //!< Root Node\r
-        int    BytesPerCluster;\r
-        int    inodeHandle;    //!< Inode Cache Handle\r
-       #if CACHE_FAT\r
-       Uint32  *FATCache;      //!< FAT Cache\r
-       #endif\r
-};\r
-\r
-typedef struct drv_fat_volinfo_s tFAT_VolInfo;\r
-\r
 #endif\r
diff --git a/KernelLand/Modules/Filesystems/FAT/nodecache.c b/KernelLand/Modules/Filesystems/FAT/nodecache.c
new file mode 100644 (file)
index 0000000..dc285c4
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Acess2 FAT12/16/32 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * nodecache.c
+ * - FAT-Specific node caching
+ */
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+
+// === PROTOTYPES ===
+extern tVFS_Node       *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node);
+
+// === CODE ===
+tTime FAT_int_GetAcessTimestamp(Uint16 Date, Uint16 Time, Uint8 MS)
+{
+       return MS * 10 + timestamp(
+               // Seconds         Minutes              Hours
+               (Time & 0x1F) * 2, (Time >> 5) & 0x3F, (Time >> 11) & 0x1F,
+               // Day             Month                    Year
+               (Date & 0x1F) - 1, ((Date >> 5) & 0xF) - 1, 1980 + ((Date >> 9) & 0xFF)
+               );
+}
+
+void FAT_int_GetFATTimestamp(tTime AcessTimestamp, Uint16 *Date, Uint16 *Time, Uint8 *MS)
+{
+        int    y, m, d;
+        int    h, min, s, ms;
+       format_date(AcessTimestamp, &y, &m, &d, &h, &min, &s, &ms);
+       if(Date)
+               *Date = (d + 1) | ((m + 1) << 5) | ((y - 1980) << 9);
+       if(Time)
+               *Time = (s / 2) | (min << 5) | (h << 11);
+       if(MS)
+               *MS = (ms / 10) + (s & 1) * 100;
+}
+
+/**
+ * \brief Creates a tVFS_Node structure for a given file entry
+ * \param Parent       Parent directory VFS node
+ * \param Entry        File table entry for the new node
+ */
+tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry)
+{
+       tVFS_Node       node;
+       tVFS_Node       *ret;
+       tFAT_VolInfo    *disk = Parent->ImplPtr;
+
+       ENTER("pParent pEntry", Parent, Entry);
+       LOG("disk = %p", disk);
+       
+       if( (ret = FAT_int_GetNode(disk, Entry->cluster | (Entry->clusterHi<<16))) ) {
+               LEAVE('p', ret);
+               return ret;
+       }
+
+       memset(&node, 0, sizeof(tVFS_Node));
+       
+       // Set Other Data
+       // 0-27: Cluster, 32-59: Parent Cluster
+       node.Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);
+       LOG("node.Inode = %llx", node.Inode);
+       node.ImplInt = 0;
+       // Disk Pointer
+       node.ImplPtr = disk;
+       node.Size = Entry->size;
+       LOG("Entry->size = %i", Entry->size);
+       // root:root
+       node.UID = 0;   node.GID = 0;
+       node.NumACLs = 1;
+       
+       node.Flags = 0;
+       if(Entry->attrib & ATTR_DIRECTORY)      node.Flags |= VFS_FFLAG_DIRECTORY;
+       if(Entry->attrib & ATTR_READONLY) {
+               node.Flags |= VFS_FFLAG_READONLY;
+               node.ACLs = &gVFS_ACL_EveryoneRX;       // R-XR-XR-X
+       }
+       else {
+               node.ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX
+       }
+       
+       // Create timestamps
+       node.CTime = FAT_int_GetAcessTimestamp(Entry->cdate, Entry->ctime, Entry->ctimems);
+       node.MTime = FAT_int_GetAcessTimestamp(Entry->mdate, Entry->mtime, 0);
+       node.ATime = FAT_int_GetAcessTimestamp(Entry->adate, 0, 0);
+       
+       // Set pointers
+       if(node.Flags & VFS_FFLAG_DIRECTORY) {
+               //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);
+               node.Type = &gFAT_DirType;      
+               node.Size = -1;
+       }
+       else {
+               node.Type = &gFAT_FileType;
+       }
+
+       // TODO: Cache node     
+       ret = FAT_int_CacheNode(disk, &node);
+       LEAVE('p', ret);
+       return ret;
+}
+
+tVFS_Node *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster)
+{
+       if( Cluster == Disk->rootOffset )
+               return &Disk->rootNode;
+       
+       // If the directory isn't in the cache, what do?
+       // - we want to lock it such that we don't collide, but don't want to put crap data in the cache
+       // - Put a temp node in with a flag that indicates it's incomplete?
+       
+       Mutex_Acquire(&Disk->lNodeCache);
+       tFAT_CachedNode *cnode;
+
+       for(cnode = Disk->NodeCache; cnode; cnode = cnode->Next)
+       {
+               if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
+                       cnode->Node.ReferenceCount ++;
+                       Mutex_Release(&Disk->lNodeCache);
+                       return &cnode->Node;
+               }
+       }       
+
+       // Create a temporary node?
+       Log_Warning("FAT", "TODO: Impliment FAT_int_CreateIncompleteDirNode()");
+
+       Mutex_Release(&Disk->lNodeCache);
+       return NULL;
+}
+
+tVFS_Node *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster)
+{
+       if( Cluster == Disk->rootOffset )
+               return &Disk->rootNode;
+       Mutex_Acquire(&Disk->lNodeCache);
+       tFAT_CachedNode *cnode;
+
+       for(cnode = Disk->NodeCache; cnode; cnode = cnode->Next)
+       {
+               if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
+                       cnode->Node.ReferenceCount ++;
+                       Mutex_Release(&Disk->lNodeCache);
+                       return &cnode->Node;
+               }
+       }       
+
+       Mutex_Release(&Disk->lNodeCache);
+       return NULL;
+}
+
+tVFS_Node *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node)
+{
+       tFAT_CachedNode *cnode, *prev = NULL;
+       Mutex_Acquire(&Disk->lNodeCache);
+       
+       for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
+       {
+               if( cnode->Node.Inode == Node->Inode ) {
+                       cnode->Node.ReferenceCount ++;
+                       Mutex_Release(&Disk->lNodeCache);
+                       return &cnode->Node;
+               }
+       }
+       
+       cnode = malloc(sizeof(tFAT_CachedNode));
+       cnode->Next = NULL;
+       memcpy(&cnode->Node, Node, sizeof(tVFS_Node));
+       cnode->Node.ReferenceCount = 1;
+       
+       if( prev )
+               prev->Next = cnode;
+       else
+               Disk->NodeCache = cnode;
+       
+       Mutex_Release(&Disk->lNodeCache);
+       return &cnode->Node;
+}
+
+int FAT_int_DerefNode(tVFS_Node *Node)
+{
+       tFAT_VolInfo    *Disk = Node->ImplPtr;
+       tFAT_CachedNode *cnode, *prev = NULL;
+        int    bFreed = 0;
+
+       if( Node == &Disk->rootNode )
+               return 0;
+
+       Mutex_Acquire(&Disk->lNodeCache);
+       Node->ReferenceCount --;
+       for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
+       {
+               if(Node == &cnode->Node) {
+                       if(prev)
+                               prev->Next = cnode->Next;
+                       else
+                               Disk->NodeCache = cnode->Next;
+                       break;
+               }
+       }
+       if(Node->ReferenceCount == 0 && cnode) {
+               // Already out of the list :)
+               free(cnode->Node.Data);
+               free(cnode);
+               bFreed = 1;
+       }
+       Mutex_Release(&Disk->lNodeCache);
+       if( !cnode ) {
+               // Not here?
+               return -1;
+       }
+       
+       return bFreed;
+}
+
+void FAT_int_ClearNodeCache(tFAT_VolInfo *Disk)
+{
+       // TODO: In theory when this is called, all handles will be closed
+}
index 3ac0735..6751147 100644 (file)
@@ -36,3 +36,13 @@ Dir "Apps" {
                }
        }
 }
+#$Dir "Keen5" {
+#      File "keen5e" "/home/tpg/Projects/AcessPorts/omnispeak/bin/keen5e"
+#      File "EGADICT.CK5"  "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/EGADICT.CK5"
+#      File "EGAGRAPH.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/EGAGRAPH.CK5"
+#      File "EGAHEAD.CK5"  "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/EGAHEAD.CK5"
+#      File "GAMEMAPS.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/GAMEMAPS.CK5"
+#      File "GFXINFOE.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/GFXINFOE.CK5"
+#      File "MAPHEAD.CK5"  "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/MAPHEAD.CK5"
+#      File "TILEINFO.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/TILEINFO.CK5"
+#}
index 7cb8e0a..090e4c0 100644 (file)
@@ -69,7 +69,7 @@ void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
 {
        tInterface      *iface;
        tIPv6Header     *hdr = Buffer;
-        int    ret, dataLength;
+        int    ret;
        char    *dataPtr;
        Uint8   nextHeader;
        
@@ -105,7 +105,6 @@ void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
        // Process Options
        nextHeader = hdr->NextHeader;
        dataPtr = hdr->Data;
-       dataLength = hdr->PayloadLength;
        for( ;; )
        {
                struct {
index 3dcd294..c4f716f 100644 (file)
@@ -114,8 +114,6 @@ int Link_HandlePacket(tAdapter *Adapter, tIPStackBuffer *Buffer)
        void    *data = IPStack_Buffer_CompactBuffer(Buffer, &len);
        
        tEthernetHeader *hdr = (void*)data;
-        int    i;
-       Uint32  checksum;
 
        if(len < sizeof(tEthernetHeader)) {
                Log_Log("Net Link", "Recieved an undersized packet (%i < %i)",
@@ -133,11 +131,12 @@ int Link_HandlePacket(tAdapter *Adapter, tIPStackBuffer *Buffer)
                hdr->Dest.B[3], hdr->Dest.B[4], hdr->Dest.B[5],
                ntohs(hdr->Type)
                );
-       checksum = *(Uint32*)&hdr->Data[len-sizeof(tEthernetHeader)-4];
+//     Uint32 checksum = *(Uint32*)(data + len + 4);
        //Log_Log("NET", "Checksum 0x%08x", checksum);
        // TODO: Check checksum
        
        // Check if there is a registered callback for this packet type
+        int    i;
        for( i = giRegisteredTypes; i--; )
        {
                if(gaRegisteredTypes[i].Type == ntohs(hdr->Type))       break;
index 49e7777..f49d8ea 100644 (file)
@@ -29,7 +29,7 @@ extern void   Heap_Stats(void);
 
 // === PROTOTYPES ===
  int   Keyboard_Install(char **Arguments);
-void   Keyboard_Cleanup(void);
+ int   Keyboard_Cleanup(void);
 // - Internal
 tKeymap        *Keyboard_LoadMap(const char *Name);
 void   Keyboard_FreeMap(tKeymap *Keymap);
@@ -68,9 +68,10 @@ int Keyboard_Install(char **Arguments)
 /**
  * \brief Pre-unload cleanup function
  */
-void Keyboard_Cleanup(void)
+int Keyboard_Cleanup(void)
 {
        // TODO: Do I need this?
+       return 0;
 }
 
 // --- Map Management ---
index 5e6a9a2..56bf9b5 100644 (file)
@@ -15,7 +15,7 @@
 
 // === PROTOTYPES ===
  int   Mouse_Install(char **Arguments);
-void   Mouse_Cleanup(void);
+ int   Mouse_Cleanup(void);
 // - "User" side
 char   *Mouse_Root_ReadDir(tVFS_Node *Node, int Pos);
 tVFS_Node      *Mouse_Root_FindDir(tVFS_Node *Node, const char *Name);
@@ -62,8 +62,9 @@ int Mouse_Install(char **Arguments)
 /**
  * \brief Pre-unload cleanup function
  */
-void Mouse_Cleanup(void)
+int Mouse_Cleanup(void)
 {
+       return 0;
 }
 
 // --- VFS Interface ---
index 5576e8e..c106f77 100644 (file)
@@ -16,8 +16,9 @@ struct sLVM_VolType
 {
        const char *Name;
 
-       int     (*Read)(void *, Uint64, size_t, void *);
-       int     (*Write)(void *, Uint64, size_t, const void *);
+        int    (*Read)(void *, Uint64, size_t, void *);
+        int    (*Write)(void *, Uint64, size_t, const void *);
+       void    (*Cleanup)(void *);
 };
 
 
index 0bca233..b3b9c6c 100644 (file)
@@ -5,7 +5,7 @@
  * lvm.h
  * - LVM Core definitions
  */
-#define DEBUG  0
+#define DEBUG  1
 #define VERSION        VER2(0,1)
 #include "lvm_int.h"
 #include <fs_devfs.h>
@@ -15,7 +15,7 @@
 // === PROTOTYPES ===
 // ---
  int   LVM_Initialise(char **Arguments);
-void   LVM_Cleanup(void);
+ int   LVM_Cleanup(void);
 // ---
 char   *LVM_Root_ReadDir(tVFS_Node *Node, int ID);
 tVFS_Node      *LVM_Root_FindDir(tVFS_Node *Node, const char *Name);
@@ -60,9 +60,58 @@ int LVM_Initialise(char **Arguments)
        return 0;
 }
 
-void LVM_Cleanup(void)
+int LVM_Cleanup(void)
 {
+       // Attempt to destroy all volumes
+       tLVM_Vol        *vol, *prev = NULL, *next;
        
+       // TODO: Locks?
+       for( vol = gpLVM_FirstVolume; vol; prev = vol, vol = next )
+       {
+               next = vol->Next;
+                int    nFree = 0;
+               
+               for( int i = 0; i < vol->nSubVolumes; i ++ )
+               {
+                       tLVM_SubVolume  *sv;
+                       sv = vol->SubVolumes[i];
+                       if( sv == NULL ) {
+                               nFree ++;
+                               continue;
+                       }
+
+                       Mutex_Acquire(&sv->Node.Lock);
+                       if(sv->Node.ReferenceCount == 0) {
+                               nFree ++;
+                               vol->SubVolumes[i] = NULL;
+                       }
+                       Mutex_Release(&sv->Node.Lock);
+                       
+                       Mutex_Acquire(&sv->Node.Lock);
+                       LOG("Removed subvolume %s:%s", vol->Name, sv->Name);
+                       free(sv);
+               }
+               
+               if( nFree != vol->nSubVolumes )
+                       continue ;
+
+               if(prev)
+                       prev->Next = next;
+               else
+                       gpLVM_FirstVolume = next;
+
+               Mutex_Acquire(&vol->DirNode.Lock);
+               Mutex_Acquire(&vol->VolNode.Lock);
+               if( vol->Type->Cleanup )
+                       vol->Type->Cleanup( vol->Ptr );
+               LOG("Removed volume %s", vol->Name);
+               free(vol);
+       }
+
+       if( gpLVM_FirstVolume ) 
+               return EBUSY;
+       
+       return EOK;
 }
 
 // --------------------------------------------------------------------
index fafa1f3..c9ce9a8 100644 (file)
@@ -52,6 +52,7 @@ int LVM_AddVolume(const tLVM_VolType *Type, const char *Name, void *Ptr, size_t
        real_vol->Next = NULL;
        real_vol->Type = Type;
        real_vol->Ptr = Ptr;
+       real_vol->BlockSize = BlockSize;
        real_vol->BlockCount = BlockCount;
        real_vol->nSubVolumes = dummy_vol.nSubVolumes;
        real_vol->SubVolumes = (void*)( real_vol->Name + strlen(Name) + 1 );
index 6b38e65..dce7c33 100644 (file)
@@ -95,7 +95,6 @@ int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, i
        const int       ciMaxPacketSize = 0x400;
        struct sDeviceRequest   req;
         int    bToggle = 0;
-       void    *final;
         int    dest = Dev->Address*16 + Endpoint;
 
        ENTER("pDev xdest iType iIndex iLength pDest",
@@ -131,7 +130,7 @@ int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, i
 
        Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
        LOG("OUT (Status)");
-       final = Dev->Host->HostDef->ControlOUT(
+       Dev->Host->HostDef->ControlOUT(
                Dev->Host->Ptr, dest, 1,
                USB_int_WakeThread, Proc_GetCurThread(),
                NULL, 0
index 40231b4..94d258a 100644 (file)
@@ -14,7 +14,7 @@
 
 // === PROTOTYPES ===
  int   MSC_Initialise(char **Arguments);
-void   MSC_Cleanup(void);
+ int   MSC_Cleanup(void);
 void   MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen);
 void   MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data);
 // --- Internal Helpers
@@ -43,8 +43,9 @@ int MSC_Initialise(char **Arguments)
        return 0;
 }
 
-void MSC_Cleanup(void)
+int MSC_Cleanup(void)
 {
+       return 0;
 }
 
 void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen)
index cc8fda3..d7ab474 100644 (file)
@@ -252,6 +252,7 @@ void VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colou
        ch.BGCol  = (Colour & 0x0F0000) >> (16-8);
        ch.BGCol |= (Colour & 0x000F00) >> (8-4);
        ch.BGCol |= (Colour & 0x00000F);
+       ch.FGCol = 0;
        word = VGA_int_GetWord(&ch);
 
        Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
index f506599..e952a3a 100755 (executable)
@@ -12,6 +12,11 @@ _NETTYPE="user"
 
 while [ $# -ne 0 ]; do
        case $1 in
+       -raspberrypi)
+               _SYSTEM="versatilepb"
+               QEMU_PARAMS=$QEMU_PARAMS" -cpu arm1176 -m 192 -localtime"
+               _KERNEL=Acess2.armv6-raspberrypi.bin
+               ;;
        -gdb)
                QEMU_PARAMS=$QEMU_PARAMS" -s -S"
                ;;
@@ -31,7 +36,7 @@ while [ $# -ne 0 ]; do
        esac
        shift
 done
-QEMU_PARAMS="-M $_SYSTEM -kernel $_KERNEL -net nic -net $_NETTYPE"$QEMU_PARAMS
+QEMU_PARAMS="-M $_SYSTEM -kernel KernelLand/$_KERNEL -net nic -net $_NETTYPE"$QEMU_PARAMS
 
 #      /home/tpg/apps/bin/qemu-system-x86_64 $QEMU_PARAMS -serial stdio -serial file:QemuLog.txt
 #      qemu-system-x86_64 $QEMU_PARAMS -serial stdio | tee QemuLog.txt
diff --git a/Tools/DiskTool/src/Makefile b/Tools/DiskTool/src/Makefile
new file mode 100644 (file)
index 0000000..b232567
--- /dev/null
@@ -0,0 +1,102 @@
+
+TARGET := $(shell gcc -v 2>&1 | grep Targ | awk '{print $$2}')
+
+include ../../../Makefile.Version.cfg
+-include Makefile.BuildNum
+ifeq ($(BUILD_NUM),)
+BUILD_NUM = 1
+endif
+
+
+KERNEL_SRC = ../../../KernelLand/Kernel/
+MODULE_SRC = ../../../KernelLand/Modules/
+
+BIN = ../DiskTool
+# Kernel Sources (compiled with -ffreestanding)
+K_OBJ := lib.o
+K_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o
+K_OBJ += vfs/nodecache.o vfs/mount.o vfs/memfile.o # vfs/select.o
+K_OBJ += vfs/fs/root.o vfs/fs/devfs.o
+K_OBJ += drvutil_disk.o drv/proc.o
+# Modules
+MODULES := Storage/LVM Filesystems/FAT Filesystems/Ext2
+# Local kernel soruces (same as above, but located in same directory as Makefile)
+L_OBJ = vfs_handles.o threads.o nativefs.o time.o actions.o
+# Native Sources (compiled as usual)
+N_OBJ = main.o script.o logging.o helpers.o
+
+# Compilation Options
+CFLAGS := -Wall -std=gnu99 -g -Werror
+CPPFLAGS := -I include/
+K_CPPFLAGS := -I $(KERNEL_SRC)include -I $(MODULE_SRC)
+LDFLAGS += -Wl,--defsym,__buildnum=$(BUILD_NUM) -g
+
+BUILDINFO_OBJ := obj/$(TARGET)/buildinfo.o
+BUILDINFO_SRC := $(BUILDINFO_OBJ:%.o=%.c)
+
+# ====================
+# == Start of Magic ==
+# ====================
+# -- Load modules ---
+$(foreach module,$(MODULES), $(eval include $(MODULE_SRC)$(module)/Makefile) $(eval M_OBJ += $(addprefix $(module)/,$(OBJ))) )
+
+# -- Apply Prefixes to object paths
+OBJ_PREFIX = obj/$(TARGET)/
+K_OBJ_PREFIX = $(OBJ_PREFIX)_Kernel/
+M_OBJ_PREFIX = $(OBJ_PREFIX)_Module/
+K_OBJ := $(addprefix $(K_OBJ_PREFIX),$(K_OBJ))
+M_OBJ := $(addprefix $(M_OBJ_PREFIX),$(M_OBJ))
+L_OBJ := $(addprefix $(OBJ_PREFIX),$(L_OBJ))
+N_OBJ := $(addprefix $(OBJ_PREFIX),$(N_OBJ))
+
+OBJ := $(N_OBJ) $(L_OBJ) $(K_OBJ) $(M_OBJ) $(BUILDINFO_OBJ)
+
+DEPFILES  = $(filter %.o,$(OBJ))
+DEPFILES := $(DEPFILES:%=%.dep)
+
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+       $(RM) -f $(OBJ) $(DEPFILES) $(BIN)
+
+$(BIN): $(OBJ)
+       @echo [CC Link] -o $(BIN)
+       @$(CC) -o $(BIN) $(OBJ) $(LDFLAGS)
+       @echo BUILD_NUM = $$(( $(BUILD_NUM) + 1 )) > Makefile.BuildNum
+
+$(M_OBJ): $(M_OBJ_PREFIX)%.o: $(MODULE_SRC)%.c
+       @mkdir -p $(dir $@)
+       @echo [CC Module] -o $@
+       @$(CC) -c $< -o $@ -ffreestanding $(CFLAGS) $(CPPFLAGS) $(K_CPPFLAGS) -MMD -MP -MF [email protected]
+
+$(K_OBJ): $(K_OBJ_PREFIX)%.o: $(KERNEL_SRC)%.c
+       @mkdir -p $(dir $@)
+       @echo [CC Kernel] -o $@
+       @$(CC) -c $< -o $@ -ffreestanding $(CFLAGS) $(CPPFLAGS) $(K_CPPFLAGS) -MMD -MP -MF [email protected]
+
+$(L_OBJ): $(OBJ_PREFIX)%.o: %.c
+       @mkdir -p $(dir $@)
+       @echo [CC Local] -o $@
+       @$(CC) -c $< -o $@ -ffreestanding $(CFLAGS) $(CPPFLAGS) $(K_CPPFLAGS) -MMD -MP -MF [email protected]
+
+$(N_OBJ): $(OBJ_PREFIX)%.o: %.c
+       @mkdir -p $(dir $@)
+       @echo [CC Native] -o $@
+       @$(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS) -MMD -MP -MF [email protected]
+
+# Hacky buildinfo.c file
+$(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) Makefile
+       @echo "" > $@
+       @echo "const char gsKernelVersion[] = \"$(ACESS_VERSION)\";" >> $@
+       @echo "const char gsGitHash[] = \""`git log -n 1 | head -n 1 | awk '{print $$2}'`"\";" >> $@
+       @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@
+$(BUILDINFO_OBJ): $(BUILDINFO_SRC)
+       @echo [CC] -o $@
+       @$(CC) -o $@ -c $< $(CFLAGS) $(CPPFLAGS)
+
+$(OBJ): Makefile
+
+-include $(DEPFILES)
diff --git a/Tools/DiskTool/src/actions.c b/Tools/DiskTool/src/actions.c
new file mode 100644 (file)
index 0000000..377608d
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * actions.c
+ * - High level actions that call the VFS
+ * # Kernel-space compiled
+ */
+#include <acess.h>
+#include <disktool_common.h>
+#include <Storage/LVM/include/lvm.h>
+
+// === IMPORTS ===
+extern int     NativeFS_Install(char **Arguments);
+extern int     LVM_Cleanup(void);
+
+// === PROTOTYPES ===
+void   DiskTool_Initialise(void)       __attribute__((constructor(101)));
+void   DiskTool_Cleanup(void);
+ int   DiskTool_int_TranslateOpen(const char *File, int Mode);
+ int   DiskTool_LVM_Read(void *Handle, Uint64 Block, size_t BlockCount, void *Dest);
+ int   DiskTool_LVM_Write(void *Handle, Uint64 Block, size_t BlockCount, const void *Dest);
+void   DiskTool_LVM_Cleanup(void *Handle);
+
+// === GLOBALS ===
+tLVM_VolType   gDiskTool_VolumeType = {
+       .Name = "DiskTool",
+       .Read  = DiskTool_LVM_Read,
+       .Write = DiskTool_LVM_Write,
+       .Cleanup = DiskTool_LVM_Cleanup
+};
+
+// === CODE ===
+void DiskTool_Initialise(void)
+{
+       VFS_Init();
+       NativeFS_Install(NULL);
+       VFS_MkDir("/Native");
+       VFS_Mount("/", "/Native", "nativefs", "");
+}
+
+void DiskTool_Cleanup(void)
+{
+        int    vfs_rv, lvm_rv;
+        int    nNochangeLoop = 0;
+       // Unmount all
+       do {
+               lvm_rv = LVM_Cleanup();
+               vfs_rv = VFS_UnmountAll();
+               Log_Debug("DiskTool", "Unmounted %i volumes", vfs_rv);
+               if( vfs_rv == 0 && lvm_rv == 0 ) {
+                       nNochangeLoop ++;
+                       if(nNochangeLoop == 2) {
+                               Log_Error("DiskTool", "Possible handle leak");
+                               break;
+                       }
+               }
+               else {
+                       nNochangeLoop = 0;
+               }
+       }
+       while( vfs_rv >= 0 || lvm_rv != 0 );
+}
+
+int DiskTool_RegisterLVM(const char *Identifier, const char *Path)
+{
+       int fd = DiskTool_int_TranslateOpen(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);
+       if(fd == -1)
+               return -1;
+       VFS_Seek(fd, 0, SEEK_END);
+       LVM_AddVolume( &gDiskTool_VolumeType, Identifier, (void*)(tVAddr)fd, 512, VFS_Tell(fd)/512);
+       return 0;
+}
+
+int DiskTool_MountImage(const char *Identifier, const char *Path)
+{
+       // Validate Identifier and make mountpoint string
+       char mountpoint[sizeof("/Mount/") + strlen(Identifier) + 1];
+       strcpy(mountpoint, "/Mount/");
+       strcat(mountpoint, Identifier);
+       
+       // Translate path       
+       size_t tpath_len = DiskTool_int_TranslatePath(NULL, Path);
+       if(tpath_len == -1)
+               return -1;
+       char tpath[tpath_len-1];
+       DiskTool_int_TranslatePath(tpath, Path);
+       
+       // Call mount
+       VFS_MkDir(mountpoint);
+       // TODO: Detect filesystem?
+       return VFS_Mount(tpath, mountpoint, "fat", "");
+}
+
+int DiskTool_Copy(const char *Source, const char *Destination)
+{
+       int src = DiskTool_int_TranslateOpen(Source, VFS_OPENFLAG_READ);
+       if( src == -1 ) {
+               Log_Error("DiskTool", "Unable to open %s for reading", Source);
+               return -1;
+       }
+       int dst = DiskTool_int_TranslateOpen(Destination, VFS_OPENFLAG_WRITE|VFS_OPENFLAG_CREATE);
+       if( dst == -1 ) {
+               Log_Error("DiskTool", "Unable to open %s for writing", Destination);
+               VFS_Close(src);
+               return -1;
+       }
+
+       char    buf[1024];
+       size_t  len, total = 0;
+       while( (len = VFS_Read(src, sizeof(buf), buf)) == sizeof(buf) ) {
+               VFS_Write(dst, len, buf);
+               total += len;
+       }
+       VFS_Write(dst, len, buf), total += len;
+
+       Log_Notice("DiskTool", "Copied %i from %s to %s", total, Source, Destination);
+
+       VFS_Close(dst);
+       VFS_Close(src);
+       
+       return 0;
+}
+
+int DiskTool_ListDirectory(const char *Directory)
+{
+       int fd = DiskTool_int_TranslateOpen(Directory, VFS_OPENFLAG_READ|VFS_OPENFLAG_DIRECTORY);
+       if(fd == -1) {
+//             fprintf(stderr, "Can't open '%s'\n", Directory);
+               return -1;
+       }
+
+       Log("Directory listing of '%s'", Directory);    
+
+       char    name[256];
+       while( VFS_ReadDir(fd, name) )
+       {
+               Log("- %s", name);
+       }
+       
+       VFS_Close(fd);
+       
+       return 0;
+}
+
+int DiskTool_LVM_Read(void *Handle, Uint64 Block, size_t BlockCount, void *Dest)
+{
+       VFS_ReadAt( (int)(tVAddr)Handle, Block*512, BlockCount*512, Dest);
+       return 0;
+}
+int DiskTool_LVM_Write(void *Handle, Uint64 Block, size_t BlockCount, const void *Dest)
+{
+       VFS_WriteAt( (int)(tVAddr)Handle, Block*512, BlockCount*512, Dest);
+       return 0;
+}
+void DiskTool_LVM_Cleanup(void *Handle)
+{
+       VFS_Close( (int)(tVAddr)Handle );
+}
+
+// --- Internal helpers ---
+int DiskTool_int_TranslateOpen(const char *File, int Flags)
+{
+       size_t tpath_len = DiskTool_int_TranslatePath(NULL, File);
+       if(tpath_len == -1)
+               return -1;
+       char tpath[tpath_len-1];
+       DiskTool_int_TranslatePath(tpath, File);
+
+       return VFS_Open(tpath, Flags);
+}
+
diff --git a/Tools/DiskTool/src/helpers.c b/Tools/DiskTool/src/helpers.c
new file mode 100644 (file)
index 0000000..f326677
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * helpers.c
+ */
+#include <stdlib.h>
+#include <acess_logging.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+
+// === GLOBALS ===
+char   gsWorkingDirectory[1024];
+
+
+// === CODE ===
+size_t DiskTool_int_TranslatePath(char *Buffer, const char *Path)
+{
+        int    len;
+       const char *colon = strchr(Path, ':');
+
+       if( Path[0] == '#' )
+       {
+               if(Buffer)
+                       strcpy(Buffer, Path+1);
+               return strlen(Path) - 1;
+       }
+       
+       if( colon )
+       {
+               const char *pos;
+               for(pos = Path; pos < colon; pos ++)
+               {
+                       if( !isalpha(*pos) )
+                               goto native_path;
+               }
+               
+               len = strlen("/Mount/");
+               len += strlen(Path);
+               if( Buffer ) {
+                       strcpy(Buffer, "/Mount/");
+                       strncat(Buffer+strlen("/Mount/"), Path, colon - Path);
+                       strcat(Buffer, colon + 1);
+               }
+               return len;
+       }
+       
+native_path:
+
+       if( !gsWorkingDirectory[0] ) {  
+               getcwd(gsWorkingDirectory, 1024);
+       }
+
+       len = strlen("/Native");
+       len += strlen( gsWorkingDirectory ) + 1;
+       len += strlen(Path);
+       if( Buffer ) {
+               strcpy(Buffer, "/Native");
+               strcat(Buffer, gsWorkingDirectory);
+               strcat(Buffer, "/");
+               strcat(Buffer, Path);
+       }
+       return len;
+}
diff --git a/Tools/DiskTool/src/include/acess.h b/Tools/DiskTool/src/include/acess.h
new file mode 100644 (file)
index 0000000..16009a4
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Acess2 DiskTool utility
+ * - By John Hodge (thePowersGang)
+ *
+ * include/acess.h
+ * - Mock kernel core header
+ */
+#ifndef _DISKTOOL__ACESS_H_
+#define _DISKTOOL__ACESS_H_
+
+#define        CONCAT(x,y) x ## y
+#define EXPAND_CONCAT(x,y) CONCAT(x,y)
+#define STR(x) #x
+#define EXPAND_STR(x) STR(x)
+
+#define ASSERT(x)      do{}while(0)
+
+extern char    __buildnum[];
+#define BUILD_NUM      ((int)(Uint)&__buildnum)
+extern const char gsGitHash[];
+
+#define BITS   32
+#define NULL   ((void*)0)
+#include <stdint.h>
+
+typedef uintptr_t      Uint;
+//typedef unsigned int size_t;
+#include <stddef.h>
+typedef uint64_t       off_t;
+typedef char   BOOL;
+
+
+typedef uint8_t        Uint8;
+typedef uint16_t       Uint16;
+typedef uint32_t       Uint32;
+typedef uint64_t       Uint64;
+
+typedef int8_t Sint8;
+typedef int16_t        Sint16;
+typedef int32_t        Sint32;
+typedef int64_t        Sint64;
+
+typedef uintptr_t      tVAddr;
+typedef uint32_t       tPAddr;
+
+typedef uint32_t       tUID;
+typedef uint32_t       tGID;
+typedef uint32_t       tTID;
+
+// NOTE: Since this is single-threaded (for now) mutexes can be implimented as simple locks
+typedef char   tMutex;
+typedef char   tShortSpinlock;
+
+typedef int64_t        tTime;
+extern tTime   now(void);
+extern int64_t timestamp(int sec, int min, int hr, int day, int month, int year);
+extern void    format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
+
+#define PACKED __attribute__((packed))
+#define DEPRECATED
+#define EXPORT(s)
+#define EXPORTV(s)
+
+#include <vfs_ext.h>
+
+// These are actually library functions, but they can't be included, so they're defined manually
+extern void    *malloc(size_t bytes);
+extern void    *calloc(size_t nmemb, size_t size);
+extern void    *realloc(void *oldptr, size_t bytes);
+extern void    free(void *buffer);
+
+#include <errno.h>
+#include <acess_logging.h>
+
+// Threads
+extern int     *Threads_GetErrno(void);
+//extern tPGID Threads_GetPGID(void);
+//extern tPID  Threads_GetPID(void);
+extern tTID    Threads_GetTID(void);
+extern tUID    Threads_GetUID(void);
+extern tGID    Threads_GetGID(void);
+
+// Kinda hacky way of not colliding with native errno
+#define errno  (*(Threads_GetErrno()))
+
+/**
+ * \name Endianness Swapping
+ * \{
+ */
+#ifdef __BIG_ENDIAN__
+#define        LittleEndian16(_val)    SwapEndian16(_val)
+#define        LittleEndian32(_val)    SwapEndian32(_val)
+#define        LittleEndian64(_val)    SwapEndian32(_val)
+#define        BigEndian16(_val)       (_val)
+#define        BigEndian32(_val)       (_val)
+#define        BigEndian64(_val)       (_val)
+#else
+#define        LittleEndian16(_val)    (_val)
+#define        LittleEndian32(_val)    (_val)
+#define        LittleEndian64(_val)    (_val)
+#define        BigEndian16(_val)       SwapEndian16(_val)
+#define        BigEndian32(_val)       SwapEndian32(_val)
+#define        BigEndian64(_val)       SwapEndian64(_val)
+#endif
+extern Uint16  SwapEndian16(Uint16 Val);
+extern Uint32  SwapEndian32(Uint32 Val);
+extern Uint64  SwapEndian64(Uint64 Val);
+/**
+ * \}
+ */
+
+
+#include <string.h>
+extern int     strucmp(const char *s1, const char *s2);
+extern int     strpos(const char *Str, char Ch);
+extern void    itoa(char *buf, uint64_t num, int base, int minLength, char pad);
+extern int     snprintf(char *buf, size_t len, const char *fmt, ...);
+extern int     sprintf(char *buf, const char *fmt, ...);
+extern int     ReadUTF8(const Uint8 *str, Uint32 *Val);
+extern int     WriteUTF8(Uint8 *str, Uint32 Val);
+#define CheckString(str)       (1)
+#define CheckMem(mem,sz)       (1)
+#include <ctype.h>
+
+// TODO: Move out?
+extern int     DivUp(int value, int divisor);
+extern uint64_t        DivMod64U(uint64_t Num, uint64_t Den, uint64_t *Rem);
+
+static inline int Mutex_Acquire(tMutex *m) {
+       if(*m)  Log_KernelPanic("---", "Double mutex lock");
+       *m = 1;
+       return 0;
+}
+static inline void Mutex_Release(tMutex *m) { *m = 0; }
+
+static inline void SHORTLOCK(tShortSpinlock *Lock) {
+       if(*Lock)       Log_KernelPanic("---", "Double short lock");
+       *Lock = 1;
+}
+static inline void SHORTREL(tShortSpinlock *m) { *m = 0; }
+
+#endif
+
diff --git a/Tools/DiskTool/src/include/acess_logging.h b/Tools/DiskTool/src/include/acess_logging.h
new file mode 100644 (file)
index 0000000..f8577dd
--- /dev/null
@@ -0,0 +1,34 @@
+
+#ifndef _DISKTOOL__ACESS_LOGGING_H_
+#define _DISKTOOL__ACESS_LOGGING_H_
+
+#if DEBUG
+# define ENTER(str, v...)      Debug_TraceEnter(__func__, str, ##v)
+# define LOG(fmt, v...)        Debug_TraceLog(__func__, fmt, ##v)
+# define LEAVE(t, v...)        Debug_TraceLeave(__func__, t, ##v)
+# define LEAVE_RET(t,v)        do{LEAVE('-');return v;}while(0)
+#else
+# define ENTER(...)    do{}while(0)
+# define LOG(...)      do{}while(0)
+# define LEAVE(...)    do{}while(0)
+# define LEAVE_RET(t,v)        return v;
+#endif
+
+extern void    Log_KernelPanic(const char *Ident, const char *Message, ...) __attribute__((noreturn));
+extern void    Log_Panic(const char *Ident, const char *Message, ...);
+extern void    Log_Error(const char *Ident, const char *Message, ...);
+extern void    Log_Warning(const char *Ident, const char *Message, ...);
+extern void    Log_Notice(const char *Ident, const char *Message, ...);
+extern void    Log_Log(const char *Ident, const char *Message, ...);
+extern void    Log_Debug(const char *Ident, const char *Message, ...);
+
+extern void    Warning(const char *Message, ...);
+extern void    Log(const char *Message, ...);
+extern void    Debug_HexDump(const char *Prefix, const void *Data, size_t Length);
+
+extern void    Debug_TraceEnter(const char *Function, const char *Format, ...);
+extern void    Debug_TraceLog(const char *Function, const char *Format, ...);
+extern void    Debug_TraceLeave(const char *Function, char Type, ...);
+
+#endif
+
diff --git a/Tools/DiskTool/src/include/arch.h b/Tools/DiskTool/src/include/arch.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tools/DiskTool/src/include/disktool_common.h b/Tools/DiskTool/src/include/disktool_common.h
new file mode 100644 (file)
index 0000000..bd30b01
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ * 
+ * include/disktool_common.h
+ * - DiskTool internal API between native and kernel code
+ */
+#ifndef _INCLUDE__DISKTOOL_COMMON_H_
+#define _INCLUDE__DISKTOOL_COMMON_H_
+
+extern void    DiskTool_Cleanup(void);
+
+extern int     DiskTool_RegisterLVM(const char *Identifier, const char *Path);
+extern int     DiskTool_MountImage(const char *Identifier, const char *Path);
+extern int     DiskTool_Copy(const char *Source, const char *Destination);
+extern int     DiskTool_ListDirectory(const char *Directory);
+
+extern size_t  DiskTool_int_TranslatePath(char *Buffer, const char *Path);
+
+#endif
+
diff --git a/Tools/DiskTool/src/include/modules.h b/Tools/DiskTool/src/include/modules.h
new file mode 100644 (file)
index 0000000..c940c10
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * include/modules.h
+ * - Reimplimentation of kernel module interface for POSIX userland
+ */
+#ifndef _INCLUDE__MODULES_H_
+#define _INCLUDE__MODULES_H_
+
+enum
+{
+       MODULE_ERR_OK,
+};
+
+#define MODULE_DEFINE(flags, version, name, init, deinit, deps...) \
+void __init_##init(void) __attribute__((constructor(200))); void __init_##init(void){init(NULL);}
+
+#endif
+
diff --git a/Tools/DiskTool/src/include/rwlock.h b/Tools/DiskTool/src/include/rwlock.h
new file mode 100644 (file)
index 0000000..b9ff514
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Acess2 Disk Tool
+ */
+#ifndef _RWLOCK_H
+#define _RWLOCK_H
+
+typedef char   tRWLock;
+
+static inline int RWLock_AcquireRead(tRWLock *m) {
+       if(*m)  Log_KernelPanic("---", "Double mutex lock");
+       *m = 1;
+       return 0;
+}
+static inline int RWLock_AcquireWrite(tRWLock *m) {
+       if(*m)  Log_KernelPanic("---", "Double mutex lock");
+       *m = 1;
+       return 0;
+}
+static inline void RWLock_Release(tRWLock *m) { *m = 0; }
+
+#endif
+
diff --git a/Tools/DiskTool/src/logging.c b/Tools/DiskTool/src/logging.c
new file mode 100644 (file)
index 0000000..fde9055
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <acess_logging.h>
+#include <ctype.h>
+
+#define LOGHDR(col,type)       fprintf(stderr, "\e["col"m[%-8.8s]"type" ", Ident)
+#define LOGTAIL()      fprintf(stderr, "\e[0m\n")
+
+#define PUTERR(col,type)       {\
+       LOGHDR(col,type);\
+       va_list args; va_start(args, Message);\
+       vfprintf(stderr, Message, args);\
+       va_end(args);\
+       LOGTAIL();\
+}
+
+// === CODE ===
+void Log_KernelPanic(const char *Ident, const char *Message, ...) {
+       PUTERR("35", "k")
+       exit(-1);
+}
+void Log_Panic(const char *Ident, const char *Message, ...)
+       PUTERR("34", "p")
+void Log_Error(const char *Ident, const char *Message, ...)
+       PUTERR("31", "e")
+void Log_Warning(const char *Ident, const char *Message, ...)
+       PUTERR("33", "w")
+void Log_Notice(const char *Ident, const char *Message, ...)
+       PUTERR("32", "n")
+void Log_Log(const char *Ident, const char *Message, ...)
+       PUTERR("37", "l")
+void Log_Debug(const char *Ident, const char *Message, ...)
+       PUTERR("37", "d")
+
+void Warning(const char *Message, ...) {
+       const char *Ident = "";
+       PUTERR("33", "W")
+}
+void Log(const char *Message, ...) {
+       const char *Ident = "";
+       PUTERR("37", "L")
+}
+
+void Debug_HexDump(const char *Prefix, const void *Data, size_t Length)
+{
+       const uint8_t *data = Data;
+       size_t  ofs;
+       fprintf(stderr, "[HexDump ]d %s: %i bytes\n", Prefix, (int)Length);
+       for( ofs = 0; ofs + 16 <= Length; ofs += 16 )
+       {
+               fprintf(stderr, "[HexDump ]d %s:", Prefix);
+               fprintf(stderr, "  %02x %02x %02x %02x %02x %02x %02x %02x",
+                       data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+               data += 8;
+               fprintf(stderr, "  %02x %02x %02x %02x %02x %02x %02x %02x",
+                       data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+               data += 8;
+               fprintf(stderr, "\n");
+       }
+       
+       fprintf(stderr, "[HexDump ]d %s:", Prefix);
+       for( ; ofs < Length; ofs ++ )
+       {
+               if( ofs % 16 == 8 )     fprintf(stderr, " ");
+               fprintf(stderr, " %02x", data[ofs%16]);
+       }
+       fprintf(stderr, "\n");
+}
+
+ int   giDebug_TraceLevel = 0;
+
+void Debug_TraceEnter(const char *Function, const char *Format, ...)
+{
+       const char *Ident = "Trace";
+       LOGHDR("37","T");
+       for( int i = 0; i < giDebug_TraceLevel; i ++ )
+               fprintf(stderr, " ");
+       fprintf(stderr, "%s: (", Function);
+
+       va_list args;
+       va_start(args, Format);
+       
+       int hasBeenPrev = 0;
+       while(*Format)
+       {
+               while( *Format && isblank(*Format) )
+                       Format ++;
+               if( !*Format )  break;
+               
+               char type = *Format++;
+               const char *start = Format;
+               while( *Format && !isblank(*Format) )
+                       Format ++;
+               
+               if(hasBeenPrev)
+                       fprintf(stderr, ",");
+               hasBeenPrev = 1;
+               
+               fprintf(stderr, "%.*s=", (int)(Format-start), start);
+               switch(type)
+               {
+               case 'p':
+                       fprintf(stderr, "%p", va_arg(args,const void *));
+                       break;
+               case 's':
+                       fprintf(stderr, "\"%s\"", va_arg(args,const char *));
+                       break;
+               case 'i':
+                       fprintf(stderr, "%i", va_arg(args,int));
+                       break;
+               case 'x':
+                       fprintf(stderr, "0x%x", va_arg(args,unsigned int));
+                       break;
+               default:
+                       va_arg(args,uintptr_t);
+                       fprintf(stderr, "?");
+                       break;
+               }
+       }
+
+       va_end(args);
+
+       fprintf(stderr, ")");
+       LOGTAIL();
+       giDebug_TraceLevel ++;
+}
+
+void Debug_TraceLog(const char *Function, const char *Format, ...)
+{
+       const char *Ident = "Trace";
+       LOGHDR("37","T");
+       
+       for( int i = 0; i < giDebug_TraceLevel; i ++ )
+               fprintf(stderr, " ");
+       fprintf(stderr, "%s: ", Function);
+       
+       va_list args;
+       va_start(args, Format);
+
+       vfprintf(stderr, Format, args);
+       
+       va_end(args);
+       LOGTAIL();
+}
+
+void Debug_TraceLeave(const char *Function, char Type, ...)
+{
+       if( giDebug_TraceLevel == 0 ) {
+               Log_Error("Debug", "Function %s called LEAVE without ENTER", Function);
+       }
+       
+       const char *Ident = "Trace";
+       LOGHDR("37","T");
+       
+       va_list args;
+       va_start(args, Type);
+
+       if( giDebug_TraceLevel > 0 )
+       {       
+               giDebug_TraceLevel --;
+               for( int i = 0; i < giDebug_TraceLevel; i ++ )
+                       fprintf(stderr, " ");
+       }
+       fprintf(stderr, "%s: RETURN", Function);
+       switch(Type)
+       {
+       case '-':
+               break;
+       case 'i':
+               fprintf(stderr, " %i", va_arg(args, int));
+               break;
+       case 'x':
+               fprintf(stderr, " 0x%x", va_arg(args, unsigned int));
+               break;
+       case 's':
+               fprintf(stderr, " \"%s\"", va_arg(args, const char *));
+               break;
+       case 'p':
+               fprintf(stderr, " %p", va_arg(args, const void *));
+               break;
+       default:
+               fprintf(stderr, " ?");
+               break;
+       }
+       
+       va_end(args);
+       LOGTAIL();
+}
+
diff --git a/Tools/DiskTool/src/main.c b/Tools/DiskTool/src/main.c
new file mode 100644 (file)
index 0000000..823bb2b
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <disktool_common.h>
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+       // Parse arguments
+       for( int i = 1; i < argc; i ++ )
+       {
+               if( strcmp("mount", argv[i]) == 0 || strcmp("-i", argv[i]) == 0 ) {
+                       // Mount an image
+                       if( argc - i < 3 ) {
+                               fprintf(stderr, "--image/-i takes 2 arguments (ident and path)\n");
+                               exit(-1);
+                       }
+
+                       if( DiskTool_MountImage(argv[i+1], argv[i+2]) ) {
+                               fprintf(stderr, "Unable to mount '%s' as '%s'\n", argv[i+2], argv[i+1]);
+                               break;
+                       }
+
+                       i += 2;
+                       continue ;
+               }
+               
+               if( strcmp("mountlvm", argv[i]) == 0 ) {
+                       
+                       if( argc - i < 3 ) {
+                               fprintf(stderr, "mountlvm takes 2 arguments (ident and path)\n");
+                               exit(-1);
+                       }
+
+                       if( DiskTool_RegisterLVM(argv[i+1], argv[i+2]) ) {
+                               fprintf(stderr, "Unable to register '%s' as LVM '%s'\n", argv[i+2], argv[i+1]);
+                               break;
+                       }
+                       
+                       i += 2;
+                       continue ;
+               }
+               
+               if( strcmp("ls", argv[i]) == 0 ) {
+                       if( argc - i < 2 ) {
+                               fprintf(stderr, "ls 1 argument (path)\n");
+                               break;
+                       }
+
+                       DiskTool_ListDirectory(argv[i+1]);
+                       i += 1;
+                       continue ;
+               }
+               
+               if( strcmp("cp", argv[i]) == 0 ) {
+                       
+                       if( argc - i < 3 ) {
+                               fprintf(stderr, "cp takes 2 arguments (source and destination)\n");
+                               break;
+                       }
+
+                       DiskTool_Copy(argv[i+1], argv[i+2]);                    
+
+                       i += 2;
+                       continue ;
+               }
+       }
+       
+       DiskTool_Cleanup();
+       
+       return 0;
+}
+
+// NOTE: This is in a native compiled file because it needs access to the real errno macro
+int *Threads_GetErrno(void)
+{
+       return &errno;
+}
+
+// TODO: Move into a helper lib?
+void itoa(char *buf, uint64_t num, int base, int minLength, char pad)
+{
+       char fmt[] = "%0ll*x";
+       switch(base)
+       {
+       case  8:        fmt[5] = 'o';   break;
+       case 10:        fmt[5] = 'd';   break;
+       case 16:        fmt[5] = 'x';   break;
+       }
+       if(pad != '0') {
+               fmt[1] = '%';
+               sprintf(buf, fmt+1, minLength, num);
+       }
+       else {
+               sprintf(buf, fmt, minLength, num);
+       }
+}
+
+int strpos(const char *Str, char Ch)
+{
+       const char *r = strchr(Str, Ch);
+       if(!r)  return -1;
+       return r - Str;
+}
+
+int strucmp(const char *s1, const char *s2)
+{
+       return strcasecmp(s1, s2);
+}
+
+uint64_t DivMod64U(uint64_t value, uint64_t divisor, uint64_t *remainder)
+{
+       if(remainder)
+               *remainder = value % divisor;
+       return value / divisor;
+}
+
diff --git a/Tools/DiskTool/src/nativefs.c b/Tools/DiskTool/src/nativefs.c
new file mode 120000 (symlink)
index 0000000..164ccfc
--- /dev/null
@@ -0,0 +1 @@
+../../../AcessNative/acesskernel_src/nativefs.c
\ No newline at end of file
diff --git a/Tools/DiskTool/src/script.c b/Tools/DiskTool/src/script.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tools/DiskTool/src/threads.c b/Tools/DiskTool/src/threads.c
new file mode 100644 (file)
index 0000000..79ec4c6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 
+ */
+#include <acess.h>
+#include <threads.h>
+
+// === CODE ===
+tThread *Proc_GetCurThread(void)
+{
+       return NULL;
+}
+
+void Threads_PostEvent(tThread *Thread, Uint32 Events)
+{
+       
+}
+
+Uint32 Threads_WaitEvents(Uint32 Events)
+{
+       Log_KernelPanic("Threads", "Can't use _WaitEvents in DiskTool");
+       return 0;
+}
+
+void Threads_ClearEvent(Uint32 Mask)
+{
+       
+}
+
+tUID Threads_GetUID(void) { return 0; }
+tGID Threads_GetGID(void) { return 0; }
+
+int *Threads_GetMaxFD(void) { static int max_fd=32; return &max_fd; }
+char **Threads_GetCWD(void) { static char *cwd; return &cwd; }
+char **Threads_GetChroot(void) { static char *chroot; return &chroot; }
+
diff --git a/Tools/DiskTool/src/time.c b/Tools/DiskTool/src/time.c
new file mode 100644 (file)
index 0000000..445b04b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ * 
+ * time.c
+ * - Timing functions (emulated)
+ */
+#include <acess.h>
+#include <timers.h>
+
+// === CODE ===
+tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument)
+{
+       return NULL;
+}
+
+void Time_ScheduleTimer(tTimer *Timer, int Delta)
+{
+       
+}
+
+void Time_FreeTimer(tTimer *Timer)
+{
+       
+}
+
+Sint64 now(void)
+{
+       // TODO: Translate UNIX time into Acess time
+       return 0;
+}
+
diff --git a/Tools/DiskTool/src/vfs_handles.c b/Tools/DiskTool/src/vfs_handles.c
new file mode 100644 (file)
index 0000000..4f30151
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 
+ */
+#include <acess.h>
+#include <vfs.h>
+#include <vfs_int.h>
+
+#define MAX_KERNEL_FILES       32
+
+// === GLOBALS ===
+tVFS_Handle    gaKernelHandles[MAX_KERNEL_FILES];
+
+// === CODE ===
+int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
+{
+       for( int i = 0; i < MAX_KERNEL_FILES; i ++ )
+       {
+               if(gaKernelHandles[i].Node)     continue;
+               gaKernelHandles[i].Node = Node;
+               gaKernelHandles[i].Position = 0;
+               gaKernelHandles[i].Mode = Mode;
+               return i;
+       }       
+
+       return -1;
+}
+
+tVFS_Handle *VFS_GetHandle(int ID)
+{
+       if( ID < 0 || ID >= MAX_KERNEL_FILES )
+               return NULL;
+       return &gaKernelHandles[ID];
+}
index 92f8984..b3648bb 100644 (file)
@@ -75,30 +75,40 @@ void IPC_Init(void)
         int    tmp;
        // TODO: Check this
        giNetworkFileHandle = open("/Devices/ip/loop/udp", OPENFLAG_READ);
-       tmp = AXWIN_PORT;       ioctl(giNetworkFileHandle, 4, &tmp);    // TODO: Don't hard-code IOCtl number
+       if( giNetworkFileHandle != -1 )
+       {
+               tmp = AXWIN_PORT;
+               ioctl(giNetworkFileHandle, 4, &tmp);    // TODO: Don't hard-code IOCtl number
+       }
 }
 
 void IPC_FillSelect(int *nfds, fd_set *set)
 {
-       if( giNetworkFileHandle > *nfds )       *nfds = giNetworkFileHandle;
-       FD_SET(giNetworkFileHandle, set);
+       if( giNetworkFileHandle != -1 )
+       {
+               if( giNetworkFileHandle > *nfds )       *nfds = giNetworkFileHandle;
+               FD_SET(giNetworkFileHandle, set);
+       }
 }
 
 void IPC_HandleSelect(fd_set *set)
 {
-       if( FD_ISSET(giNetworkFileHandle, set) )
+       if( giNetworkFileHandle != -1 )
        {
-               char    staticBuf[STATICBUF_SIZE];
-                int    readlen, identlen;
-               char    *msg;
-
-               readlen = read(giNetworkFileHandle, staticBuf, sizeof(staticBuf));
-               
-               identlen = 4 + Net_GetAddressSize( ((uint16_t*)staticBuf)[1] );
-               msg = staticBuf + identlen;
-
-               IPC_Handle(&gIPC_Type_Datagram, staticBuf, readlen - identlen, (void*)msg);
-//             _SysDebug("IPC_HandleSelect: UDP handled");
+               if( FD_ISSET(giNetworkFileHandle, set) )
+               {
+                       char    staticBuf[STATICBUF_SIZE];
+                        int    readlen, identlen;
+                       char    *msg;
+       
+                       readlen = read(giNetworkFileHandle, staticBuf, sizeof(staticBuf));
+                       
+                       identlen = 4 + Net_GetAddressSize( ((uint16_t*)staticBuf)[1] );
+                       msg = staticBuf + identlen;
+       
+                       IPC_Handle(&gIPC_Type_Datagram, staticBuf, readlen - identlen, (void*)msg);
+//                     _SysDebug("IPC_HandleSelect: UDP handled");
+               }
        }
 
        while(SysGetMessage(NULL, NULL))
index 3e6af58..5b513de 100644 (file)
@@ -34,13 +34,24 @@ void Video_Setup(void)
         int    tmpInt;
        
        // Open terminal
+       #if 0
        giTerminalFD = open(gsTerminalDevice, OPENFLAG_READ|OPENFLAG_WRITE);
        if( giTerminalFD == -1 )
        {
                fprintf(stderr, "ERROR: Unable to open '%s' (%i)\n", gsTerminalDevice, _errno);
                exit(-1);
        }
-       
+       #else
+       giTerminalFD = 1;
+       // Check that the console is a VT
+       // - ioctl(..., 0, NULL) returns the type, which should be 2
+       if( ioctl(1, 0, NULL) != 2 )
+       {
+               fprintf(stderr, "stdout is not an Acess VT, can't start");
+               _SysDebug("stdout is not an Acess VT, can't start");
+               exit(-1);
+       }
+       #endif
        
        // Set mode to video
        tmpInt = TERM_MODE_FB;
@@ -70,11 +81,12 @@ void Video_Update(void)
        
        if( giVideo_LastDirtyLine == 0 )        return; 
 
-//     _SysDebug("Video_Update - Updating lines %i to %i (0x%x+0x%x px)",
-//             giVideo_FirstDirtyLine, giVideo_LastDirtyLine, ofs, size);
+       _SysDebug("Video_Update - Updating lines %i to %i (0x%x+0x%x px)",
+               giVideo_FirstDirtyLine, giVideo_LastDirtyLine, ofs, size);
        seek(giTerminalFD, ofs*4, 1);
+       _SysDebug("Video_Update - Sending");
        write(giTerminalFD, gpScreenBuffer+ofs, size*4);
-//     _SysDebug("Video_Update - Done");
+       _SysDebug("Video_Update - Done");
        giVideo_FirstDirtyLine = 0;
        giVideo_LastDirtyLine = 0;
 }

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