3 * By John Hodge (thePowersGang)
4 * This file is published under the terms of the Acess licence. See the
5 * file COPYING for details.
7 * dir.c - Directory Handling
15 int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
16 tVFS_Node *NTFS_FindDir(tVFS_Node *Node, const char *Name, Uint Flags);
17 Uint64 NTFS_int_IndexLookup(Uint64 Inode, const char *IndexName, const char *Str);
21 * \brief Get the name of an indexed directory entry
23 int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
25 tNTFS_Directory *dir = (void*)Node;
26 tNTFS_Disk *disk = Node->ImplPtr;
28 ASSERT(dir->I30Root->IsResident);
29 const tNTFS_Attrib_IndexRoot *idxroot = dir->I30Root->ResidentData;
30 //const tNTFS_Attrib_IndexEntry *rootents = (void*)(idxroot + 1);
32 if( idxroot->Flags & 0x01 )
34 // Read from allocation
35 char buf[disk->ClusterSize];
36 struct sNTFS_IndexHeader *hdr = (void*)buf;
38 size_t len = sizeof(buf);
39 struct sNTFS_IndexEntry_Filename *ent = (void*)(buf + len);
41 for( ; ; ent = (void*)((char*)ent + ent->EntrySize) )
43 if( (char*)ent == buf + len ) {
44 if( len < sizeof(buf))
46 len = NTFS_ReadAttribData(dir->I30Allocation, ofs, sizeof(buf), buf);
48 //Debug_HexDump("NTFS_ReadDir", buf, sizeof(*hdr));
49 ent = (void*)(buf + (hdr->EntriesOffset + 0x18));
51 // TODO: When end of node is hit, should the next cluster be loaded?
52 if( ent->IndexFlags & 0x02 )
54 // A little hacky - hide all internal files
55 if( (ent->MFTReference & ((1ULL << 48)-1)) < 12 )
60 //LOG("ent = {.MFTEnt=%llx,.FilenameOfs=%x}", ent->MFTReference, ent->FilenameOfs);
62 //Uint16 *name16 = (Uint16*)ent + ent->FilenameOfs/2;
63 Uint16 *name16 = ent->Filename.Filename;
64 size_t nlen = UTF16_ConvertToUTF8(0, NULL, ent->Filename.FilenameLength, name16);
65 char tmpname[ nlen+1 ];
66 UTF16_ConvertToUTF8(nlen+1, tmpname, ent->Filename.FilenameLength, name16);
67 LOG("name = %i '%s'", ent->Filename.FilenameNamespace, tmpname);
69 LOG("name = '%.*ls'", ent->Filename.FilenameLength, ent->Filename.Filename);
75 // Last entry does not refer to a file
76 if( ent->IndexFlags & 0x02 )
79 if( ent->Filename.FilenameNamespace == NTFS_FilenameNamespace_DOS )
82 //Uint16 *name16 = (Uint16*)ent + ent->FilenameOfs/2;
83 Uint16 *name16 = ent->Filename.Filename;
84 UTF16_ConvertToUTF8(FILENAME_MAX, Dest, ent->Filename.FilenameLength, name16);
85 LOG("Filename '%s'", Dest);
96 typedef int (*tNTFS_BTreeSearch_CmpFcn)(const tNTFS_IndexEntry_Filename *Ent, size_t SLen, const void *Search);
98 int NTFS_BTreeSearch_CmpI30(const tNTFS_IndexEntry_Filename *Ent, size_t SLen, const void *Search)
101 size_t fname_len = Ent->Filename.FilenameLength*2;
102 size_t cmplen = MIN(fnamelen, SLen);
103 int ret = memcmp(Ent->Filename.Filename, Search, cmplen);
108 else if( cmplen == SLen )
113 LOG("Cmp '%.*ls' == '%s'", Ent->Filename.FilenameLength, Ent->Filename.Filename, Search);
114 // return UTF16_CompareWithUTF8(Ent->Filename.FilenameLength, Ent->Filename.Filename, Search);
115 return UTF16_CompareWithUTF8CI(Ent->Filename.FilenameLength, Ent->Filename.Filename, Search);
119 Uint64 NTFS_BTreeSearch(size_t Length, tNTFS_IndexHeader *IndexHdr,
120 tNTFS_BTreeSearch_CmpFcn Cmp, size_t SLen, const void *Search)
122 void *buffer_end = (char*)IndexHdr + Length;
123 tNTFS_IndexEntry_Filename *ent = (void*)((char*)IndexHdr + IndexHdr->EntriesOffset + 0x18);
124 while( !(ent->IndexFlags & 0x02) )
126 if( (void*)(&ent->_rsvd + 1) > buffer_end ) {
130 // TODO: Handle collations?
131 int cmp = Cmp(ent, SLen, Search);
133 LOG("Located at %p: 0x%016llx", ent->MFTReference);
134 return ent->MFTReference & ((1ULL << 48)-1);
139 ent = (void*)((char*)ent + ent->EntrySize);
141 if( ent->IndexFlags & 0x01 ) {
142 LOG("Descend to VCN %llx", *(Uint64*)((char*)ent + ent->EntrySize - 8));
143 return (1ULL << 63) | *(Uint64*)((char*)ent + ent->EntrySize - 8);
149 tVFS_Node *NTFS_int_CreateNode(tNTFS_Disk *Disk, Uint64 MFTEntry)
151 tNTFS_FILE_Header *ent = NTFS_GetMFT(Disk, MFTEntry);
152 if( !ent || !(ent->Flags & 0x01) )
158 tNTFS_Directory tpl_dir;
161 memset(&types, 0, sizeof(tVFS_Node));
162 if( ent->Flags & 0x02 )
165 size = sizeof(types.tpl_dir);
166 ret = &types.tpl_dir.Node;
167 ret->Type = &gNTFS_DirType;
168 ret->Flags = VFS_FFLAG_DIRECTORY;
170 types.tpl_dir.I30Root = NTFS_GetAttrib(Disk, MFTEntry, NTFS_FileAttrib_IndexRoot, "$I30", 0);
171 types.tpl_dir.I30Allocation = NTFS_GetAttrib(Disk, MFTEntry, NTFS_FileAttrib_IndexAllocation, "$I30", 0);
176 size = sizeof(types.tpl_file);
177 ret = &types.tpl_file.Node;
178 ret->Type = &gNTFS_FileType;
179 types.tpl_file.Data = NTFS_GetAttrib(Disk, MFTEntry, NTFS_FileAttrib_Data, "", 0);
181 ret->Inode = MFTEntry;
186 NTFS_ReleaseMFT(Disk, MFTEntry, ent);
187 return Inode_CacheNodeEx(Disk->InodeCache, ret, size);
191 * \brief Get an entry from a directory by name
193 tVFS_Node *NTFS_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
195 tNTFS_Directory *dir = (void*)Node;
196 tNTFS_Disk *disk = Node->ImplPtr;
197 ASSERT(dir->I30Root->IsResident);
198 const tNTFS_Attrib_IndexRoot *idxroot = dir->I30Root->ResidentData;
201 size_t name16len = UTF16_ConvertFromUTF8(0, NULL, Name);
202 Uint16 name16[name16len+1];
203 UTF16_ConvertFromUTF8(name16len+1, name16, Name);
207 if( idxroot->Flags & 0x01 )
209 size_t unit_len = MAX(disk->ClusterSize, 2048);
210 char buf[ unit_len ];
212 size_t ofs = (mftent & 0xFFFFFF) * unit_len;
213 size_t len = NTFS_ReadAttribData(dir->I30Allocation, ofs, sizeof(buf), buf);
214 //mftent = NTFS_BTreeSearch(len, (void*)buf, NTFS_BTreeSearch_CmpI30, name16len*2, name16);
215 mftent = NTFS_BTreeSearch(len, (void*)buf, NTFS_BTreeSearch_CmpI30, -1, Name);
216 } while(mftent & (1ULL << 63));
226 tVFS_Node *ret = Inode_GetCache(disk->InodeCache, mftent);
229 return NTFS_int_CreateNode(disk, mftent);