83cf74f316b27982fa0e1b906e44bba3e2a0f55a
[reactos.git] / ntoskrnl / ob / symlink.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/ob/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/ob.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 ObSymbolicLinkType = NULL;
32
33 static GENERIC_MAPPING ObpSymbolicLinkMapping = {
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  *      ObpCreateSymbolicLink
48  *
49  * DESCRIPTION
50  *
51  * ARGUMENTS
52  *
53  * RETURNN VALUE
54  *      Status.
55  *
56  * REVISIONS
57  */
58 NTSTATUS STDCALL
59 ObpCreateSymbolicLink(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  *      ObpDeleteSymbolicLink
71  *
72  * DESCRIPTION
73  *
74  * ARGUMENTS
75  *
76  * RETURNN VALUE
77  *      Status.
78  *
79  * REVISIONS
80  */
81 VOID STDCALL
82 ObpDeleteSymbolicLink(PVOID ObjectBody)
83 {
84   PSYMLNK_OBJECT SymlinkObject = (PSYMLNK_OBJECT)ObjectBody;
85
86   RtlFreeUnicodeString(&SymlinkObject->TargetName);
87 }
88
89
90 /**********************************************************************
91  * NAME                                                 INTERNAL
92  *      ObpParseSymbolicLink
93  *
94  * DESCRIPTION
95  *
96  * ARGUMENTS
97  *
98  * RETURN VALUE
99  *
100  * REVISIONS
101  */
102 NTSTATUS STDCALL
103 ObpParseSymbolicLink(PVOID Object,
104                      PVOID * NextObject,
105                      PUNICODE_STRING FullPath,
106                      PWSTR * RemainingPath,
107                      ULONG Attributes)
108 {
109   PSYMLNK_OBJECT SymlinkObject = (PSYMLNK_OBJECT) Object;
110   UNICODE_STRING TargetPath;
111
112   DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath);
113
114   /*
115    * Stop parsing if the entire path has been parsed and
116    * the desired object is a symbolic link object.
117    */
118   if (((*RemainingPath == NULL) || (**RemainingPath == 0)) &&
119       (Attributes & OBJ_OPENLINK))
120     {
121       DPRINT("Parsing stopped!\n");
122       *NextObject = NULL;
123       return(STATUS_SUCCESS);
124     }
125
126    /* build the expanded path */
127    TargetPath.MaximumLength = SymlinkObject->TargetName.Length + sizeof(WCHAR);
128    if (RemainingPath && *RemainingPath)
129      {
130         TargetPath.MaximumLength += (wcslen(*RemainingPath) * sizeof(WCHAR));
131      }
132    TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
133    TargetPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
134                                              TargetPath.MaximumLength,
135                                              TAG_SYMLINK_TTARGET);
136    wcscpy(TargetPath.Buffer, SymlinkObject->TargetName.Buffer);
137    if (RemainingPath && *RemainingPath)
138      {
139         wcscat(TargetPath.Buffer, *RemainingPath);
140      }
141
142    /* transfer target path buffer into FullPath */
143    RtlFreeUnicodeString(FullPath);
144    FullPath->Length = TargetPath.Length;
145    FullPath->MaximumLength = TargetPath.MaximumLength;
146    FullPath->Buffer = TargetPath.Buffer;
147
148    /* reinitialize RemainingPath for reparsing */
149    *RemainingPath = FullPath->Buffer;
150
151    *NextObject = NULL;
152    return STATUS_REPARSE;
153 }
154
155
156 /**********************************************************************
157  * NAME                                                 INTERNAL
158  *      ObInitSymbolicLinkImplementation
159  *
160  * DESCRIPTION
161  *
162  * ARGUMENTS
163  *      None.
164  *
165  * RETURNN VALUE
166  *      None.
167  *
168  * REVISIONS
169  */
170 VOID ObInitSymbolicLinkImplementation (VOID)
171 {
172   ObSymbolicLinkType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
173
174   ObSymbolicLinkType->Tag = TAG('S', 'Y', 'M', 'T');
175   ObSymbolicLinkType->TotalObjects = 0;
176   ObSymbolicLinkType->TotalHandles = 0;
177   ObSymbolicLinkType->MaxObjects = ULONG_MAX;
178   ObSymbolicLinkType->MaxHandles = ULONG_MAX;
179   ObSymbolicLinkType->PagedPoolCharge = 0;
180   ObSymbolicLinkType->NonpagedPoolCharge = sizeof(SYMLNK_OBJECT);
181   ObSymbolicLinkType->Mapping = &ObpSymbolicLinkMapping;
182   ObSymbolicLinkType->Dump = NULL;
183   ObSymbolicLinkType->Open = NULL;
184   ObSymbolicLinkType->Close = NULL;
185   ObSymbolicLinkType->Delete = ObpDeleteSymbolicLink;
186   ObSymbolicLinkType->Parse = ObpParseSymbolicLink;
187   ObSymbolicLinkType->Security = NULL;
188   ObSymbolicLinkType->QueryName = NULL;
189   ObSymbolicLinkType->OkayToClose = NULL;
190   ObSymbolicLinkType->Create = ObpCreateSymbolicLink;
191   ObSymbolicLinkType->DuplicationNotify = NULL;
192
193   RtlInitUnicodeStringFromLiteral(&ObSymbolicLinkType->TypeName,
194                                   L"SymbolicLink");
195
196   ObpCreateTypeObject(ObSymbolicLinkType);
197 }
198
199
200 /**********************************************************************
201  * NAME                                         EXPORTED
202  *      NtCreateSymbolicLinkObject
203  *
204  * DESCRIPTION
205  *
206  * ARGUMENTS
207  *
208  * RETURN VALUE
209  *
210  * REVISIONS
211  *
212  */
213 NTSTATUS STDCALL
214 NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,
215                            IN ACCESS_MASK DesiredAccess,
216                            IN POBJECT_ATTRIBUTES ObjectAttributes,
217                            IN PUNICODE_STRING DeviceName)
218 {
219   PSYMLNK_OBJECT SymbolicLink;
220   NTSTATUS Status;
221
222   assert_irql(PASSIVE_LEVEL);
223
224   DPRINT("NtCreateSymbolicLinkObject(SymbolicLinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, DeviceName %wZ)\n",
225          SymbolicLinkHandle,
226          DesiredAccess,
227          ObjectAttributes,
228          DeviceName);
229
230   Status = ObCreateObject(SymbolicLinkHandle,
231                           DesiredAccess,
232                           ObjectAttributes,
233                           ObSymbolicLinkType,
234                           (PVOID*)&SymbolicLink);
235   if (!NT_SUCCESS(Status))
236     {
237       return(Status);
238     }
239
240   SymbolicLink->TargetName.Length = 0;
241   SymbolicLink->TargetName.MaximumLength = 
242     ((wcslen(DeviceName->Buffer) + 1) * sizeof(WCHAR));
243   SymbolicLink->TargetName.Buffer = 
244     ExAllocatePoolWithTag(NonPagedPool,
245                           SymbolicLink->TargetName.MaximumLength,
246                           TAG_SYMLINK_TARGET);
247   RtlCopyUnicodeString(&SymbolicLink->TargetName,
248                        DeviceName);
249
250   DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
251
252   InitializeObjectAttributes(&SymbolicLink->Target,
253                              &SymbolicLink->TargetName,
254                              0,
255                              NULL,
256                              NULL);
257
258   DPRINT("%s() = STATUS_SUCCESS\n",__FUNCTION__);
259   ObDereferenceObject(SymbolicLink);
260
261   return(STATUS_SUCCESS);
262 }
263
264
265 /**********************************************************************
266  * NAME                                                 EXPORTED
267  *      NtOpenSymbolicLinkObject
268  *
269  * DESCRIPTION
270  *
271  * ARGUMENTS
272  *
273  * RETURN VALUE
274  *
275  * REVISIONS
276  *
277  */
278 NTSTATUS STDCALL
279 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
280                          IN ACCESS_MASK DesiredAccess,
281                          IN POBJECT_ATTRIBUTES ObjectAttributes)
282 {
283   DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
284          ObjectAttributes->ObjectName);
285
286   return(ObOpenObjectByName(ObjectAttributes,
287                             ObSymbolicLinkType,
288                             NULL,
289                             KeGetPreviousMode(),
290                             DesiredAccess,
291                             NULL,
292                             LinkHandle));
293 }
294
295
296 /**********************************************************************
297  * NAME                                                 EXPORTED
298  *      NtQuerySymbolicLinkObject
299  *
300  * DESCRIPTION
301  *
302  * ARGUMENTS
303  *
304  * RETURN VALUE
305  *
306  * REVISIONS
307  *
308  */
309 NTSTATUS STDCALL
310 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
311                           IN OUT PUNICODE_STRING LinkTarget,
312                           OUT PULONG ReturnedLength OPTIONAL)
313 {
314   PSYMLNK_OBJECT SymlinkObject;
315   NTSTATUS Status;
316
317   Status = ObReferenceObjectByHandle(LinkHandle,
318                                      SYMBOLIC_LINK_QUERY,
319                                      ObSymbolicLinkType,
320                                      KeGetPreviousMode(),
321                                      (PVOID *)&SymlinkObject,
322                                      NULL);
323   if (!NT_SUCCESS(Status))
324     {
325       return(Status);
326     }
327
328   RtlCopyUnicodeString(LinkTarget,
329                        SymlinkObject->Target.ObjectName);
330   if (ReturnedLength != NULL)
331     {
332       *ReturnedLength = SymlinkObject->Target.Length;
333     }
334   ObDereferenceObject(SymlinkObject);
335
336   return(STATUS_SUCCESS);
337 }
338
339 /* EOF */