Modules/NTFS - Implimentation progressing (ReadDir/FindDir appear to work)
authorJohn Hodge <[email protected]>
Sun, 23 Jun 2013 06:49:09 +0000 (14:49 +0800)
committerJohn Hodge <[email protected]>
Sun, 23 Jun 2013 06:49:09 +0000 (14:49 +0800)
KernelLand/Modules/Filesystems/NTFS/attributes.h
KernelLand/Modules/Filesystems/NTFS/common.h
KernelLand/Modules/Filesystems/NTFS/dir.c
KernelLand/Modules/Filesystems/NTFS/main.c
KernelLand/Modules/Filesystems/NTFS/ntfs.h

index b72588e..6afd912 100644 (file)
@@ -69,7 +69,7 @@ typedef struct sNTFS_Attrib_Filename
        } PACKED        Type;
 
        Uint8   FilenameLength; 
-       Uint8   FilenameNamespac      //!< Filename namespace (DOS, Windows, Unix)
+       Uint8   FilenameNamespace;      //!< Filename namespace (DOS, Windows, Unix)
        Uint16  Filename[0];
 } PACKED       tNTFS_Attrib_Filename;
 
index ac93b52..db117a6 100644 (file)
@@ -49,6 +49,8 @@ struct sNTFS_Disk
        
        tNTFS_Attrib    *MFTDataAttr;
        tNTFS_Attrib    *MFTBitmapAttr;
+
+        int    InodeCache;
        
        tNTFS_Directory RootDir;
 };
@@ -80,7 +82,12 @@ struct sNTFS_Attrib
        };
 };
 
+extern tVFS_NodeType   gNTFS_DirType;
+extern tVFS_NodeType   gNTFS_FileType;
+
 // -- MFT Access / Manipulation
+extern tNTFS_FILE_Header       *NTFS_GetMFT(tNTFS_Disk *Disk, Uint32 MFTEntry);
+extern void    NTFS_ReleaseMFT(tNTFS_Disk *Disk, Uint32 MFTEntry, tNTFS_FILE_Header *Entry);
 extern tNTFS_Attrib    *NTFS_GetAttrib(tNTFS_Disk *Disk, Uint32 MFTEntry, int Type, const char *Name, int DesIdx);
 extern size_t  NTFS_ReadAttribData(tNTFS_Attrib *Attrib, Uint64 Offset, size_t Length, void *Buffer);
 // -- dir.c
index 5066783..d7492d0 100644 (file)
@@ -8,7 +8,7 @@
  */
 #define DEBUG  1
 #include "common.h"
-#include "index.h"
+//#include "index.h"
 #include <utf16.h>
 
 // === PROTOTYPES ===
@@ -38,7 +38,7 @@ int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
                size_t len = sizeof(buf);
                struct sNTFS_IndexEntry_Filename *ent = (void*)(buf + len);
                
-               for(;;)
+               for( ; ; ent = (void*)((char*)ent + ent->EntrySize) )
                {
                        if( (char*)ent == buf + len ) {
                                if( len < sizeof(buf))
@@ -48,25 +48,42 @@ int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
                                //Debug_HexDump("NTFS_ReadDir", buf, sizeof(*hdr));
                                ent = (void*)(buf + (hdr->EntriesOffset + 0x18));
                        }
+                       // TODO: When end of node is hit, should the next cluster be loaded?
+                       if( ent->IndexFlags & 0x02 )
+                               break;
+                       // A little hacky - hide all internal files
+                       if( (ent->MFTReference & ((1ULL << 48)-1)) < 12 )
+                               continue;
                        if( Pos -- <= 0 )
                                break;
-                       LOG("ent = {.MFTEnt=%llx,.FilenameOfs=%x}", ent->MFTReference, ent->FilenameOfs);
+
+                       //LOG("ent = {.MFTEnt=%llx,.FilenameOfs=%x}", ent->MFTReference, ent->FilenameOfs);
+                       #if 0
                        //Uint16        *name16 = (Uint16*)ent + ent->FilenameOfs/2;
                        Uint16  *name16 = ent->Filename.Filename;
                        size_t  nlen = UTF16_ConvertToUTF8(0, NULL, ent->Filename.FilenameLength, name16);
                        char tmpname[ nlen+1 ];
                        UTF16_ConvertToUTF8(nlen+1, tmpname, ent->Filename.FilenameLength, name16);
-                       LOG("name = '%s'", tmpname);
-                       ent = (void*)((char*)ent + ent->EntrySize);
+                       LOG("name = %i '%s'", ent->Filename.FilenameNamespace, tmpname);
+                       #elif 0
+                       LOG("name = '%.*ls'", ent->Filename.FilenameLength, ent->Filename.Filename);
+                       #endif
                }
 
