ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

path.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.