Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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