-               if( Pos < 0 )
-               {
-                       //Uint16        *name16 = (Uint16*)ent + ent->FilenameOfs/2;
-                       Uint16  *name16 = ent->Filename.Filename;
-                       UTF16_ConvertToUTF8(FILENAME_MAX, Dest, ent->Filename.FilenameLength, name16);
-                       return 0;
-               }
+               if( Pos >= 0 )
+                       return -1;
+               // Last entry does not refer to a file
+               if( ent->IndexFlags & 0x02 )
+                       return -1;
+               
+               if( ent->Filename.FilenameNamespace == NTFS_FilenameNamespace_DOS )
+                       return 1; 
+
+               //Uint16        *name16 = (Uint16*)ent + ent->FilenameOfs/2;
+               Uint16  *name16 = ent->Filename.Filename;
+               UTF16_ConvertToUTF8(FILENAME_MAX, Dest, ent->Filename.FilenameLength, name16);
+               LOG("Filename '%s'", Dest);
+               return 0;
        }
        else
        {
@@ -76,32 +93,139 @@ int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
        return -ENOTIMPL;
 }
 
+typedef int (*tNTFS_BTreeSearch_CmpFcn)(const tNTFS_IndexEntry_Filename *Ent, size_t SLen, const void *Search);
+
+int NTFS_BTreeSearch_CmpI30(const tNTFS_IndexEntry_Filename *Ent, size_t SLen, const void *Search)
+{
+       #if 0
+       size_t  fname_len = Ent->Filename.FilenameLength*2;
+       size_t  cmplen = MIN(fnamelen, SLen);
+       int ret = memcmp(Ent->Filename.Filename, Search, cmplen);
+       if( ret != 0 )
+               return ret;
+       if( cmplen < SLen )
+               return -1;
+       else if( cmplen == SLen )
+               return 0;
+       else
+               return 1;
+       #else
+       LOG("Cmp '%.*ls' == '%s'", Ent->Filename.FilenameLength, Ent->Filename.Filename, Search);
+//     return UTF16_CompareWithUTF8(Ent->Filename.FilenameLength, Ent->Filename.Filename, Search);
+       return UTF16_CompareWithUTF8CI(Ent->Filename.FilenameLength, Ent->Filename.Filename, Search);
+       #endif
+}
+
+Uint64 NTFS_BTreeSearch(size_t Length, tNTFS_IndexHeader *IndexHdr,
+       tNTFS_BTreeSearch_CmpFcn Cmp, size_t SLen, const void *Search)
+{
+       void    *buffer_end = (char*)IndexHdr + Length;
+       tNTFS_IndexEntry_Filename *ent = (void*)((char*)IndexHdr + IndexHdr->EntriesOffset + 0x18);
+       while( !(ent->IndexFlags & 0x02) )
+       {
+               if( (void*)(&ent->_rsvd + 1) > buffer_end ) {
+                       // on-disk error
+                       return 0;
+               }
+               // TODO: Handle collations?
+               int cmp = Cmp(ent, SLen, Search);
+               if( cmp == 0 ) {
+                       LOG("Located at %p: 0x%016llx", ent->MFTReference);
+                       return ent->MFTReference & ((1ULL << 48)-1);
+               }
+               if( cmp > 0 )
+                       break;
+               
+               ent = (void*)((char*)ent + ent->EntrySize);
+       }
+       if( ent->IndexFlags & 0x01 ) {
+               LOG("Descend to VCN %llx", *(Uint64*)((char*)ent + ent->EntrySize - 8));
+               return (1ULL << 63) | *(Uint64*)((char*)ent + ent->EntrySize - 8);
+       }
+       LOG("Not found");
+       return 0;
+}
+
+tVFS_Node *NTFS_int_CreateNode(tNTFS_Disk *Disk, Uint64 MFTEntry)
+{
+       tNTFS_FILE_Header       *ent = NTFS_GetMFT(Disk, MFTEntry);
+       if( !ent || !(ent->Flags & 0x01) )
+               return NULL;    
+
+       tVFS_Node       *ret;
+       size_t  size;
+       union {
+               tNTFS_Directory tpl_dir;
+               tNTFS_File      tpl_file;
+       } types;
+       memset(&types, 0, sizeof(tVFS_Node));
+       if( ent->Flags & 0x02 )
+       {
+               // Directory
+               size = sizeof(types.tpl_dir);
+               ret = &types.tpl_dir.Node;
+               ret->Type = &gNTFS_DirType;
+               ret->Flags = VFS_FFLAG_DIRECTORY;
+               
+               types.tpl_dir.I30Root = NTFS_GetAttrib(Disk, MFTEntry, NTFS_FileAttrib_IndexRoot, "$I30", 0);
+               types.tpl_dir.I30Allocation = NTFS_GetAttrib(Disk, MFTEntry, NTFS_FileAttrib_IndexAllocation, "$I30", 0);
+       }
+       else
+       {
+               // File
+               size = sizeof(types.tpl_file);
+               ret = &types.tpl_file.Node;
+               ret->Type = &gNTFS_FileType;
+               types.tpl_file.Data = NTFS_GetAttrib(Disk, MFTEntry, NTFS_FileAttrib_Data, "", 0); 
+       }
+       ret->Inode = MFTEntry;
+       ret->ImplPtr = Disk;
+
+       // TODO: Permissions
+       
+       NTFS_ReleaseMFT(Disk, MFTEntry, ent);
+       return Inode_CacheNodeEx(Disk->InodeCache, ret, size);
+}
+
 /**
  * \brief Get an entry from a directory by name
  */
 tVFS_Node *NTFS_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
 {
-       #if 0
        tNTFS_Directory *dir = (void*)Node;
        tNTFS_Disk      *disk = Node->ImplPtr;
        ASSERT(dir->I30Root->IsResident);
        const tNTFS_Attrib_IndexRoot    *idxroot = dir->I30Root->ResidentData;
 
+       #if 0
+       size_t  name16len = UTF16_ConvertFromUTF8(0, NULL, Name);
+       Uint16  name16[name16len+1];
+       UTF16_ConvertFromUTF8(name16len+1, name16, Name);
+       #endif
+
+       Uint64  mftent = 0;
        if( idxroot->Flags & 0x01 )
        {
-               char buf[disk->ClusterSize];
-               size_t len = NTFS_ReadAttribData(dir->I30Allocation, 0, sizeof(buf), buf);
-               struct sNTFS_IndexHeader *hdr = (void*)buf;
+               size_t  unit_len = MAX(disk->ClusterSize, 2048);
+               char buf[ unit_len ];
+               do {
+                       size_t ofs = (mftent & 0xFFFFFF) * unit_len;
+                       size_t len = NTFS_ReadAttribData(dir->I30Allocation, ofs, sizeof(buf), buf);
+                       //mftent = NTFS_BTreeSearch(len, (void*)buf, NTFS_BTreeSearch_CmpI30, name16len*2, name16);
+                       mftent = NTFS_BTreeSearch(len, (void*)buf, NTFS_BTreeSearch_CmpI30, -1, Name);
+               } while(mftent & (1ULL << 63));
+       }
+       else
+       {
        }
-       #endif
        
-       return NULL;
+       if( !mftent )
+               return NULL;
+       
+       // Allocate node
+       tVFS_Node       *ret = Inode_GetCache(disk->InodeCache, mftent);
+       if(ret)
+               return ret;
+       return NTFS_int_CreateNode(disk, mftent);
 }
 
