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.

9683 lines
278 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract:
  6. This module contains support routines for the NT File Replication Service.
  7. Author:
  8. David A. Orbits (davidor) 25-Mar-1997
  9. Environment:
  10. User Mode Service
  11. Revision History:
  12. --*/
  13. #include <ntreppch.h>
  14. #pragma hdrstop
  15. #include <frs.h>
  16. #include <tablefcn.h>
  17. #include <ntfrsapi.h>
  18. #include <info.h>
  19. #include <sddl.h>
  20. #ifdef SECURITY_WIN32
  21. #include <security.h>
  22. #else
  23. #define SECURITY_WIN32
  24. #include <security.h>
  25. #undef SECURITY_WIN32
  26. #endif
  27. #include "stdarg.h"
  28. #include <accctrl.h>
  29. #include <aclapi.h>
  30. extern PGEN_TABLE ReparseTagTable;
  31. extern PGEN_TABLE ReplicasByGuid;
  32. extern PGEN_TABLE VolSerialNumberToDriveTable;
  33. VOID
  34. FrsBuildVolSerialNumberToDriveTable(
  35. PWCHAR LogicalDrives,
  36. BOOL EmptyTable
  37. );
  38. BOOL
  39. JrnlIsChangeOrderInReplica(
  40. IN PCHANGE_ORDER_ENTRY ChangeOrder,
  41. IN PLONGLONG DirFileID
  42. );
  43. #if 0
  44. LPTSTR
  45. FrsSupInitPath(
  46. OUT LPTSTR OutPath,
  47. IN LPTSTR InPath,
  48. IN ULONG MaxOutPath
  49. )
  50. /*++
  51. Routine Description:
  52. Initialize a directory path string. Add a backslash as needed and
  53. return a pointer to the start of the file part of the output string.
  54. Return NULL if the Output path string is too small.
  55. If InPath is NULL, OutPath is set to NULL and no slash.
  56. Arguments:
  57. OutPath - The output string with the initialized path.
  58. InPath - The supplied input path.
  59. MaxOutPath - The maximum number of charaters that fit in OutPath.
  60. Return Value:
  61. Pointer to the start of the filename part of the output string.
  62. NULL if output string is too small.
  63. --*/
  64. //
  65. // Capture the directory path and add a backslash if necc.
  66. //
  67. {
  68. #undef DEBSUB
  69. #define DEBSUB "FrsSupInitPath:"
  70. ULONG Length;
  71. Length = wcslen(InPath);
  72. if (Length > MaxOutPath) {
  73. return NULL;
  74. }
  75. wcscpy(OutPath, InPath);
  76. if (Length > 0) {
  77. if (OutPath[Length - 1] != COLON_CHAR &&
  78. OutPath[Length - 1] != BACKSLASH_CHAR) {
  79. wcscat(OutPath, L"\\");
  80. Length += 1;
  81. }
  82. }
  83. return &OutPath[Length];
  84. }
  85. #endif 0
  86. LONG
  87. FrsIsParent(
  88. IN PWCHAR Directory,
  89. IN PWCHAR Path
  90. )
  91. /*++
  92. Routine Description:
  93. Is Path a child of Directory or is the Directory a child of the path.
  94. In other words, is the directory represented by Path beneath
  95. the directory hierarchy represented by Directory (or vice-versa).
  96. E.g., c:\a\b is a child of c:\a.
  97. In the case of an exact match, Path is considered a child of
  98. Directory. This routine can be easily spoofed; a better check
  99. using FIDs and volume IDs should be implemented.
  100. Arguments:
  101. Directory
  102. Path
  103. Return Value:
  104. -1 = Path is a child of Directory or Path is the same as Directory
  105. 0 = No relationship
  106. 1 = Directory is a child of Path
  107. --*/
  108. {
  109. #undef DEBSUB
  110. #define DEBSUB "FrsIsParent:"
  111. PWCHAR D;
  112. PWCHAR P;
  113. LONG Result = 0;
  114. PWCHAR IndexPtrDir = NULL;
  115. PWCHAR IndexPtrPath = NULL;
  116. DWORD Colon = 0;
  117. DWORD CloseBrace = 0;
  118. DWORD WStatus;
  119. HANDLE Handle = INVALID_HANDLE_VALUE;
  120. IO_STATUS_BLOCK Iosb;
  121. PFILE_FS_VOLUME_INFORMATION VolumeInfoDir = NULL;
  122. PFILE_FS_VOLUME_INFORMATION VolumeInfoPath = NULL;
  123. DWORD VolumeInfoLength;
  124. NTSTATUS NtStatus;
  125. OBJECT_ATTRIBUTES Obja;
  126. UNICODE_STRING FileName;
  127. ULONG FileAttributes;
  128. ULONG CreateDisposition;
  129. ULONG ShareMode;
  130. //
  131. // Note: This is easily spoofed into giving false negatives.
  132. // Need to improve it to uses FIDs and voluem IDs
  133. //
  134. //
  135. // Defensive; NULL strings or empty strings can't be children/parents
  136. //
  137. if (!Directory || !Path || !*Directory || !*Path) {
  138. return Result;
  139. }
  140. //
  141. // If both the paths are on different volumes then they can not overlap.
  142. //
  143. //
  144. // Open the target symlink. If this is a dos type path name then
  145. // convert it to NtPathName or else use it as it is.
  146. //
  147. if (wcscspn(Directory, L":") == 1) {
  148. WStatus = FrsOpenSourceFileW(&Handle,
  149. Directory,
  150. GENERIC_READ,
  151. FILE_OPEN_FOR_BACKUP_INTENT);
  152. CLEANUP1_WS(4, "++ Could not open %ws; ", Directory, WStatus, RETURN);
  153. } else {
  154. //
  155. // The path already in Nt style. Use it as it is.
  156. //
  157. FileName.Buffer = Directory;
  158. FileName.Length = (USHORT)(wcslen(Directory) * sizeof(WCHAR));
  159. FileName.MaximumLength = (USHORT)(wcslen(Directory) * sizeof(WCHAR));
  160. InitializeObjectAttributes(&Obja,
  161. &FileName,
  162. OBJ_CASE_INSENSITIVE,
  163. NULL,
  164. NULL);
  165. CreateDisposition = FILE_OPEN; // Open existing file
  166. ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  167. FileAttributes = FILE_ATTRIBUTE_NORMAL;
  168. NtStatus = NtCreateFile(&Handle,
  169. GENERIC_READ,
  170. &Obja,
  171. &Iosb,
  172. NULL, // Initial allocation size
  173. FileAttributes,
  174. ShareMode,
  175. CreateDisposition,
  176. FILE_OPEN_FOR_BACKUP_INTENT,
  177. NULL, 0);
  178. WStatus = FrsSetLastNTError(NtStatus);
  179. CLEANUP1_WS(4, "++ Could not open %ws;", Directory, WStatus, RETURN);
  180. }
  181. //
  182. // Get the volume information.
  183. //
  184. VolumeInfoLength = sizeof(FILE_FS_VOLUME_INFORMATION) +
  185. MAXIMUM_VOLUME_LABEL_LENGTH;
  186. VolumeInfoDir = FrsAlloc(VolumeInfoLength);
  187. NtStatus = NtQueryVolumeInformationFile(Handle,
  188. &Iosb,
  189. VolumeInfoDir,
  190. VolumeInfoLength,
  191. FileFsVolumeInformation);
  192. CloseHandle(Handle);
  193. WStatus = FrsSetLastNTError(NtStatus);
  194. CLEANUP1_WS(4,"ERROR - Getting NtQueryVolumeInformationFile for %ws\n", Directory, WStatus, RETURN);
  195. // Open the target symlink. If this is a dos type path name then
  196. // convert it to NtPathName or else use it as it is.
  197. //
  198. if (wcscspn(Path, L":") == 1) {
  199. WStatus = FrsOpenSourceFileW(&Handle,
  200. Path,
  201. GENERIC_READ,
  202. FILE_OPEN_FOR_BACKUP_INTENT);
  203. CLEANUP1_WS(4, "++ Could not open %ws; ", Path, WStatus, RETURN);
  204. } else {
  205. //
  206. // The path already in Nt style. Use it as it is.
  207. //
  208. FileName.Buffer = Path;
  209. FileName.Length = (USHORT)(wcslen(Path) * sizeof(WCHAR));
  210. FileName.MaximumLength = (USHORT)(wcslen(Path) * sizeof(WCHAR));
  211. InitializeObjectAttributes(&Obja,
  212. &FileName,
  213. OBJ_CASE_INSENSITIVE,
  214. NULL,
  215. NULL);
  216. CreateDisposition = FILE_OPEN; // Open existing file
  217. ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  218. FileAttributes = FILE_ATTRIBUTE_NORMAL;
  219. NtStatus = NtCreateFile(&Handle,
  220. GENERIC_READ,
  221. &Obja,
  222. &Iosb,
  223. NULL, // Initial allocation size
  224. FileAttributes,
  225. ShareMode,
  226. CreateDisposition,
  227. FILE_OPEN_FOR_BACKUP_INTENT,
  228. NULL, 0);
  229. WStatus = FrsSetLastNTError(NtStatus);
  230. CLEANUP1_WS(4, "++ Could not open %ws;", Path, WStatus, RETURN);
  231. }
  232. //
  233. // Get the volume information.
  234. //
  235. VolumeInfoLength = sizeof(FILE_FS_VOLUME_INFORMATION) +
  236. MAXIMUM_VOLUME_LABEL_LENGTH;
  237. VolumeInfoPath = FrsAlloc(VolumeInfoLength);
  238. NtStatus = NtQueryVolumeInformationFile(Handle,
  239. &Iosb,
  240. VolumeInfoPath,
  241. VolumeInfoLength,
  242. FileFsVolumeInformation);
  243. WStatus = FrsSetLastNTError(NtStatus);
  244. CLEANUP1_WS(4,"ERROR - Getting NtQueryVolumeInformationFile for %ws\n", Path, WStatus, RETURN);
  245. if (VolumeInfoDir->VolumeSerialNumber != VolumeInfoPath->VolumeSerialNumber) {
  246. goto RETURN;
  247. }
  248. //
  249. // Find the colon. Every path has to either have a colon followed by a '\'
  250. // or it should be of the form. "\??\Volume{60430005-ab47-11d3-8973-806d6172696f}\"
  251. //
  252. Colon = wcscspn(Directory, L":");
  253. if (Colon == wcslen(Directory)) {
  254. //
  255. // Path does not have a colon. It can be of the form
  256. // "\??\Volume{60430005-ab47-11d3-8973-806d6172696f}\"
  257. //
  258. CloseBrace = wcscspn(Directory, L"}");
  259. if (Directory[CloseBrace] != L'}' ||
  260. Directory[CloseBrace + 1] != L'\\') {
  261. Result = 0;
  262. goto RETURN;
  263. }
  264. //
  265. // Copy the path up to 1 past the closing brace as it is. It could be \??\Volume...
  266. // or \\.\Volume... or \\?\Volume.. or some other complex form.
  267. // Start looking for reparse points past the closing brace.
  268. //
  269. IndexPtrDir = &Directory[CloseBrace + 1];
  270. } else {
  271. if (Directory[Colon] != L':' ||
  272. Directory[Colon + 1] != L'\\') {
  273. Result = 0;
  274. goto RETURN;
  275. }
  276. //
  277. // Copy the path up to 1 past the colon as it is. It could be d:\
  278. // or \\.\d:\ or \??\d:\ or some other complex form.
  279. // Start looking for reparse points past the colon.
  280. //
  281. IndexPtrDir = &Directory[Colon + 1];
  282. }
  283. //
  284. // Find the colon. Every path has to either have a colon followed by a '\'
  285. // or it should be of the form. "\??\Volume{60430005-ab47-11d3-8973-806d6172696f}\"
  286. //
  287. Colon = wcscspn(Path, L":");
  288. if (Colon == wcslen(Path)) {
  289. //
  290. // Path does not have a colon. It can be of the form
  291. // "\??\Volume{60430005-ab47-11d3-8973-806d6172696f}\"
  292. //
  293. CloseBrace = wcscspn(Path, L"}");
  294. if (Path[CloseBrace] != L'}' ||
  295. Path[CloseBrace + 1] != L'\\') {
  296. Result = 0;
  297. goto RETURN;
  298. }
  299. //
  300. // Copy the path up to 1 past the closing brace as it is. It could be \??\Volume...
  301. // or \\.\Volume... or \\?\Volume.. or some other complex form.
  302. // Start looking for reparse points past the closing brace.
  303. //
  304. IndexPtrPath = &Path[CloseBrace + 1];
  305. } else {
  306. if (Path[Colon] != L':' ||
  307. Path[Colon + 1] != L'\\') {
  308. Result = 0;
  309. goto RETURN;
  310. }
  311. //
  312. // Copy the path up to 1 past the colon as it is. It could be d:\
  313. // or \\.\d:\ or \??\d:\ or some other complex form.
  314. // Start looking for reparse points past the colon.
  315. //
  316. IndexPtrPath = &Path[Colon + 1];
  317. }
  318. //
  319. // Break at the first non-matching wchar (collapse dup \s)
  320. //
  321. for (D = IndexPtrDir, P = IndexPtrPath; *P && *D; ++P, ++D) {
  322. //
  323. // Skip dup \s
  324. //
  325. while (*P == L'\\' && *(P + 1) == L'\\') {
  326. ++P;
  327. }
  328. while (*D == L'\\' && *(D + 1) == L'\\') {
  329. ++D;
  330. }
  331. if (towlower(*P) != towlower(*D)) {
  332. break;
  333. }
  334. }
  335. //
  336. // Exact match; consider Path a child of Directory
  337. //
  338. if (!*D && !*P) {
  339. Result = -1;
  340. goto RETURN;
  341. }
  342. //
  343. // Collapse dup \s
  344. //
  345. while (*P == L'\\' && *(P + 1) == L'\\') {
  346. ++P;
  347. }
  348. while (*D == L'\\' && *(D + 1) == L'\\') {
  349. ++D;
  350. }
  351. //
  352. // Path is a child of Directory
  353. //
  354. if ((!*D || (*D == L'\\' && !*(D + 1))) &&
  355. (!*P || *P == L'\\' || (P != Path && *(P - 1) == L'\\'))) {
  356. Result = -1;
  357. goto RETURN;
  358. }
  359. //
  360. // Directory is a child of Path
  361. //
  362. if ((!*P || (*P == L'\\' && !*(P + 1))) &&
  363. (!*D || *D == L'\\' || (D != Directory && *(D - 1) == L'\\'))) {
  364. Result = 1;
  365. goto RETURN;
  366. }
  367. //
  368. // no relationship
  369. //
  370. RETURN:
  371. FRS_CLOSE(Handle);
  372. FrsFree(VolumeInfoDir);
  373. FrsFree(VolumeInfoPath);
  374. return Result;
  375. }
  376. #if 0
  377. ULONG FrsSupMakeFullFileName(
  378. IN PREPLICA Replica,
  379. IN PTCHAR RelativeName,
  380. OUT PTCHAR FullName,
  381. IN ULONG MaxLength
  382. )
  383. {
  384. /*++
  385. Routine Description:
  386. Build a full file name for a given data source with the supplied
  387. RelativeName.
  388. Arguments:
  389. Replica - The replica tree to provide the root path.
  390. RelativeName - The relative file name from the root of the data source.
  391. FullName - The returned full path name of the file.
  392. MaxLength - The maximum number of characters that fit in FullName.
  393. Return Value:
  394. Status - ERROR_BAD_PATHNAME if the name is too long.
  395. --*/
  396. #undef DEBSUB
  397. #define DEBSUB "FrsSupMakeFullFileName:"
  398. ULONG Length, TotalLength;
  399. PTCHAR pFilePart;
  400. PCONFIG_TABLE_RECORD ConfigRecord;
  401. ConfigRecord = (PCONFIG_TABLE_RECORD) (Replica->ConfigTable.pDataRecord);
  402. //
  403. // Init the file name string with the DataSource root path.
  404. //
  405. pFilePart = FrsSupInitPath( FullName, ConfigRecord->FSRootPath, MaxLength);
  406. if (pFilePart == NULL) {
  407. return ERROR_BAD_PATHNAME;
  408. }
  409. Length = wcslen(RelativeName);
  410. TotalLength = Length + wcslen(FullName);
  411. if (TotalLength > MaxLength) {
  412. return ERROR_BAD_PATHNAME;
  413. }
  414. //
  415. // Append the relative file name to the end of the base path.
  416. //
  417. wcscpy(pFilePart, RelativeName);
  418. return ERROR_SUCCESS;
  419. }
  420. #endif 0
  421. ULONG
  422. FrsForceDeleteFile(
  423. PTCHAR DestName
  424. )
  425. /*++
  426. Routine Description:
  427. Support routine to delete File System Files. Returns success if file
  428. is not there or if it was there and was deleted.
  429. Arguments:
  430. DestName - The fully qualified file name.
  431. Return Value:
  432. Win32 Status
  433. --*/
  434. {
  435. #undef DEBSUB
  436. #define DEBSUB "FrsForceDeleteFile:"
  437. ULONG WStatus = ERROR_SUCCESS;
  438. ULONG FileAttributes;
  439. if (!DeleteFile(DestName)) {
  440. WStatus = GetLastError();
  441. if ((WStatus == ERROR_FILE_NOT_FOUND) ||
  442. (WStatus == ERROR_PATH_NOT_FOUND)) {
  443. return ERROR_SUCCESS;
  444. }
  445. FileAttributes = GetFileAttributes(DestName);
  446. if ((FileAttributes != 0xFFFFFFFF) &&
  447. (FileAttributes & NOREPL_ATTRIBUTES)) {
  448. //
  449. // Reset file attributes to allow delete.
  450. //
  451. SetFileAttributes(DestName,
  452. FILE_ATTRIBUTE_NORMAL |
  453. (FileAttributes & ~NOREPL_ATTRIBUTES));
  454. }
  455. if (!DeleteFile(DestName)) {
  456. WStatus = GetLastError();
  457. DPRINT1_WS(4, "++ WARN - cannot delete %ws;", DestName, WStatus);
  458. }
  459. }
  460. return WStatus;
  461. }
  462. HANDLE
  463. FrsCreateEvent(
  464. IN BOOL ManualReset,
  465. IN BOOL InitialState
  466. )
  467. /*++
  468. Routine Description:
  469. Support routine to create an event.
  470. Arguments:
  471. ManualReset - TRUE if ResetEvent is required
  472. InitialState - TRUE if signaled
  473. Return Value:
  474. Address of the created event handle.
  475. --*/
  476. {
  477. #undef DEBSUB
  478. #define DEBSUB "FrsCreateEvent:"
  479. HANDLE Handle;
  480. Handle = CreateEvent(NULL, ManualReset, InitialState, NULL);
  481. if (!HANDLE_IS_VALID(Handle)) {
  482. RaiseException(ERROR_INVALID_HANDLE, 0, 0, NULL);
  483. }
  484. return Handle;
  485. }
  486. HANDLE
  487. FrsCreateWaitableTimer(
  488. IN BOOL ManualReset
  489. )
  490. /*++
  491. Routine Description:
  492. Support routine to create a waitable timer.
  493. Arguments:
  494. ManualReset - TRUE if not synchronization timer
  495. Return Value:
  496. Address of the created waitable timer handle.
  497. --*/
  498. {
  499. #undef DEBSUB
  500. #define DEBSUB "FrsCreateWaitableTimer:"
  501. HANDLE Handle;
  502. Handle = CreateWaitableTimer(NULL, ManualReset, NULL);
  503. if (!HANDLE_IS_VALID(Handle)) {
  504. RaiseException(ERROR_INVALID_HANDLE, 0, 0, NULL);
  505. }
  506. return Handle;
  507. }
  508. ULONG
  509. FrsUuidCreate(
  510. OUT GUID *Guid
  511. )
  512. /*++
  513. Routine Description:
  514. Frs wrapper on UuidCreate() to generate an exception if we fail
  515. to get correctly formed Guid. In particular UuidCreate can have
  516. problems getting the network address.
  517. RPC_S_OK - The operation completed successfully.
  518. RPC_S_UUID_NO_ADDRESS - We were unable to obtain the ethernet or
  519. token ring address for this machine.
  520. RPC_S_UUID_LOCAL_ONLY - On NT & Chicago if we can't get a
  521. network address. This is a warning to the user, the
  522. UUID is still valid, it just may not be unique on other machines.
  523. RPC_S_OUT_OF_MEMORY - Returned as needed.
  524. Arguments:
  525. Guid - Pointer to returned guid.
  526. Return Value:
  527. FrsStatus
  528. --*/
  529. {
  530. #undef DEBSUB
  531. #define DEBSUB "FrsUuidCreate:"
  532. DWORD MsgBufSize;
  533. WCHAR MsgBuf[MAX_PATH + 1];
  534. RPC_STATUS RpcStatusFromUuidCreate;
  535. RpcStatusFromUuidCreate = UuidCreate(Guid);
  536. if (RpcStatusFromUuidCreate == RPC_S_OK) {
  537. return FrsErrorSuccess;
  538. }
  539. DPRINT_WS(0, "ERROR - Failed to get GUID.", RpcStatusFromUuidCreate);
  540. if (RpcStatusFromUuidCreate == RPC_S_UUID_NO_ADDRESS) {
  541. DPRINT(0, "++ UuidCreate() returned RPC_S_UUID_NO_ADDRESS.\n");
  542. } else
  543. if (RpcStatusFromUuidCreate == RPC_S_UUID_LOCAL_ONLY) {
  544. DPRINT(0, "++ UuidCreate() returned RPC_S_UUID_LOCAL_ONLY.\n");
  545. } else
  546. if (RpcStatusFromUuidCreate == RPC_S_OUT_OF_MEMORY) {
  547. DPRINT(0, "++ UuidCreate() returned RPC_S_OUT_OF_MEMORY.\n");
  548. }
  549. //
  550. // Format the error code
  551. //
  552. MsgBufSize = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  553. FORMAT_MESSAGE_MAX_WIDTH_MASK,
  554. NULL,
  555. RpcStatusFromUuidCreate,
  556. 0,
  557. MsgBuf,
  558. MAX_PATH + 1,
  559. NULL);
  560. //
  561. // No message; use the status code
  562. //
  563. if (!MsgBufSize) {
  564. swprintf(MsgBuf, L"%d (0x%08x)", RpcStatusFromUuidCreate, RpcStatusFromUuidCreate);
  565. }
  566. //
  567. // This is very bad. Any member that can't generate proper GUIDs is
  568. // busted.
  569. //
  570. // Shutdown with an event log message
  571. //
  572. EPRINT2(EVENT_FRS_CANNOT_CREATE_UUID, ComputerName, MsgBuf);
  573. //
  574. // EXIT BECAUSE THE CALLERS CANNOT HANDLE THIS ERROR.
  575. //
  576. DPRINT(0, ":S: NTFRS IS EXITING W/O CLEANUP! SERVICE CONTROLLER RESTART EXPECTED.\n");
  577. DEBUG_FLUSH();
  578. exit(RpcStatusFromUuidCreate);
  579. return FrsErrorInvalidGuid;
  580. }
  581. LONG
  582. FrsGuidCompare (
  583. IN GUID *Guid1,
  584. IN GUID *Guid2
  585. )
  586. /*++
  587. Routine Description:
  588. Do a simple, straight unsigned compare of two GUIDs.
  589. UuidCompare doesn't do this. I don't know what kind of comparison it
  590. does.
  591. Arguments:
  592. Guid1 - The first Guid
  593. Guid2 - The second Guid.
  594. Return Value:
  595. Result: -1 if Guid1 < Guid2
  596. 0 if Guid1 = Guid2
  597. +1 if Guid1 > Guid2
  598. --*/
  599. {
  600. #undef DEBSUB
  601. #define DEBSUB "FrsGuidCompare:"
  602. PULONG p1 = (PULONG) Guid1;
  603. PULONG p2 = (PULONG) Guid2;
  604. p1 += 4;
  605. p2 += 4;
  606. while (p1 != (PVOID) Guid1) {
  607. p1 -= 1;
  608. p2 -= 1;
  609. if (*p1 > *p2) {
  610. return 1;
  611. }
  612. if (*p1 < *p2) {
  613. return -1;
  614. }
  615. }
  616. return 0;
  617. }
  618. VOID
  619. FrsNowAsFileTime(
  620. IN PLONGLONG Now
  621. )
  622. /*++
  623. Routine Description:
  624. Return the current time as a filetime in longlong format.
  625. Arguments:
  626. Now - address of longlong to receive current time.
  627. Return Value:
  628. Fill in Now with current file time
  629. --*/
  630. {
  631. #undef DEBSUB
  632. #define DEBSUB "FrsNowAsFileTime:"
  633. FILETIME FileTime;
  634. GetSystemTimeAsFileTime(&FileTime);
  635. COPY_TIME(Now, &FileTime);
  636. }
  637. char *Days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  638. char *Months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  639. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  640. VOID
  641. FileTimeToString(
  642. IN FILETIME *FileTime,
  643. OUT PCHAR Buffer
  644. )
  645. /*++
  646. Routine Description:
  647. Convert a FileTime (UTC time) to an ANSI date/time string in the
  648. local time zone.
  649. Arguments:
  650. Time - ptr to a FILETIME
  651. Str - a string of at least TIME_STRING_LENGTH bytes to receive the time.
  652. Return Value:
  653. None
  654. --*/
  655. {
  656. #undef DEBSUB
  657. #define DEBSUB "FileTimeToString:"
  658. FILETIME LocalFileTime;
  659. SYSTEMTIME SystemTime;
  660. Buffer[0] = '\0';
  661. if (FileTime->dwHighDateTime != 0 || FileTime->dwLowDateTime != 0) {
  662. if (!FileTimeToLocalFileTime(FileTime, &LocalFileTime) ||
  663. !FileTimeToSystemTime(&LocalFileTime, &SystemTime)) {
  664. strcpy(Buffer, "Time???");
  665. return;
  666. }
  667. if (_snprintf(Buffer, TIME_STRING_LENGTH, "%s %s %2d, %4d %02d:%02d:%02d",
  668. Days[SystemTime.wDayOfWeek],Months[SystemTime.wMonth - 1],
  669. SystemTime.wDay,SystemTime.wYear,SystemTime.wHour,
  670. SystemTime.wMinute,SystemTime.wSecond) < 0) {
  671. Buffer[TIME_STRING_LENGTH - 1] ='\0';
  672. }
  673. }
  674. return;
  675. }
  676. VOID
  677. FileTimeToStringClockTime(
  678. IN FILETIME *FileTime,
  679. OUT PCHAR Buffer
  680. )
  681. /*++
  682. Routine Description:
  683. Convert a FileTime (UTC time) to an ANSI time string in the
  684. local time zone.
  685. Arguments:
  686. Time - ptr to a FILETIME
  687. Str - a string to hold hh:mm:ss\0. (9 bytes min.)
  688. Return Value:
  689. None
  690. --*/
  691. {
  692. #undef DEBSUB
  693. #define DEBSUB "FileTimeToStringClockTime:"
  694. FILETIME LocalFileTime;
  695. SYSTEMTIME SystemTime;
  696. Buffer[0] = '\0';
  697. if (FileTime->dwHighDateTime == 0 && FileTime->dwLowDateTime == 0) {
  698. strcpy(Buffer, "??:??:??");
  699. return;
  700. }
  701. if (!FileTimeToLocalFileTime(FileTime, &LocalFileTime) ||
  702. !FileTimeToSystemTime(&LocalFileTime, &SystemTime)) {
  703. strcpy(Buffer, "??:??:??");
  704. return;
  705. }
  706. if (_snprintf(Buffer, 9, "%02d:%02d:%02d",
  707. SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond) < 0) {
  708. Buffer[9-1] = '\0';
  709. }
  710. }
  711. DWORD
  712. GeneralizedTimeToSystemTime(
  713. IN PWCHAR szTime,
  714. OUT PSYSTEMTIME psysTime
  715. )
  716. /*++
  717. Routine Description:
  718. Converts a generalized time string to the equivalent system time.
  719. (Taken from the repadmin DS code. converted to swscanf)
  720. Parameters:
  721. szTime - [Supplies] This is string containing generalized time.
  722. psysTime - [Returns] This is the SYSTEMTIME struct to be returned.
  723. Return Value:
  724. Win 32 Error code, note could only result from invalid parameter.
  725. --*/
  726. {
  727. ULONG len;
  728. ULONG yr=0, mo=0, day=0, hr=0, min=0, sec=0;
  729. LONG Fields;
  730. //
  731. // param sanity
  732. //
  733. if ((szTime == NULL) || (psysTime == NULL)) {
  734. return ERROR_INVALID_PARAMETER;
  735. }
  736. len = wcslen(szTime);
  737. if( len < 15 || szTime[14] != '.') {
  738. return ERROR_INVALID_PARAMETER;
  739. }
  740. // initialize
  741. memset(psysTime, 0, sizeof(SYSTEMTIME));
  742. //
  743. // yyyymmddhhmmss.
  744. //
  745. Fields = swscanf(szTime, L"%04d%02d%02d%02d%02d%02d",
  746. &yr, &mo, &day, &hr, &min, &sec);
  747. psysTime->wYear = (USHORT) yr;
  748. psysTime->wMonth = (USHORT) mo;
  749. psysTime->wDay = (USHORT) day;
  750. psysTime->wHour = (USHORT) hr;
  751. psysTime->wMinute = (USHORT) min;
  752. psysTime->wSecond = (USHORT) sec;
  753. if (Fields != 6) {
  754. DPRINT2(1, "Time convert error on '%ws', Fields = %d\n", szTime, Fields);
  755. DPRINT6(1, "Time results: '%d' '%d' '%d' '%d' '%d' '%d' \n",
  756. yr, mo, day, hr, min, sec);
  757. }
  758. return (Fields == 6 ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER);
  759. }
  760. VOID
  761. FormatGeneralizedTime(
  762. IN PWCHAR GTimeStr,
  763. IN ULONG Length,
  764. OUT PCHAR Buffer
  765. )
  766. /*++
  767. Routine Description:
  768. Convert a generalized time string to a printable form.
  769. (taken from the DS code)
  770. Arguments:
  771. GTimeStr -- Generalized time string from DS.
  772. Length - Size of buffer in bytes.
  773. Buffer - buffer with returned string.
  774. Return Value:
  775. Buffer containing printable string.
  776. --*/
  777. {
  778. #undef DEBSUB
  779. #define DEBSUB "FormatGeneralizedTime:"
  780. TIME_ZONE_INFORMATION tz;
  781. DWORD WStatus;
  782. BOOL bstatus;
  783. SYSTEMTIME sysTime, localTime;
  784. if ((Length < 12) || (Buffer == NULL) || (GTimeStr == NULL)) {
  785. return;
  786. }
  787. strcpy(Buffer, "<unknown>");
  788. GeneralizedTimeToSystemTime(GTimeStr, &sysTime);
  789. WStatus = GetTimeZoneInformation(&tz);
  790. if ( WStatus == TIME_ZONE_ID_INVALID ) {
  791. DPRINT_WS(1, "Cannot format time field. ", GetLastError());
  792. } else {
  793. bstatus = SystemTimeToTzSpecificLocalTime(
  794. (WStatus == TIME_ZONE_ID_UNKNOWN) ? NULL : &tz,
  795. &sysTime,
  796. &localTime );
  797. if ( bstatus ) {
  798. if ( _snprintf(Buffer, Length, "%d/%d/%d %d:%d:%d %S %S [%d]",
  799. localTime.wMonth, localTime.wDay, localTime.wYear,
  800. localTime.wHour, localTime.wMinute, localTime.wSecond,
  801. tz.StandardName, tz.DaylightName, tz.Bias) < 0) {
  802. Buffer[Length - 1]='\0';
  803. }
  804. } else {
  805. if (_snprintf(Buffer, Length, "%d/%d/%d %d:%d:%d UNC",
  806. localTime.wMonth, localTime.wDay, localTime.wYear,
  807. localTime.wHour, localTime.wMinute, localTime.wSecond) < 0) {
  808. Buffer[Length - 1]='\0';
  809. }
  810. }
  811. }
  812. }
  813. VOID
  814. GuidToStr(
  815. IN GUID *pGuid,
  816. OUT PCHAR s
  817. )
  818. /*++
  819. Routine Description:
  820. Convert a GUID to a string.
  821. Based on code from Mac McLain.
  822. Arguments:
  823. pGuid - ptr to the GUID.
  824. s - The output character buffer.
  825. Must be at least GUID_CHAR_LEN (36 bytes) long.
  826. Function Return Value:
  827. None.
  828. --*/
  829. {
  830. #undef DEBSUB
  831. #define DEBSUB "GuidToStr:"
  832. if (pGuid != NULL) {
  833. sprintf(s, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
  834. pGuid->Data1,
  835. pGuid->Data2,
  836. pGuid->Data3,
  837. pGuid->Data4[0],
  838. pGuid->Data4[1],
  839. pGuid->Data4[2],
  840. pGuid->Data4[3],
  841. pGuid->Data4[4],
  842. pGuid->Data4[5],
  843. pGuid->Data4[6],
  844. pGuid->Data4[7]);
  845. } else {
  846. sprintf(s, "<ptr-null>");
  847. }
  848. }
  849. VOID
  850. GuidToStrW(
  851. IN GUID *pGuid,
  852. OUT PWCHAR ws
  853. )
  854. /*++
  855. Routine Description:
  856. Convert a GUID to a wide string.
  857. Functions expects that the passed in string is large
  858. enough to hold the string form of a GUID.
  859. WCHAR ws[GUID_CHAR_LEN + 1];
  860. Arguments:
  861. pGuid - ptr to the GUID.
  862. ws - The output character buffer.
  863. Must be at least GUID_CHAR_LEN (36 wchars) long.
  864. Function Return Value:
  865. None.
  866. --*/
  867. {
  868. #undef DEBSUB
  869. #define DEBSUB "GuidToStrW:"
  870. if (pGuid) {
  871. swprintf(ws, L"%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
  872. pGuid->Data1,
  873. pGuid->Data2,
  874. pGuid->Data3,
  875. pGuid->Data4[0],
  876. pGuid->Data4[1],
  877. pGuid->Data4[2],
  878. pGuid->Data4[3],
  879. pGuid->Data4[4],
  880. pGuid->Data4[5],
  881. pGuid->Data4[6],
  882. pGuid->Data4[7]);
  883. } else {
  884. swprintf(ws, L"<ptr-null>");
  885. }
  886. }
  887. BOOL
  888. StrWToGuid(
  889. IN PWCHAR ws,
  890. OUT GUID *pGuid
  891. )
  892. /*++
  893. Routine Description:
  894. Convert a wide string into a GUID. The wide string was created with
  895. GuidToStrW().
  896. Arguments:
  897. pGuid - ptr to the output GUID.
  898. ws - The character buffer.
  899. Function Return Value:
  900. None.
  901. --*/
  902. {
  903. #undef DEBSUB
  904. #define DEBSUB "StrWToGuid:"
  905. DWORD Fields;
  906. UCHAR Guid[sizeof(GUID) + sizeof(DWORD)]; // 3 byte overflow
  907. GUID *lGuid = (GUID *)Guid;
  908. FRS_ASSERT(ws && pGuid);
  909. Fields = swscanf(ws, L"%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
  910. &lGuid->Data1,
  911. &lGuid->Data2,
  912. &lGuid->Data3,
  913. &lGuid->Data4[0],
  914. &lGuid->Data4[1],
  915. &lGuid->Data4[2],
  916. &lGuid->Data4[3],
  917. &lGuid->Data4[4],
  918. &lGuid->Data4[5],
  919. &lGuid->Data4[6],
  920. &lGuid->Data4[7]);
  921. COPY_GUID(pGuid, lGuid);
  922. return (Fields == 11);
  923. }
  924. VOID
  925. StrToGuid(
  926. IN PCHAR s,
  927. OUT GUID *pGuid
  928. )
  929. /*++
  930. Routine Description:
  931. Convert a string in GUID display format to an object ID that
  932. can be used to lookup a file.
  933. based on a routine by Mac McLain
  934. Arguments:
  935. pGuid - ptr to the output GUID.
  936. s - The input character buffer in display guid format.
  937. e.g.: b81b486b-c338-11d0-ba4f0000f80007df
  938. Must be at least GUID_CHAR_LEN (35 bytes) long.
  939. Function Return Value:
  940. None.
  941. --*/
  942. {
  943. #undef DEBSUB
  944. #define DEBSUB "StrToGuid:"
  945. UCHAR Guid[sizeof(GUID) + sizeof(DWORD)]; // 3 byte overflow
  946. GUID *lGuid = (GUID *)Guid;
  947. FRS_ASSERT(s && pGuid);
  948. sscanf(s, "%08lx-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
  949. &lGuid->Data1,
  950. &lGuid->Data2,
  951. &lGuid->Data3,
  952. &lGuid->Data4[0],
  953. &lGuid->Data4[1],
  954. &lGuid->Data4[2],
  955. &lGuid->Data4[3],
  956. &lGuid->Data4[4],
  957. &lGuid->Data4[5],
  958. &lGuid->Data4[6],
  959. &lGuid->Data4[7]);
  960. COPY_GUID(pGuid, lGuid);
  961. }
  962. NTSTATUS
  963. SetupOnePrivilege (
  964. ULONG Privilege,
  965. PUCHAR PrivilegeName
  966. )
  967. {
  968. #undef DEBSUB
  969. #define DEBSUB "SetupOnePrivilege:"
  970. BOOLEAN PreviousPrivilegeState = FALSE;
  971. NTSTATUS Status;
  972. Status = RtlAdjustPrivilege(Privilege, TRUE, FALSE, &PreviousPrivilegeState);
  973. if (!NT_SUCCESS(Status)) {
  974. DPRINT1(0, ":S: Your login does not have `%s' privilege.\n", PrivilegeName);
  975. if (Status != STATUS_PRIVILEGE_NOT_HELD) {
  976. DPRINT_NT(0, ":S: RtlAdjustPrivilege failed :", Status);
  977. }
  978. DPRINT(0, ":S: Update your: User Manager -> Policies -> User Rights.\n");
  979. } else {
  980. DPRINT2(4, ":S: Added `%s' privilege (previous: %s)\n",
  981. PrivilegeName, (PreviousPrivilegeState ? "Enabled" : "Disabled"));
  982. }
  983. return Status;
  984. }
  985. PWCHAR
  986. FrsGetResourceStr(
  987. LONG Id
  988. )
  989. /*++
  990. Routine Description:
  991. This routine Loads the specified resource string.
  992. It allocates a buffer and returns the ptr.
  993. Arguments:
  994. Id - An FRS_IDS_xxx identifier.
  995. Return Value:
  996. Ptr to allocated string.
  997. The caller must free the buffer with a call to FrsFree().
  998. --*/
  999. #undef DEBSUB
  1000. #define DEBSUB "FrsGetResourceStr:"
  1001. {
  1002. LONG N = 0;
  1003. WCHAR WStr[200];
  1004. HINSTANCE hInst = NULL;
  1005. PWCHAR MessageFile = NULL;
  1006. //
  1007. // ID Must be Valid.
  1008. //
  1009. if ((Id <= IDS_TABLE_START) || (Id > IDS_TABLE_END)) {
  1010. DPRINT1(0, "++ Resource string ID is out of range - %d\n", Id);
  1011. Id = IDS_MISSING_STRING;
  1012. }
  1013. WStr[0] = UNICODE_NULL;
  1014. CfgRegReadString(FKC_FRS_MESSAGE_FILE_PATH, NULL, 0, &MessageFile);
  1015. hInst = LoadLibrary(MessageFile);
  1016. if (hInst != NULL) {
  1017. N = LoadString(hInst, Id, WStr, ARRAY_SZ(WStr));
  1018. if (N == 0) {
  1019. DPRINT_WS(0, "ERROR - Failed to get resource string.", GetLastError());
  1020. }
  1021. FreeLibrary(hInst);
  1022. } else {
  1023. DPRINT_WS(0, "ERROR - Failed to LoadLibrary.", GetLastError());
  1024. }
  1025. FrsFree(MessageFile);
  1026. return FrsWcsDup(WStr);
  1027. }
  1028. DWORD
  1029. FrsOpenSourceFileW(
  1030. OUT PHANDLE Handle,
  1031. IN LPCWSTR lpFileName,
  1032. IN ACCESS_MASK DesiredAccess,
  1033. IN ULONG CreateOptions
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. This function opens the specified file with backup intent for
  1038. reading all the files attributes, ...
  1039. Arguments:
  1040. Handle - A pointer to a handle to return an open handle.
  1041. lpFileName - Represents the name of the file or directory to be opened.
  1042. DesiredAccess
  1043. CreateOptions
  1044. Return Value:
  1045. Win32 Error status.
  1046. --*/
  1047. {
  1048. #undef DEBSUB
  1049. #define DEBSUB "FrsOpenSourceFileW:"
  1050. NTSTATUS Status;
  1051. DWORD WStatus = ERROR_SUCCESS;
  1052. OBJECT_ATTRIBUTES Obja;
  1053. UNICODE_STRING FileName;
  1054. IO_STATUS_BLOCK IoStatusBlock;
  1055. BOOLEAN b;
  1056. RTL_RELATIVE_NAME_U RelativeName;
  1057. PVOID FreeBuffer;
  1058. ULONG FileAttributes;
  1059. ULONG CreateDisposition;
  1060. ULONG ShareMode;
  1061. //
  1062. // Convert the Dos name to an NT name.
  1063. //
  1064. b = RtlDosPathNameToNtPathName_U(lpFileName, &FileName, NULL, &RelativeName);
  1065. if ( !b ) {
  1066. return ERROR_INVALID_NAME;
  1067. }
  1068. FreeBuffer = FileName.Buffer;
  1069. if ( RelativeName.RelativeName.Length ) {
  1070. FileName = RelativeName.RelativeName;
  1071. } else {
  1072. RelativeName.ContainingDirectory = NULL;
  1073. }
  1074. InitializeObjectAttributes(&Obja,
  1075. &FileName,
  1076. OBJ_CASE_INSENSITIVE,
  1077. RelativeName.ContainingDirectory,
  1078. NULL);
  1079. CreateDisposition = FILE_OPEN; // Open existing file
  1080. ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  1081. FileAttributes = FILE_ATTRIBUTE_NORMAL;
  1082. Status = NtCreateFile(Handle,
  1083. DesiredAccess,
  1084. &Obja,
  1085. &IoStatusBlock,
  1086. NULL, // Initial allocation size
  1087. FileAttributes,
  1088. ShareMode,
  1089. CreateDisposition,
  1090. CreateOptions,
  1091. NULL, 0);
  1092. if (!NT_SUCCESS(Status)) {
  1093. *Handle = INVALID_HANDLE_VALUE;
  1094. //
  1095. // Get a Win32 status.
  1096. //
  1097. WStatus = FrsSetLastNTError(Status);
  1098. DPRINT_NT(0, "NtCreateFile failed :", Status);
  1099. if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
  1100. //
  1101. // Standard Win32 mapping for this is ERROR_ALREADY_EXISTS.
  1102. // Change it.
  1103. //
  1104. WStatus = ERROR_FILE_EXISTS;
  1105. SetLastError(ERROR_FILE_EXISTS);
  1106. }
  1107. DPRINT1_WS(0, "++ CreateFile failed on file %ws;", FileName.Buffer, WStatus);
  1108. }
  1109. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  1110. return WStatus;
  1111. }
  1112. DWORD
  1113. FrsOpenSourceFile2W(
  1114. OUT PHANDLE Handle,
  1115. IN LPCWSTR lpFileName,
  1116. IN ACCESS_MASK DesiredAccess,
  1117. IN ULONG CreateOptions,
  1118. IN ULONG ShareMode
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. This function opens the specified file with backup intent for
  1123. reading all the files attributes, ...
  1124. Like FrsOpenSourceFileW but also accepts the sharing mode parameter.
  1125. Arguments:
  1126. Handle - A pointer to a handle to return an open handle.
  1127. lpFileName - Represents the name of the file or directory to be opened.
  1128. DesiredAccess
  1129. CreateOptions
  1130. ShareMode - File sharing mode for NtCreateFile.
  1131. Return Value:
  1132. Win32 Error status.
  1133. --*/
  1134. {
  1135. #undef DEBSUB
  1136. #define DEBSUB "FrsOpenSourceFile2W:"
  1137. NTSTATUS Status;
  1138. DWORD WStatus = ERROR_SUCCESS;
  1139. OBJECT_ATTRIBUTES Obja;
  1140. UNICODE_STRING FileName;
  1141. IO_STATUS_BLOCK IoStatusBlock;
  1142. BOOLEAN b;
  1143. RTL_RELATIVE_NAME_U RelativeName;
  1144. PVOID FreeBuffer;
  1145. ULONG FileAttributes;
  1146. ULONG CreateDisposition;
  1147. //
  1148. // Convert the Dos name to an NT name.
  1149. //
  1150. b = RtlDosPathNameToNtPathName_U(lpFileName, &FileName, NULL, &RelativeName);
  1151. if ( !b ) {
  1152. return ERROR_INVALID_NAME;
  1153. }
  1154. FreeBuffer = FileName.Buffer;
  1155. if ( RelativeName.RelativeName.Length ) {
  1156. FileName = RelativeName.RelativeName;
  1157. } else {
  1158. RelativeName.ContainingDirectory = NULL;
  1159. }
  1160. InitializeObjectAttributes(&Obja,
  1161. &FileName,
  1162. OBJ_CASE_INSENSITIVE,
  1163. RelativeName.ContainingDirectory,
  1164. NULL);
  1165. CreateDisposition = FILE_OPEN; // Open existing file
  1166. FileAttributes = FILE_ATTRIBUTE_NORMAL;
  1167. Status = NtCreateFile(Handle,
  1168. DesiredAccess,
  1169. &Obja,
  1170. &IoStatusBlock,
  1171. NULL, // Initial allocation size
  1172. FileAttributes,
  1173. ShareMode,
  1174. CreateDisposition,
  1175. CreateOptions,
  1176. NULL, 0);
  1177. if (!NT_SUCCESS(Status)) {
  1178. *Handle = INVALID_HANDLE_VALUE;
  1179. //
  1180. // Get a Win32 status.
  1181. //
  1182. WStatus = FrsSetLastNTError(Status);
  1183. DPRINT_NT(0, "NtCreateFile failed :", Status);
  1184. if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
  1185. //
  1186. // Standard Win32 mapping for this is ERROR_ALREADY_EXISTS.
  1187. // Change it.
  1188. //
  1189. WStatus = ERROR_FILE_EXISTS;
  1190. SetLastError(ERROR_FILE_EXISTS);
  1191. }
  1192. DPRINT1_WS(0, "++ CreateFile failed on file %ws;", FileName.Buffer, WStatus);
  1193. }
  1194. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  1195. return WStatus;
  1196. }
  1197. BOOL
  1198. FrsGetFileInfoByHandle(
  1199. IN PWCHAR Name,
  1200. IN HANDLE Handle,
  1201. OUT PFILE_NETWORK_OPEN_INFORMATION FileOpenInfo
  1202. )
  1203. /*++
  1204. Routine Description:
  1205. Return the network file info for the specified handle.
  1206. Arguments:
  1207. Name - File's name for printing error messages
  1208. Handle - Open file handle
  1209. FileOpenInfo - Returns the file FILE_NETWORK_OPEN_INFORMATION data.
  1210. Return Value:
  1211. TRUE - FileOpenInfo contains the file's info
  1212. FALSE - Contents of FileOpenInfo is undefined
  1213. --*/
  1214. {
  1215. #undef DEBSUB
  1216. #define DEBSUB "FrsGetFileInfoByHandle:"
  1217. NTSTATUS Status;
  1218. IO_STATUS_BLOCK IoStatusBlock;
  1219. //
  1220. // Return some file info
  1221. //
  1222. Status = NtQueryInformationFile(Handle,
  1223. &IoStatusBlock,
  1224. FileOpenInfo,
  1225. sizeof(FILE_NETWORK_OPEN_INFORMATION),
  1226. FileNetworkOpenInformation);
  1227. if (!NT_SUCCESS(Status)) {
  1228. DPRINT_NT(0, "NtQueryInformationFile failed :", Status);
  1229. return FALSE;
  1230. }
  1231. return TRUE;
  1232. }
  1233. DWORD
  1234. FrsGetFileInternalInfoByHandle(
  1235. IN HANDLE Handle,
  1236. OUT PFILE_INTERNAL_INFORMATION InternalFileInfo
  1237. )
  1238. /*++
  1239. Routine Description:
  1240. Return the internal file info for the specified handle.
  1241. Arguments:
  1242. Handle - Open file handle
  1243. InternalFileInfo - Basically, file's reference number (fid)
  1244. Return Value:
  1245. Win32 Status
  1246. --*/
  1247. {
  1248. #undef DEBSUB
  1249. #define DEBSUB "FrsGetFileInternalInfoByHandle:"
  1250. NTSTATUS Status;
  1251. IO_STATUS_BLOCK IoStatusBlock;
  1252. //
  1253. // Return some file info
  1254. //
  1255. Status = NtQueryInformationFile(Handle,
  1256. &IoStatusBlock,
  1257. InternalFileInfo,
  1258. sizeof(FILE_INTERNAL_INFORMATION),
  1259. FileInternalInformation);
  1260. return FrsSetLastNTError(Status);
  1261. }
  1262. DWORD
  1263. FrsReadFileDetails(
  1264. IN HANDLE Handle,
  1265. IN LPCWSTR FileName,
  1266. OUT PFILE_OBJECTID_BUFFER ObjectIdBuffer,
  1267. OUT PLONGLONG FileIdBuffer,
  1268. OUT PFILE_NETWORK_OPEN_INFORMATION FileNetworkOpenInfo,
  1269. IN OUT BOOL *ExistingOid
  1270. )
  1271. /*++
  1272. Routine Description:
  1273. This routine reads the object ID. If there is no
  1274. object ID on the file we put one on it.
  1275. Arguments:
  1276. Handle -- The file handle of an opened file.
  1277. FileName -- The name of the file. For error messages only.
  1278. ObjectIdBuffer -- The output buffer to hold the object ID.
  1279. FileIdBuffer -- Returns the NTFS FileReference (FileId).
  1280. FileNetworkOpenInfo -- returns FILE_NETWORK_OPEN_INFORMATION
  1281. ExistingOid -- INPUT: TRUE means use existing File OID if found.
  1282. RETURN: TRUE means an existing File OID was used.
  1283. Return Value:
  1284. Returns the Win Status of the last error found, or success.
  1285. --*/
  1286. {
  1287. #undef DEBSUB
  1288. #define DEBSUB "FrsReadFileDetails:"
  1289. FILE_INTERNAL_INFORMATION FileReference;
  1290. NTSTATUS Status;
  1291. IO_STATUS_BLOCK Iosb;
  1292. LONG Loop;
  1293. BOOL CallerSupplied = FALSE;
  1294. CHAR GuidStr[GUID_CHAR_LEN];
  1295. //
  1296. // Get the file ID.
  1297. //
  1298. Status = NtQueryInformationFile(Handle,
  1299. &Iosb,
  1300. FileIdBuffer,
  1301. sizeof(FILE_INTERNAL_INFORMATION),
  1302. FileInternalInformation);
  1303. if (!NT_SUCCESS(Status)) {
  1304. DPRINT_NT(0, "++ ERROR - QueryInfoFile FileID failed :", Status);
  1305. FrsSetLastNTError(Status);
  1306. }
  1307. //
  1308. // Get file times, size, attributes.
  1309. //
  1310. Status = NtQueryInformationFile(Handle,
  1311. &Iosb,
  1312. FileNetworkOpenInfo,
  1313. sizeof(FILE_NETWORK_OPEN_INFORMATION),
  1314. FileNetworkOpenInformation);
  1315. if (!NT_SUCCESS(Status)) {
  1316. DPRINT_NT(0, "++ ERROR - QueryInfoFile FileNetworkOpenInformation failed :", Status);
  1317. FrsSetLastNTError(Status);
  1318. }
  1319. if (!*ExistingOid) {
  1320. //
  1321. // Set up to slam a new OID on the file.
  1322. //
  1323. CallerSupplied = TRUE;
  1324. ZeroMemory(ObjectIdBuffer, sizeof(FILE_OBJECTID_BUFFER));
  1325. FrsUuidCreate((GUID *)ObjectIdBuffer->ObjectId);
  1326. }
  1327. return FrsGetOrSetFileObjectId(Handle, FileName, CallerSupplied, ObjectIdBuffer);
  1328. }
  1329. #if 0
  1330. // This may not be needed.
  1331. ULONG
  1332. FrsReadFileSecurity(
  1333. IN HANDLE Handle,
  1334. IN OUT PTABLE_CTX TableCtx,
  1335. IN PWCHAR FileName
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. This routine gets the security descriptor from the file. The returned data
  1340. is stored into the security descriptor field in the data record allocated
  1341. with the table context. If the default buffer is not large enough
  1342. a larger buffer is allocated.
  1343. Arguments:
  1344. Handle -- Handle to open file from which to extract the security desc.
  1345. TableCtx -- The table context struct where the security descriptor is
  1346. to be written. It must be an IDTable.
  1347. FileName -- The full filename. For error messages only.
  1348. Return Value:
  1349. Returns the WIN32 STATUS error status.
  1350. Note: In the event that GetFileSecurity returns ERROR_NO_SECURITY_ON_OBJECT
  1351. we release the buffer, setting the length to zero, and return ERROR_SUCCESS.
  1352. --*/
  1353. {
  1354. #undef DEBSUB
  1355. #define DEBSUB "FrsReadFileSecurity:"
  1356. ULONG WStatus;
  1357. NTSTATUS Status;
  1358. ULONG BufLen;
  1359. PSECURITY_DESCRIPTOR Buffer;
  1360. ULONG BufNeeded;
  1361. ULONG ActualLen;
  1362. JET_ERR jerr;
  1363. PJET_SETCOLUMN JSetColumn;
  1364. //
  1365. // Check the table type is an IDTable.
  1366. //
  1367. if (TableCtx->TableType != IDTablex) {
  1368. DPRINT1(0, "++ ERROR - Invalid Table Type: %d\n", TableCtx->TableType);
  1369. return ERROR_INVALID_PARAMETER;
  1370. }
  1371. //
  1372. // Get ptrs to the Jet SetColumn array and the buffer address & length
  1373. //
  1374. JSetColumn = TableCtx->pJetSetCol;
  1375. Buffer = (PSECURITY_DESCRIPTOR) JSetColumn[SecDescx].pvData;
  1376. BufLen = JSetColumn[SecDescx].cbData;
  1377. //
  1378. // The security descriptor is a variable length binary field that
  1379. // must have a type/size prefix.
  1380. //
  1381. ((PFRS_NODE_HEADER) Buffer)->Size = (USHORT) BufLen;
  1382. ((PFRS_NODE_HEADER) Buffer)->Type = 0;
  1383. BufNeeded = 0;
  1384. //
  1385. // Check that the security descriptor buffer looks reasonable.
  1386. //
  1387. if (Buffer == NULL) {
  1388. DPRINT2(0, "++ ERROR - Invalid SD buffer. Buffer Addr: %08x, Len: %d\n",
  1389. Buffer, BufLen);
  1390. return ERROR_INVALID_PARAMETER;
  1391. }
  1392. //
  1393. // Now go get all the security information.
  1394. //
  1395. while (TRUE) {
  1396. BufLen -= sizeof(FRS_NODE_HEADER); // for type / size prefix.
  1397. (PCHAR)Buffer += sizeof(FRS_NODE_HEADER);
  1398. Status = NtQuerySecurityObject(
  1399. Handle,
  1400. SACL_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION |
  1401. GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
  1402. Buffer,
  1403. BufLen,
  1404. &BufNeeded);
  1405. if (NT_SUCCESS(Status)) {
  1406. ActualLen = GetSecurityDescriptorLength(Buffer) + sizeof(FRS_NODE_HEADER);
  1407. BufLen += sizeof(FRS_NODE_HEADER);
  1408. DPRINT3(5, "++ GetFileSecurity-1 Buflen: %d, Bufneeded: %d, ActualLen: %d\n",
  1409. BufLen, BufNeeded, ActualLen);
  1410. //
  1411. // If current buffer size is more than 16 bytes larger than needed AND
  1412. // also more than 5% greater than needed then shrink the buffer but
  1413. // keep the data.
  1414. //
  1415. if (((BufLen-ActualLen) > 16) &&
  1416. (BufLen > (ActualLen + ActualLen/20))) {
  1417. DPRINT3(5, "++ GetFileSecurity-2 Reducing buffer, Buflen: %d, Bufneeded: %d, ActualLen: %d\n",
  1418. BufLen, BufNeeded, ActualLen);
  1419. //
  1420. // Unused space in field buffer is greater than 6%.
  1421. // Reduce the buffer size but keep the data.
  1422. //
  1423. jerr = DbsReallocateFieldBuffer(TableCtx, SecDescx, ActualLen, TRUE);
  1424. if (!JET_SUCCESS(jerr)) {
  1425. return ERROR_NOT_ENOUGH_MEMORY;
  1426. }
  1427. Buffer = (PSECURITY_DESCRIPTOR) JSetColumn[SecDescx].pvData;
  1428. ((PFRS_NODE_HEADER) Buffer)->Size = (USHORT) ActualLen;
  1429. ((PFRS_NODE_HEADER) Buffer)->Type = 0;
  1430. }
  1431. return ERROR_SUCCESS;
  1432. }
  1433. //
  1434. // Set the win32 error code and message string.
  1435. //
  1436. WStatus = FrsSetLastNTError(Status);
  1437. //
  1438. // If not enough buffer reallocate larger buffer.
  1439. //
  1440. if (WStatus == ERROR_INSUFFICIENT_BUFFER) {
  1441. //
  1442. // Reallocate the buffer for the security descriptor.
  1443. //
  1444. jerr = DbsReallocateFieldBuffer(TableCtx, SecDescx, BufNeeded, FALSE);
  1445. if (!JET_SUCCESS(jerr)) {
  1446. DPRINT_JS(0, "++ ERROR - DbsReallocateFieldBuffer failed.", jerr);
  1447. return ERROR_NOT_ENOUGH_MEMORY;
  1448. }
  1449. Buffer = (PSECURITY_DESCRIPTOR) JSetColumn[SecDescx].pvData;
  1450. ((PFRS_NODE_HEADER) Buffer)->Size = (USHORT) BufNeeded;
  1451. ((PFRS_NODE_HEADER) Buffer)->Type = 0;
  1452. //
  1453. // Get new buffer params and try again to get security information.
  1454. //
  1455. BufLen = BufNeeded;
  1456. continue;
  1457. }
  1458. //
  1459. // Check for ERROR_NO_SECURITY_ON_OBJECT and release the buffer so we
  1460. // don't waste space in the database.
  1461. //
  1462. if (WStatus == ERROR_NO_SECURITY_ON_OBJECT) {
  1463. DPRINT2(0, "++ ERROR - GetFileSecurity-3 (NO_SEC) Buflen: %d, Bufneeded: %d\n", BufLen, BufNeeded);
  1464. //
  1465. // Free the buffer and set the length to zero.
  1466. //
  1467. DbsReallocateFieldBuffer(TableCtx, SecDescx, 0, FALSE);
  1468. return ERROR_SUCCESS;
  1469. }
  1470. //
  1471. // Some other error.
  1472. //
  1473. DPRINT_WS(0, "++ ERROR - GetFileSecurity-4;", WStatus);
  1474. return WStatus;
  1475. }
  1476. }
  1477. #endif
  1478. PWCHAR
  1479. FrsGetFullPathByHandle(
  1480. IN PWCHAR Name,
  1481. IN HANDLE Handle
  1482. )
  1483. /*++
  1484. Routine Description:
  1485. Return a copy of the handle's full pathname. Free with FrsFree().
  1486. Arguments:
  1487. Name
  1488. Handle
  1489. Return Value:
  1490. Return a copy of the handle's full pathname. Free with FrsFree().
  1491. --*/
  1492. {
  1493. #undef DEBSUB
  1494. #define DEBSUB "FrsGetFullPathByHandle"
  1495. NTSTATUS Status;
  1496. IO_STATUS_BLOCK IoStatusBlock;
  1497. DWORD BufferSize;
  1498. PCHAR Buffer;
  1499. PWCHAR RetFileName = NULL;
  1500. CHAR NameBuffer[sizeof(ULONG) + (sizeof(WCHAR)*(MAX_PATH+1))];
  1501. PFILE_NAME_INFORMATION FileName;
  1502. if (!HANDLE_IS_VALID(Handle)) {
  1503. return NULL;
  1504. }
  1505. BufferSize = sizeof(NameBuffer);
  1506. Buffer = NameBuffer;
  1507. again:
  1508. FileName = (PFILE_NAME_INFORMATION) Buffer;
  1509. FileName->FileNameLength = BufferSize - (sizeof(ULONG) + sizeof(WCHAR));
  1510. Status = NtQueryInformationFile(Handle,
  1511. &IoStatusBlock,
  1512. FileName,
  1513. BufferSize - sizeof(WCHAR),
  1514. FileNameInformation);
  1515. if (NT_SUCCESS(Status) ) {
  1516. FileName->FileName[FileName->FileNameLength/2] = UNICODE_NULL;
  1517. RetFileName = FrsWcsDup(FileName->FileName);
  1518. } else {
  1519. //
  1520. // Try a larger buffer
  1521. //
  1522. if (Status == STATUS_BUFFER_OVERFLOW) {
  1523. DPRINT2(4, "++ Buffer size %d was too small for %ws\n",
  1524. BufferSize, Name);
  1525. BufferSize = FileName->FileNameLength + sizeof(ULONG) + sizeof(WCHAR);
  1526. if (Buffer != NameBuffer) {
  1527. FrsFree(Buffer);
  1528. }
  1529. Buffer = FrsAlloc(BufferSize);
  1530. DPRINT2(4, "++ Retrying with buffer size %d for %ws\n",
  1531. BufferSize, Name);
  1532. goto again;
  1533. }
  1534. DPRINT1_NT(0, "++ NtQueryInformationFile - FileNameInformation failed.",
  1535. Name, Status);
  1536. }
  1537. //
  1538. // A large buffer was allocated if the file's full
  1539. // name could not fit into MAX_PATH chars.
  1540. //
  1541. if (Buffer != NameBuffer) {
  1542. FrsFree(Buffer);
  1543. }
  1544. return RetFileName;
  1545. }
  1546. PWCHAR
  1547. FrsGetTrueFileNameByHandle(
  1548. IN PWCHAR Name,
  1549. IN HANDLE Handle,
  1550. OUT PLONGLONG DirFileID
  1551. )
  1552. /*++
  1553. Routine Description:
  1554. Return a copy of the filename part associated with this handle.
  1555. Free with FrsFree().
  1556. Arguments:
  1557. Name
  1558. Handle
  1559. DirFileID - If non-null, return the parent File ID.
  1560. Return Value:
  1561. Return a copy of the filename part associated with this handle.
  1562. --*/
  1563. {
  1564. #undef DEBSUB
  1565. #define DEBSUB "FrsGetTrueFileNameByHandle"
  1566. PWCHAR Path;
  1567. PWCHAR File;
  1568. ULONG Len;
  1569. Path = FrsGetFullPathByHandle(Name, Handle);
  1570. if (!Path) {
  1571. return NULL;
  1572. }
  1573. for (Len = wcslen(Path); Len && Path[Len] != L'\\'; --Len);
  1574. File = FrsWcsDup(&Path[Len + 1]);
  1575. FrsFree(Path);
  1576. if (DirFileID != NULL) {
  1577. FrsReadFileParentFid(Handle, DirFileID);
  1578. }
  1579. return File;
  1580. }
  1581. DWORD
  1582. FrsOpenFileRelativeByName(
  1583. IN HANDLE VolumeHandle,
  1584. IN PULONGLONG FileReferenceNumber,
  1585. IN PWCHAR FileName,
  1586. IN GUID *ParentGuid,
  1587. IN GUID *FileGuid,
  1588. OUT HANDLE *Handle
  1589. )
  1590. /*++
  1591. Routine Description:
  1592. Open the file specified by its true name using the FID for either
  1593. a rename or delete installation. If the FID is null then use the
  1594. Filename as given.
  1595. FrsOpenFileRelativeByName(Coe->NewReplica->pVme->VolumeHandle,
  1596. &Coe->FileReferenceNumber, // or NULL
  1597. Coc->FileName,
  1598. &Coc->OldParentGuid,
  1599. &Coc->FileGuid
  1600. &Handle);
  1601. Arguments:
  1602. VolumeHandle, - handle to root of the drive
  1603. FileReferenceNumber - FID for the file in question (NULL if supplied
  1604. filename is valid)
  1605. FileName, - Filename
  1606. *ParentGuid, - ptr to the object ID for the file's parent dir.
  1607. *FileGuid, - ptr to the object ID for the file (for checking,
  1608. NULL if no check needed).
  1609. *Handle - Returned handle for open file.
  1610. Return Value:
  1611. Handle and win32 status
  1612. --*/
  1613. {
  1614. #undef DEBSUB
  1615. #define DEBSUB "FrsOpenFileRelativeByName"
  1616. PWCHAR TrueFileName;
  1617. DWORD WStatus;
  1618. *Handle = INVALID_HANDLE_VALUE;
  1619. if (FileReferenceNumber != NULL) {
  1620. //
  1621. // Open the source file and get the current "True" File name.
  1622. //
  1623. WStatus = FrsOpenSourceFileById(Handle,
  1624. NULL,
  1625. NULL,
  1626. VolumeHandle,
  1627. FileReferenceNumber,
  1628. FILE_ID_LENGTH,
  1629. // READ_ACCESS,
  1630. READ_ATTRIB_ACCESS,
  1631. ID_OPTIONS,
  1632. SHARE_ALL,
  1633. FILE_OPEN);
  1634. if (!WIN_SUCCESS(WStatus)) {
  1635. DPRINT1_WS(4, "++ Couldn't open file %ws;", FileName, WStatus);
  1636. return WStatus;
  1637. }
  1638. //
  1639. // File's TrueFileName
  1640. //
  1641. TrueFileName = FrsGetTrueFileNameByHandle(FileName, *Handle, NULL);
  1642. FRS_CLOSE(*Handle);
  1643. if (TrueFileName == NULL) {
  1644. DPRINT1(4, "++ Couldn't get base name for %ws\n", FileName);
  1645. WIN_SET_FAIL(WStatus);
  1646. return WStatus;
  1647. }
  1648. } else {
  1649. TrueFileName = FileName;
  1650. }
  1651. //
  1652. // Open the file relative to the parent using the true filename.
  1653. //
  1654. WStatus = FrsCreateFileRelativeById(Handle,
  1655. VolumeHandle,
  1656. ParentGuid,
  1657. OBJECT_ID_LENGTH,
  1658. FILE_ATTRIBUTE_NORMAL,
  1659. TrueFileName,
  1660. (USHORT)(wcslen(TrueFileName) * sizeof(WCHAR)),
  1661. NULL,
  1662. FILE_OPEN,
  1663. // DELETE | READ_ACCESS | FILE_WRITE_ATTRIBUTES);
  1664. DELETE | READ_ATTRIB_ACCESS | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY);
  1665. if (FileReferenceNumber != NULL) {
  1666. FrsFree(TrueFileName);
  1667. }
  1668. if (!WIN_SUCCESS(WStatus)) {
  1669. DPRINT1_WS(4, "++ Couldn't open relative file %ws;", FileName, WStatus);
  1670. return WStatus;
  1671. }
  1672. //
  1673. // Get the file's oid and check it against the value supplied.
  1674. //
  1675. if (FileGuid != NULL) {
  1676. WStatus = FrsCheckObjectId(FileName, *Handle, FileGuid);
  1677. if (!WIN_SUCCESS(WStatus)) {
  1678. DPRINT1_WS(0, "++ Object id mismatch for file %ws;", FileName, WStatus);
  1679. FRS_CLOSE(*Handle);
  1680. }
  1681. }
  1682. return WStatus;
  1683. }
  1684. DWORD
  1685. FrsDeleteFileRelativeByName(
  1686. IN HANDLE VolumeHandle,
  1687. IN GUID *ParentGuid,
  1688. IN PWCHAR FileName,
  1689. IN PQHASH_TABLE FrsWriteFilter
  1690. )
  1691. /*++
  1692. Routine Description:
  1693. Delete the file or dir subtree specified by its name relative to
  1694. the parent dir specified by its object ID (guid).
  1695. Arguments:
  1696. VolumeHandle, - handle to root of the drive
  1697. *ParentGuid, - ptr to the object ID for the file's parent dir.
  1698. FileName, - Filename
  1699. FrsWriteFilter - Write filter to use for dampening (NULL if undampened).
  1700. e.g. Coe->NewReplica->pVme->FrsWriteFilter
  1701. Return Value:
  1702. Win32 status
  1703. --*/
  1704. {
  1705. #undef DEBSUB
  1706. #define DEBSUB "FrsDeleteFileRelativeByName"
  1707. DWORD WStatus;
  1708. HANDLE Handle = INVALID_HANDLE_VALUE;
  1709. //
  1710. // Open the file
  1711. //
  1712. WStatus = FrsOpenFileRelativeByName(VolumeHandle,
  1713. NULL,
  1714. FileName,
  1715. ParentGuid,
  1716. NULL,
  1717. &Handle);
  1718. if (!WIN_SUCCESS(WStatus)) {
  1719. DPRINT1_WS(4, "++ Couldn't open file %ws for delete;", FileName, WStatus);
  1720. //
  1721. // File has already been deleted; done
  1722. //
  1723. if (WIN_NOT_FOUND(WStatus)) {
  1724. DPRINT1(4, "++ %ws is already deleted\n", FileName);
  1725. WStatus = ERROR_SUCCESS;
  1726. }
  1727. goto out;
  1728. }
  1729. //
  1730. // Handles can be marked so that any usn records resulting from
  1731. // operations on the handle will have the same "mark". In this
  1732. // case, the mark is a bit in the SourceInfo field of the usn
  1733. // record. The mark tells NtFrs to ignore the usn record during
  1734. // recovery because this was a NtFrs generated change.
  1735. //
  1736. if (FrsWriteFilter) {
  1737. WStatus = FrsMarkHandle(VolumeHandle, Handle);
  1738. DPRINT1_WS(0, "++ WARN - FrsMarkHandle(%ws);", FileName, WStatus);
  1739. }
  1740. //
  1741. // Reset the attributes that prevent deletion
  1742. //
  1743. WStatus = FrsResetAttributesForReplication(FileName, Handle);
  1744. if (!WIN_SUCCESS(WStatus)) {
  1745. goto out;
  1746. }
  1747. //
  1748. // Mark the file for delete
  1749. //
  1750. WStatus = FrsDeleteByHandle(FileName, Handle);
  1751. if (!WIN_SUCCESS(WStatus)) {
  1752. //
  1753. // If this was a non-empty dir then delete the subtree.
  1754. //
  1755. if (WStatus == ERROR_DIR_NOT_EMPTY) {
  1756. WStatus = FrsEnumerateDirectory(Handle,
  1757. FileName,
  1758. 0,
  1759. ENUMERATE_DIRECTORY_FLAGS_NONE,
  1760. NULL,
  1761. FrsEnumerateDirectoryDeleteWorker);
  1762. }
  1763. WStatus = FrsDeleteByHandle(FileName, Handle);
  1764. }
  1765. if (!WIN_SUCCESS(WStatus)) {
  1766. DPRINT1_WS(0, "++ Could not delete %ws;", FileName, WStatus);
  1767. goto out;
  1768. }
  1769. out:
  1770. DPRINT2(5, "++ %s deleting %ws\n", (WIN_SUCCESS(WStatus)) ? "Success" : "Failure",
  1771. FileName);
  1772. //
  1773. // If the file was marked for delete, this close will delete it
  1774. //
  1775. if (HANDLE_IS_VALID(Handle)) {
  1776. if (FrsWriteFilter != NULL) {
  1777. FrsCloseWithUsnDampening(FileName, &Handle, FrsWriteFilter, NULL);
  1778. } else {
  1779. FRS_CLOSE(Handle);
  1780. }
  1781. }
  1782. return WStatus;
  1783. }
  1784. DWORD
  1785. FrsDeletePath(
  1786. IN PWCHAR Path,
  1787. IN DWORD DirectoryFlags
  1788. )
  1789. /*++
  1790. Routine Description:
  1791. Delete the file or dir subtree specified by its path
  1792. WARN: Does not dampen the operations. To be safe, the replica
  1793. set should not exist or the directory should be filtered.
  1794. Otherwise, the deletes might replicate.
  1795. Arguments:
  1796. Path - Path of file system object
  1797. DirectoryFlags - See tablefcn.h, ENUMERATE_DIRECTORY_FLAGS_
  1798. Return Value:
  1799. Win32 status
  1800. --*/
  1801. {
  1802. #undef DEBSUB
  1803. #define DEBSUB "FrsDeletePath"
  1804. DWORD WStatus;
  1805. HANDLE Handle = INVALID_HANDLE_VALUE;
  1806. FILE_NETWORK_OPEN_INFORMATION FileInfo;
  1807. //
  1808. // Open the file
  1809. //
  1810. WStatus = FrsOpenSourceFileW(&Handle,
  1811. Path,
  1812. // DELETE | READ_ACCESS | FILE_WRITE_ATTRIBUTES,
  1813. DELETE | READ_ATTRIB_ACCESS | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY,
  1814. OPEN_OPTIONS);
  1815. if (WIN_NOT_FOUND(WStatus)) {
  1816. CLEANUP1_WS(1, "++ WARN - FrsOpenSourceFile(%ws); (IGNORED);",
  1817. Path, WStatus, RETURN_SUCCESS);
  1818. }
  1819. CLEANUP1_WS(0, "++ ERROR - FrsOpenSourceFile(%ws);", Path, WStatus, CLEANUP);
  1820. //
  1821. // Get the file's attributes
  1822. //
  1823. if (!FrsGetFileInfoByHandle(Path, Handle, &FileInfo)) {
  1824. DPRINT1(1, "++ WARN - Can't get attributes for %ws\n", Path);
  1825. WIN_SET_FAIL(WStatus);
  1826. goto CLEANUP;
  1827. }
  1828. //
  1829. // Don't delete the file if DIRECTORIES_ONLY is set
  1830. //
  1831. if (DirectoryFlags & ENUMERATE_DIRECTORY_FLAGS_DIRECTORIES_ONLY &&
  1832. !(FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1833. WStatus = ERROR_DIRECTORY;
  1834. goto CLEANUP;
  1835. }
  1836. //
  1837. // Reset the attributes that prevent deletion
  1838. //
  1839. if (FileInfo.FileAttributes & NOREPL_ATTRIBUTES) {
  1840. DPRINT1(5, "++ Reseting attributes for %ws for delete\n", Path);
  1841. WStatus = FrsSetFileAttributes(Path, Handle,
  1842. FileInfo.FileAttributes &
  1843. ~NOREPL_ATTRIBUTES);
  1844. CLEANUP1_WS(0, "++ ERROR: - Can't reset attributes for %ws for delete", Path, WStatus, CLEANUP);
  1845. DPRINT1(5, "++ Attributes for %ws now allow deletion\n", Path);
  1846. }
  1847. //
  1848. // Mark the file for delete
  1849. //
  1850. WStatus = FrsDeleteByHandle(Path, Handle);
  1851. if (!WIN_SUCCESS(WStatus)) {
  1852. //
  1853. // If this was a non-empty dir then delete the subtree.
  1854. //
  1855. if (WStatus == ERROR_DIR_NOT_EMPTY) {
  1856. WStatus = FrsEnumerateDirectory(Handle,
  1857. Path,
  1858. 0,
  1859. DirectoryFlags,
  1860. NULL,
  1861. FrsEnumerateDirectoryDeleteWorker);
  1862. }
  1863. WStatus = FrsDeleteByHandle(Path, Handle);
  1864. }
  1865. DPRINT1_WS(0, "++ ERROR - Could not delete %ws;", Path, WStatus);
  1866. CLEANUP:
  1867. DPRINT2(5, "++ %s deleting %ws\n",
  1868. (WIN_SUCCESS(WStatus)) ? "Success" : "Failure", Path);
  1869. FRS_CLOSE(Handle);
  1870. return WStatus;
  1871. RETURN_SUCCESS:
  1872. WStatus = ERROR_SUCCESS;
  1873. goto CLEANUP;
  1874. }
  1875. DWORD
  1876. FrsDeleteDirectoryContents(
  1877. IN PWCHAR Path,
  1878. IN DWORD DirectoryFlags
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. Delete the contents of the directory Path
  1883. Arguments:
  1884. Path - Path of file system object
  1885. DirectoryFlags - See tablefcn.h, ENUMERATE_DIRECTORY_FLAGS_
  1886. Return Value:
  1887. Win32 status
  1888. --*/
  1889. {
  1890. #undef DEBSUB
  1891. #define DEBSUB "FrsDeleteDirectoryContents"
  1892. DWORD WStatus;
  1893. HANDLE Handle = INVALID_HANDLE_VALUE;
  1894. //
  1895. // Open the file
  1896. //
  1897. WStatus = FrsOpenSourceFileW(&Handle, Path,
  1898. // READ_ACCESS,
  1899. READ_ATTRIB_ACCESS | FILE_LIST_DIRECTORY,
  1900. OPEN_OPTIONS);
  1901. if (WIN_NOT_FOUND(WStatus)) {
  1902. CLEANUP1_WS(1, "++ WARN - FrsOpenSourceFile(%ws); (IGNORED);",
  1903. Path, WStatus, RETURN_SUCCESS);
  1904. }
  1905. CLEANUP1_WS(0, "++ ERROR - FrsOpenSourceFile(%ws);", Path, WStatus, CLEANUP);
  1906. WStatus = FrsEnumerateDirectory(Handle,
  1907. Path,
  1908. 0,
  1909. DirectoryFlags,
  1910. NULL,
  1911. FrsEnumerateDirectoryDeleteWorker);
  1912. CLEANUP1_WS(0, "++ ERROR - Could not delete contents of %ws;",
  1913. Path, WStatus, CLEANUP);
  1914. CLEANUP:
  1915. DPRINT2(5, "++ %s deleting contents of %ws\n",
  1916. (WIN_SUCCESS(WStatus)) ? "Success" : "Failure", Path);
  1917. FRS_CLOSE(Handle);
  1918. return WStatus;
  1919. RETURN_SUCCESS:
  1920. WStatus = ERROR_SUCCESS;
  1921. goto CLEANUP;
  1922. }
  1923. DWORD
  1924. FrsOpenBaseNameForInstall(
  1925. IN PCHANGE_ORDER_ENTRY Coe,
  1926. OUT HANDLE *Handle
  1927. )
  1928. /*++
  1929. Routine Description:
  1930. Open the file specified by Coe by its relative name for either
  1931. a rename or delete installation.
  1932. Note that it is possible for the file to have been moved to a new parent
  1933. dir by a previous remote CO or a local CO, making the OldParentGuid in the
  1934. Change Order invalid. First we try to find the file under the OldParentGuid
  1935. in the CO and then we try by the parent Guid in the IDTable. We check for
  1936. a match by comparing with the file GUID in the change order.
  1937. It is also possible that the file has been renamed to a point outside the
  1938. replica tree so even if we find it by FID we still can't do anything to it.
  1939. When we fail to find the file in either of the above directories we force this
  1940. CO thru retry, expecting another CO behind us to get processed and update
  1941. the parent guid in the IDTable or maybe mark the file as deleted.
  1942. Arguments:
  1943. Coe
  1944. Handle
  1945. Return Value:
  1946. Handle and win status
  1947. --*/
  1948. {
  1949. #undef DEBSUB
  1950. #define DEBSUB "FrsOpenBaseNameForInstall"
  1951. LONGLONG ParentFid;
  1952. PWCHAR FileName;
  1953. DWORD WStatus;
  1954. PCHANGE_ORDER_COMMAND Coc = &Coe->Cmd;
  1955. PIDTABLE_RECORD IDTableRec;
  1956. BOOLEAN UseActualLocation = FALSE;
  1957. ParentFid = QUADZERO;
  1958. *Handle = INVALID_HANDLE_VALUE;
  1959. //
  1960. // Open the source file
  1961. //
  1962. WStatus = FrsOpenSourceFileById(Handle,
  1963. NULL,
  1964. NULL,
  1965. Coe->NewReplica->pVme->VolumeHandle,
  1966. &Coe->FileReferenceNumber,
  1967. FILE_ID_LENGTH,
  1968. // READ_ACCESS,
  1969. READ_ATTRIB_ACCESS,
  1970. ID_OPTIONS,
  1971. SHARE_ALL,
  1972. FILE_OPEN);
  1973. if (!WIN_SUCCESS(WStatus)) {
  1974. CHANGE_ORDER_TRACEW(3, Coe, "File open by FID failed", WStatus);
  1975. return WStatus;
  1976. }
  1977. //
  1978. // Get the File's true on-disk filename and the true parent FID.
  1979. //
  1980. FileName = FrsGetTrueFileNameByHandle(Coc->FileName, *Handle, &ParentFid);
  1981. FRS_CLOSE(*Handle);
  1982. if (FileName == NULL) {
  1983. CHANGE_ORDER_TRACE(3, Coe, "Failed to get file base name");
  1984. return ERROR_FILE_NOT_FOUND;
  1985. }
  1986. //
  1987. // Open the file relative to the parent using the true filename.
  1988. //
  1989. WStatus = FrsCreateFileRelativeById(Handle,
  1990. Coe->NewReplica->pVme->VolumeHandle,
  1991. &Coc->OldParentGuid,
  1992. OBJECT_ID_LENGTH,
  1993. FILE_ATTRIBUTE_NORMAL,
  1994. FileName,
  1995. (USHORT)(wcslen(FileName) * sizeof(WCHAR)),
  1996. NULL,
  1997. FILE_OPEN,
  1998. // DELETE | READ_ACCESS | FILE_WRITE_ATTRIBUTES);
  1999. DELETE | READ_ATTRIB_ACCESS | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY);
  2000. if (WIN_SUCCESS(WStatus)) {
  2001. //
  2002. // Get the file's oid and check it against the change order. Need to
  2003. // do this to cover the case of a rename of the file to a different
  2004. // parent dir followed by a create of a file with the same name.
  2005. // If this occurred the above open would succeed.
  2006. //
  2007. WStatus = FrsCheckObjectId(Coc->FileName, *Handle, &Coc->FileGuid);
  2008. if (WIN_SUCCESS(WStatus)) {
  2009. goto RETURN;
  2010. }
  2011. CHANGE_ORDER_TRACE(3, Coe, "File OID mismatch CO, after Coc->OldParentGuid open");
  2012. FRS_CLOSE(*Handle);
  2013. } else {
  2014. CHANGE_ORDER_TRACEW(3, Coe, "File open failed under Coc->OldParentGuid", WStatus);
  2015. }
  2016. //
  2017. // We did not find the file using the True Name from the file and the
  2018. // Old parent Guid from the change order. The file may have been moved
  2019. // by a previous remote CO or a Local CO. Try the Parent Guid in the
  2020. // IDTable record.
  2021. //
  2022. FRS_ASSERT(Coe->RtCtx != NULL);
  2023. FRS_ASSERT(IS_ID_TABLE(&Coe->RtCtx->IDTable));
  2024. IDTableRec = Coe->RtCtx->IDTable.pDataRecord;
  2025. FRS_ASSERT(IDTableRec != NULL);
  2026. WStatus = FrsCreateFileRelativeById(Handle,
  2027. Coe->NewReplica->pVme->VolumeHandle,
  2028. &IDTableRec->ParentGuid,
  2029. OBJECT_ID_LENGTH,
  2030. FILE_ATTRIBUTE_NORMAL,
  2031. FileName,
  2032. (USHORT)(wcslen(FileName) * sizeof(WCHAR)),
  2033. NULL,
  2034. FILE_OPEN,
  2035. // DELETE | READ_ACCESS | FILE_WRITE_ATTRIBUTES);
  2036. DELETE | READ_ATTRIB_ACCESS | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY);
  2037. if (WIN_SUCCESS(WStatus)) {
  2038. //
  2039. // Get the file's oid and check it against the change order.
  2040. //
  2041. WStatus = FrsCheckObjectId(Coc->FileName, *Handle, &Coc->FileGuid);
  2042. if (WIN_SUCCESS(WStatus)) {
  2043. goto RETURN;
  2044. }
  2045. CHANGE_ORDER_TRACE(3, Coe, "File OID mismatch CO, after IDTableRec->ParentGuid");
  2046. FRS_CLOSE(*Handle);
  2047. } else {
  2048. CHANGE_ORDER_TRACEW(3, Coe, "File open failed under IDTableRec->ParentGuid", WStatus);
  2049. }
  2050. //
  2051. // If this is a delete change order then we may have a problem if the file
  2052. // has been moved to a different parent dir by a local file operation.
  2053. // The local change order that did this can be rejected if the remote
  2054. // CO delete is processed first so the local co fails reconcile. But the
  2055. // ondisk rename has been completed and when the remote CO delete tries to
  2056. // delete the file it may not be in either the parent dir from the remote
  2057. // CO or the parent dir from the IDTable. To cover this case we find the
  2058. // TRUE parent dir and check to see if the file is still in the replica tree.
  2059. // If it is then we delete it using the TRUE parent dir. IF it isn't then
  2060. // return success since the file is already outside the tree.
  2061. // Note that a sharing conflict on the target file can block the delete
  2062. // for an extended period of time so the timing window in which this can
  2063. // occur can be pretty wide.
  2064. //
  2065. //
  2066. // We also need to deal with the case where a new file is still sitting in
  2067. // the preinstall directory (and the CO is in install_rename_retry.)
  2068. // In that case we will have failed to find the file under the old parent from
  2069. // the CO or under the parent listed in the IDTable.
  2070. //
  2071. if (DOES_CO_DELETE_FILE_NAME(Coc)) {
  2072. if (JrnlIsChangeOrderInReplica(Coe, &ParentFid)) {
  2073. UseActualLocation = TRUE;
  2074. } else {
  2075. //
  2076. // File not in the replica tree any more so tell the caller.
  2077. //
  2078. WStatus = ERROR_FILE_NOT_FOUND;
  2079. goto RETURN;
  2080. }
  2081. }
  2082. if((ULONGLONG)ParentFid == Coe->NewReplica->PreInstallFid) {
  2083. UseActualLocation = TRUE;
  2084. }
  2085. if (UseActualLocation) {
  2086. WStatus = FrsCreateFileRelativeById(Handle,
  2087. Coe->NewReplica->pVme->VolumeHandle,
  2088. &ParentFid,
  2089. FILE_ID_LENGTH,
  2090. FILE_ATTRIBUTE_NORMAL,
  2091. FileName,
  2092. (USHORT)(wcslen(FileName) * sizeof(WCHAR)),
  2093. NULL,
  2094. FILE_OPEN,
  2095. // DELETE | READ_ACCESS | FILE_WRITE_ATTRIBUTES);
  2096. DELETE | READ_ATTRIB_ACCESS | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY);
  2097. if (WIN_SUCCESS(WStatus)) {
  2098. //
  2099. // Get the file's oid and check it against the change order.
  2100. //
  2101. WStatus = FrsCheckObjectId(Coc->FileName, *Handle, &Coc->FileGuid);
  2102. if (WIN_SUCCESS(WStatus)) {
  2103. goto RETURN;
  2104. }
  2105. CHANGE_ORDER_TRACE(3, Coe, "File OID mismatch with CO after TRUE ParentFid open");
  2106. FRS_CLOSE(*Handle);
  2107. } else {
  2108. CHANGE_ORDER_TRACEW(3, Coe, "File open failed under True Parent FID", WStatus);
  2109. }
  2110. }
  2111. //
  2112. // The file is there but not where we expected it to be so send this CO
  2113. // through retry to let a subsequent Local CO get processed and update the
  2114. // IDTable.
  2115. //
  2116. WStatus = ERROR_RETRY;
  2117. RETURN:
  2118. CHANGE_ORDER_TRACEW(3, Coe, "Base File open", WStatus);
  2119. FrsFree(FileName);
  2120. return WStatus;
  2121. }
  2122. DWORD
  2123. FrsDeleteById(
  2124. IN PWCHAR VolumeName,
  2125. IN PWCHAR Name,
  2126. IN PVOLUME_MONITOR_ENTRY pVme,
  2127. IN PVOID Id,
  2128. IN DWORD IdLen
  2129. )
  2130. /*++
  2131. Routine Description:
  2132. Delete the file represented by Id
  2133. Arguments:
  2134. VolumeName - corresponding to pVme
  2135. Name - For error messages
  2136. pVme - volume entry
  2137. Id - Represents the name of the file or directory to be opened.
  2138. IdLen - length of Id (Fid or Oid)
  2139. Return Value:
  2140. Handle and win status
  2141. --*/
  2142. {
  2143. #undef DEBSUB
  2144. #define DEBSUB "FrsDeleteById"
  2145. DWORD WStatus;
  2146. HANDLE Handle = INVALID_HANDLE_VALUE;
  2147. PWCHAR Path = NULL;
  2148. PWCHAR FullPath = NULL;
  2149. DPRINT1(5, "++ Deleting %ws by id\n", Name);
  2150. //
  2151. // Open the source file
  2152. //
  2153. WStatus = FrsOpenSourceFileById(&Handle,
  2154. NULL,
  2155. NULL,
  2156. pVme->VolumeHandle,
  2157. Id,
  2158. IdLen,
  2159. // READ_ACCESS,
  2160. READ_ATTRIB_ACCESS,
  2161. ID_OPTIONS,
  2162. SHARE_ALL,
  2163. FILE_OPEN);
  2164. CLEANUP1_WS(4, "++ ERROR - FrsOpenSourceFileById(%ws);", Name, WStatus, CLEANUP);
  2165. //
  2166. // File's relative pathname
  2167. //
  2168. Path = FrsGetFullPathByHandle(Name, Handle);
  2169. if (Path) {
  2170. FullPath = FrsWcsCat(VolumeName, Path);
  2171. }
  2172. FRS_CLOSE(Handle);
  2173. if (FullPath == NULL) {
  2174. DPRINT1(4, "++ ERROR - FrsGetFullPathByHandle(%ws)\n", Name);
  2175. WIN_SET_FAIL(WStatus);
  2176. goto CLEANUP;
  2177. }
  2178. //
  2179. // Open the file relative to the parent using the true filename.
  2180. //
  2181. WStatus = FrsOpenSourceFileW(&Handle,
  2182. FullPath,
  2183. // DELETE | READ_ACCESS | FILE_WRITE_ATTRIBUTES,
  2184. DELETE | READ_ATTRIB_ACCESS | FILE_WRITE_ATTRIBUTES,
  2185. OPEN_OPTIONS);
  2186. CLEANUP2_WS(4, "++ ERROR - FrsOpenSourceFile(%ws -> %ws);",
  2187. Name, FullPath, WStatus, CLEANUP);
  2188. //
  2189. // Handles can be marked so that any usn records resulting from
  2190. // operations on the handle will have the same "mark". In this
  2191. // case, the mark is a bit in the SourceInfo field of the usn
  2192. // record. The mark tells NtFrs to ignore the usn record during
  2193. // recovery because this was a NtFrs generated change.
  2194. //
  2195. WStatus = FrsMarkHandle(pVme->VolumeHandle, Handle);
  2196. CLEANUP1_WS(0, "++ WARN - FrsMarkHandle(%ws);", Name, WStatus, RETURN_SUCCESS);
  2197. //
  2198. // Get the file's oid and check it against the id
  2199. //
  2200. if (IdLen == OBJECT_ID_LENGTH) {
  2201. WStatus = FrsCheckObjectId(Name, Handle, Id);
  2202. CLEANUP1_WS(4, "++ ERROR - FrsCheckObjectId(%ws);", Name, WStatus, CLEANUP);
  2203. }
  2204. WStatus = FrsResetAttributesForReplication(FullPath, Handle);
  2205. DPRINT1_WS(4, "++ ERROR - FrsResetAttributesForReplication(%ws):", FullPath, WStatus);
  2206. WStatus = FrsDeleteByHandle(Name, Handle);
  2207. FrsCloseWithUsnDampening(Name, &Handle, pVme->FrsWriteFilter, NULL);
  2208. CLEANUP1_WS(4, "++ ERROR - FrsDeleteByHandle(%ws);", Name, WStatus, CLEANUP);
  2209. CLEANUP:
  2210. FRS_CLOSE(Handle);
  2211. FrsFree(Path);
  2212. FrsFree(FullPath);
  2213. return WStatus;
  2214. RETURN_SUCCESS:
  2215. WStatus = ERROR_SUCCESS;
  2216. goto CLEANUP;
  2217. }
  2218. BOOL
  2219. FrsCloseWithUsnDampening(
  2220. IN PWCHAR Name,
  2221. IN OUT PHANDLE Handle,
  2222. IN PQHASH_TABLE FrsWriteFilter,
  2223. OUT USN *RetUsn
  2224. )
  2225. /*++
  2226. Routine Description:
  2227. Close the handle after insuring that any modifications made to the
  2228. file will not generate change orders.
  2229. Arguments:
  2230. Name - File name for error messages.
  2231. Handle - Handle to the replica set file file being closed. Nop if
  2232. INVALID_HANDLE_VALUE.
  2233. Replica - ptr to Replica struct where this file was written.
  2234. This gets us to the volume write filter table to record the USN.
  2235. RetUsn - ptr to return location for the close USN. NULL if not requested.
  2236. Return Value:
  2237. TRUE - handle is closed and any changes where dampened
  2238. FALSE - handle is closed but replication was *not* dampened
  2239. --*/
  2240. {
  2241. #undef DEBSUB
  2242. #define DEBSUB "FrsCloseWithUsnDampening"
  2243. DWORD BytesReturned = 0;
  2244. USN Usn = 0;
  2245. ULONG GStatus;
  2246. BOOL RetStatus;
  2247. RetStatus = TRUE;
  2248. if (!HANDLE_IS_VALID(*Handle)) {
  2249. return TRUE;
  2250. }
  2251. //
  2252. // Get the lock on the Usn Write Filter table.
  2253. // We have to get this before the FSCTL_WRITE_USN_CLOSE_RECORD call
  2254. // which will generate the journal close record. THis closes the
  2255. // race between our subsequent update of the WriteFilter below
  2256. // and the journal thread that processes the USN close record.
  2257. //
  2258. QHashAcquireLock(FrsWriteFilter);
  2259. //
  2260. // Close the file and force out the journal close record now. This
  2261. // call returns the USN of the generated close record so we can filter
  2262. // it out of the journal record stream.
  2263. //
  2264. if (!DeviceIoControl(*Handle,
  2265. FSCTL_WRITE_USN_CLOSE_RECORD,
  2266. NULL, 0,
  2267. &Usn, sizeof(USN),
  2268. &BytesReturned, NULL)) {
  2269. //
  2270. // Access denied is returned if there is another open
  2271. //
  2272. if (GetLastError() != ERROR_ACCESS_DENIED) {
  2273. DPRINT1_WS(0, "++ Can't dampen replication on %ws;", Name, GetLastError());
  2274. } else {
  2275. DPRINT1(0, "++ Can't dampen %ws; access denied\n", Name);
  2276. }
  2277. RetStatus = FALSE;
  2278. }
  2279. RetStatus = RetStatus && (BytesReturned == sizeof(USN));
  2280. if (RetStatus) {
  2281. //
  2282. // Put the USN in the FrsWriteFilter table for the replica so we
  2283. // can ignore it and the drop the lock on the table.
  2284. //
  2285. GStatus = QHashInsert(FrsWriteFilter, &Usn, &Usn, 0, TRUE);
  2286. QHashReleaseLock(FrsWriteFilter);
  2287. if (GStatus != GHT_STATUS_SUCCESS ) {
  2288. DPRINT1(0, "++ QHashInsert error: %d\n", GStatus);
  2289. RetStatus = FALSE;
  2290. }
  2291. } else {
  2292. QHashReleaseLock(FrsWriteFilter);
  2293. }
  2294. //
  2295. // Return the close USN.
  2296. //
  2297. if (RetUsn != NULL) {
  2298. *RetUsn = Usn;
  2299. }
  2300. //
  2301. // Now do the normal close to release the handle. NTFS completed its
  2302. // close work above.
  2303. //
  2304. FRS_CLOSE(*Handle);
  2305. DPRINT2(5, "++ Dampening %s on %ws\n", (RetStatus) ? "Succeeded" : "Failed", Name);
  2306. return RetStatus;
  2307. }
  2308. VOID
  2309. ProcessOpenByIdStatus(
  2310. IN HANDLE Handle,
  2311. IN ULONG NtStatus,
  2312. IN PVOID ObjectId,
  2313. IN ULONG Length
  2314. )
  2315. /*++
  2316. Routine Description:
  2317. Print the results of an open-by-id.
  2318. Arguments:
  2319. NtStatus
  2320. ObjectId
  2321. Length
  2322. Return Value:
  2323. None.
  2324. --*/
  2325. {
  2326. #undef DEBSUB
  2327. #define DEBSUB "ProcessOpenByIdStatus:"
  2328. CHAR GuidStr[GUID_CHAR_LEN];
  2329. PWCHAR Path;
  2330. if (!NT_SUCCESS(NtStatus)) {
  2331. //
  2332. // Note: The following call seems to generate intermittant AVs in the
  2333. // symbol lookup code. Only include it for testing.
  2334. //
  2335. //STACK_TRACE_AND_PRINT(2);
  2336. if (Length == FILE_ID_LENGTH) {
  2337. DPRINT2_NT(1, "++ %08X %08X Fid Open failed;",
  2338. *((PULONG)ObjectId+1), *(PULONG)ObjectId, NtStatus);
  2339. } else {
  2340. GuidToStr((GUID *) ObjectId, GuidStr);
  2341. DPRINT1_NT(1, "++ %s ObjectId Open failed;", GuidStr, NtStatus);
  2342. }
  2343. return;
  2344. }
  2345. //
  2346. // Open succeeded.
  2347. //
  2348. if (Length == FILE_ID_LENGTH) {
  2349. DPRINT2(4,"++ %08X %08X Fid Opened succesfully\n",
  2350. *((PULONG)ObjectId+1), *((PULONG)ObjectId));
  2351. } else {
  2352. GuidToStr((GUID *) ObjectId, GuidStr);
  2353. DPRINT1(4, "++ %s ObjectId Opened succesfully\n", GuidStr);
  2354. }
  2355. if (DoDebug(4, DEBSUB)) {
  2356. Path = FrsGetFullPathByHandle(L"Unknown", Handle);
  2357. if (Path) {
  2358. DPRINT1(4, "++ Filename is: %ws\n", Path);
  2359. }
  2360. FrsFree(Path);
  2361. }
  2362. }
  2363. DWORD
  2364. FrsForceOpenId(
  2365. OUT PHANDLE Handle,
  2366. IN OUT OVERLAPPED *OpLock, OPTIONAL
  2367. IN PVOLUME_MONITOR_ENTRY pVme,
  2368. IN PVOID Id,
  2369. IN DWORD IdLen,
  2370. IN ACCESS_MASK DesiredAccess,
  2371. IN ULONG CreateOptions,
  2372. IN ULONG ShareMode,
  2373. IN ULONG CreateDisposition
  2374. )
  2375. /*++
  2376. Routine Description:
  2377. Open the file for the desired access. If the open fails, reset
  2378. the readonly/system/hidden attributes and retry. In any case,
  2379. make sure the attributes are reset to their original value
  2380. before returning.
  2381. Arguments:
  2382. Handle - Returns the file handle.
  2383. OpLock - Overlapped struct for an oplock (optional).
  2384. pVme - volume entry
  2385. Id - Represents the name of the file or directory to be opened.
  2386. IdLen - length of Id (Fid or Oid)
  2387. DesiredAccess - see replutil.h for defined access modes (xxx_ACCESS)
  2388. CreateOptions - see replutil.h for defined options (xxx_OPTIONS
  2389. ShareMode - standard share modes defined in sdk
  2390. CreateDisposition - E.g., FILE_OPEN or FILE_OVERWRITE
  2391. Return Value:
  2392. Win error status.
  2393. --*/
  2394. {
  2395. #undef DEBSUB
  2396. #define DEBSUB "FrsForceOpenId:"
  2397. HANDLE AttrHandle;
  2398. ULONG WStatus, WStatus1;
  2399. ULONG AttrWStatus;
  2400. FILE_NETWORK_OPEN_INFORMATION FileNetworkOpenInfo;
  2401. DPRINT2(5, "++ Attempting to force open Id %08x %08x (%d bytes)\n",
  2402. PRINTQUAD((*(PULONGLONG)Id)), IdLen);
  2403. //
  2404. // Open the file
  2405. //
  2406. WStatus = FrsOpenSourceFileById(Handle,
  2407. NULL,
  2408. OpLock,
  2409. pVme->VolumeHandle,
  2410. Id,
  2411. IdLen,
  2412. DesiredAccess,
  2413. CreateOptions,
  2414. ShareMode,
  2415. CreateDisposition);
  2416. //
  2417. // File has been opened successfully
  2418. //
  2419. if (WIN_SUCCESS(WStatus)) {
  2420. DPRINT2(5, "++ Successfully opened Id %08x %08x (%d)\n",
  2421. PRINTQUAD((*(PULONGLONG)Id)), IdLen);
  2422. return WStatus;
  2423. }
  2424. //
  2425. // File has been deleted; done
  2426. //
  2427. if (WIN_NOT_FOUND(WStatus)) {
  2428. DPRINT2(4, "++ Id %08x %08x (%d) not found\n",
  2429. PRINTQUAD((*(PULONGLONG)Id)), IdLen);
  2430. return WStatus;
  2431. }
  2432. //
  2433. // Not an attribute problem
  2434. //
  2435. if (!WIN_ACCESS_DENIED(WStatus)) {
  2436. DPRINT2_WS(4, "++ Open Id %08x %08x (%d) failed;",
  2437. PRINTQUAD((*(PULONGLONG)Id)), IdLen, WStatus);
  2438. return WStatus;
  2439. }
  2440. //
  2441. // Attempt to reset attributes (e.g., reset readonly)
  2442. //
  2443. AttrWStatus = FrsOpenSourceFileById(&AttrHandle,
  2444. &FileNetworkOpenInfo,
  2445. NULL,
  2446. pVme->VolumeHandle,
  2447. Id,
  2448. IdLen,
  2449. // READ_ACCESS | FILE_WRITE_ATTRIBUTES,
  2450. // STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | ACCESS_SYSTEM_SECURITY | SYNCHRONIZE,
  2451. READ_ATTRIB_ACCESS | WRITE_ATTRIB_ACCESS,
  2452. CreateOptions,
  2453. SHARE_ALL,
  2454. FILE_OPEN);
  2455. //
  2456. // Couldn't open the file for write-attribute access
  2457. //
  2458. if (!WIN_SUCCESS(AttrWStatus)) {
  2459. DPRINT2_WS(4, "++ Open Id %08x %08x (%d) for minimal access failed;",
  2460. PRINTQUAD((*(PULONGLONG)Id)), IdLen, WStatus);
  2461. return WStatus;
  2462. }
  2463. //
  2464. // Handles can be marked so that any usn records resulting from
  2465. // operations on the handle will have the same "mark". In this
  2466. // case, the mark is a bit in the SourceInfo field of the usn
  2467. // record. The mark tells NtFrs to ignore the usn record during
  2468. // recovery because this was a NtFrs generated change.
  2469. //
  2470. WStatus1 = FrsMarkHandle(pVme->VolumeHandle, AttrHandle);
  2471. DPRINT1_WS(0, "++ WARN - FrsMarkHandle(%08x %08x);",
  2472. PRINTQUAD((*(PULONGLONG)Id)), WStatus1);
  2473. //
  2474. // The file's attributes are not preventing the open; done
  2475. //
  2476. if (!(FileNetworkOpenInfo.FileAttributes & NOREPL_ATTRIBUTES)) {
  2477. DPRINT2_WS(4, "++ Id %08x %08x (%d)attributes not preventing open;",
  2478. PRINTQUAD((*(PULONGLONG)Id)), IdLen, WStatus);
  2479. FRS_CLOSE(AttrHandle);
  2480. return WStatus;
  2481. }
  2482. //
  2483. // Reset the attributes
  2484. //
  2485. WStatus1 = FrsSetFileAttributes(L"<unknown>",
  2486. AttrHandle,
  2487. FileNetworkOpenInfo.FileAttributes &
  2488. ~NOREPL_ATTRIBUTES);
  2489. if (!WIN_SUCCESS(WStatus1)) {
  2490. DPRINT2_WS(4, "++ Can't reset attributes for Id %08x %08x (%d);",
  2491. PRINTQUAD((*(PULONGLONG)Id)), IdLen, WStatus1);
  2492. FRS_CLOSE(AttrHandle);
  2493. return WStatus1;
  2494. }
  2495. //
  2496. // Try to open the file again
  2497. //
  2498. WStatus = FrsOpenSourceFileById(Handle,
  2499. NULL,
  2500. NULL,
  2501. pVme->VolumeHandle,
  2502. Id,
  2503. IdLen,
  2504. DesiredAccess,
  2505. CreateOptions,
  2506. SHARE_ALL,
  2507. CreateDisposition);
  2508. //
  2509. // Reset the original attributes
  2510. //
  2511. WStatus1 = FrsSetFileAttributes(L"<unknown>",
  2512. AttrHandle,
  2513. FileNetworkOpenInfo.FileAttributes);
  2514. if (!WIN_SUCCESS(WStatus1)) {
  2515. DPRINT2_WS(0, "++ ERROR - Can't set attributes for Id %08x %08x (%d);",
  2516. PRINTQUAD((*(PULONGLONG)Id)), IdLen, WStatus1);
  2517. }
  2518. //
  2519. // Close the handle that we used to set and reset attributes
  2520. //
  2521. FRS_CLOSE(AttrHandle);
  2522. DPRINT3(4, "++ Force open %08x %08x (%d) %s WITH SHARE ALL!\n",
  2523. PRINTQUAD((*(PULONGLONG)Id)), IdLen,
  2524. WIN_SUCCESS(WStatus) ? "Succeeded" : "Failed");
  2525. return (WStatus);
  2526. }
  2527. DWORD
  2528. FrsOpenSourceFileById(
  2529. OUT PHANDLE Handle,
  2530. OUT PFILE_NETWORK_OPEN_INFORMATION FileOpenInfo,
  2531. OUT OVERLAPPED *OpLock,
  2532. IN HANDLE VolumeHandle,
  2533. IN PVOID ObjectId,
  2534. IN ULONG Length,
  2535. IN ACCESS_MASK DesiredAccess,
  2536. IN ULONG CreateOptions,
  2537. IN ULONG ShareMode,
  2538. IN ULONG CreateDisposition
  2539. )
  2540. /*++
  2541. Routine Description:
  2542. This function opens the specified file by File ID or Object ID.
  2543. If the length is 8 perform a relative open using the file ID and the
  2544. volume handle passed in the VolumeHandle arg. If the length is 16
  2545. perform an object ID relative open using the volume handle.
  2546. Arguments:
  2547. Handle - Returns the file handle.
  2548. FileOpenInfo - If non-NULL, returns the FILE_NETWORK_OPEN_INFORMATION data.
  2549. OpLock - If non-NULL, the caller desires an oplock
  2550. VolumeHandle - The handle for a FileID based relative open.
  2551. ObjectId - Represents the name of the file or directory to be opened.
  2552. Length - 8 for file IDs and 16 for object IDs.
  2553. DesiredAccess - see replutil.h for defined access modes (xxx_ACCESS)
  2554. CreateOptions - see replutil.h for defined options (xxx_OPTIONS
  2555. ShareMode - standard share modes defined in sdk
  2556. CreateDisposition - E.g., FILE_OPEN or FILE_OVERWRITE
  2557. Return Value:
  2558. Win error status.
  2559. --*/
  2560. {
  2561. #undef DEBSUB
  2562. #define DEBSUB "FrsOpenSourceFileById:"
  2563. ULONG Ignored;
  2564. NTSTATUS NtStatus;
  2565. OBJECT_ATTRIBUTES ObjectAttributes;
  2566. IO_STATUS_BLOCK IoStatusBlock;
  2567. UNICODE_STRING str;
  2568. FRS_ASSERT(HANDLE_IS_VALID(VolumeHandle));
  2569. FRS_ASSERT(Length == OBJECT_ID_LENGTH || Length == FILE_ID_LENGTH);
  2570. *Handle = INVALID_HANDLE_VALUE;
  2571. //
  2572. // Object attributes (e.g., the file's fid or oid
  2573. //
  2574. str.Length = (USHORT)Length;
  2575. str.MaximumLength = (USHORT)Length;
  2576. str.Buffer = ObjectId;
  2577. InitializeObjectAttributes(&ObjectAttributes,
  2578. &str,
  2579. OBJ_CASE_INSENSITIVE,
  2580. VolumeHandle,
  2581. NULL);
  2582. //
  2583. // Optional oplock
  2584. //
  2585. if (OpLock != NULL) {
  2586. ZeroMemory(OpLock, sizeof(OVERLAPPED));
  2587. OpLock->hEvent = FrsCreateEvent(TRUE, FALSE);
  2588. CreateOptions &= ~FILE_SYNCHRONOUS_IO_NONALERT;
  2589. }
  2590. NtStatus = NtCreateFile(Handle,
  2591. DesiredAccess,
  2592. &ObjectAttributes,
  2593. &IoStatusBlock,
  2594. NULL,
  2595. FILE_ATTRIBUTE_NORMAL,
  2596. ShareMode,
  2597. CreateDisposition,
  2598. CreateOptions,
  2599. NULL,
  2600. 0);
  2601. //
  2602. // Apply oplock if requested
  2603. //
  2604. if (NT_SUCCESS(NtStatus) && OpLock) {
  2605. if (!DeviceIoControl(*Handle,
  2606. FSCTL_REQUEST_FILTER_OPLOCK,
  2607. NULL,
  2608. 0,
  2609. NULL,
  2610. 0,
  2611. &Ignored,
  2612. OpLock)) {
  2613. if (GetLastError() != ERROR_IO_PENDING) {
  2614. DPRINT_WS(3, "++ WARN: Can't get oplock;", GetLastError());
  2615. //
  2616. // Cleanup the handles
  2617. //
  2618. FRS_CLOSE(OpLock->hEvent);
  2619. }
  2620. }
  2621. }
  2622. //
  2623. // Report status
  2624. //
  2625. ProcessOpenByIdStatus(*Handle, NtStatus, ObjectId, Length);
  2626. //
  2627. // Couldn't open; return status
  2628. //
  2629. if (!NT_SUCCESS(NtStatus) ) {
  2630. *Handle = INVALID_HANDLE_VALUE;
  2631. DPRINT_NT(0, "++ ERROR - NtCreateFile failed :", NtStatus);
  2632. return FrsSetLastNTError(NtStatus);
  2633. }
  2634. //
  2635. // Return some file info and the file handle.
  2636. //
  2637. if (FileOpenInfo) {
  2638. NtStatus = NtQueryInformationFile(*Handle,
  2639. &IoStatusBlock,
  2640. FileOpenInfo,
  2641. sizeof(FILE_NETWORK_OPEN_INFORMATION),
  2642. FileNetworkOpenInformation);
  2643. if (!NT_SUCCESS(NtStatus) ) {
  2644. //
  2645. // Cleanup the handles
  2646. //
  2647. DPRINT_NT(0, "++ NtQueryInformationFile - FileNetworkOpenInformation failed:", NtStatus);
  2648. FRS_CLOSE(*Handle);
  2649. if (OpLock != NULL) {
  2650. FRS_CLOSE(OpLock->hEvent);
  2651. }
  2652. return FrsSetLastNTError(NtStatus);
  2653. }
  2654. }
  2655. return FrsSetLastNTError(NtStatus);
  2656. }
  2657. DWORD
  2658. FrsCreateFileRelativeById(
  2659. OUT PHANDLE Handle,
  2660. IN HANDLE VolumeHandle,
  2661. IN PVOID ParentObjectId,
  2662. IN ULONG OidLength,
  2663. IN ULONG FileCreateAttributes,
  2664. IN PWCHAR BaseFileName,
  2665. IN USHORT FileNameLen,
  2666. IN PLARGE_INTEGER AllocationSize,
  2667. IN ULONG CreateDisposition,
  2668. IN ACCESS_MASK DesiredAccess
  2669. )
  2670. /*++
  2671. Routine Description:
  2672. This function creates a new file in the directory specified by the parent
  2673. file object ID. It does a replative open of the parent using the volume
  2674. handle provided. Then it does a relative open of the target file using
  2675. the parent handle and the file name.
  2676. If the length is 8 perform a relative open using the file ID and the
  2677. volume handle passed in the VolumeHandle arg. If the length is 16
  2678. perform an object ID relative open using the volume handle.
  2679. The file attributes parameter is used to decide if the create is a
  2680. file or a directory.
  2681. Arguments:
  2682. Handle - Returns the file handle.
  2683. VolumeHandle - The handle for a ID based relative open.
  2684. ParentObjectId - The object or file id of the parent directory. If NULL
  2685. open the file relative to the Volume Handle.
  2686. OidLength - 8 for file IDs and 16 for object IDs. (len of parent oid)
  2687. FileCreateAttributes - Initial File Create Attributes
  2688. BaseFileName - ptr to NULL terminated file name
  2689. FileNameLen - File name length (not incl the null) in bytes.
  2690. AllocationSize - The allocation size for the file.
  2691. CreateDisposition - E.g., FILE_CREATE or FILE_OPEN
  2692. DesiredAccess - Access rights
  2693. Return Value:
  2694. WIN32 error status. Use GetLastError() to get the win32 error code.
  2695. If the file already exsists the Win32 error return is ERROR_ALREADY_EXISTS.
  2696. The NT error status is STATUS_OBJECT_NAME_COLLISION.
  2697. --*/
  2698. {
  2699. #undef DEBSUB
  2700. #define DEBSUB "FrsCreateFileRelativeById:"
  2701. UNICODE_STRING UStr;
  2702. DWORD WStatus;
  2703. NTSTATUS NtStatus;
  2704. NTSTATUS NtStatus2;
  2705. HANDLE File, DirHandle;
  2706. ULONG ShareMode;
  2707. ULONG CreateOptions;
  2708. ULONG EaSize;
  2709. OBJECT_ATTRIBUTES ObjectAttributes;
  2710. IO_STATUS_BLOCK IoStatusBlock;
  2711. PFILE_FULL_EA_INFORMATION EaBuffer;
  2712. PFILE_NAME_INFORMATION FileName;
  2713. CHAR GuidStr[GUID_CHAR_LEN];
  2714. CHAR NameBuffer[sizeof(ULONG) + (sizeof(WCHAR)*(MAX_PATH+1))];
  2715. *Handle = INVALID_HANDLE_VALUE;
  2716. //
  2717. // Open the parent directory using the object ID provided.
  2718. //
  2719. if (ParentObjectId != NULL) {
  2720. WStatus = FrsOpenSourceFileById(&DirHandle,
  2721. NULL,
  2722. NULL,
  2723. VolumeHandle,
  2724. ParentObjectId,
  2725. OidLength,
  2726. // READ_ACCESS,
  2727. READ_ATTRIB_ACCESS | FILE_LIST_DIRECTORY,
  2728. ID_OPTIONS,
  2729. SHARE_ALL,
  2730. FILE_OPEN);
  2731. if (!WIN_SUCCESS(WStatus)) {
  2732. DPRINT_WS(1, "++ ERROR - Open on parent dir failed;", WStatus);
  2733. return WStatus;
  2734. }
  2735. } else {
  2736. DirHandle = VolumeHandle;
  2737. OidLength = 0;
  2738. }
  2739. //
  2740. // Create the target file.
  2741. //
  2742. FrsSetUnicodeStringFromRawString(&UStr, FileNameLen, BaseFileName, FileNameLen);
  2743. InitializeObjectAttributes( &ObjectAttributes,
  2744. &UStr,
  2745. OBJ_CASE_INSENSITIVE,
  2746. DirHandle,
  2747. NULL );
  2748. //
  2749. // Mask off the junk that may have come in from the journal
  2750. //
  2751. FileCreateAttributes &= FILE_ATTRIBUTE_VALID_FLAGS;
  2752. //
  2753. // Set create options depending on file or dir.
  2754. //
  2755. CreateOptions = FILE_OPEN_FOR_BACKUP_INTENT // FILE_FLAG_BACKUP_SEMANTICS
  2756. | FILE_OPEN_REPARSE_POINT
  2757. | FILE_OPEN_NO_RECALL // Don't migrate data for HSM
  2758. | FILE_SEQUENTIAL_ONLY
  2759. | FILE_SYNCHRONOUS_IO_NONALERT;
  2760. if (CreateDisposition == FILE_CREATE || CreateDisposition == FILE_OPEN_IF) {
  2761. if (FileCreateAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  2762. CreateOptions |= FILE_DIRECTORY_FILE;
  2763. CreateOptions &= ~(FILE_SEQUENTIAL_ONLY | FILE_OPEN_NO_RECALL);
  2764. } else {
  2765. CreateOptions |= FILE_NON_DIRECTORY_FILE;
  2766. }
  2767. }
  2768. EaBuffer = NULL;
  2769. EaSize = 0;
  2770. // ShareMode = 0; // no sharing
  2771. //
  2772. // Fix for Bug 186880
  2773. //
  2774. ShareMode = FILE_SHARE_READ; // share for read.
  2775. //
  2776. // Do the relative open.
  2777. //
  2778. DPRINT1(5, "++ DesiredAccess: %08x\n", DesiredAccess);
  2779. if (AllocationSize != NULL) {
  2780. DPRINT2(5, "++ AllocationSize: %08x %08x\n", AllocationSize->HighPart, AllocationSize->LowPart);
  2781. }
  2782. DPRINT1(5, "++ FileCreateAttributes: %08x\n", FileCreateAttributes);
  2783. DPRINT1(5, "++ ShareMode: %08x\n", ShareMode);
  2784. DPRINT1(5, "++ CreateDisposition: %08x\n", CreateDisposition);
  2785. DPRINT1(5, "++ CreateOptions: %08x\n", CreateOptions);
  2786. if (OidLength == 16) {
  2787. GuidToStr((GUID *) ParentObjectId, GuidStr);
  2788. DPRINT1(5, "++ Parent ObjectId: %s\n", GuidStr);
  2789. }
  2790. NtStatus = NtCreateFile(&File,
  2791. DesiredAccess,
  2792. &ObjectAttributes,
  2793. &IoStatusBlock,
  2794. AllocationSize, // Initial allocation size
  2795. FileCreateAttributes,
  2796. ShareMode,
  2797. CreateDisposition,
  2798. CreateOptions,
  2799. EaBuffer,
  2800. EaSize);
  2801. if (ParentObjectId != NULL) {
  2802. FRS_CLOSE(DirHandle);
  2803. }
  2804. if (!NT_SUCCESS(NtStatus)) {
  2805. DPRINT1_NT(5, "++ ERROR - CreateFile failed on %ws.", BaseFileName, NtStatus);
  2806. DPRINT1(5, "++ DesiredAccess: %08x\n", DesiredAccess);
  2807. if (AllocationSize != NULL) {
  2808. DPRINT2(5, "++ AllocationSize: %08x %08x\n", AllocationSize->HighPart, AllocationSize->LowPart);
  2809. }
  2810. DPRINT1(5, "++ FileCreateAttributes: %08x\n", FileCreateAttributes);
  2811. DPRINT1(5, "++ ShareMode: %08x\n", ShareMode);
  2812. DPRINT1(5, "++ CreateDisposition: %08x\n", CreateDisposition);
  2813. DPRINT1(5, "++ CreateOptions: %08x\n", CreateOptions);
  2814. if (OidLength == 16) {
  2815. GuidToStr((GUID *) ParentObjectId, GuidStr);
  2816. DPRINT1(5, "++ Parent ObjectId: %s\n", GuidStr);
  2817. }
  2818. if (NtStatus == STATUS_INVALID_PARAMETER) {
  2819. DPRINT(5, "++ Invalid parameter on open by ID likely means file not found.\n");
  2820. return ERROR_FILE_NOT_FOUND;
  2821. }
  2822. return FrsSetLastNTError(NtStatus);
  2823. }
  2824. if (DoDebug(5, DEBSUB)) {
  2825. FileName = (PFILE_NAME_INFORMATION) &NameBuffer[0];
  2826. FileName->FileNameLength = sizeof(NameBuffer) - sizeof(ULONG);
  2827. NtStatus2 = NtQueryInformationFile(File,
  2828. &IoStatusBlock,
  2829. FileName,
  2830. sizeof(NameBuffer),
  2831. FileNameInformation );
  2832. if (!NT_SUCCESS(NtStatus2)) {
  2833. DPRINT_NT(1, "++ NtQueryInformationFile - FileNameInformation failed:",
  2834. NtStatus2);
  2835. } else {
  2836. FileName->FileName[FileName->FileNameLength/2] = UNICODE_NULL;
  2837. DPRINT1(5, "++ Name of created file is: %ws\n", FileName->FileName); //
  2838. }
  2839. }
  2840. //
  2841. // Return the file handle.
  2842. //
  2843. *Handle = File;
  2844. return FrsSetLastNTError(NtStatus);
  2845. }
  2846. DWORD
  2847. FrsCreateFileRelativeById2(
  2848. OUT PHANDLE Handle,
  2849. IN HANDLE VolumeHandle,
  2850. IN PVOID ParentObjectId,
  2851. IN ULONG OidLength,
  2852. IN ULONG FileCreateAttributes,
  2853. IN PWCHAR BaseFileName,
  2854. IN USHORT FileNameLen,
  2855. IN PLARGE_INTEGER AllocationSize,
  2856. IN ULONG CreateDisposition,
  2857. IN ACCESS_MASK DesiredAccess,
  2858. IN ULONG ShareMode
  2859. )
  2860. /*++
  2861. Routine Description:
  2862. This function creates a new file in the directory specified by the parent
  2863. file object ID. It does a replative open of the parent using the volume
  2864. handle provided. Then it does a relative open of the target file using
  2865. the parent handle and the file name.
  2866. If the length is 8 perform a relative open using the file ID and the
  2867. volume handle passed in the VolumeHandle arg. If the length is 16
  2868. perform an object ID relative open using the volume handle.
  2869. The file attributes parameter is used to decide if the create is a
  2870. file or a directory.
  2871. Arguments:
  2872. Handle - Returns the file handle.
  2873. VolumeHandle - The handle for a ID based relative open.
  2874. ParentObjectId - The object or file id of the parent directory. If NULL
  2875. open the file relative to the Volume Handle.
  2876. OidLength - 8 for file IDs and 16 for object IDs. (len of parent oid)
  2877. FileCreateAttributes - Initial File Create Attributes
  2878. BaseFileName - ptr to NULL terminated file name
  2879. FileNameLen - File name length (not incl the null) in bytes.
  2880. AllocationSize - The allocation size for the file.
  2881. CreateDisposition - E.g., FILE_CREATE or FILE_OPEN
  2882. DesiredAccess - Access rights
  2883. ShareMode - The sharing mode.
  2884. Return Value:
  2885. WIN32 error status. Use GetLastError() to get the win32 error code.
  2886. If the file already exsists the Win32 error return is ERROR_ALREADY_EXISTS.
  2887. The NT error status is STATUS_OBJECT_NAME_COLLISION.
  2888. --*/
  2889. {
  2890. #undef DEBSUB
  2891. #define DEBSUB "FrsCreateFileRelativeById2:"
  2892. UNICODE_STRING UStr;
  2893. DWORD WStatus;
  2894. NTSTATUS NtStatus;
  2895. NTSTATUS NtStatus2;
  2896. HANDLE File, DirHandle;
  2897. ULONG CreateOptions;
  2898. ULONG EaSize;
  2899. OBJECT_ATTRIBUTES ObjectAttributes;
  2900. IO_STATUS_BLOCK IoStatusBlock;
  2901. PFILE_FULL_EA_INFORMATION EaBuffer;
  2902. PFILE_NAME_INFORMATION FileName;
  2903. CHAR GuidStr[GUID_CHAR_LEN];
  2904. CHAR NameBuffer[sizeof(ULONG) + (sizeof(WCHAR)*(MAX_PATH+1))];
  2905. *Handle = INVALID_HANDLE_VALUE;
  2906. //
  2907. // Open the parent directory using the object ID provided.
  2908. //
  2909. if (ParentObjectId != NULL) {
  2910. WStatus = FrsOpenSourceFileById(&DirHandle,
  2911. NULL,
  2912. NULL,
  2913. VolumeHandle,
  2914. ParentObjectId,
  2915. OidLength,
  2916. // READ_ACCESS,
  2917. READ_ATTRIB_ACCESS | FILE_LIST_DIRECTORY,
  2918. ID_OPTIONS,
  2919. SHARE_ALL,
  2920. FILE_OPEN);
  2921. if (!WIN_SUCCESS(WStatus)) {
  2922. DPRINT_WS(1, "++ ERROR - Open on parent dir failed;", WStatus);
  2923. return WStatus;
  2924. }
  2925. } else {
  2926. DirHandle = VolumeHandle;
  2927. OidLength = 0;
  2928. }
  2929. //
  2930. // Create the target file.
  2931. //
  2932. FrsSetUnicodeStringFromRawString(&UStr, FileNameLen, BaseFileName, FileNameLen);
  2933. InitializeObjectAttributes( &ObjectAttributes,
  2934. &UStr,
  2935. OBJ_CASE_INSENSITIVE,
  2936. DirHandle,
  2937. NULL );
  2938. //
  2939. // Mask off the junk that may have come in from the journal
  2940. //
  2941. FileCreateAttributes &= FILE_ATTRIBUTE_VALID_FLAGS;
  2942. //
  2943. // Set create options depending on file or dir.
  2944. //
  2945. CreateOptions = FILE_OPEN_FOR_BACKUP_INTENT // FILE_FLAG_BACKUP_SEMANTICS
  2946. | FILE_OPEN_REPARSE_POINT
  2947. | FILE_OPEN_NO_RECALL // Don't migrate data for HSM
  2948. | FILE_SEQUENTIAL_ONLY
  2949. | FILE_SYNCHRONOUS_IO_NONALERT;
  2950. if (CreateDisposition == FILE_CREATE || CreateDisposition == FILE_OPEN_IF) {
  2951. if (FileCreateAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  2952. CreateOptions |= FILE_DIRECTORY_FILE;
  2953. CreateOptions &= ~(FILE_SEQUENTIAL_ONLY | FILE_OPEN_NO_RECALL);
  2954. } else {
  2955. CreateOptions |= FILE_NON_DIRECTORY_FILE;
  2956. }
  2957. }
  2958. EaBuffer = NULL;
  2959. EaSize = 0;
  2960. //
  2961. // Do the relative open.
  2962. //
  2963. DPRINT1(5, "++ DesiredAccess: %08x\n", DesiredAccess);
  2964. if (AllocationSize != NULL) {
  2965. DPRINT2(5, "++ AllocationSize: %08x %08x\n", AllocationSize->HighPart, AllocationSize->LowPart);
  2966. }
  2967. DPRINT1(5, "++ FileCreateAttributes: %08x\n", FileCreateAttributes);
  2968. DPRINT1(5, "++ ShareMode: %08x\n", ShareMode);
  2969. DPRINT1(5, "++ CreateDisposition: %08x\n", CreateDisposition);
  2970. DPRINT1(5, "++ CreateOptions: %08x\n", CreateOptions);
  2971. if (OidLength == 16) {
  2972. GuidToStr((GUID *) ParentObjectId, GuidStr);
  2973. DPRINT1(5, "++ Parent ObjectId: %s\n", GuidStr);
  2974. }
  2975. NtStatus = NtCreateFile(&File,
  2976. DesiredAccess,
  2977. &ObjectAttributes,
  2978. &IoStatusBlock,
  2979. AllocationSize, // Initial allocation size
  2980. FileCreateAttributes,
  2981. ShareMode,
  2982. CreateDisposition,
  2983. CreateOptions,
  2984. EaBuffer,
  2985. EaSize);
  2986. if (ParentObjectId != NULL) {
  2987. FRS_CLOSE(DirHandle);
  2988. }
  2989. if (!NT_SUCCESS(NtStatus)) {
  2990. DPRINT1_NT(5, "++ ERROR - CreateFile failed on %ws.", BaseFileName, NtStatus);
  2991. DPRINT1(5, "++ DesiredAccess: %08x\n", DesiredAccess);
  2992. if (AllocationSize != NULL) {
  2993. DPRINT2(5, "++ AllocationSize: %08x %08x\n", AllocationSize->HighPart, AllocationSize->LowPart);
  2994. }
  2995. DPRINT1(5, "++ FileCreateAttributes: %08x\n", FileCreateAttributes);
  2996. DPRINT1(5, "++ ShareMode: %08x\n", ShareMode);
  2997. DPRINT1(5, "++ CreateDisposition: %08x\n", CreateDisposition);
  2998. DPRINT1(5, "++ CreateOptions: %08x\n", CreateOptions);
  2999. if (OidLength == 16) {
  3000. GuidToStr((GUID *) ParentObjectId, GuidStr);
  3001. DPRINT1(5, "++ Parent ObjectId: %s\n", GuidStr);
  3002. }
  3003. if (NtStatus == STATUS_INVALID_PARAMETER) {
  3004. DPRINT(5, "++ Invalid parameter on open by ID likely means file not found.\n");
  3005. return ERROR_FILE_NOT_FOUND;
  3006. }
  3007. return FrsSetLastNTError(NtStatus);
  3008. }
  3009. if (DoDebug(5, DEBSUB)) {
  3010. FileName = (PFILE_NAME_INFORMATION) &NameBuffer[0];
  3011. FileName->FileNameLength = sizeof(NameBuffer) - sizeof(ULONG);
  3012. NtStatus2 = NtQueryInformationFile(File,
  3013. &IoStatusBlock,
  3014. FileName,
  3015. sizeof(NameBuffer),
  3016. FileNameInformation );
  3017. if (!NT_SUCCESS(NtStatus2)) {
  3018. DPRINT_NT(1, "++ NtQueryInformationFile - FileNameInformation failed:",
  3019. NtStatus2);
  3020. } else {
  3021. FileName->FileName[FileName->FileNameLength/2] = UNICODE_NULL;
  3022. DPRINT1(5, "++ Name of created file is: %ws\n", FileName->FileName); //
  3023. }
  3024. }
  3025. //
  3026. // Return the file handle.
  3027. //
  3028. *Handle = File;
  3029. return FrsSetLastNTError(NtStatus);
  3030. }
  3031. DWORD
  3032. FrsDeleteFile(
  3033. IN PWCHAR Name
  3034. )
  3035. /*++
  3036. Routine Description:
  3037. Delete the file
  3038. Arguments:
  3039. Name
  3040. Return Value:
  3041. WStatus.
  3042. --*/
  3043. {
  3044. #undef DEBSUB
  3045. #define DEBSUB "FrsDeleteFile:"
  3046. DWORD WStatus = ERROR_SUCCESS;
  3047. //
  3048. // Delete file
  3049. //
  3050. DPRINT1(4, "++ Deleting %ws\n", Name);
  3051. if (!DeleteFile(Name)) {
  3052. WStatus = GetLastError();
  3053. if (WStatus != ERROR_FILE_NOT_FOUND &&
  3054. WStatus != ERROR_PATH_NOT_FOUND) {
  3055. DPRINT1_WS(0, "++ Can't delete file %ws;", Name, WStatus);
  3056. } else {
  3057. WStatus = ERROR_SUCCESS;
  3058. }
  3059. }
  3060. return WStatus;
  3061. }
  3062. DWORD
  3063. FrsCreateDirectory(
  3064. IN PWCHAR Name
  3065. )
  3066. /*++
  3067. Routine Description:
  3068. Create a directory
  3069. Arguments:
  3070. Name
  3071. Return Value:
  3072. Win32 Error Status
  3073. --*/
  3074. {
  3075. #undef DEBSUB
  3076. #define DEBSUB "FrsCreateDirectory:"
  3077. ULONG WStatus;
  3078. //
  3079. // Create the directory
  3080. //
  3081. if (!CreateDirectory(Name, NULL)) {
  3082. WStatus = GetLastError();
  3083. if (!WIN_ALREADY_EXISTS(WStatus)) {
  3084. DPRINT1_WS(0, "Can't create directory %ws;", Name, WStatus);
  3085. return WStatus;
  3086. }
  3087. }
  3088. return ERROR_SUCCESS;
  3089. }
  3090. DWORD
  3091. FrsVerifyVolume(
  3092. IN PWCHAR Path,
  3093. IN PWCHAR SetName,
  3094. IN ULONG Flags
  3095. )
  3096. /*++
  3097. Routine Description:
  3098. Does the volume exist and is it NTFS? If not generate an event log entry
  3099. and return non success.
  3100. Also if we are checking the volume for object id support then check
  3101. that the volume does not share the same Volume Serial Number with
  3102. other volumes in VolSerialNumberToDriveTable.
  3103. Arguments:
  3104. Path -- A path string with a volume component.
  3105. SetName -- the Replica set name for event log messages.
  3106. Flags -- The file system flags that must be set. The currently valid
  3107. set are:
  3108. FILE_CASE_SENSITIVE_SEARCH
  3109. FILE_CASE_PRESERVED_NAMES
  3110. FILE_UNICODE_ON_DISK
  3111. FILE_PERSISTENT_ACLS
  3112. FILE_FILE_COMPRESSION
  3113. FILE_VOLUME_QUOTAS
  3114. FILE_SUPPORTS_SPARSE_FILES
  3115. FILE_SUPPORTS_REPARSE_POINTS
  3116. FILE_SUPPORTS_REMOTE_STORAGE
  3117. FILE_VOLUME_IS_COMPRESSED
  3118. FILE_SUPPORTS_OBJECT_IDS
  3119. FILE_SUPPORTS_ENCRYPTION
  3120. FILE_NAMED_STREAMS
  3121. Return Value:
  3122. WIN32 Status
  3123. --*/
  3124. {
  3125. #undef DEBSUB
  3126. #define DEBSUB "FrsVerifyVolume:"
  3127. DWORD WStatus = ERROR_SUCCESS;
  3128. PWCHAR VolumeName = NULL;
  3129. ULONG FsAttributeInfoLength;
  3130. IO_STATUS_BLOCK Iosb;
  3131. NTSTATUS Status;
  3132. PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo = NULL;
  3133. HANDLE PathHandle = INVALID_HANDLE_VALUE;
  3134. DWORD VolumeInfoLength;
  3135. PFILE_FS_VOLUME_INFORMATION VolumeInfo = NULL;
  3136. PVOLUME_INFO_NODE VolumeInfoNode = NULL;
  3137. ULONG Colon = 0;
  3138. WCHAR LogicalDrive[5]; // "D:\<null><null>"
  3139. PGEN_ENTRY VolumeInfoNodeEntry = NULL;
  3140. PWCHAR ListOfVolumes = NULL;
  3141. PWCHAR TempListOfVolumes = NULL;
  3142. WCHAR VSNStr[MAX_PATH];// "%04x-%04x"
  3143. BOOL DuplicateVSNFound = FALSE;
  3144. if ((Path == NULL) || (wcslen(Path) == 0)) {
  3145. WStatus = ERROR_INVALID_PARAMETER;
  3146. goto RETURN;
  3147. }
  3148. //
  3149. // Always open the path by masking off the FILE_OPEN_REPARSE_POINT flag
  3150. // because we want to open the destination dir not the junction if the root
  3151. // happens to be a mount point.
  3152. //
  3153. WStatus = FrsOpenSourceFileW(&PathHandle,
  3154. Path,
  3155. GENERIC_READ,
  3156. FILE_OPEN_FOR_BACKUP_INTENT);
  3157. if (!WIN_SUCCESS(WStatus)) {
  3158. DPRINT1_WS(0, "ERROR - Unable to open root path %ws. Retry at next poll.",
  3159. Path, WStatus);
  3160. goto RETURN;
  3161. }
  3162. //
  3163. // Get the volume information.
  3164. //
  3165. FsAttributeInfoLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) +
  3166. MAXIMUM_VOLUME_LABEL_LENGTH;
  3167. FsAttributeInfo = FrsAlloc(FsAttributeInfoLength);
  3168. Status = NtQueryVolumeInformationFile(PathHandle,
  3169. &Iosb,
  3170. FsAttributeInfo,
  3171. FsAttributeInfoLength,
  3172. FileFsAttributeInformation);
  3173. if (!NT_SUCCESS(Status)) {
  3174. DPRINT2(0,"ERROR - Getting NtQueryVolumeInformationFile for %ws. NtStatus = %08x\n",
  3175. Path, Status);
  3176. goto RETURN;
  3177. }
  3178. if ((FsAttributeInfo->FileSystemAttributes & Flags) != Flags) {
  3179. DPRINT3(0, "++ Error - Required filesystem not present for %ws. Needed %08x, Found %08x\n",
  3180. Path, Flags, FsAttributeInfo->FileSystemAttributes);
  3181. WStatus = ERROR_INVALID_PARAMETER;
  3182. goto RETURN;
  3183. }
  3184. WStatus = ERROR_SUCCESS;
  3185. //
  3186. // If we are checking for object ids then we must be
  3187. // verifying the root volume. Also check that this volume
  3188. // does not share volumeserialnumber with any other volume
  3189. // on this computer. Currently (05/18/2002) we rely on
  3190. // VolumeSerialNumber being unique. We use it to find out
  3191. // which volume to open the journal on. If there are mutiple
  3192. // volumes on a machine with the same VSN then we could open
  3193. // the journal on the wrong volume. Print a eventlog message
  3194. // and return error.
  3195. //
  3196. if (Flags & FILE_SUPPORTS_OBJECT_IDS) {
  3197. VolumeInfoLength = sizeof(FILE_FS_VOLUME_INFORMATION) +
  3198. MAXIMUM_VOLUME_LABEL_LENGTH;
  3199. VolumeInfo = FrsAlloc(VolumeInfoLength);
  3200. Status = NtQueryVolumeInformationFile(PathHandle,
  3201. &Iosb,
  3202. VolumeInfo,
  3203. VolumeInfoLength,
  3204. FileFsVolumeInformation);
  3205. if (NT_SUCCESS(Status)) {
  3206. //
  3207. // Look for the volume if the mapping table exists.
  3208. //
  3209. if (VolSerialNumberToDriveTable != NULL) {
  3210. VolumeInfoNode = GTabLookup(VolSerialNumberToDriveTable,
  3211. &(VolumeInfo->VolumeSerialNumber),
  3212. NULL);
  3213. }
  3214. //
  3215. // If the volume is not found in the table or if the table is not yet
  3216. // initialized then initialize the table and add the drive taken from
  3217. // this path to the list of drives in the table. In most cases the
  3218. // drive extracted from the path will be same as the volume that hosts the
  3219. // path. If that is not the case then we re-build the table by
  3220. // enumerating all the drives on the computer below.
  3221. //
  3222. if (VolumeInfoNode == NULL) {
  3223. //
  3224. // Create the table and add the prefix drive to the table of drives.
  3225. // Find the position of colon in the path to extract the drive letter.
  3226. // The path may be of the form "d:\replicaroot" or "\\?\d:\replicaroot"
  3227. //
  3228. Colon = wcscspn(Path, L":");
  3229. if (Path[Colon] == L':') {
  3230. CopyMemory(LogicalDrive, &Path[Colon - 1], 3 * sizeof(WCHAR)); // "D:\"
  3231. LogicalDrive[3] = L'\0';
  3232. LogicalDrive[4] = L'\0';
  3233. } // else LogicalDrive remains NULL
  3234. //
  3235. // Add the drive and do not empty the table.
  3236. //
  3237. FrsBuildVolSerialNumberToDriveTable(LogicalDrive, FALSE);
  3238. VolumeInfoNode = GTabLookup(VolSerialNumberToDriveTable, &(VolumeInfo->VolumeSerialNumber), NULL);
  3239. }
  3240. //
  3241. // If the volume is still not found in the mapping table then it means that
  3242. // the prefix of the path (E.g. "D:\" if the path is "D:\replicaroot" ) is not the
  3243. // volume that hosts the path. In this case load the mapping table with all
  3244. // the drives on the computer and look for the volume again.
  3245. //
  3246. if (VolumeInfoNode == NULL) {
  3247. //
  3248. // Could not find the drive in the table. Rebuild the table by enumerating
  3249. // all the drives on the computer and try again.
  3250. //
  3251. DPRINT1(2, "WARN - Enumerating all drives on the computer to find the volume for path %ws\n", Path);
  3252. //
  3253. // Enumerate and add all drives to the table. Empty the table before starting.
  3254. //
  3255. FrsBuildVolSerialNumberToDriveTable(NULL, TRUE);
  3256. VolumeInfoNode = GTabLookup(VolSerialNumberToDriveTable, &(VolumeInfo->VolumeSerialNumber), NULL);
  3257. }
  3258. if (VolumeInfoNode) {
  3259. //
  3260. // Check if there are duplicates.
  3261. //
  3262. LOCK_GEN_TABLE(VolSerialNumberToDriveTable);
  3263. VolumeInfoNodeEntry = GTabLookupEntryNoLock(VolSerialNumberToDriveTable, &(VolumeInfo->VolumeSerialNumber), NULL);
  3264. if ((VolumeInfoNodeEntry != NULL) && (VolumeInfoNodeEntry->Dups != NULL)) {
  3265. //
  3266. // The volume we are verifying shares VSN with
  3267. // one or more other volumes. Collect data for the
  3268. // eventlog message.
  3269. //
  3270. wsprintf(VSNStr, L"%04x-%04x",
  3271. ((VolumeInfo->VolumeSerialNumber >> 16) & 0x0000ffff),
  3272. (VolumeInfo->VolumeSerialNumber & 0x0000ffff));
  3273. do {
  3274. VolumeInfoNode = VolumeInfoNodeEntry->Data;
  3275. if (ListOfVolumes != NULL) {
  3276. //
  3277. // DriveName is of the form \\.\D:
  3278. //
  3279. if (wcslen(VolumeInfoNode->DriveName) >= 6) {
  3280. TempListOfVolumes = FrsWcsCat3(ListOfVolumes,L", ",&VolumeInfoNode->DriveName[4]);
  3281. } else {
  3282. TempListOfVolumes = FrsWcsCat3(ListOfVolumes,L", ",VolumeInfoNode->DriveName);
  3283. }
  3284. FrsFree(ListOfVolumes);
  3285. } else {
  3286. if (wcslen(VolumeInfoNode->DriveName) >= 6) {
  3287. TempListOfVolumes = FrsWcsDup(&VolumeInfoNode->DriveName[4]);
  3288. }else{
  3289. TempListOfVolumes = FrsWcsDup(VolumeInfoNode->DriveName);
  3290. }
  3291. }
  3292. ListOfVolumes = TempListOfVolumes;
  3293. VolumeInfoNodeEntry = VolumeInfoNodeEntry->Dups;
  3294. } while ( VolumeInfoNodeEntry != NULL );
  3295. EPRINT2(EVENT_FRS_DUPLICATE_VSN,VSNStr,ListOfVolumes);
  3296. FrsFree(ListOfVolumes);
  3297. DuplicateVSNFound = TRUE;
  3298. }
  3299. UNLOCK_GEN_TABLE(VolSerialNumberToDriveTable);
  3300. } else {
  3301. DPRINT1(0, "ERROR - Volume not found for path %ws\n", Path);
  3302. WStatus = ERROR_FILE_NOT_FOUND;
  3303. }
  3304. } else {
  3305. DPRINT1_NT(1,"WARN - NtQueryVolumeInformationFile failed for %ws;", Path, Status);
  3306. WStatus = FrsSetLastNTError(Status);
  3307. }
  3308. }
  3309. RETURN:
  3310. if (!WIN_SUCCESS(WStatus)) {
  3311. if (WStatus == ERROR_INVALID_PARAMETER) {
  3312. //
  3313. // Generate an event log message.
  3314. //
  3315. VolumeName = FrsWcsVolume(Path);
  3316. EPRINT4(EVENT_FRS_VOLUME_NOT_SUPPORTED,
  3317. SetName,
  3318. ComputerName,
  3319. ((Path == NULL) ? L"<null>" : Path),
  3320. ((VolumeName == NULL) ? L"<null>" : VolumeName));
  3321. } else if (DuplicateVSNFound == FALSE){
  3322. //
  3323. // Something else is wrong. Print generic root
  3324. // invalid message.
  3325. //
  3326. EPRINT1(EVENT_FRS_ROOT_NOT_VALID, Path);
  3327. }
  3328. }
  3329. FrsFree(FsAttributeInfo);
  3330. FrsFree(VolumeInfo);
  3331. FRS_CLOSE(PathHandle);
  3332. FrsFree(VolumeName);
  3333. return WStatus;
  3334. }
  3335. DWORD
  3336. FrsCheckForNoReparsePoint(
  3337. IN PWCHAR Name
  3338. )
  3339. /*++
  3340. Routine Description:
  3341. Does the path reside on the same volume at the prefix drive name?
  3342. It won't exist on the same volume if any element of the path
  3343. is a reparse point pointing to a directory on another volume.
  3344. Arguments:
  3345. Name
  3346. Return Value:
  3347. WIN32 Status
  3348. --*/
  3349. {
  3350. #undef DEBSUB
  3351. #define DEBSUB "FrsCheckForNoReparsePoint:"
  3352. DWORD WStatus;
  3353. NTSTATUS Status;
  3354. PWCHAR Volume = NULL;
  3355. PWCHAR Temp = NULL;
  3356. HANDLE FileHandlePath;
  3357. HANDLE FileHandleDrive;
  3358. IO_STATUS_BLOCK Iosb;
  3359. PFILE_FS_VOLUME_INFORMATION VolumeInfoPath = NULL;
  3360. PFILE_FS_VOLUME_INFORMATION VolumeInfoDrive = NULL;
  3361. ULONG VolumeInfoLength;
  3362. if (!Name) {
  3363. return ERROR_INVALID_PARAMETER;
  3364. }
  3365. //
  3366. // Get the handle to the path passed in.
  3367. //
  3368. WStatus = FrsOpenSourceFileW(&FileHandlePath,
  3369. Name,
  3370. // READ_ACCESS,
  3371. READ_ATTRIB_ACCESS,
  3372. OPEN_OPTIONS & ~FILE_OPEN_REPARSE_POINT);
  3373. CLEANUP1_WS(4, "++ ERROR - FrsOpenSourceFile(%ws);", Name, WStatus, CLEANUP);
  3374. //
  3375. // Get the volume information for this handle.
  3376. //
  3377. VolumeInfoPath = FrsAlloc(sizeof(FILE_FS_VOLUME_INFORMATION) + MAXIMUM_VOLUME_LABEL_LENGTH);
  3378. VolumeInfoLength = sizeof(*VolumeInfoPath) + MAXIMUM_VOLUME_LABEL_LENGTH;
  3379. Status = NtQueryVolumeInformationFile(FileHandlePath,
  3380. &Iosb,
  3381. VolumeInfoPath,
  3382. VolumeInfoLength,
  3383. FileFsVolumeInformation);
  3384. NtClose(FileHandlePath);
  3385. if (!NT_SUCCESS(Status)) {
  3386. WStatus = FrsSetLastNTError(Status);
  3387. CLEANUP1_NT(4, "++ ERROR - NtQueryVolumeInformationFile(%ws);",
  3388. Name, Status, CLEANUP);
  3389. }
  3390. //
  3391. // Get the volume part of the absolute path.
  3392. //
  3393. Temp = FrsWcsVolume(Name);
  3394. if (!Temp || (wcslen(Temp) == 0)) {
  3395. WStatus = ERROR_FILE_NOT_FOUND;
  3396. goto CLEANUP;
  3397. }
  3398. Volume = FrsWcsCat(Temp, L"\\");
  3399. //
  3400. // Get the handle to the prefix drive of the path passed in.
  3401. //
  3402. WStatus = FrsOpenSourceFileW(&FileHandleDrive, Volume,
  3403. // READ_ACCESS,
  3404. READ_ATTRIB_ACCESS,
  3405. OPEN_OPTIONS);
  3406. CLEANUP1_WS(4, "++ ERROR - opening volume %ws ;", Volume, WStatus, CLEANUP);
  3407. //
  3408. // Get the volume information for this handle.
  3409. //
  3410. VolumeInfoDrive = FrsAlloc(sizeof(FILE_FS_VOLUME_INFORMATION) + MAXIMUM_VOLUME_LABEL_LENGTH);
  3411. VolumeInfoLength = sizeof(*VolumeInfoDrive) + MAXIMUM_VOLUME_LABEL_LENGTH;
  3412. Status = NtQueryVolumeInformationFile(FileHandleDrive,
  3413. &Iosb,
  3414. VolumeInfoDrive,
  3415. VolumeInfoLength,
  3416. FileFsVolumeInformation);
  3417. NtClose(FileHandleDrive);
  3418. if (!NT_SUCCESS(Status)) {
  3419. WStatus = FrsSetLastNTError(Status);
  3420. CLEANUP1_NT(4, "++ ERROR - NtQueryVolumeInformationFile(%ws);",
  3421. Volume, Status, CLEANUP);
  3422. }
  3423. //
  3424. // Now compare the VolumeSerialNumber acquired from the above two queries.
  3425. // If it is the same then there are no reparse points in the path that
  3426. // redirect the path to a different volume.
  3427. //
  3428. if (VolumeInfoPath->VolumeSerialNumber != VolumeInfoDrive->VolumeSerialNumber) {
  3429. WStatus = ERROR_GEN_FAILURE;
  3430. DPRINT2(0, "++ Error - VolumeSerialNumber mismatch %x != %x\n",
  3431. VolumeInfoPath->VolumeSerialNumber,
  3432. VolumeInfoDrive->VolumeSerialNumber);
  3433. DPRINT2(0, "++ Error - Root path (%ws) is not on %ws. Invalid replica root path.\n",
  3434. Name,Volume);
  3435. goto CLEANUP;
  3436. }
  3437. CLEANUP:
  3438. //
  3439. // Cleanup
  3440. //
  3441. FrsFree(VolumeInfoPath);
  3442. FrsFree(Volume);
  3443. FrsFree(Temp);
  3444. FrsFree(VolumeInfoDrive);
  3445. return WStatus;
  3446. }
  3447. DWORD
  3448. FrsDoesDirectoryExist(
  3449. IN PWCHAR Name,
  3450. OUT PDWORD pAttributes
  3451. )
  3452. /*++
  3453. Routine Description:
  3454. Does the directory Name exist?
  3455. Arguments:
  3456. Name
  3457. pAttributes - return the attributes on the file/dir if it exits.
  3458. Return Value:
  3459. WIN32 Status
  3460. --*/
  3461. {
  3462. #undef DEBSUB
  3463. #define DEBSUB "FrsDoesDirectoryExist:"
  3464. DWORD WStatus;
  3465. //
  3466. // Can't get attributes
  3467. //
  3468. *pAttributes = GetFileAttributes(Name);
  3469. if (*pAttributes == 0xFFFFFFFF) {
  3470. WStatus = GetLastError();
  3471. DPRINT1_WS(4, "++ GetFileAttributes(%ws); ", Name, WStatus);
  3472. return WStatus;
  3473. }
  3474. //
  3475. // Not a directory
  3476. //
  3477. if (!(*pAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  3478. DPRINT1(4, "++ %ws is not a directory\n", Name);
  3479. return ERROR_DIRECTORY;
  3480. }
  3481. return ERROR_SUCCESS;
  3482. }
  3483. DWORD
  3484. FrsDoesFileExist(
  3485. IN PWCHAR Name
  3486. )
  3487. /*++
  3488. Routine Description:
  3489. Does the file Name exist?
  3490. Arguments:
  3491. Name
  3492. Return Value:
  3493. WIN32 Status
  3494. --*/
  3495. {
  3496. #undef DEBSUB
  3497. #define DEBSUB "FrsDoesFileExist:"
  3498. DWORD WStatus;
  3499. DWORD Attributes;
  3500. //
  3501. // Can't get attributes
  3502. //
  3503. Attributes = GetFileAttributes(Name);
  3504. if (Attributes == 0xFFFFFFFF) {
  3505. WStatus = GetLastError();
  3506. DPRINT1_WS(4, "++ GetFileAttributes(%ws); ", Name, WStatus);
  3507. return WStatus;
  3508. }
  3509. //
  3510. // Not a directory
  3511. //
  3512. if (Attributes & FILE_ATTRIBUTE_DIRECTORY) {
  3513. DPRINT1(4, "++ %ws is not a file\n", Name);
  3514. return ERROR_DIRECTORY;
  3515. }
  3516. return ERROR_SUCCESS;
  3517. }
  3518. DWORD
  3519. FrsSetFilePointer(
  3520. IN PWCHAR Name,
  3521. IN HANDLE Handle,
  3522. IN ULONG High,
  3523. IN ULONG Low
  3524. )
  3525. /*++
  3526. Routine Description:
  3527. Position file pointer
  3528. Arguments:
  3529. Handle
  3530. Name
  3531. High
  3532. Low
  3533. Return Value:
  3534. Win32 Error Status
  3535. --*/
  3536. {
  3537. #undef DEBSUB
  3538. #define DEBSUB "FrsSetFilePointer:"
  3539. DWORD WStatus = ERROR_SUCCESS;
  3540. Low = SetFilePointer(Handle, Low, &High, FILE_BEGIN);
  3541. if (Low == INVALID_SET_FILE_POINTER) {
  3542. WStatus = GetLastError();
  3543. if (WStatus != NO_ERROR) {
  3544. DPRINT1_WS(0, "++ Can't set file pointer for %ws;", Name, WStatus);
  3545. }
  3546. }
  3547. return WStatus;
  3548. }
  3549. DWORD
  3550. FrsSetFileTime(
  3551. IN PWCHAR Name,
  3552. IN HANDLE Handle,
  3553. IN FILETIME *CreateTime,
  3554. IN FILETIME *AccessTime,
  3555. IN FILETIME *WriteTime
  3556. )
  3557. /*++
  3558. Routine Description:
  3559. Position file pointer
  3560. Arguments:
  3561. Name
  3562. Handle
  3563. Attributes
  3564. CreateTime
  3565. AccessTime
  3566. WriteTime
  3567. Return Value:
  3568. WStatus.
  3569. --*/
  3570. {
  3571. #undef DEBSUB
  3572. #define DEBSUB "FrsSetFileTime:"
  3573. DWORD WStatus = ERROR_SUCCESS;
  3574. if (!SetFileTime(Handle, CreateTime, AccessTime, WriteTime)) {
  3575. WStatus = GetLastError();
  3576. DPRINT1_WS(0, "++ Can't set file times for %ws;", Name, WStatus);
  3577. }
  3578. return WStatus;
  3579. }
  3580. DWORD
  3581. FrsSetEndOfFile(
  3582. IN PWCHAR Name,
  3583. IN HANDLE Handle
  3584. )
  3585. /*++
  3586. Routine Description:
  3587. Set end of file at current file position
  3588. Arguments:
  3589. Handle
  3590. Name
  3591. Return Value:
  3592. WStatus.
  3593. --*/
  3594. {
  3595. #undef DEBSUB
  3596. #define DEBSUB "FrsSetEndOfFile:"
  3597. DWORD WStatus = ERROR_SUCCESS;
  3598. if (!SetEndOfFile(Handle)) {
  3599. WStatus = GetLastError();
  3600. DPRINT1_WS(0, "++ ERROR - Setting EOF for %ws;", Name, WStatus);
  3601. }
  3602. return WStatus;
  3603. }
  3604. DWORD
  3605. FrsFlushFile(
  3606. IN PWCHAR Name,
  3607. IN HANDLE Handle
  3608. )
  3609. /*++
  3610. Routine Description:
  3611. Flush the file's data to disk
  3612. Assumes that the debug lock is already held.
  3613. Arguments:
  3614. Handle
  3615. Name
  3616. Return Value:
  3617. WStatus
  3618. --*/
  3619. {
  3620. #undef DEBSUB
  3621. #define DEBSUB "FrsFlushFile:"
  3622. DWORD WStatus = ERROR_SUCCESS;
  3623. if (HANDLE_IS_VALID(Handle)) {
  3624. if (!FlushFileBuffers(Handle)) {
  3625. WStatus = GetLastError();
  3626. DPRINT1_WS_NOLOCK(0, "++ Can't flush file for %ws;", Name, WStatus);
  3627. }
  3628. }
  3629. return WStatus;
  3630. }
  3631. DWORD
  3632. FrsSetCompression(
  3633. IN PWCHAR Name,
  3634. IN HANDLE Handle,
  3635. IN USHORT TypeOfCompression
  3636. )
  3637. /*++
  3638. Routine Description:
  3639. Enable compression on Handle.
  3640. Arguments:
  3641. Name
  3642. Handle
  3643. TypeOfCompression
  3644. Return Value:
  3645. WStatus
  3646. --*/
  3647. {
  3648. #undef DEBSUB
  3649. #define DEBSUB "FrsSetCompression:"
  3650. DWORD BytesReturned;
  3651. DWORD WStatus = ERROR_SUCCESS;
  3652. if (!DeviceIoControl(Handle,
  3653. FSCTL_SET_COMPRESSION,
  3654. &TypeOfCompression, sizeof(TypeOfCompression),
  3655. NULL, 0, &BytesReturned, NULL)) {
  3656. WStatus = GetLastError();
  3657. DPRINT1_WS(0, "++ Can't set compression on %ws;", Name, WStatus);
  3658. }
  3659. return WStatus;
  3660. }
  3661. DWORD
  3662. FrsGetCompression(
  3663. IN PWCHAR Name,
  3664. IN HANDLE Handle,
  3665. IN PUSHORT TypeOfCompression
  3666. )
  3667. /*++
  3668. Routine Description:
  3669. Enable compression on Handle.
  3670. Arguments:
  3671. Handle
  3672. Name
  3673. TypeOfCompression
  3674. Return Value:
  3675. WStatus
  3676. --*/
  3677. {
  3678. #undef DEBSUB
  3679. #define DEBSUB "FrsGetCompression:"
  3680. DWORD BytesReturned;
  3681. DWORD WStatus = ERROR_SUCCESS;
  3682. if (!DeviceIoControl(Handle,
  3683. FSCTL_GET_COMPRESSION,
  3684. NULL, 0,
  3685. TypeOfCompression, sizeof(TypeOfCompression),
  3686. &BytesReturned, NULL)) {
  3687. WStatus = GetLastError();
  3688. DPRINT1_WS(0, "++ Can't get compression for %ws;", Name, WStatus);
  3689. }
  3690. return WStatus;
  3691. }
  3692. DWORD
  3693. FrsRenameByHandle(
  3694. IN PWCHAR Name,
  3695. IN ULONG NameLen,
  3696. IN HANDLE Handle,
  3697. IN HANDLE TargetHandle,
  3698. IN BOOL ReplaceIfExists
  3699. )
  3700. /*++
  3701. Routine Description:
  3702. Rename the file
  3703. Arguments:
  3704. Name - New name
  3705. NameLen - length of Name
  3706. Handle - file handle
  3707. TargetHandle - Target directory
  3708. ReplaceIfExists
  3709. Return Value:
  3710. Win Status
  3711. --*/
  3712. {
  3713. #undef DEBSUB
  3714. #define DEBSUB "FrsRenameByHandle:"
  3715. PFILE_RENAME_INFORMATION RenameInfo;
  3716. IO_STATUS_BLOCK IoStatus;
  3717. ULONG NtStatus;
  3718. //
  3719. // Rename the file; deleting any destination file if requested
  3720. //
  3721. RenameInfo = FrsAlloc(sizeof(FILE_RENAME_INFORMATION) + NameLen);
  3722. RenameInfo->ReplaceIfExists = (ReplaceIfExists != 0);
  3723. RenameInfo->RootDirectory = TargetHandle;
  3724. RenameInfo->FileNameLength = NameLen;
  3725. CopyMemory(RenameInfo->FileName, Name, NameLen);
  3726. NtStatus = NtSetInformationFile(Handle,
  3727. &IoStatus,
  3728. RenameInfo,
  3729. sizeof(FILE_RENAME_INFORMATION)
  3730. + NameLen,
  3731. FileRenameInformation);
  3732. FrsFree(RenameInfo);
  3733. DPRINT1_NT(5, "++ INFO - Renaming %ws failed; ", Name, NtStatus);
  3734. return FrsSetLastNTError(NtStatus);
  3735. }
  3736. DWORD
  3737. FrsCheckObjectId(
  3738. IN PWCHAR Name,
  3739. IN HANDLE Handle,
  3740. IN GUID *Guid
  3741. )
  3742. /*++
  3743. Routine Description:
  3744. Check that the GUID on the file is the same.
  3745. Arguments:
  3746. Name - for error messages
  3747. Handle - Supplies a handle to the file
  3748. Guid - guid to check
  3749. Return Value:
  3750. Win Status
  3751. --*/
  3752. {
  3753. #undef DEBSUB
  3754. #define DEBSUB "FrsCheckObjectId:"
  3755. DWORD WStatus;
  3756. FILE_OBJECTID_BUFFER ObjectIdBuffer;
  3757. //
  3758. // Get the file's object id and check it
  3759. //
  3760. WStatus = FrsGetObjectId(Handle, &ObjectIdBuffer);
  3761. if (!WIN_SUCCESS(WStatus)) {
  3762. DPRINT1_WS(4, "++ No object id for file %ws;", Name, WStatus);
  3763. } else {
  3764. //
  3765. // Same file, no morph needed. (must have been renamed sometime before)
  3766. //
  3767. if (memcmp(ObjectIdBuffer.ObjectId, Guid, sizeof(GUID))) {
  3768. DPRINT1(4, "++ Object ids don't match for file %ws\n", Name);
  3769. WStatus = ERROR_FILE_NOT_FOUND;
  3770. }
  3771. }
  3772. return WStatus;
  3773. }
  3774. PWCHAR
  3775. FrsCreateGuidName(
  3776. IN GUID *Guid,
  3777. IN PWCHAR Prefix
  3778. )
  3779. /*++
  3780. Routine Description:
  3781. Convert the guid into a file name
  3782. Arguments:
  3783. Guid
  3784. Prefix
  3785. Return Value:
  3786. Character string
  3787. --*/
  3788. {
  3789. #undef DEBSUB
  3790. #define DEBSUB "FrsCreateGuidName:"
  3791. WCHAR WGuid[GUID_CHAR_LEN + 1];
  3792. //
  3793. // Translate the guid into a string
  3794. //
  3795. GuidToStrW(Guid, WGuid);
  3796. //
  3797. // Create the file name <prefix>Guid
  3798. //
  3799. return FrsWcsCat(Prefix, WGuid);
  3800. }
  3801. DWORD
  3802. FrsGetObjectId(
  3803. IN HANDLE Handle,
  3804. OUT PFILE_OBJECTID_BUFFER ObjectIdBuffer
  3805. )
  3806. /*++
  3807. Routine Description:
  3808. This routine reads the object ID.
  3809. Arguments:
  3810. Handle -- The file handle of an opened file.
  3811. ObjectIdBuffer -- The output buffer to hold the object ID.
  3812. Return Value:
  3813. Returns the Win Status of the last error found, or success.
  3814. --*/
  3815. {
  3816. #undef DEBSUB
  3817. #define DEBSUB "FrsGetObjectId:"
  3818. NTSTATUS NtStatus;
  3819. IO_STATUS_BLOCK Iosb;
  3820. CHAR GuidStr[GUID_CHAR_LEN];
  3821. //
  3822. // zero the buffer in case the data that comes back is short.
  3823. //
  3824. ZeroMemory(ObjectIdBuffer, sizeof(FILE_OBJECTID_BUFFER));
  3825. //
  3826. // Get the Object ID
  3827. //
  3828. NtStatus = NtFsControlFile(Handle, // file handle
  3829. NULL, // event
  3830. NULL, // apc routine
  3831. NULL, // apc context
  3832. &Iosb, // iosb
  3833. FSCTL_GET_OBJECT_ID, // FsControlCode
  3834. &Handle, // input buffer
  3835. sizeof(HANDLE), // input buffer length
  3836. ObjectIdBuffer, // OutputBuffer for data from the FS
  3837. sizeof(FILE_OBJECTID_BUFFER)); // OutputBuffer Length
  3838. if (NT_SUCCESS(NtStatus)) {
  3839. GuidToStr((GUID *)ObjectIdBuffer->ObjectId, GuidStr);
  3840. DPRINT1(4, "++ Existing oid for this file is %s\n", GuidStr );
  3841. }
  3842. return FrsSetLastNTError(NtStatus);
  3843. }
  3844. DWORD
  3845. FrsGetOrSetFileObjectId(
  3846. IN HANDLE Handle,
  3847. IN LPCWSTR FileName,
  3848. IN BOOL CallerSupplied,
  3849. OUT PFILE_OBJECTID_BUFFER ObjectIdBuffer
  3850. )
  3851. /*++
  3852. Routine Description:
  3853. This routine reads the object ID. If there is no
  3854. object ID on the file we put one on it. If the CallerSupplied flag is
  3855. TRUE then we delete the current object ID on the file (if any) and
  3856. stamp the object ID provided on the file.
  3857. Note: This function does not preserve the 48 byte extended info in the
  3858. object ID. Currently this is not a problem but could be a link tracking
  3859. issue in the future.
  3860. Arguments:
  3861. Handle -- The file handle of an opened file.
  3862. FileName -- The name of the file. For error messages only.
  3863. CallerSupplied -- TRUE if caller supplies new OID to override ANY
  3864. OID currently on the file.
  3865. ObjectIdBuffer -- The output buffer to hold the object ID.
  3866. Return Value:
  3867. Returns the Win Status of the last error found, or success.
  3868. --*/
  3869. {
  3870. #undef DEBSUB
  3871. #define DEBSUB "FrsGetOrSetFileObjectId:"
  3872. DWORD WStatus = ERROR_SUCCESS;
  3873. NTSTATUS NtStatus;
  3874. ULONG ObjectIdBufferSize;
  3875. IO_STATUS_BLOCK Iosb;
  3876. CHAR GuidStr[GUID_CHAR_LEN];
  3877. LONG Loop;
  3878. ObjectIdBufferSize = sizeof(FILE_OBJECTID_BUFFER);
  3879. if (!CallerSupplied) {
  3880. WStatus = FrsGetObjectId(Handle, ObjectIdBuffer);
  3881. if (WIN_SUCCESS(WStatus)) {
  3882. return WStatus;
  3883. }
  3884. //
  3885. // Clear the extra bits past the object id
  3886. //
  3887. ZeroMemory(ObjectIdBuffer, sizeof(FILE_OBJECTID_BUFFER));
  3888. }
  3889. if (WIN_OID_NOT_PRESENT(WStatus) || CallerSupplied) {
  3890. //
  3891. // No object ID on the file. Create one. Just in case, try 15 times
  3892. // to get a unique one. Don't let the kernel create the object ID
  3893. // using FSCTL_CREATE_OR_GET_OBJECT_ID since it currently (April 97)
  3894. // doesn't add the net card address.
  3895. //
  3896. Loop = 0;
  3897. do {
  3898. if (!CallerSupplied) {
  3899. FrsUuidCreate((GUID *)ObjectIdBuffer->ObjectId);
  3900. }
  3901. if (Loop > 0) {
  3902. DPRINT2(1, "++ Failed to assign Object ID %s (dup_name, retrying) to the file: %ws\n",
  3903. GuidStr, FileName);
  3904. }
  3905. GuidToStr((GUID *)ObjectIdBuffer->ObjectId, GuidStr);
  3906. //
  3907. // If this object ID is caller supplied then there might already
  3908. // be one on the file so delete it first.
  3909. //
  3910. NtStatus = NtFsControlFile(
  3911. Handle, // file handle
  3912. NULL, // event
  3913. NULL, // apc routine
  3914. NULL, // apc context
  3915. &Iosb, // iosb
  3916. FSCTL_DELETE_OBJECT_ID, // FsControlCode
  3917. NULL, // input buffer
  3918. 0, // input buffer length
  3919. NULL, // OutputBuffer for data from the FS
  3920. 0); // OutputBuffer Length
  3921. NtStatus = NtFsControlFile(
  3922. Handle, // file handle
  3923. NULL, // event
  3924. NULL, // apc routine
  3925. NULL, // apc context
  3926. &Iosb, // iosb
  3927. FSCTL_SET_OBJECT_ID, // FsControlCode
  3928. ObjectIdBuffer, // input buffer
  3929. ObjectIdBufferSize, // input buffer length
  3930. NULL, // OutputBuffer for data from the FS
  3931. 0); // OutputBuffer Length
  3932. } while ((NtStatus == STATUS_DUPLICATE_NAME) &&
  3933. (++Loop < 16) &&
  3934. (!CallerSupplied));
  3935. if (!NT_SUCCESS(NtStatus)) {
  3936. DPRINT1_NT(1, "++ ERROR - Set oid failed on file %ws;", FileName, NtStatus);
  3937. } else {
  3938. GuidToStr((GUID *)ObjectIdBuffer->ObjectId, GuidStr);
  3939. DPRINT2(4, "++ Assigned Object ID %s (success) to the file: %ws\n",
  3940. GuidStr, FileName);
  3941. }
  3942. return FrsSetLastNTError(NtStatus);
  3943. }
  3944. return WStatus;
  3945. }
  3946. DWORD
  3947. FrsDeleteFileObjectId(
  3948. IN HANDLE Handle,
  3949. IN LPCWSTR FileName
  3950. )
  3951. /*++
  3952. Routine Description:
  3953. Delete object id (if it exists)
  3954. Arguments:
  3955. Handle -- The file handle of an opened file.
  3956. FileName -- The name of the file. For error messages only.
  3957. Return Value:
  3958. Returns the Win Status of the last error found, or success.
  3959. --*/
  3960. {
  3961. #undef DEBSUB
  3962. #define DEBSUB "FrsDeleteFileObjectId:"
  3963. NTSTATUS NtStatus;
  3964. DWORD WStatus;
  3965. IO_STATUS_BLOCK Iosb;
  3966. //
  3967. // Remove the object id from the file
  3968. //
  3969. NtStatus = NtFsControlFile(Handle, // file handle
  3970. NULL, // event
  3971. NULL, // apc routine
  3972. NULL, // apc context
  3973. &Iosb, // iosb
  3974. FSCTL_DELETE_OBJECT_ID, // FsControlCode
  3975. NULL, // input buffer
  3976. 0, // input buffer length
  3977. NULL, // OutputBuffer for data from the FS
  3978. 0); // OutputBuffer Length
  3979. WStatus = FrsSetLastNTError(NtStatus);
  3980. if (WIN_NOT_IMPLEMENTED(WStatus)) {
  3981. DPRINT1_WS(0, "++ Could not delete object id for %ws (not implemented);", FileName, WStatus);
  3982. } else
  3983. if (!WIN_SUCCESS(WStatus)) {
  3984. DPRINT1_WS(0, "++ Could not delete object id for %ws;", FileName, WStatus);
  3985. } else {
  3986. DPRINT1(4, "++ Deleted object id from %ws.\n", FileName);
  3987. }
  3988. return WStatus;
  3989. }
  3990. DWORD
  3991. FrsReadFileUsnData(
  3992. IN HANDLE Handle,
  3993. OUT USN *UsnBuffer
  3994. )
  3995. /*++
  3996. Routine Description:
  3997. This routine reads the USN of the last modify operation to a file.
  3998. Arguments:
  3999. Handle -- The file handle of an opened file.
  4000. UsnBuffer -- The output buffer to hold the object ID.
  4001. Return Value:
  4002. Returns the NTSTATUS of the last error found, or success.
  4003. --*/
  4004. {
  4005. #undef DEBSUB
  4006. #define DEBSUB "FrsReadFileUsnData:"
  4007. ULONG NtStatus;
  4008. IO_STATUS_BLOCK Iosb;
  4009. ULONGLONG Buffer[(sizeof(USN_RECORD) + MAX_PATH*2 + 7)/8];
  4010. //
  4011. // Go get the USN record for the file.
  4012. //
  4013. NtStatus = NtFsControlFile(
  4014. Handle, // file handle
  4015. NULL, // event
  4016. NULL, // apc routine
  4017. NULL, // apc context
  4018. &Iosb, // iosb
  4019. FSCTL_READ_FILE_USN_DATA, // FsControlCode
  4020. &Handle, // input buffer
  4021. sizeof(HANDLE), // input buffer length
  4022. Buffer, // OutputBuffer for USNRecord
  4023. sizeof(Buffer)); // OutputBuffer Length
  4024. if (!NT_SUCCESS(NtStatus)) {
  4025. if (NtStatus == STATUS_INVALID_DEVICE_STATE) {
  4026. DPRINT(0, "++ FSCTL_READ_FILE_USN_DATA failed. No journal on volume\n");
  4027. }
  4028. DPRINT_NT(0, "++ FSCTL_READ_FILE_USN_DATA failed. ", NtStatus);
  4029. return FrsSetLastNTError(NtStatus);
  4030. }
  4031. //
  4032. // Return the last USN on the file.
  4033. //
  4034. *UsnBuffer = ((PUSN_RECORD) (Buffer))->Usn;
  4035. DUMP_USN_RECORD(4, (PUSN_RECORD)(Buffer));
  4036. return ERROR_SUCCESS;
  4037. }
  4038. DWORD
  4039. FrsReadFileParentFid(
  4040. IN HANDLE Handle,
  4041. OUT ULONGLONG *ParentFid
  4042. )
  4043. /*++
  4044. Routine Description:
  4045. This routine reads the parent FID for the file.
  4046. *** WARNING ***
  4047. Note with multiple links to a file there could be multiple parents.
  4048. NTFS gives us one of them.
  4049. Arguments:
  4050. Handle -- The file handle of an opened file.
  4051. ParentFid -- The output buffer to hold the parent file ID.
  4052. Return Value:
  4053. Returns the NTSTATUS of the last error found, or success.
  4054. --*/
  4055. {
  4056. #undef DEBSUB
  4057. #define DEBSUB "FrsReadFileParentFid:"
  4058. ULONG NtStatus;
  4059. IO_STATUS_BLOCK Iosb;
  4060. ULONGLONG Buffer[(sizeof(USN_RECORD) + MAX_PATH*2 + 7)/8];
  4061. //
  4062. // Go get the USN record for the file.
  4063. //
  4064. NtStatus = NtFsControlFile(
  4065. Handle, // file handle
  4066. NULL, // event
  4067. NULL, // apc routine
  4068. NULL, // apc context
  4069. &Iosb, // iosb
  4070. FSCTL_READ_FILE_USN_DATA, // FsControlCode
  4071. &Handle, // input buffer
  4072. sizeof(HANDLE), // input buffer length
  4073. Buffer, // OutputBuffer for USNRecord
  4074. sizeof(Buffer)); // OutputBuffer Length
  4075. if (!NT_SUCCESS(NtStatus)) {
  4076. if (NtStatus == STATUS_INVALID_DEVICE_STATE) {
  4077. DPRINT(0, "++ FSCTL_READ_FILE_USN_DATA failed. No journal on volume\n");
  4078. }
  4079. DPRINT_NT(0, "++ FSCTL_READ_FILE_USN_DATA failed.", NtStatus);
  4080. *ParentFid = ZERO_FID;
  4081. return FrsSetLastNTError(NtStatus);
  4082. }
  4083. //
  4084. // Return a parent FID for the file. (could be more than one with links)
  4085. //
  4086. *ParentFid = ((PUSN_RECORD) (Buffer))->ParentFileReferenceNumber;
  4087. DUMP_USN_RECORD(4, (PUSN_RECORD)(Buffer));
  4088. return ERROR_SUCCESS;
  4089. }
  4090. DWORD
  4091. FrsGetReparseTag(
  4092. IN HANDLE Handle,
  4093. OUT ULONG *ReparseTag
  4094. )
  4095. /*++
  4096. Routine Description:
  4097. Return the value of the reparse tag.
  4098. Arguments:
  4099. Handle - Handle for a reparse point
  4100. ReparseTag - returned reparse tag if ERROR_SUCCESS
  4101. Return Value:
  4102. Win32 Status
  4103. --*/
  4104. {
  4105. #undef DEBSUB
  4106. #define DEBSUB "FrsGetReparseTag:"
  4107. NTSTATUS NtStatus;
  4108. DWORD ReparseDataLength;
  4109. PCHAR ReparseBuffer;
  4110. IO_STATUS_BLOCK IoStatusBlock;
  4111. PREPARSE_DATA_BUFFER ReparseBufferHeader;
  4112. //
  4113. // Allocate a buffer and get the information.
  4114. //
  4115. ReparseDataLength = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
  4116. ReparseBuffer = FrsAlloc(ReparseDataLength);
  4117. //
  4118. // Query the reparse point.
  4119. //
  4120. NtStatus = NtFsControlFile(Handle,
  4121. NULL,
  4122. NULL,
  4123. NULL,
  4124. &IoStatusBlock,
  4125. FSCTL_GET_REPARSE_POINT,
  4126. NULL,
  4127. 0,
  4128. (PVOID)ReparseBuffer,
  4129. ReparseDataLength
  4130. );
  4131. if (!NT_SUCCESS(NtStatus)) {
  4132. DPRINT_NT(4, "++ Could not get reparse point;", NtStatus);
  4133. FrsFree(ReparseBuffer);
  4134. return FrsSetLastNTError(NtStatus);
  4135. }
  4136. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)ReparseBuffer;
  4137. *ReparseTag = ReparseBufferHeader->ReparseTag;
  4138. FrsFree(ReparseBuffer);
  4139. return ERROR_SUCCESS;
  4140. }
  4141. DWORD
  4142. FrsGetReparseData(
  4143. IN HANDLE Handle,
  4144. OUT PREPARSE_GUID_DATA_BUFFER *ReparseData,
  4145. OUT ULONG *ReparseTag
  4146. )
  4147. /*++
  4148. Routine Description:
  4149. Return the value of the reparse tag.
  4150. Arguments:
  4151. Handle - Handle for a reparse point
  4152. ReparseData - returned reparse data buffer if ERROR_SUCCESS
  4153. NOTE: ReparseData can be NULL on success.
  4154. Return Value:
  4155. Win32 Status
  4156. --*/
  4157. {
  4158. #undef DEBSUB
  4159. #define DEBSUB "FrsGetReparseData:"
  4160. NTSTATUS NtStatus;
  4161. DWORD ReparseDataLength;
  4162. IO_STATUS_BLOCK IoStatusBlock;
  4163. //
  4164. // Allocate a buffer and get the information.
  4165. //
  4166. ReparseDataLength = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
  4167. *ReparseData = FrsAlloc(ReparseDataLength);
  4168. //
  4169. // Query the reparse point.
  4170. //
  4171. NtStatus = NtFsControlFile(Handle,
  4172. NULL,
  4173. NULL,
  4174. NULL,
  4175. &IoStatusBlock,
  4176. FSCTL_GET_REPARSE_POINT,
  4177. NULL,
  4178. 0,
  4179. (PVOID)*ReparseData,
  4180. ReparseDataLength
  4181. );
  4182. if (!NT_SUCCESS(NtStatus)) {
  4183. DPRINT_NT(4, "++ Could not get reparse point;", NtStatus);
  4184. FrsFree(*ReparseData);
  4185. return FrsSetLastNTError(NtStatus);
  4186. }
  4187. *ReparseTag = (*ReparseData)->ReparseTag;
  4188. //
  4189. // We only accept operations on files with certain reparse points.
  4190. // For example a rename of a SIS file into a replica tree needs to prop
  4191. // a create CO.
  4192. //
  4193. if (!ReparseTagReplicate(*ReparseTag)) {
  4194. DPRINT1(4, "++ Reparse tag %08x is unsupported.\n", *ReparseTag);
  4195. FrsFree(*ReparseData);
  4196. *ReparseData = NULL;
  4197. return ERROR_GEN_FAILURE;
  4198. }
  4199. //
  4200. // If we are replicating the file data we will
  4201. // not replicate the reparse poiont.
  4202. //
  4203. if(ReparseTagReplicateFileData(*ReparseTag)) {
  4204. DPRINT1(4, "++ Reparse tag %08x. Will not replicate reparse point.\n", *ReparseTag);
  4205. FrsFree(*ReparseData);
  4206. *ReparseData = NULL;
  4207. }
  4208. return ERROR_SUCCESS;
  4209. }
  4210. DWORD
  4211. FrsCheckReparse(
  4212. IN PWCHAR Name,
  4213. IN PVOID Id,
  4214. IN DWORD IdLen,
  4215. IN HANDLE VolumeHandle
  4216. )
  4217. /*++
  4218. Routine Description:
  4219. Check that the reparse point is allowed
  4220. Arguments:
  4221. Name - File name for error messages
  4222. Id - Fid or Oid
  4223. VolumeHandle - open handle to the volume root.
  4224. Thread Return Value:
  4225. Win32 Status
  4226. --*/
  4227. {
  4228. #undef DEBSUB
  4229. #define DEBSUB "FrsCheckReparse:"
  4230. DWORD WStatus;
  4231. HANDLE Handle;
  4232. ULONG ReparseTag;
  4233. //
  4234. // For proper cleanup in the event of failure
  4235. //
  4236. Handle = INVALID_HANDLE_VALUE;
  4237. //
  4238. // Open the file for read access
  4239. WStatus = FrsOpenSourceFileById(&Handle,
  4240. NULL,
  4241. NULL,
  4242. VolumeHandle,
  4243. Id,
  4244. IdLen,
  4245. // READ_ACCESS,
  4246. READ_ATTRIB_ACCESS,
  4247. ID_OPTIONS,
  4248. SHARE_ALL,
  4249. FILE_OPEN);
  4250. //
  4251. // File has been deleted; done
  4252. //
  4253. if (!WIN_SUCCESS(WStatus)) {
  4254. DPRINT2_WS(4, "++ %ws (Id %08x %08x) could not open for reparse;",
  4255. Name, PRINTQUAD(*((PULONGLONG)Id)), WStatus);
  4256. return WStatus;
  4257. }
  4258. //
  4259. // What type of reparse is it?
  4260. //
  4261. WStatus = FrsGetReparseTag(Handle, &ReparseTag);
  4262. FRS_CLOSE(Handle);
  4263. if (!WIN_SUCCESS(WStatus)) {
  4264. DPRINT2_WS(4, "++ %ws (Id %08x %08x) could not get reparse tag;",
  4265. Name, PRINTQUAD(*((PULONGLONG)Id)), WStatus);
  4266. return WStatus;
  4267. }
  4268. //
  4269. // We only accept operations on files with certain reparse points.
  4270. // For example a rename of a SIS file into a replica tree needs to prop
  4271. // a create CO.
  4272. //
  4273. if (!ReparseTagReplicate(ReparseTag)) {
  4274. DPRINT3(4, "++ %ws (Id %08x %08x) is reparse tag %08x is unsupported.\n",
  4275. Name, PRINTQUAD(*((PULONGLONG)Id)), ReparseTag);
  4276. return ERROR_OPERATION_ABORTED;
  4277. }
  4278. return ERROR_SUCCESS;
  4279. }
  4280. DWORD
  4281. FrsDeleteReparsePoint(
  4282. IN HANDLE Handle
  4283. )
  4284. /*++
  4285. Routine Description:
  4286. Delete the reparse point on the opened file.
  4287. Arguments:
  4288. Handle - Handle for a reparse point
  4289. Return Value:
  4290. Win32 Status
  4291. --*/
  4292. {
  4293. #undef DEBSUB
  4294. #define DEBSUB "FrsDeleteReparsePoint:"
  4295. ULONG WStatus = ERROR_SUCCESS;
  4296. DWORD ReparseDataLength;
  4297. ULONG ReparseTag;
  4298. PCHAR ReparseData;
  4299. PREPARSE_DATA_BUFFER ReparseBufferHeader;
  4300. ULONG ActualSize;
  4301. //
  4302. // Allocate a buffer and get the information.
  4303. //
  4304. ReparseDataLength = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
  4305. ReparseData = FrsAlloc(ReparseDataLength);
  4306. //
  4307. // Need the reparse tag in order to do the delete.
  4308. //
  4309. if (!DeviceIoControl(Handle,
  4310. FSCTL_GET_REPARSE_POINT,
  4311. (LPVOID) NULL,
  4312. (DWORD) 0,
  4313. (LPVOID) ReparseData,
  4314. ReparseDataLength,
  4315. &ActualSize,
  4316. (LPOVERLAPPED) NULL )) {
  4317. WStatus = GetLastError();
  4318. CLEANUP_WS(0, "++ FrsDeleteReparsePoint - FSCTL_GET_REPARSE_POINT failed,",
  4319. WStatus, RETURN);
  4320. }
  4321. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)ReparseData;
  4322. ReparseTag = ReparseBufferHeader->ReparseTag;
  4323. DPRINT1(3, "++ FrsDeleteReparsePoint - Tag: 08x\n", ReparseTag);
  4324. //
  4325. // Delete the reparse point.
  4326. //
  4327. ZeroMemory(ReparseBufferHeader, sizeof(REPARSE_DATA_BUFFER_HEADER_SIZE));
  4328. ReparseBufferHeader->ReparseTag = ReparseTag;
  4329. ReparseBufferHeader->ReparseDataLength = 0;
  4330. if (!DeviceIoControl(Handle,
  4331. FSCTL_DELETE_REPARSE_POINT,
  4332. (LPVOID) ReparseData,
  4333. REPARSE_DATA_BUFFER_HEADER_SIZE,
  4334. (LPVOID) NULL,
  4335. (DWORD) 0,
  4336. &ActualSize,
  4337. (LPOVERLAPPED) NULL )) {
  4338. WStatus = GetLastError();
  4339. CLEANUP_WS(0, "++ FrsDeleteReparsePoint - FSCTL_DELETE_REPARSE_POINT failed,",
  4340. WStatus, RETURN);
  4341. }
  4342. RETURN:
  4343. FrsFree(ReparseData);
  4344. return WStatus;
  4345. }
  4346. DWORD
  4347. FrsChaseSymbolicLink(
  4348. IN PWCHAR SymLink,
  4349. OUT PWCHAR *OutPrintName,
  4350. OUT PWCHAR *OutSubstituteName
  4351. )
  4352. /*++
  4353. Routine Description:
  4354. This function opens the specified file with backup intent for
  4355. reading all the files attributes, ...
  4356. Arguments:
  4357. Handle - A pointer to a handle to return an open handle.
  4358. lpFileName - Represents the name of the file or directory to be opened.
  4359. DesiredAccess
  4360. CreateOptions
  4361. Return Value:
  4362. Winstatus.
  4363. --*/
  4364. {
  4365. #undef DEBSUB
  4366. #define DEBSUB "FrsChaseSymbolicLink:"
  4367. NTSTATUS NtStatus;
  4368. DWORD WStatus;
  4369. HANDLE Handle = INVALID_HANDLE_VALUE;
  4370. DWORD ReparseDataLength;
  4371. PCHAR ReparseBuffer;
  4372. DWORD SubLen;
  4373. DWORD PrintLen;
  4374. PWCHAR SubName;
  4375. PWCHAR PrintName;
  4376. IO_STATUS_BLOCK IoStatusBlock;
  4377. PREPARSE_DATA_BUFFER ReparseBufferHeader;
  4378. OBJECT_ATTRIBUTES Obja;
  4379. UNICODE_STRING FileName;
  4380. ULONG FileAttributes;
  4381. ULONG CreateDisposition;
  4382. ULONG ShareMode;
  4383. ULONG Colon;
  4384. if ((OutPrintName == NULL) || (OutSubstituteName == NULL)) {
  4385. return ERROR_INVALID_PARAMETER;
  4386. }
  4387. //
  4388. // Assume no symlink
  4389. //
  4390. *OutPrintName = FrsWcsDup(SymLink);
  4391. *OutSubstituteName = FrsWcsDup(SymLink);
  4392. //
  4393. // Allocate a buffer and get the information.
  4394. //
  4395. ReparseDataLength = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
  4396. ReparseBuffer = FrsAlloc(ReparseDataLength);
  4397. NEXT_LINK:
  4398. //
  4399. // Open the target symlink. If this is a dos type path name then
  4400. // convert it to NtPathName or else use it as it is.
  4401. //
  4402. Colon = wcscspn(*OutSubstituteName, L":");
  4403. if (Colon == 1 ||
  4404. (wcsncmp(*OutSubstituteName, L"\\\\?\\", wcslen(L"\\\\?\\")) == 0 )) {
  4405. WStatus = FrsOpenSourceFileW(&Handle,
  4406. *OutSubstituteName,
  4407. GENERIC_READ,
  4408. FILE_OPEN_FOR_BACKUP_INTENT |
  4409. FILE_OPEN_REPARSE_POINT);
  4410. CLEANUP1_WS(4, "++ Could not open %ws; ", *OutSubstituteName, WStatus, CLEANUP);
  4411. } else {
  4412. //
  4413. // The path already in Nt style. Use it as it is.
  4414. //
  4415. FileName.Buffer = *OutSubstituteName;
  4416. FileName.Length = (USHORT)(wcslen(*OutSubstituteName) * sizeof(WCHAR));
  4417. FileName.MaximumLength = (USHORT)(wcslen(*OutSubstituteName) * sizeof(WCHAR));
  4418. InitializeObjectAttributes(&Obja,
  4419. &FileName,
  4420. OBJ_CASE_INSENSITIVE,
  4421. NULL,
  4422. NULL);
  4423. CreateDisposition = FILE_OPEN; // Open existing file
  4424. ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  4425. FileAttributes = FILE_ATTRIBUTE_NORMAL;
  4426. NtStatus = NtCreateFile(&Handle,
  4427. GENERIC_READ,
  4428. &Obja,
  4429. &IoStatusBlock,
  4430. NULL, // Initial allocation size
  4431. FileAttributes,
  4432. ShareMode,
  4433. CreateDisposition,
  4434. FILE_OPEN_FOR_BACKUP_INTENT |
  4435. FILE_OPEN_REPARSE_POINT,
  4436. NULL, 0);
  4437. WStatus = FrsSetLastNTError(NtStatus);
  4438. CLEANUP1_WS(4, "++ Could not open %ws;", *OutSubstituteName, WStatus, CLEANUP);
  4439. }
  4440. //
  4441. // Query the reparse point.
  4442. //
  4443. // Now go and get the data.
  4444. //
  4445. NtStatus = NtFsControlFile(Handle,
  4446. NULL,
  4447. NULL,
  4448. NULL,
  4449. &IoStatusBlock,
  4450. FSCTL_GET_REPARSE_POINT,
  4451. NULL,
  4452. 0,
  4453. (PVOID)ReparseBuffer,
  4454. ReparseDataLength
  4455. );
  4456. FRS_CLOSE(Handle);
  4457. if (NtStatus == STATUS_NOT_A_REPARSE_POINT) {
  4458. FrsFree(ReparseBuffer);
  4459. return ERROR_SUCCESS;
  4460. }
  4461. WStatus = FrsSetLastNTError(NtStatus);
  4462. CLEANUP1_WS(4, "++ Could not fsctl %ws;", *OutSubstituteName, WStatus, CLEANUP);
  4463. //
  4464. // Display the buffer.
  4465. //
  4466. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)ReparseBuffer;
  4467. if ((ReparseBufferHeader->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) ||
  4468. (ReparseBufferHeader->ReparseTag == IO_REPARSE_TAG_SYMBOLIC_LINK)) {
  4469. SubName = &ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer[0];
  4470. SubLen = ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength;
  4471. PrintName = &ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer[(SubLen + sizeof(UNICODE_NULL))/sizeof(WCHAR)];
  4472. PrintLen = ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength;
  4473. SubName[SubLen / sizeof(WCHAR)] = L'\0';
  4474. PrintName[PrintLen / sizeof(WCHAR)] = L'\0';
  4475. DPRINT2(4, "++ %ws -> (print) %ws\n", *OutPrintName, PrintName);
  4476. DPRINT2(4, "++ %ws -> (substitute) %ws\n", *OutSubstituteName, SubName);
  4477. FrsFree(*OutPrintName);
  4478. FrsFree(*OutSubstituteName);
  4479. //
  4480. // We need to return both print name and substitute name.
  4481. //
  4482. *OutPrintName = FrsWcsDup(PrintName);
  4483. *OutSubstituteName = FrsWcsDup(SubName);
  4484. goto NEXT_LINK;
  4485. }
  4486. return ERROR_SUCCESS;
  4487. CLEANUP:
  4488. FRS_CLOSE(Handle);
  4489. FrsFree(ReparseBuffer);
  4490. *OutPrintName = FrsFree(*OutPrintName);
  4491. *OutSubstituteName = FrsFree(*OutSubstituteName);
  4492. return WStatus;
  4493. }
  4494. DWORD
  4495. FrsTraverseReparsePoints(
  4496. IN PWCHAR SuppliedPath,
  4497. OUT PWCHAR *RealPath
  4498. )
  4499. /*++
  4500. Routine Description:
  4501. This function steps through each element of the path
  4502. and maps all reparse points to actual paths. In the end the
  4503. path returned has no reparse points of the form
  4504. IO_REPARSE_TAG_MOUNT_POINT and IO_REPARSE_TAG_SYMBOLIC_LINK.
  4505. Arguments:
  4506. Supplied - Input path. May or may not have any reparse points.
  4507. RealPath - Path without any reparse points or NULL if there is an error
  4508. reading reparse data.
  4509. Return Value:
  4510. Winstatus.
  4511. --*/
  4512. {
  4513. #undef DEBSUB
  4514. #define DEBSUB "FrsTraverseReparsePoints:"
  4515. PWCHAR TempStr = NULL;
  4516. PWCHAR IndexPtr = NULL;
  4517. PWCHAR BackSlashPtr = NULL;
  4518. PWCHAR TempPath = NULL;
  4519. PWCHAR PrintablePath = NULL;
  4520. DWORD Colon = 0;
  4521. DWORD CloseBrace = 0;
  4522. DWORD LoopBreaker = 0;
  4523. DWORD WStatus = ERROR_SUCCESS;
  4524. ULONG FileAttributes = 0;
  4525. BOOL ReparsePointFound = FALSE;
  4526. if (!SuppliedPath) {
  4527. WStatus = ERROR_INVALID_PARAMETER;
  4528. goto CLEANUP;
  4529. }
  4530. TempStr = FrsAlloc((wcslen(SuppliedPath) + 1) * sizeof(WCHAR));
  4531. wcscpy(TempStr,SuppliedPath);
  4532. //
  4533. // Repeat the procedure until you have a clean path without any
  4534. // reparse points.
  4535. // e.g.
  4536. // f:\c -> d:\destination
  4537. // e:\a\b -> f:\c\d (which is actually d:\destination\d)
  4538. // Given path is e:\a\b\c
  4539. // FIrst time through the loop we will have f:\c\d\c
  4540. // Second time we will translate the reparse point at f:\c
  4541. // and get the correct answer d:\destination\d\c
  4542. //
  4543. do {
  4544. *RealPath = NULL;
  4545. ReparsePointFound = FALSE;
  4546. //
  4547. // Find the colon. Every path has to either have a colon followed by a '\'
  4548. // or it should be of the form. "\??\Volume{60430005-ab47-11d3-8973-806d6172696f}\"
  4549. //
  4550. Colon = wcscspn(TempStr, L":");
  4551. if (Colon == wcslen(TempStr)) {
  4552. //
  4553. // Path does not have a colon. It can be of the form
  4554. // "\??\Volume{60430005-ab47-11d3-8973-806d6172696f}\"
  4555. //
  4556. CloseBrace = wcscspn(TempStr, L"}");
  4557. if (TempStr[CloseBrace] != L'}' ||
  4558. TempStr[CloseBrace + 1] != L'\\') {
  4559. WStatus = ERROR_INVALID_PARAMETER;
  4560. goto CLEANUP;
  4561. }
  4562. //
  4563. // Copy the path up to 1 past the closing brace as it is. It could be \??\Volume...
  4564. // or \\.\Volume... or \\?\Volume.. or some other complex form.
  4565. // Start looking for reparse points past the closing brace.
  4566. //
  4567. *RealPath = FrsAlloc((CloseBrace + 3)* sizeof(WCHAR));
  4568. wcsncpy(*RealPath,TempStr,CloseBrace + 2);
  4569. (*RealPath)[CloseBrace + 2] = L'\0';
  4570. IndexPtr = &TempStr[CloseBrace + 1];
  4571. } else {
  4572. if (TempStr[Colon] != L':' ||
  4573. TempStr[Colon + 1] != L'\\') {
  4574. WStatus = ERROR_INVALID_PARAMETER;
  4575. goto CLEANUP;
  4576. }
  4577. //
  4578. // Copy the path up to 1 past the colon as it is. It could be d:\
  4579. // or \\.\d:\ or \??\d:\ or some other complex form.
  4580. // Start looking for reparse points past the colon.
  4581. //
  4582. *RealPath = FrsAlloc((Colon + 3)* sizeof(WCHAR));
  4583. wcsncpy(*RealPath,TempStr,Colon + 2);
  4584. (*RealPath)[Colon + 2] = L'\0';
  4585. IndexPtr = &TempStr[Colon + 1];
  4586. }
  4587. BackSlashPtr = wcstok(IndexPtr,L"\\");
  4588. if (BackSlashPtr == NULL) {
  4589. WStatus = ERROR_INVALID_PARAMETER;
  4590. goto CLEANUP;
  4591. }
  4592. do {
  4593. if ((*RealPath)[wcslen(*RealPath) - 1] == L'\\') {
  4594. TempPath = FrsAlloc((wcslen(*RealPath) + wcslen(BackSlashPtr) + 1)* sizeof(WCHAR));
  4595. wcscpy(TempPath,*RealPath);
  4596. } else {
  4597. TempPath = FrsAlloc((wcslen(*RealPath) + wcslen(BackSlashPtr) + wcslen(L"\\") + 1)* sizeof(WCHAR));
  4598. wcscpy(TempPath,*RealPath);
  4599. wcscat(TempPath,L"\\");
  4600. }
  4601. wcscat(TempPath,BackSlashPtr);
  4602. FrsFree(*RealPath);
  4603. *RealPath = TempPath;
  4604. TempPath = NULL;
  4605. //
  4606. //
  4607. //
  4608. //
  4609. // FrsChaseSymbolicLink returns both then PrintName and the SubstituteName.
  4610. // We use the SubstituteName as it is always guaranteed to be there.
  4611. // PrintName is ignored.
  4612. //
  4613. WStatus = FrsChaseSymbolicLink(*RealPath, &PrintablePath, &TempPath);
  4614. PrintablePath = FrsFree(PrintablePath);
  4615. if (!WIN_SUCCESS(WStatus)) {
  4616. DPRINT1(0,"ERROR reading reparse point data WStatus = %d\n",WStatus);
  4617. FrsFree(TempPath);
  4618. goto CLEANUP;
  4619. //
  4620. // We are only looking for reparse points that are
  4621. // either IO_REPARSE_TAG_MOUNT_POINT or IO_REPARSE_TAG_SYMBOLIC_LINK.
  4622. // Check if the path returned by FrsChaseSymbolicLink is same as the
  4623. // path passed to it. If it is then we haven't hit a reparse point.
  4624. //
  4625. } else if (wcscmp(*RealPath,TempPath)) {
  4626. ReparsePointFound = TRUE;
  4627. FrsFree(*RealPath);
  4628. *RealPath = TempPath;
  4629. TempPath = NULL;
  4630. } else {
  4631. TempPath = FrsFree(TempPath);
  4632. }
  4633. } while ( (BackSlashPtr = wcstok(NULL,L"\\")) != NULL);
  4634. if (SuppliedPath[wcslen(SuppliedPath) - 1] == L'\\') {
  4635. TempPath = FrsAlloc((wcslen(*RealPath) + wcslen(L"\\") + 1)* sizeof(WCHAR));
  4636. wcscpy(TempPath,*RealPath);
  4637. wcscat(TempPath,L"\\");
  4638. FrsFree(*RealPath);
  4639. *RealPath = TempPath;
  4640. TempPath = NULL;
  4641. }
  4642. FrsFree(TempStr);
  4643. TempStr = *RealPath;
  4644. //
  4645. // Break out of the loop if there is a junction point loop.
  4646. // If we have traversed the path 100 times and still can't
  4647. // get to the destination then we probably have a loop
  4648. // in the path.
  4649. //
  4650. ++LoopBreaker;
  4651. } while ( ReparsePointFound && LoopBreaker < 100);
  4652. //
  4653. // Path has loops in it. Return error.
  4654. //
  4655. if (LoopBreaker >= 100) {
  4656. WStatus = ERROR_INVALID_PARAMETER;
  4657. goto CLEANUP;
  4658. }
  4659. CLEANUP:
  4660. DPRINT2(5,"Supplied Path = %ws, Traversed Path = %ws\n",SuppliedPath,(*RealPath)?*RealPath:L"<null>");
  4661. //
  4662. // If we are returning error then return NULL as the real path.
  4663. //
  4664. if (!WIN_SUCCESS(WStatus)) {
  4665. FrsFree(TempStr);
  4666. *RealPath = FrsFree(*RealPath);
  4667. }
  4668. return WStatus;
  4669. }
  4670. BOOL
  4671. FrsSearchArgv(
  4672. IN LONG ArgC,
  4673. IN PWCHAR *ArgV,
  4674. IN PWCHAR ArgKey,
  4675. OUT PWCHAR *ArgValue
  4676. )
  4677. /*++
  4678. Routine Description:
  4679. This routine searches an ArgV vector for the keyword in ArgKey.
  4680. If found it looks for an equals sign and returns a copy of the right
  4681. hand side in ArgValue. The caller must free the returned string.
  4682. Arguments:
  4683. ArgC - The number of entries in the ArgV vector.
  4684. ArgV - The vector of PWCHARS to search.
  4685. ArgKey - The key to search for. MUST BE LOWERCASE TO MATCH.
  4686. ArgValue - return location for the buffer ptr. Caller must free.
  4687. if NULL no right hand side is returned.
  4688. Return Value:
  4689. TRUE if ArgKey is found.
  4690. --*/
  4691. {
  4692. #undef DEBSUB
  4693. #define DEBSUB "FrsSearchArgv:"
  4694. LONG i, n, Len;
  4695. PWCHAR TestStr;
  4696. PWCHAR Wcs;
  4697. if (ArgValue != NULL) {
  4698. *ArgValue = NULL;
  4699. }
  4700. //
  4701. // Are we running as a service? We need to know prior
  4702. // to calling the first DPRINT.
  4703. //
  4704. for (n = 0; n < ArgC; ++n) {
  4705. TestStr = ArgV[n];
  4706. Len = wcslen(TestStr);
  4707. if (Len <= 0) {
  4708. continue;
  4709. }
  4710. //
  4711. // Skip -,/
  4712. //
  4713. if (TestStr[0] == L'-' || TestStr[0] == L'/') {
  4714. TestStr++;
  4715. Len--;
  4716. }
  4717. //
  4718. // Skip over leading spaces and tabs.
  4719. //
  4720. while ((TestStr[0] == UNICODE_SPACE) || (TestStr[0] == UNICODE_TAB) ) {
  4721. TestStr++;
  4722. Len--;
  4723. }
  4724. if (Len <= 0) {
  4725. continue;
  4726. }
  4727. _wcslwr(TestStr);
  4728. if (wcsstr(TestStr, ArgKey) != TestStr) {
  4729. continue;
  4730. }
  4731. //
  4732. // Found a match. Look for a value.
  4733. //
  4734. if (ArgValue != NULL) {
  4735. DPRINT2(5, "match on ArgV[%d] = %ws\n", n, TestStr);
  4736. Wcs = wcschr(TestStr, L'=');
  4737. if (Wcs) {
  4738. //
  4739. // Trim trailing leading spaces and tabs.
  4740. //
  4741. while ((TestStr[Len-1] == UNICODE_SPACE) ||
  4742. (TestStr[Len-1] == UNICODE_TAB )) {
  4743. Len--;
  4744. }
  4745. FRS_ASSERT(&TestStr[Len-1] >= Wcs);
  4746. TestStr[Len] = UNICODE_NULL;
  4747. *ArgValue = FrsWcsDup(Wcs+1);
  4748. DPRINT1(5, "++ return value = %ws\n", *ArgValue);
  4749. }
  4750. }
  4751. return TRUE;
  4752. }
  4753. DPRINT1(5, "++ No match for ArgKey = %ws\n", ArgKey);
  4754. return FALSE;
  4755. }
  4756. BOOL
  4757. FrsSearchArgvDWord(
  4758. IN LONG ArgC,
  4759. IN PWCHAR *ArgV,
  4760. IN PWCHAR ArgKey,
  4761. OUT PDWORD ArgValue
  4762. )
  4763. /*++
  4764. Routine Description:
  4765. This routine searches an ArgV vector for the keyword in ArgKey.
  4766. If found it looks for an equals sign and returns the right
  4767. hand side in ArgValue as a base 10 number.
  4768. Arguments:
  4769. ArgC - The number of entries in the ArgV vector.
  4770. ArgV - The vector of PWCHARS to search.
  4771. ArgKey - The key to search for. MUST BE LOWERCASE TO MATCH.
  4772. ArgValue - return location for the DWORD right hand side.
  4773. if ArgKey not found no right hand side is returned.
  4774. Return Value:
  4775. TRUE if ArgKey is found.
  4776. --*/
  4777. {
  4778. #undef DEBSUB
  4779. #define DEBSUB "FrsSearchArgvDWord:"
  4780. ULONG Len;
  4781. PWCHAR WStr;
  4782. if (FrsSearchArgv(ArgC, ArgV, ArgKey, &WStr)) {
  4783. //
  4784. // Found ArgKey
  4785. //
  4786. if (WStr != NULL) {
  4787. //
  4788. // Found rhs.
  4789. //
  4790. Len = wcslen(WStr);
  4791. if ((Len > 0) && (wcsspn(WStr, L"0123456789") == Len)){
  4792. *ArgValue = wcstoul(WStr, NULL, 10);
  4793. FrsFree(WStr);
  4794. return TRUE;
  4795. } else {
  4796. DPRINT2(0, "++ ERROR - Invalid decimal string '%ws' for %ws\n",
  4797. WStr, ArgKey);
  4798. FrsFree(WStr);
  4799. }
  4800. }
  4801. }
  4802. return FALSE;
  4803. }
  4804. BOOL
  4805. FrsDissectCommaList (
  4806. IN UNICODE_STRING RawArg,
  4807. OUT PUNICODE_STRING FirstArg,
  4808. OUT PUNICODE_STRING RemainingArg
  4809. )
  4810. /*++
  4811. Routine Description:
  4812. This routine parses a comma (or semicolon) separated string.
  4813. It picks off the first element in the given RawArg and provides both it and
  4814. the remaining part. Leading blanks and tabs are ignored. FirstArg is
  4815. returned zero length when there is either a leading comma or embedded
  4816. double comma. However the buffer address in FirstArg still points to where
  4817. the arg started so the caller can tell how much of the string has been
  4818. processed. The function returns FALSE when the input string is empty. It
  4819. returns TRUE when the FirstArg is valid, even if it is null.
  4820. Here are some examples:
  4821. RawArg FirstArg RemainingArg Result
  4822. ---- --------- ------------- ------
  4823. empty empty empty FALSE
  4824. , empty empty TRUE
  4825. ,, empty , TRUE
  4826. A A empty TRUE
  4827. A, A empty TRUE
  4828. ,A empty A TRUE
  4829. "A ,B,C,D" A " B,C,D" TRUE
  4830. *A? *A? empty TRUE
  4831. Note that both output strings use the same string buffer memory of the
  4832. input string, and are not necessarily null terminated.
  4833. Based on FsRtlDissectName.
  4834. Arguments:
  4835. RawArg - The full string to parse.
  4836. FirstArg - The first name in the RawArg.
  4837. Don't allocate a buffer for this string.
  4838. RemainingArg - The rest of the RawArg after the first comma (if any).
  4839. Don't allocate a buffer for this string.
  4840. Return Value:
  4841. FALSE if the RawArg is empty else TRUE (meaning FirstArg is valid).
  4842. --*/
  4843. {
  4844. #undef DEBSUB
  4845. #define DEBSUB "FrsDissectCommaList:"
  4846. ULONG i = 0;
  4847. ULONG RawArgLength;
  4848. ULONG FirstArgStart;
  4849. //
  4850. // Make both output strings empty for now
  4851. //
  4852. FirstArg->Length = 0;
  4853. FirstArg->MaximumLength = 0;
  4854. FirstArg->Buffer = NULL;
  4855. RemainingArg->Length = 0;
  4856. RemainingArg->MaximumLength = 0;
  4857. RemainingArg->Buffer = NULL;
  4858. RawArgLength = RawArg.Length / sizeof(WCHAR);
  4859. //DPRINT2(5, "RawArg string: %ws {%d)\n",
  4860. // (RawArg.Buffer != NULL) ? RawArg.Buffer : L"<NULL>", RawArg.Length);
  4861. //
  4862. // Skip over leading spaces and tabs.
  4863. //
  4864. while (i < RawArgLength) {
  4865. if (( RawArg.Buffer[i] != UNICODE_SPACE ) &&
  4866. ( RawArg.Buffer[i] != UNICODE_TAB )){
  4867. break;
  4868. }
  4869. i += 1;
  4870. }
  4871. //
  4872. // Check for an empty input string
  4873. //
  4874. if (i == RawArgLength) {
  4875. return FALSE;
  4876. }
  4877. //
  4878. // Now run down the input string until we hit a comma or a semicolon or
  4879. // the end of the string, remembering where we started.
  4880. //
  4881. FirstArgStart = i;
  4882. while (i < RawArgLength) {
  4883. if ((RawArg.Buffer[i] == L',') || (RawArg.Buffer[i] == L';')) {
  4884. break;
  4885. }
  4886. i += 1;
  4887. }
  4888. //
  4889. // At this point all characters up to (but not including) i are
  4890. // in the first part. So setup the first arg. A leading comma returns
  4891. // a zero length string.
  4892. //
  4893. FirstArg->Length = (USHORT)((i - FirstArgStart) * sizeof(WCHAR));
  4894. FirstArg->MaximumLength = FirstArg->Length;
  4895. FirstArg->Buffer = &RawArg.Buffer[FirstArgStart];
  4896. //
  4897. // If no more string is left then return zero length. Else eat the comma and
  4898. // return the remaining part (could be null if string ends with comma).
  4899. //
  4900. if (i < RawArgLength) {
  4901. RemainingArg->Length = (USHORT)((RawArgLength - (i+1)) * sizeof(WCHAR));
  4902. RemainingArg->MaximumLength = RemainingArg->Length;
  4903. RemainingArg->Buffer = &RawArg.Buffer[i+1];
  4904. }
  4905. //DPRINT2(5, "FirstArg string: %ws {%d)\n",
  4906. // (FirstArg->Buffer != NULL) ? FirstArg->Buffer : L"<NULL>", FirstArg->Length);
  4907. //DPRINT2(5, "RemainingArg string: %ws {%d)\n",
  4908. // (RemainingArg->Buffer != NULL) ? RemainingArg->Buffer : L"<NULL>", RemainingArg->Length);
  4909. return TRUE;
  4910. }
  4911. BOOL
  4912. FrsCheckNameFilter(
  4913. IN PUNICODE_STRING Name,
  4914. IN PLIST_ENTRY FilterListHead
  4915. )
  4916. /*++
  4917. Routine Description:
  4918. Check the file name against each entry in the specified filter list.
  4919. Arguments:
  4920. Name - The file name to check (no slashes, spaces, etc.)
  4921. FilterListHead - The head of the filter list.
  4922. Return Value:
  4923. TRUE if Name is found in the FilterList.
  4924. --*/
  4925. {
  4926. #undef DEBSUB
  4927. #define DEBSUB "FrsCheckNameFilter:"
  4928. NTSTATUS Status;
  4929. ULONG Length;
  4930. BOOL Found = FALSE;
  4931. UNICODE_STRING UpcaseName;
  4932. WCHAR LocalBuffer[64];
  4933. if (IsListEmpty(FilterListHead)) {
  4934. return FALSE;
  4935. }
  4936. //
  4937. // Upper case the name string.
  4938. //
  4939. Length = Name->Length;
  4940. UpcaseName.Length = (USHORT) Length;
  4941. UpcaseName.MaximumLength = (USHORT) Length;
  4942. UpcaseName.Buffer = (Length > sizeof(LocalBuffer)) ? FrsAlloc(Length) : LocalBuffer;
  4943. Status = RtlUpcaseUnicodeString(&UpcaseName, Name, FALSE);
  4944. if (!NT_SUCCESS(Status)) {
  4945. DPRINT_NT(0, "++ RtlUpcaseUnicodeString failed;", Status);
  4946. FRS_ASSERT(!"RtlUpcaseUnicodeString failed");
  4947. goto RETURN;
  4948. }
  4949. //
  4950. // Walk the filter list, checking the name against each entry.
  4951. //
  4952. ForEachSimpleListEntry( FilterListHead, WILDCARD_FILTER_ENTRY, ListEntry,
  4953. //
  4954. // iterator pE is of type *WILDCARD_FILTER_ENTRY.
  4955. //
  4956. if (BooleanFlagOn(pE->Flags, WILDCARD_FILTER_ENTRY_IS_WILD)) {
  4957. Found = FrsIsNameInExpression(&pE->UFileName, &UpcaseName, FALSE, NULL);
  4958. } else {
  4959. Found = RtlEqualUnicodeString(&pE->UFileName, &UpcaseName, FALSE);
  4960. }
  4961. if (Found) {
  4962. break;
  4963. }
  4964. );
  4965. RETURN:
  4966. //
  4967. // Free the upcase buffer if we could not use the local one.
  4968. //
  4969. if (UpcaseName.Buffer != LocalBuffer) {
  4970. FrsFree(UpcaseName.Buffer);
  4971. }
  4972. UpcaseName.Buffer = NULL;
  4973. return Found;
  4974. }
  4975. VOID
  4976. FrsEmptyNameFilter(
  4977. IN PLIST_ENTRY FilterListHead
  4978. )
  4979. /*++
  4980. Routine Description:
  4981. Empty the filter list.
  4982. Arguments:
  4983. FilterListHead - The list head to empty.
  4984. Return Value:
  4985. None.
  4986. --*/
  4987. {
  4988. #undef DEBSUB
  4989. #define DEBSUB "FrsEmptyNameFilter:"
  4990. ForEachSimpleListEntry( FilterListHead, WILDCARD_FILTER_ENTRY, ListEntry,
  4991. //
  4992. // iterator pE is of type *WILDCARD_FILTER_ENTRY.
  4993. //
  4994. RemoveEntryList(&pE->ListEntry);
  4995. FrsFreeType(pE);
  4996. );
  4997. }
  4998. VOID
  4999. FrsLoadNameFilter(
  5000. IN PUNICODE_STRING FilterString,
  5001. IN PLIST_ENTRY FilterListHead
  5002. )
  5003. /*++
  5004. Routine Description:
  5005. Parse the input filter string and create a new filter list.
  5006. If the filter list passed in is not empty then it is emptied first.
  5007. Arguments:
  5008. FilterString - The comma separated filter list.
  5009. FilterListHead - The list head on which to create the filter entries.
  5010. Return Value:
  5011. None.
  5012. --*/
  5013. {
  5014. #undef DEBSUB
  5015. #define DEBSUB "FrsLoadNameFilter:"
  5016. NTSTATUS Status;
  5017. ULONG Length;
  5018. PWILDCARD_FILTER_ENTRY FilterEntry;
  5019. UNICODE_STRING UpcaseFilter, FirstArg;
  5020. WCHAR LocalBuffer[128];
  5021. //
  5022. // Empty the filter list if neessary.
  5023. //
  5024. FrsEmptyNameFilter(FilterListHead);
  5025. //
  5026. // Uppercase the new filter string.
  5027. //
  5028. DPRINT2(5, "++ filter string: %ws (%d)\n",
  5029. (FilterString->Buffer != NULL) ? FilterString->Buffer : L"<NULL>",
  5030. FilterString->Length);
  5031. Length = FilterString->Length;
  5032. UpcaseFilter.Length = (USHORT) Length;
  5033. UpcaseFilter.MaximumLength = (USHORT) Length;
  5034. UpcaseFilter.Buffer = (Length > sizeof(LocalBuffer)) ? FrsAlloc(Length) : LocalBuffer;
  5035. Status = RtlUpcaseUnicodeString(&UpcaseFilter, FilterString, FALSE);
  5036. if (!NT_SUCCESS(Status)) {
  5037. DPRINT_NT(0, "++ RtlUpcaseUnicodeString failed;", Status);
  5038. FRS_ASSERT(!"RtlUpcaseUnicodeString failed");
  5039. goto RETURN;
  5040. }
  5041. //
  5042. // Parse the comma list (skipping null entries) and create filter
  5043. // entries for each one.
  5044. //
  5045. while (FrsDissectCommaList (UpcaseFilter, &FirstArg, &UpcaseFilter)) {
  5046. Length = (ULONG) FirstArg.Length;
  5047. if (Length == 0) {
  5048. continue;
  5049. }
  5050. // DPRINT2(5, "++ FirstArg string: %ws {%d)\n",
  5051. // (FirstArg.Buffer != NULL) ? FirstArg.Buffer : L"<NULL>",
  5052. // FirstArg.Length);
  5053. //
  5054. // Allocate and init a wildcard filter entry.
  5055. //
  5056. FilterEntry = FrsAllocTypeSize(WILDCARD_FILTER_ENTRY_TYPE, Length);
  5057. FilterEntry->UFileName.Length = FirstArg.Length;
  5058. FilterEntry->UFileName.MaximumLength = FirstArg.MaximumLength;
  5059. CopyMemory(FilterEntry->UFileName.Buffer, FirstArg.Buffer, Length);
  5060. FilterEntry->UFileName.Buffer[Length/2] = UNICODE_NULL;
  5061. //
  5062. // Check for any wild card characters in the name.
  5063. //
  5064. if (FrsDoesNameContainWildCards(&FilterEntry->UFileName)) {
  5065. SetFlag(FilterEntry->Flags, WILDCARD_FILTER_ENTRY_IS_WILD);
  5066. //DPRINT1(5, "++ Wildcards found in %ws\n", FilterEntry->UFileName.Buffer);
  5067. }
  5068. //
  5069. // Add the entry to the end of the filter list.
  5070. //
  5071. InsertTailList(FilterListHead, &FilterEntry->ListEntry);
  5072. }
  5073. RETURN:
  5074. //
  5075. // Free the upcase buffer if we could not use the local one.
  5076. //
  5077. if (UpcaseFilter.Buffer != LocalBuffer) {
  5078. FrsFree(UpcaseFilter.Buffer);
  5079. }
  5080. UpcaseFilter.Buffer = NULL;
  5081. return;
  5082. }
  5083. ULONG
  5084. FrsParseIntegerCommaList(
  5085. IN PWCHAR ArgString,
  5086. IN ULONG MaxResults,
  5087. OUT PLONG Results,
  5088. OUT PULONG NumberResults,
  5089. OUT PULONG Offset
  5090. )
  5091. /*++
  5092. Routine Description:
  5093. Parse a list of integers separated by commas.
  5094. The integers are returned in successive locations of the Results array.
  5095. Null entries (e.g. ",,") return zero for the value.
  5096. Arguments:
  5097. ArgString - The comma separated NULL terminated string with integer values.
  5098. MaxResults - The maximum number of results that can be returned.
  5099. Results - An array of the integer results.
  5100. NumberResults - The number of results returned.
  5101. Offset - The offset to the next byte to process in ArgString if there
  5102. were not enough entries to return all the results.
  5103. Return Value:
  5104. FrsErrorStatus.
  5105. --*/
  5106. {
  5107. #undef DEBSUB
  5108. #define DEBSUB "FrsParseIntegerCommaList:"
  5109. NTSTATUS Status;
  5110. ULONG Length, i = 0;
  5111. ULONG FStatus = FrsErrorSuccess;
  5112. BOOL More;
  5113. PWILDCARD_FILTER_ENTRY FilterEntry;
  5114. UNICODE_STRING TempUStr, FirstArg;
  5115. RtlInitUnicodeString(&TempUStr, ArgString);
  5116. //
  5117. // Parse the comma list and convert each entry to a LONG.
  5118. //
  5119. while (More = FrsDissectCommaList (TempUStr, &FirstArg, &TempUStr) &&
  5120. (i < MaxResults)) {
  5121. Length = (ULONG) FirstArg.Length;
  5122. Results[i] = 0;
  5123. if (Length == 0) {
  5124. i += 1;
  5125. continue;
  5126. }
  5127. Status = RtlUnicodeStringToInteger (&FirstArg, 10, &Results[i]);
  5128. if (!NT_SUCCESS(Status)) {
  5129. DPRINT2_NT(1, "++ RtlUnicodeStringToInteger failed on arg %d of %ws :",
  5130. i, ArgString, Status);
  5131. FStatus = FrsErrorBadParam;
  5132. }
  5133. i += 1;
  5134. }
  5135. *NumberResults = i;
  5136. if (More) {
  5137. //
  5138. // There are more arguments to parse but we are out of the loop so
  5139. // return MoreWork status along with the offset into ArgString where
  5140. // we left off.
  5141. //
  5142. if (FStatus == FrsErrorSuccess) {
  5143. FStatus = FrsErrorMoreWork;
  5144. }
  5145. *Offset = (ULONG)(FirstArg.Buffer - ArgString);
  5146. }
  5147. return FStatus;
  5148. }
  5149. DWORD
  5150. FrsSetFileAttributes(
  5151. PWCHAR Name,
  5152. HANDLE Handle,
  5153. ULONG FileAttributes
  5154. )
  5155. /*++
  5156. Routine Description:
  5157. This routine sets the file's attributes
  5158. Arguments:
  5159. Name - for error messages
  5160. Handle - Supplies a handle to the file that is to be marked for delete.
  5161. Attributes - Attributes for the file
  5162. Return Value:
  5163. WStatus.
  5164. --*/
  5165. {
  5166. #undef DEBSUB
  5167. #define DEBSUB "FrsSetFileAttributes:"
  5168. IO_STATUS_BLOCK IoStatus;
  5169. FILE_BASIC_INFORMATION BasicInformation;
  5170. NTSTATUS Status;
  5171. DWORD WStatus = ERROR_SUCCESS;
  5172. //
  5173. // Set the attributes
  5174. //
  5175. ZeroMemory(&BasicInformation, sizeof(BasicInformation));
  5176. BasicInformation.FileAttributes = FileAttributes | FILE_ATTRIBUTE_NORMAL;
  5177. Status = NtSetInformationFile(Handle,
  5178. &IoStatus,
  5179. &BasicInformation,
  5180. sizeof(BasicInformation),
  5181. FileBasicInformation);
  5182. if (!NT_SUCCESS(Status)) {
  5183. WStatus = FrsSetLastNTError(Status);
  5184. DPRINT1_NT(0, " ERROR - NtSetInformationFile(BasicInformation) failed on %ws :",
  5185. Name, Status);
  5186. }
  5187. return WStatus;
  5188. }
  5189. DWORD
  5190. FrsResetAttributesForReplication(
  5191. PWCHAR Name,
  5192. HANDLE Handle
  5193. )
  5194. /*++
  5195. Routine Description:
  5196. This routine turns off the attributes that prevent deletion and write
  5197. Arguments:
  5198. Name - for error messages
  5199. Handle - Supplies a handle to the file that is to be marked for delete.
  5200. Return Value:
  5201. WStatus.
  5202. --*/
  5203. {
  5204. #undef DEBSUB
  5205. #define DEBSUB "FrsResetAttributesForReplication:"
  5206. FILE_NETWORK_OPEN_INFORMATION FileInfo;
  5207. DWORD WStatus = ERROR_SUCCESS;
  5208. //
  5209. // Get the file's attributes
  5210. //
  5211. if (!FrsGetFileInfoByHandle(Name, Handle, &FileInfo)) {
  5212. DPRINT1(4, "++ Can't get attributes for %ws\n", Name);
  5213. WIN_SET_FAIL(WStatus);
  5214. return WStatus;
  5215. }
  5216. //
  5217. // Turn off the access attributes that prevent deletion and write
  5218. //
  5219. if (FileInfo.FileAttributes & NOREPL_ATTRIBUTES) {
  5220. DPRINT1(4, "++ Reseting attributes for %ws\n", Name);
  5221. WStatus = FrsSetFileAttributes(Name, Handle,
  5222. FileInfo.FileAttributes &
  5223. ~NOREPL_ATTRIBUTES);
  5224. if (!WIN_SUCCESS(WStatus)) {
  5225. DPRINT1(4, "++ Can't reset attributes for %ws\n", Name);
  5226. return WStatus;
  5227. }
  5228. DPRINT1(4, "++ Attributes for %ws now allow replication\n", Name);
  5229. } else {
  5230. DPRINT1(4, "++ Attributes for %ws allow replication\n", Name);
  5231. }
  5232. return WStatus;
  5233. }
  5234. DWORD
  5235. FrsEnumerateDirectoryDeleteWorker(
  5236. IN HANDLE DirectoryHandle,
  5237. IN PWCHAR DirectoryName,
  5238. IN DWORD DirectoryLevel,
  5239. IN PFILE_DIRECTORY_INFORMATION DirectoryRecord,
  5240. IN DWORD DirectoryFlags,
  5241. IN PWCHAR FileName,
  5242. IN PVOID Ignored
  5243. )
  5244. /*++
  5245. Routine Description:
  5246. Empty a directory of non-replicating files and dirs if this is
  5247. an ERROR_DIR_NOT_EMPTY and this is a retry change order for a
  5248. directory delete.
  5249. Arguments:
  5250. DirectoryHandle - Handle for this directory.
  5251. DirectoryName - Relative name of directory
  5252. DirectoryLevel - Directory level (0 == root)
  5253. DirectoryFlags - See tablefcn.h, ENUMERATE_DIRECTORY_FLAGS_
  5254. DirectoryRecord - Record from DirectoryHandle
  5255. FileName - From DirectoryRecord (w/terminating NULL)
  5256. Ignored - Context is ignored
  5257. Return Value:
  5258. Win32 Status
  5259. --*/
  5260. {
  5261. #undef DEBSUB
  5262. #define DEBSUB "FrsEnumerateDirectoryDeleteWorker:"
  5263. DWORD WStatus;
  5264. NTSTATUS NtStatus;
  5265. HANDLE Handle = INVALID_HANDLE_VALUE;
  5266. UNICODE_STRING ObjectName;
  5267. OBJECT_ATTRIBUTES ObjectAttributes;
  5268. IO_STATUS_BLOCK IoStatusBlock;
  5269. //
  5270. // Depth first
  5271. //
  5272. if (DirectoryRecord->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  5273. WStatus = FrsEnumerateDirectoryRecurse(DirectoryHandle,
  5274. DirectoryName,
  5275. DirectoryLevel,
  5276. DirectoryRecord,
  5277. DirectoryFlags,
  5278. FileName,
  5279. INVALID_HANDLE_VALUE,
  5280. Ignored,
  5281. FrsEnumerateDirectoryDeleteWorker);
  5282. if (!WIN_SUCCESS(WStatus)) {
  5283. goto CLEANUP;
  5284. }
  5285. }
  5286. //
  5287. // Relative open
  5288. //
  5289. ZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
  5290. ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
  5291. ObjectName.Length = (USHORT)DirectoryRecord->FileNameLength;
  5292. ObjectName.MaximumLength = (USHORT)DirectoryRecord->FileNameLength;
  5293. ObjectName.Buffer = DirectoryRecord->FileName;
  5294. ObjectAttributes.ObjectName = &ObjectName;
  5295. ObjectAttributes.RootDirectory = DirectoryHandle;
  5296. NtStatus = NtCreateFile(&Handle,
  5297. // GENERIC_READ | SYNCHRONIZE | DELETE | FILE_WRITE_ATTRIBUTES,
  5298. DELETE | SYNCHRONIZE | READ_ATTRIB_ACCESS | FILE_WRITE_ATTRIBUTES,
  5299. &ObjectAttributes,
  5300. &IoStatusBlock,
  5301. NULL, // AllocationSize
  5302. FILE_ATTRIBUTE_NORMAL,
  5303. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  5304. FILE_OPEN,
  5305. FILE_OPEN_FOR_BACKUP_INTENT |
  5306. FILE_OPEN_REPARSE_POINT |
  5307. FILE_SYNCHRONOUS_IO_NONALERT,
  5308. NULL, // EA buffer
  5309. 0 // EA buffer size
  5310. );
  5311. //
  5312. // Error opening file or directory
  5313. //
  5314. WStatus = FrsSetLastNTError(NtStatus);
  5315. CLEANUP1_WS(0, "++ ERROR - NtCreateFile(%ws) failed :", FileName, WStatus, CLEANUP);
  5316. //
  5317. // Turn off readonly, system, and hidden
  5318. //
  5319. FrsResetAttributesForReplication(FileName, Handle);
  5320. //
  5321. // Delete the file
  5322. //
  5323. WStatus = FrsDeleteByHandle(FileName, Handle);
  5324. DPRINT2(4, "++ Deleted file %ws\\%ws\n", DirectoryName, FileName);
  5325. CLEANUP:
  5326. FRS_CLOSE(Handle);
  5327. return WStatus;
  5328. }
  5329. DWORD
  5330. FrsEnumerateDirectoryRecurse(
  5331. IN HANDLE DirectoryHandle,
  5332. IN PWCHAR DirectoryName,
  5333. IN DWORD DirectoryLevel,
  5334. IN PFILE_DIRECTORY_INFORMATION DirectoryRecord,
  5335. IN DWORD DirectoryFlags,
  5336. IN PWCHAR FileName,
  5337. IN HANDLE FileHandle,
  5338. IN PVOID Context,
  5339. IN PENUMERATE_DIRECTORY_ROUTINE Function
  5340. )
  5341. /*++
  5342. Routine Description:
  5343. Open the directory identified by FileName in the directory
  5344. identified by DirectoryHandle and call FrsEnumerateDirectory().
  5345. Arguments:
  5346. DirectoryHandle - Handle for this directory.
  5347. DirectoryName - Relative name of directory
  5348. DirectoryLevel - Directory level
  5349. DirectoryRecord - From FrsEnumerateRecord()
  5350. DirectoryFlags - See tablefcn.h, ENUMERATE_DIRECTORY_FLAGS_
  5351. FileName - Open this directory and recurse
  5352. FileHandle - Use for FileName if not INVALID_HANDLE_VALUE
  5353. Context - Passes global info from the caller to Function
  5354. Function - Called for every record
  5355. Return Value:
  5356. WIN32 STATUS
  5357. --*/
  5358. {
  5359. #undef DEBSUB
  5360. #define DEBSUB "FrsEnumerateDirectoryRecurse:"
  5361. DWORD WStatus;
  5362. NTSTATUS NtStatus;
  5363. HANDLE LocalHandle = INVALID_HANDLE_VALUE;
  5364. UNICODE_STRING ObjectName;
  5365. OBJECT_ATTRIBUTES ObjectAttributes;
  5366. IO_STATUS_BLOCK IoStatusBlock;
  5367. //
  5368. // Relative open
  5369. //
  5370. if (!HANDLE_IS_VALID(FileHandle)) {
  5371. ZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
  5372. ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
  5373. ObjectName.Length = (USHORT)DirectoryRecord->FileNameLength;
  5374. ObjectName.MaximumLength = (USHORT)DirectoryRecord->FileNameLength;
  5375. ObjectName.Buffer = DirectoryRecord->FileName;
  5376. ObjectAttributes.ObjectName = &ObjectName;
  5377. ObjectAttributes.RootDirectory = DirectoryHandle;
  5378. NtStatus = NtCreateFile(&LocalHandle,
  5379. // READ_ACCESS,
  5380. READ_ATTRIB_ACCESS | FILE_LIST_DIRECTORY,
  5381. &ObjectAttributes,
  5382. &IoStatusBlock,
  5383. NULL, // AllocationSize
  5384. FILE_ATTRIBUTE_NORMAL,
  5385. FILE_SHARE_READ | FILE_SHARE_WRITE,
  5386. FILE_OPEN,
  5387. FILE_OPEN_FOR_BACKUP_INTENT |
  5388. FILE_OPEN_REPARSE_POINT |
  5389. FILE_SEQUENTIAL_ONLY |
  5390. FILE_SYNCHRONOUS_IO_NONALERT,
  5391. NULL, // EA buffer
  5392. 0 // EA buffer size
  5393. );
  5394. //
  5395. // Error opening directory
  5396. //
  5397. if (!NT_SUCCESS(NtStatus)) {
  5398. DPRINT1_NT(0, "++ ERROR - NtCreateFile(%ws) :", FileName, NtStatus);
  5399. if (DirectoryFlags & ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE) {
  5400. //
  5401. // Skip this directory tree
  5402. //
  5403. WStatus = ERROR_SUCCESS;
  5404. } else {
  5405. //
  5406. // Abort the entire enumeration
  5407. //
  5408. WStatus = FrsSetLastNTError(NtStatus);
  5409. }
  5410. goto CLEANUP;
  5411. }
  5412. FileHandle = LocalHandle;
  5413. }
  5414. //
  5415. // RECURSE
  5416. //
  5417. WStatus = FrsEnumerateDirectory(FileHandle,
  5418. FileName,
  5419. DirectoryLevel + 1,
  5420. DirectoryFlags,
  5421. Context,
  5422. Function);
  5423. CLEANUP:
  5424. FRS_CLOSE(LocalHandle);
  5425. return WStatus;
  5426. }
  5427. DWORD
  5428. FrsEnumerateDirectory(
  5429. IN HANDLE DirectoryHandle,
  5430. IN PWCHAR DirectoryName,
  5431. IN DWORD DirectoryLevel,
  5432. IN DWORD DirectoryFlags,
  5433. IN PVOID Context,
  5434. IN PENUMERATE_DIRECTORY_ROUTINE Function
  5435. )
  5436. /*++
  5437. Routine Description:
  5438. Enumerate the directory identified by DirectoryHandle, passing each
  5439. directory record to Function. If the record is for a directory,
  5440. call Function before recursing if ProcessBeforeCallingFunction
  5441. is TRUE.
  5442. Function controls the enumeration of the CURRENT directory
  5443. by setting ContinueEnumeration to TRUE (continue) or
  5444. FALSE (terminate).
  5445. Function controls the enumeration of the entire directory
  5446. tree by returning a WIN32 STATUS that is not ERROR_SUCCESS.
  5447. FrsEnumerateDirectory() will terminate the entire directory
  5448. enumeration by returning a WIN32 STATUS other than ERROR_SUCCESS
  5449. when encountering an error.
  5450. Context passes global info from the caller to Function.
  5451. Arguments:
  5452. DirectoryHandle - Handle for this directory.
  5453. DirectoryName - Relative name of directory
  5454. DirectoryLevel - Directory level
  5455. DirectoryFlags - See tablefcn.h, ENUMERATE_DIRECTORY_FLAGS_
  5456. Context - Passes global info from the caller to Function
  5457. Function - Called for every record
  5458. Return Value:
  5459. WIN32 STATUS
  5460. --*/
  5461. {
  5462. #undef DEBSUB
  5463. #define DEBSUB "FrsEnumerateDirectory:"
  5464. DWORD WStatus;
  5465. NTSTATUS NtStatus;
  5466. BOOL Recurse;
  5467. PFILE_DIRECTORY_INFORMATION DirectoryRecord;
  5468. PFILE_DIRECTORY_INFORMATION DirectoryBuffer = NULL;
  5469. BOOLEAN RestartScan = TRUE;
  5470. PWCHAR FileName = NULL;
  5471. DWORD FileNameLength = 0;
  5472. DWORD NumBuffers = 0;
  5473. DWORD NumRecords = 0;
  5474. UNICODE_STRING ObjectName;
  5475. OBJECT_ATTRIBUTES ObjectAttributes;
  5476. IO_STATUS_BLOCK IoStatusBlock;
  5477. extern LONG EnumerateDirectorySizeInBytes;
  5478. DPRINT3(4, "++ Enumerating %ws at level %d using buffer size %d\n",
  5479. DirectoryName, DirectoryLevel, EnumerateDirectorySizeInBytes);
  5480. //
  5481. // The buffer size is configurable with registry value
  5482. // ENUMERATE_DIRECTORY_SIZE
  5483. //
  5484. DirectoryBuffer = FrsAlloc(EnumerateDirectorySizeInBytes);
  5485. NEXT_BUFFER:
  5486. if (FrsIsShuttingDown) {
  5487. DPRINT(0, "WARN - IDTable Load aborted; service shutting down\n");
  5488. WStatus = ERROR_PROCESS_ABORTED;
  5489. goto CLEANUP;
  5490. }
  5491. //
  5492. // READ A BUFFER FULL OF DIRECTORY INFORMATION
  5493. //
  5494. NtStatus = NtQueryDirectoryFile(DirectoryHandle, // Directory Handle
  5495. NULL, // Event
  5496. NULL, // ApcRoutine
  5497. NULL, // ApcContext
  5498. &IoStatusBlock,
  5499. DirectoryBuffer,
  5500. EnumerateDirectorySizeInBytes,
  5501. FileDirectoryInformation,
  5502. FALSE, // return single entry
  5503. NULL, // FileName
  5504. RestartScan // restart scan
  5505. );
  5506. //
  5507. // Enumeration Complete
  5508. //
  5509. if (NtStatus == STATUS_NO_MORE_FILES) {
  5510. WStatus = ERROR_SUCCESS;
  5511. goto CLEANUP;
  5512. }
  5513. //
  5514. // Error enumerating directory; return to caller
  5515. //
  5516. if (!NT_SUCCESS(NtStatus)) {
  5517. DPRINT1_NT(0, "++ ERROR - NtQueryDirectoryFile(%ws) : ", DirectoryName, NtStatus);
  5518. if (DirectoryFlags & ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE) {
  5519. //
  5520. // Don't abort the entire enumeration; just this directory
  5521. //
  5522. WStatus = ERROR_SUCCESS;
  5523. } else {
  5524. //
  5525. // Abort the entire enumeration
  5526. //
  5527. WStatus = FrsSetLastNTError(NtStatus);
  5528. }
  5529. goto CLEANUP;
  5530. }
  5531. ++NumBuffers;
  5532. //
  5533. // PROCESS DIRECTORY RECORDS
  5534. //
  5535. DirectoryRecord = DirectoryBuffer;
  5536. NEXT_RECORD:
  5537. if (FrsIsShuttingDown) {
  5538. DPRINT(0, "WARN - IDTable Load aborted; service shutting down\n");
  5539. WStatus = ERROR_PROCESS_ABORTED;
  5540. goto CLEANUP;
  5541. }
  5542. ++NumRecords;
  5543. //
  5544. // Filter . and ..
  5545. //
  5546. if (DirectoryRecord->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  5547. //
  5548. // Skip .
  5549. //
  5550. if (DirectoryRecord->FileNameLength == 2 &&
  5551. DirectoryRecord->FileName[0] == L'.') {
  5552. goto ADVANCE_TO_NEXT_RECORD;
  5553. }
  5554. //
  5555. // Skip ..
  5556. //
  5557. if (DirectoryRecord->FileNameLength == 4 &&
  5558. DirectoryRecord->FileName[0] == L'.' &&
  5559. DirectoryRecord->FileName[1] == L'.') {
  5560. goto ADVANCE_TO_NEXT_RECORD;
  5561. }
  5562. } else if (DirectoryFlags & ENUMERATE_DIRECTORY_FLAGS_DIRECTORIES_ONLY) {
  5563. goto ADVANCE_TO_NEXT_RECORD;
  5564. }
  5565. //
  5566. // Add a terminating NULL to the FileName (painful)
  5567. //
  5568. if (FileNameLength < DirectoryRecord->FileNameLength + sizeof(WCHAR)) {
  5569. FrsFree(FileName);
  5570. FileNameLength = DirectoryRecord->FileNameLength + sizeof(WCHAR);
  5571. FileName = FrsAlloc(FileNameLength);
  5572. }
  5573. CopyMemory(FileName, DirectoryRecord->FileName, DirectoryRecord->FileNameLength);
  5574. FileName[DirectoryRecord->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
  5575. //
  5576. // Process the record
  5577. //
  5578. WStatus = (*Function)(DirectoryHandle,
  5579. DirectoryName,
  5580. DirectoryLevel,
  5581. DirectoryRecord,
  5582. DirectoryFlags,
  5583. FileName,
  5584. Context);
  5585. if (!WIN_SUCCESS(WStatus)) {
  5586. if (DirectoryFlags & ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE) {
  5587. //
  5588. // Don't abort the entire enumeration; just this entry
  5589. //
  5590. WStatus = ERROR_SUCCESS;
  5591. } else {
  5592. //
  5593. // Abort the entire enumeration
  5594. //
  5595. goto CLEANUP;
  5596. }
  5597. }
  5598. ADVANCE_TO_NEXT_RECORD:
  5599. //
  5600. // Next record
  5601. //
  5602. if (DirectoryRecord->NextEntryOffset) {
  5603. DirectoryRecord = (PVOID)(((PCHAR)DirectoryRecord) +
  5604. DirectoryRecord->NextEntryOffset);
  5605. goto NEXT_RECORD;
  5606. }
  5607. //
  5608. // Done with this buffer; go get another one
  5609. // But don't restart the scan for every loop!
  5610. //
  5611. RestartScan = FALSE;
  5612. goto NEXT_BUFFER;
  5613. CLEANUP:
  5614. FrsFree(FileName);
  5615. FrsFree(DirectoryBuffer);
  5616. DPRINT5(4, "++ Enumerating %ws at level %d has finished "
  5617. "(%d buffers, %d records) with WStatus %s\n",
  5618. DirectoryName, DirectoryLevel, NumBuffers, NumRecords, ErrLabelW32(WStatus));
  5619. return WStatus;
  5620. }
  5621. DWORD
  5622. FrsFillDisk(
  5623. IN PWCHAR DirectoryName,
  5624. IN BOOL Cleanup
  5625. )
  5626. /*++
  5627. Routine Description:
  5628. Use all the disk space by creating a file in DirectoryName and
  5629. allocating space down to the last byte.
  5630. Delete the fill file if Cleanup is TRUE;
  5631. Arguments:
  5632. DirectoryName - Full pathname to the directory
  5633. Cleanup - Delete file if TRUE
  5634. Return Value:
  5635. WIN32 STATUS (ERROR_DISK_FULL is mapped to ERROR_SUCCESS)
  5636. --*/
  5637. {
  5638. #undef DEBSUB
  5639. #define DEBSUB "FrsFillDisk:"
  5640. DWORD WStatus;
  5641. NTSTATUS NtStatus;
  5642. DWORD Tid;
  5643. ULONGLONG Eof;
  5644. ULONGLONG NewEof;
  5645. ULONGLONG IncEof;
  5646. LARGE_INTEGER LargeInteger;
  5647. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  5648. HANDLE DirectoryHandle = INVALID_HANDLE_VALUE;
  5649. UNICODE_STRING ObjectName;
  5650. OBJECT_ATTRIBUTES ObjectAttributes;
  5651. IO_STATUS_BLOCK IoStatusBlock;
  5652. WCHAR TidW[9];
  5653. //
  5654. // Open parent directory
  5655. //
  5656. WStatus = FrsOpenSourceFileW(&DirectoryHandle, DirectoryName, READ_ACCESS, OPEN_OPTIONS);
  5657. CLEANUP1_WS(0, "++ DBG ERROR - Cannot open fill directory %ws;",
  5658. DirectoryName, WStatus, CLEANUP);
  5659. //
  5660. // Relative open
  5661. //
  5662. Tid = GetCurrentThreadId();
  5663. swprintf(TidW, L"%08x", Tid);
  5664. ZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
  5665. ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
  5666. ObjectName.Length = (USHORT)(wcslen(TidW) * sizeof(WCHAR));
  5667. ObjectName.MaximumLength = (USHORT)(wcslen(TidW) * sizeof(WCHAR));
  5668. ObjectName.Buffer = TidW;
  5669. ObjectAttributes.ObjectName = &ObjectName;
  5670. ObjectAttributes.RootDirectory = DirectoryHandle;
  5671. NtStatus = NtCreateFile(
  5672. &FileHandle,
  5673. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | DELETE | FILE_WRITE_ATTRIBUTES,
  5674. &ObjectAttributes,
  5675. &IoStatusBlock,
  5676. NULL, // AllocationSize
  5677. FILE_ATTRIBUTE_NORMAL,
  5678. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  5679. FILE_OPEN_IF,
  5680. FILE_OPEN_FOR_BACKUP_INTENT |
  5681. FILE_OPEN_REPARSE_POINT |
  5682. FILE_SYNCHRONOUS_IO_NONALERT,
  5683. NULL, // EA buffer
  5684. 0 // EA buffer size
  5685. );
  5686. //
  5687. // Error opening file or directory
  5688. //
  5689. if (!NT_SUCCESS(NtStatus)) {
  5690. WStatus = FrsSetLastNTError(NtStatus);
  5691. CLEANUP1_NT(0, "++ DBG ERROR - NtCreateFile(%ws) : ", TidW, NtStatus, CLEANUP);
  5692. }
  5693. //
  5694. // Remove fill file
  5695. //
  5696. if (Cleanup) {
  5697. //
  5698. // Turn off readonly, system, and hidden
  5699. //
  5700. FrsResetAttributesForReplication(TidW, FileHandle);
  5701. //
  5702. // Delete the file
  5703. //
  5704. WStatus = FrsDeleteByHandle(TidW, FileHandle);
  5705. DPRINT2(4, "++ DBG - Deleted file %ws\\%ws\n", DirectoryName, TidW);
  5706. LeaveCriticalSection(&DebugInfo.DbsOutOfSpaceLock);
  5707. goto CLEANUP;
  5708. }
  5709. //
  5710. // WARN: Hold the lock until the file is deleted
  5711. //
  5712. EnterCriticalSection(&DebugInfo.DbsOutOfSpaceLock);
  5713. //
  5714. // Create fill file
  5715. //
  5716. NewEof = 0;
  5717. Eof = 0;
  5718. for (IncEof = (LONGLONG)-1; IncEof; IncEof >>= 1) {
  5719. NewEof = Eof;
  5720. do {
  5721. NewEof += IncEof;
  5722. LargeInteger.QuadPart = NewEof;
  5723. WStatus = FrsSetFilePointer(TidW, FileHandle, LargeInteger.HighPart,
  5724. LargeInteger.LowPart);
  5725. if (!WIN_SUCCESS(WStatus)) {
  5726. continue;
  5727. }
  5728. if (!SetEndOfFile(FileHandle)) {
  5729. WStatus = GetLastError();
  5730. continue;
  5731. }
  5732. DPRINT2(4, "++ DBG %ws: Allocated Eof is %08x %08x\n",
  5733. TidW, PRINTQUAD(NewEof));
  5734. Eof = NewEof;
  5735. WStatus = ERROR_SUCCESS;
  5736. } while (WIN_SUCCESS(WStatus) && !FrsIsShuttingDown);
  5737. }
  5738. DPRINT3(4, "++ DBG - Allocated %d MB in %ws\\%ws\n",
  5739. (DWORD)(Eof / (1024 * 1024)), DirectoryName, TidW);
  5740. CLEANUP:
  5741. FRS_CLOSE(DirectoryHandle);
  5742. FRS_CLOSE(FileHandle);
  5743. return WStatus;
  5744. }
  5745. #define THIRTY_SECONDS (30 * 1000)
  5746. ULONG
  5747. FrsRunProcess(
  5748. IN PWCHAR AppPathAndName,
  5749. IN PWCHAR CommandLine,
  5750. IN HANDLE StandardIn,
  5751. IN HANDLE StandardOut,
  5752. IN HANDLE StandardError
  5753. )
  5754. /*++
  5755. Routine Description:
  5756. Run the specified command in a separate process.
  5757. Wait for the process to complete.
  5758. Arguments:
  5759. AppPathAndName - Application to launch. Full path.
  5760. CommandLine - Unicode, null terminated command line string.
  5761. StandardIn - Handle to use for standard in.
  5762. StandardOut - Handle to use for Standard Out. NULL means use Debug log.
  5763. StandardError - Handle to use for Standard Error. NULL means use Debug log.
  5764. Return Value:
  5765. WIN32 STATUS
  5766. --*/
  5767. {
  5768. #undef DEBSUB
  5769. #define DEBSUB "FrsRunProcess:"
  5770. #define MAX_CMD_LINE 1024
  5771. ULONG WStatus;
  5772. LONG WaitCount=20;
  5773. BOOL NeedDbgLock = FALSE;
  5774. BOOL CloseStandardIn = FALSE;
  5775. BOOL BStatus = TRUE;
  5776. STARTUPINFO StartupInfo;
  5777. PROCESS_INFORMATION ProcessInfo;
  5778. DWORD Len;
  5779. DWORD TLen;
  5780. WCHAR ExpandedApp[MAX_CMD_LINE+1];
  5781. WCHAR ExpandedCmd[MAX_CMD_LINE+1];
  5782. SECURITY_ATTRIBUTES SecurityAttributes;
  5783. TLen = ARRAY_SZ(ExpandedApp);
  5784. //
  5785. // Setup the process I/O Handles.
  5786. //
  5787. if (!HANDLE_IS_VALID(StandardIn)) {
  5788. //
  5789. // Provide a handle to the NUL device for input.
  5790. //
  5791. // Set this handle to be inheritable as it is being passed
  5792. // to a child process that will inherit the handle.
  5793. //
  5794. SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  5795. SecurityAttributes.bInheritHandle = TRUE;
  5796. SecurityAttributes.lpSecurityDescriptor = NULL; // not same as NULL DACL
  5797. StandardIn = CreateFileW(
  5798. L"NUL", // lpszName
  5799. GENERIC_READ | GENERIC_WRITE, // fdwAccess
  5800. FILE_SHARE_READ | FILE_SHARE_WRITE, // fdwShareMode
  5801. &SecurityAttributes, // lpsa
  5802. OPEN_ALWAYS, // fdwCreate
  5803. FILE_ATTRIBUTE_NORMAL, // fdwAttrAndFlags
  5804. NULL // hTemplateFile
  5805. );
  5806. if (!HANDLE_IS_VALID(StandardIn)) {
  5807. WStatus = GetLastError();
  5808. DPRINT_WS(0, "++ CreateFileW(NUL) failed;", WStatus);
  5809. goto RETURN;
  5810. }
  5811. CloseStandardIn = TRUE;
  5812. }
  5813. if (!HANDLE_IS_VALID(StandardOut)) {
  5814. StandardOut = DebugInfo.LogFILE;
  5815. NeedDbgLock = TRUE;
  5816. }
  5817. if (!HANDLE_IS_VALID(StandardError)) {
  5818. StandardError = DebugInfo.LogFILE;
  5819. NeedDbgLock = TRUE;
  5820. }
  5821. memset(&StartupInfo, 0, sizeof(STARTUPINFO));
  5822. StartupInfo.cb = sizeof(STARTUPINFO);
  5823. StartupInfo.dwFlags = STARTF_USESTDHANDLES;
  5824. StartupInfo.hStdInput = StandardIn;
  5825. StartupInfo.hStdOutput = StandardOut;
  5826. StartupInfo.hStdError = StandardError;
  5827. //
  5828. // Look for environment vars in command line and expand them.
  5829. //
  5830. Len = ExpandEnvironmentStrings(AppPathAndName, ExpandedApp, TLen);
  5831. if (Len == 0) {
  5832. WStatus = GetLastError();
  5833. DPRINT1_WS(1, "++ ws command not expanded.", AppPathAndName, WStatus);
  5834. goto RETURN;
  5835. }
  5836. Len = ExpandEnvironmentStrings(CommandLine, ExpandedCmd, TLen);
  5837. if (Len == 0) {
  5838. WStatus = GetLastError();
  5839. DPRINT1_WS(1, "++ ws command not expanded.", CommandLine, WStatus);
  5840. goto RETURN;
  5841. }
  5842. DPRINT2(0,"++ Running: %ws, CommandLine: %ws\n", ExpandedApp, ExpandedCmd);
  5843. //
  5844. // Get debug lock so our output stays in one piece.
  5845. //
  5846. if (NeedDbgLock) {DebLock();}
  5847. try {
  5848. BStatus = CreateProcessW(
  5849. ExpandedApp, // lpApplicationName,
  5850. ExpandedCmd, // lpCommandLine,
  5851. NULL, // lpProcessAttributes,
  5852. NULL, // lpThreadAttributes,
  5853. TRUE, // bInheritHandles,
  5854. DETACHED_PROCESS | CREATE_NO_WINDOW, // dwCreationFlags,
  5855. NULL, // lpEnvironment,
  5856. NULL, // lpCurrentDirectory,
  5857. &StartupInfo, // lpStartupInfo,
  5858. &ProcessInfo); // lpProcessInformation
  5859. //
  5860. // Close the process and thread handles
  5861. //
  5862. if ( !BStatus ) {
  5863. WStatus = GetLastError();
  5864. DPRINT_NOLOCK3(0, "++ CreateProcessW Failed to run: '%ws', CommandLine: '%ws' WStatus: %s",
  5865. ExpandedApp, ExpandedCmd, ErrLabelW32(WStatus));
  5866. __leave;
  5867. }
  5868. WStatus = WAIT_FAILED;
  5869. while (--WaitCount > 0) {
  5870. WStatus = WaitForSingleObject( ProcessInfo.hProcess, THIRTY_SECONDS);
  5871. if (WStatus == WAIT_OBJECT_0) {
  5872. break;
  5873. }
  5874. DPRINT_NOLOCK1(0, "++ Waiting for process complete -- Time remaining: %d seconds\n",
  5875. WaitCount * (THIRTY_SECONDS / 1000));
  5876. }
  5877. } finally {
  5878. //
  5879. // If the above took an exception make sure we drop the lock.
  5880. //
  5881. if (NeedDbgLock) {DebUnLock();}
  5882. }
  5883. if ( !BStatus ) {
  5884. //
  5885. // Create process failed. We're done.
  5886. //
  5887. return WStatus;
  5888. }
  5889. GetExitCodeProcess( ProcessInfo.hProcess, &WStatus );
  5890. if ( BStatus ) {
  5891. DPRINT2(0, "++ CreateProcess( %ws, %ws) succeeds\n", ExpandedApp, ExpandedCmd);
  5892. DPRINT4(0, "++ ProcessInformation = hProcess %08x hThread %08x"
  5893. " ProcessId %08x ThreadId %08x\n",
  5894. ProcessInfo.hProcess, ProcessInfo.hThread, ProcessInfo.dwProcessId,
  5895. ProcessInfo.dwThreadId);
  5896. }
  5897. if (WStatus == STILL_ACTIVE) {
  5898. //
  5899. // Didn't finish. Bag it.
  5900. //
  5901. DPRINT(0, "++ Process failed to complete. Terminating\n");
  5902. WStatus = ERROR_PROCESS_ABORTED;
  5903. if (!TerminateProcess(ProcessInfo.hProcess, WStatus)) {
  5904. WStatus = GetLastError();
  5905. DPRINT_WS(0, "++ Process termination request failed :", WStatus);
  5906. }
  5907. } else {
  5908. DPRINT1(0, "++ Process completed with status: %d\n", WStatus);
  5909. }
  5910. FRS_CLOSE( ProcessInfo.hThread );
  5911. FRS_CLOSE( ProcessInfo.hProcess );
  5912. RETURN:
  5913. //
  5914. // close stdin handle.
  5915. //
  5916. if (CloseStandardIn) {
  5917. FRS_CLOSE(StandardIn);
  5918. }
  5919. return WStatus;
  5920. }
  5921. DWORD
  5922. FrsSetDacl(
  5923. PWCHAR RegName
  5924. )
  5925. /*++
  5926. Routine Description:
  5927. Add backup operators to the dacl for the specified registry key.
  5928. Arguments:
  5929. RegName - registry key (note HKEY_LOCAL_MACHINE becomes MACHINE)
  5930. Return Value:
  5931. WIN32 STATUS
  5932. API-UPDATE ... API-UPDATE ... API-UPDATE ... API-UPDATE ... API-UPDATE ...
  5933. From: Anne Hopkins
  5934. Sent: Tuesday, May 23, 2000 2:21 PM
  5935. To: Windows NT Development Announcements
  5936. Cc: Win32 API Changes Notification
  5937. Subject: RE: NT4 ACL API users should move to Win2K APIs
  5938. Sorry, the spec (and sample excerpt) referenced below is out-of-date
  5939. For Win2k security apis, use:
  5940. - public/sdk/inc/aclapi.h
  5941. - Platform SDK documentation (in MSDN) for reference and dev model
  5942. The reason to move to Win2k security APIs is to get the win2k Inheritance model,
  5943. with automatic propagation for File System and RGY ACLs. (DS does its own ACL
  5944. propagation). These APIs are also easier to use than the NT4 apis.
  5945. From: Anne Hopkins
  5946. Sent: Tuesday, May 23, 2000 10:49 AM
  5947. To: Win32 API Changes Notification
  5948. Subject: NT4 ACL API users should move to Win2K APIs
  5949. If you use old NT 4 or prior ACL APIs, you should plan on updating them
  5950. to win2k APIs as described in the New Win32 Access Control API spec:
  5951. \\cpntserver\areas\Security\Authorization\Specs\access5.doc
  5952. If you can't do this for Whistler, be sure to plan for it in Blackcomb.
  5953. NT 4 API EXAMPLE:
  5954. GetNamedSecurityInfo([in]object, [out]ACL...) // get the ACL from the file
  5955. BuildExplicitAccessWithName([out]ExplicitAccess, [in]TrusteeName, [in]Mask, ) // Build the new Explicit Access
  5956. SetEntriesInAcl([in]ExplicitAccess, [in]OldAcl, [out]NewAcl) // Add the new entry to the ACL
  5957. SetNameSecurityInfo([in]object, [in]NewACL...) // write the ACL back onto the file
  5958. NT 5.0 EXAMPLE:
  5959. GetNamedSecurityInfoEx([in]object, [in] provider, [out] pAccessList) // Get the access list from the file
  5960. BuildExplicitAccessWithName([out]ExplicitAccess, [in]TrusteeName, [in]Mask, ) // Build the access request
  5961. SetEntriesInAccessList([in]ExplicitAccess, [in] OldAccessList, [out]NewAccessList) // Add it to the list
  5962. SetNameSecurityInfoEx([in]object, [in[ NewAccessList) // Write the access list back to the file
  5963. --*/
  5964. {
  5965. #undef DEBSUB
  5966. #define DEBSUB "FrsSetDacl"
  5967. DWORD WStatus;
  5968. PACL OldDACL;
  5969. PACL NewDACL = NULL;
  5970. PSECURITY_DESCRIPTOR SD = NULL;
  5971. PSID SystemSid = NULL;
  5972. PSID AdminsSid = NULL;
  5973. PSID EverySid = NULL;
  5974. PSID BackupSid = NULL;
  5975. EXPLICIT_ACCESS ExplicitAccess[4];
  5976. SID_IDENTIFIER_AUTHORITY SidNtAuthority = SECURITY_NT_AUTHORITY;
  5977. SID_IDENTIFIER_AUTHORITY SidWorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  5978. //
  5979. // No registry key to process
  5980. //
  5981. if (!RegName) {
  5982. return ERROR_INVALID_PARAMETER;
  5983. }
  5984. //
  5985. // Get existing DACL
  5986. //
  5987. WStatus = GetNamedSecurityInfo(RegName,
  5988. SE_REGISTRY_KEY,
  5989. DACL_SECURITY_INFORMATION,
  5990. NULL,
  5991. NULL,
  5992. &OldDACL,
  5993. NULL,
  5994. &SD);
  5995. CLEANUP1_WS(0, "++ ERROR - GetNamedSecurityInfo(%ws);", RegName, WStatus, CLEANUP);
  5996. //
  5997. // Allocate the admins sid
  5998. //
  5999. if (!AllocateAndInitializeSid(&SidNtAuthority,
  6000. 2,
  6001. SECURITY_BUILTIN_DOMAIN_RID,
  6002. DOMAIN_ALIAS_RID_ADMINS,
  6003. 0, 0, 0, 0, 0, 0,
  6004. &AdminsSid)) {
  6005. WStatus = GetLastError();
  6006. CLEANUP_WS(0, "++ WARN - AllocateAndInitializeSid(ADMINS);", WStatus, CLEANUP);
  6007. }
  6008. //
  6009. // Allocate the system sid
  6010. //
  6011. if (!AllocateAndInitializeSid(&SidNtAuthority,
  6012. 1,
  6013. SECURITY_LOCAL_SYSTEM_RID,
  6014. 0, 0, 0, 0, 0, 0, 0,
  6015. &SystemSid)) {
  6016. WStatus = GetLastError();
  6017. CLEANUP_WS(0, "++ WARN - AllocateAndInitializeSid(SYSTEM);", WStatus, CLEANUP);
  6018. }
  6019. //
  6020. // Allocate the backup operators sid
  6021. //
  6022. if (!AllocateAndInitializeSid(&SidNtAuthority,
  6023. 2,
  6024. SECURITY_BUILTIN_DOMAIN_RID,
  6025. DOMAIN_ALIAS_RID_BACKUP_OPS,
  6026. 0, 0, 0, 0, 0, 0,
  6027. &BackupSid)) {
  6028. WStatus = GetLastError();
  6029. CLEANUP_WS(0, "++ WARN - AllocateAndInitializeSid(BACKUP OPS);", WStatus, CLEANUP);
  6030. }
  6031. //
  6032. // Allocate the everyone sid
  6033. //
  6034. if (!AllocateAndInitializeSid(&SidWorldAuthority,
  6035. 1,
  6036. SECURITY_WORLD_RID,
  6037. 0, 0, 0, 0, 0, 0, 0,
  6038. &EverySid)) {
  6039. WStatus = GetLastError();
  6040. CLEANUP_WS(0, "++ WARN - AllocateAndInitializeSid(EVERYONE);", WStatus, CLEANUP);
  6041. }
  6042. //
  6043. // Initialize an EXPLICIT_ACCESS structure to allow access
  6044. //
  6045. ZeroMemory(ExplicitAccess, sizeof(ExplicitAccess));
  6046. //
  6047. // Admins
  6048. //
  6049. ExplicitAccess[0].grfAccessPermissions = GENERIC_ALL;
  6050. ExplicitAccess[0].grfAccessMode = SET_ACCESS;
  6051. ExplicitAccess[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  6052. ExplicitAccess[0].Trustee.pMultipleTrustee = NULL;
  6053. ExplicitAccess[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  6054. ExplicitAccess[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  6055. ExplicitAccess[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  6056. ExplicitAccess[0].Trustee.ptstrName = AdminsSid;
  6057. //
  6058. // System
  6059. //
  6060. ExplicitAccess[1].grfAccessPermissions = GENERIC_ALL;
  6061. ExplicitAccess[1].grfAccessMode = SET_ACCESS;
  6062. ExplicitAccess[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  6063. ExplicitAccess[1].Trustee.pMultipleTrustee = NULL;
  6064. ExplicitAccess[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  6065. ExplicitAccess[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  6066. ExplicitAccess[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  6067. ExplicitAccess[1].Trustee.ptstrName = SystemSid;
  6068. //
  6069. // Backup
  6070. //
  6071. ExplicitAccess[2].grfAccessPermissions = GENERIC_ALL;
  6072. ExplicitAccess[2].grfAccessMode = SET_ACCESS;
  6073. ExplicitAccess[2].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  6074. ExplicitAccess[2].Trustee.pMultipleTrustee = NULL;
  6075. ExplicitAccess[2].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  6076. ExplicitAccess[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  6077. ExplicitAccess[2].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  6078. ExplicitAccess[2].Trustee.ptstrName = BackupSid;
  6079. //
  6080. // Everyone
  6081. //
  6082. ExplicitAccess[3].grfAccessPermissions = GENERIC_READ;
  6083. ExplicitAccess[3].grfAccessMode = SET_ACCESS;
  6084. ExplicitAccess[3].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  6085. ExplicitAccess[3].Trustee.pMultipleTrustee = NULL;
  6086. ExplicitAccess[3].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  6087. ExplicitAccess[3].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  6088. ExplicitAccess[3].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  6089. ExplicitAccess[3].Trustee.ptstrName = EverySid;
  6090. //
  6091. // Create an new ACL by merging the EXPLICIT_ACCESS structure
  6092. // with the existing DACL
  6093. //
  6094. WStatus = SetEntriesInAcl(4, ExplicitAccess, OldDACL, &NewDACL);
  6095. CLEANUP1_WS(0, "++ ERROR - SetEntriesInAcl(%ws);", RegName, WStatus, CLEANUP);
  6096. //
  6097. // attach the new ACL as the object's DACL
  6098. //
  6099. WStatus = SetNamedSecurityInfo(RegName,
  6100. SE_REGISTRY_KEY,
  6101. DACL_SECURITY_INFORMATION,
  6102. NULL,
  6103. NULL,
  6104. NewDACL,
  6105. NULL);
  6106. CLEANUP1_WS(0, "++ ERROR - SetNamedSecurityInfo(%ws);", RegName, WStatus, CLEANUP);
  6107. CLEANUP:
  6108. if (SD) {
  6109. LocalFree((HLOCAL)SD);
  6110. }
  6111. if(NewDACL) {
  6112. LocalFree((HLOCAL)NewDACL);
  6113. }
  6114. if (AdminsSid) {
  6115. FreeSid(AdminsSid);
  6116. }
  6117. if (SystemSid) {
  6118. FreeSid(SystemSid);
  6119. }
  6120. if (BackupSid) {
  6121. FreeSid(BackupSid);
  6122. }
  6123. if (EverySid) {
  6124. FreeSid(EverySid);
  6125. }
  6126. return WStatus;
  6127. }
  6128. #define FRS_FULL_ACCESS ( STANDARD_RIGHTS_ALL | \
  6129. FILE_READ_DATA | \
  6130. FILE_WRITE_DATA | \
  6131. FILE_APPEND_DATA | \
  6132. FILE_READ_EA | \
  6133. FILE_WRITE_EA | \
  6134. FILE_EXECUTE | \
  6135. FILE_READ_ATTRIBUTES | \
  6136. FILE_WRITE_ATTRIBUTES | \
  6137. FILE_CREATE_PIPE_INSTANCE | \
  6138. FILE_LIST_DIRECTORY | \
  6139. FILE_ADD_FILE | \
  6140. FILE_ADD_SUBDIRECTORY | \
  6141. FILE_DELETE_CHILD | \
  6142. FILE_TRAVERSE )
  6143. DWORD
  6144. FrsRestrictAccessToFileOrDirectory(
  6145. PWCHAR Name,
  6146. HANDLE Handle,
  6147. BOOL InheritFromParent,
  6148. BOOL PushToChildren
  6149. )
  6150. /*++
  6151. Routine Description:
  6152. Restrict access to administrators and local system.
  6153. Arguments:
  6154. Name - File or directory name for error messages
  6155. Handle - opened handle for name. If handle is NULL then open 'Name'.
  6156. InheritFromParent - FALSE : Protects the DACL from inheriting ACEs.
  6157. TRUE : Inherits ACEs from the parent whenever applicable.
  6158. PushToChildren - FALSE : No ineritance.
  6159. TRUE : Both containers and noncontainer objects that are
  6160. contained by the primary object inherit the ACE.
  6161. This flag corresponds to the combination of
  6162. the CONTAINER_INHERIT_ACE and OBJECT_INHERIT_ACE flags.
  6163. Return Value:
  6164. WIN32 STATUS
  6165. --*/
  6166. {
  6167. #undef DEBSUB
  6168. #define DEBSUB "FrsRestrictAccessToFileOrDirectory"
  6169. DWORD WStatus = ERROR_SUCCESS;
  6170. HANDLE LocalHandle = NULL;
  6171. SECURITY_INFORMATION SecurityInfo;
  6172. EXPLICIT_ACCESS ExplicitAccess[2];
  6173. PACL NewDACL = NULL;
  6174. SID_IDENTIFIER_AUTHORITY SidNtAuthority = SECURITY_NT_AUTHORITY;
  6175. PSID SystemSid = NULL;
  6176. PSID AdminsSid = NULL;
  6177. //
  6178. // No file or directory handle?
  6179. //
  6180. if (!HANDLE_IS_VALID(Handle)) {
  6181. //
  6182. // Open the directory
  6183. //
  6184. if (Name == NULL) {
  6185. return ERROR_INVALID_PARAMETER;
  6186. }
  6187. LocalHandle = CreateFile(
  6188. Name,
  6189. GENERIC_WRITE | WRITE_DAC | FILE_READ_ATTRIBUTES | FILE_TRAVERSE,
  6190. FILE_SHARE_READ,
  6191. NULL,
  6192. OPEN_EXISTING,
  6193. FILE_FLAG_BACKUP_SEMANTICS,
  6194. NULL);
  6195. if (!HANDLE_IS_VALID(LocalHandle)) {
  6196. return GetLastError();
  6197. }
  6198. Handle = LocalHandle;
  6199. }
  6200. //
  6201. // Allocate the admins sid
  6202. //
  6203. if (!AllocateAndInitializeSid(&SidNtAuthority,
  6204. 2,
  6205. SECURITY_BUILTIN_DOMAIN_RID,
  6206. DOMAIN_ALIAS_RID_ADMINS,
  6207. 0, 0, 0, 0, 0, 0,
  6208. &AdminsSid)) {
  6209. WStatus = GetLastError();
  6210. CLEANUP_WS(0, "++ WARN - AllocateAndInitializeSid(ADMINS);", WStatus, CLEANUP);
  6211. }
  6212. //
  6213. // Allocate the system sid
  6214. //
  6215. if (!AllocateAndInitializeSid(&SidNtAuthority,
  6216. 1,
  6217. SECURITY_LOCAL_SYSTEM_RID,
  6218. 0, 0, 0, 0, 0, 0, 0,
  6219. &SystemSid)) {
  6220. WStatus = GetLastError();
  6221. CLEANUP_WS(0, "++ WARN - AllocateAndInitializeSid(SYSTEM);", WStatus, CLEANUP);
  6222. }
  6223. ZeroMemory(ExplicitAccess, sizeof(ExplicitAccess));
  6224. ExplicitAccess[0].grfAccessPermissions = FRS_FULL_ACCESS;
  6225. ExplicitAccess[0].grfAccessMode = SET_ACCESS;
  6226. if (PushToChildren == TRUE) {
  6227. ExplicitAccess[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  6228. } else {
  6229. ExplicitAccess[0].grfInheritance = NO_INHERITANCE;
  6230. }
  6231. ExplicitAccess[0].Trustee.pMultipleTrustee = NULL;
  6232. ExplicitAccess[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  6233. ExplicitAccess[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  6234. ExplicitAccess[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  6235. ExplicitAccess[0].Trustee.ptstrName = AdminsSid;
  6236. ExplicitAccess[1].grfAccessPermissions = FRS_FULL_ACCESS;
  6237. ExplicitAccess[1].grfAccessMode = SET_ACCESS;
  6238. if (PushToChildren == TRUE) {
  6239. ExplicitAccess[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  6240. } else {
  6241. ExplicitAccess[1].grfInheritance = NO_INHERITANCE;
  6242. }
  6243. ExplicitAccess[1].Trustee.pMultipleTrustee = NULL;
  6244. ExplicitAccess[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  6245. ExplicitAccess[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  6246. ExplicitAccess[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  6247. ExplicitAccess[1].Trustee.ptstrName = SystemSid;
  6248. //
  6249. // Create new ACL.
  6250. //
  6251. WStatus = SetEntriesInAcl(2, ExplicitAccess, NULL, &NewDACL);
  6252. CLEANUP1_WS(0, "++ ERROR - SetEntriesInAcl(%ws);", Name, WStatus, CLEANUP);
  6253. //
  6254. // attach the new ACL as the object's DACL
  6255. // PROTECTED_DACL_SECURITY_INFORMATION - Means don't inherit ACLs from parent
  6256. //
  6257. SecurityInfo = DACL_SECURITY_INFORMATION;
  6258. if (InheritFromParent == TRUE) {
  6259. SecurityInfo |= UNPROTECTED_DACL_SECURITY_INFORMATION;
  6260. } else {
  6261. SecurityInfo |= PROTECTED_DACL_SECURITY_INFORMATION;
  6262. }
  6263. WStatus = SetSecurityInfo(Handle,
  6264. SE_FILE_OBJECT,
  6265. SecurityInfo,
  6266. NULL,
  6267. NULL,
  6268. NewDACL,
  6269. NULL);
  6270. CLEANUP1_WS(0, "++ ERROR - SetSecurityInfo(%ws);", Name, WStatus, CLEANUP);
  6271. CLEANUP:
  6272. if(NewDACL) {
  6273. LocalFree((HLOCAL)NewDACL);
  6274. }
  6275. if (SystemSid) {
  6276. FreeSid(SystemSid);
  6277. }
  6278. if (AdminsSid) {
  6279. FreeSid(AdminsSid);
  6280. }
  6281. FRS_CLOSE(LocalHandle);
  6282. return WStatus;
  6283. }
  6284. ULONG
  6285. FrsProcessBackupRestore(
  6286. VOID
  6287. )
  6288. /*++
  6289. Routine Description:
  6290. Check the registry to see if a restore has transpired.
  6291. If so, delete the database and reset the registry as needed.
  6292. Arguments:
  6293. None.
  6294. Return Value:
  6295. WIN32 STATUS
  6296. --*/
  6297. {
  6298. #undef DEBSUB
  6299. #define DEBSUB "FrsProcessBackupRestore:"
  6300. ULONG WStatus;
  6301. DWORD KeyIdx;
  6302. HKEY hKey = INVALID_HANDLE_VALUE;
  6303. HKEY HBurKey = INVALID_HANDLE_VALUE;
  6304. HKEY HCumuKey = INVALID_HANDLE_VALUE;
  6305. DWORD GblBurFlags;
  6306. DWORD BurSetFlags;
  6307. WCHAR RegBuf[MAX_PATH + 1];
  6308. //
  6309. // Check for backup/restore in progress
  6310. // FRS_CONFIG_SECTION\backup/restore\Stop NtFrs from Starting
  6311. //
  6312. WStatus = CfgRegOpenKey(FKC_BKUP_STOP_SECTION_KEY, NULL, 0, &hKey);
  6313. if (WIN_SUCCESS(WStatus)) {
  6314. DPRINT_WS(0, ":S: WARN - Backup/Restore in progress; retry later.", WStatus);
  6315. EPRINT1(EVENT_FRS_CANNOT_START_BACKUP_RESTORE_IN_PROGRESS, ComputerName);
  6316. FRS_REG_CLOSE(hKey);
  6317. return ERROR_BUSY;
  6318. }
  6319. //
  6320. // Open FRS_CONFIG_SECTION\backup/restore
  6321. // Create it if it doesn't exist and put an ACL on it.
  6322. //
  6323. WStatus = CfgRegOpenKey(FKC_BKUP_SECTION_KEY, NULL, 0, &HBurKey);
  6324. if (!WIN_SUCCESS(WStatus)) {
  6325. WStatus = CfgRegOpenKey(FKC_BKUP_SECTION_KEY, NULL, FRS_RKF_CREATE_KEY, &HBurKey);
  6326. CLEANUP_WS(0, "ERROR - Failed to create backup/restore key.", WStatus, CLEANUP_OK);
  6327. //
  6328. // New key; Ensure backup operators have access.
  6329. //
  6330. WStatus = FrsSetDacl(L"MACHINE\\" FRS_BACKUP_RESTORE_SECTION);
  6331. DPRINT_WS(0, "WARN - FrsSetDacl failed on backup/restore key.", WStatus);
  6332. //
  6333. // Ignore errors
  6334. //
  6335. WStatus = ERROR_SUCCESS;
  6336. }
  6337. //
  6338. // Move the Bur cumulative replica sets to the standard location
  6339. //
  6340. // Open FRS_CONFIG_SECTION\backup/restore\Process at Startup\Cumulative Replica Sets
  6341. // Enumerate the Replica Sets.
  6342. //
  6343. CfgRegOpenKey(FKC_BKUP_MV_CUMSETS_SECTION_KEY, NULL, FRS_RKF_CREATE_KEY, &hKey);
  6344. KeyIdx = 0;
  6345. HCumuKey = 0;
  6346. while (hKey) {
  6347. WStatus = RegEnumKey(hKey, KeyIdx, RegBuf, MAX_PATH + 1);
  6348. if (!WIN_SUCCESS(WStatus)) {
  6349. if (WStatus != ERROR_NO_MORE_ITEMS) {
  6350. DPRINT_WS(0, "WARN - Backup/restore enum.", WStatus);
  6351. }
  6352. break;
  6353. }
  6354. //
  6355. // Create the corresponding key in the standard location.
  6356. //
  6357. // FRS_CONFIG_SECTION\Cumulative Replica Sets\<RegBuf>
  6358. //
  6359. CfgRegOpenKey(FKC_CUMSET_N_BURFLAGS, RegBuf, FRS_RKF_CREATE_KEY, &HCumuKey);
  6360. FRS_REG_CLOSE(HCumuKey);
  6361. //
  6362. // Delete key from Backup/Restore section.
  6363. //
  6364. // FRS_CONFIG_SECTION\backup/restore\Process at Startup\Cumulative Replica Sets\<RegBuf>
  6365. //
  6366. WStatus = RegDeleteKey(hKey, RegBuf);
  6367. if (!WIN_SUCCESS(WStatus)) {
  6368. DPRINT2_WS(0, ":S: WARN - RegDeleteKey(%ws\\%ws);",
  6369. FRS_BACKUP_RESTORE_MV_CUMULATIVE_SETS_SECTION, RegBuf, WStatus);
  6370. ++KeyIdx;
  6371. }
  6372. }
  6373. FRS_REG_CLOSE(hKey);
  6374. //
  6375. // PROCESS Global Backup/Restore BURFLAGS
  6376. //
  6377. // FRS_CONFIG_SECTION\backup/restore\Process at Startup\BurFlags
  6378. //
  6379. WStatus = CfgRegReadDWord(FKC_BKUP_STARTUP_GLOBAL_BURFLAGS, NULL, 0, &GblBurFlags);
  6380. CLEANUP_WS(0, "ERROR - Failed to read Global BurFlags.", WStatus, CLEANUP_OK);
  6381. //
  6382. // Do we need to delete the database?
  6383. //
  6384. if ((GblBurFlags & NTFRSAPI_BUR_FLAGS_RESTORE) &&
  6385. (GblBurFlags & NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES)) {
  6386. DPRINT(4, ":S: Deleting database after full non-auth restore\n");
  6387. WStatus = FrsDeletePath(JetPath, ENUMERATE_DIRECTORY_FLAGS_NONE);
  6388. CLEANUP1_WS(0, ":S: ERROR - FrsDeletePath(%ws);", JetPath, WStatus, CLEANUP);
  6389. DPRINT(4, ":S: Recreating database after full non-auth restore\n");
  6390. //
  6391. // Create the database directories
  6392. //
  6393. if (!CreateDirectory(JetPath, NULL)) {
  6394. WStatus = GetLastError();
  6395. if (!WIN_ALREADY_EXISTS(WStatus)) {
  6396. CLEANUP1_WS(0, ":S: ERROR - CreateDirecotry(%ws);", JetPath, WStatus, CLEANUP);
  6397. }
  6398. }
  6399. if (!CreateDirectory(JetSys, NULL)) {
  6400. WStatus = GetLastError();
  6401. if (!WIN_ALREADY_EXISTS(WStatus)) {
  6402. CLEANUP1_WS(0, ":S: ERROR - CreateDirecotry(%ws);", JetSys, WStatus, CLEANUP);
  6403. }
  6404. }
  6405. if (!CreateDirectory(JetTemp, NULL)) {
  6406. WStatus = GetLastError();
  6407. if (!WIN_ALREADY_EXISTS(WStatus)) {
  6408. CLEANUP1_WS(0, ":S: ERROR - CreateDirecotry(%ws);", JetTemp, WStatus, CLEANUP);
  6409. }
  6410. }
  6411. if (!CreateDirectory(JetLog, NULL)) {
  6412. WStatus = GetLastError();
  6413. if (!WIN_ALREADY_EXISTS(WStatus)) {
  6414. CLEANUP1_WS(0, ":S: ERROR - CreateDirecotry(%ws);", JetLog, WStatus, CLEANUP);
  6415. }
  6416. }
  6417. //
  6418. // Enumerate the sets under "Cumulative Replica Sets" and mark them as not/primary
  6419. // FRS_CONFIG_SECTION\Cumulative Replica Sets
  6420. //
  6421. CfgRegOpenKey(FKC_CUMSET_SECTION_KEY, NULL, FRS_RKF_CREATE_KEY, &hKey);
  6422. CLEANUP_WS(0, "ERROR - Failed to open Cumulative Replica Sets.", WStatus, CLEANUP);
  6423. //
  6424. // Enumerate the Replica Sets
  6425. //
  6426. KeyIdx = 0;
  6427. while (TRUE) {
  6428. WStatus = RegEnumKey(hKey, KeyIdx, RegBuf, MAX_PATH + 1);
  6429. if (WStatus == ERROR_NO_MORE_ITEMS) {
  6430. break;
  6431. }
  6432. CLEANUP_WS(0, "WARN - Cumulative Replica Sets enum.", WStatus, CLEANUP);
  6433. //
  6434. // Save type of restore in BurFlags for this replica set.
  6435. // FRS_CONFIG_SECTION\Cumulative Replica Sets\<RegBuf>\BurFlags
  6436. //
  6437. WStatus = CfgRegWriteDWord(FKC_CUMSET_N_BURFLAGS, RegBuf, 0, GblBurFlags);
  6438. DPRINT_WS(0, "WARN - Cumulative Replica Sets BurFlags Write.", WStatus);
  6439. ++KeyIdx;
  6440. }
  6441. FRS_REG_CLOSE(hKey);
  6442. } // End of Delete Data Base
  6443. //
  6444. // Move individual BurFlags into Cumulative Replica Sets
  6445. // Open FRS_CONFIG_SECTION\backup/restore\Process at Startup\Replica Sets
  6446. // Enumerate the Replica Sets
  6447. //
  6448. CfgRegOpenKey(FKC_BKUP_MV_SETS_SECTION_KEY, NULL, FRS_RKF_CREATE_KEY, &hKey);
  6449. KeyIdx = 0;
  6450. while (hKey) {
  6451. WStatus = RegEnumKey(hKey, KeyIdx, RegBuf, MAX_PATH + 1);
  6452. if (!WIN_SUCCESS(WStatus)) {
  6453. if (WStatus != ERROR_NO_MORE_ITEMS) {
  6454. DPRINT_WS(0, "WARN - Backup/restore enum.", WStatus);
  6455. }
  6456. break;
  6457. }
  6458. //
  6459. // Get BurFlags
  6460. // FRS_CONFIG_SECTION\backup/restore\Process at Startup\Replica Sets\<RegBuf>\BurFlags
  6461. //
  6462. WStatus = CfgRegReadDWord(FKC_BKUP_STARTUP_SET_N_BURFLAGS,
  6463. RegBuf,
  6464. FRS_RKF_CREATE_KEY,
  6465. &BurSetFlags);
  6466. if (WIN_SUCCESS(WStatus)) {
  6467. //
  6468. // Write BurFlags
  6469. // FRS_CONFIG_SECTION\Cumulative Replica Sets\<RegBuf>\BurFlags
  6470. //
  6471. CfgRegWriteDWord(FKC_CUMSET_N_BURFLAGS,
  6472. RegBuf,
  6473. FRS_RKF_CREATE_KEY,
  6474. BurSetFlags);
  6475. }
  6476. //
  6477. // Delete source data key.
  6478. // FRS_CONFIG_SECTION\backup/restore\Process at Startup\Replica Sets\<RegBuf>
  6479. //
  6480. WStatus = RegDeleteKey(hKey, RegBuf);
  6481. if (!WIN_SUCCESS(WStatus)) {
  6482. DPRINT2_WS(0, ":S: WARN - RegDeleteKey(%ws\\%ws);",
  6483. FRS_BACKUP_RESTORE_MV_SETS_SECTION, RegBuf, WStatus);
  6484. ++KeyIdx;
  6485. }
  6486. }
  6487. FRS_REG_CLOSE(hKey);
  6488. //
  6489. // Set backup/restore flags to 0
  6490. //
  6491. // FRS_CONFIG_SECTION\backup/restore\Process at Startup\BurFlags
  6492. //
  6493. GblBurFlags = NTFRSAPI_BUR_FLAGS_NONE;
  6494. WStatus = CfgRegWriteDWord(FKC_BKUP_STARTUP_GLOBAL_BURFLAGS, NULL, 0, GblBurFlags);
  6495. CLEANUP_WS(0, "ERROR - Failed to clear Global BurFlags.", WStatus, CLEANUP);
  6496. goto CLEANUP;
  6497. CLEANUP_OK:
  6498. WStatus = ERROR_SUCCESS;
  6499. CLEANUP:
  6500. FRS_REG_CLOSE(HBurKey);
  6501. return WStatus;
  6502. }
  6503. #define DEFAULT_MULTI_STRING_WCHARS (4) // at least 8
  6504. VOID
  6505. FrsCatToMultiString(
  6506. IN PWCHAR CatStr,
  6507. IN OUT DWORD *IOSize,
  6508. IN OUT DWORD *IOIdx,
  6509. IN OUT PWCHAR *IOStr
  6510. )
  6511. /*++
  6512. Routine Description:
  6513. Add a string + Catenation (if present) to the multi-string value
  6514. Arguments:
  6515. CatStr - string to concatenate
  6516. IOSize - Total size in wide chars of WStr
  6517. IOIdx - Current index to terminating \0 following \0 of last string
  6518. IOStr - Current string
  6519. Return Value:
  6520. None.
  6521. --*/
  6522. {
  6523. #undef DEBSUB
  6524. #define DEBSUB "FrsCatToMultiString:"
  6525. DWORD NewSize;
  6526. DWORD CatSize;
  6527. PWCHAR Str;
  6528. //
  6529. // NOP
  6530. //
  6531. if (!CatStr) {
  6532. return;
  6533. }
  6534. //
  6535. // allocate initial buffer
  6536. //
  6537. if (!*IOStr) {
  6538. *IOSize = DEFAULT_MULTI_STRING_WCHARS;
  6539. *IOStr = FrsAlloc(*IOSize * sizeof(WCHAR));
  6540. (*IOStr)[0] = L'\0';
  6541. (*IOStr)[1] = L'\0';
  6542. *IOIdx = 1;
  6543. }
  6544. //
  6545. // Extend buffer when needed (note that CatStr overwrites first
  6546. // \0 in the terminating \0\0. Hence, CatSize - 1 + 2 == CatSize + 1
  6547. //
  6548. CatSize = wcslen(CatStr);
  6549. while ((CatSize + 1 + *IOIdx) >= *IOSize) {
  6550. NewSize = *IOSize << 1;
  6551. Str = FrsAlloc(NewSize * sizeof(WCHAR));
  6552. CopyMemory(Str, *IOStr, *IOSize * sizeof(WCHAR));
  6553. FrsFree(*IOStr);
  6554. *IOStr = Str;
  6555. *IOSize = NewSize;
  6556. }
  6557. //
  6558. // Concatenate CatStr
  6559. //
  6560. *IOIdx -= 1;
  6561. CopyMemory(&(*IOStr)[*IOIdx], CatStr, CatSize * sizeof(WCHAR));
  6562. *IOIdx += CatSize;
  6563. //
  6564. // Append \0\0 and leave the index addressing the second \0.
  6565. //
  6566. (*IOStr)[*IOIdx] = L'\0';
  6567. *IOIdx += 1;
  6568. (*IOStr)[*IOIdx] = L'\0';
  6569. FRS_ASSERT(*IOIdx < *IOSize);
  6570. }
  6571. VOID
  6572. FrsAddToMultiString(
  6573. IN PWCHAR AddStr,
  6574. IN OUT DWORD *IOSize,
  6575. IN OUT DWORD *IOIdx,
  6576. IN OUT PWCHAR *IOStr
  6577. )
  6578. /*++
  6579. Routine Description:
  6580. Add a string + Catenation (if present) to the multi-string value
  6581. Arguments:
  6582. AddStr - string to add
  6583. IOSize - Total size in wide chars of WStr
  6584. IOIdx - Current index to terminating \0 following \0 of last string
  6585. IOStr - Current string
  6586. Return Value:
  6587. None.
  6588. --*/
  6589. {
  6590. #undef DEBSUB
  6591. #define DEBSUB "FrsAddToMultiString:"
  6592. DWORD NewSize;
  6593. DWORD StrSize;
  6594. PWCHAR Str;
  6595. //
  6596. // NOP
  6597. //
  6598. if (!AddStr) {
  6599. return;
  6600. }
  6601. //
  6602. // allocate initial buffer
  6603. //
  6604. if (!*IOStr) {
  6605. *IOSize = DEFAULT_MULTI_STRING_WCHARS;
  6606. *IOStr = FrsAlloc(*IOSize * sizeof(WCHAR));
  6607. *IOIdx = 0;
  6608. }
  6609. //
  6610. // Extend buffer when needed
  6611. //
  6612. StrSize = wcslen(AddStr);
  6613. while ((StrSize + 2 + *IOIdx) >= *IOSize) {
  6614. NewSize = *IOSize << 1;
  6615. Str = FrsAlloc(NewSize * sizeof(WCHAR));
  6616. CopyMemory(Str, *IOStr, *IOSize * sizeof(WCHAR));
  6617. FrsFree(*IOStr);
  6618. *IOStr = Str;
  6619. *IOSize = NewSize;
  6620. }
  6621. //
  6622. // Append AddStr
  6623. //
  6624. CopyMemory(&(*IOStr)[*IOIdx], AddStr, StrSize * sizeof(WCHAR));
  6625. *IOIdx += StrSize;
  6626. //
  6627. // Append \0\0 and leave the index addressing the second \0.
  6628. //
  6629. (*IOStr)[*IOIdx] = L'\0';
  6630. *IOIdx += 1;
  6631. (*IOStr)[*IOIdx] = L'\0';
  6632. FRS_ASSERT(*IOIdx < *IOSize);
  6633. }
  6634. DWORD
  6635. UtilTranslateName(
  6636. IN PWCHAR FromName,
  6637. IN EXTENDED_NAME_FORMAT FromNameFormat,
  6638. IN EXTENDED_NAME_FORMAT ToNameFormat,
  6639. OUT PWCHAR *OutToName
  6640. )
  6641. /*++
  6642. Routine Description:
  6643. Translate one name format into another
  6644. Arguments:
  6645. FromName - Input, or source, name
  6646. FromNameFormat - Format of FromName
  6647. ToNameFormat - Desired format of *OutToName,
  6648. OutToName - converted string; free with FrsFree()
  6649. Return Value:
  6650. WIN32 Status
  6651. --*/
  6652. {
  6653. #undef DEBSUB
  6654. #define DEBSUB "UtilTranslateName:"
  6655. DWORD WStatus;
  6656. WCHAR ToNameBuffer[MAX_PATH + 1];
  6657. DWORD ToNameSize = MAX_PATH + 1;
  6658. PWCHAR ToName = ToNameBuffer;
  6659. *OutToName = NULL;
  6660. if (!FromName) {
  6661. return ERROR_INVALID_PARAMETER;
  6662. }
  6663. //
  6664. // Name -> Name (using stack buffer)
  6665. //
  6666. if (!TranslateName(FromName, FromNameFormat, ToNameFormat, ToName, &ToNameSize)) {
  6667. WStatus = GetLastError();
  6668. } else {
  6669. WStatus = ERROR_SUCCESS;
  6670. }
  6671. //
  6672. // Name -> Name (using FrsAlloc'ed buffer)
  6673. //
  6674. while (WIN_BUF_TOO_SMALL(WStatus)) {
  6675. ToName = FrsAlloc((ToNameSize + 1) * sizeof(WCHAR));
  6676. if (!TranslateName(FromName, FromNameFormat, ToNameFormat, ToName, &ToNameSize)) {
  6677. WStatus = GetLastError();
  6678. ToName = FrsFree(ToName);
  6679. } else {
  6680. WStatus = ERROR_SUCCESS;
  6681. }
  6682. }
  6683. if (!WIN_SUCCESS(WStatus)) {
  6684. DPRINT1_WS(4, "++ WARN - TranslateName(%ws);", FromName, WStatus);
  6685. goto CLEANUP;
  6686. }
  6687. DPRINT2(5, "++ From -> To: %ws -> %ws\n",
  6688. FromName, ToName);
  6689. *OutToName = FrsWcsDup(ToName);
  6690. CLEANUP:
  6691. if (ToName != ToNameBuffer) {
  6692. FrsFree(ToName);
  6693. }
  6694. return WStatus;
  6695. }
  6696. DWORD
  6697. UtilConvertDnToStringSid(
  6698. IN PWCHAR Dn,
  6699. OUT PWCHAR *OutStringSid
  6700. )
  6701. /*++
  6702. Routine Description:
  6703. Retries GetTokenInformation() with larger buffers.
  6704. Arguments:
  6705. Dn - Dn of computer or user object
  6706. OutStringSid - String'ized sid. Free with FrsFree();
  6707. Return Value:
  6708. WIN32 Status
  6709. --*/
  6710. {
  6711. #undef DEBSUB
  6712. #define DEBSUB "UtilConvertDnToStringSid:"
  6713. DWORD WStatus;
  6714. WCHAR SamCompatibleBuffer[MAX_PATH + 1];
  6715. DWORD SamCompatibleSize = MAX_PATH + 1;
  6716. PWCHAR SamCompatible = SamCompatibleBuffer;
  6717. if (OutStringSid) {
  6718. *OutStringSid = NULL;
  6719. }
  6720. if (!Dn) {
  6721. return ERROR_INVALID_PARAMETER;
  6722. }
  6723. //
  6724. // Dn -> Account (using stack buffer)
  6725. //
  6726. if (!TranslateName(Dn,
  6727. NameFullyQualifiedDN,
  6728. NameSamCompatible,
  6729. SamCompatible,
  6730. &SamCompatibleSize)) {
  6731. WStatus = GetLastError();
  6732. } else {
  6733. WStatus = ERROR_SUCCESS;
  6734. }
  6735. //
  6736. // Dn -> Account (using FrsAlloc'ed buffer)
  6737. //
  6738. while (WIN_BUF_TOO_SMALL(WStatus)) {
  6739. SamCompatible = FrsAlloc((SamCompatibleSize + 1) * sizeof(WCHAR));
  6740. if (!TranslateName(Dn,
  6741. NameFullyQualifiedDN,
  6742. NameSamCompatible,
  6743. SamCompatible,
  6744. &SamCompatibleSize)) {
  6745. WStatus = GetLastError();
  6746. SamCompatible = FrsFree(SamCompatible);
  6747. } else {
  6748. WStatus = ERROR_SUCCESS;
  6749. }
  6750. }
  6751. CLEANUP1_WS(4, "++ WARN - TranslateName(%ws);", Dn, WStatus, CLEANUP);
  6752. DPRINT2(5, "++ Dn -> Account: %ws -> %ws\n", Dn, SamCompatible);
  6753. CLEANUP:
  6754. if (SamCompatible != SamCompatibleBuffer) {
  6755. FrsFree(SamCompatible);
  6756. }
  6757. return WStatus;
  6758. }
  6759. DWORD
  6760. UtilGetTokenInformation(
  6761. IN HANDLE TokenHandle,
  6762. IN TOKEN_INFORMATION_CLASS TokenInformationClass,
  6763. IN DWORD InitialTokenBufSize,
  6764. OUT DWORD *OutTokenBufSize,
  6765. OUT PVOID *OutTokenBuf
  6766. )
  6767. /*++
  6768. Routine Description:
  6769. Retries GetTokenInformation() with larger buffers.
  6770. Arguments:
  6771. TokenHandle - From OpenCurrentProcess/Thread()
  6772. TokenInformationClass - E.g., TokenUser
  6773. InitialTokenBufSize - Initial buffer size; 0 = default
  6774. OutTokenBufSize - Resultant returned buf size
  6775. OutTokenBuf - free with with FrsFree()
  6776. Return Value:
  6777. OutTokenBufSize - Size of returned info (NOT THE BUFFER SIZE!)
  6778. OutTokenBuf - info of type TokenInformationClass. Free with FrsFree().
  6779. --*/
  6780. {
  6781. #undef DEBSUB
  6782. #define DEBSUB "UtilGetTokenInformation:"
  6783. DWORD WStatus;
  6784. *OutTokenBuf = NULL;
  6785. *OutTokenBufSize = 0;
  6786. //
  6787. // Check inputs
  6788. //
  6789. if (!HANDLE_IS_VALID(TokenHandle)) {
  6790. return ERROR_INVALID_PARAMETER;
  6791. }
  6792. if (InitialTokenBufSize == 0 ||
  6793. InitialTokenBufSize > (1024 * 1024)) {
  6794. InitialTokenBufSize = 1024;
  6795. }
  6796. //
  6797. // Retry if buffer is too small
  6798. //
  6799. *OutTokenBufSize = InitialTokenBufSize;
  6800. AGAIN:
  6801. //
  6802. // Need to check if *OutTokenBufSize == 0 as FrsAlloc asserts if called with 0 as the first parameter (prefix fix).
  6803. //
  6804. *OutTokenBuf = (*OutTokenBufSize == 0)? NULL : FrsAlloc(*OutTokenBufSize);
  6805. WStatus = ERROR_SUCCESS;
  6806. if (!GetTokenInformation(TokenHandle,
  6807. TokenInformationClass,
  6808. *OutTokenBuf,
  6809. *OutTokenBufSize,
  6810. OutTokenBufSize)) {
  6811. WStatus = GetLastError();
  6812. DPRINT2_WS(4, "++ WARN - GetTokenInformation(Info %d, Size %d);",
  6813. TokenInformationClass, *OutTokenBufSize, WStatus);
  6814. *OutTokenBuf = FrsFree(*OutTokenBuf);
  6815. if (WIN_BUF_TOO_SMALL(WStatus)) {
  6816. goto AGAIN;
  6817. }
  6818. }
  6819. return WStatus;
  6820. }
  6821. VOID
  6822. UtilPrintUser(
  6823. IN DWORD Severity
  6824. )
  6825. /*++
  6826. Routine Description:
  6827. Print info about the user (privs, user sid).
  6828. Arguments:
  6829. Severity - for dprint
  6830. Return Value:
  6831. None.
  6832. --*/
  6833. {
  6834. #undef DEBSUB
  6835. #define DEBSUB "UtilPrintUser:"
  6836. DWORD WStatus;
  6837. DWORD TokenBufSize;
  6838. PVOID TokenBuf = NULL;
  6839. HANDLE TokenHandle = NULL;
  6840. PWCHAR SidStr;
  6841. DWORD i;
  6842. TOKEN_PRIVILEGES *Tp;
  6843. TOKEN_USER *Tu;
  6844. DWORD PrivLen;
  6845. WCHAR PrivName[MAX_PATH + 1];
  6846. //
  6847. // For this process/thread
  6848. //
  6849. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &TokenHandle)) {
  6850. WStatus = GetLastError();
  6851. CLEANUP_WS(0, "++ WARN - OpenProcessToken();", WStatus, CLEANUP);
  6852. }
  6853. //
  6854. // Get the Token privileges from the access token for this thread or process
  6855. //
  6856. WStatus = UtilGetTokenInformation(TokenHandle,
  6857. TokenPrivileges,
  6858. 0,
  6859. &TokenBufSize,
  6860. &TokenBuf);
  6861. CLEANUP_WS(4, "++ UtilGetTokenInformation(TokenPrivileges);", WStatus, USER);
  6862. //
  6863. // Print token privileges
  6864. //
  6865. Tp = (TOKEN_PRIVILEGES *)TokenBuf;
  6866. for (i = 0; i < Tp->PrivilegeCount; ++i) {
  6867. PrivLen = MAX_PATH + 1;
  6868. if (!LookupPrivilegeName(NULL, &Tp->Privileges[i].Luid, PrivName, &PrivLen)) {
  6869. DPRINT_WS(0, "++ WARN - LookupPrivilegeName();", WStatus);
  6870. continue;
  6871. }
  6872. DPRINT5(Severity, "++ Priv %2d is %ws :%s:%s:%s:\n",
  6873. i,
  6874. PrivName,
  6875. (Tp->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) ? "Enabled by default" : "",
  6876. (Tp->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) ? "Enabled" : "",
  6877. (Tp->Privileges[i].Attributes & SE_PRIVILEGE_USED_FOR_ACCESS) ? "Used" : "");
  6878. }
  6879. TokenBuf = FrsFree(TokenBuf);
  6880. //
  6881. // Get the TokenUser from the access token for this process
  6882. //
  6883. USER:
  6884. WStatus = UtilGetTokenInformation(TokenHandle,
  6885. TokenUser,
  6886. 0,
  6887. &TokenBufSize,
  6888. &TokenBuf);
  6889. CLEANUP_WS(4, "++ UtilGetTokenInformation(TokenUser);", WStatus, CLEANUP);
  6890. Tu = (TOKEN_USER *)TokenBuf;
  6891. if (!ConvertSidToStringSid(Tu->User.Sid, &SidStr)) {
  6892. WStatus = GetLastError();
  6893. DPRINT_WS(4, "++ WARN - ConvertSidToStringSid();", WStatus);
  6894. } else {
  6895. DPRINT1(Severity, "++ User Sid: %ws\n", SidStr);
  6896. LocalFree(SidStr);
  6897. }
  6898. TokenBuf = FrsFree(TokenBuf);
  6899. CLEANUP:
  6900. FRS_CLOSE(TokenHandle);
  6901. FrsFree(TokenBuf);
  6902. }
  6903. DWORD
  6904. UtilRpcServerHandleToAuthSidString(
  6905. IN handle_t ServerHandle,
  6906. IN PWCHAR AuthClient,
  6907. OUT PWCHAR *AuthSid
  6908. )
  6909. /*++
  6910. Routine Description:
  6911. Extract a the string'ized user sid from the rpc server handle
  6912. by impersonating the caller and extracting the token info.
  6913. Arguments:
  6914. ServerHandle - from the rpc serve call
  6915. AuthClient - From the rpc server handle; for messages
  6916. ClientSid - stringized user sid; free with FrsFree()
  6917. Return Value:
  6918. Win32 Status.
  6919. --*/
  6920. {
  6921. #undef DEBSUB
  6922. #define DEBSUB "UtilRpcServerHandleToAuthSidString:"
  6923. DWORD WStatus;
  6924. DWORD WStatus2;
  6925. DWORD TokenBufSize;
  6926. PWCHAR SidStr;
  6927. TOKEN_USER *Tu;
  6928. PVOID TokenBuf = NULL;
  6929. BOOL Impersonated = FALSE;
  6930. HANDLE TokenHandle = NULL;
  6931. //
  6932. // Initialize return value
  6933. //
  6934. *AuthSid = NULL;
  6935. //
  6936. // Impersonate the rpc caller
  6937. //
  6938. WStatus = RpcImpersonateClient(ServerHandle);
  6939. CLEANUP1_WS(0, "++ ERROR - RpcImpersonateClient(%ws);", AuthClient, WStatus, CLEANUP);
  6940. Impersonated = TRUE;
  6941. //
  6942. // Open the impersonated thread token
  6943. //
  6944. if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &TokenHandle)) {
  6945. WStatus = GetLastError();
  6946. CLEANUP_WS(0, "++ WARN - OpenProcessToken();", WStatus, CLEANUP);
  6947. }
  6948. //
  6949. // Get the user sid
  6950. //
  6951. WStatus = UtilGetTokenInformation(TokenHandle,
  6952. TokenUser,
  6953. 0,
  6954. &TokenBufSize,
  6955. &TokenBuf);
  6956. CLEANUP_WS(4, "++ UtilGetTokenInformation(TokenUser);", WStatus, CLEANUP);
  6957. //
  6958. // Convert the sid into a string
  6959. //
  6960. Tu = (TOKEN_USER *)TokenBuf;
  6961. if (!ConvertSidToStringSid(Tu->User.Sid, &SidStr)) {
  6962. WStatus = GetLastError();
  6963. CLEANUP_WS(4, "++ WARN - ConvertSidToStringSid();", WStatus, CLEANUP);
  6964. } else {
  6965. DPRINT1(5, "++ Client Sid is %ws\n", SidStr);
  6966. *AuthSid = FrsWcsDup(SidStr);
  6967. LocalFree(SidStr);
  6968. }
  6969. //
  6970. // Done
  6971. //
  6972. WStatus = ERROR_SUCCESS;
  6973. CLEANUP:
  6974. TokenBuf = FrsFree(TokenBuf);
  6975. FRS_CLOSE(TokenHandle);
  6976. if (Impersonated) {
  6977. WStatus2 = RpcRevertToSelf();
  6978. DPRINT1_WS(0, "++ ERROR IGNORED - RpcRevertToSelf(%ws);", AuthClient, WStatus2);
  6979. }
  6980. return WStatus;
  6981. }
  6982. BOOL
  6983. FrsRemoveDisabledPrivileges (
  6984. VOID
  6985. )
  6986. /*++
  6987. Routine Description:
  6988. Remove all disabled privileges from our token.
  6989. NOTE: THis capability is not available in WIN2K.
  6990. Arguments:
  6991. None.
  6992. Return Value:
  6993. TRUE if all disabled privileges were successfully removed.
  6994. --*/
  6995. {
  6996. #undef DEBSUB
  6997. #define DEBSUB "FrsRemoveDisabledPrivileges:"
  6998. NTSTATUS NtStatus = STATUS_SUCCESS;
  6999. DWORD WStatus = ERROR_SUCCESS;
  7000. DWORD BufferSize = 0;
  7001. HANDLE hProcessToken = INVALID_HANDLE_VALUE;
  7002. PTOKEN_PRIVILEGES pTokenPrivs = NULL;
  7003. DWORD i = 0;
  7004. #define PRIVILEGE_NAME_LENGTH MAX_PATH
  7005. WCHAR PrivilegeName[PRIVILEGE_NAME_LENGTH];
  7006. DWORD PrivilegeNameLength = PRIVILEGE_NAME_LENGTH;
  7007. //
  7008. // Open the token.
  7009. //
  7010. NtStatus = NtOpenProcessToken(NtCurrentProcess(),
  7011. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  7012. &hProcessToken);
  7013. if (!NT_SUCCESS(NtStatus))
  7014. {
  7015. DPRINT1(0, "Unable to open process token. NtStatus = 0x%08x\n", NtStatus);
  7016. WStatus = FrsTranslateNtError(NtStatus, FALSE);
  7017. goto Cleanup;
  7018. }
  7019. //
  7020. // Read the priveleges.
  7021. //
  7022. //
  7023. // First find out the buffer size we need.
  7024. //
  7025. GetTokenInformation(hProcessToken,
  7026. TokenPrivileges,
  7027. NULL,
  7028. 0,
  7029. &BufferSize
  7030. );
  7031. //
  7032. // Allocate the buffer and get the info
  7033. //
  7034. pTokenPrivs = FrsAlloc(BufferSize);
  7035. if(!GetTokenInformation(hProcessToken,
  7036. TokenPrivileges,
  7037. pTokenPrivs,
  7038. BufferSize,
  7039. &BufferSize
  7040. )) {
  7041. WStatus = GetLastError();
  7042. DPRINT1(0, "Unable to get token information. WStatus = %d\n", WStatus);
  7043. goto Cleanup;
  7044. }
  7045. //
  7046. // Find all non-enabled privileges and mark them for removal
  7047. //
  7048. for(i=0; i < pTokenPrivs->PrivilegeCount; i++) {
  7049. if(!(pTokenPrivs->Privileges[i].Attributes &
  7050. SE_PRIVILEGE_ENABLED)) {
  7051. pTokenPrivs->Privileges[i].Attributes = SE_PRIVILEGE_REMOVED;
  7052. if(!LookupPrivilegeName(NULL,
  7053. &(pTokenPrivs->Privileges[i].Luid),
  7054. PrivilegeName,
  7055. &PrivilegeNameLength
  7056. )) {
  7057. DPRINT2(0, "Marking privilege %d-%d for removal.\n",
  7058. pTokenPrivs->Privileges[i].Luid.HighPart,
  7059. pTokenPrivs->Privileges[i].Luid.LowPart
  7060. );
  7061. } else {
  7062. DPRINT1(0, "Marking privilege %ws for removal.\n",
  7063. PrivilegeName);
  7064. }
  7065. }
  7066. }
  7067. //
  7068. // Now, actually remove the privileges
  7069. //
  7070. if(!AdjustTokenPrivileges(hProcessToken,
  7071. FALSE,
  7072. pTokenPrivs,
  7073. BufferSize,
  7074. NULL,
  7075. NULL)) {
  7076. WStatus = GetLastError();
  7077. DPRINT1(0, "Unable to adjust token privileges. WStatus = %d\n", WStatus);
  7078. goto Cleanup;
  7079. }
  7080. DPRINT(0, "Privileges successfully updated.\n");
  7081. Cleanup:
  7082. FRS_CLOSE(hProcessToken);
  7083. FrsFree(pTokenPrivs);
  7084. return WIN_SUCCESS(WStatus);
  7085. }
  7086. BOOL
  7087. FrsSetupPrivileges (
  7088. VOID
  7089. )
  7090. /*++
  7091. Routine Description:
  7092. Enable the privileges we need to replicate files.
  7093. Arguments:
  7094. None.
  7095. Return Value:
  7096. TRUE if got all privileges.
  7097. --*/
  7098. {
  7099. #undef DEBSUB
  7100. #define DEBSUB "FrsSetupPrivileges:"
  7101. NTSTATUS Status;
  7102. //
  7103. // Get the SE_SECURITY_PRIVILEGE to read/write SACLs on files.
  7104. //
  7105. Status = SetupOnePrivilege(SE_SECURITY_PRIVILEGE, "Security");
  7106. if (!NT_SUCCESS(Status)) {
  7107. DPRINT_WS(0, "ERROR - Failed to get Security privilege.",
  7108. FrsSetLastNTError(Status));
  7109. return FALSE;
  7110. }
  7111. //
  7112. // Get backup/restore privilege to bypass ACL checks.
  7113. //
  7114. Status = SetupOnePrivilege(SE_BACKUP_PRIVILEGE, "Backup");
  7115. if (!NT_SUCCESS(Status)) {
  7116. DPRINT_WS(0, "ERROR - Failed to get Backup privilege.",
  7117. FrsSetLastNTError(Status));
  7118. return FALSE;
  7119. }
  7120. Status = SetupOnePrivilege(SE_RESTORE_PRIVILEGE, "Restore");
  7121. if (!NT_SUCCESS(Status)) {
  7122. DPRINT_WS(0, "ERROR - Failed to get Restore privilege.",
  7123. FrsSetLastNTError(Status));
  7124. return FALSE;
  7125. }
  7126. return FrsRemoveDisabledPrivileges();
  7127. #if 0
  7128. //
  7129. // Set priority privilege in order to raise our base priority.
  7130. //
  7131. SetupOnePrivilege(SE_INC_BASE_PRIORITY_PRIVILEGE,
  7132. "Increase base priority");
  7133. //
  7134. // Set quota privilege in order to accommodate large profile buffers.
  7135. //
  7136. SetupOnePrivilege(SE_INCREASE_QUOTA_PRIVILEGE,
  7137. "Increase quotas");
  7138. #endif
  7139. }
  7140. DWORD
  7141. FrsMarkHandle(
  7142. IN HANDLE VolumeHandle,
  7143. IN HANDLE Handle
  7144. )
  7145. /*++
  7146. Routine Description:
  7147. Mark the handle as so that the journal record records
  7148. a flag that indicates "replication service is altering the file; ignore".
  7149. Arguments:
  7150. VolumeHandle - Used to check access
  7151. Handle - Handle to mark
  7152. Return Value:
  7153. Win32 Status
  7154. --*/
  7155. {
  7156. #undef DEBSUB
  7157. #define DEBSUB "FrsMarkHandle:"
  7158. DWORD WStatus;
  7159. DWORD BytesReturned;
  7160. MARK_HANDLE_INFO MarkHandleInfo;
  7161. //
  7162. // Mark the handle as one of ours so that the journal thread
  7163. // knows to ignore the usn records.
  7164. //
  7165. MarkHandleInfo.UsnSourceInfo = USN_SOURCE_REPLICATION_MANAGEMENT;
  7166. MarkHandleInfo.VolumeHandle = VolumeHandle;
  7167. MarkHandleInfo.HandleInfo = 0;
  7168. if (!DeviceIoControl(Handle,
  7169. FSCTL_MARK_HANDLE,
  7170. (LPVOID)&MarkHandleInfo,
  7171. (DWORD)sizeof(MarkHandleInfo),
  7172. NULL,
  7173. 0,
  7174. (LPDWORD)&BytesReturned,
  7175. NULL)) {
  7176. WStatus = GetLastError();
  7177. DPRINT_WS(0, "++ WARN - DeviceIoControl(MarkHandle);", WStatus);
  7178. } else {
  7179. WStatus = ERROR_SUCCESS;
  7180. //DPRINT(0, "++ TEMP - DeviceIoControl(MarkHandle) Success\n");
  7181. }
  7182. return WStatus;
  7183. }
  7184. VOID
  7185. FrsCreateJoinGuid(
  7186. OUT GUID *OutGuid
  7187. )
  7188. /*++
  7189. Routine Description:
  7190. Generate a random session id that is sizeof(GUID) in length.
  7191. The session id must be very random becuase it is used to
  7192. authenticate packets from our partners after a join.
  7193. The join was authenticated using impersonation.
  7194. Arguments:
  7195. Guid - Address of a guid
  7196. Return Value:
  7197. None.
  7198. --*/
  7199. {
  7200. #undef DEBSUB
  7201. #define DEBSUB "FrsCreateJoinGuid:"
  7202. DWORD WStatus;
  7203. HCRYPTPROV hProv;
  7204. //
  7205. // Acquire the context.
  7206. // Consider caching the context if this function is called often.
  7207. //
  7208. if (!CryptAcquireContext(&hProv,
  7209. NULL,
  7210. NULL,
  7211. PROV_RSA_FULL,
  7212. CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
  7213. WStatus = GetLastError();
  7214. DPRINT_WS(0, "++ WARN - CryptAcquireContext();", WStatus);
  7215. //
  7216. // Can't use CryptGenRandom(); try using a guid
  7217. //
  7218. FrsUuidCreate(OutGuid);
  7219. } else {
  7220. //
  7221. // Generate a random number
  7222. //
  7223. if (!CryptGenRandom(hProv, sizeof(GUID), (PBYTE)OutGuid)) {
  7224. WStatus = GetLastError();
  7225. DPRINT_WS(0, "++ WARN - CryptGenRandom();", WStatus);
  7226. //
  7227. // Can't use CryptGenRandom(); try using a guid
  7228. //
  7229. FrsUuidCreate(OutGuid);
  7230. } else {
  7231. DPRINT(5, "++ Created join guid\n");
  7232. }
  7233. //
  7234. // Release the context
  7235. //
  7236. if (!CryptReleaseContext(hProv, 0)) {
  7237. WStatus = GetLastError();
  7238. DPRINT_WS(0, "++ ERROR - CryptReleaseContext();", WStatus);
  7239. }
  7240. }
  7241. }
  7242. VOID
  7243. FrsFlagsToStr(
  7244. IN DWORD Flags,
  7245. IN PFLAG_NAME_TABLE NameTable,
  7246. IN ULONG Length,
  7247. OUT PSTR Buffer
  7248. )
  7249. /*++
  7250. Routine Description:
  7251. Routine to convert a Flags word to a descriptor string using the
  7252. supplied NameTable.
  7253. Arguments:
  7254. Flags - flags to convert.
  7255. NameTable - An array of FLAG_NAME_TABLE structs.
  7256. Length - Size of buffer in bytes.
  7257. Buffer - buffer with returned string.
  7258. Return Value:
  7259. Buffer containing printable string.
  7260. --*/
  7261. {
  7262. #undef DEBSUB
  7263. #define DEBSUB "FrsFlagsToStr:"
  7264. PFLAG_NAME_TABLE pNT = NameTable;
  7265. LONG Remaining = Length-1;
  7266. FRS_ASSERT((Length > 4) && (Buffer != NULL));
  7267. *Buffer = '\0';
  7268. if (Flags == 0) {
  7269. strncpy(Buffer, "<Flags Clear>", Length);
  7270. return;
  7271. }
  7272. //
  7273. // Build a string for each bit set in the Flag name table.
  7274. //
  7275. while ((Flags != 0) && (pNT->Flag != 0)) {
  7276. if ((pNT->Flag & Flags) != 0) {
  7277. Remaining -= strlen(pNT->Name);
  7278. if (Remaining < 0) {
  7279. //
  7280. // Out of string buffer. Tack a "..." at the end.
  7281. //
  7282. Remaining += strlen(pNT->Name);
  7283. if (Remaining > 3) {
  7284. strcat(Buffer, "..." );
  7285. } else {
  7286. strcpy(&Buffer[Length-4], "...");
  7287. }
  7288. return;
  7289. }
  7290. //
  7291. // Tack the name onto the buffer and clear the flag bit so we
  7292. // know what is left set when we run out of table.
  7293. //
  7294. strcat(Buffer, pNT->Name);
  7295. ClearFlag(Flags, pNT->Flag);
  7296. }
  7297. pNT += 1;
  7298. }
  7299. if (Flags != 0) {
  7300. //
  7301. // If any flags are still set give them back in hex if there is
  7302. // enough room in the buffer. "0xFFFFFFFF " needs 12 characters
  7303. // including the null.
  7304. //
  7305. if ((Length - strlen(Buffer)) >= 12) {
  7306. sprintf( &Buffer[strlen(Buffer)], "0x%08x ", Flags );
  7307. }
  7308. }
  7309. return;
  7310. }
  7311. DWORD
  7312. FrsDeleteByHandle(
  7313. IN PWCHAR Name,
  7314. IN HANDLE Handle
  7315. )
  7316. /*++
  7317. Routine Description:
  7318. This routine marks a file for delete, so that when the supplied handle
  7319. is closed, the file will actually be deleted.
  7320. Arguments:
  7321. Name - for error messages
  7322. Handle - Supplies a handle to the file that is to be marked for delete.
  7323. Return Value:
  7324. Win Status
  7325. --*/
  7326. {
  7327. #undef DEBSUB
  7328. #define DEBSUB "FrsDeleteByHandle:"
  7329. //
  7330. // NOTE: This function is at the end of the module because we have to
  7331. // undefine DeleteFile to set the flag in the DispositionInfo struct.
  7332. //
  7333. #undef DeleteFile
  7334. FILE_DISPOSITION_INFORMATION DispositionInformation;
  7335. IO_STATUS_BLOCK IoStatus;
  7336. NTSTATUS NtStatus;
  7337. if (!HANDLE_IS_VALID(Handle)) {
  7338. return ERROR_SUCCESS;
  7339. }
  7340. //
  7341. // Mark the file for delete. The delete happens when the handle is closed.
  7342. //
  7343. DispositionInformation.DeleteFile = TRUE;
  7344. NtStatus = NtSetInformationFile(Handle,
  7345. &IoStatus,
  7346. &DispositionInformation,
  7347. sizeof(DispositionInformation),
  7348. FileDispositionInformation);
  7349. DPRINT1_NT(4, "++ Could not delete %ws;", Name, NtStatus);
  7350. return FrsSetLastNTError(NtStatus);
  7351. }
  7352. VOID
  7353. FrsForceDeleteFileByWildCard(
  7354. PWCHAR DirPath,
  7355. PWCHAR WildCard
  7356. )
  7357. /*++
  7358. Routine Description:
  7359. Delete all files that match the wildcard. The Path and wildcard are combined.
  7360. to form the search path.
  7361. Arguments:
  7362. Return Value:
  7363. None
  7364. --*/
  7365. {
  7366. #undef DEBSUB
  7367. #define DEBSUB "FrsForceDeleteFileByWildCard:"
  7368. PWCHAR SearchPath = NULL;
  7369. HANDLE SearchHandle = INVALID_HANDLE_VALUE;
  7370. WIN32_FIND_DATA FindData;
  7371. PWCHAR FilePath = NULL;
  7372. DWORD WStatus;
  7373. if ((DirPath == NULL) || (wcslen(DirPath) == 0)) {
  7374. return;
  7375. }
  7376. SearchPath = FrsWcsPath(DirPath, WildCard);
  7377. SearchHandle = FindFirstFile(SearchPath, &FindData);
  7378. if (!HANDLE_IS_VALID(SearchHandle)) {
  7379. WStatus = GetLastError();
  7380. if (WStatus != ERROR_FILE_NOT_FOUND) {
  7381. DPRINT1_WS(1, "++ ERROR - FindFirstFile(%ws);", SearchPath, WStatus);
  7382. }
  7383. goto CLEANUP;
  7384. }
  7385. do {
  7386. DPRINT1(4, "++ Deleting file %ws\n", FindData.cFileName);
  7387. FilePath = FrsWcsPath(DirPath, FindData.cFileName);
  7388. FrsForceDeleteFile(FilePath);
  7389. FilePath = FrsFree(FilePath);
  7390. } while (FindNextFile(SearchHandle, &FindData));
  7391. CLEANUP:
  7392. FRS_FIND_CLOSE(SearchHandle);
  7393. SearchPath = FrsFree(SearchPath);
  7394. }
  7395. VOID
  7396. FrsDeleteAllTempFiles(
  7397. )
  7398. /*++
  7399. Routine Description:
  7400. This routine enumerates the registry and deletes the preinstall directory
  7401. and all staging files for all the replica sets. Call this only when we
  7402. do not intent to use any state in the database. Calling this function
  7403. while a replica set is in use can cause unexpected results.
  7404. Arguments:
  7405. Return Value:
  7406. Win Status
  7407. --*/
  7408. {
  7409. #undef DEBSUB
  7410. #define DEBSUB "FrsDeleteAllTempFiles:"
  7411. HKEY hKey = INVALID_HANDLE_VALUE;
  7412. DWORD WStatus = ERROR_SUCCESS;
  7413. DWORD KeyIdx;
  7414. WCHAR RegBuf[MAX_PATH + 1];
  7415. PWCHAR RootPath = NULL;
  7416. PWCHAR PreInstallPath = NULL;
  7417. PWCHAR StagePath = NULL;
  7418. PWCHAR WildCard = NULL;
  7419. //
  7420. // Open the key "System\\CurrentControlSet\\Services\\NtFrs\\Parameters\\Replica Sets"
  7421. // We will enumerate through all the subkeys under it and cleanup every
  7422. // replica set.
  7423. //
  7424. WStatus = CfgRegOpenKey(FKC_SET_SECTION_KEY, NULL, 0, &hKey);
  7425. if (!WIN_SUCCESS(WStatus)) {
  7426. //
  7427. // No replica sets to cleanup.
  7428. //
  7429. return;
  7430. }
  7431. KeyIdx = 0;
  7432. while (TRUE) {
  7433. WStatus = RegEnumKey(hKey, KeyIdx, RegBuf, MAX_PATH + 1);
  7434. if (!WIN_SUCCESS(WStatus)) {
  7435. if (WStatus != ERROR_NO_MORE_ITEMS) {
  7436. DPRINT_WS(0, "WARN - Replica Sets enum.", WStatus);
  7437. }
  7438. break;
  7439. }
  7440. ++KeyIdx;
  7441. WStatus = CfgRegReadString(FKC_SET_N_REPLICA_SET_ROOT, RegBuf, 0, &RootPath);
  7442. if (!WIN_SUCCESS(WStatus)) {
  7443. //
  7444. // Failure reading reg key.
  7445. //
  7446. DPRINT2_WS(0, "WARN - Failed to read key %ws for %ws\n", FKC_SET_N_REPLICA_SET_ROOT, RegBuf, WStatus);
  7447. continue;
  7448. }
  7449. PreInstallPath = FrsWcsPath(RootPath,NTFRS_PREINSTALL_DIRECTORY);
  7450. DPRINT1(4,"++ Deleting Preinstall directory %ws\n", PreInstallPath);
  7451. FrsDeletePath(PreInstallPath, ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE);
  7452. RootPath = FrsFree(RootPath);
  7453. PreInstallPath = FrsFree(PreInstallPath);
  7454. WStatus = CfgRegReadString(FKC_SET_N_REPLICA_SET_STAGE, RegBuf, 0, &StagePath);
  7455. if (!WIN_SUCCESS(WStatus)) {
  7456. //
  7457. // Failure reading reg key.
  7458. //
  7459. DPRINT2_WS(0, "WARN - Failed to read key %ws for %ws\n", FKC_SET_N_REPLICA_SET_ROOT, RegBuf, WStatus);
  7460. continue;
  7461. }
  7462. //
  7463. // Delete all the staging files in the staging area.
  7464. //
  7465. WildCard = FrsWcsCat(GENERIC_PREFIX, L"*.*");
  7466. FrsForceDeleteFileByWildCard(StagePath, WildCard);
  7467. WildCard = FrsFree(WildCard);
  7468. RootPath = FrsFree(RootPath);
  7469. PreInstallPath = FrsFree(PreInstallPath);
  7470. StagePath = FrsFree(StagePath);
  7471. }
  7472. RootPath = FrsFree(RootPath);
  7473. PreInstallPath = FrsFree(PreInstallPath);
  7474. StagePath = FrsFree(StagePath);
  7475. FRS_REG_CLOSE(hKey);
  7476. }
  7477. BOOL
  7478. ReparseTagReplicateFileData(
  7479. DWORD ReparseTag
  7480. )
  7481. {
  7482. PREPARSE_TAG_TABLE_ENTRY ReparseTagTableEntry = NULL;
  7483. ReparseTagTableEntry = GTabLookup(ReparseTagTable, &ReparseTag, NULL);
  7484. if(ReparseTagTableEntry &&
  7485. (0 == _wcsicmp(ReparseTagTableEntry->ReplicationType,
  7486. REPARSE_TAG_REPLICATION_TYPE_FILE_DATA))) {
  7487. return TRUE;
  7488. }
  7489. return FALSE;
  7490. }
  7491. BOOL
  7492. ReparseTagReplicateReparsePoint(
  7493. DWORD ReparseTag
  7494. )
  7495. {
  7496. PREPARSE_TAG_TABLE_ENTRY ReparseTagTableEntry = NULL;
  7497. ReparseTagTableEntry = GTabLookup(ReparseTagTable, &ReparseTag, NULL);
  7498. if(ReparseTagTableEntry &&
  7499. (0 == _wcsicmp(ReparseTagTableEntry->ReplicationType,
  7500. REPARSE_TAG_REPLICATION_TYPE_REPARSE_POINT))) {
  7501. return TRUE;
  7502. }
  7503. return FALSE;
  7504. }
  7505. VOID
  7506. FrsCheckLocalResources()
  7507. /*++
  7508. Routine Description:
  7509. Checks the available disk space on the database volume and
  7510. the root and staging volume for each active replica set.
  7511. Uses the ReplicasByGuid table to enumerte the replicas.
  7512. If the available disk space is less than 1% of the total
  7513. disk space it prints the eventlog message EVENT_FRS_OUT_OF_DISK_SPACE.
  7514. Arguments:
  7515. None.
  7516. Return Value:
  7517. None.
  7518. --*/
  7519. {
  7520. #undef DEBSUB
  7521. #define DEBSUB "FrsCheckLocalResources:"
  7522. PREPLICA Replica;
  7523. PVOID Key;
  7524. ULARGE_INTEGER FreeBytesAvailableToCaller;
  7525. ULARGE_INTEGER TotalNumberOfBytes;
  7526. PWCHAR Volume;
  7527. if (GetDiskFreeSpaceEx(WorkingPath,&FreeBytesAvailableToCaller,&TotalNumberOfBytes,NULL)) {
  7528. //
  7529. // Check space for database.
  7530. // Print the event log message if the available free space is
  7531. // less than 1%.
  7532. //
  7533. if ((FreeBytesAvailableToCaller.QuadPart*100) < TotalNumberOfBytes.QuadPart) {
  7534. Volume = FrsWcsVolume(WorkingPath);
  7535. if ((Volume != NULL) && (wcslen(Volume) >= wcslen(L"\\\\.\\D:"))) {
  7536. //
  7537. // If we are able to get the volume in the form
  7538. // \\.\D: then use the volume in the event log so
  7539. // that we don't print more than one event log
  7540. // message per volume. If we can't get the
  7541. // volume then we print the path.
  7542. //
  7543. EPRINT1(EVENT_FRS_OUT_OF_DISK_SPACE, &Volume[4]);
  7544. }else{
  7545. EPRINT1(EVENT_FRS_OUT_OF_DISK_SPACE, WorkingPath);
  7546. }
  7547. FrsFree(Volume);
  7548. }
  7549. DPRINT3(5, "Disk space check for database. %ws FreeSpace = %08x %08x bytes,TotalDiskSpace = %08x %08x bytes\n",
  7550. WorkingPath,
  7551. PRINTQUAD(FreeBytesAvailableToCaller.QuadPart),
  7552. PRINTQUAD(TotalNumberOfBytes.QuadPart));
  7553. FreeBytesAvailableToCaller.QuadPart = FreeBytesAvailableToCaller.QuadPart/(1024*1024);
  7554. TotalNumberOfBytes.QuadPart = TotalNumberOfBytes.QuadPart/(1024*1024);
  7555. DPRINT3(4, "Disk space check for database. %ws FreeSpace = %d MB,TotalDiskSpace = %d MB\n",
  7556. WorkingPath,
  7557. FreeBytesAvailableToCaller.LowPart,
  7558. TotalNumberOfBytes.LowPart);
  7559. }
  7560. Key = NULL;
  7561. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  7562. if (GetDiskFreeSpaceEx(Replica->Root,&FreeBytesAvailableToCaller,&TotalNumberOfBytes,NULL)) {
  7563. //
  7564. // For each replica check free disk space on the
  7565. // volume hosting the root path.
  7566. // Print the event log message if the available free space is
  7567. // less than 1%.
  7568. //
  7569. if ((FreeBytesAvailableToCaller.QuadPart*100) < TotalNumberOfBytes.QuadPart) {
  7570. if ((Replica->Volume != NULL) && (wcslen(Replica->Volume) >= wcslen(L"\\\\.\\D:"))) {
  7571. //
  7572. // If we are able to get the volume in the form
  7573. // \\.\D: then use the volume in the event log so
  7574. // that we don't print more than one event log
  7575. // message per volume. If we can't get the
  7576. // volume then we print the path.
  7577. //
  7578. EPRINT1(EVENT_FRS_OUT_OF_DISK_SPACE, &Replica->Volume[4]);
  7579. }else{
  7580. EPRINT1(EVENT_FRS_OUT_OF_DISK_SPACE, Replica->Root);
  7581. }
  7582. }
  7583. DPRINT3(5, "Disk space check for replica root. %ws FreeSpace = %08x %08x bytes,TotalDiskSpace = %08x %08x bytes\n",
  7584. Replica->Root,
  7585. PRINTQUAD(FreeBytesAvailableToCaller.QuadPart),
  7586. PRINTQUAD(TotalNumberOfBytes.QuadPart));
  7587. FreeBytesAvailableToCaller.QuadPart = FreeBytesAvailableToCaller.QuadPart/(1024*1024);
  7588. TotalNumberOfBytes.QuadPart = TotalNumberOfBytes.QuadPart/(1024*1024);
  7589. DPRINT3(4, "Disk space check for replica root. %ws FreeSpace = %d MB,TotalDiskSpace = %d MB\n",
  7590. Replica->Root,
  7591. FreeBytesAvailableToCaller.LowPart,
  7592. TotalNumberOfBytes.LowPart);
  7593. }
  7594. if (GetDiskFreeSpaceEx(Replica->Stage,&FreeBytesAvailableToCaller,&TotalNumberOfBytes,NULL)) {
  7595. //
  7596. // For each replica check free disk space on the
  7597. // volume hosting the staging path.
  7598. // Print the event log message if the available free space is
  7599. // less than 1%.
  7600. //
  7601. if ((FreeBytesAvailableToCaller.QuadPart*100) < TotalNumberOfBytes.QuadPart) {
  7602. Volume = FrsWcsVolume(Replica->Stage);
  7603. if ((Volume != NULL) && (wcslen(Volume) >= wcslen(L"\\\\.\\D:"))) {
  7604. //
  7605. // If we are able to get the volume in the form
  7606. // \\.\D: then use the volume in the event log so
  7607. // that we don't print more than one event log
  7608. // message per volume. If we can't get the
  7609. // volume then we print the path.
  7610. //
  7611. EPRINT1(EVENT_FRS_OUT_OF_DISK_SPACE, &Volume[4]);
  7612. }else{
  7613. EPRINT1(EVENT_FRS_OUT_OF_DISK_SPACE, Replica->Stage);
  7614. }
  7615. FrsFree(Volume);
  7616. }
  7617. DPRINT3(5, "Disk space check for replica stage. %ws FreeSpace = %08x %08x bytes,TotalDiskSpace = %08x %08x bytes\n",
  7618. Replica->Stage,
  7619. PRINTQUAD(FreeBytesAvailableToCaller.QuadPart),
  7620. PRINTQUAD(TotalNumberOfBytes.QuadPart));
  7621. FreeBytesAvailableToCaller.QuadPart = FreeBytesAvailableToCaller.QuadPart/(1024*1024);
  7622. TotalNumberOfBytes.QuadPart = TotalNumberOfBytes.QuadPart/(1024*1024);
  7623. DPRINT3(4, "Disk space check for replica stage. %ws FreeSpace = %d MB,TotalDiskSpace = %d MB\n",
  7624. Replica->Stage,
  7625. FreeBytesAvailableToCaller.LowPart,
  7626. TotalNumberOfBytes.LowPart);
  7627. }
  7628. }
  7629. }
  7630. DWORD
  7631. FrsFreezeForBackup()
  7632. /*++
  7633. Routine Description:
  7634. This API is called by the FRS writer component.
  7635. This API sets the FrsFrozenForBackup flag and then
  7636. waits for the install command server to finish
  7637. processing all install that are currently in
  7638. progress. When the install command server completes
  7639. all currently active installs it sets the
  7640. FrsNoInstallsInProgressEvent event.
  7641. This is an synchronous API that does not return
  7642. until the install command server has drained all
  7643. currently active installs. Once this API returns
  7644. it is guaranteed that FRS will not install
  7645. any more files until the FrsThawAfterBackup API
  7646. is called at which point it resumes installs.
  7647. Try not to leave FRS in frozen state for a long time.
  7648. While FRS is in frozen state no files are installed and
  7649. staging files can keep increasing. Since the staging
  7650. reclaim logic does not delete staging files that are
  7651. marked install-incomplete this can lead to staging full
  7652. errors.
  7653. Frozen state is not persistent across service shutdown
  7654. and startup.
  7655. There is no reference count on the number of times
  7656. freeze is called. One call to thaw will cause the
  7657. service to resume installs even if freeze was called
  7658. multiple times.
  7659. Arguments:
  7660. None.
  7661. Return Value:
  7662. WStatus.
  7663. --*/
  7664. {
  7665. #undef DEBSUB
  7666. #define DEBSUB "FrsFreezeForBackup:"
  7667. DPRINT2(4,"Before: FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  7668. if (FrsFrozenForBackup) {
  7669. DPRINT2(4,"Already in frozen state: FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  7670. return ERROR_SUCCESS;
  7671. }
  7672. ResetEvent(FrsThawEvent);
  7673. FrsFrozenForBackup = TRUE;
  7674. ResetEvent(FrsNoInstallsInProgressEvent);
  7675. if (FrsFilesInInstall >= 0) {
  7676. DPRINT2(4,"Waiting to freeze: FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  7677. WaitForSingleObject(FrsNoInstallsInProgressEvent, INFINITE);
  7678. }
  7679. DPRINT2(4,"After: FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  7680. return ERROR_SUCCESS;
  7681. }
  7682. DWORD
  7683. FrsThawAfterBackup()
  7684. /*++
  7685. Routine Description:
  7686. This API is used to take the service out of frozen state.
  7687. This API sets the FrsThawEvent event. The
  7688. install command server threads are waiting for this
  7689. event.
  7690. See the description of FrsFreezeForBackup for more details.
  7691. Arguments:
  7692. None.
  7693. Return Value:
  7694. WStatus.
  7695. --*/
  7696. {
  7697. #undef DEBSUB
  7698. #define DEBSUB "FrsThawAfterBackup:"
  7699. DPRINT2(4,"Before: FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  7700. if (FrsFrozenForBackup == FALSE) {
  7701. DPRINT2(4,"Already in thaw state: FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  7702. return ERROR_SUCCESS;
  7703. }
  7704. FrsFrozenForBackup = FALSE;
  7705. SetEvent(FrsThawEvent);
  7706. DPRINT2(4,"After: FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  7707. return ERROR_SUCCESS;
  7708. }