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.

1957 lines
42 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999 - 2000.
  5. //
  6. // File: file.cpp
  7. //
  8. // Contents: NtMarta file functions
  9. //
  10. // History: 4/99 philh Created
  11. //----------------------------------------------------------------------------
  12. #include <aclpch.hxx>
  13. #pragma hdrstop
  14. extern "C" {
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. }
  19. #include <windows.h>
  20. #include <kernel.h>
  21. #include <assert.h>
  22. #include <ntstatus.h>
  23. extern "C" {
  24. #include <lmcons.h>
  25. #include <lmapibuf.h>
  26. #include <lmdfs.h>
  27. }
  28. #include <memory.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <time.h>
  33. #include <stddef.h>
  34. #include <file.h>
  35. #ifdef STATIC
  36. #undef STATIC
  37. #endif
  38. #define STATIC
  39. //+-------------------------------------------------------------------------
  40. // File Context data structures
  41. //--------------------------------------------------------------------------
  42. typedef struct _FILE_FIND_DATA FILE_FIND_DATA, *PFILE_FIND_DATA;
  43. typedef struct _FILE_CONTEXT {
  44. DWORD dwRefCnt;
  45. DWORD dwFlags;
  46. // Only closed when FILE_CONTEXT_CLOSE_HANDLE_FLAG is set
  47. HANDLE hFile;
  48. // Following is allocated and updated for FindFirst, FindNext
  49. PFILE_FIND_DATA pFileFindData;
  50. } FILE_CONTEXT, *PFILE_CONTEXT;
  51. #define FILE_CONTEXT_CLOSE_HANDLE_FLAG 0x1
  52. typedef struct _QUERY_NAMES_INFO_BUFFER {
  53. FILE_NAMES_INFORMATION NamesInfo;
  54. WCHAR Names[MAX_PATH];
  55. } QUERY_NAMES_INFO_BUFFER;
  56. struct _FILE_FIND_DATA {
  57. HANDLE hDir;
  58. BOOL fRestartScan; // TRUE on first Find
  59. QUERY_NAMES_INFO_BUFFER NamesInfoBuffer;
  60. };
  61. //+-------------------------------------------------------------------------
  62. // File allocation functions
  63. //--------------------------------------------------------------------------
  64. #define I_MartaFileZeroAlloc(size) \
  65. LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, size)
  66. #define I_MartaFileNonzeroAlloc(size) \
  67. LocalAlloc(LMEM_FIXED, size)
  68. STATIC
  69. inline
  70. VOID
  71. I_MartaFileFree(
  72. IN LPVOID pv
  73. )
  74. /*++
  75. Routine Description:
  76. Free the given memory.
  77. Arguments:
  78. pv - Ponter to memory to be freed.
  79. Return Value:
  80. None.
  81. --*/
  82. {
  83. if (pv)
  84. LocalFree(pv);
  85. }
  86. STATIC
  87. DWORD
  88. I_MartaFileGetNtParentString(
  89. IN OUT LPWSTR pwszNtParent
  90. )
  91. /*++
  92. Routine Description:
  93. Given the name for a file/dir, get the name of its parent. Does not allocate
  94. memory. Scans till the first '\' from the right and deletes the name after
  95. that.
  96. Arguments:
  97. pwszNtParent - Object name which will be converted to its parent name.
  98. Return Value:
  99. ERROR_SUCCESS in case of success.
  100. ERROR_* otherwise
  101. --*/
  102. {
  103. DWORD dwErr;
  104. DWORD cch;
  105. LPWSTR pwsz;
  106. if (NULL == pwszNtParent)
  107. return ERROR_INVALID_NAME;
  108. cch = wcslen(pwszNtParent);
  109. pwsz = pwszNtParent + cch;
  110. if (0 == cch)
  111. goto InvalidNameReturn;
  112. pwsz--;
  113. //
  114. // Remove any trailing '\'s
  115. //
  116. while (L'\\' == *pwsz) {
  117. if (pwsz == pwszNtParent)
  118. goto InvalidNameReturn;
  119. pwsz--;
  120. }
  121. //
  122. // Peal off the last path name component
  123. //
  124. while (L'\\' != *pwsz) {
  125. if (pwsz == pwszNtParent)
  126. goto InvalidNameReturn;
  127. pwsz--;
  128. }
  129. //
  130. // Remove all trailing '\'s from the parent.
  131. //
  132. while (L'\\' == *pwsz) {
  133. if (pwsz == pwszNtParent)
  134. goto InvalidNameReturn;
  135. pwsz--;
  136. }
  137. pwsz++;
  138. assert(L'\\' == *pwsz);
  139. //
  140. // Required to distinguish between the device and root directory.
  141. //
  142. pwsz++;
  143. dwErr = ERROR_SUCCESS;
  144. CommonReturn:
  145. *pwsz = L'\0';
  146. return dwErr;
  147. InvalidNameReturn:
  148. dwErr = ERROR_INVALID_NAME;
  149. goto CommonReturn;
  150. }
  151. STATIC
  152. DWORD
  153. I_MartaFileInitContext(
  154. OUT PFILE_CONTEXT *ppFileContext
  155. )
  156. /*++
  157. Routine Description:
  158. Allocate and initialize memory for the context.
  159. Arguments:
  160. ppFileContext - To return the pointer to the allcoated memory.
  161. Return Value:
  162. ERROR_SUCCESS in case of success.
  163. ERROR_* otherwise
  164. --*/
  165. {
  166. DWORD dwErr;
  167. PFILE_CONTEXT pFileContext;
  168. if (pFileContext = (PFILE_CONTEXT) I_MartaFileZeroAlloc(
  169. sizeof(FILE_CONTEXT))) {
  170. pFileContext->dwRefCnt = 1;
  171. dwErr = ERROR_SUCCESS;
  172. } else {
  173. pFileContext = NULL;
  174. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  175. }
  176. *ppFileContext = pFileContext;
  177. return dwErr;
  178. }
  179. STATIC
  180. DWORD
  181. I_MartaFileNtOpenFile(
  182. IN PUNICODE_STRING pFileName,
  183. IN HANDLE hContainingDirectory, // NULL if pFileName is absolute
  184. IN ACCESS_MASK AccessMask,
  185. IN OUT PFILE_CONTEXT pFileContext
  186. )
  187. /*++
  188. Routine Description:
  189. Open the given file/dir with requested permissions and copy the handle into
  190. the supplied context.
  191. Arguments:
  192. pFileName - Name of the file/dir to be opened.
  193. hContainingDirectory - Handle to the parent dir.
  194. AccessMask - Desired access mask for the open.
  195. pFileContext - Handle will be copied into the context structure.
  196. Return Value:
  197. ERROR_SUCCESS in case of success.
  198. ERROR_* otherwise
  199. --*/
  200. {
  201. // cut and paste code from windows\base\advapi\security.c SetFileSecurityW
  202. NTSTATUS Status;
  203. OBJECT_ATTRIBUTES Obja;
  204. IO_STATUS_BLOCK IoStatusBlock;
  205. InitializeObjectAttributes(
  206. &Obja,
  207. pFileName,
  208. OBJ_CASE_INSENSITIVE,
  209. hContainingDirectory,
  210. NULL
  211. );
  212. //
  213. // Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior. Thus, the
  214. // security will always be set, as before, in the file denoted by the name.
  215. //
  216. Status = NtOpenFile(
  217. &pFileContext->hFile,
  218. AccessMask,
  219. &Obja,
  220. &IoStatusBlock,
  221. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  222. FILE_OPEN_REPARSE_POINT
  223. );
  224. //
  225. // Back-level file systems may not support the FILE_OPEN_REPARSE_POINT
  226. // flag. We treat this case explicitly.
  227. //
  228. if ( Status == STATUS_INVALID_PARAMETER ) {
  229. //
  230. // Open without inhibiting the reparse behavior.
  231. //
  232. Status = NtOpenFile(
  233. &pFileContext->hFile,
  234. AccessMask,
  235. &Obja,
  236. &IoStatusBlock,
  237. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  238. 0
  239. );
  240. }
  241. if (NT_SUCCESS(Status)) {
  242. pFileContext->dwFlags |= FILE_CONTEXT_CLOSE_HANDLE_FLAG;
  243. return ERROR_SUCCESS;
  244. } else
  245. return RtlNtStatusToDosError(Status);
  246. }
  247. DWORD
  248. MartaOpenFileNamedObject(
  249. IN LPCWSTR pwszObject,
  250. IN ACCESS_MASK AccessMask,
  251. OUT PMARTA_CONTEXT pContext
  252. )
  253. /*++
  254. Routine Description:
  255. Open the given file/dir with desired access mask and return a context
  256. handle.
  257. Arguments:
  258. pwszObject - Name of the file/dir which will be opened.
  259. AccessMask - Desired access mask with which the file/dir will be opened.
  260. pContext - To return a context handle.
  261. Return Value:
  262. ERROR_SUCCESS in case of success.
  263. ERROR_* otherwise
  264. --*/
  265. {
  266. DWORD dwErr = ERROR_SUCCESS;
  267. PFILE_CONTEXT pFileContext = NULL;
  268. UNICODE_STRING FileName;
  269. RTL_RELATIVE_NAME RelativeName;
  270. PVOID FreeBuffer = NULL;
  271. if (NULL == pwszObject)
  272. goto InvalidNameReturn;
  273. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileContext)))
  274. goto ErrorReturn;
  275. //
  276. // Convert the name into NT pathname.
  277. //
  278. if (!RtlDosPathNameToNtPathName_U(
  279. pwszObject,
  280. &FileName,
  281. NULL,
  282. &RelativeName
  283. ))
  284. goto InvalidNameReturn;
  285. FreeBuffer = FileName.Buffer;
  286. if (RelativeName.RelativeName.Length ) {
  287. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  288. } else {
  289. RelativeName.ContainingDirectory = NULL;
  290. }
  291. //
  292. // Call the helper routine that does the actual open.
  293. //
  294. if (ERROR_SUCCESS != (dwErr = I_MartaFileNtOpenFile(
  295. &FileName,
  296. RelativeName.ContainingDirectory,
  297. AccessMask,
  298. pFileContext
  299. )))
  300. goto ErrorReturn;
  301. CommonReturn:
  302. if (FreeBuffer)
  303. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  304. *pContext = (MARTA_CONTEXT) pFileContext;
  305. return dwErr;
  306. ErrorReturn:
  307. if (pFileContext) {
  308. MartaCloseFileContext((MARTA_CONTEXT) pFileContext);
  309. pFileContext = NULL;
  310. }
  311. assert(ERROR_SUCCESS != dwErr);
  312. if (ERROR_SUCCESS == dwErr)
  313. dwErr = ERROR_INTERNAL_ERROR;
  314. goto CommonReturn;
  315. InvalidNameReturn:
  316. dwErr = ERROR_INVALID_NAME;
  317. goto ErrorReturn;
  318. }
  319. void
  320. I_MartaFileFreeFindData(
  321. IN PFILE_FIND_DATA pFileFindData
  322. )
  323. /*++
  324. Routine Description:
  325. Free up the memory associated with the internal structure.
  326. Arguments:
  327. pFileFindData - Internal file structure to be freed.
  328. Return Value:
  329. ERROR_SUCCESS in case of success.
  330. ERROR_* otherwise
  331. --*/
  332. {
  333. if (NULL == pFileFindData)
  334. return;
  335. if (pFileFindData->hDir)
  336. NtClose(pFileFindData->hDir);
  337. I_MartaFileFree(pFileFindData);
  338. }
  339. DWORD
  340. MartaCloseFileContext(
  341. IN MARTA_CONTEXT Context
  342. )
  343. /*++
  344. Routine Description:
  345. Close the context.
  346. Arguments:
  347. Context - Context to be closed.
  348. Return Value:
  349. ERROR_SUCCESS in case of success.
  350. ERROR_* otherwise
  351. --*/
  352. {
  353. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  354. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  355. return ERROR_INVALID_PARAMETER;
  356. //
  357. // If the refcnt has gone to zero then free up the memory associated with
  358. // the context handle. Also, close the file handle.
  359. //
  360. if (0 == --pFileContext->dwRefCnt) {
  361. if (pFileContext->pFileFindData)
  362. I_MartaFileFreeFindData(pFileContext->pFileFindData);
  363. if (pFileContext->dwFlags & FILE_CONTEXT_CLOSE_HANDLE_FLAG)
  364. NtClose(pFileContext->hFile);
  365. I_MartaFileFree(pFileContext);
  366. }
  367. return ERROR_SUCCESS;
  368. }
  369. DWORD
  370. MartaAddRefFileContext(
  371. IN MARTA_CONTEXT Context
  372. )
  373. /*++
  374. Routine Description:
  375. Bump up the ref count for this context.
  376. Arguments:
  377. Context - Context whose ref count should be bumped up.
  378. Return Value:
  379. ERROR_SUCCESS in case of success.
  380. ERROR_* otherwise
  381. --*/
  382. {
  383. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  384. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  385. return ERROR_INVALID_PARAMETER;
  386. pFileContext->dwRefCnt++;
  387. return ERROR_SUCCESS;
  388. }
  389. DWORD
  390. MartaOpenFileHandleObject(
  391. IN HANDLE Handle,
  392. IN ACCESS_MASK AccessMask,
  393. OUT PMARTA_CONTEXT pContext
  394. )
  395. /*++
  396. Routine Description:
  397. Given a file handle, open the context with the desired access mask and
  398. return a context handle.
  399. Arguments:
  400. Handle - Existing file handle.
  401. AccessMask - Desired access mask for file open.
  402. pContext - To return a handle to the context.
  403. Return Value:
  404. ERROR_SUCCESS in case of success.
  405. ERROR_* otherwise
  406. --*/
  407. {
  408. DWORD dwErr;
  409. PFILE_CONTEXT pFileContext = NULL;
  410. //
  411. // Allocate and initialize context.
  412. //
  413. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileContext)))
  414. goto ErrorReturn;
  415. //
  416. // Duplicate the handle for desired access mask.
  417. //
  418. if (0 == AccessMask)
  419. pFileContext->hFile = Handle;
  420. else {
  421. if (!DuplicateHandle(
  422. GetCurrentProcess(),
  423. Handle,
  424. GetCurrentProcess(),
  425. &pFileContext->hFile,
  426. AccessMask,
  427. FALSE, // bInheritHandle
  428. 0 // fdwOptions
  429. )) {
  430. dwErr = GetLastError();
  431. goto ErrorReturn;
  432. }
  433. pFileContext->dwFlags |= FILE_CONTEXT_CLOSE_HANDLE_FLAG;
  434. }
  435. dwErr = ERROR_SUCCESS;
  436. CommonReturn:
  437. *pContext = (MARTA_CONTEXT) pFileContext;
  438. return dwErr;
  439. ErrorReturn:
  440. if (pFileContext) {
  441. MartaCloseFileContext((MARTA_CONTEXT) pFileContext);
  442. pFileContext = NULL;
  443. }
  444. assert(ERROR_SUCCESS != dwErr);
  445. if (ERROR_SUCCESS == dwErr)
  446. dwErr = ERROR_INTERNAL_ERROR;
  447. goto CommonReturn;
  448. }
  449. DWORD
  450. MartaGetFileParentContext(
  451. IN MARTA_CONTEXT Context,
  452. IN ACCESS_MASK AccessMask,
  453. OUT PMARTA_CONTEXT pParentContext
  454. )
  455. /*++
  456. Routine Description:
  457. Given the context for a file/dir, get the context for its parent.
  458. Arguments:
  459. Context - Context for the file/dir.
  460. AccessMask - Desired access mask with which the parent will be opened.
  461. pParentContext - To return the context for the parent.
  462. Return Value:
  463. ERROR_SUCCESS in case of success.
  464. ERROR_* otherwise
  465. --*/
  466. {
  467. DWORD dwErr;
  468. LPWSTR pwszNtParentObject = NULL;
  469. PFILE_CONTEXT pFileContext = NULL;
  470. UNICODE_STRING FileName;
  471. //
  472. // Convert the context into the name of the file/dir.
  473. //
  474. if (ERROR_SUCCESS != (dwErr = MartaConvertFileContextToNtName(
  475. Context, &pwszNtParentObject)))
  476. goto ErrorReturn;
  477. //
  478. // Get the name of the parent.
  479. //
  480. if (ERROR_SUCCESS != (dwErr = I_MartaFileGetNtParentString(
  481. pwszNtParentObject)))
  482. goto NoParentReturn;
  483. //
  484. // Initialize the context structure.
  485. //
  486. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileContext)))
  487. goto ErrorReturn;
  488. RtlInitUnicodeString(&FileName, pwszNtParentObject);
  489. //
  490. // Open the parent dir with the requested permissions.
  491. //
  492. if (ERROR_SUCCESS != (dwErr = I_MartaFileNtOpenFile(
  493. &FileName,
  494. NULL, // hContainingDirectory,
  495. AccessMask,
  496. pFileContext
  497. )))
  498. goto NoParentReturn;
  499. CommonReturn:
  500. I_MartaFileFree(pwszNtParentObject);
  501. *pParentContext = (MARTA_CONTEXT) pFileContext;
  502. return dwErr;
  503. NoParentReturn:
  504. dwErr = ERROR_SUCCESS;
  505. ErrorReturn:
  506. if (pFileContext) {
  507. MartaCloseFileContext((MARTA_CONTEXT) pFileContext);
  508. pFileContext = NULL;
  509. }
  510. goto CommonReturn;
  511. }
  512. DWORD
  513. MartaFindFirstFile(
  514. IN MARTA_CONTEXT Context,
  515. IN ACCESS_MASK AccessMask,
  516. OUT PMARTA_CONTEXT pChildContext
  517. )
  518. /*++
  519. Routine Description:
  520. FInd the first file/dir in the given directory.
  521. Arguments:
  522. Context - Context for the directory.
  523. AccessMask - Desired access mask for opening the child file/dir.
  524. pChildContext - To return the context for the first child in the given dir.
  525. Return Value:
  526. ERROR_SUCCESS in case of success.
  527. ERROR_* otherwise
  528. Note:
  529. Does not free up the current context.
  530. --*/
  531. {
  532. DWORD dwErr;
  533. NTSTATUS Status;
  534. PFILE_CONTEXT pFileParentContext = (PFILE_CONTEXT) Context;
  535. PFILE_CONTEXT pFileFirstContext = NULL;
  536. PFILE_FIND_DATA pFileFindData; // freed as part of pFileFirstContext
  537. UNICODE_STRING FileName;
  538. OBJECT_ATTRIBUTES Obja;
  539. IO_STATUS_BLOCK IoStatusBlock;
  540. //
  541. // Allocate a context for the first child.
  542. //
  543. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileFirstContext)))
  544. goto ErrorReturn;
  545. if (NULL == (pFileFindData = (PFILE_FIND_DATA) I_MartaFileZeroAlloc(
  546. sizeof(FILE_FIND_DATA))))
  547. goto NotEnoughMemoryReturn;
  548. pFileFindData->fRestartScan = TRUE;
  549. pFileFirstContext->pFileFindData = pFileFindData;
  550. //
  551. // Duplicate the parent's file handle for synchronized directory access
  552. //
  553. RtlInitUnicodeString(&FileName, NULL);
  554. InitializeObjectAttributes(
  555. &Obja,
  556. &FileName,
  557. OBJ_CASE_INSENSITIVE,
  558. pFileParentContext->hFile,
  559. NULL
  560. );
  561. //
  562. // Obtained following parameter values from windows\base\filefind.c
  563. //
  564. Status = NtOpenFile(
  565. &pFileFindData->hDir,
  566. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  567. &Obja,
  568. &IoStatusBlock,
  569. FILE_SHARE_READ | FILE_SHARE_WRITE,
  570. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
  571. FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT
  572. );
  573. //
  574. // Back-level file systems may not support the FILE_OPEN_REPARSE_POINT
  575. // flag. We treat this case explicitly.
  576. //
  577. if ( Status == STATUS_INVALID_PARAMETER ) {
  578. //
  579. // Open without inhibiting the reparse behavior.
  580. //
  581. Status = NtOpenFile(
  582. &pFileFindData->hDir,
  583. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  584. &Obja,
  585. &IoStatusBlock,
  586. FILE_SHARE_READ | FILE_SHARE_WRITE,
  587. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
  588. FILE_OPEN_FOR_BACKUP_INTENT
  589. );
  590. }
  591. if (!NT_SUCCESS(Status))
  592. goto StatusErrorReturn;
  593. //
  594. // Following closes / frees pFileFirstContext
  595. //
  596. dwErr = MartaFindNextFile(
  597. (MARTA_CONTEXT) pFileFirstContext,
  598. AccessMask,
  599. pChildContext
  600. );
  601. CommonReturn:
  602. return dwErr;
  603. StatusErrorReturn:
  604. dwErr = RtlNtStatusToDosError(Status);
  605. ErrorReturn:
  606. if (pFileFirstContext)
  607. MartaCloseFileContext((MARTA_CONTEXT) pFileFirstContext);
  608. *pChildContext = NULL;
  609. assert(ERROR_SUCCESS != dwErr);
  610. if (ERROR_SUCCESS == dwErr)
  611. dwErr = ERROR_INTERNAL_ERROR;
  612. goto CommonReturn;
  613. NotEnoughMemoryReturn:
  614. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  615. goto ErrorReturn;
  616. }
  617. STATIC
  618. BOOL
  619. I_MartaIsDfsJunctionPoint(
  620. IN MARTA_CONTEXT Context
  621. );
  622. DWORD
  623. MartaFindNextFile(
  624. IN MARTA_CONTEXT Context,
  625. IN ACCESS_MASK AccessMask,
  626. OUT PMARTA_CONTEXT pSiblingContext
  627. )
  628. /*++
  629. Routine Description:
  630. Get the next object in the tree. This is the sibling for the current context.
  631. Arguments:
  632. Context - Context for the current object.
  633. AccessMask - Desired access mask for the opening the sibling.
  634. pSiblingContext - To return a handle for the sibling.
  635. Return Value:
  636. ERROR_SUCCESS in case of success.
  637. ERROR_* otherwise
  638. Note:
  639. Closes the current context.
  640. --*/
  641. {
  642. DWORD dwErr = ERROR_SUCCESS;
  643. NTSTATUS Status;
  644. PFILE_CONTEXT pFilePrevContext = (PFILE_CONTEXT) Context;
  645. PFILE_CONTEXT pFileSiblingContext = NULL;
  646. //
  647. // Following don't need to be freed or closed
  648. //
  649. PFILE_FIND_DATA pFileFindData;
  650. IO_STATUS_BLOCK IoStatusBlock;
  651. PFILE_NAMES_INFORMATION pNamesInfo;
  652. HANDLE hDir;
  653. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileSiblingContext)))
  654. goto ErrorReturn;
  655. //
  656. // Move the FindData on to the sibling context
  657. //
  658. pFileFindData = pFilePrevContext->pFileFindData;
  659. if (NULL == pFileFindData)
  660. goto InvalidParameterReturn;
  661. pFilePrevContext->pFileFindData = NULL;
  662. pFileSiblingContext->pFileFindData = pFileFindData;
  663. hDir = pFileFindData->hDir;
  664. pNamesInfo = &pFileFindData->NamesInfoBuffer.NamesInfo;
  665. while (TRUE) {
  666. UNICODE_STRING FileName;
  667. DWORD cchFileName;
  668. LPCWSTR pwszFileName;
  669. //
  670. // Get the name of the sibling object.
  671. //
  672. Status = NtQueryDirectoryFile(
  673. hDir,
  674. NULL, // HANDLE Event OPTIONAL,
  675. NULL, // PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  676. NULL, // ApcContext OPTIONAL,
  677. &IoStatusBlock,
  678. pNamesInfo,
  679. sizeof(pFileFindData->NamesInfoBuffer),
  680. FileNamesInformation,
  681. TRUE, // BOOLEAN ReturnSingleEntry,
  682. NULL, // PUNICODE_STRING FileName OPTIONAL,
  683. pFileFindData->fRestartScan != FALSE
  684. );
  685. if (ERROR_SUCCESS != Status)
  686. goto StatusErrorReturn;
  687. pFileFindData->fRestartScan = FALSE;
  688. FileName.Length = (USHORT) pNamesInfo->FileNameLength;
  689. FileName.MaximumLength = (USHORT) FileName.Length;
  690. FileName.Buffer = pNamesInfo->FileName;
  691. cchFileName = FileName.Length / sizeof(WCHAR);
  692. pwszFileName = FileName.Buffer;
  693. // Skip "." and ".."
  694. if (0 < cchFileName && L'.' == pwszFileName[0] &&
  695. (1 == cchFileName ||
  696. (2 == cchFileName && L'.' == pwszFileName[1])))
  697. continue;
  698. //
  699. // For an error still return this context. This allows the caller
  700. // to continue on to the next sibling object and know there was an
  701. // error with this sibling object
  702. //
  703. dwErr = I_MartaFileNtOpenFile(
  704. &FileName,
  705. hDir,
  706. AccessMask,
  707. pFileSiblingContext
  708. );
  709. //
  710. // Per Praerit, skip DFS junction points.
  711. //
  712. if (ERROR_SUCCESS == dwErr &&
  713. I_MartaIsDfsJunctionPoint(pFileSiblingContext)) {
  714. assert(pFileSiblingContext->dwFlags &
  715. FILE_CONTEXT_CLOSE_HANDLE_FLAG);
  716. if (pFileSiblingContext->dwFlags &
  717. FILE_CONTEXT_CLOSE_HANDLE_FLAG) {
  718. NtClose(pFileSiblingContext->hFile);
  719. pFileSiblingContext->hFile = NULL;
  720. pFileSiblingContext->dwFlags &=
  721. ~FILE_CONTEXT_CLOSE_HANDLE_FLAG;
  722. }
  723. continue;
  724. } else
  725. break;
  726. }
  727. CommonReturn:
  728. MartaCloseFileContext(Context);
  729. *pSiblingContext = (MARTA_CONTEXT) pFileSiblingContext;
  730. return dwErr;
  731. StatusErrorReturn:
  732. dwErr = RtlNtStatusToDosError(Status);
  733. ErrorReturn:
  734. if (pFileSiblingContext) {
  735. MartaCloseFileContext((MARTA_CONTEXT) pFileSiblingContext);
  736. pFileSiblingContext = NULL;
  737. }
  738. //
  739. // If there are no more chidren, return ERROR_SUCCESS with a NULL sibling
  740. // context.
  741. //
  742. if (ERROR_NO_MORE_FILES == dwErr)
  743. dwErr = ERROR_SUCCESS;
  744. goto CommonReturn;
  745. InvalidParameterReturn:
  746. dwErr = ERROR_INVALID_PARAMETER;
  747. goto ErrorReturn;
  748. }
  749. #define WINDFS_DEVICE L"\\Device\\WinDfs"
  750. #define WINDFS_DEVICE_LEN (sizeof(WINDFS_DEVICE) / sizeof(WCHAR) - 1)
  751. #define WINDFS_PREFIX WINDFS_DEVICE L"\\Root"
  752. #define WINDFS_PREFIX_LEN (sizeof(WINDFS_PREFIX) / sizeof(WCHAR) - 1)
  753. #define MAX_QUERY_RETRY_CNT 16
  754. STATIC
  755. DWORD
  756. I_MartaFileHandleToNtDfsName(
  757. IN HANDLE hFile,
  758. OUT LPWSTR *ppwszNtObject
  759. )
  760. /*++
  761. Routine Description:
  762. Covert the given file handle for a DFS object into name. Allocates memory.
  763. Arguments:
  764. hFile - Handle for the DFS object.
  765. ppwszNtObject - To return the name of the DFS object.
  766. Return Value:
  767. ERROR_SUCCESS in case of success.
  768. ERROR_* otherwise
  769. Note:
  770. Couple of problems in the name returned by NtQueryObject for DFS objects:
  771. - Name contains 4 extra, bogus bytes (This is a BUG that should be fixed)
  772. - For logical drives, returns \Device\WinDfs\X:0\server\share. This
  773. needs to be converted to \Device\WinDfs\Root\server\share.
  774. Where X is the drive letter.
  775. This routine is called when it has already been determined the hFile
  776. refers to a DFS object name.
  777. --*/
  778. {
  779. NTSTATUS Status;
  780. DWORD dwErr;
  781. LPWSTR pwszNtObject = NULL;
  782. IO_STATUS_BLOCK IoStatusBlock;
  783. BYTE Buff[MAX_PATH * 4];
  784. PFILE_NAME_INFORMATION pAllocNI = NULL;
  785. PFILE_NAME_INFORMATION pNI; // not allocated
  786. LPWSTR pwszFileName;
  787. DWORD cchFileName;
  788. DWORD cchNtObject;
  789. ULONG cbNI;
  790. DWORD cRetry;
  791. pNI = (PFILE_NAME_INFORMATION) Buff;
  792. cbNI = sizeof(Buff);
  793. cRetry = 0;
  794. while (TRUE) {
  795. //
  796. // This returns the filename without the Nt Dfs object name prefix.
  797. //
  798. // Assumption: the returned filename always has a leading '\'.
  799. //
  800. Status = NtQueryInformationFile(
  801. hFile,
  802. &IoStatusBlock,
  803. pNI,
  804. cbNI,
  805. FileNameInformation
  806. );
  807. if (ERROR_SUCCESS == Status)
  808. break;
  809. if (!(Status == STATUS_BUFFER_TOO_SMALL ||
  810. Status == STATUS_INFO_LENGTH_MISMATCH ||
  811. Status == STATUS_BUFFER_OVERFLOW))
  812. goto StatusErrorReturn;
  813. if (++cRetry >= MAX_QUERY_RETRY_CNT)
  814. goto InvalidNameReturn;
  815. //
  816. // Double buffer length and retry
  817. //
  818. cbNI = cbNI * 2;
  819. I_MartaFileFree(pAllocNI);
  820. if (NULL == (pAllocNI = (PFILE_NAME_INFORMATION)
  821. I_MartaFileNonzeroAlloc(cbNI)))
  822. goto NotEnoughMemoryReturn;
  823. pNI = pAllocNI;
  824. }
  825. //
  826. // Compute the length of the buffer required to hold the name.
  827. //
  828. pwszFileName = pNI->FileName;
  829. cchFileName = pNI->FileNameLength / sizeof(WCHAR);
  830. if (0 == cchFileName)
  831. goto InvalidNameReturn;
  832. cchNtObject = WINDFS_PREFIX_LEN + cchFileName;
  833. //
  834. // Allocate memory.
  835. //
  836. if (NULL == (pwszNtObject = (LPWSTR) I_MartaFileNonzeroAlloc(
  837. (cchNtObject + 1) * sizeof(WCHAR))))
  838. goto NotEnoughMemoryReturn;
  839. //
  840. // Copy the prefix and the file name.
  841. //
  842. memcpy(pwszNtObject, WINDFS_PREFIX, WINDFS_PREFIX_LEN * sizeof(WCHAR));
  843. memcpy(pwszNtObject + WINDFS_PREFIX_LEN, pwszFileName,
  844. cchFileName * sizeof(WCHAR));
  845. pwszNtObject[cchNtObject] = L'\0';
  846. dwErr = ERROR_SUCCESS;
  847. CommonReturn:
  848. I_MartaFileFree(pAllocNI);
  849. *ppwszNtObject = pwszNtObject;
  850. return dwErr;
  851. StatusErrorReturn:
  852. dwErr = RtlNtStatusToDosError(Status);
  853. ErrorReturn:
  854. assert(NULL == pwszNtObject);
  855. assert(ERROR_SUCCESS != dwErr);
  856. if (ERROR_SUCCESS == dwErr)
  857. dwErr = ERROR_INTERNAL_ERROR;
  858. goto CommonReturn;
  859. NotEnoughMemoryReturn:
  860. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  861. goto ErrorReturn;
  862. InvalidNameReturn:
  863. dwErr = ERROR_INVALID_NAME;
  864. goto ErrorReturn;
  865. }
  866. STATIC
  867. BOOL
  868. I_MartaIsDfsJunctionPoint(
  869. IN MARTA_CONTEXT Context
  870. )
  871. /*++
  872. Routine Description:
  873. Determine whether this is a DFS junction point.
  874. Arguments:
  875. Context - Context for which the caller want to determine whether this is a
  876. dfs junction point.
  877. Return Value:
  878. TRUE if this is a DFS junction point.
  879. FALSE o/w.
  880. --*/
  881. {
  882. BOOL fDfsJunctionPoint = FALSE;
  883. LPWSTR pwszNtObject = NULL;
  884. DWORD cchNtObject;
  885. LPWSTR pwszDfs; // not allocated
  886. NET_API_STATUS NetStatus;
  887. LPBYTE pbNetInfo = NULL;
  888. if (ERROR_SUCCESS != MartaConvertFileContextToNtName(
  889. Context, &pwszNtObject))
  890. goto CommonReturn;
  891. //
  892. // Check the prefix.
  893. //
  894. if (0 != _wcsnicmp(pwszNtObject, WINDFS_PREFIX, WINDFS_PREFIX_LEN))
  895. goto CommonReturn;
  896. //
  897. // Convert the NtDfs name to a UNC name
  898. //
  899. pwszDfs = pwszNtObject + WINDFS_PREFIX_LEN - 1;
  900. *pwszDfs = L'\\';
  901. //
  902. // Assumption: the following is only successful for DFS junction point
  903. // filename.
  904. //
  905. NetStatus = NetDfsGetInfo(
  906. pwszDfs,
  907. NULL, // ServerName
  908. NULL, // ShareName
  909. 1,
  910. &pbNetInfo
  911. );
  912. if (0 == NetStatus) {
  913. fDfsJunctionPoint = TRUE;
  914. }
  915. CommonReturn:
  916. if (pwszNtObject)
  917. LocalFree(pwszNtObject);
  918. if (pbNetInfo)
  919. NetApiBufferFree(pbNetInfo);
  920. return fDfsJunctionPoint;
  921. }
  922. DWORD
  923. MartaConvertFileContextToNtName(
  924. IN MARTA_CONTEXT Context,
  925. OUT LPWSTR *ppwszNtObject
  926. )
  927. /*++
  928. Routine Description:
  929. Returns the NT Object Name for the given context. Allocates memory.
  930. Arguments:
  931. Context - Context for the file/dir.
  932. ppwszNtbject - To return the name of the file/dir.
  933. Return Value:
  934. ERROR_SUCCESS in case of success.
  935. ERROR_* otherwise
  936. --*/
  937. {
  938. DWORD dwErr = ERROR_SUCCESS;
  939. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  940. LPWSTR pwszNtObject = NULL;
  941. BYTE Buff[MAX_PATH * 4];
  942. ULONG cLen = 0;
  943. POBJECT_NAME_INFORMATION pNI; // not allocated
  944. POBJECT_NAME_INFORMATION pAllocNI = NULL;
  945. NTSTATUS Status;
  946. HANDLE hFile; // not opened
  947. LPWSTR pwszPath;
  948. DWORD cchPath;
  949. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  950. goto InvalidParameterReturn;
  951. hFile = pFileContext->hFile;
  952. //
  953. // First, determine the size of the buffer we need.
  954. //
  955. pNI = (POBJECT_NAME_INFORMATION) Buff;
  956. Status = NtQueryObject(hFile,
  957. ObjectNameInformation,
  958. pNI,
  959. sizeof(Buff),
  960. &cLen);
  961. if (!NT_SUCCESS(Status)) {
  962. if (Status == STATUS_BUFFER_TOO_SMALL ||
  963. Status == STATUS_INFO_LENGTH_MISMATCH ||
  964. Status == STATUS_BUFFER_OVERFLOW) {
  965. //
  966. // Allocate a big enough buffer
  967. //
  968. if (NULL == (pAllocNI = (POBJECT_NAME_INFORMATION)
  969. I_MartaFileNonzeroAlloc(cLen)))
  970. goto NotEnoughMemoryReturn;
  971. pNI = pAllocNI;
  972. Status = NtQueryObject(hFile,
  973. ObjectNameInformation,
  974. pNI,
  975. cLen,
  976. NULL);
  977. if (!NT_SUCCESS(Status))
  978. goto StatusErrorReturn;
  979. } else
  980. goto StatusErrorReturn;
  981. }
  982. pwszPath = pNI->Name.Buffer;
  983. cchPath = pNI->Name.Length / sizeof(WCHAR);
  984. //
  985. // For DFS names, call a helper routine.
  986. //
  987. if (WINDFS_DEVICE_LEN <= cchPath &&
  988. 0 == _wcsnicmp(pwszPath, WINDFS_DEVICE, WINDFS_DEVICE_LEN))
  989. dwErr = I_MartaFileHandleToNtDfsName(hFile, &pwszNtObject);
  990. else {
  991. //
  992. // Allocate and return the name of the object.
  993. //
  994. if (NULL == (pwszNtObject = (LPWSTR) I_MartaFileNonzeroAlloc(
  995. (cchPath + 1) * sizeof(WCHAR))))
  996. goto NotEnoughMemoryReturn;
  997. memcpy(pwszNtObject, pwszPath, cchPath * sizeof(WCHAR));
  998. pwszNtObject[cchPath] = L'\0';
  999. dwErr = ERROR_SUCCESS;
  1000. }
  1001. CommonReturn:
  1002. I_MartaFileFree(pAllocNI);
  1003. *ppwszNtObject = pwszNtObject;
  1004. return dwErr;
  1005. StatusErrorReturn:
  1006. dwErr = RtlNtStatusToDosError(Status);
  1007. ErrorReturn:
  1008. assert(NULL == pwszNtObject);
  1009. assert(ERROR_SUCCESS != dwErr);
  1010. if (ERROR_SUCCESS == dwErr)
  1011. dwErr = ERROR_INTERNAL_ERROR;
  1012. goto CommonReturn;
  1013. NotEnoughMemoryReturn:
  1014. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1015. goto ErrorReturn;
  1016. InvalidParameterReturn:
  1017. dwErr = ERROR_INVALID_PARAMETER;
  1018. goto ErrorReturn;
  1019. }
  1020. DWORD
  1021. MartaGetFileProperties(
  1022. IN MARTA_CONTEXT Context,
  1023. IN OUT PMARTA_OBJECT_PROPERTIES pProperties
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. Return the properties for file/dir represented by the context.
  1028. Arguments:
  1029. Context - Context whose properties the caller has asked for.
  1030. pProperties - To return the properties for this file/dir.
  1031. Return Value:
  1032. ERROR_SUCCESS in case of success.
  1033. ERROR_* otherwise
  1034. --*/
  1035. {
  1036. DWORD dwErr = ERROR_SUCCESS;
  1037. NTSTATUS Status;
  1038. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  1039. IO_STATUS_BLOCK IoStatusBlock;
  1040. FILE_BASIC_INFORMATION BasicFileInfo;
  1041. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  1042. goto InvalidParameterReturn;
  1043. //
  1044. // Query the attributes for the file/dir.
  1045. // In case of error, assume that it is a dir.
  1046. //
  1047. if (!NT_SUCCESS(Status = NtQueryInformationFile(
  1048. pFileContext->hFile,
  1049. &IoStatusBlock,
  1050. &BasicFileInfo,
  1051. sizeof(BasicFileInfo),
  1052. FileBasicInformation)))
  1053. pProperties->dwFlags |= MARTA_OBJECT_IS_CONTAINER;
  1054. else if (BasicFileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1055. pProperties->dwFlags |= MARTA_OBJECT_IS_CONTAINER;
  1056. dwErr = ERROR_SUCCESS;
  1057. CommonReturn:
  1058. return dwErr;
  1059. ErrorReturn:
  1060. assert(ERROR_SUCCESS != dwErr);
  1061. if (ERROR_SUCCESS == dwErr)
  1062. dwErr = ERROR_INTERNAL_ERROR;
  1063. goto CommonReturn;
  1064. InvalidParameterReturn:
  1065. dwErr = ERROR_INVALID_PARAMETER;
  1066. goto ErrorReturn;
  1067. }
  1068. DWORD
  1069. MartaGetFileTypeProperties(
  1070. IN OUT PMARTA_OBJECT_TYPE_PROPERTIES pProperties
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. Return the properties of file system objects.
  1075. Arguments:
  1076. pProperties - To return the properties of file system objects.
  1077. Return Value:
  1078. ERROR_SUCCESS.
  1079. --*/
  1080. {
  1081. const GENERIC_MAPPING GenMap = {
  1082. FILE_GENERIC_READ,
  1083. FILE_GENERIC_WRITE,
  1084. FILE_GENERIC_EXECUTE,
  1085. FILE_ALL_ACCESS
  1086. };
  1087. //
  1088. // Propagation to be done on the client side.
  1089. //
  1090. pProperties->dwFlags |= MARTA_OBJECT_TYPE_MANUAL_PROPAGATION_NEEDED_FLAG;
  1091. //
  1092. // Tree organization of obects is present.
  1093. //
  1094. pProperties->dwFlags |= MARTA_OBJECT_TYPE_INHERITANCE_MODEL_PRESENT_FLAG;
  1095. //
  1096. // Return the generic mapping too.
  1097. //
  1098. pProperties->GenMap = GenMap;
  1099. return ERROR_SUCCESS;
  1100. }
  1101. DWORD
  1102. MartaGetFileRights(
  1103. IN MARTA_CONTEXT Context,
  1104. IN SECURITY_INFORMATION SecurityInfo,
  1105. OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
  1106. )
  1107. /*++
  1108. Routine Description:
  1109. Get the security descriptor for the given handle.
  1110. Arguments:
  1111. Context - Context for file/dir.
  1112. SecurityInfo - Type of security information to be read.
  1113. ppSecurityDescriptor - To return a self-relative security decriptor pointer.
  1114. Return Value:
  1115. ERROR_SUCCESS in case of success.
  1116. ERROR_* otherwise
  1117. --*/
  1118. {
  1119. BOOL fResult;
  1120. DWORD dwErr = ERROR_SUCCESS;
  1121. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  1122. DWORD cbSize;
  1123. PISECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  1124. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  1125. goto InvalidParameterReturn;
  1126. //
  1127. // First, get the size we need
  1128. //
  1129. cbSize = 0;
  1130. if (GetKernelObjectSecurity(
  1131. pFileContext->hFile,
  1132. SecurityInfo,
  1133. NULL, // pSecDesc
  1134. 0,
  1135. &cbSize
  1136. ))
  1137. goto InternalErrorReturn;
  1138. dwErr = GetLastError();
  1139. if (ERROR_INSUFFICIENT_BUFFER == dwErr) {
  1140. if (NULL == (pSecurityDescriptor =
  1141. (PISECURITY_DESCRIPTOR) I_MartaFileNonzeroAlloc(cbSize)))
  1142. goto NotEnoughMemoryReturn;
  1143. //
  1144. // Now get the security descriptor.
  1145. //
  1146. if (!GetKernelObjectSecurity(
  1147. pFileContext->hFile,
  1148. SecurityInfo,
  1149. pSecurityDescriptor,
  1150. cbSize,
  1151. &cbSize
  1152. ))
  1153. goto LastErrorReturn;
  1154. } else
  1155. goto ErrorReturn;
  1156. dwErr = ERROR_SUCCESS;
  1157. CommonReturn:
  1158. *ppSecurityDescriptor = pSecurityDescriptor;
  1159. return dwErr;
  1160. LastErrorReturn:
  1161. dwErr = GetLastError();
  1162. ErrorReturn:
  1163. if (pSecurityDescriptor) {
  1164. I_MartaFileFree(pSecurityDescriptor);
  1165. pSecurityDescriptor = NULL;
  1166. }
  1167. assert(ERROR_SUCCESS != dwErr);
  1168. if (ERROR_SUCCESS == dwErr)
  1169. dwErr = ERROR_INTERNAL_ERROR;
  1170. goto CommonReturn;
  1171. NotEnoughMemoryReturn:
  1172. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1173. goto ErrorReturn;
  1174. InvalidParameterReturn:
  1175. dwErr = ERROR_INVALID_PARAMETER;
  1176. goto ErrorReturn;
  1177. InternalErrorReturn:
  1178. dwErr = ERROR_INTERNAL_ERROR;
  1179. goto ErrorReturn;
  1180. }
  1181. DWORD
  1182. MartaSetFileRights(
  1183. IN MARTA_CONTEXT Context,
  1184. IN SECURITY_INFORMATION SecurityInfo,
  1185. IN PSECURITY_DESCRIPTOR pSecurityDescriptor
  1186. )
  1187. /*++
  1188. Routine Description:
  1189. Set the given security descriptor on the file/dir represented by the context.
  1190. Arguments:
  1191. Context - Context for the file/dir.
  1192. SecurityInfo - Type of security info to be stamped on the file/dir.
  1193. pSecurityDescriptor - Security descriptor to be stamped.
  1194. Return Value:
  1195. ERROR_SUCCESS in case of success.
  1196. ERROR_* otherwise
  1197. --*/
  1198. {
  1199. DWORD dwErr;
  1200. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  1201. //
  1202. // Basic validation on the context.
  1203. //
  1204. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  1205. goto InvalidParameterReturn;
  1206. //
  1207. // Set the security on the file/dir.
  1208. //
  1209. if (!SetKernelObjectSecurity(
  1210. pFileContext->hFile,
  1211. SecurityInfo,
  1212. pSecurityDescriptor
  1213. ))
  1214. goto LastErrorReturn;
  1215. dwErr = ERROR_SUCCESS;
  1216. CommonReturn:
  1217. return dwErr;
  1218. InvalidParameterReturn:
  1219. dwErr = ERROR_INVALID_PARAMETER;
  1220. goto CommonReturn;
  1221. LastErrorReturn:
  1222. dwErr = GetLastError();
  1223. if (ERROR_SUCCESS == dwErr)
  1224. dwErr = ERROR_INTERNAL_ERROR;
  1225. goto CommonReturn;
  1226. }
  1227. ACCESS_MASK
  1228. MartaGetFileDesiredAccess(
  1229. IN SECURITY_OPEN_TYPE OpenType,
  1230. IN BOOL Attribs,
  1231. IN SECURITY_INFORMATION SecurityInfo
  1232. )
  1233. /*++
  1234. Routine Description:
  1235. Gets the access required to open object to be able to set or get the
  1236. specified security info.
  1237. Arguments:
  1238. OpenType - Flag indicating if the object is to be opened to read or write
  1239. the security information
  1240. Attribs - TRUE indicates that additional access bits should be returned.
  1241. SecurityInfo - owner/group/dacl/sacl
  1242. Return Value:
  1243. Desired access mask with which open should be called.
  1244. --*/
  1245. {
  1246. ACCESS_MASK DesiredAccess = 0;
  1247. if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
  1248. (SecurityInfo & GROUP_SECURITY_INFORMATION) )
  1249. {
  1250. switch (OpenType)
  1251. {
  1252. case READ_ACCESS_RIGHTS:
  1253. DesiredAccess |= READ_CONTROL;
  1254. break;
  1255. case WRITE_ACCESS_RIGHTS:
  1256. DesiredAccess |= WRITE_OWNER;
  1257. break;
  1258. case MODIFY_ACCESS_RIGHTS:
  1259. DesiredAccess |= READ_CONTROL | WRITE_OWNER;
  1260. break;
  1261. }
  1262. }
  1263. if (SecurityInfo & DACL_SECURITY_INFORMATION)
  1264. {
  1265. switch (OpenType)
  1266. {
  1267. case READ_ACCESS_RIGHTS:
  1268. DesiredAccess |= READ_CONTROL;
  1269. break;
  1270. case WRITE_ACCESS_RIGHTS:
  1271. DesiredAccess |= WRITE_DAC;
  1272. break;
  1273. case MODIFY_ACCESS_RIGHTS:
  1274. DesiredAccess |= READ_CONTROL | WRITE_DAC;
  1275. break;
  1276. }
  1277. }
  1278. if (SecurityInfo & SACL_SECURITY_INFORMATION)
  1279. {
  1280. DesiredAccess |= READ_CONTROL | ACCESS_SYSTEM_SECURITY;
  1281. }
  1282. //
  1283. // ONLY FOR FILES.
  1284. //
  1285. if (Attribs)
  1286. {
  1287. DesiredAccess |= FILE_READ_ATTRIBUTES | READ_CONTROL;
  1288. }
  1289. return (DesiredAccess);
  1290. }
  1291. DWORD
  1292. MartaReopenFileContext(
  1293. IN OUT MARTA_CONTEXT Context,
  1294. IN ACCESS_MASK AccessMask
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. Given the context for a file/dir, close the existing handle if one exists
  1299. and reopen the context with new permissions.
  1300. Arguments:
  1301. Context - Context to be reopened.
  1302. AccessMask - Permissions for the reopen.
  1303. Return Value:
  1304. ERROR_SUCCESS in case of success.
  1305. ERROR_* otherwise
  1306. --*/
  1307. {
  1308. DWORD dwErr = ERROR_SUCCESS;
  1309. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  1310. //
  1311. // Following don't need to be freed or closed
  1312. //
  1313. PFILE_FIND_DATA pFileFindData;
  1314. IO_STATUS_BLOCK IoStatusBlock;
  1315. PFILE_NAMES_INFORMATION pNamesInfo;
  1316. HANDLE hDir;
  1317. UNICODE_STRING FileName;
  1318. //
  1319. // VishnuP: Bug #384222 (AV since Context == NULL).
  1320. // In MartaUpdateTree(), we don't error in case the
  1321. // ChildContext is NULL so return here too with success
  1322. //
  1323. if ( NULL == Context)
  1324. {
  1325. return ERROR_SUCCESS;
  1326. }
  1327. //
  1328. // Extract the data needed to open the file.
  1329. //
  1330. pFileFindData = pFileContext->pFileFindData;
  1331. hDir = pFileFindData->hDir;
  1332. pNamesInfo = &pFileFindData->NamesInfoBuffer.NamesInfo;
  1333. FileName.Length = (USHORT) pNamesInfo->FileNameLength;
  1334. FileName.MaximumLength = (USHORT) FileName.Length;
  1335. FileName.Buffer = pNamesInfo->FileName;
  1336. //
  1337. // Close the original handle. We do not expect to hit this given the way
  1338. // the code is organized now.
  1339. //
  1340. if (pFileContext->dwFlags & FILE_CONTEXT_CLOSE_HANDLE_FLAG)
  1341. NtClose(pFileContext->hFile);
  1342. //
  1343. // Open the file with the access mask desired.
  1344. //
  1345. dwErr = I_MartaFileNtOpenFile(
  1346. &FileName,
  1347. hDir,
  1348. AccessMask,
  1349. pFileContext
  1350. );
  1351. //
  1352. // In case of a successful open mark the context.
  1353. //
  1354. if (ERROR_SUCCESS == dwErr)
  1355. {
  1356. pFileContext->dwFlags |= FILE_CONTEXT_CLOSE_HANDLE_FLAG;
  1357. }
  1358. return dwErr;
  1359. }
  1360. DWORD
  1361. MartaReopenFileOrigContext(
  1362. IN OUT MARTA_CONTEXT Context,
  1363. IN ACCESS_MASK AccessMask
  1364. )
  1365. /*++
  1366. Routine Description:
  1367. This is a dummy routine.
  1368. Arguments:
  1369. Are ignored.
  1370. Return Value:
  1371. ERROR_SUCCESS
  1372. Note:
  1373. The context structure must be left untouched.
  1374. --*/
  1375. {
  1376. //
  1377. // This is a dummy routine. The real reopen is done by MartaFindFirstFile
  1378. // that is called just after this call. The context contains a valid handle
  1379. // which was used to set a new DACL on the file/dir.
  1380. //
  1381. return ERROR_SUCCESS;
  1382. }
  1383. DWORD
  1384. MartaGetFileNameFromContext(
  1385. IN MARTA_CONTEXT Context,
  1386. OUT LPWSTR *pObjectName
  1387. )
  1388. /*++
  1389. Routine Description:
  1390. Get the name of the file/dir from the context. This routine allocates
  1391. memory required to hold the name of the object.
  1392. Arguments:
  1393. Context - Handle to the context.
  1394. pObjectName - To return the pointer to the allocated string.
  1395. Return Value:
  1396. ERROR_SUCCESS in case of success.
  1397. ERROR_* otherwise
  1398. --*/
  1399. {
  1400. return MartaConvertFileContextToNtName(Context, pObjectName);
  1401. }
  1402. DWORD
  1403. MartaGetFileParentName(
  1404. IN LPWSTR ObjectName,
  1405. OUT LPWSTR *pParentName
  1406. )
  1407. /*++
  1408. Routine Description:
  1409. Given the name of a file/dir return the name of its parent. The routine
  1410. allocates memory required to hold the parent name.
  1411. Arguments:
  1412. ObjectName - Name of the file/dir.
  1413. pParentName - To return the pointer to the allocated parent name.
  1414. In case of the root of the tree, we return NULL parent with ERROR_SUCCESS.
  1415. Return Value:
  1416. ERROR_SUCCESS in case of success.
  1417. ERROR_* otherwise
  1418. --*/
  1419. {
  1420. ULONG Length = wcslen(ObjectName) + 1;
  1421. PWCHAR Name = (PWCHAR) I_MartaFileNonzeroAlloc(sizeof(WCHAR) * Length);
  1422. DWORD dwErr = ERROR_SUCCESS;
  1423. *pParentName = NULL;
  1424. if (!Name)
  1425. {
  1426. return ERROR_NOT_ENOUGH_MEMORY;
  1427. }
  1428. //
  1429. // Copy the name of the object into the allocated buffer.
  1430. //
  1431. wcscpy((WCHAR *) Name, ObjectName);
  1432. //
  1433. // Convert the object name intp its parent name.
  1434. //
  1435. dwErr = I_MartaFileGetNtParentString(Name);
  1436. if (ERROR_SUCCESS != dwErr)
  1437. {
  1438. I_MartaFileFree(Name);
  1439. //
  1440. // This is the root of the tree which does not have a parent. Return
  1441. // ERROR_SUCCESS with ParentName as NULL.
  1442. //
  1443. if (ERROR_INVALID_NAME == dwErr)
  1444. return ERROR_SUCCESS;
  1445. return dwErr;
  1446. }
  1447. *pParentName = Name;
  1448. return dwErr;
  1449. }