Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2321 lines
63 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. fileio.c
  5. Abstract:
  6. Implementation of file i/o.
  7. Author:
  8. Wesley Witt (wesw) 18-Dec-1998
  9. Revision History:
  10. Andrew Ritz (andrewr) 8-Jul-1999 : added comments
  11. --*/
  12. #include "sfcp.h"
  13. #pragma hdrstop
  14. #define STRSAFE_NO_DEPRECATE
  15. #include <strsafe.h>
  16. //#include <initguid.h>
  17. //#include <devguid.h>
  18. #define SECURITY_FLAGS (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)
  19. NTSTATUS
  20. SfcOpenFile(
  21. IN PUNICODE_STRING FileName,
  22. IN HANDLE DirHandle,
  23. IN ULONG SharingFlags,
  24. OUT PHANDLE FileHandle
  25. )
  26. /*++
  27. Routine Description:
  28. Routine opens a handle to the specified file. Wrapper for NtOpenFile...
  29. Arguments:
  30. FileName - supplies the name of the file to open
  31. DirHandle - handle to the directory that the file is located
  32. SharingFlags - specifies the sharing flags to be used when opening the file.
  33. FileHandle - receives the file handle
  34. Return Value:
  35. NTSTATUS code indicating outcome.
  36. --*/
  37. {
  38. NTSTATUS Status;
  39. OBJECT_ATTRIBUTES ObjectAttributes;
  40. IO_STATUS_BLOCK IoStatusBlock;
  41. ASSERT(FileHandle != NULL);
  42. ASSERT((FileName != NULL) && (FileName->Buffer != NULL));
  43. ASSERT(DirHandle != INVALID_HANDLE_VALUE);
  44. *FileHandle = NULL;
  45. InitializeObjectAttributes(
  46. &ObjectAttributes,
  47. FileName,
  48. OBJ_CASE_INSENSITIVE,
  49. DirHandle,
  50. NULL
  51. );
  52. Status = NtOpenFile(
  53. FileHandle,
  54. FILE_READ_ATTRIBUTES | SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
  55. &ObjectAttributes,
  56. &IoStatusBlock,
  57. SharingFlags,
  58. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY
  59. );
  60. if (!NT_SUCCESS(Status)) {
  61. DebugPrint2( LVL_VERBOSE, L"Could not open file (%wZ), ec=%lx", FileName, Status );
  62. return Status;
  63. }
  64. return STATUS_SUCCESS;
  65. }
  66. HANDLE
  67. SfcCreateDir(
  68. IN PCWSTR DirName,
  69. IN BOOL UseCompression
  70. )
  71. /*++
  72. Routine Description:
  73. Routine creates a directory if it doesn't already exist.
  74. Arguments:
  75. DirName - supplies the dos-style directory name to be created
  76. UseCompression - if TRUE, try to set compression on this directory
  77. Return Value:
  78. a valid directory handle for success, otherwise NULL.
  79. --*/
  80. {
  81. NTSTATUS Status;
  82. HANDLE FileHandle;
  83. UNICODE_STRING FileName;
  84. OBJECT_ATTRIBUTES ObjectAttributes;
  85. IO_STATUS_BLOCK IoStatusBlock;
  86. USHORT CompressionState = COMPRESSION_FORMAT_DEFAULT;
  87. //
  88. // convert the pathname to something the NT Api can use
  89. //
  90. if (!RtlDosPathNameToNtPathName_U( DirName, &FileName, NULL, NULL )) {
  91. DebugPrint1( LVL_VERBOSE, L"Unable to to convert %ws to an NT path", DirName );
  92. return NULL;
  93. }
  94. InitializeObjectAttributes(
  95. &ObjectAttributes,
  96. &FileName,
  97. OBJ_CASE_INSENSITIVE,
  98. NULL,
  99. NULL
  100. );
  101. //
  102. // create the directory
  103. //
  104. Status = NtCreateFile(
  105. &FileHandle,
  106. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  107. &ObjectAttributes,
  108. &IoStatusBlock,
  109. NULL,
  110. FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_NORMAL,
  111. FILE_SHARE_READ | FILE_SHARE_WRITE,
  112. FILE_CREATE,
  113. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  114. NULL,
  115. 0
  116. );
  117. if(!NT_SUCCESS(Status) ) {
  118. DebugPrint2( LVL_VERBOSE, L"Unable to create dir (%wZ) - Status == %lx", &FileName, Status );
  119. FileHandle = NULL;
  120. }
  121. if (FileHandle && UseCompression) {
  122. //
  123. // try to set compression on the specified directory
  124. //
  125. NTSTATUS s;
  126. s = NtFsControlFile(
  127. FileHandle,
  128. NULL,
  129. NULL,
  130. NULL,
  131. &IoStatusBlock,
  132. FSCTL_SET_COMPRESSION,
  133. &CompressionState,
  134. sizeof(CompressionState),
  135. NULL,
  136. 0
  137. );
  138. //
  139. // just check the status so we can log it-- this can fail if our FS
  140. // doesn't support compression, etc.
  141. //
  142. if (!NT_SUCCESS(s)) {
  143. DebugPrint2( LVL_VERBOSE, L"Unable to set compression on directory (%wZ) - Status = %lx", &FileName, Status );
  144. }
  145. }
  146. MemFree( FileName.Buffer );
  147. return(FileHandle);
  148. }
  149. HANDLE
  150. SfcOpenDir(
  151. BOOL IsDosName,
  152. BOOL IsSynchronous,
  153. PCWSTR DirName
  154. )
  155. /*++
  156. Routine Description:
  157. Routine opens a directory handle to an existant directory.
  158. Arguments:
  159. IsDosName - if TRUE, the directory name needs to be converted to an NT
  160. path
  161. IsSynchronous - if TRUE,
  162. DirName - null terminated unicode string specifying directory to open
  163. Return Value:
  164. a valid directory handle for success, otherwise NULL.
  165. --*/
  166. {
  167. NTSTATUS Status;
  168. HANDLE FileHandle;
  169. UNICODE_STRING FileName;
  170. OBJECT_ATTRIBUTES ObjectAttributes;
  171. IO_STATUS_BLOCK IoStatusBlock;
  172. ASSERT(DirName != NULL);
  173. //
  174. // convert the pathname to something the NT Api can use if requested
  175. //
  176. if (IsDosName) {
  177. if (!RtlDosPathNameToNtPathName_U( DirName, &FileName, NULL, NULL )) {
  178. DebugPrint1( LVL_VERBOSE,
  179. L"Unable to to convert %ws to an NT path",
  180. DirName );
  181. return NULL;
  182. }
  183. } else {
  184. RtlInitUnicodeString( &FileName, DirName );
  185. }
  186. InitializeObjectAttributes(
  187. &ObjectAttributes,
  188. &FileName,
  189. OBJ_CASE_INSENSITIVE,
  190. NULL,
  191. NULL
  192. );
  193. //
  194. // open the directory
  195. //
  196. Status = NtOpenFile(
  197. &FileHandle,
  198. FILE_LIST_DIRECTORY | SYNCHRONIZE | READ_CONTROL | WRITE_DAC,
  199. &ObjectAttributes,
  200. &IoStatusBlock,
  201. FILE_SHARE_READ | FILE_SHARE_WRITE,
  202. FILE_DIRECTORY_FILE | (IsSynchronous ? FILE_SYNCHRONOUS_IO_NONALERT : 0)
  203. );
  204. if (!NT_SUCCESS(Status)) {
  205. DebugPrint2( LVL_VERBOSE, L"Unable to open a handle to the (%wZ) directory - Status == %lx", &FileName, Status );
  206. FileHandle = NULL;
  207. }
  208. if (IsDosName) {
  209. MemFree( FileName.Buffer );
  210. }
  211. return FileHandle;
  212. }
  213. NTSTATUS
  214. SfcMapEntireFile(
  215. IN HANDLE hFile,
  216. OUT PHANDLE Section,
  217. OUT PVOID *ViewBase,
  218. OUT PSIZE_T ViewSize
  219. )
  220. /*++
  221. Routine Description:
  222. Routine memory maps a view of an already opened file. It is assumed that
  223. the file was opened with the proper permissions.
  224. Arguments:
  225. hFile - file handle to the file to map
  226. Section - recieves a handle to the mapped section object
  227. ViewBase - receives a pointer to the base address
  228. ViewSize - receives the size of the mapped filed
  229. Return Value:
  230. NTSTATUS code indicating outcome.
  231. --*/
  232. {
  233. NTSTATUS Status;
  234. LARGE_INTEGER SectionOffset;
  235. ASSERT( hFile != NULL );
  236. ASSERT( Section != NULL && ViewBase != NULL && ViewSize != NULL );
  237. *ViewSize = 0;
  238. SectionOffset.QuadPart = 0;
  239. //
  240. // create the section object
  241. //
  242. Status = NtCreateSection(
  243. Section,
  244. SECTION_ALL_ACCESS,
  245. NULL,
  246. NULL,
  247. PAGE_EXECUTE_WRITECOPY,
  248. SEC_COMMIT,
  249. hFile
  250. );
  251. if(!NT_SUCCESS(Status)) {
  252. DebugPrint1( LVL_VERBOSE, L"Status %lx from ZwCreateSection", Status );
  253. return(Status);
  254. }
  255. *ViewBase = NULL;
  256. //
  257. // map the section
  258. //
  259. Status = NtMapViewOfSection(
  260. *Section,
  261. NtCurrentProcess(),
  262. ViewBase,
  263. 0,
  264. 0,
  265. &SectionOffset,
  266. ViewSize,
  267. ViewShare,
  268. 0,
  269. PAGE_EXECUTE_WRITECOPY
  270. );
  271. if(!NT_SUCCESS(Status)) {
  272. NTSTATUS s;
  273. DebugPrint1( LVL_VERBOSE, L"SfcMapEntireFile: Status %lx from ZwMapViewOfSection", Status );
  274. s = NtClose(*Section);
  275. if(!NT_SUCCESS(s)) {
  276. DebugPrint1( LVL_VERBOSE, L"SfcMapEntireFile: Warning: status %lx from ZwClose on section handle", s );
  277. }
  278. return(Status);
  279. }
  280. return(STATUS_SUCCESS);
  281. }
  282. BOOL
  283. SfcUnmapFile(
  284. IN HANDLE Section,
  285. IN PVOID ViewBase
  286. )
  287. /*++
  288. Routine Description:
  289. Routine unmaps a memory mapped view of a file.
  290. Arguments:
  291. Section - handle to the mapped section object
  292. ViewBase - pointer to the base mapping address
  293. Return Value:
  294. TRUE if we successfully cleaned up.
  295. --*/
  296. {
  297. NTSTATUS Status;
  298. BOOL rc = TRUE;
  299. ASSERT( (Section != NULL) && (ViewBase != NULL) );
  300. Status = NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
  301. if(!NT_SUCCESS(Status)) {
  302. DebugPrint1( LVL_VERBOSE, L"Warning: status %lx from ZwUnmapViewOfSection", Status );
  303. rc = FALSE;
  304. }
  305. Status = NtClose(Section);
  306. if(!NT_SUCCESS(Status)) {
  307. DebugPrint1( LVL_VERBOSE, L"Warning: status %lx from ZwClose on section handle", Status );
  308. rc = FALSE;
  309. }
  310. return(rc);
  311. }
  312. NTSTATUS
  313. SfcDeleteFile(
  314. HANDLE DirHandle,
  315. PUNICODE_STRING FileName
  316. )
  317. /*++
  318. Routine Description:
  319. Routine deletes a file in the specified directory
  320. Arguments:
  321. DirHandle - handle to the directory the file is present in
  322. FileName - supplies filename of file to be deleted
  323. Return Value:
  324. NTSTATUS code indicating outcome.
  325. --*/
  326. {
  327. NTSTATUS Status;
  328. OBJECT_ATTRIBUTES ObjectAttributes;
  329. IO_STATUS_BLOCK IoStatusBlock;
  330. HANDLE FileHandle;
  331. FILE_DISPOSITION_INFORMATION Disposition;
  332. ASSERT( (DirHandle != NULL)
  333. && (FileName != NULL)
  334. && (FileName->Buffer != NULL) );
  335. InitializeObjectAttributes(
  336. &ObjectAttributes,
  337. FileName,
  338. OBJ_CASE_INSENSITIVE,
  339. DirHandle,
  340. NULL
  341. );
  342. //
  343. // open a handle to the file
  344. //
  345. Status = NtOpenFile(
  346. &FileHandle,
  347. DELETE | FILE_READ_ATTRIBUTES,
  348. &ObjectAttributes,
  349. &IoStatusBlock,
  350. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  351. FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  352. );
  353. if (!NT_SUCCESS(Status)) {
  354. DebugPrint2( LVL_VERBOSE, L"Could not open file (%wZ), ec=%lx", FileName, Status );
  355. return Status;
  356. }
  357. //
  358. // undef DeleteFile so that DeleteFileW doesn't get in the way
  359. //
  360. #undef DeleteFile
  361. Disposition.DeleteFile = TRUE;
  362. Status = NtSetInformationFile(
  363. FileHandle,
  364. &IoStatusBlock,
  365. &Disposition,
  366. sizeof(Disposition),
  367. FileDispositionInformation
  368. );
  369. if (!NT_SUCCESS(Status)) {
  370. DebugPrint2( LVL_VERBOSE, L"Could not delete file (%wZ), ec=%lx", FileName, Status );
  371. }
  372. NtClose(FileHandle);
  373. return Status;
  374. }
  375. NTSTATUS
  376. SfcRenameFile(
  377. HANDLE DirHandle,
  378. PUNICODE_STRING OldFileName, // this file must exist
  379. PUNICODE_STRING NewFileName // this file may exists, but it doesn't matter
  380. )
  381. /*++
  382. Routine Description:
  383. Routine renames a file in the specified directory
  384. Arguments:
  385. DirHandle - handle to the directory the file is present in
  386. OldFileName - supplies filename of the source file to be renamed.
  387. NewFileName - supplies filename of the destination filename
  388. Return Value:
  389. NTSTATUS code indicating outcome.
  390. --*/
  391. {
  392. NTSTATUS Status;
  393. OBJECT_ATTRIBUTES ObjectAttributes;
  394. IO_STATUS_BLOCK IoStatusBlock;
  395. HANDLE FileHandle;
  396. PFILE_RENAME_INFORMATION NewName;
  397. ASSERT( (DirHandle != NULL)
  398. && (OldFileName != NULL) && (OldFileName->Buffer != NULL)
  399. && (NewFileName != NULL) && (NewFileName->Buffer != NULL) );
  400. //
  401. // first of all, try to reset unwanted attributes on the new file
  402. // this could fail because the new file may not be there at all
  403. //
  404. InitializeObjectAttributes(
  405. &ObjectAttributes,
  406. NewFileName,
  407. OBJ_CASE_INSENSITIVE,
  408. DirHandle,
  409. NULL
  410. );
  411. Status = NtOpenFile(
  412. &FileHandle,
  413. FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  414. &ObjectAttributes,
  415. &IoStatusBlock,
  416. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  417. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  418. );
  419. if(NT_SUCCESS(Status))
  420. {
  421. FILE_BASIC_INFORMATION BasicInfo;
  422. RtlZeroMemory(&BasicInfo, sizeof(BasicInfo));
  423. BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  424. NtSetInformationFile(
  425. FileHandle,
  426. &IoStatusBlock,
  427. &BasicInfo,
  428. sizeof(BasicInfo),
  429. FileBasicInformation
  430. );
  431. NtClose(FileHandle);
  432. }
  433. InitializeObjectAttributes(
  434. &ObjectAttributes,
  435. OldFileName,
  436. OBJ_CASE_INSENSITIVE,
  437. DirHandle,
  438. NULL
  439. );
  440. //
  441. // open a handle to the file
  442. //
  443. Status = NtOpenFile(
  444. &FileHandle,
  445. FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE,
  446. &ObjectAttributes,
  447. &IoStatusBlock,
  448. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  449. FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  450. );
  451. if (!NT_SUCCESS(Status)) {
  452. DebugPrint2( LVL_VERBOSE, L"Could not open file for rename (%wZ), ec=%lx", OldFileName, Status );
  453. return Status;
  454. }
  455. //
  456. // allocate and setup the rename structure
  457. //
  458. NewName = MemAlloc( NewFileName->Length+sizeof(*NewName));
  459. if (NewName != NULL) {
  460. NewName->ReplaceIfExists = TRUE;
  461. NewName->RootDirectory = DirHandle;
  462. NewName->FileNameLength = NewFileName->Length;
  463. RtlMoveMemory( NewName->FileName, NewFileName->Buffer, NewFileName->Length );
  464. //
  465. // do the rename
  466. //
  467. Status = NtSetInformationFile(
  468. FileHandle,
  469. &IoStatusBlock,
  470. NewName,
  471. NewFileName->Length+sizeof(*NewName),
  472. FileRenameInformation
  473. );
  474. if (!NT_SUCCESS(Status)) {
  475. DebugPrint3( LVL_VERBOSE, L"Could not rename file, ec=%lx, dll=(%wZ)(%wZ)", Status, OldFileName, NewFileName );
  476. }
  477. //
  478. // flush changes to disk so this is committed (at least on NTFS)
  479. //
  480. NtFlushBuffersFile( FileHandle, &IoStatusBlock );
  481. MemFree( NewName );
  482. } else {
  483. Status = STATUS_NO_MEMORY;
  484. }
  485. NtClose(FileHandle);
  486. return Status;
  487. }
  488. NTSTATUS
  489. SfcMoveFileDelayed(
  490. IN PCWSTR OldFileNameDos,
  491. IN PCWSTR NewFileNameDos,
  492. IN BOOL AllowProtectedRename
  493. )
  494. /*++
  495. Routine Description:
  496. Appends the given delayed move file operation to the registry
  497. value that contains the list of move file operations to be
  498. performed on the next boot.
  499. Arguments:
  500. OldFileName - Supplies the old file name
  501. NewFileName - Supplies the new file name
  502. AllowProtectedRename - if TRUE, allow the session manager to do the rename
  503. of this file upon reboot even if it's a protected
  504. file
  505. Return Value:
  506. NTSTATUS code indicating outcome
  507. --*/
  508. {
  509. OBJECT_ATTRIBUTES Obja;
  510. UNICODE_STRING KeyName;
  511. UNICODE_STRING ValueName;
  512. HANDLE KeyHandle = NULL;
  513. PWSTR ValueData, s;
  514. PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = NULL;
  515. ULONG ValueLength = 1024;
  516. ULONG ReturnedLength;
  517. NTSTATUS Status;
  518. NTSTATUS rVal = STATUS_SUCCESS;
  519. UNICODE_STRING OldFileName = {0};
  520. UNICODE_STRING NewFileName = {0};
  521. //
  522. // convert the file names
  523. //
  524. if (!RtlDosPathNameToNtPathName_U( OldFileNameDos, &OldFileName, NULL, NULL )) {
  525. DebugPrint1( LVL_VERBOSE, L"Unable to to convert %ws to an NT path", OldFileNameDos );
  526. rVal = STATUS_NO_MEMORY;
  527. goto exit;
  528. }
  529. if (NewFileNameDos) {
  530. if (!RtlDosPathNameToNtPathName_U( NewFileNameDos, &NewFileName, NULL, NULL )) {
  531. DebugPrint1( LVL_VERBOSE, L"Unable to to convert %ws to an NT path", NewFileNameDos );
  532. rVal = STATUS_NO_MEMORY;
  533. goto exit;
  534. }
  535. } else {
  536. RtlInitUnicodeString( &NewFileName, NULL );
  537. }
  538. //
  539. // open the registry
  540. //
  541. RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
  542. RtlInitUnicodeString( &ValueName, L"PendingFileRenameOperations" );
  543. InitializeObjectAttributes(
  544. &Obja,
  545. &KeyName,
  546. (OBJ_OPENIF | OBJ_CASE_INSENSITIVE),
  547. NULL,
  548. NULL
  549. );
  550. Status = NtCreateKey(
  551. &KeyHandle,
  552. GENERIC_READ | GENERIC_WRITE,
  553. &Obja,
  554. 0,
  555. NULL,
  556. 0,
  557. NULL
  558. );
  559. if ( Status == STATUS_ACCESS_DENIED ) {
  560. Status = NtCreateKey(
  561. &KeyHandle,
  562. GENERIC_READ | GENERIC_WRITE,
  563. &Obja,
  564. 0,
  565. NULL,
  566. REG_OPTION_BACKUP_RESTORE,
  567. NULL
  568. );
  569. }
  570. if (!NT_SUCCESS( Status )) {
  571. rVal = Status;
  572. goto exit;
  573. }
  574. //
  575. // retrieve the pending file rename registry key, allocating space until
  576. // we have enough to retrieve the data as well as our new strings
  577. //
  578. while (TRUE) {
  579. //
  580. // allocate space for old name + NULL + new name + NULL + 2 possible '@' chars
  581. //
  582. ValueInfo = MemAlloc(ValueLength + OldFileName.Length + NewFileName.Length + 4 * sizeof(WCHAR));
  583. if (ValueInfo == NULL) {
  584. NtClose(KeyHandle);
  585. rVal = STATUS_NO_MEMORY;
  586. goto exit;
  587. }
  588. //
  589. // File rename operations are stored in the registry in a
  590. // single MULTI_SZ value. This allows the renames to be
  591. // performed in the same order that they were originally
  592. // requested. Each rename operation consists of a pair of
  593. // NULL-terminated strings.
  594. //
  595. Status = NtQueryValueKey(KeyHandle,
  596. &ValueName,
  597. KeyValuePartialInformation,
  598. ValueInfo,
  599. ValueLength,
  600. &ReturnedLength
  601. );
  602. if (NT_SUCCESS(Status)) {
  603. break;
  604. }
  605. //
  606. // The existing value is too large for our buffer.
  607. // Retry with a larger buffer.
  608. //
  609. if (Status == STATUS_BUFFER_OVERFLOW) {
  610. ValueLength = ReturnedLength;
  611. MemFree( ValueInfo );
  612. ValueInfo = NULL;
  613. } else {
  614. //
  615. // we failed for some other reason...bail out
  616. //
  617. break;
  618. }
  619. }
  620. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  621. //
  622. // The value does not currently exist. Create the
  623. // value with our data.
  624. //
  625. s = ValueData = (PWSTR)ValueInfo;
  626. } else if (NT_SUCCESS(Status)) {
  627. ASSERT( ValueInfo->Type == REG_MULTI_SZ );
  628. //
  629. // A value already exists, append our two strings to the
  630. // MULTI_SZ.
  631. //
  632. // (note that the reg data is terminated with two NULLs, so
  633. // we subtract 1 from our pointer to account for that)
  634. //
  635. ValueData = (PWSTR)(&ValueInfo->Data);
  636. s = (PWSTR)((PCHAR)ValueData + ValueInfo->DataLength) - 1;
  637. } else {
  638. ASSERT(MemFree != NULL);
  639. rVal = Status;
  640. goto exit;
  641. }
  642. ASSERT( s != NULL );
  643. //
  644. // session manager recognizes this screwy syntax whereby if you set an "@"
  645. // in front of the source filename, it always allows the rename to occur.
  646. //
  647. // the pair of values are NULL separated and terminates in two NULL
  648. // characters
  649. //
  650. //
  651. if (AllowProtectedRename) {
  652. wcscpy( s, L"@" );
  653. s += 1;
  654. }
  655. CopyMemory(s, OldFileName.Buffer, OldFileName.Length);
  656. s += (OldFileName.Length/sizeof(WCHAR));
  657. *s++ = L'\0';
  658. if (AllowProtectedRename && NewFileName.Length) {
  659. wcscpy( s, L"@" );
  660. s += 1;
  661. }
  662. CopyMemory(s, NewFileName.Buffer, NewFileName.Length);
  663. s += (NewFileName.Length/sizeof(WCHAR));
  664. *s++ = L'\0';
  665. *s++ = L'\0';
  666. //
  667. // set the registry key
  668. //
  669. Status = NtSetValueKey(
  670. KeyHandle,
  671. &ValueName,
  672. 0,
  673. REG_MULTI_SZ,
  674. ValueData,
  675. (ULONG)((s-ValueData)*sizeof(WCHAR))
  676. );
  677. rVal = Status;
  678. exit:
  679. if (OldFileName.Length) {
  680. RtlFreeUnicodeString(&OldFileName);
  681. }
  682. if (NewFileName.Length) {
  683. RtlFreeUnicodeString(&NewFileName);
  684. }
  685. if (KeyHandle) {
  686. NtClose(KeyHandle);
  687. }
  688. if (ValueInfo) {
  689. MemFree( ValueInfo );
  690. }
  691. return rVal;
  692. }
  693. #if 0
  694. DWORD
  695. RetrieveFileSecurity(
  696. IN PCTSTR FileName,
  697. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
  698. )
  699. /*++
  700. Routine Description:
  701. Retreive security information from a file and place it into a buffer.
  702. Arguments:
  703. FileName - supplies name of file whose security information is desired.
  704. SecurityDescriptor - If the function is successful, receives pointer
  705. to buffer containing security information for the file. The pointer
  706. may be NULL, indicating that there is no security information
  707. associated with the file or that the underlying filesystem does not
  708. support file security.
  709. Return Value:
  710. Win32 error code indicating outcome. If ERROR_SUCCESS check the value returned
  711. in SecurityDescriptor.
  712. The caller can free the buffer with MemFree() when done with it.
  713. --*/
  714. {
  715. BOOL b;
  716. DWORD d;
  717. DWORD BytesRequired;
  718. PSECURITY_DESCRIPTOR p;
  719. BytesRequired = 1024;
  720. while (TRUE) {
  721. //
  722. // Allocate a buffer of the required size.
  723. //
  724. p = MemAlloc(BytesRequired);
  725. if(!p) {
  726. return(ERROR_NOT_ENOUGH_MEMORY);
  727. }
  728. //
  729. // Get the security.
  730. //
  731. b = GetFileSecurity(
  732. FileName,
  733. SECURITY_FLAGS,
  734. p,
  735. BytesRequired,
  736. &BytesRequired
  737. );
  738. //
  739. // Return with sucess
  740. //
  741. if(b) {
  742. *SecurityDescriptor = p;
  743. return(ERROR_SUCCESS);
  744. }
  745. //
  746. // Return an error code, unless we just need a bigger buffer
  747. //
  748. MemFree(p);
  749. d = GetLastError();
  750. if(d != ERROR_INSUFFICIENT_BUFFER) {
  751. return (d);
  752. }
  753. //
  754. // There's a bug in GetFileSecurity that can cause it to ask for a
  755. // REALLY big buffer. In that case, we return an error.
  756. //
  757. if (BytesRequired > 0xF0000000) {
  758. return (ERROR_INVALID_DATA);
  759. }
  760. //
  761. // Otherwise, we'll try again with a bigger buffer
  762. //
  763. }
  764. }
  765. #endif
  766. NTSTATUS
  767. SfcCopyFile(
  768. IN HANDLE SrcDirHandle,
  769. IN PCWSTR SrcDirName,
  770. IN HANDLE DstDirHandle,
  771. IN PCWSTR DstDirName,
  772. IN const PUNICODE_STRING FileName,
  773. IN const PUNICODE_STRING SourceFileNameIn OPTIONAL
  774. )
  775. /*++
  776. Routine Description:
  777. Copy a file from the source to the destination. Since we are running
  778. in SMSS, we cannot use CopyFile.
  779. Arguments:
  780. SrcDirHandle - handle to source directory where file exists
  781. DstDirHandle - handle to destination directory where file will be placed
  782. FileName - UNICODE_STRING of relative name of file to be copied
  783. Return Value:
  784. NTSTATUS code of any fatal error.
  785. --*/
  786. {
  787. NTSTATUS Status,DeleteStatus;
  788. HANDLE SrcFileHandle;
  789. HANDLE DstFileHandle;
  790. HANDLE SectionHandle;
  791. PVOID ImageBase;
  792. ULONG remainingLength;
  793. ULONG writeLength;
  794. PUCHAR base;
  795. IO_STATUS_BLOCK IoStatusBlock;
  796. LARGE_INTEGER FileOffset;
  797. WCHAR TmpNameBuffer[MAX_PATH];
  798. WCHAR Tmp2NameBuffer[MAX_PATH];
  799. UNICODE_STRING TmpName;
  800. UNICODE_STRING Tmp2Name;
  801. OBJECT_ATTRIBUTES ObjectAttributes;
  802. FILE_STANDARD_INFORMATION StandardInfo;
  803. FILE_BASIC_INFORMATION BasicInfo;
  804. SIZE_T ViewSize;
  805. PUNICODE_STRING SourceFileName;
  806. SourceFileName = (SourceFileNameIn) ? SourceFileNameIn : FileName;
  807. ASSERT(SourceFileName != NULL);
  808. //
  809. // open & map the source file
  810. //
  811. Status = SfcOpenFile( SourceFileName, SrcDirHandle, SHARE_ALL, &SrcFileHandle );
  812. if(!NT_SUCCESS(Status) ) {
  813. return Status;
  814. }
  815. Status = SfcMapEntireFile( SrcFileHandle, &SectionHandle, &ImageBase, &ViewSize );
  816. if(!NT_SUCCESS(Status) ) {
  817. NtClose( SrcFileHandle );
  818. return Status;
  819. }
  820. Status = NtQueryInformationFile(
  821. SrcFileHandle,
  822. &IoStatusBlock,
  823. &StandardInfo,
  824. sizeof(StandardInfo),
  825. FileStandardInformation
  826. );
  827. if (!NT_SUCCESS(Status)) {
  828. DebugPrint1( LVL_VERBOSE, L"QueryInfoFile status %lx", Status );
  829. SfcUnmapFile( SectionHandle, ImageBase );
  830. NtClose( SrcFileHandle );
  831. return Status;
  832. }
  833. Status = NtQueryInformationFile(
  834. SrcFileHandle,
  835. &IoStatusBlock,
  836. &BasicInfo,
  837. sizeof(BasicInfo),
  838. FileBasicInformation
  839. );
  840. if (!NT_SUCCESS(Status)) {
  841. DebugPrint1( LVL_VERBOSE, L"QueryInfoFile status %lx", Status );
  842. SfcUnmapFile( SectionHandle, ImageBase );
  843. NtClose( SrcFileHandle );
  844. return Status;
  845. }
  846. //
  847. // create the temp file name
  848. //
  849. TmpName.MaximumLength = sizeof(TmpNameBuffer);
  850. TmpName.Buffer = TmpNameBuffer;
  851. RtlZeroMemory( TmpName.Buffer, TmpName.MaximumLength );
  852. RtlCopyMemory( TmpName.Buffer, FileName->Buffer, FileName->Length );
  853. wcscat( TmpName.Buffer, L".new" );
  854. TmpName.Length = UnicodeLen(TmpName.Buffer);
  855. InitializeObjectAttributes(
  856. &ObjectAttributes,
  857. &TmpName,
  858. OBJ_CASE_INSENSITIVE,
  859. DstDirHandle,
  860. NULL
  861. );
  862. BasicInfo.FileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
  863. Status = NtCreateFile(
  864. &DstFileHandle,
  865. (ACCESS_MASK)(DELETE | SYNCHRONIZE | GENERIC_WRITE | FILE_WRITE_ATTRIBUTES),
  866. &ObjectAttributes,
  867. &IoStatusBlock,
  868. &StandardInfo.EndOfFile,
  869. BasicInfo.FileAttributes ,
  870. FILE_SHARE_READ | FILE_SHARE_WRITE,
  871. FILE_OVERWRITE_IF,
  872. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY | FILE_OPEN_FOR_BACKUP_INTENT,
  873. NULL,
  874. 0
  875. );
  876. if(!NT_SUCCESS(Status) ) {
  877. DebugPrint2( LVL_VERBOSE, L"Unable to create temp file (%wZ) - Status == %lx", &TmpName, Status );
  878. SfcUnmapFile( SectionHandle, ImageBase );
  879. NtClose( SrcFileHandle );
  880. return Status;
  881. }
  882. //
  883. // copy the bits
  884. //
  885. // guard the write with a try/except because if there is an i/o error,
  886. // memory management will raise an in-page exception.
  887. //
  888. FileOffset.QuadPart = 0;
  889. base = ImageBase;
  890. remainingLength = StandardInfo.EndOfFile.LowPart;
  891. try {
  892. while (remainingLength != 0) {
  893. writeLength = 60 * 1024;
  894. if (writeLength > remainingLength) {
  895. writeLength = remainingLength;
  896. }
  897. Status = NtWriteFile(
  898. DstFileHandle,
  899. NULL,
  900. NULL,
  901. NULL,
  902. &IoStatusBlock,
  903. base,
  904. writeLength,
  905. &FileOffset,
  906. NULL
  907. );
  908. base += writeLength;
  909. FileOffset.LowPart += writeLength;
  910. remainingLength -= writeLength;
  911. if (!NT_SUCCESS(Status)) {
  912. break;
  913. }
  914. }
  915. } except(EXCEPTION_EXECUTE_HANDLER) {
  916. Status = STATUS_IN_PAGE_ERROR;
  917. }
  918. if (NT_SUCCESS(Status)) {
  919. Status = NtSetInformationFile(
  920. DstFileHandle,
  921. &IoStatusBlock,
  922. &BasicInfo,
  923. sizeof(BasicInfo),
  924. FileBasicInformation
  925. );
  926. if (!NT_SUCCESS(Status)) {
  927. DebugPrint2( LVL_VERBOSE, L"Could not set file information for (%wZ), ec=%lx", &TmpName, Status );
  928. }
  929. }
  930. #if 0
  931. if (NT_SUCCESS(Status) && SrcDirName) {
  932. PSECURITY_DESCRIPTOR SecurityDescriptor;
  933. wcscpy( Tmp2NameBuffer, SrcDirName );
  934. pSetupConcatenatePaths( Tmp2NameBuffer, FileName->Buffer, UnicodeChars(Tmp2NameBuffer), NULL );
  935. if (RetrieveFileSecurity( Tmp2NameBuffer, &SecurityDescriptor ) == ERROR_SUCCESS) {
  936. SetFileSecurity(
  937. TmpName.Buffer,
  938. SECURITY_FLAGS,
  939. SecurityDescriptor
  940. );
  941. MemFree( SecurityDescriptor );
  942. }
  943. }
  944. #endif
  945. SfcUnmapFile( SectionHandle, ImageBase );
  946. NtClose( SrcFileHandle );
  947. NtClose( DstFileHandle );
  948. if (!NT_SUCCESS(Status)) {
  949. DebugPrint2( LVL_VERBOSE, L"Could not copy file, ec=%lx, dll=%wZ", Status, &TmpName );
  950. NtDeleteFile( &ObjectAttributes );
  951. return Status;
  952. }
  953. //
  954. // attempt to rename the new (.new) file to the
  955. // destination file name. in most cases this will
  956. // work, but it will fail when the destination file
  957. // is in use.
  958. //
  959. Status = SfcRenameFile( DstDirHandle, &TmpName, FileName );
  960. if (NT_SUCCESS(Status) ) {
  961. return Status;
  962. } else {
  963. DebugPrint2( LVL_VERBOSE, L"Could not rename file, ec=%lx, dll=%wZ", Status, &TmpName );
  964. }
  965. //
  966. // the rename failed so it must be in use
  967. //
  968. Tmp2Name.MaximumLength = sizeof(Tmp2NameBuffer);
  969. Tmp2Name.Buffer = Tmp2NameBuffer;
  970. RtlZeroMemory( Tmp2Name.Buffer, Tmp2Name.MaximumLength );
  971. RtlCopyMemory( Tmp2Name.Buffer, FileName->Buffer, FileName->Length );
  972. wcscat( Tmp2Name.Buffer, L".tmp" );
  973. Tmp2Name.Length = UnicodeLen(Tmp2Name.Buffer);
  974. Status = SfcRenameFile( DstDirHandle, FileName, &Tmp2Name );
  975. if(!NT_SUCCESS(Status) ) {
  976. DebugPrint2( LVL_VERBOSE, L"Could not rename file, ec=%lx, dll=%wZ", Status, &Tmp2Name );
  977. NtDeleteFile( &ObjectAttributes );
  978. return Status;
  979. }
  980. Status = SfcRenameFile( DstDirHandle, &TmpName, FileName );
  981. if(!NT_SUCCESS(Status) ) {
  982. DebugPrint2( LVL_VERBOSE, L"Could not rename file, ec=%lx, dll=%wZ", Status, &Tmp2Name );
  983. Status = SfcRenameFile( DstDirHandle, &Tmp2Name, FileName );
  984. if(!NT_SUCCESS(Status) ) {
  985. DebugPrint2( LVL_VERBOSE, L"Could not rename file, ec=%lx, dll=%wZ", Status, &Tmp2Name );
  986. NtDeleteFile( &ObjectAttributes );
  987. return Status;
  988. }
  989. NtDeleteFile( &ObjectAttributes );
  990. return Status;
  991. }
  992. DeleteStatus = SfcDeleteFile( DstDirHandle, &Tmp2Name );
  993. if (!NT_SUCCESS(DeleteStatus) && DstDirName) {
  994. wcscpy( TmpNameBuffer, L"@" );
  995. wcscat( TmpNameBuffer, DstDirName );
  996. wcscat( TmpNameBuffer, L"\\" );
  997. wcscat( TmpNameBuffer, Tmp2NameBuffer );
  998. Status = SfcMoveFileDelayed( TmpNameBuffer, NULL, TRUE );
  999. return Status;
  1000. }
  1001. return Status;
  1002. }
  1003. BOOL
  1004. SfcGetCdRomDrivePath(
  1005. IN PWSTR CdRomPath
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. Finds the first CDROM on your machine. Cycles through the drive letters
  1010. until it finds a drive that's a CDROM.
  1011. Arguments:
  1012. CdRomPath - buffer to receive CDROM path. Assumes that this buffer is at
  1013. least 8 characters big
  1014. Return Value:
  1015. TRUE if we found a CD-ROM
  1016. Note that this routine always returns back the first CD-ROM
  1017. --*/
  1018. {
  1019. int i;
  1020. WCHAR Path[8];
  1021. ASSERT( CdRomPath != NULL );
  1022. CdRomPath[0] = 0;
  1023. for (i=0; i<26; i++) {
  1024. swprintf( Path, L"%c:\\", L'a'+i );
  1025. if (GetDriveType( Path ) == DRIVE_CDROM) {
  1026. wcsncpy( CdRomPath, Path, UnicodeChars(Path) );
  1027. return TRUE;
  1028. }
  1029. }
  1030. return FALSE;
  1031. }
  1032. BOOL
  1033. SfcIsFileOnMedia(
  1034. IN PCWSTR FileName
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. checks if the specified file exists. Used to verify that a file present
  1039. on our media or if it's also compressed on our media.
  1040. Arguments:
  1041. FileName - specifies the filename to look for
  1042. Return Value:
  1043. TRUE if the file is present.
  1044. --*/
  1045. {
  1046. PWSTR CompressedName;
  1047. DWORD dwTemp1, dwTemp2;
  1048. UINT uiTemp1;
  1049. //
  1050. // this does exactly what we want...look for file.??? and file.??_
  1051. //
  1052. if (SetupGetFileCompressionInfo(
  1053. FileName,
  1054. &CompressedName,
  1055. &dwTemp1,
  1056. &dwTemp2,
  1057. &uiTemp1 ) == ERROR_SUCCESS) {
  1058. LocalFree(CompressedName);
  1059. return TRUE;
  1060. }
  1061. return FALSE;
  1062. }
  1063. DWORD
  1064. SfcGetPathType(
  1065. IN PCWSTR Path,
  1066. OUT PWSTR NewPath,
  1067. IN DWORD NewPathSize
  1068. )
  1069. /*++
  1070. Routine Description:
  1071. Determines the type of drive specified. If the drive is a drive letter and
  1072. it's a remote drive, we will retrieve the UNC pathname of that drive.
  1073. Arguments:
  1074. Path - contains the path to check.
  1075. NewPath - if a remote path (DRIVE_REMOTE), this receives the UNC pathname
  1076. of that drive. otherwise, this will receive the original path
  1077. on success.
  1078. NewPathSize - size in characters of NewPath buffer.
  1079. Return Value:
  1080. returns a PATH_ constant similar to a DRIVE_ constant
  1081. --*/
  1082. {
  1083. WCHAR buf[MAX_PATH*2];
  1084. DWORD DriveType;
  1085. WCHAR MyPath[4];
  1086. ASSERT(Path != NULL && Path[0] != 0);
  1087. if (Path[0] == L'\\' && Path[1] == L'\\') {
  1088. if (wcslen(Path)+1 > NewPathSize) {
  1089. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1090. return(PATH_INVALID);
  1091. }
  1092. wcsncpy(NewPath,Path,NewPathSize);
  1093. return PATH_UNC;
  1094. }
  1095. //
  1096. // Get the path right.
  1097. //
  1098. MyPath[0] = Path[0];
  1099. MyPath[1] = L':';
  1100. MyPath[2] = L'\\';
  1101. MyPath[3] = L'\0';
  1102. DriveType = GetDriveType( MyPath );
  1103. switch (DriveType) {
  1104. case DRIVE_REMOTE:
  1105. case DRIVE_UNKNOWN:
  1106. case DRIVE_NO_ROOT_DIR:
  1107. if(SfcGetConnectionName(Path, buf, UnicodeChars(buf), NULL, 0, FALSE, NULL)) {
  1108. if (wcslen(buf) + 1 > NewPathSize) {
  1109. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1110. return(PATH_INVALID);
  1111. }
  1112. wcsncpy(NewPath, buf, NewPathSize );
  1113. return PATH_NETWORK;
  1114. } else {
  1115. DebugPrint1( LVL_VERBOSE, L"SfcGetConnectionName [%ws] failed", Path );
  1116. if (wcslen(Path)+1 > NewPathSize) {
  1117. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1118. return(PATH_INVALID);
  1119. }
  1120. wcsncpy( NewPath, Path, NewPathSize );
  1121. return PATH_LOCAL;
  1122. }
  1123. ASSERT(FALSE && "Should never get here");
  1124. break;
  1125. case DRIVE_CDROM:
  1126. if (wcslen(Path)+1 > NewPathSize) {
  1127. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1128. return(PATH_INVALID);
  1129. }
  1130. wcsncpy( NewPath, Path, NewPathSize );
  1131. return PATH_CDROM;
  1132. default:
  1133. break;
  1134. }
  1135. if (wcslen(Path)+1 > NewPathSize) {
  1136. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1137. return(PATH_INVALID);
  1138. }
  1139. wcsncpy( NewPath, Path, NewPathSize );
  1140. return PATH_LOCAL;
  1141. }
  1142. BOOL
  1143. SfcGetConnectionName(
  1144. IN PCWSTR Path,
  1145. OUT PWSTR ConnectionName,
  1146. IN DWORD ConnectionBufferSize,
  1147. OUT PWSTR RemainingPath OPTIONAL,
  1148. IN DWORD RemainingPathSize OPTIONAL,
  1149. IN BOOL KeepImpersonating,
  1150. OUT PBOOL Impersonating OPTIONAL
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. Given a path, get the name of the UNC connection path which corresponds to
  1155. this path. Assumes that the path is a remote path.
  1156. Arguments:
  1157. Path - contains the path to parse
  1158. ConnectionName - receives the UNC share that corresponds to the given path
  1159. ConnectionBufferSize - size of ConnectionName buffer in characters
  1160. Return Value:
  1161. TRUE indicates success, in which case ConnectionName will contain the UNC
  1162. path
  1163. --*/
  1164. {
  1165. DWORD dwError = ERROR_SUCCESS;
  1166. WCHAR buf[MAX_PATH*2];
  1167. PWSTR szConnection = NULL;
  1168. PWSTR szRemaining = NULL;
  1169. DWORD Size;
  1170. if(ConnectionName != NULL && ConnectionBufferSize != 0) {
  1171. ConnectionName[0] = 0;
  1172. }
  1173. if(RemainingPath != NULL && RemainingPathSize != 0) {
  1174. RemainingPath[0] = 0;
  1175. }
  1176. if(Impersonating != NULL) {
  1177. *Impersonating = FALSE;
  1178. }
  1179. if(NULL == Path || 0 == Path[0] || NULL == ConnectionName || 0 == ConnectionBufferSize || (KeepImpersonating && NULL == Impersonating)) {
  1180. SetLastError(ERROR_INVALID_PARAMETER);
  1181. return FALSE;
  1182. }
  1183. //
  1184. // if we have a UNC path just use it
  1185. //
  1186. if (Path[0] == L'\\' && Path[1] == L'\\') {
  1187. //
  1188. // a UNC path always looks lke \\server\share\otherstuff, so it's
  1189. // easy to parse it
  1190. //
  1191. lstrcpyn( buf, Path, UnicodeChars(buf) );
  1192. //
  1193. // find first '\' after '\\'
  1194. //
  1195. szRemaining = wcschr( &buf[2], L'\\' );
  1196. if(szRemaining != NULL) {
  1197. //
  1198. // find next '\' and NULL it out
  1199. //
  1200. szRemaining = wcschr(szRemaining + 1, L'\\');
  1201. if(szRemaining != NULL) {
  1202. *szRemaining++ = 0;
  1203. }
  1204. } else {
  1205. DebugPrint1( LVL_VERBOSE, L"screwy UNC path [%ws] ", buf );
  1206. ASSERT(FALSE);
  1207. }
  1208. szConnection = buf;
  1209. } else {
  1210. //
  1211. // bummer, have to translate the driver letter into a full path name
  1212. //
  1213. REMOTE_NAME_INFO *rni = (REMOTE_NAME_INFO*)buf;
  1214. Size = sizeof(buf);
  1215. dwError = WNetGetUniversalName(Path, REMOTE_NAME_INFO_LEVEL, (LPVOID) rni, &Size);
  1216. if((ERROR_BAD_DEVICE == dwError || ERROR_CONNECTION_UNAVAIL == dwError ||
  1217. ERROR_NO_NET_OR_BAD_PATH == dwError || ERROR_NOT_CONNECTED == dwError) &&
  1218. hUserToken != NULL && ImpersonateLoggedOnUser(hUserToken)) {
  1219. //
  1220. // This might make sense only in the logged-on user context
  1221. //
  1222. Size = sizeof(buf);
  1223. dwError = WNetGetUniversalName(Path, REMOTE_NAME_INFO_LEVEL, (LPVOID) rni, &Size);
  1224. if(KeepImpersonating && ERROR_SUCCESS == dwError) {
  1225. *Impersonating = TRUE;
  1226. } else {
  1227. RevertToSelf();
  1228. }
  1229. }
  1230. if(ERROR_SUCCESS == dwError) {
  1231. szConnection = rni->lpConnectionName;
  1232. szRemaining = rni->lpRemainingPath;
  1233. }
  1234. }
  1235. if(dwError != ERROR_SUCCESS) {
  1236. SetLastError(dwError);
  1237. return FALSE;
  1238. }
  1239. ASSERT(szConnection != NULL);
  1240. Size = wcslen(szConnection) + 1;
  1241. if(Size > ConnectionBufferSize) {
  1242. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1243. return FALSE;
  1244. }
  1245. RtlCopyMemory(ConnectionName, szConnection, Size * sizeof(WCHAR));
  1246. if(RemainingPath != NULL && RemainingPathSize != 0 && szRemaining != NULL && szRemaining[0] != 0) {
  1247. lstrcpyn(RemainingPath, szRemaining, RemainingPathSize);
  1248. }
  1249. return TRUE;
  1250. }
  1251. PCWSTR
  1252. IsFileInDriverCache(
  1253. IN PCWSTR TargetFilename
  1254. )
  1255. /*++
  1256. Routine Description:
  1257. Routine determines if a file is in the local driver cache. It does this by
  1258. reading the inf file "drvindex.inf", which lists all of the files that
  1259. reside in the driver cache.
  1260. This code is lifted from setupapi's implementation.
  1261. Arguments:
  1262. TargetFileName - contains the filename of the file to query.
  1263. Return Value:
  1264. If the file is in the driver cache, the function returns the name of
  1265. the cabfile which the file resides in, otherwise the function returns NULL.
  1266. --*/
  1267. {
  1268. HINF CabInf;
  1269. INFCONTEXT Context;
  1270. INFCONTEXT SectionContext;
  1271. WCHAR InfName[MAX_PATH];
  1272. WCHAR SectionName[128];
  1273. WCHAR CabName[128];
  1274. UINT Field;
  1275. UINT FieldCount;
  1276. BOOL b;
  1277. PCWSTR CacheName = NULL;
  1278. ASSERT(TargetFilename != NULL);
  1279. //
  1280. // open up the driver index file which will tell us what we need to know.
  1281. //
  1282. wcscpy( InfName, InfDirectory );
  1283. pSetupConcatenatePaths( InfName, L"drvindex.inf", UnicodeChars(InfName), NULL );
  1284. CabInf = SetupOpenInfFile( InfName, NULL, INF_STYLE_WIN4, NULL );
  1285. if (CabInf == INVALID_HANDLE_VALUE) {
  1286. return NULL;
  1287. }
  1288. //
  1289. // get the cabfiles line, which contains a list of section names we must
  1290. // search for the file in.
  1291. //
  1292. if (!SetupFindFirstLine( CabInf, L"Version", L"CabFiles", &SectionContext )) {
  1293. SetupCloseInfFile( CabInf );
  1294. return NULL;
  1295. }
  1296. do {
  1297. //
  1298. // each field in the CabFilesLine corresponds to a section name
  1299. //
  1300. FieldCount = SetupGetFieldCount( &SectionContext );
  1301. for(Field=1; Field<=FieldCount; Field++) {
  1302. b = SetupGetStringField( &SectionContext, Field, SectionName, UnicodeChars(SectionName), NULL );
  1303. //
  1304. // look for the file in this section
  1305. //
  1306. if (b && SetupFindFirstLine( CabInf, SectionName, TargetFilename, &Context )) {
  1307. //
  1308. // if we found the file in this section it must be in the
  1309. // driver cache. Now look in the "Cabs" section for a line
  1310. // that corresponds to the section name, which contains the
  1311. // actual cabfile name
  1312. //
  1313. if (SetupFindFirstLine( CabInf, L"Cabs", SectionName, &Context )) {
  1314. //
  1315. // now get that name, allocate and copy into a buffer and
  1316. // return
  1317. //
  1318. b = SetupGetStringField( &Context, 1, CabName, UnicodeChars(CabName), NULL );
  1319. if (b) {
  1320. CacheName = MemAlloc( UnicodeLen(CabName) + 8 );
  1321. if (CacheName) {
  1322. wcscpy( (PWSTR)CacheName, CabName );
  1323. SetupCloseInfFile( CabInf );
  1324. return CacheName;
  1325. }
  1326. }
  1327. }
  1328. }
  1329. }
  1330. } while (SetupFindNextMatchLine( &SectionContext, L"CabFiles", &SectionContext ));
  1331. SetupCloseInfFile( CabInf );
  1332. return NULL;
  1333. }
  1334. DWORD
  1335. SfcQueueLookForFile(
  1336. IN const PSOURCE_MEDIA sm,
  1337. IN const PSOURCE_INFO si,
  1338. IN PCWSTR fname,
  1339. OUT PWSTR NewPath
  1340. )
  1341. /*++
  1342. Routine Description:
  1343. Routine looks for the specified file. If the file isn't
  1344. at the specified location, we start looking around for the file.
  1345. We look on the cdrom and the network location if present. If we
  1346. don't find it there, then we strip off the platform extension as
  1347. a hack workaround for broken release servers that don't match what
  1348. layout.inf says about the source layout information
  1349. Arguments:
  1350. sm - pointer to SOURCE_MEDIA structure which desribes the media the
  1351. file should be on
  1352. si - pointer to a SOURCE_INFO structure which describes the media the
  1353. file should be on
  1354. fname - the full pathname to the file we're looking for
  1355. NewPath - if we find the file somewhere else besides the actual media
  1356. path, this is filled in with the correct path
  1357. Return Value:
  1358. returns a FILEOP_* setupapi code
  1359. --*/
  1360. {
  1361. DWORD PathType;
  1362. WCHAR buf[MAX_PATH];
  1363. WCHAR cdrom[16];
  1364. PWSTR s;
  1365. BOOL CDRomIsPresent;
  1366. ASSERT(fname != NULL);
  1367. ASSERT((sm != NULL) && (si != NULL));
  1368. //
  1369. // first look to see if the file is on the specified media
  1370. //
  1371. if (SfcIsFileOnMedia( fname )) {
  1372. return FILEOP_DOIT;
  1373. }
  1374. //
  1375. // get the (first) cdrom drive path
  1376. //
  1377. CDRomIsPresent = SfcGetCdRomDrivePath( cdrom );
  1378. //
  1379. // get the path type for the specified source path
  1380. //
  1381. PathType = SfcGetPathType( (PWSTR)sm->SourcePath, buf,UnicodeChars(buf) );
  1382. //
  1383. // ok the file is not on the specified media, but it
  1384. // could be located in a cab file. the tag file *MAY*
  1385. // contain the cab file name so check to see if the tag file
  1386. // name is a cab file and then look to see if the cab is
  1387. // present.
  1388. //
  1389. if (sm->Tagfile) {
  1390. s = wcsrchr( sm->Tagfile, L'.' );
  1391. if (s && _wcsicmp( s, L".cab" ) == 0) {
  1392. BuildPathForFile(
  1393. sm->SourcePath,
  1394. NULL,
  1395. sm->Tagfile,
  1396. SFC_INCLUDE_SUBDIRECTORY,
  1397. SFC_INCLUDE_ARCHSUBDIR,
  1398. buf,
  1399. UnicodeChars(buf) );
  1400. if (SfcIsFileOnMedia( buf )) {
  1401. return FILEOP_DOIT;
  1402. }
  1403. if (PathType == PATH_NETWORK || PathType == PATH_UNC) {
  1404. //
  1405. // try removing the platform dir from the path
  1406. // as a helper for the internal msft build servers
  1407. //
  1408. wcscpy( buf, sm->SourcePath );
  1409. s = wcsrchr( buf, L'\\' );
  1410. if (s && _wcsicmp(s,PLATFORM_DIR)==0) {
  1411. *s = 0;
  1412. pSetupConcatenatePaths( buf, sm->Tagfile, UnicodeChars(buf), NULL );
  1413. if (SfcIsFileOnMedia( buf )) {
  1414. wcscpy( NewPath, sm->SourcePath );
  1415. s = wcsrchr( NewPath, L'\\' );
  1416. *s = 0;
  1417. return FILEOP_NEWPATH;
  1418. }
  1419. }
  1420. //
  1421. // the cab file is not on the specified network
  1422. // source path so now look on the cdrom
  1423. //
  1424. if (CDRomIsPresent) {
  1425. BuildPathForFile(
  1426. cdrom,
  1427. si->SourcePath,
  1428. sm->Tagfile,
  1429. SFC_INCLUDE_SUBDIRECTORY,
  1430. SFC_INCLUDE_ARCHSUBDIR,
  1431. buf,
  1432. UnicodeChars(buf) );
  1433. if (SfcIsFileOnMedia( buf )) {
  1434. wcscpy( NewPath, buf );
  1435. pSetupConcatenatePaths( NewPath, si->SourcePath, MAX_PATH , NULL );
  1436. return FILEOP_NEWPATH;
  1437. }
  1438. }
  1439. }
  1440. }
  1441. }
  1442. //
  1443. // the file is not located in a cab file and it is not
  1444. // present on the specified meda. if the media
  1445. // is a network share then look on the cd for the file.
  1446. //
  1447. if (PathType == PATH_NETWORK || PathType == PATH_UNC) {
  1448. //
  1449. // try removing the platform dir from the path
  1450. // as a helper for the internal msft build servers
  1451. //
  1452. wcscpy( buf, sm->SourcePath );
  1453. s = wcsrchr( buf, L'\\' );
  1454. if (s && _wcsicmp(s,PLATFORM_DIR)==0) {
  1455. *s = 0;
  1456. pSetupConcatenatePaths( buf, sm->SourceFile, UnicodeChars(buf), NULL );
  1457. if (SfcIsFileOnMedia( buf )) {
  1458. wcscpy( NewPath, sm->SourcePath );
  1459. s = wcsrchr( NewPath, L'\\' );
  1460. *s = 0;
  1461. return FILEOP_NEWPATH;
  1462. }
  1463. }
  1464. }
  1465. //
  1466. // now try the cdrom
  1467. //
  1468. if (CDRomIsPresent) {
  1469. BuildPathForFile(
  1470. cdrom,
  1471. si->SourcePath,
  1472. sm->SourceFile,
  1473. SFC_INCLUDE_SUBDIRECTORY,
  1474. SFC_INCLUDE_ARCHSUBDIR,
  1475. buf,
  1476. UnicodeChars(buf) );
  1477. if (SfcIsFileOnMedia( buf )) {
  1478. wcscpy( NewPath, cdrom );
  1479. pSetupConcatenatePaths( NewPath, si->SourcePath, MAX_PATH, NULL );
  1480. return FILEOP_NEWPATH;
  1481. }
  1482. }
  1483. return FILEOP_ABORT;
  1484. }
  1485. HINF
  1486. SfcOpenInf(
  1487. IN PCWSTR InfName OPTIONAL,
  1488. IN BOOL ExcepPackInf
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. Routine opens the specified INF file. We also appendload any INFs to this
  1493. INF so we have all of the necessary layout information.
  1494. Arguments:
  1495. InfName - Specifies the inf to open. If no inf is specified, we just use
  1496. the os layout file "layout.inf"
  1497. Return Value:
  1498. a valid inf handle on success, else INVALID_HANDLE_VALUE
  1499. --*/
  1500. {
  1501. HINF hInf = INVALID_HANDLE_VALUE;
  1502. WCHAR SourcePath[MAX_PATH];
  1503. PCWSTR InfPath = InfName;
  1504. if (InfName && *InfName) {
  1505. //
  1506. // if this is an exception inf, InfName is a full path so leave it unchanged
  1507. //
  1508. if(!ExcepPackInf)
  1509. {
  1510. InfPath = SourcePath;
  1511. wcscpy( SourcePath, InfDirectory );
  1512. pSetupConcatenatePaths( SourcePath, InfName, UnicodeChars(SourcePath), NULL );
  1513. if (GetFileAttributes( SourcePath ) == (DWORD)-1) {
  1514. DWORD dwSize = ExpandEnvironmentStrings( L"%systemroot%\\system32", SourcePath, UnicodeChars(SourcePath) );
  1515. if(0 == dwSize) {
  1516. return INVALID_HANDLE_VALUE;
  1517. }
  1518. if(dwSize > UnicodeChars(SourcePath)) {
  1519. SetLastError(ERROR_BUFFER_OVERFLOW);
  1520. return INVALID_HANDLE_VALUE;
  1521. }
  1522. pSetupConcatenatePaths( SourcePath, InfName, UnicodeChars(SourcePath), NULL );
  1523. if (GetFileAttributes( SourcePath ) == (DWORD)-1) {
  1524. DebugPrint1( LVL_VERBOSE, L"Required inf missing [%ws]", SourcePath );
  1525. return INVALID_HANDLE_VALUE;
  1526. }
  1527. }
  1528. }
  1529. hInf = SetupOpenInfFile( InfPath, NULL, INF_STYLE_WIN4, NULL );
  1530. if (hInf == INVALID_HANDLE_VALUE) {
  1531. DebugPrint2( LVL_VERBOSE, L"SetupOpenInf failed [%ws], ec=%d", InfPath, GetLastError() );
  1532. return INVALID_HANDLE_VALUE;
  1533. }
  1534. //
  1535. // append-load layout.inf or whatever other layout file the inf wants
  1536. // to load. if this fails it's no big deal, the inf might not have a
  1537. // layout file for instance.
  1538. //
  1539. if (!SetupOpenAppendInfFile( NULL, hInf, NULL)) {
  1540. DebugPrint2( LVL_VERBOSE, L"SetupOpenAppendInfFile failed [%ws], ec=%d", InfPath, GetLastError() );
  1541. }
  1542. } else {
  1543. wcscpy( SourcePath, InfDirectory );
  1544. pSetupConcatenatePaths( SourcePath, L"layout.inf", UnicodeChars(SourcePath), NULL );
  1545. hInf = SetupOpenInfFile( SourcePath, NULL, INF_STYLE_WIN4, NULL );
  1546. if (hInf == INVALID_HANDLE_VALUE) {
  1547. DebugPrint2( LVL_VERBOSE, L"SetupOpenInf failed [%ws], ec=%d", SourcePath, GetLastError() );
  1548. return INVALID_HANDLE_VALUE;
  1549. }
  1550. }
  1551. //
  1552. // Note: major hack-o-rama. Some infs use "34000" and "34001" custom
  1553. // directory ids for the relative source path on x86, so that it
  1554. // resolves to nec98 or i386 at runtime. we emulate the same thing
  1555. // here. If some inf tries to copy to custom dirid 34000 or 34001 then
  1556. // we're busted. It would be a better solution to record these layout infs
  1557. // and their custom dirid mappings so we only set this for the infs we care
  1558. // about and so that we handle any other infs that come up with some other
  1559. // wacky convention without having to rebuild this module.
  1560. //
  1561. SetupSetDirectoryIdEx( hInf, 34000, PLATFORM_DIR, SETDIRID_NOT_FULL_PATH, 0, 0 );
  1562. SetupSetDirectoryIdEx( hInf, 34001, PLATFORM_DIR, SETDIRID_NOT_FULL_PATH, 0, 0 );
  1563. return hInf;
  1564. }
  1565. BOOL
  1566. SfcGetSourceInformation(
  1567. IN PCWSTR SourceFileName,
  1568. IN PCWSTR InfName, OPTIONAL
  1569. IN BOOL ExcepPackFile,
  1570. OUT PSOURCE_INFO si
  1571. )
  1572. /*++
  1573. Routine Description:
  1574. Routine retrieves information about a source file and stuffs it into the
  1575. supplied SOURCE_INFO structure.
  1576. Routine opens up a handle to the source's layout file and retreives layout
  1577. information from this inf.
  1578. Arguments:
  1579. SourceFileName - specifies the file to retreive source information for.
  1580. Note that if this file is renamed, we have the source
  1581. filename, not the destination filename.
  1582. InfName - specifies the layout file for the SourceFileName. If NULL,
  1583. assume that the layout file is layout.inf.
  1584. si - pointer to SOURCE_INFO structure that gets filled in with
  1585. information about the specified file.
  1586. Return Value:
  1587. if TRUE, we successfully retrieved the source information about this file
  1588. --*/
  1589. {
  1590. BOOL b = FALSE;
  1591. HINF hInf = INVALID_HANDLE_VALUE;
  1592. PCWSTR DriverCabName = NULL;
  1593. WCHAR SetupAPIFlags[32];
  1594. ASSERT((si != NULL) && (SourceFileName != NULL));
  1595. //
  1596. // if an exception file, the inf name must not be empty as we need it for the source path
  1597. //
  1598. ASSERT(!ExcepPackFile || (InfName != NULL && *InfName != 0));
  1599. wcsncpy(si->SourceFileName, SourceFileName, MAX_PATH);
  1600. //
  1601. // open the necessary inf file
  1602. //
  1603. hInf = SfcOpenInf( InfName, ExcepPackFile );
  1604. if (hInf == INVALID_HANDLE_VALUE) {
  1605. goto exit;
  1606. }
  1607. //
  1608. // get the source file location
  1609. //
  1610. b = SetupGetSourceFileLocation(
  1611. hInf,
  1612. NULL,
  1613. SourceFileName,
  1614. &si->SourceId,
  1615. NULL,
  1616. 0,
  1617. NULL
  1618. );
  1619. if (!b) {
  1620. DebugPrint1( LVL_VERBOSE, L"SetupGetSourceFileLocation failed, ec=%d", GetLastError() );
  1621. goto exit;
  1622. }
  1623. //
  1624. // get the following source file information:
  1625. // 1) path
  1626. // 2) tag file name
  1627. // 3) flags
  1628. // 4) description (for display to the user if necessary)
  1629. //
  1630. b = SetupGetSourceInfo(
  1631. hInf,
  1632. si->SourceId,
  1633. SRCINFO_PATH,
  1634. si->SourcePath,
  1635. UnicodeChars(si->SourcePath),
  1636. NULL
  1637. );
  1638. if (!b) {
  1639. DebugPrint1( LVL_VERBOSE, L"SetupGetSourceInfo failed, ec=%d", GetLastError() );
  1640. goto exit;
  1641. }
  1642. b = SetupGetSourceInfo(
  1643. hInf,
  1644. si->SourceId,
  1645. SRCINFO_TAGFILE,
  1646. si->TagFile,
  1647. UnicodeChars(si->TagFile),
  1648. NULL
  1649. );
  1650. if (!b) {
  1651. DebugPrint1( LVL_VERBOSE, L"SetupGetSourceInfo failed, ec=%d", GetLastError() );
  1652. goto exit;
  1653. }
  1654. b = SetupGetSourceInfo(
  1655. hInf,
  1656. si->SourceId,
  1657. SRCINFO_DESCRIPTION,
  1658. si->Description,
  1659. UnicodeChars(si->Description),
  1660. NULL
  1661. );
  1662. if (!b) {
  1663. DebugPrint1( LVL_VERBOSE, L"SetupGetSourceInfo failed, ec=%d", GetLastError() );
  1664. goto exit;
  1665. }
  1666. b = SetupGetSourceInfo(
  1667. hInf,
  1668. si->SourceId,
  1669. SRCINFO_FLAGS,
  1670. SetupAPIFlags,
  1671. UnicodeChars(SetupAPIFlags),
  1672. NULL
  1673. );
  1674. if (!b) {
  1675. DebugPrint1( LVL_VERBOSE, L"SetupGetSourceInfo failed, ec=%d", GetLastError() );
  1676. goto exit;
  1677. }
  1678. si->SetupAPIFlags = wcstoul(SetupAPIFlags, NULL, 0);
  1679. //
  1680. // set the source root path
  1681. //
  1682. if(!ExcepPackFile)
  1683. {
  1684. DriverCabName = IsFileInDriverCache( SourceFileName );
  1685. }
  1686. if (DriverCabName) {
  1687. si->Flags |= SI_FLAG_USEDRIVER_CACHE;
  1688. wcscpy( si->DriverCabName, DriverCabName );
  1689. //
  1690. // build up the full path to the driver cabinet file
  1691. //
  1692. BuildPathForFile(
  1693. DriverCacheSourcePath,
  1694. PLATFORM_DIR,
  1695. DriverCabName,
  1696. SFC_INCLUDE_SUBDIRECTORY,
  1697. SFC_INCLUDE_ARCHSUBDIR,
  1698. si->SourceRootPath,
  1699. UnicodeChars(si->SourceRootPath) );
  1700. //
  1701. // If the cabinet isn't present, we must use the os source path for the
  1702. // cabinet file. We first try the service pack source path and look
  1703. // for the cabfile there. If it's there, we use that path, else we
  1704. // use the OS Source Path.
  1705. //
  1706. if (GetFileAttributes( si->SourceRootPath ) == (DWORD)-1) {
  1707. SfcGetSourcePath(TRUE,si->SourceRootPath);
  1708. pSetupConcatenatePaths(
  1709. si->SourceRootPath,
  1710. DriverCabName,
  1711. UnicodeChars(si->SourceRootPath),
  1712. NULL );
  1713. if (GetFileAttributes( si->SourceRootPath ) == (DWORD)-1) {
  1714. SfcGetSourcePath(FALSE,si->SourceRootPath);
  1715. } else {
  1716. SfcGetSourcePath(TRUE,si->SourceRootPath);
  1717. }
  1718. } else {
  1719. wcsncpy(
  1720. si->SourceRootPath,
  1721. DriverCacheSourcePath,
  1722. UnicodeChars(si->SourceRootPath) );
  1723. }
  1724. MemFree( (PWSTR)DriverCabName );
  1725. DriverCabName = NULL;
  1726. } else if(ExcepPackFile) {
  1727. PCWSTR sz;
  1728. sz = wcsrchr(InfName, L'\\');
  1729. ASSERT(sz != NULL);
  1730. RtlCopyMemory(si->SourceRootPath, InfName, (PBYTE) sz - (PBYTE) InfName);
  1731. si->SourceRootPath[sz - InfName] = 0;
  1732. } else {
  1733. SfcGetSourcePath((si->SetupAPIFlags & 1) != 0, si->SourceRootPath);
  1734. }
  1735. b = TRUE;
  1736. exit:
  1737. if (hInf != INVALID_HANDLE_VALUE) {
  1738. SetupCloseInfFile( hInf );
  1739. }
  1740. return b;
  1741. }
  1742. #define SFC_BAD_CREDENTIALS(rc) \
  1743. ((rc) == ERROR_ACCESS_DENIED || (rc) == ERROR_LOGON_FAILURE || (rc) == ERROR_NO_SUCH_USER || \
  1744. (rc) == ERROR_BAD_USERNAME || (rc) == ERROR_INVALID_PASSWORD || (rc) == ERROR_NO_SUCH_LOGON_SESSION || \
  1745. (rc) == ERROR_DOWNGRADE_DETECTED)
  1746. DWORD
  1747. IsDirAccessible(
  1748. IN PCWSTR Path
  1749. )
  1750. {
  1751. DWORD dwRet = ERROR_SUCCESS;
  1752. HANDLE hDir = CreateFile(
  1753. Path,
  1754. GENERIC_READ,
  1755. FILE_SHARE_READ,
  1756. NULL,
  1757. OPEN_EXISTING,
  1758. FILE_FLAG_BACKUP_SEMANTICS,
  1759. NULL
  1760. );
  1761. if(hDir != INVALID_HANDLE_VALUE) {
  1762. CloseHandle(hDir);
  1763. } else {
  1764. dwRet = GetLastError();
  1765. }
  1766. return dwRet;
  1767. }
  1768. DWORD
  1769. EstablishConnection(
  1770. IN HWND hWndParent,
  1771. IN PCWSTR RemoteName,
  1772. IN BOOL AllowUI
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. Routine establishes a connection to the specifed remote name given some
  1777. wierd horkin path
  1778. Arguments:
  1779. hWndParent - specifies parent hwnd that can be used if AllowUI is true.
  1780. RemoteName - specifies a UNC path to connect to.
  1781. AllowUI - specifies if we allow the CONNECT_INTERACTIVE flag
  1782. when connecting to a network share
  1783. Return Value:
  1784. win32 error code indicating outcome.
  1785. --*/
  1786. {
  1787. WCHAR buf[MAX_PATH], RestofPath[MAX_PATH];
  1788. NETRESOURCE nr;
  1789. DWORD rc;
  1790. BOOL Impersonating = FALSE;
  1791. ASSERT(RemoteName != NULL && RemoteName[0] != 0);
  1792. //
  1793. // create a string that is basically just "\\server\share"
  1794. // even if the passed in string contains a unc path to a file
  1795. // or a directory.
  1796. //
  1797. if (!SfcGetConnectionName(RemoteName, buf, UnicodeChars(buf), RestofPath, UnicodeChars(RestofPath), TRUE, &Impersonating)) {
  1798. DWORD lasterror = GetLastError();
  1799. DebugPrint1( LVL_VERBOSE, L"SfcGetConnectionName failed, ec=%d", lasterror );
  1800. return(lasterror);
  1801. }
  1802. pSetupConcatenatePaths( buf, RestofPath, UnicodeChars(buf), NULL );
  1803. //
  1804. // try to establish a connection to the server
  1805. //
  1806. nr.dwScope = 0;
  1807. nr.dwType = RESOURCETYPE_DISK;
  1808. nr.dwDisplayType = 0;
  1809. nr.dwUsage = 0;
  1810. nr.lpLocalName = NULL;
  1811. nr.lpRemoteName = buf;
  1812. nr.lpComment = NULL;
  1813. nr.lpProvider = NULL;
  1814. //
  1815. // try to establish a connection to the server
  1816. //
  1817. rc = WNetAddConnection2( &nr, NULL, NULL, CONNECT_TEMPORARY );
  1818. //
  1819. // The directory could not be accessible even if the connection succeeded
  1820. //
  1821. if(ERROR_SUCCESS == rc) {
  1822. rc = IsDirAccessible(buf);
  1823. }
  1824. //
  1825. // Try again in the context of the currently logged-on user
  1826. //
  1827. if(!Impersonating && SFC_BAD_CREDENTIALS(rc) && hUserToken != NULL && ImpersonateLoggedOnUser(hUserToken)) {
  1828. Impersonating = TRUE;
  1829. rc = WNetAddConnection2( &nr, NULL, NULL, CONNECT_TEMPORARY );
  1830. if(ERROR_SUCCESS == rc) {
  1831. rc = IsDirAccessible(buf);
  1832. }
  1833. }
  1834. //
  1835. // If this failed, there's no need to impersonate anymore; we always prompt for credentials in the system context.
  1836. // If it succeeded, we must keep on impersonating until the end of the queue (when we receive SPFILENOTIFY_ENDQUEUE).
  1837. //
  1838. if(Impersonating && rc != ERROR_SUCCESS) {
  1839. RevertToSelf();
  1840. }
  1841. //
  1842. // if it failed, let's try to bring up UI to allow the connection
  1843. //
  1844. if(SFC_BAD_CREDENTIALS(rc) && AllowUI) {
  1845. HWND hwndDlgParent = hWndParent;
  1846. DWORD RetryCount = 2;
  1847. SetThreadDesktop( hUserDesktop );
  1848. if(NULL == hWndParent)
  1849. {
  1850. //
  1851. // create a parent for the authentication dialog
  1852. // in case of an error, hwndDlgParent will stay NULL; there's nothing much we can do about it
  1853. //
  1854. if(ERROR_SUCCESS == CreateDialogParent(&hwndDlgParent))
  1855. {
  1856. ASSERT(hwndDlgParent != NULL);
  1857. //SetForegroundWindow(hwndDlgParent);
  1858. }
  1859. }
  1860. do {
  1861. rc = WNetAddConnection3(
  1862. hwndDlgParent,
  1863. &nr,
  1864. NULL,
  1865. NULL,
  1866. CONNECT_TEMPORARY | CONNECT_PROMPT | CONNECT_INTERACTIVE );
  1867. if(ERROR_SUCCESS == rc) {
  1868. rc = IsDirAccessible(buf);
  1869. }
  1870. RetryCount -= 1;
  1871. } while ( (rc != ERROR_SUCCESS)
  1872. && (rc != ERROR_CANCELLED)
  1873. && (RetryCount > 0) );
  1874. if(NULL == hWndParent && hwndDlgParent != NULL)
  1875. {
  1876. //
  1877. // we created the parent, so we destroy it
  1878. //
  1879. DestroyWindow(hwndDlgParent);
  1880. }
  1881. if (rc == ERROR_SUCCESS) {
  1882. SFCLoggedOn = TRUE;
  1883. wcsncpy(SFCNetworkLoginLocation,buf,MAX_PATH);
  1884. }
  1885. }
  1886. if ((SFCLoggedOn == FALSE) && (rc == ERROR_SUCCESS)) {
  1887. WNetCancelConnection2( buf, CONNECT_UPDATE_PROFILE, FALSE );
  1888. }
  1889. return rc;
  1890. }