Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendir.c
Go to the documentation of this file.
00001 /* $Id: dir.c 55866 2012-02-25 21:09:28Z khornicek $ 00002 * 00003 * COPYRIGHT: See COPYING in the top level directory 00004 * PROJECT: ReactOS system libraries 00005 * FILE: lib/kernel32/client/file/dir.c 00006 * PURPOSE: Directory functions 00007 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org) 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <k32.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* Short File Name length in chars (8.3) */ 00017 #define SFN_LENGTH 12 00018 00019 /* Match a volume name like: 00020 * \\?\Volume{GUID} 00021 */ 00022 #define IS_VOLUME_NAME(s, l) \ 00023 ((l == 96 || (l == 98 && s[48] == '\\')) && \ 00024 s[0] == '\\'&& (s[1] == '?' || s[1] == '\\') && \ 00025 s[2] == '?' && s[3] == '\\' && s[4] == 'V' && \ 00026 s[5] == 'o' && s[6] == 'l' && s[7] == 'u' && \ 00027 s[8] == 'm' && s[9] == 'e' && s[10] == '{' && \ 00028 s[19] == '-' && s[24] == '-' && s[29] == '-' && \ 00029 s[34] == '-' && s[47] == '}') 00030 00031 /* FIXME - Get it out of here */ 00032 typedef struct _REPARSE_DATA_BUFFER { 00033 ULONG ReparseTag; 00034 USHORT ReparseDataLength; 00035 USHORT Reserved; 00036 union { 00037 struct { 00038 USHORT SubstituteNameOffset; 00039 USHORT SubstituteNameLength; 00040 USHORT PrintNameOffset; 00041 USHORT PrintNameLength; 00042 ULONG Flags; 00043 WCHAR PathBuffer[1]; 00044 } SymbolicLinkReparseBuffer; 00045 struct { 00046 USHORT SubstituteNameOffset; 00047 USHORT SubstituteNameLength; 00048 USHORT PrintNameOffset; 00049 USHORT PrintNameLength; 00050 WCHAR PathBuffer[1]; 00051 } MountPointReparseBuffer; 00052 struct { 00053 UCHAR DataBuffer[1]; 00054 } GenericReparseBuffer; 00055 }; 00056 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; 00057 00058 /* FUNCTIONS *****************************************************************/ 00059 00060 /* 00061 * @implemented 00062 */ 00063 BOOL 00064 WINAPI 00065 CreateDirectoryA(IN LPCSTR lpPathName, 00066 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) 00067 { 00068 PUNICODE_STRING PathNameW; 00069 00070 PathNameW = Basep8BitStringToStaticUnicodeString(lpPathName); 00071 if (!PathNameW) 00072 { 00073 return FALSE; 00074 } 00075 00076 return CreateDirectoryW(PathNameW->Buffer, 00077 lpSecurityAttributes); 00078 } 00079 00080 /* 00081 * @implemented 00082 */ 00083 BOOL 00084 WINAPI 00085 CreateDirectoryExA(IN LPCSTR lpTemplateDirectory, 00086 IN LPCSTR lpNewDirectory, 00087 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) 00088 { 00089 PUNICODE_STRING TemplateDirectoryW; 00090 UNICODE_STRING NewDirectoryW; 00091 BOOL ret; 00092 00093 TemplateDirectoryW = Basep8BitStringToStaticUnicodeString(lpTemplateDirectory); 00094 if (!TemplateDirectoryW) 00095 { 00096 return FALSE; 00097 } 00098 00099 if (!Basep8BitStringToDynamicUnicodeString(&NewDirectoryW, lpNewDirectory)) 00100 { 00101 return FALSE; 00102 } 00103 00104 ret = CreateDirectoryExW(TemplateDirectoryW->Buffer, 00105 NewDirectoryW.Buffer, 00106 lpSecurityAttributes); 00107 00108 RtlFreeUnicodeString(&NewDirectoryW); 00109 00110 return ret; 00111 } 00112 00113 /* 00114 * @implemented 00115 */ 00116 BOOL 00117 WINAPI 00118 CreateDirectoryW(IN LPCWSTR lpPathName, 00119 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) 00120 { 00121 DWORD Length; 00122 NTSTATUS Status; 00123 HANDLE DirectoryHandle; 00124 UNICODE_STRING NtPathU; 00125 PWSTR PathUBuffer, FilePart; 00126 IO_STATUS_BLOCK IoStatusBlock; 00127 RTL_RELATIVE_NAME_U RelativeName; 00128 OBJECT_ATTRIBUTES ObjectAttributes; 00129 00130 /* Get relative name */ 00131 if (!RtlDosPathNameToRelativeNtPathName_U(lpPathName, &NtPathU, NULL, &RelativeName)) 00132 { 00133 SetLastError(ERROR_PATH_NOT_FOUND); 00134 return FALSE; 00135 } 00136 00137 /* Check if path length is < MAX_PATH (with space for file name). 00138 * If not, prefix is required. 00139 */ 00140 if (NtPathU.Length > (MAX_PATH - SFN_LENGTH) * sizeof(WCHAR) && lpPathName[0] != L'\\' && 00141 lpPathName[1] != L'\\' && lpPathName[2] != L'?' && lpPathName[3] != L'\\') 00142 { 00143 /* Get file name position and full path length */ 00144 Length = GetFullPathNameW(lpPathName, 0, NULL, &FilePart); 00145 if (Length == 0) 00146 { 00147 RtlReleaseRelativeName(&RelativeName); 00148 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU.Buffer); 00149 SetLastError(ERROR_FILENAME_EXCED_RANGE); 00150 return FALSE; 00151 } 00152 00153 /* Keep place for 8.3 file name */ 00154 Length += SFN_LENGTH; 00155 /* No prefix, so, must be smaller than MAX_PATH */ 00156 if (Length > MAX_PATH) 00157 { 00158 RtlReleaseRelativeName(&RelativeName); 00159 RtlFreeHeap(GetProcessHeap(), 0, NtPathU.Buffer); 00160 SetLastError(ERROR_FILENAME_EXCED_RANGE); 00161 return FALSE; 00162 } 00163 } 00164 00165 /* Save buffer to allow later freeing */ 00166 PathUBuffer = NtPathU.Buffer; 00167 00168 /* If we have relative name (and root dir), use them instead */ 00169 if (RelativeName.RelativeName.Length != 0) 00170 { 00171 NtPathU.Length = RelativeName.RelativeName.Length; 00172 NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength; 00173 NtPathU.Buffer = RelativeName.RelativeName.Buffer; 00174 } 00175 else 00176 { 00177 RelativeName.ContainingDirectory = NULL; 00178 } 00179 00180 InitializeObjectAttributes(&ObjectAttributes, 00181 &NtPathU, 00182 OBJ_CASE_INSENSITIVE, 00183 RelativeName.ContainingDirectory, 00184 (lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL)); 00185 00186 Status = NtCreateFile(&DirectoryHandle, 00187 FILE_LIST_DIRECTORY | SYNCHRONIZE, 00188 &ObjectAttributes, 00189 &IoStatusBlock, 00190 NULL, 00191 FILE_ATTRIBUTE_NORMAL, 00192 FILE_SHARE_READ | FILE_SHARE_WRITE, 00193 FILE_CREATE, 00194 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT, 00195 NULL, 00196 0); 00197 00198 RtlReleaseRelativeName(&RelativeName); 00199 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00200 00201 if (NT_SUCCESS(Status)) 00202 { 00203 NtClose(DirectoryHandle); 00204 return TRUE; 00205 } 00206 00207 if (RtlIsDosDeviceName_U(lpPathName)) 00208 { 00209 Status = STATUS_NOT_A_DIRECTORY; 00210 } 00211 00212 BaseSetLastNTError(Status); 00213 return FALSE; 00214 } 00215 00216 /* 00217 * @implemented 00218 */ 00219 BOOL 00220 WINAPI 00221 CreateDirectoryExW(IN LPCWSTR lpTemplateDirectory, 00222 IN LPCWSTR lpNewDirectory, 00223 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) 00224 { 00225 DWORD Length; 00226 NTSTATUS Status; 00227 PVOID EaBuffer = NULL; 00228 BOOL ReparsePoint = FALSE; 00229 IO_STATUS_BLOCK IoStatusBlock; 00230 FILE_EA_INFORMATION FileEaInfo; 00231 ULONG EaLength = 0, StreamSize; 00232 OBJECT_ATTRIBUTES ObjectAttributes; 00233 FILE_BASIC_INFORMATION FileBasicInfo; 00234 PREPARSE_DATA_BUFFER ReparseDataBuffer; 00235 HANDLE TemplateHandle, DirectoryHandle; 00236 PFILE_STREAM_INFORMATION FileStreamInfo; 00237 FILE_ATTRIBUTE_TAG_INFORMATION FileTagInfo; 00238 UNICODE_STRING NtPathU, NtTemplatePathU, NewDirectory; 00239 RTL_RELATIVE_NAME_U RelativeName, TemplateRelativeName; 00240 PWSTR TemplateBuffer, PathUBuffer, FilePart, SubstituteName; 00241 00242 /* Get relative name of the template */ 00243 if (!RtlDosPathNameToRelativeNtPathName_U(lpTemplateDirectory, &NtTemplatePathU, NULL, &TemplateRelativeName)) 00244 { 00245 SetLastError(ERROR_PATH_NOT_FOUND); 00246 return FALSE; 00247 } 00248 00249 /* Save buffer for further freeing */ 00250 TemplateBuffer = NtTemplatePathU.Buffer; 00251 00252 /* If we have relative name (and root dir), use them instead */ 00253 if (TemplateRelativeName.RelativeName.Length != 0) 00254 { 00255 NtTemplatePathU.Length = TemplateRelativeName.RelativeName.Length; 00256 NtTemplatePathU.MaximumLength = TemplateRelativeName.RelativeName.MaximumLength; 00257 NtTemplatePathU.Buffer = TemplateRelativeName.RelativeName.Buffer; 00258 } 00259 else 00260 { 00261 TemplateRelativeName.ContainingDirectory = NULL; 00262 } 00263 00264 InitializeObjectAttributes(&ObjectAttributes, 00265 &NtTemplatePathU, 00266 OBJ_CASE_INSENSITIVE, 00267 NULL, 00268 NULL); 00269 00270 /* Open template directory */ 00271 Status = NtOpenFile(&TemplateHandle, 00272 FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA, 00273 &ObjectAttributes, 00274 &IoStatusBlock, 00275 FILE_SHARE_READ | FILE_SHARE_WRITE, 00276 FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT); 00277 if (!NT_SUCCESS(Status)) 00278 { 00279 if (Status != STATUS_INVALID_PARAMETER) 00280 { 00281 RtlReleaseRelativeName(&TemplateRelativeName); 00282 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer); 00283 BaseSetLastNTError(Status); 00284 return FALSE; 00285 } 00286 00287 OpenWithoutReparseSupport: 00288 /* Opening failed due to lacking reparse points support in the FSD, try without */ 00289 Status = NtOpenFile(&TemplateHandle, 00290 FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA, 00291 &ObjectAttributes, 00292 &IoStatusBlock, 00293 FILE_SHARE_READ | FILE_SHARE_WRITE, 00294 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT); 00295 00296 if (!NT_SUCCESS(Status)) 00297 { 00298 RtlReleaseRelativeName(&TemplateRelativeName); 00299 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer); 00300 BaseSetLastNTError(Status); 00301 return FALSE; 00302 } 00303 00304 /* Request file attributes */ 00305 FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; 00306 Status = NtQueryInformationFile(TemplateHandle, 00307 &IoStatusBlock, 00308 &FileBasicInfo, 00309 sizeof(FileBasicInfo), 00310 FileBasicInformation); 00311 if (!NT_SUCCESS(Status)) 00312 { 00313 RtlReleaseRelativeName(&TemplateRelativeName); 00314 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer); 00315 CloseHandle(TemplateHandle); 00316 BaseSetLastNTError(Status); 00317 return FALSE; 00318 00319 } 00320 } 00321 else 00322 { 00323 /* Request file attributes */ 00324 FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; 00325 Status = NtQueryInformationFile(TemplateHandle, 00326 &IoStatusBlock, 00327 &FileBasicInfo, 00328 sizeof(FileBasicInfo), 00329 FileBasicInformation); 00330 if (!NT_SUCCESS(Status)) 00331 { 00332 RtlReleaseRelativeName(&TemplateRelativeName); 00333 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer); 00334 CloseHandle(TemplateHandle); 00335 BaseSetLastNTError(Status); 00336 return FALSE; 00337 00338 } 00339 00340 /* If it is a reparse point, then get information about it */ 00341 if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) 00342 { 00343 Status = NtQueryInformationFile(TemplateHandle, 00344 &IoStatusBlock, 00345 &FileTagInfo, 00346 sizeof(FileTagInfo), 00347 FileAttributeTagInformation); 00348 if (!NT_SUCCESS(Status)) 00349 { 00350 RtlReleaseRelativeName(&TemplateRelativeName); 00351 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer); 00352 CloseHandle(TemplateHandle); 00353 BaseSetLastNTError(Status); 00354 return FALSE; 00355 } 00356 00357 /* Only mount points are supported, retry without if anything different */ 00358 if (FileTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) 00359 { 00360 CloseHandle(TemplateHandle); 00361 goto OpenWithoutReparseSupport; 00362 } 00363 00364 /* Mark we are playing with a reparse point */ 00365 ReparsePoint = TRUE; 00366 } 00367 } 00368 00369 /* Get relative name of the directory */ 00370 if (!RtlDosPathNameToRelativeNtPathName_U(lpNewDirectory, &NtPathU, NULL, &RelativeName)) 00371 { 00372 RtlReleaseRelativeName(&TemplateRelativeName); 00373 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer); 00374 NtClose(TemplateHandle); 00375 SetLastError(ERROR_PATH_NOT_FOUND); 00376 return FALSE; 00377 } 00378 00379 /* Save its buffer for further freeing */ 00380 PathUBuffer = NtPathU.Buffer; 00381 00382 /* Template & directory can't be the same */ 00383 if (RtlEqualUnicodeString(&NtPathU, 00384 &NtTemplatePathU, 00385 TRUE)) 00386 { 00387 RtlReleaseRelativeName(&RelativeName); 00388 RtlReleaseRelativeName(&TemplateRelativeName); 00389 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer); 00390 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00391 NtClose(TemplateHandle); 00392 SetLastError(ERROR_INVALID_NAME); 00393 return FALSE; 00394 } 00395 00396 RtlReleaseRelativeName(&TemplateRelativeName); 00397 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer); 00398 00399 /* Check if path length is < MAX_PATH (with space for file name). 00400 * If not, prefix is required. 00401 */ 00402 if (NtPathU.Length > (MAX_PATH - SFN_LENGTH) * sizeof(WCHAR) && lpNewDirectory[0] != L'\\' && 00403 lpNewDirectory[1] != L'\\' && lpNewDirectory[2] != L'?' && lpNewDirectory[3] != L'\\') 00404 { 00405 /* Get file name position and full path length */ 00406 Length = GetFullPathNameW(lpNewDirectory, 0, NULL, &FilePart); 00407 if (Length == 0) 00408 { 00409 RtlReleaseRelativeName(&RelativeName); 00410 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00411 CloseHandle(TemplateHandle); 00412 SetLastError(ERROR_FILENAME_EXCED_RANGE); 00413 return FALSE; 00414 } 00415 00416 /* Keep place for 8.3 file name */ 00417 Length += SFN_LENGTH; 00418 /* No prefix, so, must be smaller than MAX_PATH */ 00419 if (Length > MAX_PATH) 00420 { 00421 RtlReleaseRelativeName(&RelativeName); 00422 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00423 CloseHandle(TemplateHandle); 00424 SetLastError(ERROR_FILENAME_EXCED_RANGE); 00425 return FALSE; 00426 } 00427 } 00428 00429 /* If we have relative name (and root dir), use them instead */ 00430 if (RelativeName.RelativeName.Length != 0) 00431 { 00432 NtPathU.Length = RelativeName.RelativeName.Length; 00433 NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength; 00434 NtPathU.Buffer = RelativeName.RelativeName.Buffer; 00435 } 00436 else 00437 { 00438 RelativeName.ContainingDirectory = NULL; 00439 } 00440 00441 /* Get extended attributes */ 00442 Status = NtQueryInformationFile(TemplateHandle, 00443 &IoStatusBlock, 00444 &FileEaInfo, 00445 sizeof(FileEaInfo), 00446 FileEaInformation); 00447 if (!NT_SUCCESS(Status)) 00448 { 00449 RtlReleaseRelativeName(&RelativeName); 00450 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00451 CloseHandle(TemplateHandle); 00452 BaseSetLastNTError(Status); 00453 return FALSE; 00454 } 00455 00456 /* Start reading extended attributes */ 00457 if (FileEaInfo.EaSize != 0) 00458 { 00459 for (EaLength = FileEaInfo.EaSize * 2; ; EaLength = EaLength * 2) 00460 { 00461 /* Allocate buffer for reading */ 00462 EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, EaLength); 00463 if (!EaBuffer) 00464 { 00465 RtlReleaseRelativeName(&RelativeName); 00466 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00467 CloseHandle(TemplateHandle); 00468 BaseSetLastNTError(STATUS_NO_MEMORY); 00469 return FALSE; 00470 } 00471 00472 /* Query EAs */ 00473 Status = NtQueryEaFile(TemplateHandle, 00474 &IoStatusBlock, 00475 EaBuffer, 00476 EaLength, 00477 FALSE, 00478 NULL, 00479 0, 00480 NULL, 00481 TRUE); 00482 if (!NT_SUCCESS(Status)) 00483 { 00484 RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer); 00485 IoStatusBlock.Information = 0; 00486 } 00487 00488 /* If we don't fail because of too small buffer, stop here */ 00489 if (Status != STATUS_BUFFER_OVERFLOW && 00490 Status != STATUS_BUFFER_TOO_SMALL) 00491 { 00492 EaLength = IoStatusBlock.Information; 00493 break; 00494 } 00495 } 00496 } 00497 00498 InitializeObjectAttributes(&ObjectAttributes, 00499 &NtPathU, 00500 OBJ_CASE_INSENSITIVE, 00501 RelativeName.ContainingDirectory, 00502 (lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL)); 00503 00504 /* Ensure attributes are valid */ 00505 FileBasicInfo.FileAttributes &= FILE_ATTRIBUTE_VALID_FLAGS; 00506 00507 /* Create the new directory */ 00508 Status = NtCreateFile(&DirectoryHandle, 00509 FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | 00510 FILE_READ_ATTRIBUTES | (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? FILE_ADD_FILE : 0), 00511 &ObjectAttributes, 00512 &IoStatusBlock, 00513 NULL, 00514 FileBasicInfo.FileAttributes, 00515 FILE_SHARE_READ | FILE_SHARE_WRITE, 00516 FILE_CREATE, 00517 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 00518 FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT, 00519 EaBuffer, 00520 EaLength); 00521 if (!NT_SUCCESS(Status)) 00522 { 00523 if (Status == STATUS_INVALID_PARAMETER || Status == STATUS_ACCESS_DENIED) 00524 { 00525 /* If creation failed, it might be because FSD doesn't support reparse points 00526 * Retry without asking for such support in case template is not a reparse point 00527 */ 00528 if (!ReparsePoint) 00529 { 00530 Status = NtCreateFile(&DirectoryHandle, 00531 FILE_LIST_DIRECTORY | SYNCHRONIZE | 00532 FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES, 00533 &ObjectAttributes, 00534 &IoStatusBlock, 00535 NULL, 00536 FileBasicInfo.FileAttributes, 00537 FILE_SHARE_READ | FILE_SHARE_WRITE, 00538 FILE_CREATE, 00539 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 00540 FILE_OPEN_FOR_BACKUP_INTENT, 00541 EaBuffer, 00542 EaLength); 00543 } 00544 else 00545 { 00546 RtlReleaseRelativeName(&RelativeName); 00547 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00548 if (EaBuffer) 00549 { 00550 RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer); 00551 } 00552 CloseHandle(TemplateHandle); 00553 BaseSetLastNTError(Status); 00554 return FALSE; 00555 } 00556 } 00557 } 00558 00559 RtlReleaseRelativeName(&RelativeName); 00560 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00561 if (EaBuffer) 00562 { 00563 RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer); 00564 } 00565 00566 if (!NT_SUCCESS(Status)) 00567 { 00568 NtClose(TemplateHandle); 00569 if (RtlIsDosDeviceName_U(lpNewDirectory)) 00570 { 00571 Status = STATUS_NOT_A_DIRECTORY; 00572 } 00573 BaseSetLastNTError(Status); 00574 return FALSE; 00575 } 00576 00577 /* If template is a reparse point, copy reparse data */ 00578 if (ReparsePoint) 00579 { 00580 ReparseDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, 00581 MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 00582 if (!ReparseDataBuffer) 00583 { 00584 NtClose(TemplateHandle); 00585 NtClose(DirectoryHandle); 00586 SetLastError(STATUS_NO_MEMORY); 00587 return FALSE; 00588 } 00589 00590 /* First query data */ 00591 Status = NtFsControlFile(TemplateHandle, 00592 NULL, 00593 NULL, 00594 NULL, 00595 &IoStatusBlock, 00596 FSCTL_GET_REPARSE_POINT, 00597 NULL, 00598 0, 00599 ReparseDataBuffer, 00600 MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 00601 if (!NT_SUCCESS(Status)) 00602 { 00603 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer); 00604 NtClose(TemplateHandle); 00605 NtClose(DirectoryHandle); 00606 SetLastError(Status); 00607 return FALSE; 00608 } 00609 00610 /* Once again, ensure it is a mount point */ 00611 if (ReparseDataBuffer->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) 00612 { 00613 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer); 00614 NtClose(TemplateHandle); 00615 NtClose(DirectoryHandle); 00616 SetLastError(STATUS_OBJECT_NAME_INVALID); 00617 return FALSE; 00618 } 00619 00620 /* Get volume name */ 00621 SubstituteName = (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer + 00622 ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset); 00623 if (IS_VOLUME_NAME(SubstituteName, ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength)) 00624 { 00625 /* Prepare to define a new mount point for that volume */ 00626 RtlInitUnicodeString(&NewDirectory, lpNewDirectory); 00627 NewDirectory.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewDirectory.Length + 2 * sizeof(WCHAR)); 00628 if (!NewDirectory.Buffer) 00629 { 00630 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00631 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer); 00632 NtClose(TemplateHandle); 00633 NtClose(DirectoryHandle); 00634 return FALSE; 00635 } 00636 00637 RtlCopyMemory(&NewDirectory.Buffer, lpNewDirectory, NewDirectory.Length); 00638 if (NewDirectory.Buffer[NewDirectory.Length / sizeof(WCHAR)] != L'\\') 00639 { 00640 NewDirectory.Buffer[NewDirectory.Length / sizeof(WCHAR)] = L'\\'; 00641 NewDirectory.Buffer[(NewDirectory.Length / sizeof(WCHAR)) + 1] = UNICODE_NULL; 00642 } 00643 00644 /* Define a new mount point for that volume */ 00645 SetVolumeMountPointW(NewDirectory.Buffer, SubstituteName); 00646 00647 RtlFreeHeap(RtlGetProcessHeap(), 0, NewDirectory.Buffer); 00648 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer); 00649 NtClose(TemplateHandle); 00650 NtClose(DirectoryHandle); 00651 return TRUE; 00652 } 00653 00654 /* Otherwise copy data raw */ 00655 Status = NtFsControlFile(DirectoryHandle, 00656 NULL, 00657 NULL, 00658 NULL, 00659 &IoStatusBlock, 00660 FSCTL_SET_REPARSE_POINT, 00661 ReparseDataBuffer, 00662 ReparseDataBuffer->ReparseDataLength + 00663 FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer), 00664 NULL, 00665 0); 00666 00667 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer); 00668 NtClose(TemplateHandle); 00669 NtClose(DirectoryHandle); 00670 00671 if (NT_SUCCESS(Status)) 00672 { 00673 return TRUE; 00674 } 00675 00676 BaseSetLastNTError(Status); 00677 return FALSE; 00678 } 00679 /* In case it's not a reparse point, handle streams on the file */ 00680 else 00681 { 00682 for (StreamSize = 0x1000; ; StreamSize = StreamSize * 2) 00683 { 00684 FileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, StreamSize); 00685 if (!FileStreamInfo) 00686 { 00687 BaseMarkFileForDelete(DirectoryHandle, FileBasicInfo.FileAttributes); 00688 SetLastError(STATUS_NO_MEMORY); 00689 break; 00690 } 00691 00692 /* Query stream information */ 00693 Status = NtQueryInformationFile(TemplateHandle, 00694 &IoStatusBlock, 00695 FileStreamInfo, 00696 StreamSize, 00697 FileStreamInformation); 00698 if (NT_SUCCESS(Status)) 00699 { 00700 break; 00701 } 00702 00703 RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo); 00704 FileStreamInfo = NULL; 00705 00706 /* If it failed, ensure that's not because of too small buffer */ 00707 if (Status != STATUS_BUFFER_OVERFLOW && 00708 Status != STATUS_BUFFER_TOO_SMALL) 00709 { 00710 break; 00711 } 00712 } 00713 00714 if (!NT_SUCCESS(Status) || IoStatusBlock.Information == 0) 00715 { 00716 if (FileStreamInfo) 00717 { 00718 RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo); 00719 } 00720 00721 NtClose(TemplateHandle); 00722 NtClose(DirectoryHandle); 00723 return TRUE; 00724 } 00725 00726 #if 1 00727 /* FIXME: TODO */ 00728 DPRINT1("Warning: streams copying is unimplemented!\n"); 00729 RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo); 00730 NtClose(TemplateHandle); 00731 NtClose(DirectoryHandle); 00732 #endif 00733 return TRUE; 00734 } 00735 } 00736 00737 /* 00738 * @implemented 00739 */ 00740 BOOL 00741 WINAPI 00742 RemoveDirectoryA(IN LPCSTR lpPathName) 00743 { 00744 PUNICODE_STRING PathNameW; 00745 00746 PathNameW = Basep8BitStringToStaticUnicodeString(lpPathName); 00747 if (!PathNameW) 00748 { 00749 return FALSE; 00750 } 00751 00752 return RemoveDirectoryW(PathNameW->Buffer); 00753 } 00754 00755 /* 00756 * @implemented 00757 */ 00758 BOOL 00759 WINAPI 00760 RemoveDirectoryW(IN LPCWSTR lpPathName) 00761 { 00762 NTSTATUS Status; 00763 DWORD BytesReturned; 00764 HANDLE DirectoryHandle; 00765 IO_STATUS_BLOCK IoStatusBlock; 00766 UNICODE_STRING NtPathU, PathName; 00767 RTL_RELATIVE_NAME_U RelativeName; 00768 PWSTR PathUBuffer, SubstituteName; 00769 OBJECT_ATTRIBUTES ObjectAttributes; 00770 PREPARSE_DATA_BUFFER ReparseDataBuffer; 00771 FILE_DISPOSITION_INFORMATION FileDispInfo; 00772 FILE_ATTRIBUTE_TAG_INFORMATION FileTagInfo; 00773 00774 /* Get relative name */ 00775 if (!RtlDosPathNameToRelativeNtPathName_U(lpPathName, &NtPathU, NULL, &RelativeName)) 00776 { 00777 SetLastError(ERROR_PATH_NOT_FOUND); 00778 return FALSE; 00779 } 00780 00781 /* Save buffer to allow later freeing */ 00782 PathUBuffer = NtPathU.Buffer; 00783 00784 /* If we have relative name (and root dir), use them instead */ 00785 if (RelativeName.RelativeName.Length != 0) 00786 { 00787 NtPathU.Length = RelativeName.RelativeName.Length; 00788 NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength; 00789 NtPathU.Buffer = RelativeName.RelativeName.Buffer; 00790 } 00791 else 00792 { 00793 RelativeName.ContainingDirectory = NULL; 00794 } 00795 00796 InitializeObjectAttributes(&ObjectAttributes, 00797 &NtPathU, 00798 OBJ_CASE_INSENSITIVE, 00799 RelativeName.ContainingDirectory, 00800 NULL); 00801 00802 /* Try to open directory */ 00803 Status = NtOpenFile(&DirectoryHandle, 00804 DELETE | SYNCHRONIZE | FAILED_ACCESS_ACE_FLAG, 00805 &ObjectAttributes, 00806 &IoStatusBlock, 00807 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 00808 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 00809 FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT); 00810 if (!NT_SUCCESS(Status)) 00811 { 00812 /* We only accept failure for reparse points not being supported */ 00813 if (Status != STATUS_INVALID_PARAMETER) 00814 { 00815 goto Cleanup; 00816 } 00817 00818 /* Try to open, with reparse points support */ 00819 Status = NtOpenFile(&DirectoryHandle, 00820 DELETE | SYNCHRONIZE, 00821 &ObjectAttributes, 00822 &IoStatusBlock, 00823 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 00824 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 00825 FILE_OPEN_FOR_BACKUP_INTENT); 00826 if (!NT_SUCCESS(Status)) 00827 { 00828 goto Cleanup; 00829 } 00830 00831 /* Success, mark directory */ 00832 goto MarkFileForDelete; 00833 } 00834 00835 /* Get information about file (and reparse point) */ 00836 Status = NtQueryInformationFile(DirectoryHandle, 00837 &IoStatusBlock, 00838 &FileTagInfo, 00839 sizeof(FileTagInfo), 00840 FileAttributeTagInformation); 00841 if (!NT_SUCCESS(Status)) 00842 { 00843 /* FSD might not support querying reparse points information */ 00844 if (Status != STATUS_NOT_IMPLEMENTED && 00845 Status != STATUS_INVALID_PARAMETER) 00846 { 00847 goto CleanupHandle; 00848 } 00849 00850 /* If that's the case, then just delete directory */ 00851 goto MarkFileForDelete; 00852 } 00853 00854 /* If that's not a reparse point, nothing more to do than just delete */ 00855 if (!(FileTagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) 00856 { 00857 goto MarkFileForDelete; 00858 } 00859 00860 /* Check if that's a mount point */ 00861 if (FileTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) 00862 { 00863 /* It's not */ 00864 NtClose(DirectoryHandle); 00865 00866 /* So, try to reopen directory, ignoring mount point */ 00867 Status = NtOpenFile(&DirectoryHandle, 00868 DELETE | SYNCHRONIZE, 00869 &ObjectAttributes, 00870 &IoStatusBlock, 00871 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 00872 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 00873 FILE_OPEN_FOR_BACKUP_INTENT); 00874 if (NT_SUCCESS(Status)) 00875 { 00876 /* It succeed, we can safely delete directory (and ignore reparse point) */ 00877 goto MarkFileForDelete; 00878 } 00879 00880 /* If it failed, only allow case where IO mount point was ignored */ 00881 if (Status != STATUS_IO_REPARSE_TAG_NOT_HANDLED) 00882 { 00883 goto Cleanup; 00884 } 00885 00886 /* Reopen with reparse point support */ 00887 Status = NtOpenFile(&DirectoryHandle, 00888 DELETE | SYNCHRONIZE, 00889 &ObjectAttributes, 00890 &IoStatusBlock, 00891 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 00892 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 00893 FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT); 00894 if (NT_SUCCESS(Status)) 00895 { 00896 /* And mark for delete */ 00897 goto MarkFileForDelete; 00898 } 00899 00900 goto Cleanup; 00901 } 00902 00903 /* Here, we have a mount point, prepare to query information about it */ 00904 ReparseDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, 00905 MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 00906 if (!ReparseDataBuffer) 00907 { 00908 RtlReleaseRelativeName(&RelativeName); 00909 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00910 NtClose(DirectoryHandle); 00911 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00912 return FALSE; 00913 } 00914 00915 /* Query */ 00916 if (!DeviceIoControl(DirectoryHandle, 00917 FSCTL_GET_REPARSE_POINT, 00918 NULL, 0, 00919 ReparseDataBuffer, 00920 MAXIMUM_REPARSE_DATA_BUFFER_SIZE, 00921 &BytesReturned, 00922 NULL)) 00923 { 00924 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer); 00925 goto MarkFileForDelete; 00926 } 00927 00928 /* Get volume name */ 00929 SubstituteName = (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer + 00930 ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset); 00931 if (!IS_VOLUME_NAME(SubstituteName, ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength)) 00932 { 00933 /* This is not a volume, we can safely delete */ 00934 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer); 00935 goto MarkFileForDelete; 00936 } 00937 00938 /* Prepare to delete mount point */ 00939 RtlInitUnicodeString(&PathName, lpPathName); 00940 PathName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathName.Length + 2 * sizeof(WCHAR)); 00941 if (!PathName.Buffer) 00942 { 00943 RtlReleaseRelativeName(&RelativeName); 00944 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer); 00945 NtClose(DirectoryHandle); 00946 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00947 return FALSE; 00948 } 00949 00950 RtlCopyMemory(&PathName.Buffer, lpPathName, PathName.Length); 00951 if (PathName.Buffer[PathName.Length / sizeof(WCHAR)] != L'\\') 00952 { 00953 PathName.Buffer[PathName.Length / sizeof(WCHAR)] = L'\\'; 00954 PathName.Buffer[(PathName.Length / sizeof(WCHAR)) + 1] = UNICODE_NULL; 00955 } 00956 00957 /* Delete mount point for that volume */ 00958 DeleteVolumeMountPointW(PathName.Buffer); 00959 RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer); 00960 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer); 00961 00962 /* And mark directory for delete */ 00963 MarkFileForDelete: 00964 RtlReleaseRelativeName(&RelativeName); 00965 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00966 00967 /* Mark & set */ 00968 FileDispInfo.DeleteFile = TRUE; 00969 Status = NtSetInformationFile(DirectoryHandle, 00970 &IoStatusBlock, 00971 &FileDispInfo, 00972 sizeof(FILE_DISPOSITION_INFORMATION), 00973 FileDispositionInformation); 00974 NtClose(DirectoryHandle); 00975 00976 if (!NT_SUCCESS(Status)) 00977 { 00978 BaseSetLastNTError(Status); 00979 return FALSE; 00980 } 00981 00982 return TRUE; 00983 00984 CleanupHandle: 00985 NtClose(DirectoryHandle); 00986 00987 Cleanup: 00988 RtlReleaseRelativeName(&RelativeName); 00989 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 00990 BaseSetLastNTError(Status); 00991 return FALSE; 00992 } 00993 00994 /* EOF */ Generated on Sun May 27 2012 04:18:12 for ReactOS by
1.7.6.1
|