explorer: merge changes from lean explorer branch (shell namespace iteration, icon...
[reactos.git] / reactos / subsys / system / explorer / shell / ntobjfs.cpp
1 /*
2 * Copyright 2004, 2005 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 //
21 // Explorer clone
22 //
23 // ntobjfs.cpp
24 //
25 // Martin Fuchs, 31.01.2004
26 //
27
28
29 #include <precomp.h>
30
31 #include "ntobjfs.h"
32 //#include "winfs.h"
33 #include "regfs.h"
34
35
36 #define CONSTRUCT_NTDLLFCT(x) x(TEXT("NTDLL"), #x)
37
38 typedef DWORD (__stdcall* NTOBJECTOPENFUNCTIONS)(HANDLE*, DWORD, OpenStruct*);
39
40 struct NTDLL {
41 NTDLL()
42 : CONSTRUCT_NTDLLFCT(RtlInitAnsiString),
43 CONSTRUCT_NTDLLFCT(RtlInitUnicodeString),
44 CONSTRUCT_NTDLLFCT(RtlFreeAnsiString),
45 CONSTRUCT_NTDLLFCT(RtlFreeUnicodeString),
46 CONSTRUCT_NTDLLFCT(RtlAnsiStringToUnicodeString),
47 CONSTRUCT_NTDLLFCT(RtlUnicodeStringToAnsiString),
48 CONSTRUCT_NTDLLFCT(NtOpenDirectoryObject),
49 CONSTRUCT_NTDLLFCT(NtQueryDirectoryObject),
50 CONSTRUCT_NTDLLFCT(NtOpenFile),
51 CONSTRUCT_NTDLLFCT(NtOpenSymbolicLinkObject),
52 CONSTRUCT_NTDLLFCT(NtQuerySymbolicLinkObject),
53 CONSTRUCT_NTDLLFCT(NtQueryObject),
54 CONSTRUCT_NTDLLFCT(NtOpenMutant),
55 CONSTRUCT_NTDLLFCT(NtOpenSection),
56 CONSTRUCT_NTDLLFCT(NtOpenEvent),
57 CONSTRUCT_NTDLLFCT(NtOpenEventPair),
58 CONSTRUCT_NTDLLFCT(NtOpenIoCompletion),
59 CONSTRUCT_NTDLLFCT(NtOpenSemaphore),
60 CONSTRUCT_NTDLLFCT(NtOpenTimer),
61 CONSTRUCT_NTDLLFCT(NtOpenKey),
62 CONSTRUCT_NTDLLFCT(NtClose),
63 CONSTRUCT_NTDLLFCT(NtOpenProcess),
64 CONSTRUCT_NTDLLFCT(NtOpenThread)
65 {
66 NTOBJECTOPENFUNCTIONS* p = _ObjectOpenFunctions;
67
68 *p++ = *NtOpenDirectoryObject;
69 *p++ = *NtOpenSymbolicLinkObject;
70 *p++ = *NtOpenMutant;
71 *p++ = *NtOpenSection;
72 *p++ = *NtOpenEvent;
73 *p++ = *NtOpenSemaphore;
74 *p++ = *NtOpenTimer;
75 *p++ = *NtOpenKey;
76 *p++ = *NtOpenEventPair;
77 *p++ = *NtOpenIoCompletion;
78 *p++ = 0/*Device Object*/;
79 *p++ = 0/*NtOpenFile*/;
80 *p++ = 0/*CONTROLLER_OBJECT*/;
81 *p++ = 0/*PROFILE_OBJECT*/;
82 *p++ = 0/*TYPE_OBJECT*/;
83 *p++ = 0/*DESKTOP_OBJECT*/;
84 *p++ = 0/*WINDOWSTATION_OBJECT*/;
85 *p++ = 0/*DRIVER_OBJECT*/;
86 *p++ = 0/*TOKEN_OBJECT*/;
87 *p++ = 0/*PROCESS_OBJECT*/;
88 *p++ = 0/*THREAD_OBJECT*/;
89 *p++ = 0/*ADAPTER_OBJECT*/;
90 *p++ = 0/*PORT_OBJECT*/;
91 }
92
93 NTOBJECTOPENFUNCTIONS _ObjectOpenFunctions[23];
94 static const LPCWSTR s_ObjectTypes[];
95
96 DynamicFct<void (__stdcall*)(RtlAnsiString*, LPCSTR)> RtlInitAnsiString;
97 DynamicFct<void (__stdcall*)(RtlUnicodeString*, LPCWSTR)> RtlInitUnicodeString;
98 DynamicFct<DWORD (__stdcall*)(RtlAnsiString*)> RtlFreeAnsiString;
99 DynamicFct<DWORD (__stdcall*)(RtlUnicodeString*)> RtlFreeUnicodeString;
100 DynamicFct<DWORD (__stdcall*)(RtlUnicodeString*, const RtlAnsiString*, BOOL)> RtlAnsiStringToUnicodeString;
101 DynamicFct<DWORD (__stdcall*)(RtlAnsiString*, const RtlUnicodeString*, BOOL)> RtlUnicodeStringToAnsiString;
102
103 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenDirectoryObject;
104 DynamicFct<DWORD (__stdcall*)(HANDLE, NtObjectInfo*, DWORD size, BOOL, BOOL, void*, void*)> NtQueryDirectoryObject;
105 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, void*, DWORD*, DWORD, OpenStruct*)> NtOpenFile;
106 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenSymbolicLinkObject;
107 DynamicFct<DWORD (__stdcall*)(HANDLE, RtlUnicodeString*, DWORD*)> NtQuerySymbolicLinkObject;
108 DynamicFct<DWORD (__stdcall*)(HANDLE, DWORD, NtObject*, DWORD size, DWORD* read)> NtQueryObject;
109 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenMutant;
110 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenSection;
111 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenEvent;
112 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenEventPair;
113 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenIoCompletion;
114 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenSemaphore;
115 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenTimer;
116 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenKey;
117 DynamicFct<DWORD (__stdcall*)(HANDLE)> NtClose;
118 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenProcess;
119 DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenThread;
120 };
121
122 const LPCWSTR NTDLL::s_ObjectTypes[] = {
123 L"Directory", L"SymbolicLink",
124 L"Mutant", L"Section", L"Event", L"Semaphore",
125 L"Timer", L"Key", L"EventPair", L"IoCompletion",
126 L"Device", L"File", L"Controller", L"Profile",
127 L"Type", L"Desktop", L"WindowStatiom", L"Driver",
128 L"Token", L"Process", L"Thread", L"Adapter", L"Port",
129 0
130 };
131
132 NTDLL* g_NTDLL = NULL;
133
134
135 struct UnicodeString : public RtlUnicodeString {
136 UnicodeString(LPCWSTR str)
137 {
138 (*g_NTDLL->RtlInitUnicodeString)(this, str);
139 }
140
141 UnicodeString(size_t len, LPWSTR buffer)
142 {
143 alloc_len = len;
144 string_ptr = buffer;
145 }
146
147 operator LPCWSTR() const {return string_ptr;}
148 };
149
150
151 static DWORD NtOpenObject(OBJECT_TYPE type, HANDLE* phandle, DWORD access, LPCWSTR path/*, BOOL xflag=FALSE*/)
152 {
153 UnicodeString ustr(path);
154 OpenStruct open_struct = {sizeof(OpenStruct), 0x00, &ustr, 0x40};
155
156 if (type==DIRECTORY_OBJECT || type==SYMBOLICLINK_OBJECT)
157 access |= FILE_LIST_DIRECTORY;
158
159 /* if (xflag)
160 access |= GENERIC_READ; */
161
162 DWORD ioStatusBlock[2]; // IO_STATUS_BLOCK
163
164 if (type>=DIRECTORY_OBJECT && type<=IOCOMPLETITION_OBJECT)
165 return g_NTDLL->_ObjectOpenFunctions[type](phandle, access|STANDARD_RIGHTS_READ, &open_struct);
166 else if (type == FILE_OBJECT)
167 return (*g_NTDLL->NtOpenFile)(phandle, access, &open_struct, ioStatusBlock, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0/*OpenOptions*/);
168 else
169 return ERROR_INVALID_FUNCTION;
170 }
171
172
173 void NtObjDirectory::read_directory(int scan_flags)
174 {
175 CONTEXT("NtObjDirectory::read_directory()");
176
177 if (!g_NTDLL)
178 g_NTDLL = new NTDLL();
179
180 Entry* first_entry = NULL;
181 int level = _level + 1;
182
183 LPCTSTR path = (LPCTSTR)_path;
184
185 TCHAR buffer[MAX_PATH], *p=buffer;
186 #ifndef UNICODE
187 WCHAR wbuffer[MAX_PATH], *w=wbuffer;
188 #endif
189
190 do {
191 *p++ = *path;
192 #ifndef UNICODE
193 *w++ = *path;
194 #endif
195 } while(*path++);
196 --p;
197 #ifndef UNICODE
198 --w;
199 #endif
200
201 DWORD idx;
202 HANDLE dir_handle;
203
204 #ifdef UNICODE
205 if (NtOpenObject(_type, &dir_handle, 0, buffer))
206 #else
207 if (NtOpenObject(_type, &dir_handle, 0, wbuffer))
208 #endif
209 return;
210
211 #ifdef UNICODE
212 if (p[-1] != '\\')
213 *p++ = '\\';
214 #else
215 if (w[-1] != '\\')
216 *w++ = '\\';
217 #endif
218
219 NtObjectInfo* info = (NtObjectInfo*)alloca(2048);
220
221 if (!(*g_NTDLL->NtQueryDirectoryObject)(dir_handle, info, 2048, TRUE, TRUE, &idx, NULL)) {
222 WIN32_FIND_DATA w32fd;
223 Entry* last = NULL;
224 Entry* entry;
225
226 do {
227 memset(&w32fd, 0, sizeof(WIN32_FIND_DATA));
228
229 #ifdef UNICODE
230 if (info->name.string_ptr) {
231 info->name.string_ptr[info->name.string_len / sizeof(WCHAR)] = 0;
232 } else {
233 info->name.string_ptr = TEXT("");
234 }
235 if (info->type.string_ptr) {
236 info->type.string_ptr[info->type.string_len / sizeof(WCHAR)] = 0;
237 } else {
238 info->type.string_ptr = TEXT("");
239 }
240 lstrcpynW(p, info->name.string_ptr, COUNTOF(buffer));
241 #else
242 WideCharToMultiByte(CP_ACP, 0, info->name.string_ptr, info->name.string_len, p, COUNTOF(buffer), 0, 0);
243 #endif
244
245 lstrcpyn(w32fd.cFileName, p, sizeof(w32fd.cFileName) / sizeof(0[w32fd.cFileName]));
246
247 const LPCWSTR* tname = NTDLL::s_ObjectTypes;
248 OBJECT_TYPE type = UNKNOWN_OBJECT_TYPE;
249
250 for(; *tname; tname++)
251 if (!wcsncmp(info->type.string_ptr, *tname, 32))
252 {type=OBJECT_TYPE(tname-NTDLL::s_ObjectTypes); break;}
253
254 if (type == DIRECTORY_OBJECT) {
255 w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
256
257 entry = new NtObjDirectory(this, buffer);
258 }
259
260 else if (type == SYMBOLICLINK_OBJECT) {
261 w32fd.dwFileAttributes |= ATTRIBUTE_SYMBOLIC_LINK;
262
263 entry = NULL;
264
265 #ifndef _NO_WIN_FS
266 if (*w32fd.cFileName>='A' &&*w32fd.cFileName<='Z' && w32fd.cFileName[1]==':')
267 if (!_tcsncmp(buffer,TEXT("\\??\\"),4) || // NT4
268 !_tcsncmp(buffer,TEXT("\\GLOBAL??"),9)) { // XP
269 w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
270 entry = new WinDirectory(this, w32fd.cFileName);
271 }
272 #endif
273
274 if (!entry)
275 entry = new NtObjDirectory(this, buffer);
276 }
277
278 else if (type == KEY_OBJECT) {
279 w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
280
281 entry = new RegistryRoot(this, buffer);
282 }
283 else
284 entry = new NtObjEntry(this, type);
285
286 HANDLE handle;
287
288 #ifdef UNICODE
289 lstrcpyW(p, info->name.string_ptr);
290 if (!NtOpenObject(type, &handle, 0, buffer))
291 #else
292 lstrcpyW(w, info->name.string_ptr);
293 if (!NtOpenObject(type, &handle, 0, wbuffer))
294 #endif
295 {
296 NtObject object;
297 DWORD read;
298
299 if (!(*g_NTDLL->NtQueryObject)(handle, 0/*ObjectBasicInformation*/, &object, sizeof(NtObject), &read)) {
300 memcpy(&w32fd.ftCreationTime, &object.creation_time, sizeof(FILETIME));
301
302 memset(&entry->_bhfi, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
303 entry->_bhfi.nNumberOfLinks = object.reference_count - 1;
304 entry->_bhfi_valid = true;
305 }
306
307 if (type == SYMBOLICLINK_OBJECT) {
308 WCHAR wbuffer[_MAX_PATH];
309 UnicodeString link(_MAX_PATH, wbuffer);
310
311 if (!(*g_NTDLL->NtQuerySymbolicLinkObject)(handle, &link, NULL)) {
312 int len = link.string_len/sizeof(WCHAR);
313 entry->_content = (LPTSTR) malloc((len+1)*sizeof(TCHAR));
314 #ifdef UNICODE
315 wcsncpy_s(entry->_content, len+1, link, len);
316 #else
317 U2nA(link, entry->_content, len);
318 #endif
319 entry->_content[len] = '\0';
320 }
321 }
322
323 (*g_NTDLL->NtClose)(handle);
324 }
325
326 memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA));
327
328 #ifdef UNICODE
329 entry->_type_name = _wcsdup(info->type.string_ptr);
330 #else
331 char type_name[32];
332 WideCharToMultiByte(CP_ACP, 0, info->type.string_ptr, info->type.string_len, type_name, 32, 0, 0);
333 entry->_type_name = _strdup(type_name);
334 #endif
335
336 if (!first_entry)
337 first_entry = entry;
338
339 if (last)
340 last->_next = entry;
341
342 entry->_level = level;
343
344 last = entry;
345 } while(!(*g_NTDLL->NtQueryDirectoryObject)(dir_handle, info, 2048, TRUE, FALSE, &idx, NULL));
346
347 last->_next = NULL;
348 }
349
350 (*g_NTDLL->NtClose)(dir_handle);
351
352 _down = first_entry;
353 _scanned = true;
354 }
355
356
357 Entry* NtObjDirectory::find_entry(const void* p)
358 {
359 LPCTSTR name = (LPCTSTR)p;
360
361 for(Entry*entry=_down; entry; entry=entry->_next) {
362 LPCTSTR p = name;
363 LPCTSTR q = entry->_data.cFileName;
364
365 do {
366 if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
367 return entry;
368 } while(tolower(*p++) == tolower(*q++));
369
370 p = name;
371 q = entry->_data.cAlternateFileName;
372
373 do {
374 if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
375 return entry;
376 } while(tolower(*p++) == tolower(*q++));
377 }
378
379 return NULL;
380 }
381
382
383 // get full path of specified directory entry
384 bool NtObjEntry::get_path(PTSTR path, size_t path_count) const
385 {
386 return get_path_base ( path, path_count, ET_NTOBJS );
387 }
388
389 BOOL NtObjEntry::launch_entry(HWND hwnd, UINT nCmdShow)
390 {
391 return FALSE;
392 }