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

2088 lines
47 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_U RelativeName;
  270. PVOID FreeBuffer = NULL;
  271. BOOL ReleaseRelativeName = FALSE;
  272. if (NULL == pwszObject)
  273. goto InvalidNameReturn;
  274. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileContext)))
  275. goto ErrorReturn;
  276. //
  277. // Convert the name into NT pathname.
  278. //
  279. if (!RtlDosPathNameToRelativeNtPathName_U(
  280. pwszObject,
  281. &FileName,
  282. NULL,
  283. &RelativeName
  284. ))
  285. goto InvalidNameReturn;
  286. ReleaseRelativeName = TRUE;
  287. FreeBuffer = FileName.Buffer;
  288. if (RelativeName.RelativeName.Length ) {
  289. FileName = RelativeName.RelativeName;
  290. } else {
  291. RelativeName.ContainingDirectory = NULL;
  292. }
  293. //
  294. // Call the helper routine that does the actual open.
  295. //
  296. if (ERROR_SUCCESS != (dwErr = I_MartaFileNtOpenFile(
  297. &FileName,
  298. RelativeName.ContainingDirectory,
  299. AccessMask,
  300. pFileContext
  301. )))
  302. goto ErrorReturn;
  303. CommonReturn:
  304. if (ReleaseRelativeName) {
  305. RtlReleaseRelativeName(&RelativeName);
  306. }
  307. if (FreeBuffer)
  308. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  309. *pContext = (MARTA_CONTEXT) pFileContext;
  310. return dwErr;
  311. ErrorReturn:
  312. if (pFileContext) {
  313. MartaCloseFileContext((MARTA_CONTEXT) pFileContext);
  314. pFileContext = NULL;
  315. }
  316. assert(ERROR_SUCCESS != dwErr);
  317. if (ERROR_SUCCESS == dwErr)
  318. dwErr = ERROR_INTERNAL_ERROR;
  319. goto CommonReturn;
  320. InvalidNameReturn:
  321. dwErr = ERROR_INVALID_NAME;
  322. goto ErrorReturn;
  323. }
  324. void
  325. I_MartaFileFreeFindData(
  326. IN PFILE_FIND_DATA pFileFindData
  327. )
  328. /*++
  329. Routine Description:
  330. Free up the memory associated with the internal structure.
  331. Arguments:
  332. pFileFindData - Internal file structure to be freed.
  333. Return Value:
  334. ERROR_SUCCESS in case of success.
  335. ERROR_* otherwise
  336. --*/
  337. {
  338. if (NULL == pFileFindData)
  339. return;
  340. if (pFileFindData->hDir)
  341. NtClose(pFileFindData->hDir);
  342. I_MartaFileFree(pFileFindData);
  343. }
  344. DWORD
  345. MartaCloseFileContext(
  346. IN MARTA_CONTEXT Context
  347. )
  348. /*++
  349. Routine Description:
  350. Close the context.
  351. Arguments:
  352. Context - Context to be closed.
  353. Return Value:
  354. ERROR_SUCCESS in case of success.
  355. ERROR_* otherwise
  356. --*/
  357. {
  358. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  359. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  360. return ERROR_INVALID_PARAMETER;
  361. //
  362. // If the refcnt has gone to zero then free up the memory associated with
  363. // the context handle. Also, close the file handle.
  364. //
  365. if (0 == --pFileContext->dwRefCnt) {
  366. if (pFileContext->pFileFindData)
  367. I_MartaFileFreeFindData(pFileContext->pFileFindData);
  368. if (pFileContext->dwFlags & FILE_CONTEXT_CLOSE_HANDLE_FLAG)
  369. {
  370. NtClose(pFileContext->hFile);
  371. pFileContext->hFile = NULL;
  372. pFileContext->dwFlags &= ~FILE_CONTEXT_CLOSE_HANDLE_FLAG;
  373. }
  374. I_MartaFileFree(pFileContext);
  375. }
  376. return ERROR_SUCCESS;
  377. }
  378. DWORD
  379. MartaAddRefFileContext(
  380. IN MARTA_CONTEXT Context
  381. )
  382. /*++
  383. Routine Description:
  384. Bump up the ref count for this context.
  385. Arguments:
  386. Context - Context whose ref count should be bumped up.
  387. Return Value:
  388. ERROR_SUCCESS in case of success.
  389. ERROR_* otherwise
  390. --*/
  391. {
  392. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  393. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  394. return ERROR_INVALID_PARAMETER;
  395. pFileContext->dwRefCnt++;
  396. return ERROR_SUCCESS;
  397. }
  398. DWORD
  399. MartaOpenFileHandleObject(
  400. IN HANDLE Handle,
  401. IN ACCESS_MASK AccessMask,
  402. OUT PMARTA_CONTEXT pContext
  403. )
  404. /*++
  405. Routine Description:
  406. Given a file handle, open the context with the desired access mask and
  407. return a context handle.
  408. Arguments:
  409. Handle - Existing file handle.
  410. AccessMask - Desired access mask for file open.
  411. pContext - To return a handle to the context.
  412. Return Value:
  413. ERROR_SUCCESS in case of success.
  414. ERROR_* otherwise
  415. --*/
  416. {
  417. DWORD dwErr;
  418. PFILE_CONTEXT pFileContext = NULL;
  419. //
  420. // Allocate and initialize context.
  421. //
  422. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileContext)))
  423. goto ErrorReturn;
  424. //
  425. // Duplicate the handle for desired access mask.
  426. //
  427. if (0 == AccessMask)
  428. pFileContext->hFile = Handle;
  429. else {
  430. if (!DuplicateHandle(
  431. GetCurrentProcess(),
  432. Handle,
  433. GetCurrentProcess(),
  434. &pFileContext->hFile,
  435. AccessMask,
  436. FALSE, // bInheritHandle
  437. 0 // fdwOptions
  438. )) {
  439. dwErr = GetLastError();
  440. goto ErrorReturn;
  441. }
  442. pFileContext->dwFlags |= FILE_CONTEXT_CLOSE_HANDLE_FLAG;
  443. }
  444. dwErr = ERROR_SUCCESS;
  445. CommonReturn:
  446. *pContext = (MARTA_CONTEXT) pFileContext;
  447. return dwErr;
  448. ErrorReturn:
  449. if (pFileContext) {
  450. MartaCloseFileContext((MARTA_CONTEXT) pFileContext);
  451. pFileContext = NULL;
  452. }
  453. assert(ERROR_SUCCESS != dwErr);
  454. if (ERROR_SUCCESS == dwErr)
  455. dwErr = ERROR_INTERNAL_ERROR;
  456. goto CommonReturn;
  457. }
  458. DWORD
  459. MartaGetFileParentContext(
  460. IN MARTA_CONTEXT Context,
  461. IN ACCESS_MASK AccessMask,
  462. OUT PMARTA_CONTEXT pParentContext
  463. )
  464. /*++
  465. Routine Description:
  466. Given the context for a file/dir, get the context for its parent.
  467. Arguments:
  468. Context - Context for the file/dir.
  469. AccessMask - Desired access mask with which the parent will be opened.
  470. pParentContext - To return the context for the parent.
  471. Return Value:
  472. ERROR_SUCCESS in case of success.
  473. ERROR_* otherwise
  474. --*/
  475. {
  476. DWORD dwErr;
  477. LPWSTR pwszNtParentObject = NULL;
  478. PFILE_CONTEXT pFileContext = NULL;
  479. UNICODE_STRING FileName;
  480. //
  481. // Convert the context into the name of the file/dir.
  482. //
  483. if (ERROR_SUCCESS != (dwErr = MartaConvertFileContextToNtName(
  484. Context, &pwszNtParentObject)))
  485. goto ErrorReturn;
  486. //
  487. // Get the name of the parent.
  488. //
  489. if (ERROR_SUCCESS != (dwErr = I_MartaFileGetNtParentString(
  490. pwszNtParentObject)))
  491. goto NoParentReturn;
  492. //
  493. // Initialize the context structure.
  494. //
  495. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileContext)))
  496. goto ErrorReturn;
  497. RtlInitUnicodeString(&FileName, pwszNtParentObject);
  498. //
  499. // Open the parent dir with the requested permissions.
  500. //
  501. if (ERROR_SUCCESS != (dwErr = I_MartaFileNtOpenFile(
  502. &FileName,
  503. NULL, // hContainingDirectory,
  504. AccessMask,
  505. pFileContext
  506. )))
  507. goto NoParentReturn;
  508. CommonReturn:
  509. I_MartaFileFree(pwszNtParentObject);
  510. *pParentContext = (MARTA_CONTEXT) pFileContext;
  511. return dwErr;
  512. NoParentReturn:
  513. dwErr = ERROR_SUCCESS;
  514. ErrorReturn:
  515. if (pFileContext) {
  516. MartaCloseFileContext((MARTA_CONTEXT) pFileContext);
  517. pFileContext = NULL;
  518. }
  519. goto CommonReturn;
  520. }
  521. DWORD
  522. MartaFindFirstFile(
  523. IN MARTA_CONTEXT Context,
  524. IN ACCESS_MASK AccessMask,
  525. OUT PMARTA_CONTEXT pChildContext
  526. )
  527. /*++
  528. Routine Description:
  529. FInd the first file/dir in the given directory.
  530. Arguments:
  531. Context - Context for the directory.
  532. AccessMask - Desired access mask for opening the child file/dir.
  533. pChildContext - To return the context for the first child in the given dir.
  534. Return Value:
  535. ERROR_SUCCESS in case of success.
  536. ERROR_* otherwise
  537. Note:
  538. Does not free up the current context.
  539. --*/
  540. {
  541. DWORD dwErr;
  542. NTSTATUS Status;
  543. PFILE_CONTEXT pFileParentContext = (PFILE_CONTEXT) Context;
  544. PFILE_CONTEXT pFileFirstContext = NULL;
  545. PFILE_FIND_DATA pFileFindData; // freed as part of pFileFirstContext
  546. UNICODE_STRING FileName;
  547. OBJECT_ATTRIBUTES Obja;
  548. IO_STATUS_BLOCK IoStatusBlock;
  549. //
  550. // Allocate a context for the first child.
  551. //
  552. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileFirstContext)))
  553. goto ErrorReturn;
  554. if (NULL == (pFileFindData = (PFILE_FIND_DATA) I_MartaFileZeroAlloc(
  555. sizeof(FILE_FIND_DATA))))
  556. goto NotEnoughMemoryReturn;
  557. pFileFindData->fRestartScan = TRUE;
  558. pFileFirstContext->pFileFindData = pFileFindData;
  559. //
  560. // Duplicate the parent's file handle for synchronized directory access
  561. //
  562. RtlInitUnicodeString(&FileName, NULL);
  563. InitializeObjectAttributes(
  564. &Obja,
  565. &FileName,
  566. OBJ_CASE_INSENSITIVE,
  567. pFileParentContext->hFile,
  568. NULL
  569. );
  570. //
  571. // Obtained following parameter values from windows\base\filefind.c
  572. //
  573. Status = NtOpenFile(
  574. &pFileFindData->hDir,
  575. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  576. &Obja,
  577. &IoStatusBlock,
  578. FILE_SHARE_READ | FILE_SHARE_WRITE,
  579. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
  580. FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT
  581. );
  582. //
  583. // Back-level file systems may not support the FILE_OPEN_REPARSE_POINT
  584. // flag. We treat this case explicitly.
  585. //
  586. if ( Status == STATUS_INVALID_PARAMETER ) {
  587. //
  588. // Open without inhibiting the reparse behavior.
  589. //
  590. Status = NtOpenFile(
  591. &pFileFindData->hDir,
  592. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  593. &Obja,
  594. &IoStatusBlock,
  595. FILE_SHARE_READ | FILE_SHARE_WRITE,
  596. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
  597. FILE_OPEN_FOR_BACKUP_INTENT
  598. );
  599. }
  600. if (!NT_SUCCESS(Status))
  601. goto StatusErrorReturn;
  602. //
  603. // Following closes / frees pFileFirstContext
  604. //
  605. dwErr = MartaFindNextFile(
  606. (MARTA_CONTEXT) pFileFirstContext,
  607. AccessMask,
  608. pChildContext
  609. );
  610. CommonReturn:
  611. return dwErr;
  612. StatusErrorReturn:
  613. dwErr = RtlNtStatusToDosError(Status);
  614. ErrorReturn:
  615. if (pFileFirstContext)
  616. MartaCloseFileContext((MARTA_CONTEXT) pFileFirstContext);
  617. *pChildContext = NULL;
  618. assert(ERROR_SUCCESS != dwErr);
  619. if (ERROR_SUCCESS == dwErr)
  620. dwErr = ERROR_INTERNAL_ERROR;
  621. goto CommonReturn;
  622. NotEnoughMemoryReturn:
  623. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  624. goto ErrorReturn;
  625. }
  626. STATIC
  627. BOOL
  628. I_MartaIsDfsJunctionPoint(
  629. IN MARTA_CONTEXT Context
  630. );
  631. DWORD
  632. MartaFindNextFile(
  633. IN MARTA_CONTEXT Context,
  634. IN ACCESS_MASK AccessMask,
  635. OUT PMARTA_CONTEXT pSiblingContext
  636. )
  637. /*++
  638. Routine Description:
  639. Get the next object in the tree. This is the sibling for the current context.
  640. Arguments:
  641. Context - Context for the current object.
  642. AccessMask - Desired access mask for the opening the sibling.
  643. pSiblingContext - To return a handle for the sibling.
  644. Return Value:
  645. ERROR_SUCCESS in case of success.
  646. ERROR_* otherwise
  647. Note:
  648. Closes the current context.
  649. --*/
  650. {
  651. DWORD dwErr = ERROR_SUCCESS;
  652. NTSTATUS Status;
  653. PFILE_CONTEXT pFilePrevContext = (PFILE_CONTEXT) Context;
  654. PFILE_CONTEXT pFileSiblingContext = NULL;
  655. //
  656. // Following don't need to be freed or closed
  657. //
  658. PFILE_FIND_DATA pFileFindData;
  659. IO_STATUS_BLOCK IoStatusBlock;
  660. PFILE_NAMES_INFORMATION pNamesInfo;
  661. HANDLE hDir;
  662. if (ERROR_SUCCESS != (dwErr = I_MartaFileInitContext(&pFileSiblingContext)))
  663. goto ErrorReturn;
  664. //
  665. // Move the FindData on to the sibling context
  666. //
  667. pFileFindData = pFilePrevContext->pFileFindData;
  668. if (NULL == pFileFindData)
  669. goto InvalidParameterReturn;
  670. pFilePrevContext->pFileFindData = NULL;
  671. pFileSiblingContext->pFileFindData = pFileFindData;
  672. hDir = pFileFindData->hDir;
  673. pNamesInfo = &pFileFindData->NamesInfoBuffer.NamesInfo;
  674. while (TRUE) {
  675. UNICODE_STRING FileName;
  676. DWORD cchFileName;
  677. LPCWSTR pwszFileName;
  678. //
  679. // Get the name of the sibling object.
  680. //
  681. Status = NtQueryDirectoryFile(
  682. hDir,
  683. NULL, // HANDLE Event OPTIONAL,
  684. NULL, // PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  685. NULL, // ApcContext OPTIONAL,
  686. &IoStatusBlock,
  687. pNamesInfo,
  688. sizeof(pFileFindData->NamesInfoBuffer),
  689. FileNamesInformation,
  690. TRUE, // BOOLEAN ReturnSingleEntry,
  691. NULL, // PUNICODE_STRING FileName OPTIONAL,
  692. pFileFindData->fRestartScan != FALSE
  693. );
  694. if (ERROR_SUCCESS != Status)
  695. goto StatusErrorReturn;
  696. pFileFindData->fRestartScan = FALSE;
  697. FileName.Length = (USHORT) pNamesInfo->FileNameLength;
  698. FileName.MaximumLength = (USHORT) FileName.Length;
  699. FileName.Buffer = pNamesInfo->FileName;
  700. cchFileName = FileName.Length / sizeof(WCHAR);
  701. pwszFileName = FileName.Buffer;
  702. // Skip "." and ".."
  703. if (0 < cchFileName && L'.' == pwszFileName[0] &&
  704. (1 == cchFileName ||
  705. (2 == cchFileName && L'.' == pwszFileName[1])))
  706. continue;
  707. //
  708. // For an error still return this context. This allows the caller
  709. // to continue on to the next sibling object and know there was an
  710. // error with this sibling object
  711. //
  712. dwErr = I_MartaFileNtOpenFile(
  713. &FileName,
  714. hDir,
  715. AccessMask,
  716. pFileSiblingContext
  717. );
  718. //
  719. // Per Praerit, skip DFS junction points.
  720. //
  721. if (ERROR_SUCCESS == dwErr &&
  722. I_MartaIsDfsJunctionPoint(pFileSiblingContext)) {
  723. assert(pFileSiblingContext->dwFlags &
  724. FILE_CONTEXT_CLOSE_HANDLE_FLAG);
  725. if (pFileSiblingContext->dwFlags &
  726. FILE_CONTEXT_CLOSE_HANDLE_FLAG) {
  727. NtClose(pFileSiblingContext->hFile);
  728. pFileSiblingContext->hFile = NULL;
  729. pFileSiblingContext->dwFlags &=
  730. ~FILE_CONTEXT_CLOSE_HANDLE_FLAG;
  731. }
  732. continue;
  733. } else
  734. break;
  735. }
  736. CommonReturn:
  737. MartaCloseFileContext(Context);
  738. *pSiblingContext = (MARTA_CONTEXT) pFileSiblingContext;
  739. return dwErr;
  740. StatusErrorReturn:
  741. dwErr = RtlNtStatusToDosError(Status);
  742. ErrorReturn:
  743. if (pFileSiblingContext) {
  744. MartaCloseFileContext((MARTA_CONTEXT) pFileSiblingContext);
  745. pFileSiblingContext = NULL;
  746. }
  747. //
  748. // If there are no more chidren, return ERROR_SUCCESS with a NULL sibling
  749. // context.
  750. //
  751. if (ERROR_NO_MORE_FILES == dwErr)
  752. dwErr = ERROR_SUCCESS;
  753. goto CommonReturn;
  754. InvalidParameterReturn:
  755. dwErr = ERROR_INVALID_PARAMETER;
  756. goto ErrorReturn;
  757. }
  758. #define WINDFS_DEVICE L"\\Device\\WinDfs"
  759. #define WINDFS_DEVICE_LEN (sizeof(WINDFS_DEVICE) / sizeof(WCHAR) - 1)
  760. #define WINDFS_PREFIX WINDFS_DEVICE L"\\Root"
  761. #define WINDFS_PREFIX_LEN (sizeof(WINDFS_PREFIX) / sizeof(WCHAR) - 1)
  762. #define MAX_QUERY_RETRY_CNT 16
  763. STATIC
  764. DWORD
  765. I_MartaFileHandleToNtDfsName(
  766. IN HANDLE hFile,
  767. OUT LPWSTR *ppwszNtObject
  768. )
  769. /*++
  770. Routine Description:
  771. Covert the given file handle for a DFS object into name. Allocates memory.
  772. Arguments:
  773. hFile - Handle for the DFS object.
  774. ppwszNtObject - To return the name of the DFS object.
  775. Return Value:
  776. ERROR_SUCCESS in case of success.
  777. ERROR_* otherwise
  778. Note:
  779. Couple of problems in the name returned by NtQueryObject for DFS objects:
  780. - Name contains 4 extra, bogus bytes (This is a BUG that should be fixed)
  781. - For logical drives, returns \Device\WinDfs\X:0\server\share. This
  782. needs to be converted to \Device\WinDfs\Root\server\share.
  783. Where X is the drive letter.
  784. This routine is called when it has already been determined the hFile
  785. refers to a DFS object name.
  786. --*/
  787. {
  788. NTSTATUS Status;
  789. DWORD dwErr;
  790. LPWSTR pwszNtObject = NULL;
  791. IO_STATUS_BLOCK IoStatusBlock;
  792. BYTE Buff[MAX_PATH * 4];
  793. PFILE_NAME_INFORMATION pAllocNI = NULL;
  794. PFILE_NAME_INFORMATION pNI; // not allocated
  795. LPWSTR pwszFileName;
  796. DWORD cchFileName;
  797. DWORD cchNtObject;
  798. ULONG cbNI;
  799. DWORD cRetry;
  800. pNI = (PFILE_NAME_INFORMATION) Buff;
  801. cbNI = sizeof(Buff);
  802. cRetry = 0;
  803. while (TRUE) {
  804. //
  805. // This returns the filename without the Nt Dfs object name prefix.
  806. //
  807. // Assumption: the returned filename always has a leading '\'.
  808. //
  809. Status = NtQueryInformationFile(
  810. hFile,
  811. &IoStatusBlock,
  812. pNI,
  813. cbNI,
  814. FileNameInformation
  815. );
  816. if (ERROR_SUCCESS == Status)
  817. break;
  818. if (!(Status == STATUS_BUFFER_TOO_SMALL ||
  819. Status == STATUS_INFO_LENGTH_MISMATCH ||
  820. Status == STATUS_BUFFER_OVERFLOW))
  821. goto StatusErrorReturn;
  822. if (++cRetry >= MAX_QUERY_RETRY_CNT)
  823. goto InvalidNameReturn;
  824. //
  825. // Double buffer length and retry
  826. //
  827. cbNI = cbNI * 2;
  828. I_MartaFileFree(pAllocNI);
  829. if (NULL == (pAllocNI = (PFILE_NAME_INFORMATION)
  830. I_MartaFileNonzeroAlloc(cbNI)))
  831. goto NotEnoughMemoryReturn;
  832. pNI = pAllocNI;
  833. }
  834. //
  835. // Compute the length of the buffer required to hold the name.
  836. //
  837. pwszFileName = pNI->FileName;
  838. cchFileName = pNI->FileNameLength / sizeof(WCHAR);
  839. if (0 == cchFileName)
  840. goto InvalidNameReturn;
  841. cchNtObject = WINDFS_PREFIX_LEN + cchFileName;
  842. //
  843. // Allocate memory.
  844. //
  845. if (NULL == (pwszNtObject = (LPWSTR) I_MartaFileNonzeroAlloc(
  846. (cchNtObject + 1) * sizeof(WCHAR))))
  847. goto NotEnoughMemoryReturn;
  848. //
  849. // Copy the prefix and the file name.
  850. //
  851. memcpy(pwszNtObject, WINDFS_PREFIX, WINDFS_PREFIX_LEN * sizeof(WCHAR));
  852. memcpy(pwszNtObject + WINDFS_PREFIX_LEN, pwszFileName,
  853. cchFileName * sizeof(WCHAR));
  854. pwszNtObject[cchNtObject] = L'\0';
  855. dwErr = ERROR_SUCCESS;
  856. CommonReturn:
  857. I_MartaFileFree(pAllocNI);
  858. *ppwszNtObject = pwszNtObject;
  859. return dwErr;
  860. StatusErrorReturn:
  861. dwErr = RtlNtStatusToDosError(Status);
  862. ErrorReturn:
  863. assert(NULL == pwszNtObject);
  864. assert(ERROR_SUCCESS != dwErr);
  865. if (ERROR_SUCCESS == dwErr)
  866. dwErr = ERROR_INTERNAL_ERROR;
  867. goto CommonReturn;
  868. NotEnoughMemoryReturn:
  869. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  870. goto ErrorReturn;
  871. InvalidNameReturn:
  872. dwErr = ERROR_INVALID_NAME;
  873. goto ErrorReturn;
  874. }
  875. STATIC
  876. BOOL
  877. I_MartaIsDfsJunctionPoint(
  878. IN MARTA_CONTEXT Context
  879. )
  880. /*++
  881. Routine Description:
  882. Determine whether this is a DFS junction point.
  883. Arguments:
  884. Context - Context for which the caller want to determine whether this is a
  885. dfs junction point.
  886. Return Value:
  887. TRUE if this is a DFS junction point.
  888. FALSE o/w.
  889. --*/
  890. {
  891. BOOL fDfsJunctionPoint = FALSE;
  892. LPWSTR pwszNtObject = NULL;
  893. DWORD cchNtObject;
  894. LPWSTR pwszDfs; // not allocated
  895. NET_API_STATUS NetStatus;
  896. LPBYTE pbNetInfo = NULL;
  897. if (ERROR_SUCCESS != MartaConvertFileContextToNtName(
  898. Context, &pwszNtObject))
  899. goto CommonReturn;
  900. //
  901. // Check the prefix.
  902. //
  903. if (0 != _wcsnicmp(pwszNtObject, WINDFS_PREFIX, WINDFS_PREFIX_LEN))
  904. goto CommonReturn;
  905. //
  906. // Convert the NtDfs name to a UNC name
  907. //
  908. pwszDfs = pwszNtObject + WINDFS_PREFIX_LEN - 1;
  909. *pwszDfs = L'\\';
  910. //
  911. // Assumption: the following is only successful for DFS junction point
  912. // filename.
  913. //
  914. NetStatus = NetDfsGetInfo(
  915. pwszDfs,
  916. NULL, // ServerName
  917. NULL, // ShareName
  918. 1,
  919. &pbNetInfo
  920. );
  921. if (0 == NetStatus) {
  922. fDfsJunctionPoint = TRUE;
  923. }
  924. CommonReturn:
  925. if (pwszNtObject)
  926. LocalFree(pwszNtObject);
  927. if (pbNetInfo)
  928. NetApiBufferFree(pbNetInfo);
  929. return fDfsJunctionPoint;
  930. }
  931. DWORD
  932. MartaConvertFileContextToNtName(
  933. IN MARTA_CONTEXT Context,
  934. OUT LPWSTR *ppwszNtObject
  935. )
  936. /*++
  937. Routine Description:
  938. Returns the NT Object Name for the given context. Allocates memory.
  939. Arguments:
  940. Context - Context for the file/dir.
  941. ppwszNtbject - To return the name of the file/dir.
  942. Return Value:
  943. ERROR_SUCCESS in case of success.
  944. ERROR_* otherwise
  945. --*/
  946. {
  947. DWORD dwErr = ERROR_SUCCESS;
  948. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  949. LPWSTR pwszNtObject = NULL;
  950. BYTE Buff[MAX_PATH * 4];
  951. ULONG cLen = 0;
  952. POBJECT_NAME_INFORMATION pNI; // not allocated
  953. POBJECT_NAME_INFORMATION pAllocNI = NULL;
  954. NTSTATUS Status;
  955. HANDLE hFile; // not opened
  956. LPWSTR pwszPath;
  957. DWORD cchPath;
  958. BOOL ExtraStep = FALSE;
  959. DWORD ExtraChars = 0;
  960. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  961. goto InvalidParameterReturn;
  962. hFile = pFileContext->hFile;
  963. //
  964. // The handle is invalid but we can still extract the name based on the
  965. // containing directory name and the basename for the child.
  966. //
  967. if (hFile == NULL)
  968. {
  969. ExtraStep = TRUE;
  970. hFile = pFileContext->pFileFindData->hDir;
  971. if (hFile == NULL)
  972. {
  973. goto InvalidParameterReturn;
  974. }
  975. //
  976. // Take into account the length needed for extra basename
  977. //
  978. ExtraChars = 1+ (pFileContext->pFileFindData->NamesInfoBuffer.NamesInfo.FileNameLength/sizeof(WCHAR));
  979. }
  980. //
  981. // First, determine the size of the buffer we need.
  982. //
  983. pNI = (POBJECT_NAME_INFORMATION) Buff;
  984. Status = NtQueryObject(hFile,
  985. ObjectNameInformation,
  986. pNI,
  987. sizeof(Buff),
  988. &cLen);
  989. if (!NT_SUCCESS(Status)) {
  990. if (Status == STATUS_BUFFER_TOO_SMALL ||
  991. Status == STATUS_INFO_LENGTH_MISMATCH ||
  992. Status == STATUS_BUFFER_OVERFLOW) {
  993. //
  994. // Allocate a big enough buffer
  995. //
  996. if (NULL == (pAllocNI = (POBJECT_NAME_INFORMATION)
  997. I_MartaFileNonzeroAlloc(cLen)))
  998. goto NotEnoughMemoryReturn;
  999. pNI = pAllocNI;
  1000. Status = NtQueryObject(hFile,
  1001. ObjectNameInformation,
  1002. pNI,
  1003. cLen,
  1004. NULL);
  1005. if (!NT_SUCCESS(Status))
  1006. goto StatusErrorReturn;
  1007. } else
  1008. goto StatusErrorReturn;
  1009. }
  1010. pwszPath = pNI->Name.Buffer;
  1011. cchPath = pNI->Name.Length / sizeof(WCHAR);
  1012. //
  1013. // For DFS names, call a helper routine.
  1014. //
  1015. if (WINDFS_DEVICE_LEN <= cchPath &&
  1016. 0 == _wcsnicmp(pwszPath, WINDFS_DEVICE, WINDFS_DEVICE_LEN))
  1017. dwErr = I_MartaFileHandleToNtDfsName(hFile, &pwszNtObject);
  1018. else {
  1019. //
  1020. // Allocate and return the name of the object.
  1021. //
  1022. if (NULL == (pwszNtObject = (LPWSTR) I_MartaFileNonzeroAlloc(
  1023. (cchPath + ExtraChars + 1) * sizeof(WCHAR))))
  1024. goto NotEnoughMemoryReturn;
  1025. memcpy(pwszNtObject, pwszPath, cchPath * sizeof(WCHAR));
  1026. //
  1027. // Add the basename if we really queried the directory instead of the child
  1028. // we were supposed to.
  1029. //
  1030. if (ExtraStep)
  1031. {
  1032. //
  1033. // Add a backslash only if needed.
  1034. //
  1035. if (pwszNtObject[cchPath-1] != L'\\')
  1036. {
  1037. pwszNtObject[cchPath] = L'\\';
  1038. memcpy(pwszNtObject+cchPath+1, pFileContext->pFileFindData->NamesInfoBuffer.NamesInfo.FileName, (ExtraChars-1)*sizeof(WCHAR));
  1039. pwszNtObject[cchPath+ExtraChars] = L'\0';
  1040. }
  1041. else
  1042. {
  1043. memcpy(pwszNtObject+cchPath, pFileContext->pFileFindData->NamesInfoBuffer.NamesInfo.FileName, (ExtraChars-1)*sizeof(WCHAR));
  1044. pwszNtObject[cchPath+ExtraChars-1] = L'\0';
  1045. }
  1046. }
  1047. else
  1048. {
  1049. pwszNtObject[cchPath] = L'\0';
  1050. }
  1051. dwErr = ERROR_SUCCESS;
  1052. }
  1053. CommonReturn:
  1054. I_MartaFileFree(pAllocNI);
  1055. *ppwszNtObject = pwszNtObject;
  1056. return dwErr;
  1057. StatusErrorReturn:
  1058. dwErr = RtlNtStatusToDosError(Status);
  1059. ErrorReturn:
  1060. assert(NULL == pwszNtObject);
  1061. assert(ERROR_SUCCESS != dwErr);
  1062. if (ERROR_SUCCESS == dwErr)
  1063. dwErr = ERROR_INTERNAL_ERROR;
  1064. goto CommonReturn;
  1065. NotEnoughMemoryReturn:
  1066. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1067. goto ErrorReturn;
  1068. InvalidParameterReturn:
  1069. dwErr = ERROR_INVALID_PARAMETER;
  1070. goto ErrorReturn;
  1071. }
  1072. DWORD
  1073. MartaGetFileProperties(
  1074. IN MARTA_CONTEXT Context,
  1075. IN OUT PMARTA_OBJECT_PROPERTIES pProperties
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. Return the properties for file/dir represented by the context.
  1080. Arguments:
  1081. Context - Context whose properties the caller has asked for.
  1082. pProperties - To return the properties for this file/dir.
  1083. Return Value:
  1084. ERROR_SUCCESS in case of success.
  1085. ERROR_* otherwise
  1086. --*/
  1087. {
  1088. DWORD dwErr = ERROR_SUCCESS;
  1089. NTSTATUS Status;
  1090. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  1091. IO_STATUS_BLOCK IoStatusBlock;
  1092. FILE_BASIC_INFORMATION BasicFileInfo;
  1093. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  1094. goto InvalidParameterReturn;
  1095. //
  1096. // Query the attributes for the file/dir.
  1097. // In case of error, assume that it is a dir.
  1098. //
  1099. if (!NT_SUCCESS(Status = NtQueryInformationFile(
  1100. pFileContext->hFile,
  1101. &IoStatusBlock,
  1102. &BasicFileInfo,
  1103. sizeof(BasicFileInfo),
  1104. FileBasicInformation)))
  1105. pProperties->dwFlags |= MARTA_OBJECT_IS_CONTAINER;
  1106. else if (BasicFileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1107. pProperties->dwFlags |= MARTA_OBJECT_IS_CONTAINER;
  1108. dwErr = ERROR_SUCCESS;
  1109. CommonReturn:
  1110. return dwErr;
  1111. ErrorReturn:
  1112. assert(ERROR_SUCCESS != dwErr);
  1113. if (ERROR_SUCCESS == dwErr)
  1114. dwErr = ERROR_INTERNAL_ERROR;
  1115. goto CommonReturn;
  1116. InvalidParameterReturn:
  1117. dwErr = ERROR_INVALID_PARAMETER;
  1118. goto ErrorReturn;
  1119. }
  1120. DWORD
  1121. MartaGetFileTypeProperties(
  1122. IN OUT PMARTA_OBJECT_TYPE_PROPERTIES pProperties
  1123. )
  1124. /*++
  1125. Routine Description:
  1126. Return the properties of file system objects.
  1127. Arguments:
  1128. pProperties - To return the properties of file system objects.
  1129. Return Value:
  1130. ERROR_SUCCESS.
  1131. --*/
  1132. {
  1133. const GENERIC_MAPPING GenMap = {
  1134. FILE_GENERIC_READ,
  1135. FILE_GENERIC_WRITE,
  1136. FILE_GENERIC_EXECUTE,
  1137. FILE_ALL_ACCESS
  1138. };
  1139. //
  1140. // Propagation to be done on the client side.
  1141. //
  1142. pProperties->dwFlags |= MARTA_OBJECT_TYPE_MANUAL_PROPAGATION_NEEDED_FLAG;
  1143. //
  1144. // Tree organization of obects is present.
  1145. //
  1146. pProperties->dwFlags |= MARTA_OBJECT_TYPE_INHERITANCE_MODEL_PRESENT_FLAG;
  1147. //
  1148. // Return the generic mapping too.
  1149. //
  1150. pProperties->GenMap = GenMap;
  1151. return ERROR_SUCCESS;
  1152. }
  1153. DWORD
  1154. MartaGetFileRights(
  1155. IN MARTA_CONTEXT Context,
  1156. IN SECURITY_INFORMATION SecurityInfo,
  1157. OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. Get the security descriptor for the given handle.
  1162. Arguments:
  1163. Context - Context for file/dir.
  1164. SecurityInfo - Type of security information to be read.
  1165. ppSecurityDescriptor - To return a self-relative security decriptor pointer.
  1166. Return Value:
  1167. ERROR_SUCCESS in case of success.
  1168. ERROR_* otherwise
  1169. --*/
  1170. {
  1171. BOOL fResult;
  1172. DWORD dwErr = ERROR_SUCCESS;
  1173. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  1174. DWORD cbSize;
  1175. PISECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  1176. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  1177. goto InvalidParameterReturn;
  1178. //
  1179. // First, get the size we need
  1180. //
  1181. cbSize = 0;
  1182. if (GetKernelObjectSecurity(
  1183. pFileContext->hFile,
  1184. SecurityInfo,
  1185. NULL, // pSecDesc
  1186. 0,
  1187. &cbSize
  1188. ))
  1189. goto InternalErrorReturn;
  1190. dwErr = GetLastError();
  1191. if (ERROR_INSUFFICIENT_BUFFER == dwErr) {
  1192. if (NULL == (pSecurityDescriptor =
  1193. (PISECURITY_DESCRIPTOR) I_MartaFileNonzeroAlloc(cbSize)))
  1194. goto NotEnoughMemoryReturn;
  1195. //
  1196. // Now get the security descriptor.
  1197. //
  1198. if (!GetKernelObjectSecurity(
  1199. pFileContext->hFile,
  1200. SecurityInfo,
  1201. pSecurityDescriptor,
  1202. cbSize,
  1203. &cbSize
  1204. ))
  1205. goto LastErrorReturn;
  1206. } else
  1207. goto ErrorReturn;
  1208. dwErr = ERROR_SUCCESS;
  1209. CommonReturn:
  1210. *ppSecurityDescriptor = pSecurityDescriptor;
  1211. return dwErr;
  1212. LastErrorReturn:
  1213. dwErr = GetLastError();
  1214. ErrorReturn:
  1215. if (pSecurityDescriptor) {
  1216. I_MartaFileFree(pSecurityDescriptor);
  1217. pSecurityDescriptor = NULL;
  1218. }
  1219. assert(ERROR_SUCCESS != dwErr);
  1220. if (ERROR_SUCCESS == dwErr)
  1221. dwErr = ERROR_INTERNAL_ERROR;
  1222. goto CommonReturn;
  1223. NotEnoughMemoryReturn:
  1224. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1225. goto ErrorReturn;
  1226. InvalidParameterReturn:
  1227. dwErr = ERROR_INVALID_PARAMETER;
  1228. goto ErrorReturn;
  1229. InternalErrorReturn:
  1230. dwErr = ERROR_INTERNAL_ERROR;
  1231. goto ErrorReturn;
  1232. }
  1233. DWORD
  1234. MartaSetFileRights(
  1235. IN MARTA_CONTEXT Context,
  1236. IN SECURITY_INFORMATION SecurityInfo,
  1237. IN PSECURITY_DESCRIPTOR pSecurityDescriptor
  1238. )
  1239. /*++
  1240. Routine Description:
  1241. Set the given security descriptor on the file/dir represented by the context.
  1242. Arguments:
  1243. Context - Context for the file/dir.
  1244. SecurityInfo - Type of security info to be stamped on the file/dir.
  1245. pSecurityDescriptor - Security descriptor to be stamped.
  1246. Return Value:
  1247. ERROR_SUCCESS in case of success.
  1248. ERROR_* otherwise
  1249. --*/
  1250. {
  1251. DWORD dwErr;
  1252. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  1253. //
  1254. // Basic validation on the context.
  1255. //
  1256. if (NULL == pFileContext || 0 == pFileContext->dwRefCnt)
  1257. goto InvalidParameterReturn;
  1258. //
  1259. // Set the security on the file/dir.
  1260. //
  1261. if (!SetKernelObjectSecurity(
  1262. pFileContext->hFile,
  1263. SecurityInfo,
  1264. pSecurityDescriptor
  1265. ))
  1266. goto LastErrorReturn;
  1267. dwErr = ERROR_SUCCESS;
  1268. CommonReturn:
  1269. return dwErr;
  1270. InvalidParameterReturn:
  1271. dwErr = ERROR_INVALID_PARAMETER;
  1272. goto CommonReturn;
  1273. LastErrorReturn:
  1274. dwErr = GetLastError();
  1275. if (ERROR_SUCCESS == dwErr)
  1276. dwErr = ERROR_INTERNAL_ERROR;
  1277. goto CommonReturn;
  1278. }
  1279. ACCESS_MASK
  1280. MartaGetFileDesiredAccess(
  1281. IN SECURITY_OPEN_TYPE OpenType,
  1282. IN BOOL Attribs,
  1283. IN SECURITY_INFORMATION SecurityInfo
  1284. )
  1285. /*++
  1286. Routine Description:
  1287. Gets the access required to open object to be able to set or get the
  1288. specified security info.
  1289. Arguments:
  1290. OpenType - Flag indicating if the object is to be opened to read or write
  1291. the security information
  1292. Attribs - TRUE indicates that additional access bits should be returned.
  1293. SecurityInfo - owner/group/dacl/sacl
  1294. Return Value:
  1295. Desired access mask with which open should be called.
  1296. --*/
  1297. {
  1298. ACCESS_MASK DesiredAccess = 0;
  1299. if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
  1300. (SecurityInfo & GROUP_SECURITY_INFORMATION) )
  1301. {
  1302. switch (OpenType)
  1303. {
  1304. case READ_ACCESS_RIGHTS:
  1305. DesiredAccess |= READ_CONTROL;
  1306. break;
  1307. case WRITE_ACCESS_RIGHTS:
  1308. DesiredAccess |= WRITE_OWNER;
  1309. break;
  1310. case MODIFY_ACCESS_RIGHTS:
  1311. DesiredAccess |= READ_CONTROL | WRITE_OWNER;
  1312. break;
  1313. }
  1314. }
  1315. if (SecurityInfo & DACL_SECURITY_INFORMATION)
  1316. {
  1317. switch (OpenType)
  1318. {
  1319. case READ_ACCESS_RIGHTS:
  1320. DesiredAccess |= READ_CONTROL;
  1321. break;
  1322. case WRITE_ACCESS_RIGHTS:
  1323. DesiredAccess |= WRITE_DAC;
  1324. break;
  1325. case MODIFY_ACCESS_RIGHTS:
  1326. DesiredAccess |= READ_CONTROL | WRITE_DAC;
  1327. break;
  1328. }
  1329. }
  1330. if (SecurityInfo & SACL_SECURITY_INFORMATION)
  1331. {
  1332. DesiredAccess |= READ_CONTROL | ACCESS_SYSTEM_SECURITY;
  1333. }
  1334. //
  1335. // ONLY FOR FILES.
  1336. //
  1337. if (Attribs)
  1338. {
  1339. DesiredAccess |= FILE_READ_ATTRIBUTES | READ_CONTROL;
  1340. }
  1341. return (DesiredAccess);
  1342. }
  1343. DWORD
  1344. MartaReopenFileContext(
  1345. IN OUT MARTA_CONTEXT Context,
  1346. IN ACCESS_MASK AccessMask
  1347. )
  1348. /*++
  1349. Routine Description:
  1350. Given the context for a file/dir, close the existing handle if one exists
  1351. and reopen the context with new permissions.
  1352. Arguments:
  1353. Context - Context to be reopened.
  1354. AccessMask - Permissions for the reopen.
  1355. Return Value:
  1356. ERROR_SUCCESS in case of success.
  1357. ERROR_* otherwise
  1358. --*/
  1359. {
  1360. DWORD dwErr = ERROR_SUCCESS;
  1361. PFILE_CONTEXT pFileContext = (PFILE_CONTEXT) Context;
  1362. //
  1363. // Following don't need to be freed or closed
  1364. //
  1365. PFILE_FIND_DATA pFileFindData;
  1366. IO_STATUS_BLOCK IoStatusBlock;
  1367. PFILE_NAMES_INFORMATION pNamesInfo;
  1368. HANDLE hDir;
  1369. UNICODE_STRING FileName;
  1370. //
  1371. // VishnuP: Bug #384222 (AV since Context == NULL).
  1372. // In MartaUpdateTree(), we don't error in case the
  1373. // ChildContext is NULL so return here too with success
  1374. //
  1375. if ( NULL == Context)
  1376. {
  1377. return ERROR_SUCCESS;
  1378. }
  1379. //
  1380. // Extract the data needed to open the file.
  1381. //
  1382. pFileFindData = pFileContext->pFileFindData;
  1383. hDir = pFileFindData->hDir;
  1384. pNamesInfo = &pFileFindData->NamesInfoBuffer.NamesInfo;
  1385. FileName.Length = (USHORT) pNamesInfo->FileNameLength;
  1386. FileName.MaximumLength = (USHORT) FileName.Length;
  1387. FileName.Buffer = pNamesInfo->FileName;
  1388. //
  1389. // Close the original handle. We do not expect to hit this given the way
  1390. // the code is organized now.
  1391. //
  1392. if (pFileContext->dwFlags & FILE_CONTEXT_CLOSE_HANDLE_FLAG)
  1393. {
  1394. NtClose(pFileContext->hFile);
  1395. pFileContext->hFile = NULL;
  1396. pFileContext->dwFlags &= ~FILE_CONTEXT_CLOSE_HANDLE_FLAG;
  1397. }
  1398. //
  1399. // Open the file with the access mask desired.
  1400. //
  1401. dwErr = I_MartaFileNtOpenFile(
  1402. &FileName,
  1403. hDir,
  1404. AccessMask,
  1405. pFileContext
  1406. );
  1407. //
  1408. // In case of a successful open mark the context.
  1409. //
  1410. if (ERROR_SUCCESS == dwErr)
  1411. {
  1412. pFileContext->dwFlags |= FILE_CONTEXT_CLOSE_HANDLE_FLAG;
  1413. }
  1414. return dwErr;
  1415. }
  1416. DWORD
  1417. MartaReopenFileOrigContext(
  1418. IN OUT MARTA_CONTEXT Context,
  1419. IN ACCESS_MASK AccessMask
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. This is a dummy routine.
  1424. Arguments:
  1425. Are ignored.
  1426. Return Value:
  1427. ERROR_SUCCESS
  1428. Note:
  1429. The context structure must be left untouched.
  1430. --*/
  1431. {
  1432. //
  1433. // This is a dummy routine. The real reopen is done by MartaFindFirstFile
  1434. // that is called just after this call. The context contains a valid handle
  1435. // which was used to set a new DACL on the file/dir.
  1436. //
  1437. return ERROR_SUCCESS;
  1438. }
  1439. DWORD
  1440. MartaGetFileNameFromContext(
  1441. IN LPWSTR DosName,
  1442. IN LPWSTR NtName,
  1443. IN MARTA_CONTEXT Context,
  1444. OUT LPWSTR *pObjectName
  1445. )
  1446. /*++
  1447. Routine Description:
  1448. Get the name of the file/dir from the context. This routine allocates
  1449. memory required to hold the name of the object.
  1450. Arguments:
  1451. DosName - Dos name of the root of the tree. When this is NULL, return the
  1452. NtName as returned by the internal API.
  1453. NtName - NtName for the root of the tree.
  1454. Context - Handle to the context.
  1455. pObjectName - To return the pointer to the allocated string.
  1456. Return Value:
  1457. ERROR_SUCCESS in case of success.
  1458. ERROR_* otherwise
  1459. --*/
  1460. {
  1461. DWORD dwErr;
  1462. DWORD Length = 0;
  1463. DWORD LengthDiff = 0;
  1464. LPWSTR Str = NULL;
  1465. LPWSTR RetStr = NULL;
  1466. *pObjectName = NULL;
  1467. //
  1468. // Get the name in Nt format.
  1469. //
  1470. dwErr = MartaConvertFileContextToNtName(Context, &Str);
  1471. if (dwErr != ERROR_SUCCESS)
  1472. {
  1473. return dwErr;
  1474. }
  1475. //
  1476. // This is a special case to get the Nt name for the root of the subtree.
  1477. //
  1478. if ((DosName == NULL) || (NtName == NULL))
  1479. {
  1480. *pObjectName = Str;
  1481. return ERROR_SUCCESS;
  1482. }
  1483. //
  1484. // Compute the length needed to fit the Dosname.
  1485. //
  1486. LengthDiff = wcslen(NtName);
  1487. Length = 1 + wcslen(DosName) + wcslen(Str) - LengthDiff;
  1488. RetStr = (LPWSTR) LocalAlloc(LMEM_FIXED, Length * sizeof(WCHAR));
  1489. if (RetStr == NULL)
  1490. {
  1491. LocalFree(Str);
  1492. return ERROR_NOT_ENOUGH_MEMORY;
  1493. }
  1494. //
  1495. // Copy the prefix, followed by the suffix.
  1496. //
  1497. wcscpy(RetStr, DosName);
  1498. wcscat(RetStr, Str + LengthDiff);
  1499. LocalFree(Str);
  1500. *pObjectName = RetStr;
  1501. return ERROR_SUCCESS;
  1502. }
  1503. DWORD
  1504. MartaGetFileParentName(
  1505. IN LPWSTR ObjectName,
  1506. OUT LPWSTR *pParentName
  1507. )
  1508. /*++
  1509. Routine Description:
  1510. Given the name of a file/dir return the name of its parent. The routine
  1511. allocates memory required to hold the parent name.
  1512. Arguments:
  1513. ObjectName - Name of the file/dir.
  1514. pParentName - To return the pointer to the allocated parent name.
  1515. In case of the root of the tree, we return NULL parent with ERROR_SUCCESS.
  1516. Return Value:
  1517. ERROR_SUCCESS in case of success.
  1518. ERROR_* otherwise
  1519. --*/
  1520. {
  1521. ULONG Length = wcslen(ObjectName) + 1;
  1522. PWCHAR Name = (PWCHAR) I_MartaFileNonzeroAlloc(sizeof(WCHAR) * Length);
  1523. DWORD dwErr = ERROR_SUCCESS;
  1524. *pParentName = NULL;
  1525. if (!Name)
  1526. {
  1527. return ERROR_NOT_ENOUGH_MEMORY;
  1528. }
  1529. //
  1530. // Copy the name of the object into the allocated buffer.
  1531. //
  1532. wcscpy((WCHAR *) Name, ObjectName);
  1533. //
  1534. // Convert the object name intp its parent name.
  1535. //
  1536. dwErr = I_MartaFileGetNtParentString(Name);
  1537. if (ERROR_SUCCESS != dwErr)
  1538. {
  1539. I_MartaFileFree(Name);
  1540. //
  1541. // This is the root of the tree which does not have a parent. Return
  1542. // ERROR_SUCCESS with ParentName as NULL.
  1543. //
  1544. if (ERROR_INVALID_NAME == dwErr)
  1545. return ERROR_SUCCESS;
  1546. return dwErr;
  1547. }
  1548. *pParentName = Name;
  1549. return dwErr;
  1550. }