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.

1026 lines
24 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. lsaux.cxx
  5. Abstract:
  6. This modules defines the functions supporting list processing.
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 2-May-1995
  9. Environment:
  10. User Mode -- Win32
  11. Project:
  12. FTP Server DLL
  13. Functions Exported:
  14. Revision History:
  15. --*/
  16. /************************************************************
  17. * Include Headers
  18. ************************************************************/
  19. # include "ftpdp.hxx"
  20. # include "lsaux.hxx"
  21. /************************************************************
  22. * Functions
  23. ************************************************************/
  24. const FILETIME *
  25. PickFileTime(IN const WIN32_FIND_DATA * pfdInfo,
  26. IN const LS_OPTIONS * pOptions)
  27. /*++
  28. This function selects and returns proper FILETIME structure
  29. to display based on the current sort method and filesystem
  30. capabilities.
  31. Arguments:
  32. pfdInfo pointer to file information for a directory entry.
  33. pOptions the current ls options
  34. Returns:
  35. FILETIME -- pointer to proper time required
  36. History:
  37. MuraliK 25-Apr-1995
  38. This is a costly operation too. Given that this one is called once every
  39. directory entry is getting formatted. Can we avoid the cost ?
  40. YES, if we can use the offsets in the pfdInfo to chose the time object.
  41. NYI
  42. --*/
  43. {
  44. const FILETIME * pliTime;
  45. switch ( pOptions->SortMethod) {
  46. case LsSortByName:
  47. case LsSortByWriteTime:
  48. pliTime = &pfdInfo->ftLastWriteTime;
  49. break;
  50. case LsSortByCreationTime:
  51. pliTime = &pfdInfo->ftCreationTime;
  52. break;
  53. case LsSortByAccessTime:
  54. pliTime = &pfdInfo->ftLastAccessTime;
  55. break;
  56. default:
  57. IF_DEBUG( ERROR) {
  58. DBGPRINTF(( DBG_CONTEXT,
  59. "Invalid Sort %d!\n", pOptions->SortMethod ));
  60. }
  61. DBG_ASSERT( FALSE );
  62. pliTime = &pfdInfo->ftLastWriteTime;
  63. break;
  64. } // switch()
  65. //
  66. // If the selected time field is not supported on
  67. // the current filesystem, default to ftLastWriteTime
  68. // (all filesystems support this field).
  69. //
  70. if( NULL_FILE_TIME( *pliTime ) ) {
  71. pliTime = &pfdInfo->ftLastWriteTime;
  72. }
  73. return ( pliTime);
  74. } // PickFileTime()
  75. BOOL __cdecl
  76. FtpFilterFileInfo(
  77. IN const WIN32_FIND_DATA * pfdInfo,
  78. IN LPVOID pContext
  79. )
  80. /*++
  81. This function tries to filter out the file information using
  82. Ftp service "ls" specific filter.
  83. Arguments:
  84. pfdInfo pointer to file information that contains the current
  85. file information object for filtering.
  86. pContext pointer to FTP_LS_FILTER_INFO used for filtering.
  87. Returns:
  88. TRUE if there is a match and that this file info should not be
  89. eliminated.
  90. FALSE if this file info object can be dropped out of generated list.
  91. --*/
  92. {
  93. register FTP_LS_FILTER_INFO * pfls = (FTP_LS_FILTER_INFO *) pContext;
  94. DWORD dwAttribs;
  95. BOOL fReturn;
  96. if ( pfdInfo == NULL ||
  97. pfdInfo->dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
  98. return ( FALSE);
  99. }
  100. //
  101. // We dont need to expose hidden/system files unless necessary.
  102. //
  103. dwAttribs = pfdInfo->dwFileAttributes;
  104. if (pfls->fFilterHidden && IS_HIDDEN( dwAttribs) ||
  105. pfls->fFilterSystem && IS_SYSTEM( dwAttribs)) {
  106. return ( FALSE); // unwanted files.
  107. }
  108. // Always filter away "." and ".."
  109. const CHAR * pszFileName = ( pfdInfo->cFileName);
  110. if (pfls->fFilterDotDot && pszFileName[0] == '.' ||
  111. strcmp( pszFileName, ".") == 0 ||
  112. strcmp( pszFileName, "..") == 0) {
  113. return ( FALSE);
  114. }
  115. DBG_ASSERT( pfls->pszExpression == NULL || *pfls->pszExpression != '\0');
  116. //
  117. // Check about the file name.
  118. // If the expression is not a regular expression, use simple StringCompare
  119. // else use a regular expression comparison.
  120. // Return TRUE if there is a match else return FALSE.
  121. //
  122. return ( pfls->pszExpression == NULL || // null-expr ==> all match.
  123. (( pfls->fRegExpression)
  124. ? IsNameInRegExpressionA(pfls->pszExpression, pszFileName,
  125. pfls->fIgnoreCase)
  126. : !strcmp(pszFileName, pfls->pszExpression)
  127. ));
  128. } // FtpFilterFileInfo()
  129. APIERR
  130. GetDirectoryInfo(
  131. IN LPUSER_DATA pUserData,
  132. OUT TS_DIRECTORY_INFO * pTsDirInfo,
  133. IN CHAR * pszSearchPath,
  134. IN const FTP_LS_FILTER_INFO * pfls,
  135. IN PFN_CMP_WIN32_FIND_DATA pfnCompare
  136. )
  137. /*++
  138. This function creates a directory listing for given directory,
  139. filters out unmatched files and sorts the resulting elements
  140. using the sort function.
  141. Arguments:
  142. pUserData pointer to UserData structure.
  143. pTsDirInfo pointer to Directory Information object that will be
  144. filled in with the directory information.
  145. pszSearchPath pointer to null-terminated string containing
  146. the absolute path for directory along with
  147. the possible filter specification.
  148. eg: d:\foo\bar
  149. pfls pointer to filter information used for filtering.
  150. pfnCompare pointer to function used for sorting.
  151. Returns:
  152. NO_ERROR on success and Win32 error code if there are any failure.
  153. History:
  154. MuraliK 25-Apr-1995
  155. --*/
  156. {
  157. DWORD dwError = NO_ERROR;
  158. DBG_ASSERT( pTsDirInfo != NULL && pszSearchPath != NULL);
  159. DBG_ASSERT( !pTsDirInfo->IsValid()); // no dir list yet.
  160. IF_DEBUG(DIR_LIST) {
  161. DBGPRINTF((DBG_CONTEXT,
  162. "GetDirListing( dir=%s, Filter=%08x (Sz=%s), "
  163. "user=%08x, cmp=%08x)\n",
  164. pszSearchPath, pfls, pfls->pszExpression,
  165. pUserData->QueryUserToken(), pfnCompare));
  166. }
  167. CHAR rgDirPath[MAX_PATH+10];
  168. CHAR * pszDirPath;
  169. DWORD len = strlen( pszSearchPath);
  170. // check to see if the last character is a "\" in the dir path
  171. // if not append one to make sure GetDirectoryListing works fine.
  172. if ( *CharPrev( pszSearchPath, pszSearchPath + len ) != '\\') {
  173. DBG_ASSERT( len < sizeof(rgDirPath) - 2);
  174. wsprintf( rgDirPath, "%s\\", pszSearchPath);
  175. pszDirPath = rgDirPath;
  176. } else {
  177. pszDirPath = pszSearchPath;
  178. }
  179. if ( !pTsDirInfo->GetDirectoryListingA(pszDirPath,
  180. pUserData->QueryUserToken())
  181. ) {
  182. dwError = GetLastError();
  183. }
  184. if ( dwError == NO_ERROR) {
  185. //
  186. // we got the directory listing.
  187. // We need to apply filters to restrict the directory listing.
  188. // Next we need to sort the resulting mix based on the
  189. // sorting options requested by the list command.
  190. //
  191. //
  192. // We need to identify the appropriate filter
  193. // file spec to be applied. For present use *.*
  194. // Filtering should not fail unless tsDirInfo is invalid.
  195. //
  196. if ( pfls != NULL) {
  197. DBG_REQUIRE(pTsDirInfo->FilterFiles(FtpFilterFileInfo,
  198. (LPVOID )pfls)
  199. );
  200. }
  201. //
  202. // Sort only if sort function specified
  203. //
  204. if ( pfnCompare != NULL) {
  205. DBG_REQUIRE( pTsDirInfo->SortFileInfoPointers( pfnCompare));
  206. }
  207. }
  208. return ( dwError);
  209. } // GetDirectoryInfo()
  210. /**************************************************
  211. * Comparison Functions
  212. **************************************************/
  213. int __cdecl
  214. CompareNamesInFileInfo(
  215. IN const void * pvFileInfo1,
  216. IN const void * pvFileInfo2)
  217. /*++
  218. Compares the two directory entries by name of the files.
  219. Arguments:
  220. pvFileInfo1 pointer to FileBothDirInfo object 1.
  221. pvFileInfo2 pointer to FileBothDirInfo object 2.
  222. Returns:
  223. 0 if they are same
  224. +1 if pvFileInfo1 > pvFileInfo2
  225. -1 if pvFileInfo1 < pvFileInfo2
  226. History:
  227. MuraliK 25-Apr-1995
  228. --*/
  229. {
  230. const WIN32_FIND_DATA * pFileInfo1 =
  231. *((const WIN32_FIND_DATA **) pvFileInfo1);
  232. const WIN32_FIND_DATA * pFileInfo2 =
  233. *((const WIN32_FIND_DATA **) pvFileInfo2);
  234. ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
  235. return ( lstrcmpi((LPCSTR )pFileInfo1->cFileName,
  236. (LPCSTR )pFileInfo2->cFileName));
  237. } // CompareNamesInFileInfo()
  238. int __cdecl
  239. CompareNamesRevInFileInfo(
  240. IN const void * pvFileInfo1,
  241. IN const void * pvFileInfo2)
  242. /*++
  243. Compares the two directory entries by name of the files.
  244. Arguments:
  245. pvFileInfo1 pointer to FileBothDirInfo object 1.
  246. pvFileInfo2 pointer to FileBothDirInfo object 2.
  247. Returns:
  248. 0 if they are same
  249. -1 if pvFileInfo1 > pvFileInfo2
  250. +1 if pvFileInfo1 < pvFileInfo2
  251. History:
  252. MuraliK 25-Apr-1995
  253. --*/
  254. {
  255. return -CompareNamesInFileInfo( pvFileInfo1, pvFileInfo2);
  256. } // CompareNamesRevInFileInfo()
  257. int __cdecl
  258. CompareWriteTimesInFileInfo(
  259. IN const void * pvFileInfo1,
  260. IN const void * pvFileInfo2)
  261. /*++
  262. Compares the write times of two directory entries.
  263. Arguments:
  264. pvFileInfo1 pointer to FileBothDirInfo object 1.
  265. pvFileInfo2 pointer to FileBothDirInfo object 2.
  266. Returns:
  267. 0 if they are same
  268. +1 if pvFileInfo1 > pvFileInfo2
  269. -1 if pvFileInfo1 < pvFileInfo2
  270. History:
  271. MuraliK 25-Apr-1995
  272. --*/
  273. {
  274. const WIN32_FIND_DATA * pFileInfo1 =
  275. *((const WIN32_FIND_DATA **) pvFileInfo1);
  276. const WIN32_FIND_DATA * pFileInfo2 =
  277. *((const WIN32_FIND_DATA **) pvFileInfo2);
  278. ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
  279. INT nResult;
  280. nResult = CompareFileTime(&pFileInfo1->ftLastWriteTime,
  281. &pFileInfo2->ftLastWriteTime );
  282. if( nResult == 0 ) {
  283. nResult = CompareNamesInFileInfo( pvFileInfo1, pvFileInfo2);
  284. }
  285. return nResult;
  286. } // CompareWriteTimesInFileInfo()
  287. int __cdecl
  288. CompareWriteTimesRevInFileInfo(
  289. IN const void * pvFileInfo1,
  290. IN const void * pvFileInfo2)
  291. /*++
  292. Compares the write times of two directory entries.
  293. Arguments:
  294. pvFileInfo1 pointer to FileBothDirInfo object 1.
  295. pvFileInfo2 pointer to FileBothDirInfo object 2.
  296. Returns:
  297. 0 if they are same
  298. -1 if pvFileInfo1 > pvFileInfo2
  299. +1 if pvFileInfo1 < pvFileInfo2
  300. History:
  301. MuraliK 25-Apr-1995
  302. --*/
  303. {
  304. return -CompareWriteTimesInFileInfo( pvFileInfo1, pvFileInfo2);
  305. } // CompareWriteTimesRevInFileInfo()
  306. int __cdecl
  307. CompareCreationTimesInFileInfo(
  308. IN const void * pvFileInfo1,
  309. IN const void * pvFileInfo2)
  310. /*++
  311. Compares the creation times of two directory entries.
  312. Arguments:
  313. pvFileInfo1 pointer to FileBothDirInfo object 1.
  314. pvFileInfo2 pointer to FileBothDirInfo object 2.
  315. Returns:
  316. 0 if they are same
  317. +1 if pvFileInfo1 > pvFileInfo2
  318. -1 if pvFileInfo1 < pvFileInfo2
  319. History:
  320. MuraliK 25-Apr-1995
  321. --*/
  322. {
  323. const WIN32_FIND_DATA * pFileInfo1 =
  324. *((const WIN32_FIND_DATA **) pvFileInfo1);
  325. const WIN32_FIND_DATA * pFileInfo2 =
  326. *((const WIN32_FIND_DATA **) pvFileInfo2);
  327. ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
  328. INT nResult;
  329. if ( NULL_FILE_TIME( pFileInfo1->ftCreationTime)) {
  330. nResult = CompareFileTime(&pFileInfo1->ftLastWriteTime,
  331. &pFileInfo2->ftLastWriteTime );
  332. } else {
  333. nResult = CompareFileTime(&pFileInfo1->ftCreationTime,
  334. &pFileInfo2->ftCreationTime );
  335. }
  336. if( nResult == 0 ) {
  337. nResult = CompareNamesInFileInfo( pvFileInfo1, pvFileInfo2);
  338. }
  339. return nResult;
  340. } // CompareCreationTimesInFileInfo()
  341. int __cdecl
  342. CompareCreationTimesRevInFileInfo(
  343. IN const void * pvFileInfo1,
  344. IN const void * pvFileInfo2)
  345. /*++
  346. Compares the creation times of two directory entries.
  347. Arguments:
  348. pvFileInfo1 pointer to FileBothDirInfo object 1.
  349. pvFileInfo2 pointer to FileBothDirInfo object 2.
  350. Returns:
  351. 0 if they are same
  352. +1 if pvFileInfo1 > pvFileInfo2
  353. -1 if pvFileInfo1 < pvFileInfo2
  354. History:
  355. MuraliK 25-Apr-1995
  356. --*/
  357. {
  358. return -CompareCreationTimesInFileInfo( pvFileInfo1, pvFileInfo2 );
  359. } // CompareCreationTimesRevInFileInfo()
  360. int __cdecl
  361. CompareAccessTimesInFileInfo(
  362. IN const void * pvFileInfo1,
  363. IN const void * pvFileInfo2)
  364. /*++
  365. Compares the last access times of two directory entries.
  366. Arguments:
  367. pvFileInfo1 pointer to FileBothDirInfo object 1.
  368. pvFileInfo2 pointer to FileBothDirInfo object 2.
  369. Returns:
  370. 0 if they are same
  371. +1 if pvFileInfo1 > pvFileInfo2
  372. -1 if pvFileInfo1 < pvFileInfo2
  373. History:
  374. MuraliK 25-Apr-1995
  375. --*/
  376. {
  377. const WIN32_FIND_DATA * pFileInfo1 =
  378. *((const WIN32_FIND_DATA **) pvFileInfo1);
  379. const WIN32_FIND_DATA * pFileInfo2 =
  380. *((const WIN32_FIND_DATA **) pvFileInfo2);
  381. ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
  382. INT nResult;
  383. if ( NULL_FILE_TIME( pFileInfo1->ftLastAccessTime)) {
  384. nResult = CompareFileTime(&pFileInfo1->ftLastWriteTime,
  385. &pFileInfo2->ftLastWriteTime );
  386. } else {
  387. nResult = CompareFileTime(&pFileInfo1->ftLastAccessTime,
  388. &pFileInfo2->ftLastAccessTime );
  389. }
  390. if( nResult == 0 ) {
  391. nResult = CompareNamesInFileInfo( pvFileInfo1, pvFileInfo2);
  392. }
  393. return nResult;
  394. } // CompareAccessTimesInFileInfo()
  395. int __cdecl
  396. CompareAccessTimesRevInFileInfo(
  397. IN const void * pvFileInfo1,
  398. IN const void * pvFileInfo2)
  399. /*++
  400. Compares the last access times of two directory entries.
  401. Arguments:
  402. pvFileInfo1 pointer to FileBothDirInfo object 1.
  403. pvFileInfo2 pointer to FileBothDirInfo object 2.
  404. Returns:
  405. 0 if they are same
  406. +1 if pvFileInfo1 > pvFileInfo2
  407. -1 if pvFileInfo1 < pvFileInfo2
  408. History:
  409. MuraliK 25-Apr-1995
  410. --*/
  411. {
  412. return -CompareAccessTimesInFileInfo( pvFileInfo1, pvFileInfo2 );
  413. } // CompareAccessTimesRevInFileInfo()
  414. DWORD
  415. ComputeModeBits(
  416. IN HANDLE hUserToken,
  417. IN const CHAR * pszPathPart,
  418. IN const WIN32_FIND_DATA * pfdInfo,
  419. IN DWORD * pcLinks,
  420. IN BOOL fVolumeReadable,
  421. IN BOOL fVolumeWritable
  422. )
  423. /*++
  424. This function computes the mode buts r-w-x for a specific file.
  425. Arguments:
  426. hUserToken - The security token of the user that initiated the request.
  427. pszPathPart - contains the search path for this directory.
  428. pfdInfo - pointer to File information
  429. pcLinks - will receive the count of symbolic links to this file.
  430. fVolumeReadable - TRUE if volume is readable
  431. fVolumeWritable - TRUE if volume is writable
  432. Returns:
  433. DWORD - A combination of FILE_MODE_R, FILE_MODE_W, and FILE_MODE_X bits.
  434. HISTORY:
  435. KeithMo 01-Jun-1993 Created.
  436. MuraliK 26-Apr-1995 Modified to support new pfdInfo
  437. --*/
  438. {
  439. APIERR err;
  440. DWORD dwAccess;
  441. DWORD dwMode = 0;
  442. DBG_ASSERT( hUserToken != NULL );
  443. DBG_ASSERT( pszPathPart != NULL );
  444. DBG_ASSERT( pfdInfo != NULL );
  445. DBG_ASSERT( pcLinks != NULL );
  446. DBG_ASSERT( pszPathPart[1] == ':' );
  447. DBG_ASSERT( pszPathPart[2] == '\\' );
  448. if( !( GetFsFlags( *pszPathPart ) & FS_PERSISTENT_ACLS ) )
  449. {
  450. //
  451. // Short-circuit if on a non-NTFS partition.
  452. //
  453. *pcLinks = 1;
  454. dwAccess = FILE_ALL_ACCESS;
  455. err = NO_ERROR;
  456. }
  457. else
  458. {
  459. CHAR szPath[MAX_PATH*2];
  460. CHAR * pszEnd;
  461. INT len;
  462. //
  463. // Determine the maximum file access allowed.
  464. //
  465. DBG_ASSERT( strlen( pszPathPart) +
  466. strlen( pfdInfo->cFileName) < MAX_PATH * 2);
  467. len = strlen( pszPathPart );
  468. memcpy( szPath, pszPathPart, len );
  469. szPath[len] = '\0';
  470. pszEnd = CharPrev( szPath, szPath + len );
  471. if( *pszEnd != '\\' && *pszEnd != '/' ) {
  472. pszEnd = szPath + len;
  473. *pszEnd = '\\';
  474. }
  475. strcpy( pszEnd + 1, pfdInfo->cFileName );
  476. err = ComputeFileInfo( hUserToken,
  477. szPath,
  478. &dwAccess,
  479. pcLinks );
  480. }
  481. if( err == NO_ERROR )
  482. {
  483. //
  484. // Map various NT access to unix-like mode bits.
  485. //
  486. if( fVolumeReadable && ( dwAccess & FILE_READ_DATA ) )
  487. {
  488. dwMode |= FILE_MODE_R;
  489. }
  490. if( fVolumeReadable && ( dwAccess & FILE_EXECUTE ) )
  491. {
  492. dwMode |= FILE_MODE_X;
  493. }
  494. if( fVolumeWritable &&
  495. !( pfdInfo->dwFileAttributes & FILE_ATTRIBUTE_READONLY ) &&
  496. ( dwAccess & FILE_WRITE_DATA ) &&
  497. ( dwAccess & FILE_APPEND_DATA ) )
  498. {
  499. dwMode |= FILE_MODE_W;
  500. }
  501. }
  502. return dwMode;
  503. } // ComputeModeBits()
  504. #define DEFAULT_SECURITY_DESC_SIZE ( 2048)
  505. #define DEFAULT_PRIV_SET_SIZE ( 1024)
  506. APIERR
  507. ComputeFileInfo(
  508. HANDLE hUserToken,
  509. CHAR * pszFile,
  510. DWORD * pdwAccessGranted,
  511. DWORD * pcLinks
  512. )
  513. /*++
  514. This function uses internal Nt security api's to determine if the
  515. valid access is granted.
  516. BEWARE: this function is extremely costly! We need to simplify the cost.
  517. ==>> NYI
  518. Arguments:
  519. hUserToken - handle for the user, for whom we are determining the
  520. access and links
  521. pszFile - full path for the file.
  522. pdwAccessGranted - pointer to DWORD which will receive the granted access.
  523. pcLinks - pointer to count of links for the file.
  524. Returns:
  525. Win32 Error code if there is any failure.
  526. NO_ERROR on success.
  527. --*/
  528. {
  529. NTSTATUS NtStatus;
  530. BY_HANDLE_FILE_INFORMATION FileInfo;
  531. APIERR err;
  532. SECURITY_DESCRIPTOR * psd = NULL;
  533. PRIVILEGE_SET * pps = NULL;
  534. DWORD cbsd;
  535. DWORD cbps;
  536. GENERIC_MAPPING mapping = { 0, 0, 0, FILE_ALL_ACCESS };
  537. HANDLE hFile = INVALID_HANDLE_VALUE;
  538. BOOL fStatus;
  539. DBG_ASSERT( hUserToken != NULL );
  540. DBG_ASSERT( pszFile != NULL );
  541. DBG_ASSERT( pdwAccessGranted != NULL );
  542. DBG_ASSERT( pcLinks != NULL );
  543. //
  544. // Setup.
  545. //
  546. *pdwAccessGranted = 0;
  547. *pcLinks = 1;
  548. //
  549. // Open the target file/directory.
  550. //
  551. err = OpenPathForAccess( &hFile,
  552. pszFile,
  553. GENERIC_READ,
  554. ( FILE_SHARE_READ | FILE_SHARE_WRITE |
  555. FILE_SHARE_DELETE),
  556. hUserToken
  557. );
  558. if( err != NO_ERROR )
  559. {
  560. return err;
  561. }
  562. //
  563. // Determine the number of symbolic links.
  564. //
  565. if ( GetFileInformationByHandle( hFile,
  566. &FileInfo)
  567. ) {
  568. *pcLinks = FileInfo.nNumberOfLinks;
  569. } else {
  570. //
  571. // We won't let this be serious enough to abort
  572. // the entire operation.
  573. //
  574. *pcLinks = 1;
  575. }
  576. //
  577. // Get the file's security descriptor.
  578. //
  579. cbsd = DEFAULT_SECURITY_DESC_SIZE;
  580. psd = (SECURITY_DESCRIPTOR *)TCP_ALLOC( cbsd );
  581. if( psd == NULL )
  582. {
  583. err = GetLastError();
  584. goto Cleanup;
  585. }
  586. do
  587. {
  588. err = NO_ERROR;
  589. //
  590. // Replace NtQuerySecurityObject() by GetFileSecurity()
  591. //
  592. if (!GetFileSecurity( pszFile,
  593. OWNER_SECURITY_INFORMATION
  594. | GROUP_SECURITY_INFORMATION
  595. | DACL_SECURITY_INFORMATION,
  596. psd,
  597. cbsd,
  598. &cbsd )
  599. ) {
  600. err = GetLastError();
  601. }
  602. if( err == ERROR_INSUFFICIENT_BUFFER )
  603. {
  604. TCP_FREE( psd );
  605. psd = (SECURITY_DESCRIPTOR *)TCP_ALLOC( cbsd );
  606. if( psd == NULL )
  607. {
  608. err = GetLastError();
  609. break;
  610. }
  611. }
  612. } while( err == ERROR_INSUFFICIENT_BUFFER );
  613. if( err != NO_ERROR ) {
  614. IF_DEBUG( DIR_LIST) {
  615. DBGPRINTF(( DBG_CONTEXT,
  616. "cannot get security for %s, error %lu\n",
  617. pszFile,
  618. err ));
  619. }
  620. goto Cleanup;
  621. }
  622. //
  623. // Check access.
  624. //
  625. cbps = DEFAULT_PRIV_SET_SIZE;
  626. pps = (PRIVILEGE_SET *)TCP_ALLOC( cbps );
  627. if( pps == NULL )
  628. {
  629. err = GetLastError();
  630. goto Cleanup;
  631. }
  632. do
  633. {
  634. if( AccessCheck( psd,
  635. hUserToken,
  636. MAXIMUM_ALLOWED,
  637. &mapping,
  638. pps,
  639. &cbps,
  640. pdwAccessGranted,
  641. &fStatus ) )
  642. {
  643. err = fStatus ? NO_ERROR : GetLastError();
  644. if( err != NO_ERROR )
  645. {
  646. IF_DEBUG( DIR_LIST) {
  647. DBGPRINTF(( DBG_CONTEXT,
  648. "AccessCheck() failure. Error=%d\n", err ));
  649. }
  650. break;
  651. }
  652. }
  653. else
  654. {
  655. err = GetLastError();
  656. if( err == ERROR_INSUFFICIENT_BUFFER )
  657. {
  658. TCP_FREE( pps );
  659. pps = (PRIVILEGE_SET *)TCP_ALLOC( cbps );
  660. if( pps == NULL )
  661. {
  662. err = GetLastError();
  663. break;
  664. }
  665. }
  666. }
  667. } while( err == ERROR_INSUFFICIENT_BUFFER );
  668. if( err != NO_ERROR )
  669. {
  670. IF_DEBUG(DIR_LIST) {
  671. DBGPRINTF(( DBG_CONTEXT,
  672. "cannot get check access for %s, error %lu\n",
  673. pszFile,
  674. err ));
  675. }
  676. goto Cleanup;
  677. }
  678. Cleanup:
  679. if( psd != NULL )
  680. {
  681. TCP_FREE( psd );
  682. }
  683. if( pps != NULL )
  684. {
  685. TCP_FREE( pps );
  686. }
  687. if( hFile != INVALID_HANDLE_VALUE )
  688. {
  689. CloseHandle( hFile );
  690. }
  691. return err;
  692. } // ComputeFileInfo()
  693. # define INVALID_FS_FLAGS ((DWORD ) -1L)
  694. DWORD
  695. GetFsFlags( IN CHAR chDrive)
  696. /*++
  697. This function uses GetVolumeInformation to retrieve the file system
  698. flags for the given drive.
  699. Arguments:
  700. chDrive the drive letter to check for. Must be A-Z.
  701. Returns:
  702. DWORD containing the FS flags. 0 if unknown.
  703. History:
  704. MuraliK 25-Apr-1995
  705. --*/
  706. {
  707. INT iDrive;
  708. DWORD Flags = INVALID_FS_FLAGS;
  709. static DWORD p_FsFlags[26] = {
  710. // One per DOS drive (A - Z).
  711. INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
  712. INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
  713. INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
  714. INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
  715. INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
  716. INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
  717. INVALID_FS_FLAGS, INVALID_FS_FLAGS
  718. };
  719. //
  720. // Validate the parameter & map to uppercase.
  721. //
  722. chDrive = (INT)toupper( chDrive );
  723. DBG_ASSERT( ( chDrive >= 'A' ) && ( chDrive <= 'Z' ) );
  724. iDrive = (INT)( chDrive - 'A' );
  725. //
  726. // If we've already touched this drive, use the
  727. // cached value.
  728. //
  729. Flags = p_FsFlags[iDrive];
  730. if( Flags == INVALID_FS_FLAGS )
  731. {
  732. CHAR szRoot[] = "d:\\";
  733. //
  734. // Retrieve the flags.
  735. //
  736. szRoot[0] = chDrive;
  737. GetVolumeInformation( szRoot, // lpRootPathName
  738. NULL, // lpVolumeNameBuffer
  739. 0, // nVolumeNameSize
  740. NULL, // lpVolumeSerialNumber
  741. NULL, // lpMaximumComponentLength
  742. &Flags, // lpFileSystemFlags
  743. NULL, // lpFileSYstemNameBuffer,
  744. 0 ); // nFileSystemNameSize
  745. p_FsFlags[iDrive] = Flags;
  746. }
  747. return ( Flags == INVALID_FS_FLAGS ) ? 0 : Flags;
  748. } // GetFsFlags()
  749. /************************ End of File ***********************/