+ #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);
+
+ LOG("VCN %x: Ofs=%x, Size=%x",
+ vcn, hdr->EntriesOffset, hdr->EntriesSize);
+ if( hdr->ThisVCN != vcn ) {
+ Log_Notice("NTFS", "Data error: Index header VCN mismatch (%x!=exp %x)", hdr->ThisVCN, vcn);
+ }
+ size_t ofs = hdr->EntriesOffset + 0x18;
+ while( ofs < hdr->EntriesSize + (hdr->EntriesOffset + 0x18) )
+ {
+ struct sNTFS_IndexEntry *ent = (void*)(buf + ofs);
+ if( ofs + sizeof(*ent) > len )
+ break;
+ LOG("%03x: L=%02x,M=%02x,F=%02x, Ref=%x/%llx", ofs,
+ ent->EntrySize, ent->MessageLen, ent->IndexFlags,
+ _MFTREF_SEQ(ent->MFTReference), _MFTREF_IDX(ent->MFTReference));
+
+ if( ent->EntrySize < sizeof(*ent) ) {
+ Log_Notice("NTFS", "Data error: Index entry size too small");
+ break ;
+ }
+ if( ent->MessageLen + sizeof(*ent) > ent->EntrySize ) {
+ Log_Notice("NTFS", "Data error: Index entry message size > entry size");
+ }
+
+ if( ent->IndexFlags & NTFS_IndexFlag_HasSubNode )
+ {
+ if( ent->EntrySize < sizeof(*ent) + 8 ) {
+ Log_Notice("NTFS", "Data error: Index entry size too small (SubVCN)");
+ }
+ LOG("- SubVCN=%llx", *(Uint64*)((char*)ent + ent->EntrySize - 8));
+ }
+ if( ent->IndexFlags & NTFS_IndexFlag_IsLast )
+ break;
+
+ switch(AttribID)
+ {
+ case 0x30: {
+ struct sNTFS_Attrib_Filename *fname = (void*)(buf + ofs + sizeof(*ent));
+ LOG("- Filename: %i %.*ls",
+ fname->FilenameNamespace,
+ fname->FilenameLength, fname->Filename);
+ break; }
+ }
+
+ ofs += ent->EntrySize;
+ }
+ vcn ++;
+ }
+ LEAVE('-');
+}
+
+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);
+
+ ASSERT(types.tpl_dir.I30Root->IsResident);
+ #if 0
+ Debug_HexDump("NTFS CreateNode Root",
+ types.tpl_dir.I30Root->ResidentData,
+ types.tpl_dir.I30Root->DataSize);
+ if( types.tpl_dir.I30Allocation ) {
+ NTFS_int_DumpIndex(types.tpl_dir.I30Allocation, 0x30);
+ }
+ #endif