[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / client / file / mntpoint.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/mntpoint.c
5 * PURPOSE: File volume mount point functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Erik Bos, Alexandre Julliard :
8 * GetLogicalDriveStringsA,
9 * GetLogicalDriveStringsW, GetLogicalDrives
10 * UPDATE HISTORY:
11 * Created 01/11/98
12 */
13 //WINE copyright notice:
14 /*
15 * DOS drives handling functions
16 *
17 * Copyright 1993 Erik Bos
18 * Copyright 1996 Alexandre Julliard
19 */
20
21 #include <k32.h>
22 #define NDEBUG
23 #include <debug.h>
24 DEBUG_CHANNEL(kernel32file);
25
26 /**
27 * @name GetVolumeNameForVolumeMountPointW
28 * @implemented
29 *
30 * Return an unique volume name for a drive root or mount point.
31 *
32 * @param VolumeMountPoint
33 * Pointer to string that contains either root drive name or
34 * mount point name.
35 * @param VolumeName
36 * Pointer to buffer that is filled with resulting unique
37 * volume name on success.
38 * @param VolumeNameLength
39 * Size of VolumeName buffer in TCHARs.
40 *
41 * @return
42 * TRUE when the function succeeds and the VolumeName buffer is filled,
43 * FALSE otherwise.
44 */
45 BOOL
46 WINAPI
47 GetVolumeNameForVolumeMountPointW(IN LPCWSTR VolumeMountPoint,
48 OUT LPWSTR VolumeName,
49 IN DWORD VolumeNameLength)
50 {
51 UNICODE_STRING NtFileName;
52 OBJECT_ATTRIBUTES ObjectAttributes;
53 HANDLE FileHandle;
54 IO_STATUS_BLOCK Iosb;
55 ULONG BufferLength;
56 PMOUNTDEV_NAME MountDevName;
57 PMOUNTMGR_MOUNT_POINT MountPoint;
58 ULONG MountPointSize;
59 PMOUNTMGR_MOUNT_POINTS MountPoints;
60 ULONG Index;
61 PUCHAR SymbolicLinkName;
62 BOOL Result;
63 NTSTATUS Status;
64
65 if (!VolumeMountPoint || !VolumeMountPoint[0])
66 {
67 SetLastError(ERROR_PATH_NOT_FOUND);
68 return FALSE;
69 }
70
71 /*
72 * First step is to convert the passed volume mount point name to
73 * an NT acceptable name.
74 */
75
76 if (!RtlDosPathNameToNtPathName_U(VolumeMountPoint, &NtFileName, NULL, NULL))
77 {
78 SetLastError(ERROR_PATH_NOT_FOUND);
79 return FALSE;
80 }
81
82 if (NtFileName.Length > sizeof(WCHAR) &&
83 NtFileName.Buffer[(NtFileName.Length / sizeof(WCHAR)) - 1] == '\\')
84 {
85 NtFileName.Length -= sizeof(WCHAR);
86 }
87
88 /*
89 * Query mount point device name which we will later use for determining
90 * the volume name.
91 */
92
93 InitializeObjectAttributes(&ObjectAttributes, &NtFileName, 0, NULL, NULL);
94 Status = NtOpenFile(&FileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE,
95 &ObjectAttributes, &Iosb,
96 FILE_SHARE_READ | FILE_SHARE_WRITE,
97 FILE_SYNCHRONOUS_IO_NONALERT);
98 RtlFreeUnicodeString(&NtFileName);
99 if (!NT_SUCCESS(Status))
100 {
101 BaseSetLastNTError(Status);
102 return FALSE;
103 }
104
105 BufferLength = sizeof(MOUNTDEV_NAME) + 50 * sizeof(WCHAR);
106 do
107 {
108 MountDevName = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
109 if (MountDevName == NULL)
110 {
111 NtClose(FileHandle);
112 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
113 return FALSE;
114 }
115
116 Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
117 IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
118 NULL, 0, MountDevName, BufferLength);
119 if (!NT_SUCCESS(Status))
120 {
121 if (Status == STATUS_BUFFER_OVERFLOW)
122 {
123 BufferLength = sizeof(MOUNTDEV_NAME) + MountDevName->NameLength;
124 RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
125 continue;
126 }
127 else
128 {
129 RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
130 NtClose(FileHandle);
131 BaseSetLastNTError(Status);
132 return FALSE;
133 }
134 }
135 }
136 while (!NT_SUCCESS(Status));
137
138 NtClose(FileHandle);
139
140 /*
141 * Get the mount point information from mount manager.
142 */
143
144 MountPointSize = MountDevName->NameLength + sizeof(MOUNTMGR_MOUNT_POINT);
145 MountPoint = RtlAllocateHeap(GetProcessHeap(), 0, MountPointSize);
146 if (MountPoint == NULL)
147 {
148 RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
149 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
150 return FALSE;
151 }
152 RtlZeroMemory(MountPoint, sizeof(MOUNTMGR_MOUNT_POINT));
153 MountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
154 MountPoint->DeviceNameLength = MountDevName->NameLength;
155 RtlCopyMemory(MountPoint + 1, MountDevName->Name, MountDevName->NameLength);
156 RtlFreeHeap(RtlGetProcessHeap(), 0, MountDevName);
157
158 RtlInitUnicodeString(&NtFileName, L"\\??\\MountPointManager");
159 InitializeObjectAttributes(&ObjectAttributes, &NtFileName, 0, NULL, NULL);
160 Status = NtOpenFile(&FileHandle, FILE_GENERIC_READ, &ObjectAttributes,
161 &Iosb, FILE_SHARE_READ | FILE_SHARE_WRITE,
162 FILE_SYNCHRONOUS_IO_NONALERT);
163 if (!NT_SUCCESS(Status))
164 {
165 BaseSetLastNTError(Status);
166 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint);
167 return FALSE;
168 }
169
170 BufferLength = sizeof(MOUNTMGR_MOUNT_POINTS);
171 do
172 {
173 MountPoints = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
174 if (MountPoints == NULL)
175 {
176 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint);
177 NtClose(FileHandle);
178 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
179 return FALSE;
180 }
181
182 Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
183 IOCTL_MOUNTMGR_QUERY_POINTS,
184 MountPoint, MountPointSize,
185 MountPoints, BufferLength);
186 if (!NT_SUCCESS(Status))
187 {
188 if (Status == STATUS_BUFFER_OVERFLOW)
189 {
190 BufferLength = MountPoints->Size;
191 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints);
192 continue;
193 }
194 else if (!NT_SUCCESS(Status))
195 {
196 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint);
197 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints);
198 NtClose(FileHandle);
199 BaseSetLastNTError(Status);
200 return FALSE;
201 }
202 }
203 }
204 while (!NT_SUCCESS(Status));
205
206 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint);
207 NtClose(FileHandle);
208
209 /*
210 * Now we've gathered info about all mount points mapped to our device, so
211 * select the correct one and copy it into the output buffer.
212 */
213
214 for (Index = 0; Index < MountPoints->NumberOfMountPoints; Index++)
215 {
216 MountPoint = MountPoints->MountPoints + Index;
217 SymbolicLinkName = (PUCHAR)MountPoints + MountPoint->SymbolicLinkNameOffset;
218
219 /*
220 * Check for "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
221 * (with the last slash being optional) style symbolic links.
222 */
223
224 if (MountPoint->SymbolicLinkNameLength == 48 * sizeof(WCHAR) ||
225 (MountPoint->SymbolicLinkNameLength == 49 * sizeof(WCHAR) &&
226 SymbolicLinkName[48] == L'\\'))
227 {
228 if (RtlCompareMemory(SymbolicLinkName, L"\\??\\Volume{",
229 11 * sizeof(WCHAR)) == 11 * sizeof(WCHAR) &&
230 SymbolicLinkName[19] == L'-' && SymbolicLinkName[24] == L'-' &&
231 SymbolicLinkName[29] == L'-' && SymbolicLinkName[34] == L'-' &&
232 SymbolicLinkName[47] == L'}')
233 {
234 if (VolumeNameLength >= MountPoint->SymbolicLinkNameLength / sizeof(WCHAR))
235 {
236 RtlCopyMemory(VolumeName,
237 (PUCHAR)MountPoints + MountPoint->SymbolicLinkNameOffset,
238 MountPoint->SymbolicLinkNameLength);
239 VolumeName[1] = L'\\';
240 Result = TRUE;
241 }
242 else
243 {
244 SetLastError(ERROR_FILENAME_EXCED_RANGE);
245 Result = FALSE;
246 }
247
248 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints);
249
250 return Result;
251 }
252 }
253 }
254
255 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints);
256 SetLastError(ERROR_INVALID_PARAMETER);
257
258 return FALSE;
259 }
260
261 /*
262 * @implemented (Wine 13 sep 2008)
263 */
264 BOOL
265 WINAPI
266 GetVolumeNameForVolumeMountPointA(IN LPCSTR lpszVolumeMountPoint,
267 IN LPSTR lpszVolumeName,
268 IN DWORD cchBufferLength)
269 {
270 BOOL ret;
271 WCHAR volumeW[50], *pathW = NULL;
272 DWORD len = min( sizeof(volumeW) / sizeof(WCHAR), cchBufferLength );
273
274 TRACE("(%s, %p, %x)\n", debugstr_a(lpszVolumeMountPoint), lpszVolumeName, cchBufferLength);
275
276 if (!lpszVolumeMountPoint || !(pathW = FilenameA2W( lpszVolumeMountPoint, TRUE )))
277 return FALSE;
278
279 if ((ret = GetVolumeNameForVolumeMountPointW( pathW, volumeW, len )))
280 FilenameW2A_N( lpszVolumeName, len, volumeW, -1 );
281
282 RtlFreeHeap( RtlGetProcessHeap(), 0, pathW );
283 return ret;
284 }
285
286 /*
287 * @unimplemented
288 */
289 BOOL
290 WINAPI
291 SetVolumeMountPointW(IN LPCWSTR lpszVolumeMountPoint,
292 IN LPCWSTR lpszVolumeName)
293 {
294 STUB;
295 return 0;
296 }
297
298 /*
299 * @unimplemented
300 */
301 BOOL
302 WINAPI
303 SetVolumeMountPointA(IN LPCSTR lpszVolumeMountPoint,
304 IN LPCSTR lpszVolumeName)
305 {
306 STUB;
307 return 0;
308 }
309
310 /*
311 * @unimplemented
312 */
313 BOOL
314 WINAPI
315 DeleteVolumeMountPointA(IN LPCSTR lpszVolumeMountPoint)
316 {
317 STUB;
318 return 0;
319 }
320
321 /*
322 * @unimplemented
323 */
324 BOOL
325 WINAPI
326 DeleteVolumeMountPointW(IN LPCWSTR lpszVolumeMountPoint)
327 {
328 STUB;
329 return 0;
330 }
331
332 /*
333 * @unimplemented
334 */
335 HANDLE
336 WINAPI
337 FindFirstVolumeMountPointW(IN LPCWSTR lpszRootPathName,
338 IN LPWSTR lpszVolumeMountPoint,
339 IN DWORD cchBufferLength)
340 {
341 STUB;
342 return 0;
343 }
344
345 /*
346 * @unimplemented
347 */
348 HANDLE
349 WINAPI
350 FindFirstVolumeMountPointA(IN LPCSTR lpszRootPathName,
351 IN LPSTR lpszVolumeMountPoint,
352 IN DWORD cchBufferLength)
353 {
354 STUB;
355 return 0;
356 }
357
358 /*
359 * @unimplemented
360 */
361 BOOL
362 WINAPI
363 FindNextVolumeMountPointA(IN HANDLE hFindVolumeMountPoint,
364 IN LPSTR lpszVolumeMountPoint,
365 DWORD cchBufferLength)
366 {
367 STUB;
368 return 0;
369 }
370
371 /*
372 * @unimplemented
373 */
374 BOOL
375 WINAPI
376 FindNextVolumeMountPointW(IN HANDLE hFindVolumeMountPoint,
377 IN LPWSTR lpszVolumeMountPoint,
378 DWORD cchBufferLength)
379 {
380 STUB;
381 return 0;
382 }
383
384 /*
385 * @unimplemented
386 */
387 BOOL
388 WINAPI
389 FindVolumeMountPointClose(IN HANDLE hFindVolumeMountPoint)
390 {
391 STUB;
392 return 0;
393 }
394
395 /* EOF */