:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / ntoskrnl / io / symlink.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/io/symlink.c
6  * PURPOSE:         Implements symbolic links
7  * PROGRAMMER:      David Welch (welch@mcmail.com)
8  * UPDATE HISTORY:
9  *                  Created 22/05/98
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <limits.h>
15 #include <ddk/ntddk.h>
16 #include <internal/pool.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* GLOBALS ******************************************************************/
22
23 typedef struct
24 {
25         CSHORT                  Type;
26         CSHORT                  Size;
27         UNICODE_STRING          TargetName;
28         OBJECT_ATTRIBUTES       Target;
29 } SYMLNK_OBJECT, *PSYMLNK_OBJECT;
30
31 POBJECT_TYPE IoSymbolicLinkType = NULL;
32
33 static GENERIC_MAPPING IopSymbolicLinkMapping = {
34         STANDARD_RIGHTS_READ|SYMBOLIC_LINK_QUERY,
35         STANDARD_RIGHTS_WRITE,
36         STANDARD_RIGHTS_EXECUTE|SYMBOLIC_LINK_QUERY,
37         SYMBOLIC_LINK_ALL_ACCESS};
38
39 #define TAG_SYMLINK_TTARGET     TAG('S', 'Y', 'T', 'T')
40 #define TAG_SYMLINK_TARGET      TAG('S', 'Y', 'M', 'T')
41
42 /* FUNCTIONS *****************************************************************/
43
44
45 /**********************************************************************
46  * NAME                                                 INTERNAL
47  *      IopCreateSymbolicLink
48  *
49  * DESCRIPTION
50  *
51  * ARGUMENTS
52  *
53  * RETURNN VALUE
54  *      Status.
55  *
56  * REVISIONS
57  */
58 NTSTATUS STDCALL
59 IopCreateSymbolicLink(PVOID Object,
60                       PVOID Parent,
61                       PWSTR RemainingPath,
62                       POBJECT_ATTRIBUTES ObjectAttributes)
63 {
64   return(STATUS_SUCCESS);
65 }
66
67
68 /**********************************************************************
69  * NAME                                                 INTERNAL
70  *      IopParseSymbolicLink
71  *
72  * DESCRIPTION
73  *
74  * ARGUMENTS
75  *
76  * RETURN VALUE
77  *
78  * REVISIONS
79  */
80 NTSTATUS STDCALL
81 IopParseSymbolicLink(PVOID Object,
82                      PVOID * NextObject,
83                      PUNICODE_STRING FullPath,
84                      PWSTR * RemainingPath,
85                      ULONG Attributes)
86 {
87    PSYMLNK_OBJECT SymlinkObject = (PSYMLNK_OBJECT) Object;
88    UNICODE_STRING TargetPath;
89
90    DPRINT("IopParseSymbolicLink (RemainingPath %S)\n", *RemainingPath);
91    /*
92     * Stop parsing if the entire path has been parsed and
93     * the desired object is a symbolic link object.
94     */
95    if (((*RemainingPath == NULL) || (**RemainingPath == 0)) &&
96        (Attributes & OBJ_OPENLINK))
97      {
98         DPRINT("Parsing stopped!\n");
99         *NextObject = NULL;
100         return STATUS_SUCCESS;
101      }
102
103    /* build the expanded path */
104    TargetPath.MaximumLength = SymlinkObject->TargetName.Length + sizeof(WCHAR);
105    if (RemainingPath && *RemainingPath)
106      {
107         TargetPath.MaximumLength += (wcslen(*RemainingPath) * sizeof(WCHAR));
108      }
109    TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
110    TargetPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
111                                              TargetPath.MaximumLength,
112                                              TAG_SYMLINK_TTARGET);
113    wcscpy(TargetPath.Buffer, SymlinkObject->TargetName.Buffer);
114    if (RemainingPath && *RemainingPath)
115      {
116         wcscat(TargetPath.Buffer, *RemainingPath);
117      }
118
119    /* transfer target path buffer into FullPath */
120    RtlFreeUnicodeString(FullPath);
121    FullPath->Length = TargetPath.Length;
122    FullPath->MaximumLength = TargetPath.MaximumLength;
123    FullPath->Buffer = TargetPath.Buffer;
124
125    /* reinitialize RemainingPath for reparsing */
126    *RemainingPath = FullPath->Buffer;
127
128    *NextObject = NULL;
129    return STATUS_REPARSE;
130 }
131
132 /**********************************************************************
133  * NAME                                                 INTERNAL
134  *      IoInitSymbolicLinkImplementation
135  *
136  * DESCRIPTION
137  *
138  * ARGUMENTS
139  *      None.
140  *
141  * RETURNN VALUE
142  *      None.
143  *
144  * REVISIONS
145  */
146 VOID IoInitSymbolicLinkImplementation (VOID)
147 {
148    IoSymbolicLinkType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
149    
150    IoSymbolicLinkType->Tag = TAG('S', 'Y', 'M', 'T');
151    IoSymbolicLinkType->TotalObjects = 0;
152    IoSymbolicLinkType->TotalHandles = 0;
153    IoSymbolicLinkType->MaxObjects = ULONG_MAX;
154    IoSymbolicLinkType->MaxHandles = ULONG_MAX;
155    IoSymbolicLinkType->PagedPoolCharge = 0;
156    IoSymbolicLinkType->NonpagedPoolCharge = sizeof (SYMLNK_OBJECT);
157    IoSymbolicLinkType->Mapping = &IopSymbolicLinkMapping;
158    IoSymbolicLinkType->Dump = NULL;
159    IoSymbolicLinkType->Open = NULL;
160    IoSymbolicLinkType->Close = NULL;
161    IoSymbolicLinkType->Delete = NULL;
162    IoSymbolicLinkType->Parse = IopParseSymbolicLink;
163    IoSymbolicLinkType->Security = NULL;
164    IoSymbolicLinkType->QueryName = NULL;
165    IoSymbolicLinkType->OkayToClose = NULL;
166    IoSymbolicLinkType->Create = IopCreateSymbolicLink;
167    IoSymbolicLinkType->DuplicationNotify = NULL;
168    
169    RtlInitUnicodeStringFromLiteral(&IoSymbolicLinkType->TypeName,
170                         L"SymbolicLink");
171 }
172
173
174 /**********************************************************************
175  * NAME                                                 EXPORTED
176  *      NtOpenSymbolicLinkObject
177  *
178  * DESCRIPTION
179  *
180  * ARGUMENTS
181  *
182  * RETURN VALUE
183  *
184  * REVISIONS
185  *
186  */
187 NTSTATUS STDCALL
188 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
189                          IN ACCESS_MASK DesiredAccess,
190                          IN POBJECT_ATTRIBUTES ObjectAttributes)
191 {
192   DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
193          ObjectAttributes->ObjectName);
194
195   return(ObOpenObjectByName(ObjectAttributes,
196                             IoSymbolicLinkType,
197                             NULL,
198                             UserMode,
199                             DesiredAccess,
200                             NULL,
201                             LinkHandle));
202 }
203
204
205 /**********************************************************************
206  * NAME                                                 EXPORTED
207  *      NtQuerySymbolicLinkObject
208  *
209  * DESCRIPTION
210  *
211  * ARGUMENTS
212  *
213  * RETURN VALUE
214  *
215  * REVISIONS
216  *
217  */
218 NTSTATUS STDCALL
219 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
220                           IN OUT PUNICODE_STRING LinkTarget,
221                           OUT PULONG ReturnedLength OPTIONAL)
222 {
223   PSYMLNK_OBJECT SymlinkObject;
224   NTSTATUS Status;
225   
226   Status = ObReferenceObjectByHandle(LinkHandle,
227                                      SYMBOLIC_LINK_QUERY,
228                                      IoSymbolicLinkType,
229                                      UserMode,
230                                      (PVOID *)&SymlinkObject,
231                                      NULL);
232   if (!NT_SUCCESS(Status))
233     {
234       return(Status);
235     }
236   
237   RtlCopyUnicodeString(LinkTarget,
238                        SymlinkObject->Target.ObjectName);
239   if (ReturnedLength != NULL)
240     {
241       *ReturnedLength = SymlinkObject->Target.Length;
242     }
243   ObDereferenceObject(SymlinkObject);
244   
245   return(STATUS_SUCCESS);
246 }
247
248
249 /**********************************************************************
250  * NAME                                                 EXPORTED
251  *      IoCreateUnprotectedSymbolicLink
252  *
253  * DESCRIPTION
254  *
255  * ARGUMENTS
256  *
257  * RETURN VALUE
258  *
259  * REVISIONS
260  *
261  */
262 NTSTATUS STDCALL
263 IoCreateUnprotectedSymbolicLink(PUNICODE_STRING SymbolicLinkName,
264                                 PUNICODE_STRING DeviceName)
265 {
266   return(IoCreateSymbolicLink(SymbolicLinkName,
267                               DeviceName));
268 }
269
270
271 /**********************************************************************
272  * NAME                                                 EXPORTED
273  *      IoCreateSymbolicLink
274  *
275  * DESCRIPTION
276  *
277  * ARGUMENTS
278  *
279  * RETURN VALUE
280  *
281  * REVISIONS
282  *
283  */
284 NTSTATUS STDCALL
285 IoCreateSymbolicLink(PUNICODE_STRING SymbolicLinkName,
286                      PUNICODE_STRING DeviceName)
287 {
288         OBJECT_ATTRIBUTES       ObjectAttributes;
289         PSYMLNK_OBJECT          SymbolicLink;
290         NTSTATUS                Status;
291
292         assert_irql(PASSIVE_LEVEL);
293
294         DPRINT(
295                 "IoCreateSymbolicLink(SymbolicLinkName %S, DeviceName %S)\n",
296                 SymbolicLinkName->Buffer,
297                 DeviceName->Buffer
298                 );
299
300         InitializeObjectAttributes(
301                 & ObjectAttributes,
302                 SymbolicLinkName,
303                 OBJ_PERMANENT,
304                 NULL,
305                 NULL
306                 );
307         Status = ObCreateObject(
308                         NULL,
309                         SYMBOLIC_LINK_ALL_ACCESS,
310                         & ObjectAttributes,
311                         IoSymbolicLinkType,
312                         (PVOID*)&SymbolicLink
313                         );
314         if (!NT_SUCCESS(Status))
315         {
316                 return(Status);
317         }
318         SymbolicLink->TargetName.Length = 0;
319         SymbolicLink->TargetName.MaximumLength = 
320                 ((wcslen(DeviceName->Buffer) + 1) * sizeof(WCHAR));
321         SymbolicLink->TargetName.Buffer =
322                 ExAllocatePoolWithTag(NonPagedPool,
323                                SymbolicLink->TargetName.MaximumLength,
324                                TAG_SYMLINK_TARGET);
325         RtlCopyUnicodeString(
326                 & (SymbolicLink->TargetName),
327                 DeviceName
328                 );
329         
330         DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
331         
332         InitializeObjectAttributes(
333                 & (SymbolicLink->Target),
334                 & (SymbolicLink->TargetName),
335                 0,
336                 NULL,
337                 NULL
338                 );
339         
340         DPRINT("%s() = STATUS_SUCCESS\n",__FUNCTION__);
341         ObDereferenceObject( SymbolicLink );
342         return STATUS_SUCCESS;
343 }
344
345
346 /**********************************************************************
347  * NAME                                                 EXPORTED
348  *      IoDeleteSymbolicLink
349  *
350  * DESCRIPTION
351  *
352  * ARGUMENTS
353  *
354  * RETURN VALUE
355  *
356  * REVISIONS
357  *
358  */
359 NTSTATUS STDCALL
360 IoDeleteSymbolicLink(PUNICODE_STRING SymbolicLinkName)
361 {
362   OBJECT_ATTRIBUTES ObjectAttributes;
363   HANDLE Handle;
364   NTSTATUS Status;
365
366   assert_irql(PASSIVE_LEVEL);
367
368   DPRINT("IoDeleteSymbolicLink (SymbolicLinkName %S)\n",
369          SymbolicLinkName->Buffer);
370
371   InitializeObjectAttributes(&ObjectAttributes,
372                              SymbolicLinkName,
373                              OBJ_OPENLINK,
374                              NULL,
375                              NULL);
376
377   Status = NtOpenSymbolicLinkObject(&Handle,
378                                     SYMBOLIC_LINK_ALL_ACCESS,
379                                     &ObjectAttributes);
380   if (!NT_SUCCESS(Status))
381     return(Status);
382
383   Status = NtMakeTemporaryObject(Handle);
384   NtClose(Handle);
385
386   return(Status);
387 }
388
389
390 /**********************************************************************
391  * NAME                                         (EXPORTED as Zw)
392  *      NtCreateSymbolicLinkObject
393  *
394  * DESCRIPTION
395  *
396  * ARGUMENTS
397  *
398  * RETURN VALUE
399  *
400  * REVISIONS
401  *
402  */
403 NTSTATUS STDCALL
404 NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,
405                            IN ACCESS_MASK DesiredAccess,
406                            IN POBJECT_ATTRIBUTES ObjectAttributes,
407                            IN PUNICODE_STRING DeviceName)
408 {
409    PSYMLNK_OBJECT SymbolicLink;
410    NTSTATUS Status;
411    
412    assert_irql(PASSIVE_LEVEL);
413    
414    DPRINT("NtCreateSymbolicLinkObject(SymbolicLinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, DeviceName %S)\n",
415           SymbolicLinkHandle,
416           DesiredAccess,
417           ObjectAttributes,
418           DeviceName->Buffer);
419
420    Status = ObCreateObject(SymbolicLinkHandle,
421                            DesiredAccess,
422                            ObjectAttributes,
423                            IoSymbolicLinkType,
424                            (PVOID*)&SymbolicLink);
425    if (!NT_SUCCESS(Status))
426      {
427         return(Status);
428      }
429    
430    SymbolicLink->TargetName.Length = 0;
431    SymbolicLink->TargetName.MaximumLength = 
432      ((wcslen(DeviceName->Buffer) + 1) * sizeof(WCHAR));
433    SymbolicLink->TargetName.Buffer = 
434      ExAllocatePoolWithTag(NonPagedPool,
435                            SymbolicLink->TargetName.MaximumLength,
436                            TAG_SYMLINK_TARGET);
437    RtlCopyUnicodeString(&SymbolicLink->TargetName,
438                         DeviceName);
439    
440    DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
441    
442    InitializeObjectAttributes(&SymbolicLink->Target,
443                               &SymbolicLink->TargetName,
444                               0,
445                               NULL,
446                               NULL);
447    
448    DPRINT("%s() = STATUS_SUCCESS\n",__FUNCTION__);
449    ObDereferenceObject(SymbolicLink);
450    return(STATUS_SUCCESS);
451 }
452
453 /* EOF */