Source code of Windows XP (NT5)
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.

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