-/**
- * \brief Scans an index for the requested value and returns the associated ID
- */
-Uint64 NTFS_int_IndexLookup(Uint64 Inode, const char *IndexName, const char *Str)
-{
-       return 0;
-}
index dd1bf84..b1fafb9 100644 (file)
@@ -42,6 +42,10 @@ tVFS_NodeType        gNTFS_DirType = {
        .FindDir = NTFS_FindDir,
        .Close = NULL
        };
+tVFS_NodeType  gNTFS_FileType = {
+       .TypeName = "NTFS-File",
+       .Close = NULL
+       };
 
 tNTFS_Disk     gNTFS_Disks;
 
@@ -128,8 +132,10 @@ tVFS_Node *NTFS_InitDevice(const char *Device, const char **Options)
        else {
                disk->MFTRecSize = bs.ClustersPerMFTRecord * disk->ClusterSize;
        }
-       NTFS_DumpEntry(disk, 0);        // $MFT
+       //NTFS_DumpEntry(disk, 0);      // $MFT
        //NTFS_DumpEntry(disk, 3);      // $VOLUME
+
+       disk->InodeCache = Inode_GetHandle();
        
        disk->MFTDataAttr = NULL;
        disk->MFTDataAttr = NTFS_GetAttrib(disk, 0, NTFS_FileAttrib_Data, "", 0);
@@ -148,12 +154,14 @@ tVFS_Node *NTFS_InitDevice(const char *Device, const char **Options)
        disk->RootDir.Node.NumACLs = 1;
        disk->RootDir.Node.ACLs = &gVFS_ACL_EveryoneRX;
 
+       #if 0
        {
                // Read from allocation
                char buf[disk->ClusterSize];
                size_t len = NTFS_ReadAttribData(disk->RootDir.I30Allocation, 0, sizeof(buf), buf);
                Debug_HexDump("RootDir allocation", buf, len);
        }
+       #endif
 
        return &disk->RootDir.Node;
 }
index 797d2db..55c2631 100644 (file)
@@ -132,6 +132,9 @@ typedef struct sNTFS_FILE_Attrib
 
 #include "attributes.h"
 
+typedef struct sNTFS_IndexHeader       tNTFS_IndexHeader;
+typedef struct sNTFS_IndexEntry_Filename       tNTFS_IndexEntry_Filename;
+
 struct sNTFS_IndexHeader
 {
        Uint32  Magic;  // = 'INDX' LE
@@ -153,8 +156,8 @@ struct sNTFS_IndexEntry_Filename
        Uint64  MFTReference;
        Uint16  EntrySize;
        Uint16  FilenameOfs;
-       Uint16  IndexFlags;
-       Uint16  _flags;
+       Uint16  IndexFlags;     // [0]: Points to sub-node, [1]: Last entry in node
+       Uint16  _rsvd;
 
        #if 1
        struct sNTFS_Attrib_Filename    Filename;

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