* fast cleanup when a filesystem is unmounted.
* \{
*/
+
+typedef struct sInodeCache tInodeCache;
+
+typedef void (*tInode_CleanUpNode)(tVFS_Node *Node);
+
/**
* \fn int Inode_GetHandle(void)
* \brief Gets a unique handle to the Node Cache
* \return A unique handle for use for the rest of the Inode_* functions
*/
-extern int Inode_GetHandle(void);
+extern tInodeCache *Inode_GetHandle(tInode_CleanUpNode CleanUpNode);
/**
* \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
* \brief Gets an inode from the node cache
* \param Inode Value of the Inode field of the ::tVFS_Node you want
* \return A pointer to the cached node
*/
-extern tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode);
+extern tVFS_Node *Inode_GetCache(tInodeCache *Handle, Uint64 Inode);
/**
* \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
* \brief Caches a node in the Node Cache
* \param Node A pointer to the node to be cached (a copy is taken)
* \return A pointer to the node in the node cache
*/
-extern tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node);
-extern tVFS_Node *Inode_CacheNodeEx(int Handle, tVFS_Node *Node, size_t Size);
+extern tVFS_Node *Inode_CacheNode(tInodeCache *Handle, tVFS_Node *Node);
+extern tVFS_Node *Inode_CacheNodeEx(tInodeCache *Handle, tVFS_Node *Node, size_t Size);
/**
* \fn int Inode_UncacheNode(int Handle, Uint64 Inode)
* \brief Dereferences (and removes if needed) a node from the cache
* \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 int Inode_UncacheNode(int Handle, Uint64 Inode);
+extern int Inode_UncacheNode(tInodeCache *Handle, Uint64 Inode);
/**
* \fn void Inode_ClearCache(int Handle)
* \brief Clears the cache for a handle
* \param Handle A handle returned by Inode_GetHandle()
*/
-extern void Inode_ClearCache(int Handle);
+extern void Inode_ClearCache(tInodeCache *Handle);
/**
* \}
struct sCachedInode *Next;
tVFS_Node Node;
} tCachedInode;
-typedef struct sInodeCache {
+struct sInodeCache
+{
struct sInodeCache *Next;
- int Handle;
+ tInode_CleanUpNode CleanUpNode;
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()
+
+// Create a new inode cache
+tInodeCache *Inode_GetHandle(tInode_CleanUpNode CleanUpNode)
{
tInodeCache *ent;
ent = malloc( sizeof(tInodeCache) );
ent->MaxCached = 0;
- ent->Handle = gVFS_NextInodeHandle++;
- ent->Next = NULL; ent->FirstNode = NULL;
+ ent->Next = NULL;
+ ent->FirstNode = NULL;
+ ent->CleanUpNode = CleanUpNode;
// Add to list
SHORTLOCK( &glVFS_InodeCache );
gVFS_InodeCache = ent;
SHORTREL( &glVFS_InodeCache );
- return ent->Handle;
+ return ent;
}
/**
* \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
* \brief Gets a node from the cache
*/
-tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
+tVFS_Node *Inode_GetCache(tInodeCache *Cache, Uint64 Inode)
{
- tInodeCache *cache;
tCachedInode *ent;
- cache = Inode_int_GetFSCache(Handle);
- if(!cache) return NULL;
-
- if(Inode > cache->MaxCached) return NULL;
+ if(Inode > Cache->MaxCached) return NULL;
// Search Cache
- ent = cache->FirstNode;
- for( ; ent; ent = ent->Next )
+ for( ent = Cache->FirstNode; ent; ent = ent->Next )
{
if(ent->Node.Inode < Inode) continue;
if(ent->Node.Inode > Inode) return NULL;
/**
* \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
*/
-tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
+tVFS_Node *Inode_CacheNode(tInodeCache *Handle, tVFS_Node *Node)
{
return Inode_CacheNodeEx(Handle, Node, sizeof(*Node));
}
-tVFS_Node *Inode_CacheNodeEx(int Handle, tVFS_Node *Node, size_t Size)
+tVFS_Node *Inode_CacheNodeEx(tInodeCache *Cache, tVFS_Node *Node, size_t Size)
{
- tInodeCache *cache;
- tCachedInode *newEnt, *ent, *prev = NULL;
+ tCachedInode *newEnt, *prev = NULL;
ASSERT(Size >= sizeof(tVFS_Node));
-
- cache = Inode_int_GetFSCache(Handle);
- if(!cache) return NULL;
- if(Node->Inode > cache->MaxCached)
- cache->MaxCached = Node->Inode;
+ if(Node->Inode > Cache->MaxCached)
+ Cache->MaxCached = Node->Inode;
// Search Cache
- ent = cache->FirstNode;
- for( ; ent; prev = ent, ent = ent->Next )
+ tCachedInode *ent;
+ for( ent = Cache->FirstNode; ent; prev = ent, ent = ent->Next )
{
if(ent->Node.Inode < Node->Inode) continue;
if(ent->Node.Inode == Node->Inode) {
if( prev )
prev->Next = newEnt;
else
- cache->FirstNode = newEnt;
+ Cache->FirstNode = newEnt;
newEnt->Node.ReferenceCount = 1;
LOG("Cached %llx as %p", Node->Inode, &newEnt->Node);
* \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
* \brief Dereferences/Removes a cached node
*/
-int Inode_UncacheNode(int Handle, Uint64 Inode)
+int Inode_UncacheNode(tInodeCache *Cache, Uint64 Inode)
{
- tInodeCache *cache;
tCachedInode *ent, *prev;
- cache = Inode_int_GetFSCache(Handle);
- if(!cache) {
- Log_Notice("Inode", "Invalid cache handle %i used", Handle);
- return -1;
- }
+ ENTER("pHandle XInode", Cache, Inode);
- ENTER("iHandle XInode", Handle, Inode);
-
- if(Inode > cache->MaxCached) {
+ if(Inode > Cache->MaxCached) {
LEAVE('i', -1);
return -1;
}
// Search Cache
- ent = cache->FirstNode;
prev = NULL;
- for( ; ent; prev = ent, ent = ent->Next )
+ for( ent = Cache->FirstNode; ent; prev = ent, ent = ent->Next )
{
if(ent->Node.Inode < Inode) continue;
if(ent->Node.Inode > Inode) {
if( prev )
prev->Next = ent->Next;
else
- cache->FirstNode = ent->Next;
- if(ent->Node.Inode == cache->MaxCached)
+ Cache->FirstNode = ent->Next;
+ if(ent->Node.Inode == Cache->MaxCached)
{
- if(ent != cache->FirstNode && prev)
- cache->MaxCached = prev->Node.Inode;
+ if(ent != Cache->FirstNode && prev)
+ Cache->MaxCached = prev->Node.Inode;
else
- cache->MaxCached = 0;
+ Cache->MaxCached = 0;
}
-
+
+ if(Cache->CleanUpNode)
+ Cache->CleanUpNode(&ent->Node);
if(ent->Node.Data)
free(ent->Node.Data);
free(ent);
* \fn void Inode_ClearCache(int Handle)
* \brief Removes a cache
*/
-void Inode_ClearCache(int Handle)
+void Inode_ClearCache(tInodeCache *Cache)
{
- 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;
+ for( prev = (void*)&gVFS_InodeCache; prev && prev->Next != Cache; prev = prev->Next )
+ ;
+ if( !prev ) {
+ // Oops?
+ return;
+ }
// Search Cache
- ent = cache->FirstNode;
- while( ent )
+ for( ent = Cache->FirstNode; ent; ent = next )
{
- ent->Node.ReferenceCount = 1;
next = ent->Next;
+ ent->Node.ReferenceCount = 1;
+ // Usually has the side-effect of freeing this node
+ // TODO: Ensure that node is freed
if(ent->Node.Type && ent->Node.Type->Close)
ent->Node.Type->Close( &ent->Node );
- free(ent);
-
- ent = next;
+ else
+ free(ent);
}
// Free Cache
if(prev == NULL)
- gVFS_InodeCache = cache->Next;
+ gVFS_InodeCache = Cache->Next;
else
- prev->Next = cache->Next;
- free(cache);
+ 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;
-}
//NTFS_DumpEntry(disk, 0); // $MFT
//NTFS_DumpEntry(disk, 3); // $VOLUME
- disk->InodeCache = Inode_GetHandle();
+ disk->InodeCache = Inode_GetHandle(NTFS_FreeNode);
disk->MFTDataAttr = NULL;
disk->MFTDataAttr = NTFS_GetAttrib(disk, 0, NTFS_FileAttrib_Data, "", 0);
tNTFS_FILE_Header *NTFS_GetMFT(tNTFS_Disk *Disk, Uint32 MFTEntry)
{
+ // TODO: Cache MFT allocation for short-term
+
+ //
tNTFS_FILE_Header *ret = malloc( Disk->MFTRecSize );
if(!ret) {
Log_Warning("FS_NTFS", "malloc() fail!");
if( attr->Type != Type )
continue;
if( Name ) {
- LOG("Name check = '%s'", Name);
+ if( attr->NameOffset + attr->NameLength*2 > attr->Size ) {
+ break;
+ }
const void *name16 = (char*)attr + attr->NameOffset;
+ LOG("Name check: '%s' == '%.*ls'",
+ Name, attr->NameLength, name16);
if( UTF16_CompareWithUTF8(attr->NameLength, name16, Name) != 0 )
continue ;
}
ASSERT(attr->NameOffset % 1 == 0);
Uint16 *name16 = (Uint16*)attr + attr->NameOffset/2;
size_t namelen = UTF16_ConvertToUTF8(0, NULL, attr->NameLength, name16);
- size_t edatalen = (attr->NonresidentFlag ? 0 : attr->Resident.AttribLen*4);
+ size_t edatalen = (attr->NonresidentFlag ? 0 : attr->Resident.AttribLen);
tNTFS_Attrib *ret = malloc( sizeof(tNTFS_Attrib) + namelen + 1 + edatalen );
if(!ret) {
- LEAVE('n');
- return NULL;
+ goto _error;
}
if( attr->NonresidentFlag )
ret->Name = (void*)(ret + 1);
{
ret->DataSize = edatalen;
memcpy(ret->ResidentData, (char*)attr + attr->Resident.AttribOfs, edatalen);
+ Debug_HexDump("GetAttrib Resident", ret->ResidentData, edatalen);
}
+ NTFS_ReleaseMFT(Disk, MFTEntry, hdr);
LEAVE('p', ret);
return ret;
}
+_error:
NTFS_ReleaseMFT(Disk, MFTEntry, hdr);
LEAVE('n');
return NULL;