ntdll: Add support for root directory in NtCreateFile for Win32 file objects.
[wine] / dlls / ntdll / tests / om.c
1 /*
2  * Unit test suite for object manager functions
3  *
4  * Copyright 2005 Robert Shearman
5  * Copyright 2005 Vitaliy Margolen
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "ntdll_test.h"
23 #include "winternl.h"
24 #include "stdio.h"
25 #include "winnt.h"
26 #include "stdlib.h"
27
28 static HANDLE   (WINAPI *pCreateWaitableTimerA)(SECURITY_ATTRIBUTES*, BOOL, LPCSTR);
29 static NTSTATUS (WINAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
30 static VOID     (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR );
31 static VOID     (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING);
32 static NTSTATUS (WINAPI *pNtCreateEvent) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, BOOLEAN, BOOLEAN);
33 static NTSTATUS (WINAPI *pNtCreateMutant)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, BOOLEAN );
34 static NTSTATUS (WINAPI *pNtOpenMutant)  ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES );
35 static NTSTATUS (WINAPI *pNtCreateSemaphore)( PHANDLE, ACCESS_MASK,const POBJECT_ATTRIBUTES,LONG,LONG );
36 static NTSTATUS (WINAPI *pNtCreateTimer) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, TIMER_TYPE );
37 static NTSTATUS (WINAPI *pNtCreateSection)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, const PLARGE_INTEGER,
38                                             ULONG, ULONG, HANDLE );
39 static NTSTATUS (WINAPI *pNtOpenFile)    ( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG );
40 static NTSTATUS (WINAPI *pNtClose)       ( HANDLE );
41 static NTSTATUS (WINAPI *pNtCreateNamedPipeFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK,
42                                        ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, PLARGE_INTEGER );
43 static NTSTATUS (WINAPI *pNtOpenDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
44 static NTSTATUS (WINAPI *pNtCreateDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
45 static NTSTATUS (WINAPI *pNtOpenSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
46 static NTSTATUS (WINAPI *pNtCreateSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PUNICODE_STRING);
47
48
49 static void test_case_sensitive (void)
50 {
51     static const WCHAR buffer1[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\\','t','e','s','t',0};
52     static const WCHAR buffer2[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\\','T','e','s','t',0};
53     static const WCHAR buffer3[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\\','T','E','s','t',0};
54     static const WCHAR buffer4[] = {'\\','B','A','S','E','N','a','m','e','d','O','b','j','e','c','t','s','\\','t','e','s','t',0};
55     NTSTATUS status;
56     OBJECT_ATTRIBUTES attr;
57     UNICODE_STRING str;
58     HANDLE Event, Mutant, h;
59
60     pRtlInitUnicodeString(&str, buffer1);
61     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
62     status = pNtCreateMutant(&Mutant, GENERIC_ALL, &attr, FALSE);
63     ok(status == STATUS_SUCCESS, "Failed to create Mutant(%08x)\n", status);
64
65     status = pNtCreateEvent(&Event, GENERIC_ALL, &attr, FALSE, FALSE);
66     ok(status == STATUS_OBJECT_NAME_COLLISION,
67         "NtCreateEvent should have failed with STATUS_OBJECT_NAME_COLLISION got(%08x)\n", status);
68
69     pRtlInitUnicodeString(&str, buffer2);
70     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
71     status = pNtCreateEvent(&Event, GENERIC_ALL, &attr, FALSE, FALSE);
72     ok(status == STATUS_SUCCESS, "Failed to create Event(%08x)\n", status);
73
74     pRtlInitUnicodeString(&str, buffer3);
75     InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
76     status = pNtOpenMutant(&h, GENERIC_ALL, &attr);
77     ok(status == STATUS_OBJECT_TYPE_MISMATCH,
78         "NtOpenMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08x)\n", status);
79
80     pNtClose(Mutant);
81
82     pRtlInitUnicodeString(&str, buffer4);
83     InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
84     status = pNtCreateMutant(&Mutant, GENERIC_ALL, &attr, FALSE);
85     ok(status == STATUS_OBJECT_NAME_COLLISION,
86         "NtCreateMutant should have failed with STATUS_OBJECT_NAME_COLLISION got(%08x)\n", status);
87
88     status = pNtCreateEvent(&h, GENERIC_ALL, &attr, FALSE, FALSE);
89     ok(status == STATUS_OBJECT_NAME_COLLISION,
90         "NtCreateEvent should have failed with STATUS_OBJECT_NAME_COLLISION got(%08x)\n", status);
91
92     attr.Attributes = 0;
93     status = pNtCreateMutant(&Mutant, GENERIC_ALL, &attr, FALSE);
94     ok(status == STATUS_OBJECT_PATH_NOT_FOUND,
95         "NtCreateMutant should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08x)\n", status);
96
97     pNtClose(Event);
98 }
99
100 static void test_namespace_pipe(void)
101 {
102     static const WCHAR buffer1[] = {'\\','?','?','\\','P','I','P','E','\\','t','e','s','t','\\','p','i','p','e',0};
103     static const WCHAR buffer2[] = {'\\','?','?','\\','P','I','P','E','\\','T','E','S','T','\\','P','I','P','E',0};
104     static const WCHAR buffer3[] = {'\\','?','?','\\','p','i','p','e','\\','t','e','s','t','\\','p','i','p','e',0};
105     static const WCHAR buffer4[] = {'\\','?','?','\\','p','i','p','e','\\','t','e','s','t',0};
106     OBJECT_ATTRIBUTES attr;
107     UNICODE_STRING str;
108     IO_STATUS_BLOCK iosb;
109     NTSTATUS status;
110     LARGE_INTEGER timeout;
111     HANDLE pipe, h;
112
113     timeout.QuadPart = -10000;
114
115     pRtlInitUnicodeString(&str, buffer1);
116     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
117     status = pNtCreateNamedPipeFile(&pipe, GENERIC_READ|GENERIC_WRITE, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE,
118                                     FILE_CREATE, FILE_PIPE_FULL_DUPLEX, FALSE, FALSE, FALSE, 1, 256, 256, &timeout);
119     ok(status == STATUS_SUCCESS, "Failed to create NamedPipe(%08x)\n", status);
120
121     status = pNtCreateNamedPipeFile(&pipe, GENERIC_READ|GENERIC_WRITE, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE,
122                                     FILE_CREATE, FILE_PIPE_FULL_DUPLEX, FALSE, FALSE, FALSE, 1, 256, 256, &timeout);
123     ok(status == STATUS_INSTANCE_NOT_AVAILABLE,
124         "NtCreateNamedPipeFile should have failed with STATUS_INSTANCE_NOT_AVAILABLE got(%08x)\n", status);
125
126     pRtlInitUnicodeString(&str, buffer2);
127     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
128     status = pNtCreateNamedPipeFile(&pipe, GENERIC_READ|GENERIC_WRITE, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE,
129                                     FILE_CREATE, FILE_PIPE_FULL_DUPLEX, FALSE, FALSE, FALSE, 1, 256, 256, &timeout);
130     ok(status == STATUS_INSTANCE_NOT_AVAILABLE,
131         "NtCreateNamedPipeFile should have failed with STATUS_INSTANCE_NOT_AVAILABLE got(%08x)\n", status);
132
133     attr.Attributes = OBJ_CASE_INSENSITIVE;
134     status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN);
135     ok(status == STATUS_SUCCESS, "Failed to open NamedPipe(%08x)\n", status);
136     pNtClose(h);
137
138     pRtlInitUnicodeString(&str, buffer3);
139     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
140     status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN);
141     ok(status == STATUS_OBJECT_PATH_NOT_FOUND ||
142        status == STATUS_PIPE_NOT_AVAILABLE ||
143        status == STATUS_OBJECT_NAME_INVALID, /* vista */
144         "NtOpenFile should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08x)\n", status);
145
146     pRtlInitUnicodeString(&str, buffer4);
147     InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
148     status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN);
149     ok(status == STATUS_OBJECT_NAME_NOT_FOUND ||
150        status == STATUS_OBJECT_NAME_INVALID, /* vista */
151         "NtOpenFile should have failed with STATUS_OBJECT_NAME_NOT_FOUND got(%08x)\n", status);
152
153     pNtClose(pipe);
154 }
155
156 #define DIRECTORY_QUERY (0x0001)
157 #define SYMBOLIC_LINK_QUERY 0x0001
158
159 #define DIR_TEST_CREATE_FAILURE(h,e) \
160     status = pNtCreateDirectoryObject(h, DIRECTORY_QUERY, &attr);\
161     ok(status == e,"NtCreateDirectoryObject should have failed with %s got(%08x)\n", #e, status);
162 #define DIR_TEST_OPEN_FAILURE(h,e) \
163     status = pNtOpenDirectoryObject(h, DIRECTORY_QUERY, &attr);\
164     ok(status == e,"NtOpenDirectoryObject should have failed with %s got(%08x)\n", #e, status);
165 #define DIR_TEST_CREATE_OPEN_FAILURE(h,n,e) \
166     pRtlCreateUnicodeStringFromAsciiz(&str, n);\
167     DIR_TEST_CREATE_FAILURE(h,e) DIR_TEST_OPEN_FAILURE(h,e)\
168     pRtlFreeUnicodeString(&str);
169
170 #define DIR_TEST_CREATE_SUCCESS(h) \
171     status = pNtCreateDirectoryObject(h, DIRECTORY_QUERY, &attr); \
172     ok(status == STATUS_SUCCESS, "Failed to create Directory(%08x)\n", status);
173 #define DIR_TEST_OPEN_SUCCESS(h) \
174     status = pNtOpenDirectoryObject(h, DIRECTORY_QUERY, &attr); \
175     ok(status == STATUS_SUCCESS, "Failed to open Directory(%08x)\n", status);
176 #define DIR_TEST_CREATE_OPEN_SUCCESS(h,n) \
177     pRtlCreateUnicodeStringFromAsciiz(&str, n);\
178     DIR_TEST_CREATE_SUCCESS(&h) pNtClose(h); DIR_TEST_OPEN_SUCCESS(&h) pNtClose(h); \
179     pRtlFreeUnicodeString(&str);
180
181 static void test_name_collisions(void)
182 {
183     NTSTATUS status;
184     UNICODE_STRING str;
185     OBJECT_ATTRIBUTES attr;
186     HANDLE dir, h, h1, h2;
187     DWORD winerr;
188     LARGE_INTEGER size;
189
190     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
191     pRtlCreateUnicodeStringFromAsciiz(&str, "\\");
192     DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_COLLISION)
193     InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, 0, NULL);
194
195     DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_EXISTS)
196     pNtClose(h);
197     status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE);
198     ok(status == STATUS_OBJECT_TYPE_MISMATCH,
199         "NtCreateMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08x)\n", status);
200     pRtlFreeUnicodeString(&str);
201
202     pRtlCreateUnicodeStringFromAsciiz(&str, "\\??\\PIPE\\om.c-mutant");
203     status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE);
204     ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_OBJECT_PATH_NOT_FOUND,
205         "NtCreateMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08x)\n", status);
206     pRtlFreeUnicodeString(&str);
207
208
209     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects");
210     DIR_TEST_OPEN_SUCCESS(&dir)
211     pRtlCreateUnicodeStringFromAsciiz(&str, "om.c-test");
212     InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, dir, NULL);
213     
214     h = CreateMutexA(NULL, FALSE, "om.c-test");
215     ok(h != 0, "CreateMutexA failed got ret=%p (%d)\n", h, GetLastError());
216     status = pNtCreateMutant(&h1, GENERIC_ALL, &attr, FALSE);
217     ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL,
218         "NtCreateMutant should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status);
219     h2 = CreateMutexA(NULL, FALSE, "om.c-test");
220     winerr = GetLastError();
221     ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS,
222         "CreateMutexA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr);
223     pNtClose(h);
224     pNtClose(h1);
225     pNtClose(h2);
226
227     h = CreateEventA(NULL, FALSE, FALSE, "om.c-test");
228     ok(h != 0, "CreateEventA failed got ret=%p (%d)\n", h, GetLastError());
229     status = pNtCreateEvent(&h1, GENERIC_ALL, &attr, FALSE, FALSE);
230     ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL,
231         "NtCreateEvent should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status);
232     h2 = CreateEventA(NULL, FALSE, FALSE, "om.c-test");
233     winerr = GetLastError();
234     ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS,
235         "CreateEventA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr);
236     pNtClose(h);
237     pNtClose(h1);
238     pNtClose(h2);
239
240     h = CreateSemaphoreA(NULL, 1, 2, "om.c-test");
241     ok(h != 0, "CreateSemaphoreA failed got ret=%p (%d)\n", h, GetLastError());
242     status = pNtCreateSemaphore(&h1, GENERIC_ALL, &attr, 1, 2);
243     ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL,
244         "NtCreateSemaphore should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status);
245     h2 = CreateSemaphoreA(NULL, 1, 2, "om.c-test");
246     winerr = GetLastError();
247     ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS,
248         "CreateSemaphoreA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr);
249     pNtClose(h);
250     pNtClose(h1);
251     pNtClose(h2);
252     
253     h = pCreateWaitableTimerA(NULL, TRUE, "om.c-test");
254     ok(h != 0, "CreateWaitableTimerA failed got ret=%p (%d)\n", h, GetLastError());
255     status = pNtCreateTimer(&h1, GENERIC_ALL, &attr, NotificationTimer);
256     ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL,
257         "NtCreateTimer should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status);
258     h2 = pCreateWaitableTimerA(NULL, TRUE, "om.c-test");
259     winerr = GetLastError();
260     ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS,
261         "CreateWaitableTimerA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr);
262     pNtClose(h);
263     pNtClose(h1);
264     pNtClose(h2);
265
266     h = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 256, "om.c-test");
267     ok(h != 0, "CreateFileMappingA failed got ret=%p (%d)\n", h, GetLastError());
268     size.u.LowPart = 256;
269     size.u.HighPart = 0;
270     status = pNtCreateSection(&h1, SECTION_MAP_WRITE, &attr, &size, PAGE_READWRITE, SEC_COMMIT, 0);
271     ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL,
272         "NtCreateSection should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status);
273     h2 = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 256, "om.c-test");
274     winerr = GetLastError();
275     ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS,
276         "CreateFileMappingA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr);
277     pNtClose(h);
278     pNtClose(h1);
279     pNtClose(h2);
280
281     pRtlFreeUnicodeString(&str);
282     pNtClose(dir);
283 }
284
285 static void test_directory(void)
286 {
287     NTSTATUS status;
288     UNICODE_STRING str;
289     OBJECT_ATTRIBUTES attr;
290     HANDLE dir, dir1, h;
291     BOOL is_nt4;
292
293     /* No name and/or no attributes */
294     status = pNtCreateDirectoryObject(NULL, DIRECTORY_QUERY, &attr);
295     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
296         "NtCreateDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08x)\n", status);
297     status = pNtOpenDirectoryObject(NULL, DIRECTORY_QUERY, &attr);
298     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
299         "NtOpenDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08x)\n", status);
300
301     status = pNtCreateDirectoryObject(&h, DIRECTORY_QUERY, NULL);
302     ok(status == STATUS_SUCCESS, "Failed to create Directory without attributes(%08x)\n", status);
303     pNtClose(h);
304     status = pNtOpenDirectoryObject(&h, DIRECTORY_QUERY, NULL);
305     ok(status == STATUS_INVALID_PARAMETER,
306         "NtOpenDirectoryObject should have failed with STATUS_INVALID_PARAMETER got(%08x)\n", status);
307
308     InitializeObjectAttributes(&attr, NULL, 0, 0, NULL);
309     DIR_TEST_CREATE_SUCCESS(&dir)
310     DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD)
311
312     /* Bad name */
313     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
314
315     pRtlCreateUnicodeStringFromAsciiz(&str, "");
316     DIR_TEST_CREATE_SUCCESS(&h)
317     pNtClose(h);
318     DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD)
319     pRtlFreeUnicodeString(&str);
320     pNtClose(dir);
321
322     DIR_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects", STATUS_OBJECT_PATH_SYNTAX_BAD)
323     DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\", STATUS_OBJECT_NAME_INVALID)
324     DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects", STATUS_OBJECT_NAME_INVALID)
325     DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test", STATUS_OBJECT_NAME_INVALID)
326     DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\om.c-test\\", STATUS_OBJECT_PATH_NOT_FOUND)
327
328     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\om.c-test");
329     DIR_TEST_CREATE_SUCCESS(&h)
330     DIR_TEST_OPEN_SUCCESS(&dir1)
331     pRtlFreeUnicodeString(&str);
332     pNtClose(h);
333     pNtClose(dir1);
334
335
336     /* Use of root directory */
337
338     /* Can't use symlinks as a directory */
339     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local");
340     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
341     status = pNtOpenSymbolicLinkObject(&dir, SYMBOLIC_LINK_QUERY, &attr);
342     is_nt4 = (status == STATUS_OBJECT_NAME_NOT_FOUND);  /* nt4 doesn't have Local\\ symlink */
343     if (!is_nt4)
344     {
345         ok(status == STATUS_SUCCESS, "Failed to open SymbolicLink(%08x)\n", status);
346         pRtlFreeUnicodeString(&str);
347         InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
348         pRtlCreateUnicodeStringFromAsciiz(&str, "one more level");
349         DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_TYPE_MISMATCH)
350         pRtlFreeUnicodeString(&str);
351         pNtClose(h);
352         pNtClose(dir);
353     }
354
355     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects");
356     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
357     DIR_TEST_OPEN_SUCCESS(&dir)
358     pRtlFreeUnicodeString(&str);
359
360     InitializeObjectAttributes(&attr, NULL, 0, dir, NULL);
361     DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_NAME_INVALID)
362
363     InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
364     DIR_TEST_CREATE_OPEN_SUCCESS(h, "")
365     DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\", STATUS_OBJECT_PATH_SYNTAX_BAD)
366     DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test", STATUS_OBJECT_PATH_SYNTAX_BAD)
367     DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test\\", STATUS_OBJECT_PATH_SYNTAX_BAD)
368     DIR_TEST_CREATE_OPEN_FAILURE(&h, "om.c-test\\", STATUS_OBJECT_PATH_NOT_FOUND)
369
370     pRtlCreateUnicodeStringFromAsciiz(&str, "om.c-test");
371     DIR_TEST_CREATE_SUCCESS(&dir1)
372     DIR_TEST_OPEN_SUCCESS(&h)
373     pRtlFreeUnicodeString(&str);
374
375     pNtClose(h);
376     pNtClose(dir1);
377     pNtClose(dir);
378
379     /* Nested directories */
380     pRtlCreateUnicodeStringFromAsciiz(&str, "\\");
381     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
382     DIR_TEST_OPEN_SUCCESS(&dir)
383     InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
384     DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD)
385     pRtlFreeUnicodeString(&str);
386     pNtClose(dir);
387
388     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
389     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\om.c-test");
390     DIR_TEST_CREATE_SUCCESS(&dir)
391     pRtlFreeUnicodeString(&str);
392     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\om.c-test\\one more level");
393     DIR_TEST_CREATE_SUCCESS(&h)
394     pRtlFreeUnicodeString(&str);
395     pNtClose(h);
396     InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
397     pRtlCreateUnicodeStringFromAsciiz(&str, "one more level");
398     DIR_TEST_CREATE_SUCCESS(&h)
399     pRtlFreeUnicodeString(&str);
400     pNtClose(h);
401
402     pNtClose(dir);
403
404     if (!is_nt4)
405     {
406         InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
407         pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Global\\om.c-test");
408         DIR_TEST_CREATE_SUCCESS(&dir)
409         pRtlFreeUnicodeString(&str);
410         pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local\\om.c-test\\one more level");
411         DIR_TEST_CREATE_SUCCESS(&h)
412         pRtlFreeUnicodeString(&str);
413         pNtClose(h);
414         InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
415         pRtlCreateUnicodeStringFromAsciiz(&str, "one more level");
416         DIR_TEST_CREATE_SUCCESS(&dir)
417         pRtlFreeUnicodeString(&str);
418         pNtClose(h);
419         pNtClose(dir);
420     }
421
422     /* Create other objects using RootDirectory */
423
424     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
425     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects");
426     DIR_TEST_OPEN_SUCCESS(&dir)
427     pRtlFreeUnicodeString(&str);
428     InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
429
430     /* Test invalid paths */
431     pRtlCreateUnicodeStringFromAsciiz(&str, "\\om.c-mutant");
432     status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE);
433     ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD,
434         "NtCreateMutant should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08x)\n", status);
435     pRtlFreeUnicodeString(&str);
436     pRtlCreateUnicodeStringFromAsciiz(&str, "\\om.c-mutant\\");
437     status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE);
438     ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD,
439         "NtCreateMutant should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08x)\n", status);
440     pRtlFreeUnicodeString(&str);
441
442     pRtlCreateUnicodeStringFromAsciiz(&str, "om.c\\-mutant");
443     status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE);
444     ok(status == STATUS_OBJECT_PATH_NOT_FOUND,
445         "NtCreateMutant should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08x)\n", status);
446     pRtlFreeUnicodeString(&str);
447
448     pRtlCreateUnicodeStringFromAsciiz(&str, "om.c-mutant");
449     status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE);
450     ok(status == STATUS_SUCCESS, "Failed to create Mutant(%08x)\n", status);
451     pRtlFreeUnicodeString(&str);
452     pNtClose(h);
453
454     pNtClose(dir);
455 }
456
457 #define SYMLNK_TEST_CREATE_OPEN_FAILURE2(h,n,t,e,e2) \
458     pRtlCreateUnicodeStringFromAsciiz(&str, n);\
459     pRtlCreateUnicodeStringFromAsciiz(&target, t);\
460     status = pNtCreateSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr, &target);\
461     ok(status == e || status == e2, \
462        "NtCreateSymbolicLinkObject should have failed with %s or %s got(%08x)\n", #e, #e2, status);\
463     status = pNtOpenSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr);\
464     ok(status == e || status == e2, \
465        "NtOpenSymbolicLinkObject should have failed with %s or %s got(%08x)\n", #e, #e2, status);\
466     pRtlFreeUnicodeString(&target);\
467     pRtlFreeUnicodeString(&str);
468
469 #define SYMLNK_TEST_CREATE_OPEN_FAILURE(h,n,t,e) SYMLNK_TEST_CREATE_OPEN_FAILURE2(h,n,t,e,e)
470
471 static void test_symboliclink(void)
472 {
473     NTSTATUS status;
474     UNICODE_STRING str, target;
475     OBJECT_ATTRIBUTES attr;
476     HANDLE dir, link, h;
477     IO_STATUS_BLOCK iosb;
478
479     /* No name and/or no attributes */
480     SYMLNK_TEST_CREATE_OPEN_FAILURE2(NULL, "", "", STATUS_ACCESS_VIOLATION, STATUS_INVALID_PARAMETER)
481
482     status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, NULL);
483     ok(status == STATUS_ACCESS_VIOLATION,
484         "NtCreateSymbolicLinkObject should have failed with STATUS_ACCESS_VIOLATION got(%08x)\n", status);
485     status = pNtOpenSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL);
486     ok(status == STATUS_INVALID_PARAMETER,
487         "NtOpenSymbolicLinkObject should have failed with STATUS_INVALID_PARAMETER got(%08x)\n", status);
488
489     /* No attributes */
490     pRtlCreateUnicodeStringFromAsciiz(&target, "\\DosDevices");
491     status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, &target);
492     ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_VIOLATION, /* nt4 */
493        "NtCreateSymbolicLinkObject failed(%08x)\n", status);
494     pRtlFreeUnicodeString(&target);
495     if (!status) pNtClose(h);
496
497     InitializeObjectAttributes(&attr, NULL, 0, 0, NULL);
498     status = pNtCreateSymbolicLinkObject(&link, SYMBOLIC_LINK_QUERY, &attr, &target);
499     ok(status == STATUS_INVALID_PARAMETER ||
500        broken(status == STATUS_SUCCESS),  /* nt4 */
501        "NtCreateSymbolicLinkObject should have failed with STATUS_INVALID_PARAMETER got(%08x)\n", status);
502     if (!status) pNtClose(h);
503     status = pNtOpenSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, &attr);
504     ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD,
505        "NtOpenSymbolicLinkObject should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08x)\n", status);
506
507     /* Bad name */
508     pRtlCreateUnicodeStringFromAsciiz(&target, "anywhere");
509     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
510
511     pRtlCreateUnicodeStringFromAsciiz(&str, "");
512     status = pNtCreateSymbolicLinkObject(&link, SYMBOLIC_LINK_QUERY, &attr, &target);
513     ok(status == STATUS_SUCCESS, "Failed to create SymbolicLink(%08x)\n", status);
514     status = pNtOpenSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, &attr);
515     ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD,
516        "NtOpenSymbolicLinkObject should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08x)\n", status);
517     pNtClose(link);
518     pRtlFreeUnicodeString(&str);
519
520     pRtlCreateUnicodeStringFromAsciiz(&str, "\\");
521     status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, &attr, &target);
522     todo_wine ok(status == STATUS_OBJECT_TYPE_MISMATCH,
523                  "NtCreateSymbolicLinkObject should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08x)\n", status);
524     pRtlFreeUnicodeString(&str);
525     pRtlFreeUnicodeString(&target);
526
527     SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects", "->Somewhere", STATUS_OBJECT_PATH_SYNTAX_BAD)
528     SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\", "->Somewhere", STATUS_OBJECT_NAME_INVALID)
529     SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects", "->Somewhere", STATUS_OBJECT_NAME_INVALID)
530     SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test", "->Somewhere", STATUS_OBJECT_NAME_INVALID)
531     SYMLNK_TEST_CREATE_OPEN_FAILURE2(&h, "\\BaseNamedObjects\\om.c-test\\", "->Somewhere",
532                                      STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND)
533
534
535     /* Compaund test */
536     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local");
537     status = pNtOpenDirectoryObject(&dir, DIRECTORY_QUERY, &attr);
538     if (status == STATUS_OBJECT_NAME_NOT_FOUND)  /* nt4 doesn't have Local\\ */
539     {
540         pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects");
541         status = pNtOpenDirectoryObject(&dir, DIRECTORY_QUERY, &attr);
542     }
543     ok(status == STATUS_SUCCESS, "Failed to open Directory(%08x)\n", status);
544     pRtlFreeUnicodeString(&str);
545
546     InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
547     pRtlCreateUnicodeStringFromAsciiz(&str, "test-link");
548     pRtlCreateUnicodeStringFromAsciiz(&target, "\\DosDevices");
549     status = pNtCreateSymbolicLinkObject(&link, SYMBOLIC_LINK_QUERY, &attr, &target);
550     ok(status == STATUS_SUCCESS, "Failed to create SymbolicLink(%08x)\n", status);
551     pRtlFreeUnicodeString(&str);
552     pRtlFreeUnicodeString(&target);
553
554     pRtlCreateUnicodeStringFromAsciiz(&str, "test-link\\PIPE");
555     status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN);
556     ok(status == STATUS_SUCCESS, "Failed to open NamedPipe(%08x)\n", status);
557     pRtlFreeUnicodeString(&str);
558
559     pNtClose(h);
560     pNtClose(link);
561     pNtClose(dir);
562 }
563
564 START_TEST(om)
565 {
566     HMODULE hntdll = GetModuleHandleA("ntdll.dll");
567     HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
568
569     if (!hntdll)
570     {
571         skip("not running on NT, skipping test\n");
572         return;
573     }
574
575     pCreateWaitableTimerA = (void *)GetProcAddress(hkernel32, "CreateWaitableTimerA");
576
577     pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz");
578     pRtlFreeUnicodeString   = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
579     pNtCreateEvent          = (void *)GetProcAddress(hntdll, "NtCreateEvent");
580     pNtCreateMutant         = (void *)GetProcAddress(hntdll, "NtCreateMutant");
581     pNtOpenMutant           = (void *)GetProcAddress(hntdll, "NtOpenMutant");
582     pNtOpenFile             = (void *)GetProcAddress(hntdll, "NtOpenFile");
583     pNtClose                = (void *)GetProcAddress(hntdll, "NtClose");
584     pRtlInitUnicodeString   = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
585     pNtCreateNamedPipeFile  = (void *)GetProcAddress(hntdll, "NtCreateNamedPipeFile");
586     pNtOpenDirectoryObject  = (void *)GetProcAddress(hntdll, "NtOpenDirectoryObject");
587     pNtCreateDirectoryObject= (void *)GetProcAddress(hntdll, "NtCreateDirectoryObject");
588     pNtOpenSymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtOpenSymbolicLinkObject");
589     pNtCreateSymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtCreateSymbolicLinkObject");
590     pNtCreateSemaphore      =  (void *)GetProcAddress(hntdll, "NtCreateSemaphore");
591     pNtCreateTimer          =  (void *)GetProcAddress(hntdll, "NtCreateTimer");
592     pNtCreateSection        =  (void *)GetProcAddress(hntdll, "NtCreateSection");
593
594     test_case_sensitive();
595     test_namespace_pipe();
596     test_name_collisions();
597     test_directory();
598     test_symboliclink();
599 }