--- /dev/null
+/*
+ * AcessMicro VFS
+ * - File IO Passthru's
+ */
+#include <acess.h>
+#include "vfs.h"
+#include "vfs_int.h"
+
+// === TYPES ===
+typedef struct sCachedInode {
+ struct sCachedInode *Next;
+ tVFS_Node Node;
+} tCachedInode;
+typedef struct sInodeCache {
+ struct sInodeCache *Next;
+ int Handle;
+ tCachedInode *FirstNode; // Sorted List
+ Uint64 MaxCached; // Speeds up Searching
+} tInodeCache;
+
+// === PROTOTYPES ===
+tInodeCache *Inode_int_GetFSCache(int Handle);
+
+// === GLOBALS ===
+ int gVFS_NextInodeHandle = 1;
+tShortSpinlock glVFS_InodeCache;
+tInodeCache *gVFS_InodeCache = NULL;
+
+// === CODE ===
+/**
+ * \fn int Inode_GetHandle()
+ */
+int Inode_GetHandle()
+{
+ tInodeCache *ent;
+
+ ent = malloc( sizeof(tInodeCache) );
+ ent->MaxCached = 0;
+ ent->Handle = gVFS_NextInodeHandle++;
+ ent->Next = NULL; ent->FirstNode = NULL;
+
+ // Add to list
+ SHORTLOCK( &glVFS_InodeCache );
+ ent->Next = gVFS_InodeCache;
+ gVFS_InodeCache = ent;
+ SHORTREL( &glVFS_InodeCache );
+
+ return gVFS_NextInodeHandle-1;
+}
+
+/**
+ * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
+ * \brief Gets a node from the cache
+ */
+tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
+{
+ tInodeCache *cache;
+ tCachedInode *ent;
+
+ cache = Inode_int_GetFSCache(Handle);
+ if(!cache) return NULL;
+
+ if(Inode > cache->MaxCached) return NULL;
+
+ // Search Cache
+ ent = cache->FirstNode;
+ for( ; ent; ent = ent->Next )
+ {
+ if(ent->Node.Inode < Inode) continue;
+ if(ent->Node.Inode > Inode) return NULL;
+ ent->Node.ReferenceCount ++;
+ return &ent->Node;
+ }
+
+ return NULL; // Should never be reached
+}
+
+/**
+ * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
+ */
+tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
+{
+ tInodeCache *cache;
+ tCachedInode *newEnt, *ent, *prev;
+
+ cache = Inode_int_GetFSCache(Handle);
+ if(!cache) return NULL;
+
+ if(Node->Inode > cache->MaxCached)
+ cache->MaxCached = Node->Inode;
+
+ // Search Cache
+ ent = cache->FirstNode;
+ prev = (tCachedInode*) &cache->FirstNode;
+ for( ; ent; prev = ent, ent = ent->Next )
+ {
+ if(ent->Node.Inode < Node->Inode) continue;
+ if(ent->Node.Inode == Node->Inode) {
+ ent->Node.ReferenceCount ++;
+ return &ent->Node;
+ }
+ break;
+ }
+
+ // Create new entity
+ newEnt = malloc(sizeof(tCachedInode));
+ newEnt->Next = ent;
+ memcpy(&newEnt->Node, Node, sizeof(tVFS_Node));
+ prev->Next = newEnt;
+
+ return &newEnt->Node;
+}
+
+/**
+ * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
+ * \brief Dereferences/Removes a cached node
+ */
+void Inode_UncacheNode(int Handle, Uint64 Inode)
+{
+ tInodeCache *cache;
+ tCachedInode *ent, *prev;
+
+ cache = Inode_int_GetFSCache(Handle);
+ if(!cache) return ;
+
+ if(Inode > cache->MaxCached) return ;
+
+ // Search Cache
+ ent = cache->FirstNode;
+ prev = (tCachedInode*) &cache->FirstNode; // Special case removal
+ 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)
+ {
+ 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);
+ }
+ return ;
+ }
+
+ return ;
+}
+
+/**
+ * \fn void Inode_ClearCache(int Handle)
+ * \brief Removes a cache
+ */
+void Inode_ClearCache(int Handle)
+{
+ tInodeCache *cache;
+ tInodeCache *prev = NULL;
+ tCachedInode *ent, *next;
+
+ // Find the cache
+ for(
+ cache = gVFS_InodeCache;
+ cache && cache->Handle < Handle;
+ prev = cache, cache = cache->Next
+ );
+ if(!cache || cache->Handle != Handle) return;
+
+ // Search Cache
+ ent = cache->FirstNode;
+ while( ent )
+ {
+ ent->Node.ReferenceCount = 1;
+ next = ent->Next;
+
+ if(ent->Node.Type && ent->Node.Type->Close)
+ ent->Node.Type->Close( &ent->Node );
+ free(ent);
+
+ ent = next;
+ }
+
+ // Free Cache
+ if(prev == NULL)
+ gVFS_InodeCache = cache->Next;
+ else
+ prev->Next = cache->Next;
+ free(cache);
+}
+
+/**
+ * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
+ * \brief Gets a cache given it's handle
+ */
+tInodeCache *Inode_int_GetFSCache(int Handle)
+{
+ tInodeCache *cache = gVFS_InodeCache;
+ // Find Cache
+ for( ; cache; cache = cache->Next )
+ {
+ if(cache->Handle > Handle) continue;
+ if(cache->Handle < Handle) {
+ Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
+ return NULL;
+ }
+ break;
+ }
+ if(!cache) {
+ Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);
+ return NULL;
+ }
+
+ return cache;
+}