+ ASSERT(hdr->EntriesOffset + 0x18 < len);
+ // Apply update sequence
+ ASSERT(hdr->UpdateSequenceOfs + 2*hdr->UpdateSequenceSize <= len);
+ NTFS_int_ApplyUpdateSequence(buf,len, (void*)(buf+hdr->UpdateSequenceOfs), hdr->UpdateSequenceSize);
+ size_t ofs = hdr->EntriesOffset + 0x18;
+ ent = NTFS_int_IterateIndex(buf + ofs, len - ofs, &Pos);
+ vcn ++;
+ }
+ if( !ent ) {
+ LEAVE('i', 1);
+ return -1;
+ }
+
+ // TODO: This is not future-proof
+ const Uint16 *name16 = ent->Filename.Filename;
+ UTF16_ConvertToUTF8(FILENAME_MAX, Dest, ent->Filename.FilenameLength, name16);
+ LOG("Filename '%s'", Dest);
+ LEAVE('i', 0);
+ return 0;
+}
+
+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, const void *Data,
+ tNTFS_BTreeSearch_CmpFcn Cmp, size_t SLen, const void *Search)
+{
+ void *buffer_end = (char*)Data + Length;
+ const tNTFS_IndexEntry_Filename *ent = Data;
+ 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, 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;
+}
+
+#define _MFTREF_IDX(ref) ((ref) & ((1ULL<<48)-1))
+#define _MFTREF_SEQ(ref) ((ref) >> 48)
+
+void NTFS_int_DumpIndex(tNTFS_Attrib *Allocation, Uint AttribID)
+{
+ ENTER("pAllocation xAttribID", Allocation, AttribID);
+ if(!Allocation) {
+ LEAVE('-');
+ return ;
+ }
+ Uint32 vcn = 0;
+ size_t block_size = MAX(2048, Allocation->Disk->ClusterSize);
+ char buf[block_size];
+ size_t len;
+ while( (len = NTFS_ReadAttribData(Allocation, vcn*block_size, block_size, buf)) )
+ {
+ struct sNTFS_IndexHeader *hdr = (void*)buf;
+ // Apply update sequence
+ ASSERT(hdr->UpdateSequenceOfs + 2*hdr->UpdateSequenceSize <= len);
+ NTFS_int_ApplyUpdateSequence(buf,len, (void*)(buf+hdr->UpdateSequenceOfs), hdr->UpdateSequenceSize);