From 7461f3e62b0783a3293828e4da74668f832f78b8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 23 Jun 2013 14:49:09 +0800 Subject: [PATCH] Modules/NTFS - Implimentation progressing (ReadDir/FindDir appear to work) --- .../Modules/Filesystems/NTFS/attributes.h | 2 +- KernelLand/Modules/Filesystems/NTFS/common.h | 7 + KernelLand/Modules/Filesystems/NTFS/dir.c | 174 +++++++++++++++--- KernelLand/Modules/Filesystems/NTFS/main.c | 10 +- KernelLand/Modules/Filesystems/NTFS/ntfs.h | 7 +- 5 files changed, 171 insertions(+), 29 deletions(-) diff --git a/KernelLand/Modules/Filesystems/NTFS/attributes.h b/KernelLand/Modules/Filesystems/NTFS/attributes.h index b72588e9..6afd912c 100644 --- a/KernelLand/Modules/Filesystems/NTFS/attributes.h +++ b/KernelLand/Modules/Filesystems/NTFS/attributes.h @@ -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; diff --git a/KernelLand/Modules/Filesystems/NTFS/common.h b/KernelLand/Modules/Filesystems/NTFS/common.h index ac93b520..db117a6e 100644 --- a/KernelLand/Modules/Filesystems/NTFS/common.h +++ b/KernelLand/Modules/Filesystems/NTFS/common.h @@ -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 diff --git a/KernelLand/Modules/Filesystems/NTFS/dir.c b/KernelLand/Modules/Filesystems/NTFS/dir.c index 50667837..d7492d02 100644 --- a/KernelLand/Modules/Filesystems/NTFS/dir.c +++ b/KernelLand/Modules/Filesystems/NTFS/dir.c @@ -8,7 +8,7 @@ */ #define DEBUG 1 #include "common.h" -#include "index.h" +//#include "index.h" #include // === 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; -} diff --git a/KernelLand/Modules/Filesystems/NTFS/main.c b/KernelLand/Modules/Filesystems/NTFS/main.c index dd1bf846..b1fafb95 100644 --- a/KernelLand/Modules/Filesystems/NTFS/main.c +++ b/KernelLand/Modules/Filesystems/NTFS/main.c @@ -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; } diff --git a/KernelLand/Modules/Filesystems/NTFS/ntfs.h b/KernelLand/Modules/Filesystems/NTFS/ntfs.h index 797d2db8..55c2631e 100644 --- a/KernelLand/Modules/Filesystems/NTFS/ntfs.h +++ b/KernelLand/Modules/Filesystems/NTFS/ntfs.h @@ -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; -- 2.20.1