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  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS system libraries
00004  * FILE:            lib/rtl/path.c
00005  * PURPOSE:         Path and current directory functions
00006  * PROGRAMMERS:     Wine team
00007  *                  Thomas Weidenmueller
00008  *                  Gunnar Dalsnes
00009  *                  Alex Ionescu (alex.ionescu@reactos.org)
00010  *                  Pierre Schweitzer (pierre@reactos.org)
00011  */
00012 
00013 /* INCLUDES *****************************************************************/
00014 
00015 #include <rtl.h>
00016 
00017 #define NDEBUG
00018 #include <debug.h>
00019 
00020 /* DEFINITONS and MACROS ******************************************************/
00021 
00022 #define MAX_PFX_SIZE       16
00023 
00024 #define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/'))
00025 
00026 #define RTL_CURDIR_IS_REMOVABLE 0x1
00027 #define RTL_CURDIR_DROP_OLD_HANDLE 0x2
00028 #define RTL_CURDIR_ALL_FLAGS (RTL_CURDIR_DROP_OLD_HANDLE | RTL_CURDIR_IS_REMOVABLE) // 0x3
00029 C_ASSERT(RTL_CURDIR_ALL_FLAGS == OBJ_HANDLE_TAGBITS);
00030 
00031 
00032 /* GLOBALS ********************************************************************/
00033 
00034 static const WCHAR DeviceRootW[] = L"\\\\.\\";
00035 const UNICODE_STRING DeviceRootString = RTL_CONSTANT_STRING(L"\\\\.\\");
00036 
00037 const UNICODE_STRING RtlpDosDevicesUncPrefix = RTL_CONSTANT_STRING(L"\\??\\UNC\\");
00038 const UNICODE_STRING RtlpWin32NtRootSlash =   RTL_CONSTANT_STRING(L"\\\\?\\");
00039 const UNICODE_STRING RtlpDosSlashCONDevice =  RTL_CONSTANT_STRING(L"\\\\.\\CON");
00040 const UNICODE_STRING RtlpDosDevicesPrefix  =  RTL_CONSTANT_STRING(L"\\??\\");
00041 
00042 const UNICODE_STRING RtlpDosLPTDevice = RTL_CONSTANT_STRING(L"LPT");
00043 const UNICODE_STRING RtlpDosCOMDevice = RTL_CONSTANT_STRING(L"COM");
00044 const UNICODE_STRING RtlpDosPRNDevice = RTL_CONSTANT_STRING(L"PRN");
00045 const UNICODE_STRING RtlpDosAUXDevice = RTL_CONSTANT_STRING(L"AUX");
00046 const UNICODE_STRING RtlpDosCONDevice = RTL_CONSTANT_STRING(L"CON");
00047 const UNICODE_STRING RtlpDosNULDevice = RTL_CONSTANT_STRING(L"NUL");
00048 
00049 PRTLP_CURDIR_REF RtlpCurDirRef;
00050 
00051 /* PRIVATE FUNCTIONS **********************************************************/
00052 
00053 RTL_PATH_TYPE
00054 NTAPI
00055 RtlDetermineDosPathNameType_Ustr(IN PCUNICODE_STRING PathString)
00056 {
00057     PWCHAR Path;
00058     ULONG Chars;
00059 
00060     Path = PathString->Buffer;
00061     Chars = PathString->Length / sizeof(WCHAR);
00062 
00063     /* Return if there are no characters */
00064     if (!Chars) return RtlPathTypeRelative;
00065 
00066     /*
00067      * The algorithm is similar to RtlDetermineDosPathNameType_U but here we
00068      * actually check for the path length before touching the characters
00069      */
00070     if (IS_PATH_SEPARATOR(Path[0]))
00071     {
00072         if ((Chars < 2) || !(IS_PATH_SEPARATOR(Path[1]))) return RtlPathTypeRooted;                /* \x             */
00073         if ((Chars < 3) || ((Path[2] != L'.') && (Path[2] != L'?'))) return RtlPathTypeUncAbsolute;/* \\x            */
00074         if ((Chars >= 4) && (IS_PATH_SEPARATOR(Path[3]))) return RtlPathTypeLocalDevice;           /* \\.\x or \\?\x */
00075         if (Chars != 3) return RtlPathTypeUncAbsolute;                                             /* \\.x or \\?x   */
00076         return RtlPathTypeRootLocalDevice;                                                         /* \\. or \\?     */
00077     }
00078     else
00079     {
00080         if ((Chars < 2) || (Path[1] != L':')) return RtlPathTypeRelative;                          /* x              */
00081         if ((Chars < 3) || !(IS_PATH_SEPARATOR(Path[2]))) return RtlPathTypeDriveRelative;         /* x:             */
00082         return RtlPathTypeDriveAbsolute;                                                           /* x:\            */
00083     }
00084 }
00085 
00086 ULONG
00087 NTAPI
00088 RtlIsDosDeviceName_Ustr(IN PCUNICODE_STRING PathString)
00089 {
00090     UNICODE_STRING PathCopy;
00091     PWCHAR Start, End;
00092     USHORT PathChars, ColonCount = 0;
00093     USHORT ReturnOffset = 0, ReturnLength, OriginalLength;
00094     WCHAR c;
00095 
00096     /* Validate the input */
00097     if (!PathString) return 0;
00098 
00099     /* Check what type of path this is */
00100     switch (RtlDetermineDosPathNameType_Ustr(PathString))
00101     {
00102         /* Fail for UNC or unknown paths */
00103         case RtlPathTypeUnknown:
00104         case RtlPathTypeUncAbsolute:
00105             return 0;
00106 
00107         /* Make special check for the CON device */
00108         case RtlPathTypeLocalDevice:
00109             if (RtlEqualUnicodeString(PathString, &RtlpDosSlashCONDevice, TRUE))
00110             {
00111                 /* This should return 0x80006 */
00112                 return MAKELONG(RtlpDosCONDevice.Length, DeviceRootString.Length);
00113             }
00114             return 0;
00115 
00116         default:
00117             break;
00118     }
00119 
00120     /* Make a copy of the string */
00121     PathCopy = *PathString;
00122     OriginalLength = PathString->Length;
00123 
00124     /* Return if there's no characters */
00125     PathChars = PathCopy.Length / sizeof(WCHAR);
00126     if (!PathChars) return 0;
00127 
00128     /* Check for drive path and truncate */
00129     if (PathCopy.Buffer[PathChars - 1] == L':')
00130     {
00131         /* Fixup the lengths */
00132         PathCopy.Length -= sizeof(WCHAR);
00133         if (!--PathChars) return 0;
00134 
00135         /* Remember this for later */
00136         ColonCount = 1;
00137     }
00138 
00139     /* Check for extension or space, and truncate */
00140     do
00141     {
00142         /* Stop if we hit something else than a space or period */
00143         c = PathCopy.Buffer[PathChars - 1];
00144         if ((c != '.') && (c != ' ')) break;
00145 
00146         /* Fixup the lengths */
00147         PathCopy.Length -= sizeof(WCHAR);
00148 
00149         /* Remember this for later */
00150         ColonCount++;
00151     } while (--PathChars);
00152 
00153     /* Anything still left? */
00154     if (PathChars)
00155     {
00156         /* Loop from the end */
00157         for (End = &PathCopy.Buffer[PathChars - 1];
00158              End >= PathCopy.Buffer;
00159              --End)
00160         {
00161             /* Check if the character is a path or drive separator */
00162             c = *End;
00163             if ((c == '\\') || (c == '/') || ((c == ':') && (End == PathCopy.Buffer + 1)))
00164             {
00165                 /* Get the next lower case character */
00166                 End++;
00167                 c = *End | ' '; // ' ' == ('z' - 'Z')
00168 
00169                 /* Check if it's a DOS device (LPT, COM, PRN, AUX, or NUL) */
00170                 if ((End < &PathCopy.Buffer[OriginalLength / sizeof(WCHAR)]) &&
00171                     ((c == 'l') || (c == 'c') || (c == 'p') || (c == 'a') || (c == 'n')))
00172                 {
00173                     /* Calculate the offset */
00174                     ReturnOffset = (USHORT)((PCHAR)End - (PCHAR)PathCopy.Buffer);
00175 
00176                     /* Build the final string */
00177                     PathCopy.Length = OriginalLength - ReturnOffset - (ColonCount * sizeof(WCHAR));
00178                     PathCopy.Buffer = End;
00179 
00180                     /* Save new amount of chars in the path */
00181                     PathChars = PathCopy.Length / sizeof(WCHAR);
00182 
00183                     break;
00184                 }
00185                 else
00186                 {
00187                     return 0;
00188                 }
00189             }
00190         }
00191 
00192         /* Get the next lower case character and check if it's a DOS device */
00193         c = *PathCopy.Buffer | ' '; // ' ' == ('z' - 'Z')
00194         if ((c != 'l') && (c != 'c') && (c != 'p') && (c != 'a') && (c != 'n'))
00195         {
00196             /* Not LPT, COM, PRN, AUX, or NUL */
00197             return 0;
00198         }
00199     }
00200 
00201     /* Now skip past any extra extension or drive letter characters */
00202     Start = PathCopy.Buffer;
00203     End = &Start[PathChars];
00204     while (Start < End)
00205     {
00206         c = *Start;
00207         if ((c == '.') || (c == ':')) break;
00208         Start++;
00209     }
00210 
00211     /* And then go backwards to get rid of spaces */
00212     while ((Start > PathCopy.Buffer) && (Start[-1] == ' ')) --Start;
00213 
00214     /* Finally see how many characters are left, and that's our size */
00215     PathChars = (USHORT)(Start - PathCopy.Buffer);
00216     PathCopy.Length = PathChars * sizeof(WCHAR);
00217 
00218     /* Check if this is a COM or LPT port, which has a digit after it */
00219     if ((PathChars == 4) &&
00220         (iswdigit(PathCopy.Buffer[3]) && (PathCopy.Buffer[3] != '0')))
00221     {
00222         /* Don't compare the number part, just check for LPT or COM */
00223         PathCopy.Length -= sizeof(WCHAR);
00224         if ((RtlEqualUnicodeString(&PathCopy, &RtlpDosLPTDevice, TRUE)) ||
00225             (RtlEqualUnicodeString(&PathCopy, &RtlpDosCOMDevice, TRUE)))
00226         {
00227             /* Found it */
00228             ReturnLength = sizeof(L"COM1") - sizeof(WCHAR);
00229             return MAKELONG(ReturnLength, ReturnOffset);
00230         }
00231     }
00232     else if ((PathChars == 3) &&
00233              ((RtlEqualUnicodeString(&PathCopy, &RtlpDosPRNDevice, TRUE)) ||
00234               (RtlEqualUnicodeString(&PathCopy, &RtlpDosAUXDevice, TRUE)) ||
00235               (RtlEqualUnicodeString(&PathCopy, &RtlpDosNULDevice, TRUE)) ||
00236               (RtlEqualUnicodeString(&PathCopy, &RtlpDosCONDevice, TRUE))))
00237     {
00238         /* Otherwise this was something like AUX, NUL, PRN, or CON */
00239         ReturnLength = sizeof(L"AUX") - sizeof(WCHAR);
00240         return MAKELONG(ReturnLength, ReturnOffset);
00241     }
00242 
00243     /* Otherwise, this is not a valid DOS device */
00244     return 0;
00245 }
00246 
00247 NTSTATUS
00248 NTAPI
00249 RtlpCheckDeviceName(IN PUNICODE_STRING FileName,
00250                     IN ULONG Length,
00251                     OUT PBOOLEAN NameInvalid)
00252 {
00253     PWCHAR Buffer;
00254     NTSTATUS Status;
00255 
00256     /* Allocate a large enough buffer */
00257     Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, FileName->Length);
00258     if (Buffer)
00259     {
00260         /* Assume failure */
00261         *NameInvalid = TRUE;
00262 
00263         /* Copy the filename */
00264         RtlCopyMemory(Buffer, FileName->Buffer, FileName->Length);
00265 
00266         /* And add a dot at the end */
00267         Buffer[Length / sizeof(WCHAR)] = L'.';
00268         Buffer[(Length / sizeof(WCHAR)) + 1] = UNICODE_NULL;
00269 
00270         /* Check if the file exists or not */
00271         *NameInvalid = RtlDoesFileExists_U(Buffer) ? FALSE: TRUE;
00272 
00273         /* Get rid of the buffer now */
00274         Status = RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
00275     }
00276     else
00277     {
00278         /* Assume the name is ok, but fail the call */
00279         *NameInvalid = FALSE;
00280         Status = STATUS_NO_MEMORY;
00281     }
00282 
00283     /* Return the status */
00284     return Status;
00285 }
00286 
00287 ULONG
00288 NTAPI
00289 RtlGetFullPathName_Ustr(IN PUNICODE_STRING FileName,
00290                         IN ULONG Size,
00291                         IN PWSTR Buffer,
00292                         OUT PCWSTR *ShortName,
00293                         OUT PBOOLEAN InvalidName,
00294                         OUT RTL_PATH_TYPE *PathType)
00295 {
00296     PWCHAR FileNameBuffer;
00297     ULONG FileNameLength, FileNameChars, DosLength, DosLengthOffset, FullLength;
00298     WCHAR c;
00299     NTSTATUS Status;
00300 
00301     /* For now, assume the name is valid */
00302     DPRINT("Filename: %wZ\n", FileName);
00303     DPRINT("Size and buffer: %lx %S\n", Size, Buffer);
00304     if (InvalidName) *InvalidName = FALSE;
00305 
00306     /* Handle initial path type and failure case */
00307     *PathType = RtlPathTypeUnknown;
00308     if (!(FileName->Length) || (FileName->Buffer[0] == UNICODE_NULL)) return 0;
00309 
00310     /* Break filename into component parts */
00311     FileNameBuffer = FileName->Buffer;
00312     FileNameLength = FileName->Length;
00313     FileNameChars = FileNameLength / sizeof(WCHAR);
00314 
00315     /* Kill trailing spaces */
00316     c = FileNameBuffer[FileNameChars - 1];
00317     while ((FileNameLength) && (c == L' '))
00318     {
00319         /* Keep going, ignoring the spaces */
00320         FileNameLength -= sizeof(WCHAR);
00321         if (FileNameLength) c = FileNameBuffer[FileNameLength / sizeof(WCHAR) - 1];
00322     }
00323 
00324     /* Check if anything is left */
00325     if (!FileNameLength) return 0;
00326 
00327     /* Check if this is a DOS name */
00328     DosLength = RtlIsDosDeviceName_Ustr(FileName);
00329     DPRINT("DOS length for filename: %lx %wZ\n", DosLength, FileName);
00330     if (DosLength)
00331     {
00332         /* Zero out the short name */
00333         if (ShortName) *ShortName = NULL;
00334 
00335         /* See comment for RtlIsDosDeviceName_Ustr if this is confusing... */
00336         DosLengthOffset = DosLength >> 16;
00337         DosLength = DosLength & 0xFFFF;
00338 
00339         /* Do we have a DOS length, and does the caller want validity? */
00340         if ((InvalidName) && (DosLengthOffset))
00341         {
00342             /* Do the check */
00343             Status = RtlpCheckDeviceName(FileName, DosLengthOffset, InvalidName);
00344 
00345             /* If the check failed, or the name is invalid, fail here */
00346             if (!NT_SUCCESS(Status)) return 0;
00347             if (*InvalidName) return 0;
00348         }
00349 
00350         /* Add the size of the device root and check if it fits in the size */
00351         FullLength = DosLength + DeviceRootString.Length;
00352         if (FullLength < Size)
00353         {
00354             /* Add the device string */
00355             RtlMoveMemory(Buffer, DeviceRootString.Buffer, DeviceRootString.Length);
00356 
00357             /* Now add the DOS device name */
00358             RtlMoveMemory((PCHAR)Buffer + DeviceRootString.Length,
00359                           (PCHAR)FileNameBuffer + DosLengthOffset,
00360                           DosLength);
00361 
00362             /* Null terminate */
00363             *(PWCHAR)((ULONG_PTR)Buffer + FullLength) = UNICODE_NULL;
00364             return FullLength;
00365         }
00366 
00367         /* Otherwise, there's no space, so return the buffer size needed */
00368         if ((FullLength + sizeof(UNICODE_NULL)) > UNICODE_STRING_MAX_BYTES) return 0;
00369         return FullLength + sizeof(UNICODE_NULL);
00370     }
00371 
00372     /* This should work well enough for our current needs */
00373     *PathType = RtlDetermineDosPathNameType_U(FileNameBuffer);
00374     DPRINT("Path type: %lx\n", *PathType);
00375 
00376     /* This is disgusting... but avoids re-writing everything */
00377     DPRINT("Calling old API with %s and %lx and %S\n", FileNameBuffer, Size, Buffer);
00378     return RtlGetFullPathName_U(FileNameBuffer, Size, Buffer, (PWSTR*)ShortName);
00379 }
00380 
00381 NTSTATUS
00382 NTAPI
00383 RtlpWin32NTNameToNtPathName_U(IN PUNICODE_STRING DosPath,
00384                               OUT PUNICODE_STRING NtPath,
00385                               OUT PCWSTR *PartName,
00386                               OUT PRTL_RELATIVE_NAME_U RelativeName)
00387 {
00388     ULONG DosLength;
00389     PWSTR NewBuffer, p;
00390 
00391     /* Validate the input */
00392     if (!DosPath) return STATUS_OBJECT_NAME_INVALID;
00393 
00394     /* Validate the DOS length */
00395     DosLength = DosPath->Length;
00396     if (DosLength >= UNICODE_STRING_MAX_BYTES) return STATUS_NAME_TOO_LONG;
00397 
00398     /* Make space for the new path */
00399     NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
00400                                 0,
00401                                 DosLength + sizeof(UNICODE_NULL));
00402     if (!NewBuffer) return STATUS_NO_MEMORY;
00403 
00404     /* Copy the prefix, and then the rest of the DOS path, and NULL-terminate */
00405     RtlCopyMemory(NewBuffer, RtlpDosDevicesPrefix.Buffer, RtlpDosDevicesPrefix.Length);
00406     RtlCopyMemory((PCHAR)NewBuffer + RtlpDosDevicesPrefix.Length,
00407                   DosPath->Buffer + RtlpDosDevicesPrefix.Length / sizeof(WCHAR),
00408                   DosPath->Length - RtlpDosDevicesPrefix.Length);
00409     NewBuffer[DosLength / sizeof(WCHAR)] = UNICODE_NULL;
00410 
00411     /* Did the caller send a relative name? */
00412     if (RelativeName)
00413     {
00414         /* Zero initialize it */
00415         RtlInitEmptyUnicodeString(&RelativeName->RelativeName, NULL, 0);
00416         RelativeName->ContainingDirectory = NULL;
00417         RelativeName->CurDirRef = 0;
00418     }
00419 
00420     /* Did the caller request a partial name? */
00421     if (PartName)
00422     {
00423         /* Loop from the back until we find a path separator */
00424         p = &NewBuffer[(DosLength - 1) / sizeof (WCHAR)];
00425         while (p > NewBuffer) if (*p-- == '\\') break;
00426 
00427         /* Was one found? */
00428         if (p > NewBuffer)
00429         {
00430             /* Move past it -- anything left? */
00431             p++;
00432             if (!*p)
00433             {
00434                 /* The path ends with a path separator, no part name */
00435                 *PartName = NULL;
00436             }
00437             else
00438             {
00439                 /* What follows the path separator is the part name */
00440                 *PartName = p;
00441             }
00442         }
00443     }
00444 
00445     /* Build the final NT path string */
00446     NtPath->Length = (USHORT)DosLength;
00447     NtPath->Buffer = NewBuffer;
00448     NtPath->MaximumLength = (USHORT)DosLength + sizeof(UNICODE_NULL);
00449     return STATUS_SUCCESS;
00450 }
00451 
00452 NTSTATUS
00453 NTAPI
00454 RtlpDosPathNameToRelativeNtPathName_Ustr(IN BOOLEAN HaveRelative,
00455                                          IN PCUNICODE_STRING DosName,
00456                                          OUT PUNICODE_STRING NtName,
00457                                          OUT PCWSTR *PartName,
00458                                          OUT PRTL_RELATIVE_NAME_U RelativeName)
00459 {
00460     WCHAR BigBuffer[MAX_PATH + 1];
00461     PWCHAR PrefixBuffer, NewBuffer, Buffer;
00462     ULONG MaxLength, PathLength, PrefixLength, PrefixCut, LengthChars, Length;
00463     UNICODE_STRING CapturedDosName, PartNameString, FullPath;
00464     BOOLEAN QuickPath;
00465     RTL_PATH_TYPE InputPathType, BufferPathType;
00466     NTSTATUS Status;
00467     BOOLEAN NameInvalid;
00468     PCURDIR CurrentDirectory;
00469 
00470     /* Assume MAX_PATH for now */
00471     DPRINT("Relative: %lx DosName: %wZ NtName: %wZ, PartName: %p, RelativeName: %p\n",
00472             HaveRelative, DosName, NtName, PartName, RelativeName);
00473     MaxLength = sizeof(BigBuffer);
00474 
00475     /* Validate the input */
00476     if (!DosName) return STATUS_OBJECT_NAME_INVALID;
00477 
00478     /* Capture input string */
00479     CapturedDosName = *DosName;
00480 
00481     /* Check for \\?\\ form */
00482     if ((CapturedDosName.Length <= RtlpWin32NtRootSlash.Length) ||
00483         (CapturedDosName.Buffer[0] != RtlpWin32NtRootSlash.Buffer[0]) ||
00484         (CapturedDosName.Buffer[1] != RtlpWin32NtRootSlash.Buffer[1]) ||
00485         (CapturedDosName.Buffer[2] != RtlpWin32NtRootSlash.Buffer[2]) ||
00486         (CapturedDosName.Buffer[3] != RtlpWin32NtRootSlash.Buffer[3]))
00487     {
00488         /* Quick path won't be used */
00489         QuickPath = FALSE;
00490 
00491         /* Use the static buffer */
00492         Buffer = BigBuffer;
00493         MaxLength += RtlpDosDevicesUncPrefix.Length;
00494 
00495         /* Allocate a buffer to hold the path */
00496         NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, MaxLength);
00497         DPRINT("Length: %lx\n", MaxLength);
00498         if (!NewBuffer) return STATUS_NO_MEMORY;
00499     }
00500     else
00501     {
00502         /* Use the optimized path after acquiring the lock */
00503         QuickPath = TRUE;
00504         NewBuffer = NULL;
00505     }
00506 
00507     /* Lock the PEB and check if the quick path can be used */
00508     RtlAcquirePebLock();
00509     if (QuickPath)
00510     {
00511         /* Some simple fixups will get us the correct path */
00512         DPRINT("Quick path\n");
00513         Status = RtlpWin32NTNameToNtPathName_U(&CapturedDosName,
00514                                                NtName,
00515                                                PartName,
00516                                                RelativeName);
00517 
00518         /* Release the lock, we're done here */
00519         RtlReleasePebLock();
00520         return Status;
00521     }
00522 
00523     /* Call the main function to get the full path name and length */
00524     PathLength = RtlGetFullPathName_Ustr(&CapturedDosName,
00525                                          MAX_PATH * sizeof(WCHAR),
00526                                          Buffer,
00527                                          PartName,
00528                                          &NameInvalid,
00529                                          &InputPathType);
00530     if ((NameInvalid) || !(PathLength) || (PathLength > (MAX_PATH * sizeof(WCHAR))))
00531     {
00532         /* Invalid name, fail */
00533         DPRINT("Invalid name: %lx Path Length: %lx\n", NameInvalid, PathLength);
00534         RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
00535         RtlReleasePebLock();
00536         return STATUS_OBJECT_NAME_INVALID;
00537     }
00538 
00539     /* Start by assuming the path starts with \??\ (DOS Devices Path) */
00540     PrefixLength = RtlpDosDevicesPrefix.Length;
00541     PrefixBuffer = RtlpDosDevicesPrefix.Buffer;
00542     PrefixCut = 0;
00543 
00544     /* Check where it really is */
00545     BufferPathType = RtlDetermineDosPathNameType_U(Buffer);
00546     DPRINT("Buffer: %S Type: %lx\n", Buffer, BufferPathType);
00547     switch (BufferPathType)
00548     {
00549         /* It's actually a UNC path in \??\UNC\ */
00550         case RtlPathTypeUncAbsolute:
00551             PrefixLength = RtlpDosDevicesUncPrefix.Length;
00552             PrefixBuffer = RtlpDosDevicesUncPrefix.Buffer;
00553             PrefixCut = 2;
00554             break;
00555 
00556         case RtlPathTypeLocalDevice:
00557             /* We made a good guess, go with it but skip the \??\ */
00558             PrefixCut = 4;
00559             break;
00560 
00561         case RtlPathTypeDriveAbsolute:
00562         case RtlPathTypeDriveRelative:
00563         case RtlPathTypeRooted:
00564         case RtlPathTypeRelative:
00565             /* Our guess was good, roll with it */
00566             break;
00567 
00568         /* Nothing else is expected */
00569         default:
00570             ASSERT(FALSE);
00571 
00572     }
00573 
00574     /* Now copy the prefix and the buffer */
00575     RtlCopyMemory(NewBuffer, PrefixBuffer, PrefixLength);
00576     RtlCopyMemory((PCHAR)NewBuffer + PrefixLength,
00577                   &Buffer[PrefixCut],
00578                   PathLength - (PrefixCut * sizeof(WCHAR)));
00579 
00580     /* Compute the length */
00581     Length = PathLength - PrefixCut * sizeof(WCHAR) + PrefixLength;
00582     LengthChars = Length / sizeof(WCHAR);
00583 
00584     /* Setup the actual NT path string and terminate it */
00585     NtName->Buffer = NewBuffer;
00586     NtName->Length = (USHORT)Length;
00587     NtName->MaximumLength = (USHORT)MaxLength;
00588     NewBuffer[LengthChars] = UNICODE_NULL;
00589     DPRINT("new buffer: %S\n", NewBuffer);
00590     DPRINT("NT Name: %wZ\n", NtName);
00591 
00592     /* Check if a partial name was requested */
00593     if ((PartName) && (*PartName))
00594     {
00595         /* Convert to Unicode */
00596         Status = RtlInitUnicodeStringEx(&PartNameString, *PartName);
00597         if (NT_SUCCESS(Status))
00598         {
00599             /* Set the partial name */
00600             *PartName = &NewBuffer[LengthChars - (PartNameString.Length / sizeof(WCHAR))];
00601         }
00602         else
00603         {
00604             /* Fail */
00605             RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
00606             RtlReleasePebLock();
00607             return Status;
00608         }
00609     }
00610 
00611     /* Check if a relative name was asked for */
00612     if (RelativeName)
00613     {
00614         /* Setup the structure */
00615         RtlInitEmptyUnicodeString(&RelativeName->RelativeName, NULL, 0);
00616         RelativeName->ContainingDirectory = NULL;
00617         RelativeName->CurDirRef = NULL;
00618 
00619         /* Check if the input path itself was relative */
00620         if (InputPathType == RtlPathTypeRelative)
00621         {
00622             /* Get current directory */
00623             CurrentDirectory = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
00624             if (CurrentDirectory->Handle)
00625             {
00626                 Status = RtlInitUnicodeStringEx(&FullPath, Buffer);
00627                 if (!NT_SUCCESS(Status))
00628                 {
00629                     RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
00630                     RtlReleasePebLock();
00631                     return Status;
00632                 }
00633 
00634                 /* If current directory is bigger than full path, there's no way */
00635                 if (CurrentDirectory->DosPath.Length > FullPath.Length)
00636                 {
00637                     RtlReleasePebLock();
00638                     return Status;
00639                 }
00640 
00641                 /* File is in current directory */
00642                 if (RtlEqualUnicodeString(&FullPath, &CurrentDirectory->DosPath, TRUE))
00643                 {
00644                     /* Make relative name string */
00645                     RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)NewBuffer + FullPath.Length - PrefixCut);
00646                     RelativeName->RelativeName.Length = (USHORT)(PathLength - FullPath.Length);
00647                     /* If relative name starts with \, skip it */
00648                     if (RelativeName->RelativeName.Buffer[0] == L'\\')
00649                     {
00650                         RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)RelativeName->RelativeName.Buffer + sizeof(WCHAR));
00651                         RelativeName->RelativeName.Length -= sizeof(WCHAR);
00652                     }
00653                     RelativeName->RelativeName.MaximumLength = RelativeName->RelativeName.Length;
00654                     DPRINT("RelativeName: %wZ\n", &(RelativeName->RelativeName));
00655 
00656                     if (!HaveRelative)
00657                     {
00658                         RelativeName->ContainingDirectory = CurrentDirectory->Handle;
00659                         return Status;
00660                     }
00661 
00662                     /* Give back current directory data & reference counter */
00663                     RelativeName->CurDirRef = RtlpCurDirRef;
00664                     if (RelativeName->CurDirRef)
00665                     {
00666                         InterlockedIncrement(&RtlpCurDirRef->RefCount);
00667                     }
00668 
00669                     RelativeName->ContainingDirectory = CurrentDirectory->Handle;
00670                 }
00671             }
00672         }
00673     }
00674 
00675     /* Done */
00676     RtlReleasePebLock();
00677     return STATUS_SUCCESS;
00678 }
00679 
00680 NTSTATUS
00681 NTAPI
00682 RtlpDosPathNameToRelativeNtPathName_U(IN BOOLEAN HaveRelative,
00683                                       IN PCWSTR DosName,
00684                                       OUT PUNICODE_STRING NtName,
00685                                       OUT PCWSTR *PartName,
00686                                       OUT PRTL_RELATIVE_NAME_U RelativeName)
00687 {
00688     NTSTATUS Status;
00689     UNICODE_STRING NameString;
00690 
00691     /* Create the unicode name */
00692     Status = RtlInitUnicodeStringEx(&NameString, DosName);
00693     if (NT_SUCCESS(Status))
00694     {
00695         /* Call the unicode function */
00696         Status = RtlpDosPathNameToRelativeNtPathName_Ustr(HaveRelative,
00697                                                           &NameString,
00698                                                           NtName,
00699                                                           PartName,
00700                                                           RelativeName);
00701     }
00702 
00703     /* Return status */
00704     return Status;
00705 }
00706 
00707 BOOLEAN
00708 NTAPI
00709 RtlDosPathNameToRelativeNtPathName_Ustr(IN PCUNICODE_STRING DosName,
00710                                         OUT PUNICODE_STRING NtName,
00711                                         OUT PCWSTR *PartName,
00712                                         OUT PRTL_RELATIVE_NAME_U RelativeName)
00713 {
00714     /* Call the internal function */
00715     ASSERT(RelativeName);
00716     return NT_SUCCESS(RtlpDosPathNameToRelativeNtPathName_Ustr(TRUE,
00717                                                                DosName,
00718                                                                NtName,
00719                                                                PartName,
00720                                                                RelativeName));
00721 }
00722 
00723 BOOLEAN
00724 NTAPI
00725 RtlDoesFileExists_UstrEx(IN PCUNICODE_STRING FileName,
00726                          IN BOOLEAN SucceedIfBusy)
00727 {
00728     BOOLEAN Result;
00729     RTL_RELATIVE_NAME_U RelativeName;
00730     UNICODE_STRING NtPathName;
00731     PVOID Buffer;
00732     OBJECT_ATTRIBUTES ObjectAttributes;
00733     NTSTATUS Status;
00734     FILE_BASIC_INFORMATION BasicInformation;
00735 
00736     /* Get the NT Path */
00737     Result = RtlDosPathNameToRelativeNtPathName_Ustr(FileName,
00738                                                      &NtPathName,
00739                                                      NULL,
00740                                                      &RelativeName);
00741     if (!Result) return FALSE;
00742 
00743     /* Save the buffer */
00744     Buffer = NtPathName.Buffer;
00745 
00746     /* Check if we have a relative name */
00747     if (RelativeName.RelativeName.Length)
00748     {
00749         /* Use it */
00750         NtPathName = RelativeName.RelativeName;
00751     }
00752     else
00753     {
00754         /* Otherwise ignore it */
00755         RelativeName.ContainingDirectory = NULL;
00756     }
00757 
00758     /* Initialize the object attributes */
00759     InitializeObjectAttributes(&ObjectAttributes,
00760                                &NtPathName,
00761                                OBJ_CASE_INSENSITIVE,
00762                                RelativeName.ContainingDirectory,
00763                                NULL);
00764 
00765     /* Query the attributes and free the buffer now */
00766     Status = ZwQueryAttributesFile(&ObjectAttributes, &BasicInformation);
00767     RtlReleaseRelativeName(&RelativeName);
00768     RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
00769 
00770     /* Check if we failed */
00771     if (!NT_SUCCESS(Status))
00772     {
00773         /* Check if we failed because the file is in use */
00774         if ((Status == STATUS_SHARING_VIOLATION) ||
00775             (Status == STATUS_ACCESS_DENIED))
00776         {
00777             /* Check if the caller wants this to be considered OK */
00778             Result = SucceedIfBusy ? TRUE : FALSE;
00779         }
00780         else
00781         {
00782             /* A failure because the file didn't exist */
00783             Result = FALSE;
00784         }
00785     }
00786     else
00787     {
00788         /* The file exists */
00789         Result = TRUE;
00790     }
00791 
00792     /* Return the result */
00793     return Result;
00794 }
00795 
00796 BOOLEAN
00797 NTAPI
00798 RtlDoesFileExists_UStr(IN PUNICODE_STRING FileName)
00799 {
00800     /* Call the updated API */
00801     return RtlDoesFileExists_UstrEx(FileName, TRUE);
00802 }
00803 
00804 BOOLEAN
00805 NTAPI
00806 RtlDoesFileExists_UEx(IN PCWSTR FileName,
00807                       IN BOOLEAN SucceedIfBusy)
00808 {
00809     UNICODE_STRING NameString;
00810 
00811     /* Create the unicode name*/
00812     if (NT_SUCCESS(RtlInitUnicodeStringEx(&NameString, FileName)))
00813     {
00814         /* Call the unicode function */
00815         return RtlDoesFileExists_UstrEx(&NameString, SucceedIfBusy);
00816     }
00817 
00818     /* Fail */
00819     return FALSE;
00820 }
00821 
00822 /* PUBLIC FUNCTIONS ***********************************************************/
00823 
00824 /*
00825  * @implemented
00826  */
00827 VOID
00828 NTAPI
00829 RtlReleaseRelativeName(IN PRTL_RELATIVE_NAME_U RelativeName)
00830 {
00831     /* Check if a directory reference was grabbed */
00832     if (RelativeName->CurDirRef)
00833     {
00834         /* Decrease reference count */
00835         if (!InterlockedDecrement(&RelativeName->CurDirRef->RefCount))
00836         {
00837             /* If no one uses it any longer, close handle & free */
00838             NtClose(RelativeName->CurDirRef->Handle);
00839             RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeName->CurDirRef);
00840         }
00841         RelativeName->CurDirRef = NULL;
00842     }
00843 }
00844 
00845 /*
00846  * @implemented
00847  */
00848 ULONG
00849 NTAPI
00850 RtlGetLongestNtPathLength(VOID)
00851 {
00852     /*
00853      * The longest NT path is a DOS path that actually sits on a UNC path (ie:
00854      * a mapped network drive), which is accessed through the DOS Global?? path.
00855      * This is, and has always been equal to, 269 characters, except in Wine
00856      * which claims this is 277. Go figure.
00857      */
00858     return MAX_PATH + RtlpDosDevicesUncPrefix.Length / sizeof(WCHAR) + sizeof(ANSI_NULL);
00859 }
00860 
00861 /*
00862  * @implemented
00863  */
00864 ULONG
00865 NTAPI
00866 RtlDetermineDosPathNameType_U(IN PCWSTR Path)
00867 {
00868     DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
00869 
00870     /* Unlike the newer RtlDetermineDosPathNameType_U we assume 4 characters */
00871     if (IS_PATH_SEPARATOR(Path[0]))
00872     {
00873         if (!IS_PATH_SEPARATOR(Path[1])) return RtlPathTypeRooted;                /* \x             */
00874         if ((Path[2] != L'.') && (Path[2] != L'?')) return RtlPathTypeUncAbsolute;/* \\x            */
00875         if (IS_PATH_SEPARATOR(Path[3])) return RtlPathTypeLocalDevice;            /* \\.\x or \\?\x */
00876         if (Path[3]) return RtlPathTypeUncAbsolute;                               /* \\.x or \\?x   */
00877         return RtlPathTypeRootLocalDevice;                                        /* \\. or \\?     */
00878     }
00879     else
00880     {
00881         if (!(Path[0]) || (Path[1] != L':')) return RtlPathTypeRelative;          /* x              */
00882         if (IS_PATH_SEPARATOR(Path[2])) return RtlPathTypeDriveAbsolute;          /* x:\            */
00883         return RtlPathTypeDriveRelative;                                          /* x:             */
00884     }
00885 }
00886 
00887 /*
00888  * @implemented
00889  */
00890 ULONG
00891 NTAPI
00892 RtlIsDosDeviceName_U(IN PCWSTR Path)
00893 {
00894     UNICODE_STRING PathString;
00895     NTSTATUS Status;
00896 
00897     /* Build the string */
00898     Status = RtlInitUnicodeStringEx(&PathString, Path);
00899     if (!NT_SUCCESS(Status)) return 0;
00900 
00901     /*
00902      * Returns 0 if name is not valid DOS device name, or DWORD with
00903      * offset in bytes to DOS device name from beginning of buffer in high word
00904      * and size in bytes of DOS device name in low word
00905      */
00906      return RtlIsDosDeviceName_Ustr(&PathString);
00907 }
00908 
00909 /*
00910  * @implemented
00911  */
00912 ULONG
00913 NTAPI
00914 RtlGetCurrentDirectory_U(IN ULONG MaximumLength,
00915                          IN PWSTR Buffer)
00916 {
00917     ULONG Length, Bytes;
00918     PCURDIR CurDir;
00919     PWSTR CurDirName;
00920     DPRINT("RtlGetCurrentDirectory %lu %p\n", MaximumLength, Buffer);
00921 
00922     /* Lock the PEB to get the current directory */
00923     RtlAcquirePebLock();
00924     CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory;
00925 
00926     /* Get the buffer and character length */
00927     CurDirName = CurDir->DosPath.Buffer;
00928     Length = CurDir->DosPath.Length / sizeof(WCHAR);
00929     ASSERT((CurDirName != NULL) && (Length > 0));
00930 
00931     /*
00932      * DosPath.Buffer should always have a trailing slash. There is an assert
00933      * below which checks for this.
00934      *
00935      * This function either returns x:\ for a root (keeping the original buffer)
00936      * or it returns x:\path\foo for a directory (replacing the trailing slash
00937      * with a NULL.
00938      */
00939     Bytes = Length * sizeof(WCHAR);
00940     if ((Length <= 1) || (CurDirName[Length - 2] == L':'))
00941     {
00942         /* Check if caller does not have enough space */
00943         if (MaximumLength <= Bytes)
00944         {
00945             /* Call has no space for it, fail, add the trailing slash */
00946             RtlReleasePebLock();
00947             return Bytes + sizeof(OBJ_NAME_PATH_SEPARATOR);
00948         }
00949     }
00950     else
00951     {
00952         /* Check if caller does not have enough space */
00953         if (MaximumLength < Bytes)
00954         {
00955             /* Call has no space for it, fail */
00956             RtlReleasePebLock();
00957             return Bytes;
00958         }
00959     }
00960 
00961     /* Copy the buffer since we seem to have space */
00962     RtlCopyMemory(Buffer, CurDirName, Bytes);
00963 
00964     /* The buffer should end with a path separator */
00965     ASSERT(Buffer[Length - 1] == OBJ_NAME_PATH_SEPARATOR);
00966 
00967     /* Again check for our two cases (drive root vs path) */
00968     if ((Length <= 1) || (Buffer[Length - 2] != L':'))
00969     {
00970         /* Replace the trailing slash with a null */
00971         Buffer[Length - 1] = UNICODE_NULL;
00972         --Length;
00973     }
00974     else
00975     {
00976         /* Append the null char since there's no trailing slash */
00977         Buffer[Length] = UNICODE_NULL;
00978     }
00979 
00980     /* Release PEB lock */
00981     RtlReleasePebLock();
00982     DPRINT("CurrentDirectory %S\n", Buffer);
00983     return Length * sizeof(WCHAR);
00984 }
00985 
00986 /*
00987  * @implemented
00988  */
00989 NTSTATUS
00990 NTAPI
00991 RtlSetCurrentDirectory_U(IN PUNICODE_STRING Path)
00992 {
00993     PCURDIR CurDir;
00994     NTSTATUS Status;
00995     RTL_PATH_TYPE PathType;
00996     IO_STATUS_BLOCK IoStatusBlock;
00997     UNICODE_STRING FullPath, NtName;
00998     PRTLP_CURDIR_REF OldCurDir = NULL;
00999     OBJECT_ATTRIBUTES ObjectAttributes;
01000     FILE_FS_DEVICE_INFORMATION FileFsDeviceInfo;
01001     ULONG SavedLength, CharLength, FullPathLength;
01002     HANDLE OldHandle = NULL, CurDirHandle = NULL, OldCurDirHandle = NULL;
01003 
01004     DPRINT("RtlSetCurrentDirectory_U %wZ\n", Path);
01005 
01006     /* Initialize for failure case */
01007     RtlInitEmptyUnicodeString(&NtName, NULL, 0);
01008 
01009     /* Can't set current directory on DOS device */
01010     if (RtlIsDosDeviceName_Ustr(Path))
01011     {
01012         return STATUS_NOT_A_DIRECTORY;
01013     }
01014 
01015     /* Get current directory */
01016     RtlAcquirePebLock();
01017     CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory;
01018 
01019     /* Check if we have to drop current handle */
01020     if (((ULONG_PTR)(CurDir->Handle) & RTL_CURDIR_ALL_FLAGS) == RTL_CURDIR_DROP_OLD_HANDLE)
01021     {
01022         OldHandle = CurDir->Handle;
01023         CurDir->Handle = NULL;
01024     }
01025 
01026     /* Allocate a buffer for full path (using max possible length */
01027     FullPath.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, CurDir->DosPath.MaximumLength);
01028     if (!FullPath.Buffer)
01029     {
01030         Status = STATUS_NO_MEMORY;
01031         goto Leave;
01032     }
01033 
01034     /* Init string */
01035     FullPath.Length = 0;
01036     FullPath.MaximumLength = CurDir->DosPath.MaximumLength;
01037 
01038     /* Get new directory full path */
01039     FullPathLength = RtlGetFullPathName_Ustr(Path, FullPath.MaximumLength, FullPath.Buffer, NULL, NULL, &PathType);
01040     if (!FullPathLength)
01041     {
01042         Status = STATUS_OBJECT_NAME_INVALID;
01043         goto Leave;
01044     }
01045 
01046     SavedLength = FullPath.MaximumLength;
01047     CharLength = FullPathLength / sizeof(WCHAR);
01048 
01049     if (FullPathLength > FullPath.MaximumLength)
01050     {
01051         Status = STATUS_NAME_TOO_LONG;
01052         goto Leave;
01053     }
01054 
01055     /* Translate it to NT name */
01056     if (!RtlDosPathNameToNtPathName_U(FullPath.Buffer, &NtName, NULL, NULL))
01057     {
01058         Status = STATUS_OBJECT_NAME_INVALID;
01059         goto Leave;
01060     }
01061 
01062    InitializeObjectAttributes(&ObjectAttributes, &NtName,
01063                               OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
01064                               NULL, NULL);
01065 
01066     /* If previous current directory was removable, then check it for dropping */
01067     if (((ULONG_PTR)(CurDir->Handle) & RTL_CURDIR_ALL_FLAGS) == RTL_CURDIR_ALL_FLAGS)
01068     {
01069         /* Get back normal handle */
01070         CurDirHandle = (HANDLE)((ULONG_PTR)(CurDir->Handle) & ~RTL_CURDIR_ALL_FLAGS);
01071         CurDir->Handle = NULL;
01072 
01073         /* Get device information */
01074         Status = NtQueryVolumeInformationFile(CurDirHandle,
01075                                               &IoStatusBlock,
01076                                               &FileFsDeviceInfo,
01077                                               sizeof(FileFsDeviceInfo),
01078                                               FileFsDeviceInformation);
01079         /* Retry without taking care of removable device */
01080         if (!NT_SUCCESS(Status))
01081         {
01082             Status = RtlSetCurrentDirectory_U(Path);
01083             goto Leave;
01084         }
01085     }
01086     else
01087     {
01088         /* Open directory */
01089         Status = NtOpenFile(&CurDirHandle,
01090                             SYNCHRONIZE | FILE_TRAVERSE,
01091                             &ObjectAttributes,
01092                             &IoStatusBlock,
01093                             FILE_SHARE_READ | FILE_SHARE_WRITE,
01094                             FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
01095         if (!NT_SUCCESS(Status)) goto Leave;
01096 
01097         /* Get device information */
01098         Status = NtQueryVolumeInformationFile(CurDirHandle,
01099                                               &IoStatusBlock,
01100                                               &FileFsDeviceInfo,
01101                                               sizeof(FileFsDeviceInfo),
01102                                               FileFsDeviceInformation);
01103         if (!NT_SUCCESS(Status)) goto Leave;
01104     }
01105 
01106     /* If device is removable, mark handle */
01107     if (FileFsDeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA)
01108     {
01109         CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_CURDIR_IS_REMOVABLE);
01110     }
01111 
01112     FullPath.Length = (USHORT)FullPathLength;
01113 
01114     /* If full path isn't \ terminated, do it */
01115     if (FullPath.Buffer[CharLength - 1] != L'\\')
01116     {
01117         if ((CharLength + 1) * sizeof(WCHAR) > SavedLength)
01118         {
01119             Status = STATUS_NAME_TOO_LONG;
01120             goto Leave;
01121         }
01122 
01123         FullPath.Buffer[CharLength] = L'\\';
01124         FullPath.Buffer[CharLength + 1] = UNICODE_NULL;
01125         FullPath.Length += sizeof(WCHAR);
01126     }
01127 
01128     /* If we have previous current directory with only us as reference, save it */
01129     if (RtlpCurDirRef != NULL && RtlpCurDirRef->RefCount == 1)
01130     {
01131         OldCurDirHandle = RtlpCurDirRef->Handle;
01132     }
01133     else
01134     {
01135         /* Allocate new current directory struct saving previous one */
01136         OldCurDir = RtlpCurDirRef;
01137         RtlpCurDirRef = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTLP_CURDIR_REF));
01138         if (!RtlpCurDirRef)
01139         {
01140             RtlpCurDirRef = OldCurDir;
01141             OldCurDir = NULL;
01142             Status = STATUS_NO_MEMORY;
01143             goto Leave;
01144         }
01145 
01146         /* Set reference to 1 (us) */
01147         RtlpCurDirRef->RefCount = 1;
01148     }
01149 
01150     /* Save new data */
01151     CurDir->Handle = CurDirHandle;
01152     RtlpCurDirRef->Handle = CurDirHandle;
01153     CurDirHandle = NULL;
01154 
01155     /* Copy full path */
01156     RtlCopyMemory(CurDir->DosPath.Buffer, FullPath.Buffer, FullPath.Length + sizeof(WCHAR));
01157     CurDir->DosPath.Length = FullPath.Length;
01158 
01159     Status = STATUS_SUCCESS;
01160 
01161 Leave:
01162     RtlReleasePebLock();
01163 
01164     if (FullPath.Buffer)
01165     {
01166         RtlFreeHeap(RtlGetProcessHeap(), 0, FullPath.Buffer);
01167     }
01168 
01169     if (NtName.Buffer)
01170     {
01171         RtlFreeHeap(RtlGetProcessHeap(), 0, NtName.Buffer);
01172     }
01173 
01174     if (CurDirHandle) NtClose(CurDirHandle);
01175 
01176     if (OldHandle) NtClose(OldHandle);
01177 
01178     if (OldCurDirHandle) NtClose(OldCurDirHandle);
01179 
01180     if (OldCurDir && InterlockedDecrement(&OldCurDir->RefCount) == 0)
01181     {
01182         NtClose(OldCurDir->Handle);
01183         RtlFreeHeap(RtlGetProcessHeap(), 0, OldCurDir);
01184     }
01185 
01186     return Status;
01187 }
01188 
01189 
01190 /******************************************************************
01191  *      collapse_path
01192  *
01193  * Helper for RtlGetFullPathName_U.
01194  * Get rid of . and .. components in the path.
01195  */
01196 void FORCEINLINE collapse_path( WCHAR *path, UINT mark )
01197 {
01198     WCHAR *p, *next;
01199 
01200     /* convert every / into a \ */
01201     for (p = path; *p; p++) if (*p == '/') *p = '\\';
01202 
01203     /* collapse duplicate backslashes */
01204     next = path + max( 1, mark );
01205     for (p = next; *p; p++) if (*p != '\\' || next[-1] != '\\') *next++ = *p;
01206     *next = 0;
01207 
01208     p = path + mark;
01209     while (*p)
01210     {
01211         if (*p == '.')
01212         {
01213             switch(p[1])
01214             {
01215             case '\\': /* .\ component */
01216                 next = p + 2;
01217                 memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
01218                 continue;
01219             case 0:  /* final . */
01220                 if (p > path + mark) p--;
01221                 *p = 0;
01222                 continue;
01223             case '.':
01224                 if (p[2] == '\\')  /* ..\ component */
01225                 {
01226                     next = p + 3;
01227                     if (p > path + mark)
01228                     {
01229                         p--;
01230                         while (p > path + mark && p[-1] != '\\') p--;
01231                     }
01232                     memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
01233                     continue;
01234                 }
01235                 else if (!p[2])  /* final .. */
01236                 {
01237                     if (p > path + mark)
01238                     {
01239                         p--;
01240                         while (p > path + mark && p[-1] != '\\') p--;
01241                         if (p > path + mark) p--;
01242                     }
01243                     *p = 0;
01244                     continue;
01245                 }
01246                 break;
01247             }
01248         }
01249         /* skip to the next component */
01250         while (*p && *p != '\\') p++;
01251         if (*p == '\\')
01252         {
01253             /* remove last dot in previous dir name */
01254             if (p > path + mark && p[-1] == '.') memmove( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) );
01255             else p++;
01256         }
01257     }
01258 
01259     /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */
01260     while (p > path + mark && (p[-1] == ' ' || p[-1] == '.')) p--;
01261     *p = 0;
01262 }
01263 
01264 
01265 
01266 /******************************************************************
01267  *    skip_unc_prefix
01268  *
01269  * Skip the \\share\dir\ part of a file name. Helper for RtlGetFullPathName_U.
01270  */
01271 static const WCHAR *skip_unc_prefix( const WCHAR *ptr )
01272 {
01273     ptr += 2;
01274     while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++;  /* share name */
01275     while (IS_PATH_SEPARATOR(*ptr)) ptr++;
01276     while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++;  /* dir name */
01277     while (IS_PATH_SEPARATOR(*ptr)) ptr++;
01278     return ptr;
01279 }
01280 
01281 
01282 /******************************************************************
01283  *    get_full_path_helper
01284  *
01285  * Helper for RtlGetFullPathName_U
01286  * Note: name and buffer are allowed to point to the same memory spot
01287  */
01288 static ULONG get_full_path_helper(
01289    LPCWSTR name,
01290    LPWSTR buffer,
01291    ULONG size)
01292 {
01293     SIZE_T                      reqsize = 0, mark = 0, dep = 0, deplen;
01294     LPWSTR                      ins_str = NULL;
01295     LPCWSTR                     ptr;
01296     const UNICODE_STRING*       cd;
01297     WCHAR                       tmp[4];
01298 
01299     /* return error if name only consists of spaces */
01300     for (ptr = name; *ptr; ptr++) if (*ptr != ' ') break;
01301     if (!*ptr) return 0;
01302 
01303     RtlAcquirePebLock();
01304 
01305     //cd = &((PCURDIR)&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath)->DosPath;
01306     cd = &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath;
01307 
01308     switch (RtlDetermineDosPathNameType_U(name))
01309     {
01310     case RtlPathTypeUncAbsolute:              /* \\foo   */
01311         ptr = skip_unc_prefix( name );
01312         mark = (ptr - name);
01313         break;
01314 
01315     case RtlPathTypeLocalDevice:           /* \\.\foo */
01316         mark = 4;
01317         break;
01318 
01319     case RtlPathTypeDriveAbsolute:   /* c:\foo  */
01320         reqsize = sizeof(WCHAR);
01321         tmp[0] = towupper(name[0]);
01322         ins_str = tmp;
01323         dep = 1;
01324         mark = 3;
01325         break;
01326 
01327     case RtlPathTypeDriveRelative:   /* c:foo   */
01328         dep = 2;
01329         if (towupper(name[0]) != towupper(cd->Buffer[0]) || cd->Buffer[1] != ':')
01330         {
01331             UNICODE_STRING      var, val;
01332 
01333             tmp[0] = '=';
01334             tmp[1] = name[0];
01335             tmp[2] = ':';
01336             tmp[3] = '\0';
01337             var.Length = 3 * sizeof(WCHAR);
01338             var.MaximumLength = 4 * sizeof(WCHAR);
01339             var.Buffer = tmp;
01340             val.Length = 0;
01341             val.MaximumLength = (USHORT)size;
01342             val.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, size);
01343             if (val.Buffer == NULL)
01344             {
01345                 reqsize = 0;
01346                 goto done;
01347             }
01348 
01349             switch (RtlQueryEnvironmentVariable_U(NULL, &var, &val))
01350             {
01351             case STATUS_SUCCESS:
01352                 /* FIXME: Win2k seems to check that the environment variable actually points
01353                  * to an existing directory. If not, root of the drive is used
01354                  * (this seems also to be the only spot in RtlGetFullPathName that the
01355                  * existence of a part of a path is checked)
01356                  */
01357                 /* fall thru */
01358             case STATUS_BUFFER_TOO_SMALL:
01359                 reqsize = val.Length + sizeof(WCHAR); /* append trailing '\\' */
01360                 val.Buffer[val.Length / sizeof(WCHAR)] = '\\';
01361                 ins_str = val.Buffer;
01362                 break;
01363             case STATUS_VARIABLE_NOT_FOUND:
01364                 reqsize = 3 * sizeof(WCHAR);
01365                 tmp[0] = name[0];
01366                 tmp[1] = ':';
01367                 tmp[2] = '\\';
01368                 ins_str = tmp;
01369                 RtlFreeHeap(RtlGetProcessHeap(), 0, val.Buffer);
01370                 break;
01371             default:
01372                 DPRINT1("Unsupported status code\n");
01373                 RtlFreeHeap(RtlGetProcessHeap(), 0, val.Buffer);
01374                 break;
01375             }
01376             mark = 3;
01377             break;
01378         }
01379         /* fall through */
01380 
01381     case RtlPathTypeRelative:         /* foo     */
01382         reqsize = cd->Length;
01383         ins_str = cd->Buffer;
01384         if (cd->Buffer[1] != ':')
01385         {
01386             ptr = skip_unc_prefix( cd->Buffer );
01387             mark = ptr - cd->Buffer;
01388         }
01389         else mark = 3;
01390         break;
01391 
01392     case RtlPathTypeRooted:         /* \xxx    */
01393 #ifdef __WINE__
01394         if (name[0] == '/')  /* may be a Unix path */
01395         {
01396             const WCHAR *ptr = name;
01397             int drive = find_drive_root( &ptr );
01398             if (drive != -1)
01399             {
01400                 reqsize = 3 * sizeof(WCHAR);
01401                 tmp[0] = 'A' + drive;
01402                 tmp[1] = ':';
01403                 tmp[2] = '\\';
01404                 ins_str = tmp;
01405                 mark = 3;
01406                 dep = ptr - name;
01407                 break;
01408             }
01409         }
01410 #endif
01411         if (cd->Buffer[1] == ':')
01412         {
01413             reqsize = 2 * sizeof(WCHAR);
01414             tmp[0] = cd->Buffer[0];
01415             tmp[1] = ':';
01416             ins_str = tmp;
01417             mark = 3;
01418         }
01419         else
01420         {
01421             ptr = skip_unc_prefix( cd->Buffer );
01422             reqsize = (ptr - cd->Buffer) * sizeof(WCHAR);
01423             mark = reqsize / sizeof(WCHAR);
01424             ins_str = cd->Buffer;
01425         }
01426         break;
01427 
01428     case RtlPathTypeRootLocalDevice:         /* \\.     */
01429         reqsize = 4 * sizeof(WCHAR);
01430         dep = 3;
01431         tmp[0] = '\\';
01432         tmp[1] = '\\';
01433         tmp[2] = '.';
01434         tmp[3] = '\\';
01435         ins_str = tmp;
01436         mark = 4;
01437         break;
01438 
01439     case RtlPathTypeUnknown:
01440         goto done;
01441     }
01442 
01443     /* enough space ? */
01444     deplen = wcslen(name + dep) * sizeof(WCHAR);
01445     if (reqsize + deplen + sizeof(WCHAR) > size)
01446     {
01447         /* not enough space, return need size (including terminating '\0') */
01448         reqsize += deplen + sizeof(WCHAR);
01449         goto done;
01450     }
01451 
01452     memmove(buffer + reqsize / sizeof(WCHAR), name + dep, deplen + sizeof(WCHAR));
01453     if (reqsize) memcpy(buffer, ins_str, reqsize);
01454     reqsize += deplen;
01455 
01456     if (ins_str != tmp && ins_str != cd->Buffer)
01457         RtlFreeHeap(RtlGetProcessHeap(), 0, ins_str);
01458 
01459     collapse_path( buffer, (ULONG)mark );
01460     reqsize = wcslen(buffer) * sizeof(WCHAR);
01461 
01462 done:
01463     RtlReleasePebLock();
01464     return (ULONG)reqsize;
01465 }
01466 
01467 
01468 /******************************************************************
01469  *    RtlGetFullPathName_U  (NTDLL.@)
01470  *
01471  * Returns the number of bytes written to buffer (not including the
01472  * terminating NULL) if the function succeeds, or the required number of bytes
01473  * (including the terminating NULL) if the buffer is too small.
01474  *
01475  * file_part will point to the filename part inside buffer (except if we use
01476  * DOS device name, in which case file_in_buf is NULL)
01477  *
01478  * @implemented
01479  */
01480 ULONG NTAPI RtlGetFullPathName_U(
01481    const WCHAR* name,
01482    ULONG size,
01483    WCHAR* buffer,
01484    WCHAR** file_part)
01485 {
01486     WCHAR*      ptr;
01487     ULONG       dosdev;
01488     ULONG       reqsize;
01489 
01490     DPRINT("RtlGetFullPathName_U(%S %lu %p %p)\n", name, size, buffer, file_part);
01491 
01492     if (!name || !*name) return 0;
01493 
01494     if (file_part) *file_part = NULL;
01495 
01496     /* check for DOS device name */
01497     dosdev = RtlIsDosDeviceName_U((WCHAR*)name);
01498     if (dosdev)
01499     {
01500         DWORD   offset = HIWORD(dosdev) / sizeof(WCHAR); /* get it in WCHARs, not bytes */
01501         DWORD   sz = LOWORD(dosdev); /* in bytes */
01502 
01503         if (8 + sz + 2 > size) return sz + 10;
01504         wcscpy(buffer, DeviceRootW);
01505         memmove(buffer + 4, name + offset, sz);
01506         buffer[4 + sz / sizeof(WCHAR)] = '\0';
01507         /* file_part isn't set in this case */
01508         return sz + 8;
01509     }
01510 
01511     reqsize = get_full_path_helper(name, buffer, size);
01512     if (!reqsize) return 0;
01513     if (reqsize > size)
01514     {
01515         LPWSTR tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, reqsize);
01516         if (tmp == NULL) return 0;
01517         reqsize = get_full_path_helper(name, tmp, reqsize);
01518         if (reqsize + sizeof(WCHAR) > size)  /* it may have worked the second time */
01519         {
01520             RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
01521             return reqsize + sizeof(WCHAR);
01522         }
01523         memcpy( buffer, tmp, reqsize + sizeof(WCHAR) );
01524         RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
01525     }
01526 
01527     /* find file part */
01528     if (file_part && (ptr = wcsrchr(buffer, '\\')) != NULL && ptr >= buffer + 2 && *++ptr)
01529         *file_part = ptr;
01530     return reqsize;
01531 }
01532 
01533 /*
01534  * @implemented
01535  */
01536 BOOLEAN
01537 NTAPI
01538 RtlDosPathNameToNtPathName_U(IN PCWSTR DosName,
01539                              OUT PUNICODE_STRING NtName,
01540                              OUT PCWSTR *PartName,
01541                              OUT PRTL_RELATIVE_NAME_U RelativeName)
01542 {
01543     /* Call the internal function */
01544     return NT_SUCCESS(RtlpDosPathNameToRelativeNtPathName_U(FALSE,
01545                                                             DosName,
01546                                                             NtName,
01547                                                             PartName,
01548                                                             RelativeName));
01549 }
01550 
01551 /*
01552  * @implemented
01553  */
01554 NTSTATUS
01555 NTAPI
01556 RtlDosPathNameToNtPathName_U_WithStatus(IN PCWSTR DosName,
01557                                         OUT PUNICODE_STRING NtName,
01558                                         OUT PCWSTR *PartName,
01559                                         OUT PRTL_RELATIVE_NAME_U RelativeName)
01560 {
01561     /* Call the internal function */
01562     return RtlpDosPathNameToRelativeNtPathName_U(FALSE,
01563                                                  DosName,
01564                                                  NtName,
01565                                                  PartName,
01566                                                  RelativeName);
01567 }
01568 
01569 /*
01570  * @implemented
01571  */
01572 BOOLEAN
01573 NTAPI
01574 RtlDosPathNameToRelativeNtPathName_U(IN PCWSTR DosName,
01575                                      OUT PUNICODE_STRING NtName,
01576                                      OUT PCWSTR *PartName,
01577                                      OUT PRTL_RELATIVE_NAME_U RelativeName)
01578 {
01579     /* Call the internal function */
01580     ASSERT(RelativeName);
01581     return NT_SUCCESS(RtlpDosPathNameToRelativeNtPathName_U(TRUE,
01582                                                             DosName,
01583                                                             NtName,
01584                                                             PartName,
01585                                                             RelativeName));
01586 }
01587 
01588 /*
01589  * @implemented
01590  */
01591 NTSTATUS
01592 NTAPI
01593 RtlDosPathNameToRelativeNtPathName_U_WithStatus(IN PCWSTR DosName,
01594                                                 OUT PUNICODE_STRING NtName,
01595                                                 OUT PCWSTR *PartName,
01596                                                 OUT PRTL_RELATIVE_NAME_U RelativeName)
01597 {
01598     /* Call the internal function */
01599     ASSERT(RelativeName);
01600     return RtlpDosPathNameToRelativeNtPathName_U(TRUE,
01601                                                  DosName,
01602                                                  NtName,
01603                                                  PartName,
01604                                                  RelativeName);
01605 }
01606 
01607 /*
01608  * @unimplemented
01609  */
01610 NTSTATUS NTAPI
01611 RtlNtPathNameToDosPathName(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
01612 {
01613     DPRINT1("RtlNtPathNameToDosPathName: stub\n");
01614     return STATUS_NOT_IMPLEMENTED;
01615 }
01616 
01617 /*
01618  * @implemented
01619  */
01620 ULONG
01621 NTAPI
01622 RtlDosSearchPath_U(IN PCWSTR Path,
01623                    IN PCWSTR FileName,
01624                    IN PCWSTR Extension,
01625                    IN ULONG Size,
01626                    IN PWSTR Buffer,
01627                    OUT PWSTR *PartName)
01628 {
01629     NTSTATUS Status;
01630     ULONG ExtensionLength, Length, FileNameLength, PathLength;
01631     UNICODE_STRING TempString;
01632     PWCHAR NewBuffer, BufferStart;
01633     PCWSTR p;
01634 
01635     /* Validate the input */
01636     if (!(Path) || !(FileName)) return 0;
01637 
01638     /* Check if this is an absolute path */
01639     if (RtlDetermineDosPathNameType_U(FileName) != RtlPathTypeRelative)
01640     {
01641         /* Check if the file exists */
01642         if (RtlDoesFileExists_UEx(FileName, TRUE))
01643         {
01644             /* Get the full name, which does the DOS lookup */
01645             return RtlGetFullPathName_U(FileName, Size, Buffer, PartName);
01646         }
01647 
01648         /* Doesn't exist, so fail */
01649         return 0;
01650     }
01651 
01652     /* Scan the filename */
01653     p = FileName;
01654     while (*p)
01655     {
01656         /* Looking for an extension */
01657         if (*p == '.')
01658         {
01659             /* No extension string needed -- it's part of the filename */
01660             Extension = NULL;
01661             break;
01662         }
01663 
01664         /* Next character */
01665         p++;
01666     }
01667 
01668     /* Do we have an extension? */
01669     if (!Extension)
01670     {
01671         /* Nope, don't worry about one */
01672         ExtensionLength = 0;
01673     }
01674     else
01675     {
01676         /* Build a temporary string to get the extension length */
01677         Status = RtlInitUnicodeStringEx(&TempString, Extension);
01678         if (!NT_SUCCESS(Status)) return 0;
01679         ExtensionLength = TempString.Length;
01680     }
01681 
01682     /* Build a temporary string to get the path length */
01683     Status = RtlInitUnicodeStringEx(&TempString, Path);
01684     if (!NT_SUCCESS(Status)) return 0;
01685     PathLength = TempString.Length;
01686 
01687     /* Build a temporary string to get the filename length */
01688     Status = RtlInitUnicodeStringEx(&TempString, FileName);
01689     if (!NT_SUCCESS(Status)) return 0;
01690     FileNameLength = TempString.Length;
01691 
01692     /* Allocate the buffer for the new string name */
01693     NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
01694                                 0,
01695                                 FileNameLength +
01696                                 ExtensionLength +
01697                                 PathLength +
01698                                 3 * sizeof(WCHAR));
01699     if (!NewBuffer)
01700     {
01701         /* Fail the call */
01702         DbgPrint("%s: Failing due to out of memory (RtlAllocateHeap failure)\n",
01703                  __FUNCTION__);
01704         return 0;
01705     }
01706 
01707     /* Final loop to build the path */
01708     while (TRUE)
01709     {
01710         /* Check if we have a valid character */
01711         BufferStart = NewBuffer;
01712         if (*Path)
01713         {
01714             /* Loop as long as there's no semicolon */
01715             while (*Path != ';')
01716             {
01717                 /* Copy the next character */
01718                 *BufferStart++ = *Path++;
01719                 if (!*Path) break;
01720             }
01721 
01722             /* We found a semi-colon, to stop path processing on this loop */
01723             if (*Path == ';') ++Path;
01724         }
01725 
01726         /* Add a terminating slash if needed */
01727         if ((BufferStart != NewBuffer) && (BufferStart[-1] != '\\'))
01728         {
01729             *BufferStart++ = '\\';
01730         }
01731 
01732         /* Bail out if we reached the end */
01733         if (!*Path) Path = NULL;
01734 
01735         /* Copy the file name and check if an extension is needed */
01736         RtlCopyMemory(BufferStart, FileName, FileNameLength);
01737         if (ExtensionLength)
01738         {
01739             /* Copy the extension too */
01740             RtlCopyMemory((PCHAR)BufferStart + FileNameLength,
01741                           Extension,
01742                           ExtensionLength + sizeof(WCHAR));
01743         }
01744         else
01745         {
01746             /* Just NULL-terminate */
01747             *(PWCHAR)((PCHAR)BufferStart + FileNameLength) = UNICODE_NULL;
01748         }
01749 
01750         /* Now, does this file exist? */
01751         if (RtlDoesFileExists_UEx(NewBuffer, FALSE))
01752         {
01753             /* Call the full-path API to get the length */
01754             Length = RtlGetFullPathName_U(NewBuffer, Size, Buffer, PartName);
01755             break;
01756         }
01757 
01758         /* If we got here, path doesn't exist, so fail the call */
01759         Length = 0;
01760         if (!Path) break;
01761     }
01762 
01763     /* Free the allocation and return the length */
01764     RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
01765     return Length;
01766 }
01767 
01768 /*
01769  * @implemented
01770  */
01771 NTSTATUS
01772 NTAPI
01773 RtlGetFullPathName_UstrEx(IN PUNICODE_STRING FileName,
01774                           IN PUNICODE_STRING StaticString,
01775                           IN PUNICODE_STRING DynamicString,
01776                           IN PUNICODE_STRING *StringUsed,
01777                           IN PSIZE_T FilePartSize,
01778                           OUT PBOOLEAN NameInvalid,
01779                           OUT RTL_PATH_TYPE* PathType,
01780                           OUT PSIZE_T LengthNeeded)
01781 {
01782     NTSTATUS Status;
01783     PWCHAR StaticBuffer;
01784     PCWCH ShortName;
01785     ULONG Length;
01786     USHORT StaticLength;
01787     UNICODE_STRING TempDynamicString;
01788 
01789     /* Initialize all our locals */
01790     ShortName = NULL;
01791     StaticBuffer = NULL;
01792     TempDynamicString.Buffer = NULL;
01793 
01794     /* Initialize the input parameters */
01795     if (StringUsed) *StringUsed = NULL;
01796     if (LengthNeeded) *LengthNeeded = 0;
01797     if (FilePartSize) *FilePartSize = 0;
01798 
01799     /* Check for invalid parameters */
01800     if ((DynamicString) && !(StringUsed) && (StaticString))
01801     {
01802         return STATUS_INVALID_PARAMETER;
01803     }
01804 
01805     /* Check if we did not get an input string */
01806     if (!StaticString)
01807     {
01808         /* Allocate one */
01809         StaticLength = MAX_PATH * sizeof(WCHAR);
01810         StaticBuffer = RtlpAllocateStringMemory(MAX_PATH * sizeof(WCHAR), TAG_USTR);
01811         if (!StaticBuffer) return STATUS_NO_MEMORY;
01812     }
01813     else
01814     {
01815         /* Use the one we received */
01816         StaticBuffer = StaticString->Buffer;
01817         StaticLength = StaticString->MaximumLength;
01818     }
01819 
01820     /* Call the lower-level function */
01821     Length = RtlGetFullPathName_Ustr(FileName,
01822                                      StaticLength,
01823                                      StaticBuffer,
01824                                      &ShortName,
01825                                      NameInvalid,
01826                                      PathType);
01827     DPRINT("Length: %d StaticBuffer: %S\n", Length, StaticBuffer);
01828     if (!Length)
01829     {
01830         /* Fail if it failed */
01831         DbgPrint("%s(%d) - RtlGetFullPathName_Ustr() returned 0\n",
01832                  __FUNCTION__,
01833                  __LINE__);
01834         Status = STATUS_OBJECT_NAME_INVALID;
01835         goto Quickie;
01836     }
01837 
01838     /* Check if it fits inside our static string */
01839     if ((StaticString) && (Length < StaticLength))
01840     {
01841         /* Set the final length */
01842         StaticString->Length = (USHORT)Length;
01843 
01844         /* Set the file part size */
01845         if (FilePartSize) *FilePartSize = ShortName ? (ShortName - StaticString->Buffer) : 0;
01846 
01847         /* Return the static string if requested */
01848         if (StringUsed) *StringUsed = StaticString;
01849 
01850         /* We are done with success */
01851         Status = STATUS_SUCCESS;
01852         goto Quickie;
01853     }
01854 
01855     /* Did we not have an input dynamic string ?*/
01856     if (!DynamicString)
01857     {
01858         /* Return the length we need */
01859         if (LengthNeeded) *LengthNeeded = Length;
01860 
01861         /* And fail such that the caller can try again */
01862         Status = STATUS_BUFFER_TOO_SMALL;
01863         goto Quickie;
01864     }
01865 
01866     /* Check if it fits in our static buffer */
01867     if ((StaticBuffer) && (Length < StaticLength))
01868     {
01869         /* NULL-terminate it */
01870         StaticBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
01871 
01872         /* Set the settings for the dynamic string the caller sent */
01873         DynamicString->MaximumLength = StaticLength;
01874         DynamicString->Length = (USHORT)Length;
01875         DynamicString->Buffer = StaticBuffer;
01876 
01877         /* Set the part size */
01878         if (FilePartSize) *FilePartSize = ShortName ? (ShortName - StaticBuffer) : 0;
01879 
01880         /* Return the dynamic string if requested */
01881         if (StringUsed) *StringUsed = DynamicString;
01882 
01883         /* Do not free the static buffer on exit, and return success */
01884         StaticBuffer = NULL;
01885         Status = STATUS_SUCCESS;
01886         goto Quickie;
01887     }
01888 
01889     /* Now try again under the PEB lock */
01890     RtlAcquirePebLock();
01891     Length = RtlGetFullPathName_Ustr(FileName,
01892                                      StaticLength,
01893                                      StaticBuffer,
01894                                      &ShortName,
01895                                      NameInvalid,
01896                                      PathType);
01897     if (!Length)
01898     {
01899         /* It failed */
01900         DbgPrint("%s line %d: RtlGetFullPathName_Ustr() returned 0\n",
01901                  __FUNCTION__, __LINE__);
01902         Status = STATUS_OBJECT_NAME_INVALID;
01903         goto Release;
01904     }
01905 
01906     /* Check if it fits inside our static string now */
01907     if ((StaticString) && (Length < StaticLength))
01908     {
01909         /* Set the final length */
01910         StaticString->Length = (USHORT)Length;
01911 
01912         /* Set the file part size */
01913         if (FilePartSize) *FilePartSize = ShortName ? (ShortName - StaticString->Buffer) : 0;
01914 
01915         /* Return the static string if requested */
01916         if (StringUsed) *StringUsed = StaticString;
01917 
01918         /* We are done with success */
01919         Status = STATUS_SUCCESS;
01920         goto Release;
01921     }
01922 
01923     /* Check if the path won't even fit in a real string */
01924     if ((Length + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES)
01925     {
01926         /* Name is way too long, fail */
01927         Status = STATUS_NAME_TOO_LONG;
01928         goto Release;
01929     }
01930 
01931     /* Allocate the string to hold the path name now */
01932     TempDynamicString.Buffer = RtlpAllocateStringMemory(Length + sizeof(WCHAR),
01933                                                         TAG_USTR);
01934     if (!TempDynamicString.Buffer)
01935     {
01936         /* Out of memory, fail */
01937         Status = STATUS_NO_MEMORY;
01938         goto Release;
01939     }
01940 
01941     /* Add space for a NULL terminator, and now check the full path */
01942     TempDynamicString.MaximumLength = (USHORT)Length + sizeof(UNICODE_NULL);
01943     Length = RtlGetFullPathName_Ustr(FileName,
01944                                      Length,
01945                                      TempDynamicString.Buffer,
01946                                      &ShortName,
01947                                      NameInvalid,
01948                                      PathType);
01949     if (!Length)
01950     {
01951         /* Some path error, so fail out */
01952         DbgPrint("%s line %d: RtlGetFullPathName_Ustr() returned 0\n",
01953                  __FUNCTION__, __LINE__);
01954         Status = STATUS_OBJECT_NAME_INVALID;
01955         goto Release;
01956     }
01957 
01958     /* It should fit in the string we just allocated */
01959     ASSERT(Length < (TempDynamicString.MaximumLength - sizeof(WCHAR)));
01960     if (Length > TempDynamicString.MaximumLength)
01961     {
01962         /* This is really weird and would mean some kind of race */
01963         Status = STATUS_INTERNAL_ERROR;
01964         goto Release;
01965     }
01966 
01967     /* Return the file part size */
01968     if (FilePartSize) *FilePartSize = ShortName ? (ShortName - TempDynamicString.Buffer) : 0;
01969 
01970     /* Terminate the whole string now */
01971     TempDynamicString.Buffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
01972 
01973     /* Finalize the string and return it to the user */
01974     DynamicString->Buffer = TempDynamicString.Buffer;
01975     DynamicString->Length = (USHORT)Length;
01976     DynamicString->MaximumLength = TempDynamicString.MaximumLength;
01977     if (StringUsed) *StringUsed = DynamicString;
01978 
01979     /* Return success and make sure we don't free the buffer on exit */
01980     TempDynamicString.Buffer = NULL;
01981     Status = STATUS_SUCCESS;
01982 
01983 Release:
01984     /* Release the PEB lock */
01985     RtlReleasePebLock();
01986 
01987 Quickie:
01988     /* Free any buffers we should be freeing */
01989     DPRINT("Status: %lx %S %S\n", Status, StaticBuffer, TempDynamicString.Buffer);
01990     if ((StaticString) && (StaticBuffer) && (StaticBuffer != StaticString->Buffer))
01991     {
01992         RtlpFreeMemory(StaticBuffer, TAG_USTR);
01993     }
01994     if (TempDynamicString.Buffer)
01995     {
01996         RtlpFreeMemory(TempDynamicString.Buffer, TAG_USTR);
01997     }
01998 
01999     /* Print out any unusual errors */
02000     if ((NT_ERROR(Status)) &&
02001         (Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL))
02002     {
02003         DbgPrint("RTL: %s - failing on filename %wZ with status %08lx\n",
02004                 __FUNCTION__, FileName, Status);
02005     }
02006 
02007     /* Return, we're all done */
02008     return Status;
02009 }
02010 
02011 /*
02012  * @implemented
02013  */
02014 NTSTATUS
02015 NTAPI
02016 RtlDosSearchPath_Ustr(IN ULONG Flags,
02017                       IN PUNICODE_STRING PathString,
02018                       IN PUNICODE_STRING FileNameString,
02019                       IN PUNICODE_STRING ExtensionString,
02020                       IN PUNICODE_STRING CallerBuffer,
02021                       IN OUT PUNICODE_STRING DynamicString OPTIONAL,
02022                       OUT PUNICODE_STRING* FullNameOut OPTIONAL,
02023                       OUT PSIZE_T FilePartSize OPTIONAL,
02024                       OUT PSIZE_T LengthNeeded OPTIONAL)
02025 {
02026     WCHAR StaticCandidateBuffer[MAX_PATH];
02027     UNICODE_STRING StaticCandidateString;
02028     NTSTATUS Status;
02029     RTL_PATH_TYPE PathType;
02030     PWCHAR p, End, CandidateEnd, SegmentEnd;
02031     SIZE_T SegmentSize, ByteCount, PathSize, MaxPathSize = 0;
02032     USHORT NamePlusExtLength, WorstCaseLength, ExtensionLength = 0;
02033     PUNICODE_STRING FullIsolatedPath;
02034     DPRINT("DOS Path Search: %lx %wZ %wZ %wZ %wZ %wZ\n",
02035             Flags, PathString, FileNameString, ExtensionString, CallerBuffer, DynamicString);
02036 
02037     /* Initialize the input string */
02038     RtlInitEmptyUnicodeString(&StaticCandidateString,
02039                               StaticCandidateBuffer,
02040                               sizeof(StaticCandidateBuffer));
02041 
02042     /* Initialize optional arguments */
02043     if (FullNameOut) *FullNameOut = NULL;
02044     if (FilePartSize) *FilePartSize = 0;
02045     if (DynamicString)
02046     {
02047         DynamicString->Length = DynamicString->MaximumLength = 0;
02048         DynamicString->Buffer = NULL;
02049     }
02050 
02051     /* Check for invalid parameters */
02052     if ((Flags & ~7) ||
02053         !(PathString) ||
02054         !(FileNameString) ||
02055         ((CallerBuffer) && (DynamicString) && !(FullNameOut)))
02056     {
02057         /* Fail */
02058         DbgPrint("%s: Invalid parameters passed\n", __FUNCTION__);
02059         Status = STATUS_INVALID_PARAMETER;
02060         goto Quickie;
02061     }
02062 
02063     /* First check what kind of path this is */
02064     PathType = RtlDetermineDosPathNameType_Ustr(FileNameString);
02065 
02066     /* Check if the caller wants to prevent relative .\ and ..\ paths */
02067     if ((Flags & 2) &&
02068          (PathType == RtlPathTypeRelative) &&
02069          (FileNameString->Length >= (2 * sizeof(WCHAR))) &&
02070          (FileNameString->Buffer[0] == L'.') &&
02071          ((IS_PATH_SEPARATOR(FileNameString->Buffer[1])) ||
02072           ((FileNameString->Buffer[1] == L'.') &&
02073            ((FileNameString->Length >= (3 * sizeof(WCHAR))) &&
02074            (IS_PATH_SEPARATOR(FileNameString->Buffer[2]))))))
02075     {
02076         /* Yes, and this path is like that, so make it seem unknown */
02077         PathType = RtlPathTypeUnknown;
02078     }
02079 
02080     /* Now check relative vs non-relative paths */
02081     if (PathType == RtlPathTypeRelative)
02082     {
02083         /* Does the caller want SxS? */
02084         if (Flags & 1)
02085         {
02086             /* Apply the SxS magic */
02087             FullIsolatedPath = NULL;
02088             Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
02089                                                               FileNameString,
02090                                                               ExtensionString,
02091                                                               CallerBuffer,
02092                                                               DynamicString,
02093                                                               &FullIsolatedPath,
02094                                                               NULL,
02095                                                               FilePartSize,
02096                                                               LengthNeeded);
02097             if (NT_SUCCESS(Status))
02098             {
02099                 /* We found the SxS path, return it */
02100                 if (FullNameOut) *FullNameOut = FullIsolatedPath;
02101                 goto Quickie;
02102             }
02103             else if (Status != STATUS_SXS_KEY_NOT_FOUND)
02104             {
02105                 /* Critical SxS error, fail */
02106                 DbgPrint("%s: Failing because call to "
02107                          "RtlDosApplyIsolationRedirection_Ustr(%wZ) failed with "
02108                           "status 0x%08lx\n",
02109                          __FUNCTION__,
02110                          FileNameString,
02111                          Status);
02112                 goto Quickie;
02113             }
02114         }
02115 
02116         /* No SxS key found, or not requested, check if there's an extension */
02117         if (ExtensionString)
02118         {
02119             /* Save the extension length, and check if there's a file name */
02120             ExtensionLength = ExtensionString->Length;
02121             if (FileNameString->Length)
02122             {
02123                 /* Start parsing the file name */
02124                 End = &FileNameString->Buffer[FileNameString->Length / sizeof(WCHAR)];
02125                 while (End > FileNameString->Buffer)
02126                 {
02127                     /* If we find a path separator, there's no extension */
02128                     if (IS_PATH_SEPARATOR(*--End)) break;
02129 
02130                     /* Otherwise, did we find an extension dot? */
02131                     if (*End == L'.')
02132                     {
02133                         /* Ignore what the caller sent it, use the filename's */
02134                         ExtensionString = NULL;
02135                         ExtensionLength = 0;
02136                         break;
02137                     }
02138                 }
02139             }
02140         }
02141 
02142         /* Check if we got a path */
02143         if (PathString->Length)
02144         {
02145             /* Start parsing the path name, looking for path separators */
02146             End = &PathString->Buffer[PathString->Length / sizeof(WCHAR)];
02147             p = End;
02148             while ((p > PathString->Buffer) && (*--p == L';'))
02149             {
02150                 /* This is the size of the path -- handle a trailing slash */
02151                 PathSize = End - p - 1;
02152                 if ((PathSize) && !(IS_PATH_SEPARATOR(*(End - 1)))) PathSize++;
02153 
02154                 /* Check if we found a bigger path than before */
02155                 if (PathSize > MaxPathSize) MaxPathSize = PathSize;
02156 
02157                 /* Keep going with the path after this path separator */
02158                 End = p;
02159             }
02160 
02161             /* This is the trailing path, run the same code as above */
02162             PathSize = End - p;
02163             if ((PathSize) && !(IS_PATH_SEPARATOR(*(End - 1)))) PathSize++;
02164             if (PathSize > MaxPathSize) MaxPathSize = PathSize;
02165 
02166             /* Finally, convert the largest path size into WCHAR */
02167             MaxPathSize *= sizeof(WCHAR);
02168         }
02169 
02170         /* Use the extension, the file name, and the largest path as the size */
02171         WorstCaseLength = ExtensionLength +
02172                           FileNameString->Length +
02173                           (USHORT)MaxPathSize +
02174                           sizeof(UNICODE_NULL);
02175         if (WorstCaseLength > UNICODE_STRING_MAX_BYTES)
02176         {
02177             /* It has to fit in a registry string, if not, fail here */
02178             DbgPrint("%s returning STATUS_NAME_TOO_LONG because the computed "
02179                      "worst case file name length is %Iu bytes\n",
02180                      __FUNCTION__,
02181                      WorstCaseLength);
02182             Status = STATUS_NAME_TOO_LONG;
02183             goto Quickie;
02184         }
02185 
02186         /* Scan the path now, to see if we can find the file */
02187         p = PathString->Buffer;
02188         End = &p[PathString->Length / sizeof(WCHAR)];
02189         while (p < End)
02190         {
02191             /* Find out where this path ends */
02192             for (SegmentEnd = p;
02193                  ((SegmentEnd != End) && (*SegmentEnd != L';'));
02194                  SegmentEnd++);
02195 
02196             /* Compute the size of this path */
02197             ByteCount = SegmentSize = (SegmentEnd - p) * sizeof(WCHAR);
02198 
02199             /* Handle trailing slash if there isn't one */
02200             if ((SegmentSize) && !(IS_PATH_SEPARATOR(*(SegmentEnd - 1))))
02201             {
02202                 /* Add space for one */
02203                 SegmentSize += sizeof(OBJ_NAME_PATH_SEPARATOR);
02204             }
02205 
02206             /* Now check if our initial static buffer is too small */
02207             if (StaticCandidateString.MaximumLength <
02208                 (SegmentSize + ExtensionLength + FileNameString->Length))
02209             {
02210                 /* At this point we should've been using our static buffer */
02211                 ASSERT(StaticCandidateString.Buffer == StaticCandidateBuffer);
02212                 if (StaticCandidateString.Buffer != StaticCandidateBuffer)
02213                 {
02214                     /* Something is really messed up if this was the dynamic string */
02215                     DbgPrint("%s: internal error #1; "
02216                              "CandidateString.Buffer = %p; "
02217                              "StaticCandidateBuffer = %p\n",
02218                             __FUNCTION__,
02219                             StaticCandidateString.Buffer,
02220                             StaticCandidateBuffer);
02221                     Status = STATUS_INTERNAL_ERROR;
02222                     goto Quickie;
02223                 }
02224 
02225                 /* We checked before that the maximum possible size shoudl fit! */
02226                 ASSERT((SegmentSize + FileNameString->Length + ExtensionLength) <
02227                         UNICODE_STRING_MAX_BYTES);
02228                 if ((SegmentSize + ExtensionLength + FileNameString->Length) >
02229                     (UNICODE_STRING_MAX_BYTES - sizeof(WCHAR)))
02230                 {
02231                     /* For some reason it's not fitting anymore. Something messed up */
02232                     DbgPrint("%s: internal error #2; SegmentSize = %u, "
02233                              "FileName->Length = %u, DefaultExtensionLength = %u\n",
02234                              __FUNCTION__,
02235                              SegmentSize,
02236                              FileNameString->Length,
02237                              ExtensionLength);
02238                     Status = STATUS_INTERNAL_ERROR;
02239                     goto Quickie;
02240                 }
02241 
02242                 /* Now allocate the dynamic string */
02243                 StaticCandidateString.MaximumLength = FileNameString->Length +
02244                                                       WorstCaseLength;
02245                 StaticCandidateString.Buffer = RtlpAllocateStringMemory(WorstCaseLength,
02246                                                                         TAG_USTR);
02247                 if (!StaticCandidateString.Buffer)
02248                 {
02249                     /* Out of memory, fail */
02250                     DbgPrint("%s: Unable to allocate %u byte buffer for path candidate\n",
02251                              __FUNCTION__,
02252                              StaticCandidateString.MaximumLength);
02253                     Status = STATUS_NO_MEMORY;
02254                     goto Quickie;
02255                 }
02256             }
02257 
02258             /* Copy the path in the string */
02259             RtlCopyMemory(StaticCandidateString.Buffer, p, ByteCount);
02260 
02261             /* Get to the end of the string, and add the trailing slash if missing */
02262             CandidateEnd = &StaticCandidateString.Buffer[ByteCount / sizeof(WCHAR)];
02263             if ((SegmentSize) && (SegmentSize != ByteCount))
02264             {
02265                 *CandidateEnd++ = OBJ_NAME_PATH_SEPARATOR;
02266             }
02267 
02268             /* Copy the filename now */
02269             RtlCopyMemory(CandidateEnd,
02270                           FileNameString->Buffer,
02271                           FileNameString->Length);
02272             CandidateEnd += (FileNameString->Length / sizeof(WCHAR));
02273 
02274             /* Check if there was an extension */
02275             if (ExtensionString)
02276             {
02277                 /* Copy the extension too */
02278                 RtlCopyMemory(CandidateEnd,
02279                               ExtensionString->Buffer,
02280                               ExtensionString->Length);
02281                           CandidateEnd += (ExtensionString->Length / sizeof(WCHAR));
02282             }
02283 
02284             /* We are done, terminate it */
02285             *CandidateEnd = UNICODE_NULL;
02286 
02287             /* Now set the final length of the string so it becomes valid */
02288             StaticCandidateString.Length = (USHORT)(CandidateEnd -
02289                                             StaticCandidateString.Buffer) *
02290                                            sizeof(WCHAR);
02291 
02292             /* Check if this file exists */
02293             DPRINT("BUFFER: %S\n", StaticCandidateString.Buffer);
02294             if (RtlDoesFileExists_UEx(StaticCandidateString.Buffer, FALSE))
02295             {
02296                 /* Awesome, it does, now get the full path */
02297                 Status = RtlGetFullPathName_UstrEx(&StaticCandidateString,
02298                                                    CallerBuffer,
02299                                                    DynamicString,
02300                                                    (PUNICODE_STRING*)FullNameOut,
02301                                                    FilePartSize,
02302                                                    NULL,
02303                                                    &PathType,
02304                                                    LengthNeeded);
02305                 if (!(NT_SUCCESS(Status)) &&
02306                     ((Status != STATUS_NO_SUCH_FILE) &&
02307                      (Status != STATUS_BUFFER_TOO_SMALL)))
02308                 {
02309                     DbgPrint("%s: Failing because we thought we found %wZ on "
02310                              "the search path, but RtlGetfullPathNameUStrEx() "
02311                              "returned %08lx\n",
02312                              __FUNCTION__,
02313                              Status);
02314                 }
02315                 DPRINT("STatus: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
02316                 goto Quickie;
02317             }
02318             else
02319             {
02320                 /* Otherwise, move to the next path */
02321                 if (SegmentEnd != End)
02322                 {
02323                     /* Handle the case of the path separator trailing */
02324                     p = SegmentEnd + 1;
02325                 }
02326                 else
02327                 {
02328                     p = SegmentEnd;
02329                 }
02330             }
02331         }
02332 
02333         /* Loop finished and we didn't break out -- fail */
02334         Status = STATUS_NO_SUCH_FILE;
02335     }
02336     else
02337     {
02338         /* We have a full path, so check if it does exist */
02339         DPRINT("%wZ\n", FileNameString);
02340         if (!RtlDoesFileExists_UstrEx(FileNameString, TRUE))
02341         {
02342             /* It doesn't exist, did we have an extension? */
02343             if (!(ExtensionString) || !(ExtensionString->Length))
02344             {
02345                 /* No extension, so just fail */
02346                 Status = STATUS_NO_SUCH_FILE;
02347                 goto Quickie;
02348             }
02349 
02350             /* There was an extension, check if the filename already had one */
02351             if (!(Flags & 4) && (FileNameString->Length))
02352             {
02353                 /* Parse the filename */
02354                 p = FileNameString->Buffer;
02355                 End = &p[FileNameString->Length / sizeof(WCHAR)];
02356                 while (End > p)
02357                 {
02358                     /* If there's a path separator, there's no extension */
02359                     if (IS_PATH_SEPARATOR(*--End)) break;
02360 
02361                     /* Othwerwise, did we find an extension dot? */
02362                     if (*End == L'.')
02363                     {
02364                         /* File already had an extension, so fail */
02365                         Status = STATUS_NO_SUCH_FILE;
02366                         goto Quickie;
02367                     }
02368                 }
02369             }
02370 
02371             /* So there is an extension, we'll try again by adding it */
02372             NamePlusExtLength = FileNameString->Length +
02373                                 ExtensionString->Length +
02374                                 sizeof(UNICODE_NULL);
02375             if (NamePlusExtLength > UNICODE_STRING_MAX_BYTES)
02376             {
02377                 /* It won't fit in any kind of valid string, so fail */
02378                 DbgPrint("%s: Failing because filename plus extension (%Iu bytes) is too big\n",
02379                          __FUNCTION__,
02380                          NamePlusExtLength);
02381                 Status = STATUS_NAME_TOO_LONG;
02382                 goto Quickie;
02383             }
02384 
02385             /* Fill it fit in our temporary string? */
02386             if (NamePlusExtLength > StaticCandidateString.MaximumLength)
02387             {
02388                 /* It won't fit anymore, allocate a dynamic string for it */
02389                 StaticCandidateString.MaximumLength = NamePlusExtLength;
02390                 StaticCandidateString.Buffer = RtlpAllocateStringMemory(NamePlusExtLength,
02391                                                                         TAG_USTR);
02392                 if (!StaticCandidateString.Buffer)
02393                 {
02394                     /* Ran out of memory, so fail */
02395                     DbgPrint("%s: Failing because allocating the dynamic filename buffer failed\n",
02396                              __FUNCTION__);
02397                     Status = STATUS_NO_MEMORY;
02398                     goto Quickie;
02399                 }
02400             }
02401 
02402             /* Copy the filename */
02403             RtlCopyUnicodeString(&StaticCandidateString, FileNameString);
02404 
02405             /* Copy the extension */
02406             RtlAppendUnicodeStringToString(&StaticCandidateString,
02407                                            ExtensionString);
02408 
02409             DPRINT("SB: %wZ\n", &StaticCandidateString);
02410 
02411             /* And check if this file now exists */
02412             if (!RtlDoesFileExists_UstrEx(&StaticCandidateString, TRUE))
02413             {
02414                 /* Still no joy, fail out */
02415                 Status = STATUS_NO_SUCH_FILE;
02416                 goto Quickie;
02417             }
02418 
02419             /* File was found, get the final full path */
02420             Status = RtlGetFullPathName_UstrEx(&StaticCandidateString,
02421                                                CallerBuffer,
02422                                                DynamicString,
02423                                                (PUNICODE_STRING*)FullNameOut,
02424                                                FilePartSize,
02425                                                NULL,
02426                                                &PathType,
02427                                                LengthNeeded);
02428             if (!(NT_SUCCESS(Status)) && (Status != STATUS_NO_SUCH_FILE))
02429             {
02430                 DbgPrint("%s: Failing on \"%wZ\" because RtlGetfullPathNameUStrEx() "
02431                          "failed with status %08lx\n",
02432                          __FUNCTION__,
02433                          &StaticCandidateString,
02434                          Status);
02435             }
02436             DPRINT("STatus: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
02437         }
02438         else
02439         {
02440             /* File was found on the first try, get the final full path */
02441             Status = RtlGetFullPathName_UstrEx(FileNameString,
02442                                                CallerBuffer,
02443                                                DynamicString,
02444                                                (PUNICODE_STRING*)FullNameOut,
02445                                                FilePartSize,
02446                                                NULL,
02447                                                &PathType,
02448                                                LengthNeeded);
02449             if (!(NT_SUCCESS(Status)) &&
02450                 ((Status != STATUS_NO_SUCH_FILE) &&
02451                 (Status != STATUS_BUFFER_TOO_SMALL)))
02452             {
02453                 DbgPrint("%s: Failing because RtlGetfullPathNameUStrEx() on %wZ "
02454                          "failed with status %08lx\n",
02455                          __FUNCTION__,
02456                          FileNameString,
02457                          Status);
02458             }
02459             DPRINT("STatus: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
02460         }
02461     }
02462 
02463 Quickie:
02464     /* Anything that was not an error, turn into STATUS_SUCCESS */
02465     if (NT_SUCCESS(Status)) Status = STATUS_SUCCESS;
02466 
02467     /* Check if we had a dynamic string */
02468     if ((StaticCandidateString.Buffer) &&
02469         (StaticCandidateString.Buffer != StaticCandidateBuffer))
02470     {
02471         /* Free it */
02472         RtlFreeUnicodeString(&StaticCandidateString);
02473     }
02474 
02475     /* Return the status */
02476     return Status;
02477 }
02478 
02479 /*
02480  * @implemented
02481  */
02482 BOOLEAN
02483 NTAPI
02484 RtlDoesFileExists_U(IN PCWSTR FileName)
02485 {
02486     /* Call the new function */
02487     return RtlDoesFileExists_UEx(FileName, TRUE);
02488 }
02489 
02490 /* 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.