d7492d024b030fbbc069bae08886f5e45b9034e3
[tpg/acess2.git] / KernelLand / Modules / Filesystems / NTFS / dir.c
1 /*
2  * Acess2 - NTFS Driver
3  * By John Hodge (thePowersGang)
4  * This file is published under the terms of the Acess licence. See the
5  * file COPYING for details.
6  *
7  * dir.c - Directory Handling
8  */
9 #define DEBUG   1
10 #include "common.h"
11 //#include "index.h"
12 #include <utf16.h>
13
14 // === PROTOTYPES ===
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);
18
19 // === CODE ===
20 /**
21  * \brief Get the name of an indexed directory entry
22  */
23 int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
24 {
25         tNTFS_Directory *dir = (void*)Node;
26         tNTFS_Disk      *disk = Node->ImplPtr;
27
28         ASSERT(dir->I30Root->IsResident);
29         const tNTFS_Attrib_IndexRoot    *idxroot = dir->I30Root->ResidentData;
30         //const tNTFS_Attrib_IndexEntry *rootents = (void*)(idxroot + 1);
31
32         if( idxroot->Flags & 0x01 )
33         {
34                 // Read from allocation
35                 char buf[disk->ClusterSize];
36                 struct sNTFS_IndexHeader *hdr = (void*)buf;
37                 size_t  ofs = 0;
38                 size_t len = sizeof(buf);
39                 struct sNTFS_IndexEntry_Filename *ent = (void*)(buf + len);
40                 
41                 for( ; ; ent = (void*)((char*)ent + ent->EntrySize) )
42                 {
43                         if( (char*)ent == buf + len ) {
44                                 if( len < sizeof(buf))
45                                         break ;
46                                 len = NTFS_ReadAttribData(dir->I30Allocation, ofs, sizeof(buf), buf);
47                                 ofs += sizeof(buf);
48                                 //Debug_HexDump("NTFS_ReadDir", buf, sizeof(*hdr));
49                                 ent = (void*)(buf + (hdr->EntriesOffset + 0x18));
50                         }
51                         // TODO: When end of node is hit, should the next cluster be loaded?
52                         if( ent->IndexFlags & 0x02 )
53                                 break;
54                         // A little hacky - hide all internal files
55                         if( (ent->MFTReference & ((1ULL << 48)-1)) < 12 )
56                                 continue;
57                         if( Pos -- <= 0 )
58                                 break;
59
60                         //LOG("ent = {.MFTEnt=%llx,.FilenameOfs=%x}", ent->MFTReference, ent->FilenameOfs);
61                         #if 0
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);
68                         #elif 0
69                         LOG("name = '%.*ls'", ent->Filename.FilenameLength, ent->Filename.Filename);
70                         #endif
71                 }
72
73                 if( Pos >= 0 )
74                         return -1;
75                 // Last entry does not refer to a file
76                 if( ent->IndexFlags & 0x02 )
77                         return -1;
78                 
79                 if( ent->Filename.FilenameNamespace == NTFS_FilenameNamespace_DOS )
80                         return 1; 
81
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);
86                 return 0;
87         }
88         else
89         {
90                 // Local only
91         }
92
93         return -ENOTIMPL;
94 }
95
96 typedef int (*tNTFS_BTreeSearch_CmpFcn)(const tNTFS_IndexEntry_Filename *Ent, size_t SLen, const void *Search);
97
98 int NTFS_BTreeSearch_CmpI30(const tNTFS_IndexEntry_Filename *Ent, size_t SLen, const void *Search)
99 {
100         #if 0
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);
104         if( ret != 0 )
105                 return ret;
106         if( cmplen < SLen )
107                 return -1;
108         else if( cmplen == SLen )
109                 return 0;
110         else
111                 return 1;
112         #else
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);
116         #endif
117 }
118
119 Uint64 NTFS_BTreeSearch(size_t Length, tNTFS_IndexHeader *IndexHdr,
120         tNTFS_BTreeSearch_CmpFcn Cmp, size_t SLen, const void *Search)
121 {
122         void    *buffer_end = (char*)IndexHdr + Length;
123         tNTFS_IndexEntry_Filename *ent = (void*)((char*)IndexHdr + IndexHdr->EntriesOffset + 0x18);
124         while( !(ent->IndexFlags & 0x02) )
125         {
126                 if( (void*)(&ent->_rsvd + 1) > buffer_end ) {
127                         // on-disk error
128                         return 0;
129                 }
130                 // TODO: Handle collations?
131                 int cmp = Cmp(ent, SLen, Search);
132                 if( cmp == 0 ) {
133                         LOG("Located at %p: 0x%016llx", ent->MFTReference);
134                         return ent->MFTReference & ((1ULL << 48)-1);
135                 }
136                 if( cmp > 0 )
137                         break;
138                 
139                 ent = (void*)((char*)ent + ent->EntrySize);
140         }
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);
144         }
145         LOG("Not found");
146         return 0;
147 }
148
149 tVFS_Node *NTFS_int_CreateNode(tNTFS_Disk *Disk, Uint64 MFTEntry)
150 {
151         tNTFS_FILE_Header       *ent = NTFS_GetMFT(Disk, MFTEntry);
152         if( !ent || !(ent->Flags & 0x01) )
153                 return NULL;    
154
155         tVFS_Node       *ret;
156         size_t  size;
157         union {
158                 tNTFS_Directory tpl_dir;
159                 tNTFS_File      tpl_file;
160         } types;
161         memset(&types, 0, sizeof(tVFS_Node));
162         if( ent->Flags & 0x02 )
163         {
164                 // Directory
165                 size = sizeof(types.tpl_dir);
166                 ret = &types.tpl_dir.Node;
167                 ret->Type = &gNTFS_DirType;
168                 ret->Flags = VFS_FFLAG_DIRECTORY;
169                 
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);
172         }
173         else
174         {
175                 // File
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); 
180         }
181         ret->Inode = MFTEntry;
182         ret->ImplPtr = Disk;
183
184         // TODO: Permissions
185         
186         NTFS_ReleaseMFT(Disk, MFTEntry, ent);
187         return Inode_CacheNodeEx(Disk->InodeCache, ret, size);
188 }
189
190 /**
191  * \brief Get an entry from a directory by name
192  */
193 tVFS_Node *NTFS_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
194 {
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;
199
200         #if 0
201         size_t  name16len = UTF16_ConvertFromUTF8(0, NULL, Name);
202         Uint16  name16[name16len+1];
203         UTF16_ConvertFromUTF8(name16len+1, name16, Name);
204         #endif
205
206         Uint64  mftent = 0;
207         if( idxroot->Flags & 0x01 )
208         {
209                 size_t  unit_len = MAX(disk->ClusterSize, 2048);
210                 char buf[ unit_len ];
211                 do {
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));
217         }
218         else
219         {
220         }
221         
222         if( !mftent )
223                 return NULL;
224         
225         // Allocate node
226         tVFS_Node       *ret = Inode_GetCache(disk->InodeCache, mftent);
227         if(ret)
228                 return ret;
229         return NTFS_int_CreateNode(disk, mftent);
230 }
231

UCC git Repository :: git.ucc.asn.au