Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpath.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Win32 Base API 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: dll/win32/kernel32/client/path.c 00005 * PURPOSE: Handles path APIs 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include <k32.h> 00012 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* GLOBALS ********************************************************************/ 00017 00018 UNICODE_STRING NoDefaultCurrentDirectoryInExePath = RTL_CONSTANT_STRING(L"NoDefaultCurrentDirectoryInExePath"); 00019 00020 UNICODE_STRING BaseWindowsSystemDirectory, BaseWindowsDirectory; 00021 UNICODE_STRING BaseDefaultPathAppend, BaseDefaultPath, BaseDllDirectory; 00022 00023 PVOID gpTermsrvGetWindowsDirectoryA; 00024 PVOID gpTermsrvGetWindowsDirectoryW; 00025 00026 /* This is bitmask for each illegal filename character */ 00027 /* If someone has time, please feel free to use 0b notation */ 00028 DWORD IllegalMask[4] = 00029 { 00030 0xFFFFFFFF, // None allowed (00 to 1F) 00031 0xFC009C05, // 20, 22, 2A, 2B, 2C, 2F, 3A, 3B, 3C, 3D, 3E, 3F not allowed 00032 0x38000000, // 5B, 5C, 5D not allowed 00033 0x10000000 // 7C not allowed 00034 }; 00035 00036 BASE_SEARCH_PATH_TYPE BaseDllOrderCurrent[BaseCurrentDirPlacementMax][BaseSearchPathMax] = 00037 { 00038 { 00039 BaseSearchPathApp, 00040 BaseSearchPathCurrent, 00041 BaseSearchPathDefault, 00042 BaseSearchPathEnv, 00043 BaseSearchPathInvalid 00044 }, 00045 { 00046 BaseSearchPathApp, 00047 BaseSearchPathDefault, 00048 BaseSearchPathCurrent, 00049 BaseSearchPathEnv, 00050 BaseSearchPathInvalid 00051 } 00052 }; 00053 00054 BASE_SEARCH_PATH_TYPE BaseProcessOrderNoCurrent[BaseSearchPathMax] = 00055 { 00056 BaseSearchPathApp, 00057 BaseSearchPathDefault, 00058 BaseSearchPathEnv, 00059 BaseSearchPathInvalid, 00060 BaseSearchPathInvalid 00061 }; 00062 00063 BASE_SEARCH_PATH_TYPE BaseDllOrderNoCurrent[BaseSearchPathMax] = 00064 { 00065 BaseSearchPathApp, 00066 BaseSearchPathDll, 00067 BaseSearchPathDefault, 00068 BaseSearchPathEnv, 00069 BaseSearchPathInvalid 00070 }; 00071 00072 BASE_SEARCH_PATH_TYPE BaseProcessOrder[BaseSearchPathMax] = 00073 { 00074 BaseSearchPathApp, 00075 BaseSearchPathCurrent, 00076 BaseSearchPathDefault, 00077 BaseSearchPathEnv, 00078 BaseSearchPathInvalid 00079 }; 00080 00081 BASE_CURRENT_DIR_PLACEMENT BasepDllCurrentDirPlacement = BaseCurrentDirPlacementInvalid; 00082 00083 extern UNICODE_STRING BasePathVariableName; 00084 00085 /* PRIVATE FUNCTIONS **********************************************************/ 00086 00087 PWCHAR 00088 WINAPI 00089 BasepEndOfDirName(IN PWCHAR FileName) 00090 { 00091 PWCHAR FileNameEnd, FileNameSeparator; 00092 00093 /* Find the first slash */ 00094 FileNameSeparator = wcschr(FileName, OBJ_NAME_PATH_SEPARATOR); 00095 if (FileNameSeparator) 00096 { 00097 /* Find the last one */ 00098 FileNameEnd = wcsrchr(FileNameSeparator, OBJ_NAME_PATH_SEPARATOR); 00099 ASSERT(FileNameEnd); 00100 00101 /* Handle the case where they are one and the same */ 00102 if (FileNameEnd == FileNameSeparator) FileNameEnd++; 00103 } 00104 else 00105 { 00106 /* No directory was specified */ 00107 FileNameEnd = NULL; 00108 } 00109 00110 /* Return where the directory ends and the filename starts */ 00111 return FileNameEnd; 00112 } 00113 00114 LPWSTR 00115 WINAPI 00116 BasepComputeProcessPath(IN PBASE_SEARCH_PATH_TYPE PathOrder, 00117 IN LPWSTR AppName, 00118 IN LPVOID Environment) 00119 { 00120 PWCHAR PathBuffer, Buffer, AppNameEnd, PathCurrent; 00121 ULONG PathLengthInBytes; 00122 NTSTATUS Status; 00123 UNICODE_STRING EnvPath; 00124 PBASE_SEARCH_PATH_TYPE Order; 00125 00126 /* Initialize state */ 00127 AppNameEnd = Buffer = PathBuffer = NULL; 00128 Status = STATUS_SUCCESS; 00129 PathLengthInBytes = 0; 00130 00131 /* Loop the ordering array */ 00132 for (Order = PathOrder; *Order != BaseSearchPathInvalid; Order++) { 00133 switch (*Order) 00134 { 00135 /* Compute the size of the DLL path */ 00136 case BaseSearchPathDll: 00137 00138 /* This path only gets called if SetDllDirectory was called */ 00139 ASSERT(BaseDllDirectory.Buffer != NULL); 00140 00141 /* Make sure there's a DLL directory size */ 00142 if (BaseDllDirectory.Length) 00143 { 00144 /* Add it, plus the separator */ 00145 PathLengthInBytes += BaseDllDirectory.Length + sizeof(L';'); 00146 } 00147 break; 00148 00149 /* Compute the size of the current path */ 00150 case BaseSearchPathCurrent: 00151 00152 /* Add ".;" */ 00153 PathLengthInBytes += (2 * sizeof(WCHAR)); 00154 break; 00155 00156 /* Compute the size of the "PATH" environment variable */ 00157 case BaseSearchPathEnv: 00158 00159 /* Grab PEB lock if one wasn't passed in */ 00160 if (!Environment) RtlAcquirePebLock(); 00161 00162 /* Query the size first */ 00163 EnvPath.MaximumLength = 0; 00164 Status = RtlQueryEnvironmentVariable_U(Environment, 00165 &BasePathVariableName, 00166 &EnvPath); 00167 if (Status == STATUS_BUFFER_TOO_SMALL) 00168 { 00169 /* Compute the size we'll need for the environment */ 00170 EnvPath.MaximumLength = EnvPath.Length + sizeof(WCHAR); 00171 if ((EnvPath.Length + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES) 00172 { 00173 /* Don't let it overflow */ 00174 EnvPath.MaximumLength = EnvPath.Length; 00175 } 00176 00177 /* Allocate the environment buffer */ 00178 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 00179 0, 00180 EnvPath.MaximumLength); 00181 if (Buffer) 00182 { 00183 /* Now query the PATH environment variable */ 00184 EnvPath.Buffer = Buffer; 00185 Status = RtlQueryEnvironmentVariable_U(Environment, 00186 &BasePathVariableName, 00187 &EnvPath); 00188 } 00189 else 00190 { 00191 /* Failure case */ 00192 Status = STATUS_NO_MEMORY; 00193 } 00194 } 00195 00196 /* Release the PEB lock from above */ 00197 if (!Environment) RtlReleasePebLock(); 00198 00199 /* There might not be a PATH */ 00200 if (Status == STATUS_VARIABLE_NOT_FOUND) 00201 { 00202 /* In this case, skip this PathOrder */ 00203 EnvPath.Length = EnvPath.MaximumLength = 0; 00204 Status = STATUS_SUCCESS; 00205 } 00206 else if (!NT_SUCCESS(Status)) 00207 { 00208 /* An early failure, go to exit code */ 00209 goto Quickie; 00210 } 00211 else 00212 { 00213 /* Add the length of the PATH variable */ 00214 ASSERT(!(EnvPath.Length & 1)); 00215 PathLengthInBytes += (EnvPath.Length + sizeof(L';')); 00216 } 00217 break; 00218 00219 /* Compute the size of the default search path */ 00220 case BaseSearchPathDefault: 00221 00222 /* Just add it... it already has a ';' at the end */ 00223 ASSERT(!(BaseDefaultPath.Length & 1)); 00224 PathLengthInBytes += BaseDefaultPath.Length; 00225 break; 00226 00227 /* Compute the size of the current app directory */ 00228 case BaseSearchPathApp: 00229 /* Find out where the app name ends, to get only the directory */ 00230 if (AppName) AppNameEnd = BasepEndOfDirName(AppName); 00231 00232 /* Check if there was no application name passed in */ 00233 if (!(AppName) || !(AppNameEnd)) 00234 { 00235 /* Do we have a per-thread CURDIR to use? */ 00236 if (NtCurrentTeb()->NtTib.SubSystemTib) 00237 { 00238 /* This means someone added RTL_PERTHREAD_CURDIR */ 00239 UNIMPLEMENTED; 00240 while (TRUE); 00241 } 00242 00243 /* We do not. Do we have the LDR_ENTRY for the executable? */ 00244 if (!BasepExeLdrEntry) 00245 { 00246 /* We do not. Grab it */ 00247 LdrEnumerateLoadedModules(0, 00248 BasepLocateExeLdrEntry, 00249 NtCurrentPeb()->ImageBaseAddress); 00250 } 00251 00252 /* Now do we have it? */ 00253 if (BasepExeLdrEntry) 00254 { 00255 /* Yes, so read the name out of it */ 00256 AppName = BasepExeLdrEntry->FullDllName.Buffer; 00257 } 00258 00259 /* Find out where the app name ends, to get only the directory */ 00260 if (AppName) AppNameEnd = BasepEndOfDirName(AppName); 00261 } 00262 00263 /* So, do we have an application name and its directory? */ 00264 if ((AppName) && (AppNameEnd)) 00265 { 00266 /* Add the size of the app's directory, plus the separator */ 00267 PathLengthInBytes += ((AppNameEnd - AppName) * sizeof(WCHAR)) + sizeof(L';'); 00268 } 00269 break; 00270 00271 default: 00272 break; 00273 } 00274 } 00275 00276 /* Bam, all done, we now have the final path size */ 00277 ASSERT(PathLengthInBytes > 0); 00278 ASSERT(!(PathLengthInBytes & 1)); 00279 00280 /* Allocate the buffer to hold it */ 00281 PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLengthInBytes); 00282 if (!PathBuffer) 00283 { 00284 /* Failure path */ 00285 Status = STATUS_NO_MEMORY; 00286 goto Quickie; 00287 } 00288 00289 /* Now we loop again, this time to copy the data */ 00290 PathCurrent = PathBuffer; 00291 for (Order = PathOrder; *Order != BaseSearchPathInvalid; Order++) { 00292 switch (*Order) 00293 { 00294 /* Add the DLL path */ 00295 case BaseSearchPathDll: 00296 if (BaseDllDirectory.Length) 00297 { 00298 /* Copy it in the buffer, ASSERT there's enough space */ 00299 ASSERT((((PathCurrent - PathBuffer + 1) * sizeof(WCHAR)) + BaseDllDirectory.Length) <= PathLengthInBytes); 00300 RtlCopyMemory(PathCurrent, 00301 BaseDllDirectory.Buffer, 00302 BaseDllDirectory.Length); 00303 00304 /* Update the current pointer, add a separator */ 00305 PathCurrent += (BaseDllDirectory.Length / sizeof(WCHAR)); 00306 *PathCurrent++ = ';'; 00307 } 00308 break; 00309 00310 /* Add the current application path */ 00311 case BaseSearchPathApp: 00312 if ((AppName) && (AppNameEnd)) 00313 { 00314 /* Copy it in the buffer, ASSERT there's enough space */ 00315 ASSERT(((PathCurrent - PathBuffer + 1 + (AppNameEnd - AppName)) * sizeof(WCHAR)) <= PathLengthInBytes); 00316 RtlCopyMemory(PathCurrent, 00317 AppName, 00318 (AppNameEnd - AppName) * sizeof(WCHAR)); 00319 00320 /* Update the current pointer, add a separator */ 00321 PathCurrent += AppNameEnd - AppName; 00322 *PathCurrent++ = ';'; 00323 } 00324 break; 00325 00326 /* Add the default search path */ 00327 case BaseSearchPathDefault: 00328 /* Copy it in the buffer, ASSERT there's enough space */ 00329 ASSERT((((PathCurrent - PathBuffer) * sizeof(WCHAR)) + BaseDefaultPath.Length) <= PathLengthInBytes); 00330 RtlCopyMemory(PathCurrent, BaseDefaultPath.Buffer, BaseDefaultPath.Length); 00331 00332 /* Update the current pointer. The default path already has a ";" */ 00333 PathCurrent += (BaseDefaultPath.Length / sizeof(WCHAR)); 00334 break; 00335 00336 /* Add the path in the PATH environment variable */ 00337 case BaseSearchPathEnv: 00338 if (EnvPath.Length) 00339 { 00340 /* Copy it in the buffer, ASSERT there's enough space */ 00341 ASSERT((((PathCurrent - PathBuffer + 1) * sizeof(WCHAR)) + EnvPath.Length) <= PathLengthInBytes); 00342 RtlCopyMemory(PathCurrent, EnvPath.Buffer, EnvPath.Length); 00343 00344 /* Update the current pointer, add a separator */ 00345 PathCurrent += (EnvPath.Length / sizeof(WCHAR)); 00346 *PathCurrent++ = ';'; 00347 } 00348 break; 00349 00350 /* Add the current dierctory */ 00351 case BaseSearchPathCurrent: 00352 00353 /* Copy it in the buffer, ASSERT there's enough space */ 00354 ASSERT(((PathCurrent - PathBuffer + 2) * sizeof(WCHAR)) <= PathLengthInBytes); 00355 *PathCurrent++ = '.'; 00356 00357 /* Add the path separator */ 00358 *PathCurrent++ = ';'; 00359 break; 00360 00361 default: 00362 break; 00363 } 00364 } 00365 00366 /* Everything should've perfectly fit in there */ 00367 ASSERT((PathCurrent - PathBuffer) * sizeof(WCHAR) == PathLengthInBytes); 00368 ASSERT(PathCurrent > PathBuffer); 00369 00370 /* Terminate the whole thing */ 00371 PathCurrent[-1] = UNICODE_NULL; 00372 00373 Quickie: 00374 /* Exit path: free our buffers */ 00375 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 00376 if (PathBuffer) 00377 { 00378 /* This only gets freed in the failure path, since caller wants it */ 00379 if (!NT_SUCCESS(Status)) 00380 { 00381 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer); 00382 PathBuffer = NULL; 00383 } 00384 } 00385 00386 /* Return the path! */ 00387 return PathBuffer; 00388 } 00389 00390 LPWSTR 00391 WINAPI 00392 BaseComputeProcessSearchPath(VOID) 00393 { 00394 DPRINT("Computing Process Search path\n"); 00395 00396 /* Compute the path using default process order */ 00397 return BasepComputeProcessPath(BaseProcessOrder, NULL, NULL); 00398 } 00399 00400 LPWSTR 00401 WINAPI 00402 BaseComputeProcessExePath(IN LPWSTR FullPath) 00403 { 00404 PBASE_SEARCH_PATH_TYPE PathOrder; 00405 DPRINT1("Computing EXE path: %wZ\n", FullPath); 00406 00407 /* Check if we should use the current directory */ 00408 PathOrder = NeedCurrentDirectoryForExePathW(FullPath) ? 00409 BaseProcessOrder : BaseProcessOrderNoCurrent; 00410 00411 /* And now compute the path */ 00412 return BasepComputeProcessPath(PathOrder, NULL, NULL); 00413 } 00414 00415 LPWSTR 00416 WINAPI 00417 BaseComputeProcessDllPath(IN LPWSTR FullPath, 00418 IN PVOID Environment) 00419 { 00420 LPWSTR DllPath = NULL; 00421 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager"); 00422 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SafeDllSearchMode"); 00423 OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&KeyName, OBJ_CASE_INSENSITIVE); 00424 KEY_VALUE_PARTIAL_INFORMATION PartialInfo; 00425 HANDLE KeyHandle; 00426 NTSTATUS Status; 00427 ULONG ResultLength; 00428 BASE_CURRENT_DIR_PLACEMENT CurrentDirPlacement, OldCurrentDirPlacement; 00429 00430 /* Acquire DLL directory lock */ 00431 RtlEnterCriticalSection(&BaseDllDirectoryLock); 00432 00433 /* Check if we have a base dll directory */ 00434 if (BaseDllDirectory.Buffer) 00435 { 00436 /* Then compute the process path using DLL order (without curdir) */ 00437 DllPath = BasepComputeProcessPath(BaseDllOrderNoCurrent, FullPath, Environment); 00438 00439 /* Release DLL directory lock */ 00440 RtlLeaveCriticalSection(&BaseDllDirectoryLock); 00441 00442 /* Return dll path */ 00443 return DllPath; 00444 } 00445 00446 /* Release DLL directory lock */ 00447 RtlLeaveCriticalSection(&BaseDllDirectoryLock); 00448 00449 /* Read the current placement */ 00450 CurrentDirPlacement = BasepDllCurrentDirPlacement; 00451 if (CurrentDirPlacement == BaseCurrentDirPlacementInvalid) 00452 { 00453 /* Open the configuration key */ 00454 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); 00455 if (NT_SUCCESS(Status)) 00456 { 00457 /* Query if safe search is enabled */ 00458 Status = NtQueryValueKey(KeyHandle, 00459 &ValueName, 00460 KeyValuePartialInformation, 00461 &PartialInfo, 00462 sizeof(PartialInfo), 00463 &ResultLength); 00464 if (NT_SUCCESS(Status)) 00465 { 00466 /* Read the value if the size is OK */ 00467 if (ResultLength == sizeof(PartialInfo)) 00468 { 00469 CurrentDirPlacement = *(PULONG)PartialInfo.Data; 00470 } 00471 } 00472 00473 /* Close the handle */ 00474 NtClose(KeyHandle); 00475 00476 /* Validate the registry value */ 00477 if ((CurrentDirPlacement <= BaseCurrentDirPlacementInvalid) || 00478 (CurrentDirPlacement >= BaseCurrentDirPlacementMax)) 00479 { 00480 /* Default to safe search */ 00481 CurrentDirPlacement = BaseCurrentDirPlacementSafe; 00482 } 00483 } 00484 00485 /* Update the placement and read the old one */ 00486 OldCurrentDirPlacement = InterlockedCompareExchange((PLONG)&BasepDllCurrentDirPlacement, 00487 CurrentDirPlacement, 00488 BaseCurrentDirPlacementInvalid); 00489 if (OldCurrentDirPlacement != BaseCurrentDirPlacementInvalid) 00490 { 00491 /* If there already was a placement, use it */ 00492 CurrentDirPlacement = OldCurrentDirPlacement; 00493 } 00494 } 00495 00496 /* Check if the placement is invalid or not set */ 00497 if ((CurrentDirPlacement <= BaseCurrentDirPlacementInvalid) || 00498 (CurrentDirPlacement >= BaseCurrentDirPlacementMax)) 00499 { 00500 /* Default to safe search */ 00501 CurrentDirPlacement = BaseCurrentDirPlacementSafe; 00502 } 00503 00504 /* Compute the process path using either normal or safe search */ 00505 DllPath = BasepComputeProcessPath(BaseDllOrderCurrent[CurrentDirPlacement], 00506 FullPath, 00507 Environment); 00508 00509 /* Return dll path */ 00510 return DllPath; 00511 } 00512 00513 BOOLEAN 00514 WINAPI 00515 CheckForSameCurdir(IN PUNICODE_STRING DirName) 00516 { 00517 PUNICODE_STRING CurDir; 00518 USHORT CurLength; 00519 BOOLEAN Result; 00520 UNICODE_STRING CurDirCopy; 00521 00522 CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath; 00523 00524 CurLength = CurDir->Length; 00525 if (CurDir->Length <= 6) 00526 { 00527 if (CurLength != DirName->Length) return FALSE; 00528 } 00529 else 00530 { 00531 if ((CurLength - 2) != DirName->Length) return FALSE; 00532 } 00533 00534 RtlAcquirePebLock(); 00535 00536 CurDirCopy = *CurDir; 00537 if (CurDirCopy.Length > 6) CurDirCopy.Length -= 2; 00538 00539 Result = 0; 00540 00541 if (RtlEqualUnicodeString(&CurDirCopy, DirName, TRUE)) Result = TRUE; 00542 00543 RtlReleasePebLock(); 00544 00545 return Result; 00546 } 00547 00548 /* 00549 * Why not use RtlIsNameLegalDOS8Dot3? In fact the actual algorithm body is 00550 * identical (other than the Rtl can optionally check for spaces), however the 00551 * Rtl will always convert to OEM, while kernel32 has two possible file modes 00552 * (ANSI or OEM). Therefore we must duplicate the algorithm body to get 00553 * the correct compatible results 00554 */ 00555 BOOL 00556 WINAPI 00557 IsShortName_U(IN PWCHAR Name, 00558 IN ULONG Length) 00559 { 00560 BOOLEAN HasExtension; 00561 WCHAR c; 00562 NTSTATUS Status; 00563 UNICODE_STRING UnicodeName; 00564 ANSI_STRING AnsiName; 00565 ULONG i, Dots; 00566 CHAR AnsiBuffer[MAX_PATH]; 00567 ASSERT(Name); 00568 00569 /* What do you think 8.3 means? */ 00570 if (Length > 12) return FALSE; 00571 00572 /* Sure, any emtpy name is a short name */ 00573 if (!Length) return TRUE; 00574 00575 /* This could be . or .. or something else */ 00576 if (*Name == L'.') 00577 { 00578 /* Which one is it */ 00579 if ((Length == 1) || ((Length == 2) && *(Name + 1) == L'.')) 00580 { 00581 /* . or .., this is good */ 00582 return TRUE; 00583 } 00584 00585 /* Some other bizare dot-based name, not good */ 00586 return FALSE; 00587 } 00588 00589 /* Initialize our two strings */ 00590 RtlInitEmptyAnsiString(&AnsiName, AnsiBuffer, MAX_PATH); 00591 RtlInitEmptyUnicodeString(&UnicodeName, Name, Length * sizeof(WCHAR)); 00592 UnicodeName.Length = UnicodeName.MaximumLength; 00593 00594 /* Now do the conversion */ 00595 Status = BasepUnicodeStringTo8BitString(&AnsiName, &UnicodeName, FALSE); 00596 if (!NT_SUCCESS(Status)) return FALSE; 00597 00598 /* Now we loop the name */ 00599 HasExtension = FALSE; 00600 for (i = 0, Dots = Length - 1; i < AnsiName.Length; i++, Dots--) 00601 { 00602 /* Read the current byte */ 00603 c = AnsiName.Buffer[i]; 00604 00605 /* Is it DBCS? */ 00606 if (IsDBCSLeadByte(c)) 00607 { 00608 /* If we're near the end of the string, we can't allow a DBCS */ 00609 if ((!(HasExtension) && (i >= 7)) || (i == AnsiName.Length - 1)) 00610 { 00611 return FALSE; 00612 } 00613 00614 /* Otherwise we skip over it */ 00615 continue; 00616 } 00617 00618 /* Check for illegal characters */ 00619 if ((c > 0x7F) || (IllegalMask[c / 32] & (1 << (c % 32)))) 00620 { 00621 return FALSE; 00622 } 00623 00624 /* Check if this is perhaps an extension? */ 00625 if (c == '.') 00626 { 00627 /* Unless the extension is too large or there's more than one */ 00628 if ((HasExtension) || (Dots > 3)) return FALSE; 00629 00630 /* This looks like an extension */ 00631 HasExtension = TRUE; 00632 } 00633 00634 /* 8.3 length was validated, but now we must guard against 9.2 or similar */ 00635 if ((i >= 8) && !(HasExtension)) return FALSE; 00636 } 00637 00638 /* You survived the loop, this is a good short name */ 00639 return TRUE; 00640 } 00641 00642 BOOL 00643 WINAPI 00644 IsLongName_U(IN PWCHAR FileName, 00645 IN ULONG Length) 00646 { 00647 BOOLEAN HasExtension; 00648 ULONG i, Dots; 00649 00650 /* More than 8.3, any combination of dots, and NULL names are all long */ 00651 if (!(Length) || (Length > 12) || (*FileName == L'.')) return TRUE; 00652 00653 /* Otherwise, initialize our scanning loop */ 00654 HasExtension = FALSE; 00655 for (i = 0, Dots = Length - 1; i < Length; i++, Dots--) 00656 { 00657 /* Check if this could be an extension */ 00658 if (FileName[i] == L'.') 00659 { 00660 /* Unlike the short case, we WANT more than one extension, or a long one */ 00661 if ((HasExtension) || (Dots > 3)) 00662 { 00663 return TRUE; 00664 } 00665 HasExtension = TRUE; 00666 } 00667 00668 /* Check if this would violate the "8" in 8.3, ie. 9.2 */ 00669 if ((i >= 8) && (!HasExtension)) return TRUE; 00670 } 00671 00672 /* The name *seems* to conform to 8.3 */ 00673 return FALSE; 00674 } 00675 00676 BOOL 00677 WINAPI 00678 FindLFNorSFN_U(IN PWCHAR Path, 00679 OUT PWCHAR *First, 00680 OUT PWCHAR *Last, 00681 IN BOOL UseShort) 00682 { 00683 PWCHAR p; 00684 ULONG Length; 00685 BOOL Found = 0; 00686 ASSERT(Path); 00687 00688 /* Loop while there is something in the path */ 00689 while (TRUE) 00690 { 00691 /* Loop within the path skipping slashes */ 00692 while ((*Path == L'\\') || (*Path == L'/')) Path++; 00693 00694 /* Make sure there's something after the slashes too! */ 00695 if (*Path == UNICODE_NULL) break; 00696 00697 /* Now skip past the file name until we get to the first slash */ 00698 p = Path + 1; 00699 while ((*p) && ((*p != L'\\') && (*p != L'/'))) p++; 00700 00701 /* Whatever is in between those two is now the file name length */ 00702 Length = p - Path; 00703 00704 /* 00705 * Check if it is valid 00706 * Note that !IsShortName != IsLongName, these two functions simply help 00707 * us determine if a conversion is necessary or not. 00708 * "Found" really means: "Is a conversion necessary?", hence the "!" 00709 */ 00710 Found = UseShort ? !IsShortName_U(Path, Length) : !IsLongName_U(Path, Length); 00711 if (Found) 00712 { 00713 /* It is! did the caller request to know the markers? */ 00714 if ((First) && (Last)) 00715 { 00716 /* Return them */ 00717 *First = Path; 00718 *Last = p; 00719 } 00720 break; 00721 } 00722 00723 /* Is there anything else following this sub-path/filename? */ 00724 if (*p == UNICODE_NULL) break; 00725 00726 /* Yes, keep going */ 00727 Path = p + 1; 00728 } 00729 00730 /* Return if anything was found and valid */ 00731 return Found; 00732 } 00733 00734 PWCHAR 00735 WINAPI 00736 SkipPathTypeIndicator_U(IN LPWSTR Path) 00737 { 00738 PWCHAR ReturnPath; 00739 ULONG i; 00740 00741 /* Check what kind of path this is and how many slashes to skip */ 00742 switch (RtlDetermineDosPathNameType_U(Path)) 00743 { 00744 case RtlPathTypeDriveAbsolute: 00745 return Path + 3; 00746 00747 case RtlPathTypeDriveRelative: 00748 return Path + 2; 00749 00750 case RtlPathTypeRooted: 00751 return Path + 1; 00752 00753 case RtlPathTypeRelative: 00754 return Path; 00755 00756 case RtlPathTypeRootLocalDevice: 00757 default: 00758 return NULL; 00759 00760 case RtlPathTypeUncAbsolute: 00761 case RtlPathTypeLocalDevice: 00762 00763 /* Keep going until we bypass the path indicators */ 00764 for (ReturnPath = Path + 2, i = 2; (i > 0) && (*ReturnPath); ReturnPath++) 00765 { 00766 /* We look for 2 slashes, so keep at it until we find them */ 00767 if ((*ReturnPath == L'\\') || (*ReturnPath == L'/')) i--; 00768 } 00769 00770 return ReturnPath; 00771 } 00772 } 00773 00774 BOOL 00775 WINAPI 00776 BasepIsCurDirAllowedForPlainExeNames(VOID) 00777 { 00778 NTSTATUS Status; 00779 UNICODE_STRING EmptyString; 00780 00781 RtlInitEmptyUnicodeString(&EmptyString, NULL, 0); 00782 Status = RtlQueryEnvironmentVariable_U(NULL, 00783 &NoDefaultCurrentDirectoryInExePath, 00784 &EmptyString); 00785 return !NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL; 00786 } 00787 00788 /* PUBLIC FUNCTIONS ***********************************************************/ 00789 00790 /* 00791 * @implemented 00792 */ 00793 BOOL 00794 WINAPI 00795 SetDllDirectoryW(IN LPCWSTR lpPathName) 00796 { 00797 UNICODE_STRING OldDirectory, DllDirectory; 00798 00799 if (lpPathName) 00800 { 00801 if (wcschr(lpPathName, L';')) 00802 { 00803 SetLastError(ERROR_INVALID_PARAMETER); 00804 return FALSE; 00805 } 00806 if (!RtlCreateUnicodeString(&DllDirectory, lpPathName)) 00807 { 00808 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00809 return FALSE; 00810 } 00811 } 00812 else 00813 { 00814 RtlInitUnicodeString(&DllDirectory, NULL); 00815 } 00816 00817 RtlEnterCriticalSection(&BaseDllDirectoryLock); 00818 00819 OldDirectory = BaseDllDirectory; 00820 BaseDllDirectory = DllDirectory; 00821 00822 RtlLeaveCriticalSection(&BaseDllDirectoryLock); 00823 00824 RtlFreeUnicodeString(&OldDirectory); 00825 return TRUE; 00826 } 00827 00828 /* 00829 * @implemented 00830 */ 00831 BOOL 00832 WINAPI 00833 SetDllDirectoryA(IN LPCSTR lpPathName) 00834 { 00835 ANSI_STRING AnsiDllDirectory; 00836 UNICODE_STRING OldDirectory, DllDirectory; 00837 NTSTATUS Status; 00838 00839 if (lpPathName) 00840 { 00841 if (strchr(lpPathName, ';')) 00842 { 00843 SetLastError(ERROR_INVALID_PARAMETER); 00844 return FALSE; 00845 } 00846 00847 Status = RtlInitAnsiStringEx(&AnsiDllDirectory, lpPathName); 00848 if (NT_SUCCESS(Status)) 00849 { 00850 Status = Basep8BitStringToUnicodeString(&DllDirectory, 00851 &AnsiDllDirectory, 00852 TRUE); 00853 } 00854 00855 if (!NT_SUCCESS(Status)) 00856 { 00857 BaseSetLastNTError(Status); 00858 return FALSE; 00859 } 00860 } 00861 else 00862 { 00863 RtlInitUnicodeString(&DllDirectory, NULL); 00864 } 00865 00866 RtlEnterCriticalSection(&BaseDllDirectoryLock); 00867 00868 OldDirectory = BaseDllDirectory; 00869 BaseDllDirectory = DllDirectory; 00870 00871 RtlLeaveCriticalSection(&BaseDllDirectoryLock); 00872 00873 RtlFreeUnicodeString(&OldDirectory); 00874 return TRUE; 00875 } 00876 00877 /* 00878 * @implemented 00879 */ 00880 DWORD 00881 WINAPI 00882 GetDllDirectoryW(IN DWORD nBufferLength, 00883 OUT LPWSTR lpBuffer) 00884 { 00885 ULONG Length; 00886 00887 RtlEnterCriticalSection(&BaseDllDirectoryLock); 00888 00889 if ((nBufferLength * sizeof(WCHAR)) > BaseDllDirectory.Length) 00890 { 00891 RtlCopyMemory(lpBuffer, BaseDllDirectory.Buffer, BaseDllDirectory.Length); 00892 Length = BaseDllDirectory.Length / sizeof(WCHAR); 00893 lpBuffer[Length] = UNICODE_NULL; 00894 } 00895 else 00896 { 00897 Length = (BaseDllDirectory.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR); 00898 if (lpBuffer) *lpBuffer = UNICODE_NULL; 00899 } 00900 00901 RtlLeaveCriticalSection(&BaseDllDirectoryLock); 00902 return Length; 00903 } 00904 00905 /* 00906 * @implemented 00907 */ 00908 DWORD 00909 WINAPI 00910 GetDllDirectoryA(IN DWORD nBufferLength, 00911 OUT LPSTR lpBuffer) 00912 { 00913 NTSTATUS Status; 00914 ANSI_STRING AnsiDllDirectory; 00915 ULONG Length; 00916 00917 RtlInitEmptyAnsiString(&AnsiDllDirectory, lpBuffer, nBufferLength); 00918 00919 RtlEnterCriticalSection(&BaseDllDirectoryLock); 00920 00921 Length = BasepUnicodeStringTo8BitSize(&BaseDllDirectory); 00922 if (Length > nBufferLength) 00923 { 00924 Status = STATUS_SUCCESS; 00925 if (lpBuffer) *lpBuffer = ANSI_NULL; 00926 } 00927 else 00928 { 00929 --Length; 00930 Status = BasepUnicodeStringTo8BitString(&AnsiDllDirectory, 00931 &BaseDllDirectory, 00932 FALSE); 00933 } 00934 00935 RtlLeaveCriticalSection(&BaseDllDirectoryLock); 00936 00937 if (!NT_SUCCESS(Status)) 00938 { 00939 BaseSetLastNTError(Status); 00940 Length = 0; 00941 if (lpBuffer) *lpBuffer = ANSI_NULL; 00942 } 00943 00944 return Length; 00945 } 00946 00947 /* 00948 * @implemented 00949 */ 00950 BOOL 00951 WINAPI 00952 NeedCurrentDirectoryForExePathW(IN LPCWSTR ExeName) 00953 { 00954 if (wcschr(ExeName, L'\\')) return TRUE; 00955 00956 return BasepIsCurDirAllowedForPlainExeNames(); 00957 } 00958 00959 /* 00960 * @implemented 00961 */ 00962 BOOL 00963 WINAPI 00964 NeedCurrentDirectoryForExePathA(IN LPCSTR ExeName) 00965 { 00966 if (strchr(ExeName, '\\')) return TRUE; 00967 00968 return BasepIsCurDirAllowedForPlainExeNames(); 00969 } 00970 00971 /* 00972 * @implemented 00973 * 00974 * NOTE: Many of these A functions may seem to do rather complex A<->W mapping 00975 * beyond what you would usually expect. There are two main reasons: 00976 * 00977 * First, these APIs are subject to the ANSI/OEM File API selection status that 00978 * the caller has chosen, so we must use the "8BitString" internal Base APIs. 00979 * 00980 * Secondly, the Wide APIs (coming from the 9x world) are coded to return the 00981 * length of the paths in "ANSI" by dividing their internal Wide character count 00982 * by two... this is usually correct when dealing with pure-ASCII codepages but 00983 * not necessarily when dealing with MBCS pre-Unicode sets, which NT supports 00984 * for CJK, for example. 00985 */ 00986 DWORD 00987 WINAPI 00988 GetFullPathNameA(IN LPCSTR lpFileName, 00989 IN DWORD nBufferLength, 00990 IN LPSTR lpBuffer, 00991 IN LPSTR *lpFilePart) 00992 { 00993 NTSTATUS Status; 00994 PWCHAR Buffer; 00995 ULONG PathSize, FilePartSize; 00996 ANSI_STRING AnsiString; 00997 UNICODE_STRING FileNameString, UniString; 00998 PWCHAR LocalFilePart; 00999 PWCHAR* FilePart; 01000 01001 /* If the caller wants filepart, use a local wide buffer since this is A */ 01002 FilePart = lpFilePart != NULL ? &LocalFilePart : NULL; 01003 01004 /* Initialize for Quickie */ 01005 FilePartSize = PathSize = 0; 01006 FileNameString.Buffer = NULL; 01007 01008 /* First get our string in Unicode */ 01009 Status = Basep8BitStringToDynamicUnicodeString(&FileNameString, lpFileName); 01010 if (!NT_SUCCESS(Status)) goto Quickie; 01011 01012 /* Allocate a buffer to hold teh path name */ 01013 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 01014 0, 01015 MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL)); 01016 if (!Buffer) 01017 { 01018 BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES); 01019 goto Quickie; 01020 } 01021 01022 /* Call into RTL to get the full Unicode path name */ 01023 PathSize = RtlGetFullPathName_U(FileNameString.Buffer, 01024 MAX_PATH * sizeof(WCHAR), 01025 Buffer, 01026 FilePart); 01027 if (PathSize <= (MAX_PATH * sizeof(WCHAR))) 01028 { 01029 /* The buffer will fit, get the real ANSI string size now */ 01030 Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize); 01031 if (NT_SUCCESS(Status)) 01032 { 01033 /* Now check if the user wanted file part size as well */ 01034 if ((PathSize) && (lpFilePart) && (LocalFilePart)) 01035 { 01036 /* Yep, so in this case get the length of the file part too */ 01037 Status = RtlUnicodeToMultiByteSize(&FilePartSize, 01038 Buffer, 01039 (LocalFilePart - Buffer) * 01040 sizeof(WCHAR)); 01041 if (!NT_SUCCESS(Status)) 01042 { 01043 /* We failed to do that, so fail the whole call */ 01044 BaseSetLastNTError(Status); 01045 PathSize = 0; 01046 } 01047 } 01048 } 01049 } 01050 else 01051 { 01052 /* Reset the path size since the buffer is not large enough */ 01053 PathSize = 0; 01054 } 01055 01056 /* Either no path, or local buffer was too small, enter failure code */ 01057 if (!PathSize) goto Quickie; 01058 01059 /* If the *caller's* buffer was too small, fail, but add in space for NULL */ 01060 if (PathSize >= nBufferLength) 01061 { 01062 PathSize++; 01063 goto Quickie; 01064 } 01065 01066 /* So far so good, initialize a unicode string to convert back to ANSI/OEM */ 01067 RtlInitUnicodeString(&UniString, Buffer); 01068 Status = BasepUnicodeStringTo8BitString(&AnsiString, &UniString, TRUE); 01069 if (!NT_SUCCESS(Status)) 01070 { 01071 /* Final conversion failed, fail the call */ 01072 BaseSetLastNTError(Status); 01073 PathSize = 0; 01074 } 01075 else 01076 { 01077 /* Conversion worked, now copy the ANSI/OEM buffer into the buffer */ 01078 RtlCopyMemory(lpBuffer, AnsiString.Buffer, PathSize + 1); 01079 RtlFreeAnsiString(&AnsiString); 01080 01081 /* And finally, did the caller request file part information? */ 01082 if (lpFilePart) 01083 { 01084 /* Use the size we computed earlier and add it to the buffer */ 01085 *lpFilePart = LocalFilePart ? &lpBuffer[FilePartSize] : 0; 01086 } 01087 } 01088 01089 Quickie: 01090 /* Cleanup and return the path size */ 01091 if (FileNameString.Buffer) RtlFreeUnicodeString(&FileNameString); 01092 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 01093 return PathSize; 01094 } 01095 01096 /* 01097 * @implemented 01098 */ 01099 DWORD 01100 WINAPI 01101 GetFullPathNameW(IN LPCWSTR lpFileName, 01102 IN DWORD nBufferLength, 01103 IN LPWSTR lpBuffer, 01104 OUT LPWSTR *lpFilePart) 01105 { 01106 /* Call Rtl to do the work */ 01107 return RtlGetFullPathName_U((LPWSTR)lpFileName, 01108 nBufferLength * sizeof(WCHAR), 01109 lpBuffer, 01110 lpFilePart) / sizeof(WCHAR); 01111 } 01112 01113 /* 01114 * @implemented 01115 */ 01116 DWORD 01117 WINAPI 01118 SearchPathA(IN LPCSTR lpPath, 01119 IN LPCSTR lpFileName, 01120 IN LPCSTR lpExtension, 01121 IN DWORD nBufferLength, 01122 IN LPSTR lpBuffer, 01123 OUT LPSTR *lpFilePart) 01124 { 01125 PUNICODE_STRING FileNameString; 01126 UNICODE_STRING PathString, ExtensionString; 01127 NTSTATUS Status; 01128 ULONG PathSize, FilePartSize, AnsiLength; 01129 PWCHAR LocalFilePart, Buffer; 01130 PWCHAR* FilePart; 01131 01132 /* If the caller wants filepart, use a local wide buffer since this is A */ 01133 FilePart = lpFilePart != NULL ? &LocalFilePart : NULL; 01134 01135 /* Initialize stuff for Quickie */ 01136 PathSize = 0; 01137 Buffer = NULL; 01138 ExtensionString.Buffer = PathString.Buffer = NULL; 01139 01140 /* Get the UNICODE_STRING file name */ 01141 FileNameString = Basep8BitStringToStaticUnicodeString(lpFileName); 01142 if (!FileNameString) return 0; 01143 01144 /* Did the caller specify an extension */ 01145 if (lpExtension) 01146 { 01147 /* Yup, convert it into UNICODE_STRING */ 01148 Status = Basep8BitStringToDynamicUnicodeString(&ExtensionString, 01149 lpExtension); 01150 if (!NT_SUCCESS(Status)) goto Quickie; 01151 } 01152 01153 /* Did the caller specify a path */ 01154 if (lpPath) 01155 { 01156 /* Yup, convert it into UNICODE_STRING */ 01157 Status = Basep8BitStringToDynamicUnicodeString(&PathString, lpPath); 01158 if (!NT_SUCCESS(Status)) goto Quickie; 01159 } 01160 01161 /* Allocate our output buffer */ 01162 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nBufferLength * sizeof(WCHAR)); 01163 if (!Buffer) 01164 { 01165 /* It failed, bail out */ 01166 BaseSetLastNTError(STATUS_NO_MEMORY); 01167 goto Quickie; 01168 } 01169 01170 /* Now run the Wide search with the input buffer lengths */ 01171 PathSize = SearchPathW(PathString.Buffer, 01172 FileNameString->Buffer, 01173 ExtensionString.Buffer, 01174 nBufferLength, 01175 Buffer, 01176 FilePart); 01177 if (PathSize <= nBufferLength) 01178 { 01179 /* It fits, but is it empty? If so, bail out */ 01180 if (!PathSize) goto Quickie; 01181 01182 /* The length above is inexact, we need it in ANSI */ 01183 Status = RtlUnicodeToMultiByteSize(&AnsiLength, Buffer, PathSize * sizeof(WCHAR)); 01184 if (!NT_SUCCESS(Status)) 01185 { 01186 /* Conversion failed, fail the call */ 01187 PathSize = 0; 01188 BaseSetLastNTError(Status); 01189 goto Quickie; 01190 } 01191 01192 /* If the correct ANSI size is too big, return requird length plus a NULL */ 01193 if (AnsiLength >= nBufferLength) 01194 { 01195 PathSize = AnsiLength + 1; 01196 goto Quickie; 01197 } 01198 01199 /* Now apply the final conversion to ANSI */ 01200 Status = RtlUnicodeToMultiByteN(lpBuffer, 01201 nBufferLength - 1, 01202 &AnsiLength, 01203 Buffer, 01204 PathSize * sizeof(WCHAR)); 01205 if (!NT_SUCCESS(Status)) 01206 { 01207 /* Conversion failed, fail the whole call */ 01208 PathSize = 0; 01209 BaseSetLastNTError(STATUS_NO_MEMORY); 01210 goto Quickie; 01211 } 01212 01213 /* NULL-terminate and return the real ANSI length */ 01214 lpBuffer[AnsiLength] = ANSI_NULL; 01215 PathSize = AnsiLength; 01216 01217 /* Now check if the user wanted file part size as well */ 01218 if (lpFilePart) 01219 { 01220 /* If we didn't get a file part, clear the caller's */ 01221 if (!LocalFilePart) 01222 { 01223 *lpFilePart = NULL; 01224 } 01225 else 01226 { 01227 /* Yep, so in this case get the length of the file part too */ 01228 Status = RtlUnicodeToMultiByteSize(&FilePartSize, 01229 Buffer, 01230 (LocalFilePart - Buffer) * 01231 sizeof(WCHAR)); 01232 if (!NT_SUCCESS(Status)) 01233 { 01234 /* We failed to do that, so fail the whole call */ 01235 BaseSetLastNTError(Status); 01236 PathSize = 0; 01237 } 01238 01239 /* Return the file part buffer */ 01240 *lpFilePart = lpBuffer + FilePartSize; 01241 } 01242 } 01243 } 01244 else 01245 { 01246 /* Our initial buffer guess was too small, allocate a bigger one */ 01247 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 01248 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize * sizeof(WCHAR)); 01249 if (!Buffer) 01250 { 01251 /* Out of memory, fail everything */ 01252 BaseSetLastNTError(STATUS_NO_MEMORY); 01253 goto Quickie; 01254 } 01255 01256 /* Do the search again -- it will fail, we just want the path size */ 01257 PathSize = SearchPathW(PathString.Buffer, 01258 FileNameString->Buffer, 01259 ExtensionString.Buffer, 01260 PathSize, 01261 Buffer, 01262 FilePart); 01263 if (!PathSize) goto Quickie; 01264 01265 /* Convert it to a correct size */ 01266 Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize * sizeof(WCHAR)); 01267 if (NT_SUCCESS(Status)) 01268 { 01269 /* Make space for the NULL-char */ 01270 PathSize++; 01271 } 01272 else 01273 { 01274 /* Conversion failed for some reason, fail the call */ 01275 BaseSetLastNTError(Status); 01276 PathSize = 0; 01277 } 01278 } 01279 01280 Quickie: 01281 /* Cleanup/complete path */ 01282 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 01283 if (ExtensionString.Buffer) RtlFreeUnicodeString(&ExtensionString); 01284 if (PathString.Buffer) RtlFreeUnicodeString(&PathString); 01285 return PathSize; 01286 } 01287 01288 /* 01289 * @implemented 01290 */ 01291 DWORD 01292 WINAPI 01293 SearchPathW(IN LPCWSTR lpPath, 01294 IN LPCWSTR lpFileName, 01295 IN LPCWSTR lpExtension, 01296 IN DWORD nBufferLength, 01297 IN LPWSTR lpBuffer, 01298 OUT LPWSTR *lpFilePart) 01299 { 01300 UNICODE_STRING FileNameString, ExtensionString, PathString, CallerBuffer; 01301 ULONG Flags, LengthNeeded, FilePartSize; 01302 NTSTATUS Status; 01303 DWORD Result = 0; 01304 01305 /* Default flags for RtlDosSearchPath_Ustr */ 01306 Flags = 6; 01307 01308 /* Clear file part in case we fail */ 01309 if (lpFilePart) *lpFilePart = NULL; 01310 01311 /* Initialize path buffer for free later */ 01312 PathString.Buffer = NULL; 01313 01314 /* Convert filename to a unicode string and eliminate trailing spaces */ 01315 RtlInitUnicodeString(&FileNameString, lpFileName); 01316 while ((FileNameString.Length >= sizeof(WCHAR)) && 01317 (FileNameString.Buffer[(FileNameString.Length / sizeof(WCHAR)) - 1] == L' ')) 01318 { 01319 FileNameString.Length -= sizeof(WCHAR); 01320 } 01321 01322 /* Was it all just spaces? */ 01323 if (!FileNameString.Length) 01324 { 01325 /* Fail out */ 01326 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 01327 goto Quickie; 01328 } 01329 01330 /* Convert extension to a unicode string */ 01331 RtlInitUnicodeString(&ExtensionString, lpExtension); 01332 01333 /* Check if the user sent a path */ 01334 if (lpPath) 01335 { 01336 /* Convert it to a unicode string too */ 01337 Status = RtlInitUnicodeStringEx(&PathString, lpPath); 01338 if (NT_ERROR(Status)) 01339 { 01340 /* Fail if it was too long */ 01341 BaseSetLastNTError(Status); 01342 goto Quickie; 01343 } 01344 } 01345 else 01346 { 01347 /* A path wasn't sent, so compute it ourselves */ 01348 PathString.Buffer = BaseComputeProcessSearchPath(); 01349 if (!PathString.Buffer) 01350 { 01351 /* Fail if we couldn't compute it */ 01352 BaseSetLastNTError(STATUS_NO_MEMORY); 01353 goto Quickie; 01354 } 01355 01356 /* See how big the computed path is */ 01357 LengthNeeded = lstrlenW(PathString.Buffer); 01358 if (LengthNeeded > UNICODE_STRING_MAX_CHARS) 01359 { 01360 /* Fail if it's too long */ 01361 BaseSetLastNTError(STATUS_NAME_TOO_LONG); 01362 goto Quickie; 01363 } 01364 01365 /* Set the path size now that we have it */ 01366 PathString.MaximumLength = PathString.Length = LengthNeeded * sizeof(WCHAR); 01367 01368 /* Request SxS isolation from RtlDosSearchPath_Ustr */ 01369 Flags |= 1; 01370 } 01371 01372 /* Create the string that describes the output buffer from the caller */ 01373 CallerBuffer.Length = 0; 01374 CallerBuffer.Buffer = lpBuffer; 01375 01376 /* How much space does the caller have? */ 01377 if (nBufferLength <= UNICODE_STRING_MAX_CHARS) 01378 { 01379 /* Add it into the string */ 01380 CallerBuffer.MaximumLength = nBufferLength * sizeof(WCHAR); 01381 } 01382 else 01383 { 01384 /* Caller wants too much, limit it to the maximum length of a string */ 01385 CallerBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES; 01386 } 01387 01388 /* Call Rtl to do the work */ 01389 Status = RtlDosSearchPath_Ustr(Flags, 01390 &PathString, 01391 &FileNameString, 01392 &ExtensionString, 01393 &CallerBuffer, 01394 NULL, 01395 NULL, 01396 &FilePartSize, 01397 &LengthNeeded); 01398 if (NT_ERROR(Status)) 01399 { 01400 /* Check for unusual status codes */ 01401 if ((Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL)) 01402 { 01403 /* Print them out since maybe an app needs fixing */ 01404 DbgPrint("%s on file %wZ failed; NTSTATUS = %08lx\n", 01405 __FUNCTION__, 01406 &FileNameString, 01407 Status); 01408 DbgPrint(" Path = %wZ\n", &PathString); 01409 } 01410 01411 /* Check if the failure was due to a small buffer */ 01412 if (Status == STATUS_BUFFER_TOO_SMALL) 01413 { 01414 /* Check if the length was actually too big for Rtl to work with */ 01415 Result = LengthNeeded / sizeof(WCHAR); 01416 if (Result > 0xFFFFFFFF) BaseSetLastNTError(STATUS_NAME_TOO_LONG); 01417 } 01418 else 01419 { 01420 /* Some other error, set the error code */ 01421 BaseSetLastNTError(Status); 01422 } 01423 } 01424 else 01425 { 01426 /* It worked! Write the file part now */ 01427 if (lpFilePart) *lpFilePart = &lpBuffer[FilePartSize]; 01428 01429 /* Convert the final result length */ 01430 Result = CallerBuffer.Length / sizeof(WCHAR); 01431 } 01432 01433 Quickie: 01434 /* Check if there was a dynamic path stirng to free */ 01435 if ((PathString.Buffer != lpPath) && (PathString.Buffer)) 01436 { 01437 /* And free it */ 01438 RtlFreeHeap(RtlGetProcessHeap(), 0, PathString.Buffer); 01439 } 01440 01441 /* Return the final result lenght */ 01442 return Result; 01443 } 01444 01445 /* 01446 * @implemented 01447 */ 01448 DWORD 01449 WINAPI 01450 GetLongPathNameW(IN LPCWSTR lpszShortPath, 01451 IN LPWSTR lpszLongPath, 01452 IN DWORD cchBuffer) 01453 { 01454 PWCHAR Path, Original, First, Last, Buffer, Src, Dst; 01455 ULONG Length; 01456 WCHAR LastChar; 01457 HANDLE FindHandle; 01458 DWORD ReturnLength; 01459 ULONG ErrorMode; 01460 BOOLEAN Found = FALSE; 01461 WIN32_FIND_DATAW FindFileData; 01462 01463 /* Initialize so Quickie knows there's nothing to do */ 01464 Buffer = Original = NULL; 01465 ReturnLength = 0; 01466 01467 /* First check if the input path was obviously NULL */ 01468 if (!lpszShortPath) 01469 { 01470 /* Fail the request */ 01471 SetLastError(ERROR_INVALID_PARAMETER); 01472 return 0; 01473 } 01474 01475 /* We will be touching removed, removable drives -- don't warn the user */ 01476 ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); 01477 01478 /* Do a simple check to see if the path exists */ 01479 if (GetFileAttributesW(lpszShortPath) == INVALID_FILE_ATTRIBUTES) 01480 { 01481 /* It doesn't, so fail */ 01482 ReturnLength = 0; 01483 goto Quickie; 01484 } 01485 01486 /* Now get a pointer to the actual path, skipping indicators */ 01487 Path = SkipPathTypeIndicator_U((LPWSTR)lpszShortPath); 01488 01489 /* Is there any path or filename in there? */ 01490 if (!(Path) || 01491 (*Path == UNICODE_NULL) || 01492 !(FindLFNorSFN_U(Path, &First, &Last, FALSE))) 01493 { 01494 /* There isn't, so the long path is simply the short path */ 01495 ReturnLength = wcslen(lpszShortPath); 01496 01497 /* Is there space for it? */ 01498 if ((cchBuffer > ReturnLength) && (lpszLongPath)) 01499 { 01500 /* Make sure the pointers aren't already the same */ 01501 if (lpszLongPath != lpszShortPath) 01502 { 01503 /* They're not -- copy the short path into the long path */ 01504 RtlMoveMemory(lpszLongPath, 01505 lpszShortPath, 01506 ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL)); 01507 } 01508 } 01509 else 01510 { 01511 /* Otherwise, let caller know we need a bigger buffer, include NULL */ 01512 ReturnLength++; 01513 } 01514 goto Quickie; 01515 } 01516 01517 /* We are still in the game -- compute the current size */ 01518 Length = wcslen(lpszShortPath) + sizeof(ANSI_NULL); 01519 Original = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR)); 01520 if (!Original) goto ErrorQuickie; 01521 01522 /* Make a copy of it */ 01523 RtlMoveMemory(Original, lpszShortPath, Length * sizeof(WCHAR)); 01524 01525 /* Compute the new first and last markers */ 01526 First = &Original[First - lpszShortPath]; 01527 Last = &Original[Last - lpszShortPath]; 01528 01529 /* Set the current destination pointer for a copy */ 01530 Dst = lpszLongPath; 01531 01532 /* 01533 * Windows allows the paths to overlap -- we have to be careful with this and 01534 * see if it's same to do so, and if not, allocate our own internal buffer 01535 * that we'll return at the end. 01536 * 01537 * This is also why we use RtlMoveMemory everywhere. Don't use RtlCopyMemory! 01538 */ 01539 if ((cchBuffer) && (lpszLongPath) && 01540 (((lpszLongPath >= lpszShortPath) && (lpszLongPath < &lpszShortPath[Length])) || 01541 ((lpszLongPath < lpszShortPath) && (&lpszLongPath[cchBuffer] >= lpszShortPath)))) 01542 { 01543 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchBuffer * sizeof(WCHAR)); 01544 if (!Buffer) goto ErrorQuickie; 01545 01546 /* New destination */ 01547 Dst = Buffer; 01548 } 01549 01550 /* Prepare for the loop */ 01551 Src = Original; 01552 ReturnLength = 0; 01553 while (TRUE) 01554 { 01555 /* Current delta in the loop */ 01556 Length = First - Src; 01557 01558 /* Update the return length by it */ 01559 ReturnLength += Length; 01560 01561 /* Is there a delta? If so, is there space and buffer for it? */ 01562 if ((Length) && (cchBuffer > ReturnLength) && (lpszLongPath)) 01563 { 01564 RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR)); 01565 Dst += Length; 01566 } 01567 01568 /* "Terminate" this portion of the path's substring so we can do a find */ 01569 LastChar = *Last; 01570 *Last = UNICODE_NULL; 01571 FindHandle = FindFirstFileW(Original, &FindFileData); 01572 *Last = LastChar; 01573 01574 /* This portion wasn't found, so fail */ 01575 if (FindHandle == INVALID_HANDLE_VALUE) 01576 { 01577 ReturnLength = 0; 01578 break; 01579 } 01580 01581 /* Close the find handle */ 01582 FindClose(FindHandle); 01583 01584 /* Now check the length of the long name */ 01585 Length = wcslen(FindFileData.cFileName); 01586 if (Length) 01587 { 01588 /* This is our new first marker */ 01589 First = FindFileData.cFileName; 01590 } 01591 else 01592 { 01593 /* Otherwise, the name is the delta between our current markers */ 01594 Length = Last - First; 01595 } 01596 01597 /* Update the return length with the short name length, if any */ 01598 ReturnLength += Length; 01599 01600 /* Once again check for appropriate space and buffer */ 01601 if ((cchBuffer > ReturnLength) && (lpszLongPath)) 01602 { 01603 /* And do the copy if there is */ 01604 RtlMoveMemory(Dst, First, Length * sizeof(WCHAR)); 01605 Dst += Length; 01606 } 01607 01608 /* Now update the source pointer */ 01609 Src = Last; 01610 if (*Src == UNICODE_NULL) break; 01611 01612 /* Are there more names in there? */ 01613 Found = FindLFNorSFN_U(Src, &First, &Last, FALSE); 01614 if (!Found) break; 01615 } 01616 01617 /* The loop is done, is there anything left? */ 01618 if (ReturnLength) 01619 { 01620 /* Get the length of the straggling path */ 01621 Length = wcslen(Src); 01622 ReturnLength += Length; 01623 01624 /* Once again check for appropriate space and buffer */ 01625 if ((cchBuffer > ReturnLength) && (lpszLongPath)) 01626 { 01627 /* And do the copy if there is -- accounting for NULL here */ 01628 RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR) + sizeof(UNICODE_NULL)); 01629 01630 /* What about our buffer? */ 01631 if (Buffer) 01632 { 01633 /* Copy it into the caller's long path */ 01634 RtlMoveMemory(lpszLongPath, 01635 Buffer, 01636 ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL)); 01637 } 01638 } 01639 else 01640 { 01641 /* Buffer is too small, let the caller know, making space for NULL */ 01642 ReturnLength++; 01643 } 01644 } 01645 01646 /* We're all done */ 01647 goto Quickie; 01648 01649 ErrorQuickie: 01650 /* This is the goto for memory failures */ 01651 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 01652 01653 Quickie: 01654 /* General function end: free memory, restore error mode, return length */ 01655 if (Original) RtlFreeHeap(RtlGetProcessHeap(), 0, Original); 01656 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 01657 SetErrorMode(ErrorMode); 01658 return ReturnLength; 01659 } 01660 01661 /* 01662 * @implemented 01663 */ 01664 DWORD 01665 WINAPI 01666 GetLongPathNameA(IN LPCSTR lpszShortPath, 01667 IN LPSTR lpszLongPath, 01668 IN DWORD cchBuffer) 01669 { 01670 ULONG Result, PathLength; 01671 PWCHAR LongPath; 01672 NTSTATUS Status; 01673 UNICODE_STRING LongPathUni, ShortPathUni; 01674 ANSI_STRING LongPathAnsi; 01675 WCHAR LongPathBuffer[MAX_PATH]; 01676 01677 LongPath = NULL; 01678 LongPathAnsi.Buffer = NULL; 01679 ShortPathUni.Buffer = NULL; 01680 Result = 0; 01681 01682 if (!lpszShortPath) 01683 { 01684 SetLastError(ERROR_INVALID_PARAMETER); 01685 return 0; 01686 } 01687 01688 Status = Basep8BitStringToDynamicUnicodeString(&ShortPathUni, lpszShortPath); 01689 if (!NT_SUCCESS(Status)) goto Quickie; 01690 01691 LongPath = LongPathBuffer; 01692 01693 PathLength = GetLongPathNameW(ShortPathUni.Buffer, LongPathBuffer, MAX_PATH); 01694 if (PathLength >= MAX_PATH) 01695 { 01696 LongPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLength * sizeof(WCHAR)); 01697 if (!LongPath) 01698 { 01699 PathLength = 0; 01700 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 01701 } 01702 else 01703 { 01704 PathLength = GetLongPathNameW(ShortPathUni.Buffer, LongPath, PathLength); 01705 } 01706 } 01707 01708 if (!PathLength) goto Quickie; 01709 01710 ShortPathUni.MaximumLength = PathLength * sizeof(WCHAR) + sizeof(UNICODE_NULL); 01711 LongPathUni.Buffer = LongPath; 01712 LongPathUni.Length = PathLength * sizeof(WCHAR); 01713 01714 Status = BasepUnicodeStringTo8BitString(&LongPathAnsi, &LongPathUni, TRUE); 01715 if (!NT_SUCCESS(Status)) 01716 { 01717 BaseSetLastNTError(Status); 01718 Result = 0; 01719 } 01720 01721 Result = LongPathAnsi.Length; 01722 if ((lpszLongPath) && (cchBuffer > LongPathAnsi.Length)) 01723 { 01724 RtlMoveMemory(lpszLongPath, LongPathAnsi.Buffer, LongPathAnsi.Length); 01725 lpszLongPath[Result] = ANSI_NULL; 01726 } 01727 else 01728 { 01729 Result = LongPathAnsi.Length + sizeof(ANSI_NULL); 01730 } 01731 01732 Quickie: 01733 if (ShortPathUni.Buffer) RtlFreeUnicodeString(&ShortPathUni); 01734 if (LongPathAnsi.Buffer) RtlFreeAnsiString(&LongPathAnsi); 01735 if ((LongPath) && (LongPath != LongPathBuffer)) 01736 { 01737 RtlFreeHeap(RtlGetProcessHeap(), 0, LongPath); 01738 } 01739 return Result; 01740 } 01741 01742 /* 01743 * @implemented 01744 */ 01745 DWORD 01746 WINAPI 01747 GetShortPathNameA(IN LPCSTR lpszLongPath, 01748 IN LPSTR lpszShortPath, 01749 IN DWORD cchBuffer) 01750 { 01751 ULONG Result, PathLength; 01752 PWCHAR ShortPath; 01753 NTSTATUS Status; 01754 UNICODE_STRING LongPathUni, ShortPathUni; 01755 ANSI_STRING ShortPathAnsi; 01756 WCHAR ShortPathBuffer[MAX_PATH]; 01757 01758 ShortPath = NULL; 01759 ShortPathAnsi.Buffer = NULL; 01760 LongPathUni.Buffer = NULL; 01761 Result = 0; 01762 01763 if (!lpszLongPath) 01764 { 01765 SetLastError(ERROR_INVALID_PARAMETER); 01766 return 0; 01767 } 01768 01769 Status = Basep8BitStringToDynamicUnicodeString(&LongPathUni, lpszLongPath); 01770 if (!NT_SUCCESS(Status)) goto Quickie; 01771 01772 ShortPath = ShortPathBuffer; 01773 01774 PathLength = GetShortPathNameW(LongPathUni.Buffer, ShortPathBuffer, MAX_PATH); 01775 if (PathLength >= MAX_PATH) 01776 { 01777 ShortPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLength * sizeof(WCHAR)); 01778 if (!ShortPath) 01779 { 01780 PathLength = 0; 01781 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 01782 } 01783 else 01784 { 01785 PathLength = GetShortPathNameW(LongPathUni.Buffer, ShortPath, PathLength); 01786 } 01787 } 01788 01789 if (!PathLength) goto Quickie; 01790 01791 LongPathUni.MaximumLength = PathLength * sizeof(WCHAR) + sizeof(UNICODE_NULL); 01792 ShortPathUni.Buffer = ShortPath; 01793 ShortPathUni.Length = PathLength * sizeof(WCHAR); 01794 01795 Status = BasepUnicodeStringTo8BitString(&ShortPathAnsi, &ShortPathUni, TRUE); 01796 if (!NT_SUCCESS(Status)) 01797 { 01798 BaseSetLastNTError(Status); 01799 Result = 0; 01800 } 01801 01802 Result = ShortPathAnsi.Length; 01803 if ((lpszShortPath) && (cchBuffer > ShortPathAnsi.Length)) 01804 { 01805 RtlMoveMemory(lpszShortPath, ShortPathAnsi.Buffer, ShortPathAnsi.Length); 01806 lpszShortPath[Result] = ANSI_NULL; 01807 } 01808 else 01809 { 01810 Result = ShortPathAnsi.Length + sizeof(ANSI_NULL); 01811 } 01812 01813 Quickie: 01814 if (LongPathUni.Buffer) RtlFreeUnicodeString(&LongPathUni); 01815 if (ShortPathAnsi.Buffer) RtlFreeAnsiString(&ShortPathAnsi); 01816 if ((ShortPath) && (ShortPath != ShortPathBuffer)) 01817 { 01818 RtlFreeHeap(RtlGetProcessHeap(), 0, ShortPath); 01819 } 01820 return Result; 01821 } 01822 01823 /* 01824 * @implemented 01825 */ 01826 DWORD 01827 WINAPI 01828 GetShortPathNameW(IN LPCWSTR lpszLongPath, 01829 IN LPWSTR lpszShortPath, 01830 IN DWORD cchBuffer) 01831 { 01832 PWCHAR Path, Original, First, Last, Buffer, Src, Dst; 01833 ULONG Length; 01834 WCHAR LastChar; 01835 HANDLE FindHandle; 01836 DWORD ReturnLength; 01837 ULONG ErrorMode; 01838 BOOLEAN Found = FALSE; 01839 WIN32_FIND_DATAW FindFileData; 01840 01841 /* Initialize so Quickie knows there's nothing to do */ 01842 Buffer = Original = NULL; 01843 ReturnLength = 0; 01844 01845 /* First check if the input path was obviously NULL */ 01846 if (!lpszLongPath) 01847 { 01848 /* Fail the request */ 01849 SetLastError(ERROR_INVALID_PARAMETER); 01850 return 0; 01851 } 01852 01853 /* We will be touching removed, removable drives -- don't warn the user */ 01854 ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); 01855 01856 /* Do a simple check to see if the path exists */ 01857 if (GetFileAttributesW(lpszLongPath) == INVALID_FILE_ATTRIBUTES) 01858 { 01859 /* Windows checks for an application compatibility flag to allow this */ 01860 if (!(NtCurrentPeb()) || !(NtCurrentPeb()->AppCompatFlags.LowPart & 1)) 01861 { 01862 /* It doesn't, so fail */ 01863 ReturnLength = 0; 01864 goto Quickie; 01865 } 01866 } 01867 01868 /* Now get a pointer to the actual path, skipping indicators */ 01869 Path = SkipPathTypeIndicator_U((LPWSTR)lpszLongPath); 01870 01871 /* Is there any path or filename in there? */ 01872 if (!(Path) || 01873 (*Path == UNICODE_NULL) || 01874 !(FindLFNorSFN_U(Path, &First, &Last, TRUE))) 01875 { 01876 /* There isn't, so the long path is simply the short path */ 01877 ReturnLength = wcslen(lpszLongPath); 01878 01879 /* Is there space for it? */ 01880 if ((cchBuffer > ReturnLength) && (lpszShortPath)) 01881 { 01882 /* Make sure the pointers aren't already the same */ 01883 if (lpszLongPath != lpszShortPath) 01884 { 01885 /* They're not -- copy the short path into the long path */ 01886 RtlMoveMemory(lpszShortPath, 01887 lpszLongPath, 01888 ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL)); 01889 } 01890 } 01891 else 01892 { 01893 /* Otherwise, let caller know we need a bigger buffer, include NULL */ 01894 ReturnLength++; 01895 } 01896 goto Quickie; 01897 } 01898 01899 /* We are still in the game -- compute the current size */ 01900 Length = wcslen(lpszLongPath) + sizeof(ANSI_NULL); 01901 Original = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR)); 01902 if (!Original) goto ErrorQuickie; 01903 01904 /* Make a copy of it */ 01905 wcsncpy(Original, lpszLongPath, Length); 01906 01907 /* Compute the new first and last markers */ 01908 First = &Original[First - lpszLongPath]; 01909 Last = &Original[Last - lpszLongPath]; 01910 01911 /* Set the current destination pointer for a copy */ 01912 Dst = lpszShortPath; 01913 01914 /* 01915 * Windows allows the paths to overlap -- we have to be careful with this and 01916 * see if it's same to do so, and if not, allocate our own internal buffer 01917 * that we'll return at the end. 01918 * 01919 * This is also why we use RtlMoveMemory everywhere. Don't use RtlCopyMemory! 01920 */ 01921 if ((cchBuffer) && (lpszShortPath) && 01922 (((lpszShortPath >= lpszLongPath) && (lpszShortPath < &lpszLongPath[Length])) || 01923 ((lpszShortPath < lpszLongPath) && (&lpszShortPath[cchBuffer] >= lpszLongPath)))) 01924 { 01925 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchBuffer * sizeof(WCHAR)); 01926 if (!Buffer) goto ErrorQuickie; 01927 01928 /* New destination */ 01929 Dst = Buffer; 01930 } 01931 01932 /* Prepare for the loop */ 01933 Src = Original; 01934 ReturnLength = 0; 01935 while (TRUE) 01936 { 01937 /* Current delta in the loop */ 01938 Length = First - Src; 01939 01940 /* Update the return length by it */ 01941 ReturnLength += Length; 01942 01943 /* Is there a delta? If so, is there space and buffer for it? */ 01944 if ((Length) && (cchBuffer > ReturnLength) && (lpszShortPath)) 01945 { 01946 RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR)); 01947 Dst += Length; 01948 } 01949 01950 /* "Terminate" this portion of the path's substring so we can do a find */ 01951 LastChar = *Last; 01952 *Last = UNICODE_NULL; 01953 FindHandle = FindFirstFileW(Original, &FindFileData); 01954 *Last = LastChar; 01955 01956 /* This portion wasn't found, so fail */ 01957 if (FindHandle == INVALID_HANDLE_VALUE) 01958 { 01959 ReturnLength = 0; 01960 break; 01961 } 01962 01963 /* Close the find handle */ 01964 FindClose(FindHandle); 01965 01966 /* Now check the length of the short name */ 01967 Length = wcslen(FindFileData.cAlternateFileName); 01968 if (Length) 01969 { 01970 /* This is our new first marker */ 01971 First = FindFileData.cAlternateFileName; 01972 } 01973 else 01974 { 01975 /* Otherwise, the name is the delta between our current markers */ 01976 Length = Last - First; 01977 } 01978 01979 /* Update the return length with the short name length, if any */ 01980 ReturnLength += Length; 01981 01982 /* Once again check for appropriate space and buffer */ 01983 if ((cchBuffer > ReturnLength) && (lpszShortPath)) 01984 { 01985 /* And do the copy if there is */ 01986 RtlMoveMemory(Dst, First, Length * sizeof(WCHAR)); 01987 Dst += Length; 01988 } 01989 01990 /* Now update the source pointer */ 01991 Src = Last; 01992 if (*Src == UNICODE_NULL) break; 01993 01994 /* Are there more names in there? */ 01995 Found = FindLFNorSFN_U(Src, &First, &Last, TRUE); 01996 if (!Found) break; 01997 } 01998 01999 /* The loop is done, is there anything left? */ 02000 if (ReturnLength) 02001 { 02002 /* Get the length of the straggling path */ 02003 Length = wcslen(Src); 02004 ReturnLength += Length; 02005 02006 /* Once again check for appropriate space and buffer */ 02007 if ((cchBuffer > ReturnLength) && (lpszShortPath)) 02008 { 02009 /* And do the copy if there is -- accounting for NULL here */ 02010 RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR) + sizeof(UNICODE_NULL)); 02011 02012 /* What about our buffer? */ 02013 if (Buffer) 02014 { 02015 /* Copy it into the caller's long path */ 02016 RtlMoveMemory(lpszShortPath, 02017 Buffer, 02018 ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL)); 02019 } 02020 } 02021 else 02022 { 02023 /* Buffer is too small, let the caller know, making space for NULL */ 02024 ReturnLength++; 02025 } 02026 } 02027 02028 /* We're all done */ 02029 goto Quickie; 02030 02031 ErrorQuickie: 02032 /* This is the goto for memory failures */ 02033 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 02034 02035 Quickie: 02036 /* General function end: free memory, restore error mode, return length */ 02037 if (Original) RtlFreeHeap(RtlGetProcessHeap(), 0, Original); 02038 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 02039 SetErrorMode(ErrorMode); 02040 return ReturnLength; 02041 } 02042 02043 /* 02044 * @implemented 02045 * 02046 * NOTE: Windows returns a dos/short (8.3) path 02047 */ 02048 DWORD 02049 WINAPI 02050 GetTempPathA(IN DWORD nBufferLength, 02051 IN LPSTR lpBuffer) 02052 { 02053 WCHAR BufferW[MAX_PATH]; 02054 DWORD ret; 02055 02056 ret = GetTempPathW(MAX_PATH, BufferW); 02057 02058 if (!ret) return 0; 02059 02060 if (ret > MAX_PATH) 02061 { 02062 SetLastError(ERROR_FILENAME_EXCED_RANGE); 02063 return 0; 02064 } 02065 02066 return FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1); 02067 } 02068 02069 /* 02070 * @implemented 02071 * 02072 * ripped from wine 02073 */ 02074 DWORD 02075 WINAPI 02076 GetTempPathW(IN DWORD count, 02077 IN LPWSTR path) 02078 { 02079 static const WCHAR tmp[] = { 'T', 'M', 'P', 0 }; 02080 static const WCHAR temp[] = { 'T', 'E', 'M', 'P', 0 }; 02081 static const WCHAR userprofile[] = { 'U','S','E','R','P','R','O','F','I','L','E',0 }; 02082 WCHAR tmp_path[MAX_PATH]; 02083 UINT ret; 02084 02085 DPRINT("%u,%p\n", count, path); 02086 02087 if (!(ret = GetEnvironmentVariableW( tmp, tmp_path, MAX_PATH )) && 02088 !(ret = GetEnvironmentVariableW( temp, tmp_path, MAX_PATH )) && 02089 !(ret = GetEnvironmentVariableW( userprofile, tmp_path, MAX_PATH )) && 02090 !(ret = GetWindowsDirectoryW( tmp_path, MAX_PATH ))) 02091 return 0; 02092 02093 if (ret > MAX_PATH) 02094 { 02095 SetLastError(ERROR_FILENAME_EXCED_RANGE); 02096 return 0; 02097 } 02098 02099 ret = GetFullPathNameW(tmp_path, MAX_PATH, tmp_path, NULL); 02100 if (!ret) return 0; 02101 02102 if (ret > MAX_PATH - 2) 02103 { 02104 SetLastError(ERROR_FILENAME_EXCED_RANGE); 02105 return 0; 02106 } 02107 02108 if (tmp_path[ret-1] != '\\') 02109 { 02110 tmp_path[ret++] = '\\'; 02111 tmp_path[ret] = '\0'; 02112 } 02113 02114 ret++; /* add space for terminating 0 */ 02115 02116 if (count) 02117 { 02118 lstrcpynW(path, tmp_path, count); 02119 if (count >= ret) 02120 ret--; /* return length without 0 */ 02121 else if (count < 4) 02122 path[0] = 0; /* avoid returning ambiguous "X:" */ 02123 } 02124 02125 DPRINT("GetTempPathW returning %u, %S\n", ret, path); 02126 return ret; 02127 } 02128 02129 /* 02130 * @implemented 02131 */ 02132 DWORD 02133 WINAPI 02134 GetCurrentDirectoryA(IN DWORD nBufferLength, 02135 IN LPSTR lpBuffer) 02136 { 02137 ANSI_STRING AnsiString; 02138 NTSTATUS Status; 02139 PUNICODE_STRING StaticString; 02140 ULONG MaxLength; 02141 02142 StaticString = &NtCurrentTeb()->StaticUnicodeString; 02143 02144 MaxLength = nBufferLength; 02145 if (nBufferLength >= UNICODE_STRING_MAX_BYTES) 02146 { 02147 MaxLength = UNICODE_STRING_MAX_BYTES - 1; 02148 } 02149 02150 StaticString->Length = RtlGetCurrentDirectory_U(StaticString->MaximumLength, 02151 StaticString->Buffer); 02152 Status = RtlUnicodeToMultiByteSize(&nBufferLength, 02153 StaticString->Buffer, 02154 StaticString->Length); 02155 if (!NT_SUCCESS(Status)) 02156 { 02157 BaseSetLastNTError(Status); 02158 return 0; 02159 } 02160 02161 if (MaxLength <= nBufferLength) 02162 { 02163 return nBufferLength + 1; 02164 } 02165 02166 AnsiString.Buffer = lpBuffer; 02167 AnsiString.MaximumLength = MaxLength; 02168 Status = BasepUnicodeStringTo8BitString(&AnsiString, StaticString, FALSE); 02169 if (!NT_SUCCESS(Status)) 02170 { 02171 BaseSetLastNTError(Status); 02172 return 0; 02173 } 02174 02175 return AnsiString.Length; 02176 } 02177 02178 /* 02179 * @implemented 02180 */ 02181 DWORD 02182 WINAPI 02183 GetCurrentDirectoryW(IN DWORD nBufferLength, 02184 IN LPWSTR lpBuffer) 02185 { 02186 return RtlGetCurrentDirectory_U(nBufferLength * sizeof(WCHAR), lpBuffer) / sizeof(WCHAR); 02187 } 02188 02189 /* 02190 * @implemented 02191 */ 02192 BOOL 02193 WINAPI 02194 SetCurrentDirectoryA(IN LPCSTR lpPathName) 02195 { 02196 PUNICODE_STRING DirName; 02197 NTSTATUS Status; 02198 02199 if (!lpPathName) 02200 { 02201 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 02202 return FALSE; 02203 } 02204 02205 DirName = Basep8BitStringToStaticUnicodeString(lpPathName); 02206 if (!DirName) return FALSE; 02207 02208 if (CheckForSameCurdir(DirName)) return TRUE; 02209 02210 Status = RtlSetCurrentDirectory_U(DirName); 02211 if (NT_SUCCESS(Status)) return TRUE; 02212 02213 if ((*DirName->Buffer != L'"') || (DirName->Length <= 2)) 02214 { 02215 BaseSetLastNTError(Status); 02216 return 0; 02217 } 02218 02219 DirName = Basep8BitStringToStaticUnicodeString(lpPathName + 1); 02220 if (!DirName) return FALSE; 02221 02222 Status = RtlSetCurrentDirectory_U(DirName); 02223 if (!NT_SUCCESS(Status)) 02224 { 02225 BaseSetLastNTError(Status); 02226 return FALSE; 02227 } 02228 02229 return TRUE; 02230 } 02231 02232 /* 02233 * @implemented 02234 */ 02235 BOOL 02236 WINAPI 02237 SetCurrentDirectoryW(IN LPCWSTR lpPathName) 02238 { 02239 NTSTATUS Status; 02240 UNICODE_STRING UnicodeString; 02241 02242 if (!lpPathName) 02243 { 02244 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 02245 return FALSE; 02246 } 02247 02248 Status = RtlInitUnicodeStringEx(&UnicodeString, lpPathName); 02249 if (NT_SUCCESS(Status)) 02250 { 02251 if (!CheckForSameCurdir(&UnicodeString)) 02252 { 02253 Status = RtlSetCurrentDirectory_U(&UnicodeString); 02254 } 02255 } 02256 02257 if (!NT_SUCCESS(Status)) 02258 { 02259 BaseSetLastNTError(Status); 02260 return FALSE; 02261 } 02262 02263 return TRUE; 02264 } 02265 02266 /* 02267 * @implemented 02268 */ 02269 UINT 02270 WINAPI 02271 GetSystemDirectoryA(IN LPSTR lpBuffer, 02272 IN UINT uSize) 02273 { 02274 ANSI_STRING AnsiString; 02275 NTSTATUS Status; 02276 ULONG AnsiLength; 02277 02278 /* Get the correct size of the Unicode Base directory */ 02279 Status = RtlUnicodeToMultiByteSize(&AnsiLength, 02280 BaseWindowsSystemDirectory.Buffer, 02281 BaseWindowsSystemDirectory.MaximumLength); 02282 if (!NT_SUCCESS(Status)) return 0; 02283 02284 if (uSize < AnsiLength) return AnsiLength; 02285 02286 RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize); 02287 02288 Status = BasepUnicodeStringTo8BitString(&AnsiString, 02289 &BaseWindowsSystemDirectory, 02290 FALSE); 02291 if (!NT_SUCCESS(Status)) return 0; 02292 02293 return AnsiString.Length; 02294 } 02295 02296 /* 02297 * @implemented 02298 */ 02299 UINT 02300 WINAPI 02301 GetSystemDirectoryW(IN LPWSTR lpBuffer, 02302 IN UINT uSize) 02303 { 02304 ULONG ReturnLength; 02305 02306 ReturnLength = BaseWindowsSystemDirectory.MaximumLength; 02307 if ((uSize * sizeof(WCHAR)) >= ReturnLength) 02308 { 02309 RtlCopyMemory(lpBuffer, 02310 BaseWindowsSystemDirectory.Buffer, 02311 BaseWindowsSystemDirectory.Length); 02312 lpBuffer[BaseWindowsSystemDirectory.Length / sizeof(WCHAR)] = ANSI_NULL; 02313 02314 ReturnLength = BaseWindowsSystemDirectory.Length; 02315 } 02316 02317 return ReturnLength / sizeof(WCHAR); 02318 } 02319 02320 /* 02321 * @implemented 02322 */ 02323 UINT 02324 WINAPI 02325 GetWindowsDirectoryA(IN LPSTR lpBuffer, 02326 IN UINT uSize) 02327 { 02328 /* Is this a TS installation? */ 02329 if (gpTermsrvGetWindowsDirectoryA) UNIMPLEMENTED; 02330 02331 /* Otherwise, call the System API */ 02332 return GetSystemWindowsDirectoryA(lpBuffer, uSize); 02333 } 02334 02335 /* 02336 * @implemented 02337 */ 02338 UINT 02339 WINAPI 02340 GetWindowsDirectoryW(IN LPWSTR lpBuffer, 02341 IN UINT uSize) 02342 { 02343 /* Is this a TS installation? */ 02344 if (gpTermsrvGetWindowsDirectoryW) UNIMPLEMENTED; 02345 02346 /* Otherwise, call the System API */ 02347 return GetSystemWindowsDirectoryW(lpBuffer, uSize); 02348 } 02349 02350 /* 02351 * @implemented 02352 */ 02353 UINT 02354 WINAPI 02355 GetSystemWindowsDirectoryA(IN LPSTR lpBuffer, 02356 IN UINT uSize) 02357 { 02358 ANSI_STRING AnsiString; 02359 NTSTATUS Status; 02360 ULONG AnsiLength; 02361 02362 /* Get the correct size of the Unicode Base directory */ 02363 Status = RtlUnicodeToMultiByteSize(&AnsiLength, 02364 BaseWindowsDirectory.Buffer, 02365 BaseWindowsDirectory.MaximumLength); 02366 if (!NT_SUCCESS(Status)) return 0; 02367 02368 if (uSize < AnsiLength) return AnsiLength; 02369 02370 RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize); 02371 02372 Status = BasepUnicodeStringTo8BitString(&AnsiString, 02373 &BaseWindowsDirectory, 02374 FALSE); 02375 if (!NT_SUCCESS(Status)) return 0; 02376 02377 return AnsiString.Length; 02378 } 02379 02380 /* 02381 * @implemented 02382 */ 02383 UINT 02384 WINAPI 02385 GetSystemWindowsDirectoryW(IN LPWSTR lpBuffer, 02386 IN UINT uSize) 02387 { 02388 ULONG ReturnLength; 02389 02390 ReturnLength = BaseWindowsDirectory.MaximumLength; 02391 if ((uSize * sizeof(WCHAR)) >= ReturnLength) 02392 { 02393 RtlCopyMemory(lpBuffer, 02394 BaseWindowsDirectory.Buffer, 02395 BaseWindowsDirectory.Length); 02396 lpBuffer[BaseWindowsDirectory.Length / sizeof(WCHAR)] = ANSI_NULL; 02397 02398 ReturnLength = BaseWindowsDirectory.Length; 02399 } 02400 02401 return ReturnLength / sizeof(WCHAR); 02402 } 02403 02404 /* 02405 * @unimplemented 02406 */ 02407 UINT 02408 WINAPI 02409 GetSystemWow64DirectoryW(IN LPWSTR lpBuffer, 02410 IN UINT uSize) 02411 { 02412 #ifdef _WIN64 02413 UNIMPLEMENTED; 02414 return 0; 02415 #else 02416 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 02417 return 0; 02418 #endif 02419 } 02420 02421 /* 02422 * @unimplemented 02423 */ 02424 UINT 02425 WINAPI 02426 GetSystemWow64DirectoryA(IN LPSTR lpBuffer, 02427 IN UINT uSize) 02428 { 02429 #ifdef _WIN64 02430 UNIMPLEMENTED; 02431 return 0; 02432 #else 02433 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 02434 return 0; 02435 #endif 02436 } 02437 02438 /* EOF */ Generated on Sun May 27 2012 04:18:14 for ReactOS by
1.7.6.1
|