+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);
+}
+