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.

1358 lines
35 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1992.
  5. //
  6. // File: dir.cxx
  7. //
  8. // Contents: Directory Functions
  9. //
  10. // History: 18-Jul-91 PhilipLa Created.
  11. //
  12. //---------------------------------------------------------------
  13. #include "msfhead.cxx"
  14. #pragma hdrstop
  15. #include <dirfunc.hxx>
  16. #include <mread.hxx>
  17. #define DEB_DIR (DEB_ITRACE | 0x00040000)
  18. //+-------------------------------------------------------------------------
  19. //
  20. // Member: CMStream::KillStream, public
  21. //
  22. // Synopsis: Eliminate a given chain
  23. //
  24. // Arguments: [sectStart] -- Beginning of chain to eliminate
  25. //
  26. // Returns: S_OK if call completed OK.
  27. //
  28. // Algorithm: *Finish This*
  29. //
  30. // History: 14-Sep-92 PhilipLa Created.
  31. //
  32. // Notes:
  33. //
  34. //--------------------------------------------------------------------------
  35. #ifdef LARGE_STREAMS
  36. inline SCODE CMStream::KillStream(SECT sectStart, ULONGLONG ulSize)
  37. #else
  38. inline SCODE MSTREAM_CLASS CMStream::KillStream(SECT sectStart, ULONG ulSize)
  39. #endif
  40. {
  41. CFat *pfat;
  42. #ifndef REF
  43. pfat = ((!_fIsScratch) && (ulSize < MINISTREAMSIZE)) ? &_fatMini: &_fat;
  44. #else
  45. pfat = (ulSize < MINISTREAMSIZE) ?&_fatMini: &_fat;
  46. #endif //!REF
  47. return pfat->SetChainLength(sectStart, 0);
  48. }
  49. //+-------------------------------------------------------------------------
  50. //
  51. // Method: CDirEntry::CDirEntry, public
  52. //
  53. // Synopsis: Constructor for CDirEntry class
  54. //
  55. // Effects:
  56. //
  57. // History: 18-Jul-91 PhilipLa Created.
  58. //
  59. // Notes:
  60. //
  61. //--------------------------------------------------------------------------
  62. CDirEntry::CDirEntry()
  63. {
  64. msfAssert(sizeof(CDirEntry) == DIRENTRYSIZE);
  65. Init(STGTY_INVALID);
  66. }
  67. //+-------------------------------------------------------------------------
  68. //
  69. // Method: CDirSect::Init, public
  70. //
  71. // Synopsis: Initializer for directory sectors
  72. //
  73. // Arguments: [cdeEntries] -- Number of DirEntries in the sector
  74. //
  75. // Returns: S_OK if call completed OK.
  76. //
  77. // History: 18-Jul-91 PhilipLa Created.
  78. // 27-Dec-91 PhilipLa Converted from const to var size
  79. //
  80. // Notes:
  81. //
  82. //--------------------------------------------------------------------------
  83. SCODE CDirSect::Init(USHORT cbSector)
  84. {
  85. msfDebugOut((DEB_DIR,"Allocating sector with size %u\n",cbSector));
  86. #if WIN32 == 200
  87. //Make sure to zero out the memory, since Win95 doesn't do it for
  88. // you. NT does, so we don't need to do this there.
  89. memset(_adeEntry, 0, cbSector);
  90. #endif
  91. DIROFFSET cdeEntries = cbSector / sizeof(CDirEntry);
  92. for (ULONG i = 0; i < cdeEntries; i++)
  93. {
  94. _adeEntry[i].Init(STGTY_INVALID);
  95. }
  96. return S_OK;
  97. }
  98. //+-------------------------------------------------------------------------
  99. //
  100. // Method: CDirSect::InitCopy, public
  101. //
  102. // Synopsis: CDirSect initializer for copying
  103. //
  104. // Arguments: [dsOld] -- Const reference to dir to be copied
  105. //
  106. // Returns: S_OK if call completed successfully.
  107. //
  108. // History: 18-Feb-92 PhilipLa Created.
  109. //
  110. // Notes:
  111. //
  112. //--------------------------------------------------------------------------
  113. SCODE CDirSect::InitCopy(USHORT cbSector,
  114. const CDirSect *pdsOld)
  115. {
  116. msfDebugOut((DEB_DIR,"In CDirSect copy constructor\n"));
  117. memcpy(_adeEntry, pdsOld->_adeEntry, cbSector);
  118. msfDebugOut((DEB_DIR,"Out CDirSect copy constructor\n"));
  119. return S_OK;
  120. }
  121. //+-------------------------------------------------------------------------
  122. //
  123. // Method: CDirectory::CDirectory
  124. //
  125. // Synopsis: Default constructor
  126. //
  127. // History: 22-Apr-92 PhilipLa Created.
  128. //
  129. // Notes:
  130. //
  131. //--------------------------------------------------------------------------
  132. CDirectory::CDirectory()
  133. : _pmsParent(NULL)
  134. {
  135. _cdsTable = _cdeEntries = 0;
  136. _sidFirstFree = 0;
  137. }
  138. //+---------------------------------------------------------------------------
  139. //
  140. // Member: CDirectory::Empty, public
  141. //
  142. // Synopsis: Empty all the control structures of this instance
  143. //
  144. // Arguments: None.
  145. //
  146. // Returns: void.
  147. //
  148. // History: 04-Dec-92 PhilipLa Created
  149. //
  150. //----------------------------------------------------------------------------
  151. void CDirectory::Empty(void)
  152. {
  153. _dv.Empty();
  154. _pmsParent = NULL;
  155. _cdsTable = 0;
  156. _cdeEntries = 0;
  157. _sidFirstFree = 0;
  158. }
  159. //+-------------------------------------------------------------------------
  160. //
  161. // Method: CDirectory::InitCopy, public
  162. //
  163. // Synopsis: Init function for copying.
  164. //
  165. // Arguments: [dirOld] -- Const reference to dir object to be copied
  166. //
  167. // History: 18-Feb-92 PhilipLa Created.
  168. //
  169. // Notes:
  170. //
  171. //--------------------------------------------------------------------------
  172. void CDirectory::InitCopy(CDirectory *pdirOld)
  173. {
  174. msfDebugOut((DEB_DIR,"In CDirectory copy constructor\n"));
  175. _pmsParent = pdirOld->_pmsParent;
  176. _cdeEntries = pdirOld->_cdeEntries;
  177. _dv.InitCommon(_pmsParent->GetSectorSize());
  178. _dv.InitCopy(&pdirOld->_dv);
  179. _cdsTable = pdirOld->_cdsTable;
  180. _sidFirstFree = pdirOld->_sidFirstFree;
  181. msfDebugOut((DEB_DIR,"Out CDirectory copy constructor\n"));
  182. }
  183. //+-------------------------------------------------------------------------
  184. //
  185. // Member: CDirectory::GetFree, public
  186. //
  187. // Synposis: Locates a free directory entry
  188. //
  189. // Arguments: None.
  190. //
  191. // Returns: Stream ID of free directory entry
  192. //
  193. // Algorithm: Do a linear search of all available directories.
  194. // If no free spot is found, resize the directory and
  195. // perform the search again.
  196. //
  197. // History: 18-Jul-91 PhilipLa Created.
  198. //
  199. // Notes:
  200. //
  201. //---------------------------------------------------------------------------
  202. SCODE CDirectory::GetFree(SID * psid)
  203. {
  204. msfDebugOut((DEB_DIR,"In CDirectory::GetFree()\n"));
  205. SCODE sc = S_OK;
  206. SID sidRet = NOSTREAM;
  207. CDirSect * pds;
  208. DIRINDEX ipdsStart;
  209. DIROFFSET ideStart;
  210. SidToPair(_sidFirstFree, &ipdsStart, &ideStart);
  211. while (TRUE)
  212. {
  213. for (DIRINDEX ipds = ipdsStart; ipds < _cdsTable; ipds++)
  214. {
  215. msfChk(_dv.GetTable(ipds, FB_NONE, &pds));
  216. for (DIROFFSET ide = ideStart; ide < _cdeEntries; ide++)
  217. {
  218. if (pds->GetEntry(ide)->IsFree())
  219. {
  220. msfDebugOut((DEB_ITRACE,"GetFree found sid %lu\n",
  221. PairToSid(ipds,ide)));
  222. *psid = PairToSid(ipds, ide);
  223. _sidFirstFree = *psid + 1;
  224. _dv.ReleaseTable(ipds);
  225. return S_OK;
  226. }
  227. }
  228. _dv.ReleaseTable(ipds);
  229. ideStart = 0;
  230. }
  231. ipdsStart = ipds;
  232. msfChk(Resize(_cdsTable+1));
  233. }
  234. Err:
  235. return sc;
  236. }
  237. //+-------------------------------------------------------------------------
  238. //
  239. // Member: CDirectory::FindGreaterEntry
  240. //
  241. // Synopsis: finds next entry (for iteration)
  242. //
  243. // Arguments: [sidStart] -- child sid to start looking
  244. // [pdfn] -- previous entry name
  245. // [psidResult] -- place holder for returned sid
  246. //
  247. // Requires: sidStart != NOSTREAM
  248. //
  249. // Returns: S_OK, STG_E_NOMOREFILES, or other error
  250. //
  251. // Modifies: psidResult
  252. //
  253. // Algorithm: Iterate by returning the sid that has a name larger
  254. // than the given name.
  255. //
  256. // History: 16-Oct-92 AlexT Created
  257. //
  258. // Notes: This method is called recursively
  259. // When sc != S_OK, *psidReturn contains the recursion count
  260. // The caller must initialize *psidResult to 0 or SIDROOT
  261. //
  262. //--------------------------------------------------------------------------
  263. SCODE CDirectory::FindGreaterEntry(SID sidStart,
  264. CDfName const *pdfn,
  265. SID *psidResult)
  266. {
  267. SCODE sc;
  268. CDirEntry *pde;
  269. msfAssert(sidStart != NOSTREAM);
  270. const SID sidMax = (_cdsTable+1) * _cdeEntries;
  271. if ((*psidResult)++ > sidMax)
  272. msfErr (Err, STG_E_DOCFILECORRUPT); // prevent infinite recursion
  273. msfChk(GetDirEntry(sidStart, FB_NONE, &pde));
  274. int iCmp;
  275. iCmp = NameCompare(pdfn, pde->GetName());
  276. if (iCmp < 0)
  277. {
  278. // Since the last name returned is less than this name,
  279. // the sid to return must either be to our left or this sid
  280. SID sidLeft = pde->GetLeftSib();
  281. // We can't hold onto sidStart as we recurse, (because we'll ask for
  282. // a page each time we recurse)
  283. ReleaseEntry(sidStart);
  284. if (sidLeft == sidStart)
  285. {
  286. //Corrupt docfile - return error.
  287. return STG_E_DOCFILECORRUPT;
  288. }
  289. if ((sidLeft == NOSTREAM) ||
  290. (sc = FindGreaterEntry(sidLeft, pdfn, psidResult)) == STG_E_NOMOREFILES)
  291. {
  292. // There was no left child with a name greater than pdfn, so
  293. // we return ourself
  294. *psidResult = sidStart;
  295. sc = S_OK;
  296. }
  297. }
  298. else
  299. {
  300. // The last name returned is greater than this one, so we've already
  301. // returned this sidStart. Look in the right subtree.
  302. SID sidRight = pde->GetRightSib();
  303. // We can't hold onto sidStart as we recurse, (because we'll ask for
  304. // a page each time we recurse)
  305. ReleaseEntry(sidStart);
  306. if (sidRight == sidStart)
  307. {
  308. //Corrupt docfile - return error.
  309. return STG_E_DOCFILECORRUPT;
  310. }
  311. if (sidRight == NOSTREAM)
  312. sc = STG_E_NOMOREFILES;
  313. else
  314. sc = FindGreaterEntry(sidRight, pdfn, psidResult);
  315. }
  316. Err:
  317. return(sc);
  318. }
  319. //+-------------------------------------------------------------------------
  320. //
  321. // Method: CDirectory::SetStart, public
  322. //
  323. // Synopsis: Set starting sector for a dir entry
  324. //
  325. // Arguments: [sid] -- SID of entry to be modified
  326. // [sect] -- New starting sector for entry
  327. //
  328. // Returns: SID of modified entry
  329. //
  330. // History: 18-Feb-92 PhilipLa Created.
  331. //
  332. // Notes:
  333. //
  334. //--------------------------------------------------------------------------
  335. SCODE CDirectory::SetStart(const SID sid, const SECT sect)
  336. {
  337. SCODE sc;
  338. CDirEntry *pde;
  339. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  340. pde->SetStart(sect);
  341. ReleaseEntry(sid);
  342. Err:
  343. return sc;
  344. }
  345. //+-------------------------------------------------------------------------
  346. //
  347. // Member: CDirectory::SetChild, public
  348. //
  349. // Synposis: Set the child SID of an entry
  350. //
  351. // Effects: Modifies a single directory entry. Causes a one sector
  352. // stream write.
  353. //
  354. // Arguments: [sid] -- Stream ID of entry to be set
  355. // [sidChild] -- SID of first child of this stream
  356. //
  357. // Returns: SID of modified entry
  358. //
  359. // Algorithm: Change child field on entry, then write to stream.
  360. //
  361. // History: 24-Sep-91 PhilipLa Created.
  362. //
  363. //---------------------------------------------------------------------------
  364. SCODE CDirectory::SetChild(const SID sid, const SID sidChild)
  365. {
  366. SCODE sc;
  367. CDirEntry *pde;
  368. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  369. pde->SetChild(sidChild);
  370. ReleaseEntry(sid);
  371. Err:
  372. return sc;
  373. }
  374. //+-------------------------------------------------------------------------
  375. //
  376. // Member: CDirectory::SetSize, public
  377. //
  378. // Synposis: Set the size of an entry
  379. //
  380. // Effects: Modifies a single directory entry. Causes a one sector
  381. // stream write.
  382. //
  383. // Arguments: [sid] -- Stream ID of entry to be set
  384. // [cbSize] -- Size
  385. //
  386. // Returns: SID of modified entry
  387. //
  388. // Algorithm: Change size field on entry, then write to stream.
  389. //
  390. // History: 24-Sep-91 PhilipLa Created.
  391. //
  392. //---------------------------------------------------------------------------
  393. #ifdef LARGE_STREAMS
  394. SCODE CDirectory::SetSize(const SID sid, const ULONGLONG cbSize)
  395. #else
  396. SCODE CDirectory::SetSize(const SID sid, const ULONG cbSize)
  397. #endif
  398. {
  399. SCODE sc;
  400. CDirEntry *pde;
  401. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  402. pde->SetSize(cbSize);
  403. ReleaseEntry(sid);
  404. Err:
  405. return sc;
  406. }
  407. //+-------------------------------------------------------------------------
  408. //
  409. // Member: CDirectory::SetTime, public
  410. //
  411. // Synposis: Set the time of an entry
  412. //
  413. // Effects: Modifies a single directory entry. Causes a one sector
  414. // stream write.
  415. //
  416. // Arguments: [sid] -- Stream ID of entry to be set
  417. // [tt] - WT_*
  418. // [nt] - New time
  419. //
  420. // Returns: Apropriate status code
  421. //
  422. // Algorithm: Change time field on entry, then write to stream.
  423. //
  424. // History: 24-Sep-91 PhilipLa Created.
  425. //
  426. //---------------------------------------------------------------------------
  427. SCODE CDirectory::SetTime(const SID sid, WHICHTIME tt, TIME_T nt)
  428. {
  429. SCODE sc;
  430. CDirEntry *pde;
  431. // We don't support ACCESS times, so just ignore sets
  432. if (tt == WT_ACCESS)
  433. return S_OK;
  434. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  435. pde->SetTime(tt, nt);
  436. ReleaseEntry(sid);
  437. Err:
  438. return sc;
  439. }
  440. //+-------------------------------------------------------------------------
  441. //
  442. // Member: CDirectory::SetAllTimes, public
  443. //
  444. // Synposis: Set the times of an entry
  445. //
  446. // Effects: Modifies a single directory entry. Causes a one sector
  447. // stream write.
  448. //
  449. // Arguments: [sid] -- Stream ID of entry to be set
  450. // [atm] - ACCESS time
  451. // [mtm] - MODIFICATION time
  452. // [ctm] - Creation Time
  453. //
  454. // Returns: Appropriate Status Code
  455. //
  456. // Algorithm: Change time fields on entry, then write to stream.
  457. //
  458. // History: 24-Nov-95 SusiA Created.
  459. //
  460. //---------------------------------------------------------------------------
  461. SCODE CDirectory::SetAllTimes(const SID sid,
  462. TIME_T atm,
  463. TIME_T mtm,
  464. TIME_T ctm)
  465. {
  466. SCODE sc;
  467. CDirEntry *pde;
  468. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  469. pde->SetAllTimes(atm, mtm, ctm);
  470. ReleaseEntry(sid);
  471. Err:
  472. return sc;
  473. }
  474. //+-------------------------------------------------------------------------
  475. //
  476. // Member: CDirectory::SetFlags, public
  477. //
  478. // Synposis: Set the flags of an entry
  479. //
  480. // Effects: Modifies a single directory entry. Causes a one sector
  481. // stream write.
  482. //
  483. // Arguments: [sid] -- Stream ID of entry to be set
  484. // [mse] - New flags
  485. //
  486. // Returns: Status code
  487. //
  488. // Algorithm: Change Luid field on entry, then write to stream.
  489. //
  490. // History: 08-Oct-92 PhilipLa Created
  491. //
  492. //---------------------------------------------------------------------------
  493. SCODE CDirectory::SetFlags(const SID sid, const MSENTRYFLAGS mse)
  494. {
  495. SCODE sc;
  496. CDirEntry *pde;
  497. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  498. pde->SetFlags(mse);
  499. ReleaseEntry(sid);
  500. Err:
  501. return sc;
  502. }
  503. //+-------------------------------------------------------------------------
  504. //
  505. // Member: CDirectory::SetClassId, public
  506. //
  507. // Synposis: Set the class ID of an entry
  508. //
  509. // Effects: Modifies a single directory entry. Causes a one sector
  510. // stream write.
  511. //
  512. // Arguments: [sid] -- Stream ID of entry to be set
  513. // [cls] - Class ID
  514. //
  515. // Returns: Appropriate status code
  516. //
  517. // History: 11-Nov-92 DrewB Created.
  518. //
  519. //---------------------------------------------------------------------------
  520. SCODE CDirectory::SetClassId(const SID sid, const GUID cls)
  521. {
  522. SCODE sc;
  523. CDirEntry *pde;
  524. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  525. pde->SetClassId(cls);
  526. ReleaseEntry(sid);
  527. Err:
  528. return sc;
  529. }
  530. //+-------------------------------------------------------------------------
  531. //
  532. // Member: CDirectory::SetUserFlags, public
  533. //
  534. // Synposis: Set the user flags of an entry
  535. //
  536. // Effects: Modifies a single directory entry. Causes a one sector
  537. // stream write.
  538. //
  539. // Arguments: [sid] -- Stream ID of entry to be set
  540. // [dwUserFlags] - Flags
  541. // [dwMask] - Mask
  542. //
  543. // Returns: Appropriate status code
  544. //
  545. // History: 11-Nov-92 DrewB Created.
  546. //
  547. //---------------------------------------------------------------------------
  548. SCODE CDirectory::SetUserFlags(SID const sid,
  549. DWORD dwUserFlags,
  550. DWORD dwMask)
  551. {
  552. SCODE sc;
  553. CDirEntry *pde;
  554. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  555. pde->SetUserFlags(dwUserFlags, dwMask);
  556. ReleaseEntry(sid);
  557. Err:
  558. return sc;
  559. }
  560. //+-------------------------------------------------------------------------
  561. //
  562. // Member: CDirectory::resize, private
  563. //
  564. // Synposis: Resize a directory.
  565. //
  566. // Effects: Reallocates space for directory table, copying over
  567. // old pointers as necessary. Any new tables needed are
  568. // created here.
  569. //
  570. // Arguments: [uNewsize] -- New size for Directory
  571. //
  572. // Returns: void
  573. //
  574. // Algorithm: Allocate a new array of pointers of the necessary size.
  575. // Then, copy over all pointers from old array and allocate
  576. // new CDirSects for all new tables.
  577. //
  578. // History: 20-Jul-91 PhilipLa Created.
  579. //
  580. // Notes:
  581. //
  582. //---------------------------------------------------------------------------
  583. SCODE CDirectory::Resize(DIRINDEX uNewsize)
  584. {
  585. msfDebugOut((DEB_DIR,"In CDirectory::Resize(%i)\n",uNewsize));
  586. SCODE sc;
  587. if (uNewsize == _cdsTable) return S_OK;
  588. SECT sect1;
  589. //GetESect call will make sure we have enough Fat space.
  590. msfChk(_pmsParent->GetESect(SIDDIR, uNewsize - 1, &sect1));
  591. msfChk(_dv.Resize(uNewsize));
  592. ULONG ipds;
  593. for (ipds = _cdsTable; ipds < uNewsize; ipds++)
  594. {
  595. CDirSect *pds;
  596. msfChk(_dv.GetTable(ipds, FB_NEW, &pds));
  597. SECT sect;
  598. msfChk(_pmsParent->GetESect(SIDDIR, ipds, &sect));
  599. _cdsTable = ipds + 1;
  600. _dv.SetSect(ipds, sect);
  601. _dv.ReleaseTable(ipds);
  602. }
  603. msfChk(_pmsParent->GetHeader()->SetDirLength (_cdsTable));
  604. Err:
  605. #if DBG == 1
  606. ULONG cbSect;
  607. SECT sectStart;
  608. sectStart = _pmsParent->GetHeader()->GetDirStart();
  609. _pmsParent->GetFat()->GetLength(sectStart, &cbSect);
  610. msfAssert((cbSect == _cdsTable) &&
  611. aMsg("Directory length in FAT does not match cached size."));
  612. #endif
  613. return sc;
  614. }
  615. //+-------------------------------------------------------------------------
  616. //
  617. // Member: CDirectory::Init, public
  618. //
  619. // Synposis: Sets up a Directory instance and reads in all tables
  620. // from the stream
  621. //
  622. // Arguments: [cSect] -- Number of sectors in directory
  623. //
  624. // Returns: S_OK if call completed OK.
  625. // STG_E_READFAULT if not enough bytes were read for
  626. // a DirSector
  627. // Error code of read if read returned an error.
  628. //
  629. // Algorithm: Create array to hold appropriate number of tables.
  630. // Read in each table from disk.
  631. //
  632. // History: 18-Jul-91 PhilipLa Created.
  633. //
  634. //---------------------------------------------------------------------------
  635. SCODE CDirectory::Init(
  636. CMStream *pmsParent,
  637. DIRINDEX cSect)
  638. {
  639. msfDebugOut((DEB_DIR,"In CDirectory::Init(%lu)\n",cSect));
  640. SCODE sc;
  641. _pmsParent = P_TO_BP(CBasedMStreamPtr, pmsParent);
  642. _cdeEntries = pmsParent->GetSectorSize() / sizeof(CDirEntry);
  643. _dv.InitCommon(pmsParent->GetSectorSize());
  644. msfChk(_dv.Init(pmsParent, cSect));
  645. _cdsTable = cSect;
  646. msfDebugOut((DEB_DIR,"Out CDirectory::Init()\n"));
  647. Err:
  648. return sc;
  649. }
  650. //+-------------------------------------------------------------------------
  651. //
  652. // Member: CDirectory::InitNew, public
  653. //
  654. // Synposis: Sets up a new Directory instance for a new Mstream
  655. //
  656. // Arguments: None.
  657. //
  658. // Returns: S_OK if call completed OK.
  659. // STG_E_WRITEFAULT if not enough bytes were written.
  660. // Error code of write if write failed.
  661. //
  662. // Algorithm: Write initial DirSector to disk.
  663. //
  664. // History: 18-Jul-91 PhilipLa Created.
  665. //
  666. // Notes:
  667. //
  668. //---------------------------------------------------------------------------
  669. SCODE CDirectory::InitNew(CMStream *pmsParent)
  670. {
  671. SCODE sc;
  672. CDfName const dfnRoot(wcsRootEntry);
  673. msfDebugOut((DEB_DIR,"In CDirectory::setupnew()\n"));
  674. _pmsParent = P_TO_BP(CBasedMStreamPtr, pmsParent);
  675. _cdeEntries = pmsParent->GetSectorSize() / sizeof(CDirEntry);
  676. _dv.InitCommon(pmsParent->GetSectorSize());
  677. msfChk(_dv.Init(pmsParent, 1));
  678. CDirSect *pds;
  679. msfChk(_dv.GetTable(0, FB_NEW, &pds));
  680. _dv.SetSect(0, pmsParent->GetHeader()->GetDirStart());
  681. _dv.ReleaseTable(0);
  682. _cdsTable = 1;
  683. SID sidRoot;
  684. msfChk(GetFree(&sidRoot));
  685. CDirEntry *pdeTemp;
  686. msfChk(GetDirEntry(sidRoot, FB_DIRTY, &pdeTemp));
  687. pdeTemp->Init(STGTY_ROOT);
  688. msfAssert(sidRoot == SIDROOT);
  689. pdeTemp->SetName(&dfnRoot);
  690. ReleaseEntry(sidRoot);
  691. msfDebugOut((DEB_DIR,"Exiting CDirectory::setupnew()\n"));
  692. Err:
  693. return sc;
  694. }
  695. //+-------------------------------------------------------------------------
  696. //
  697. // Method: CDirectory::CreateEntry, public
  698. //
  699. // Synopsis: Create a new directory entry
  700. //
  701. // Arguments: [sidParent] -- SID of parent for new entry
  702. // [pwcsName] -- Name of new entry
  703. // [mef] -- Flags for new entry
  704. // [psidNew] -- Return location for new SID
  705. //
  706. // Returns: S_OK if call completed OK.
  707. //
  708. // Algorithm: Allocate new entry.
  709. // Try to insert.
  710. // If unsuccessful, return new entry to free pool.
  711. //
  712. // History: 19-Aug-92 PhilipLa Created.
  713. // 20-Jul-93 AlexT Optimized (skip initial search)
  714. //
  715. //--------------------------------------------------------------------------
  716. SCODE CDirectory::CreateEntry(
  717. SID sidParent,
  718. CDfName const *pdfn,
  719. MSENTRYFLAGS mef,
  720. SID *psidNew)
  721. {
  722. SCODE sc;
  723. SID sidNew;
  724. CDirEntry *pdeNew;
  725. // Allocate new sid
  726. msfChk(GetFree(psidNew));
  727. sidNew = *psidNew;
  728. msfChk(GetDirEntry(sidNew, FB_DIRTY, &pdeNew));
  729. // Initialize new entry
  730. pdeNew->Init(mef);
  731. TIME_T timetemp;
  732. if (STORAGELIKE(mef))
  733. {
  734. if (FAILED(sc = DfGetTOD(&timetemp)))
  735. {
  736. ReleaseEntry(sidNew);
  737. msfErr(Err, sc);
  738. }
  739. }
  740. else
  741. {
  742. timetemp.dwLowDateTime = timetemp.dwHighDateTime = 0;
  743. }
  744. pdeNew->SetTime(WT_CREATION, timetemp);
  745. pdeNew->SetTime(WT_MODIFICATION, timetemp);
  746. pdeNew->SetName(pdfn);
  747. ReleaseEntry(sidNew);
  748. // Insert new entry into the tree
  749. msfChkTo(EH_Sid, InsertEntry(sidParent, sidNew, pdfn));
  750. return(sc);
  751. EH_Sid:
  752. // We were unable to insert the new entry (most likely because of a
  753. // name conflict). Here we try to return the entry to the free list.
  754. // If we can't, the only consequence is that we leak a dir entry on
  755. // disk (128 bytes of disk space).
  756. if (SUCCEEDED(GetDirEntry(sidNew, FB_DIRTY, &pdeNew)))
  757. {
  758. pdeNew->SetFlags(STGTY_INVALID);
  759. ReleaseEntry(sidNew);
  760. if (sidNew < _sidFirstFree)
  761. {
  762. _sidFirstFree = sidNew;
  763. }
  764. }
  765. Err:
  766. return sc;
  767. }
  768. //+-------------------------------------------------------------------------
  769. //
  770. // Member: CDirectory::RenameEntry, public
  771. //
  772. // Synopsis: Rename an entry
  773. //
  774. // Arguments: [sidParent] -- Sid of parent of entry to be renamed
  775. // [pwcsName] -- Old name of entry to be renamed
  776. // [pwcsName] -- New name
  777. //
  778. // Returns: S_OK if call completed OK.
  779. //
  780. // Algorithm: Remove old entry
  781. // Rename entry
  782. // Insert as new entry
  783. //
  784. // History: 10-Sep-92 PhilipLa Created.
  785. // 16-Nov-92 AlexT Binary tree structure
  786. //
  787. // Notes:
  788. //
  789. //--------------------------------------------------------------------------
  790. SCODE CDirectory::RenameEntry(SID const sidParent,
  791. CDfName const *pdfn,
  792. CDfName const *pdfnNew)
  793. {
  794. // Make sure new name doesn't already exist
  795. SCODE sc;
  796. SEntryBuffer eb;
  797. sc = IsEntry(sidParent, pdfnNew, &eb);
  798. if (sc != STG_E_FILENOTFOUND)
  799. {
  800. if (SUCCEEDED(sc))
  801. {
  802. // Entry did exist - fail this call
  803. sc = STG_E_ACCESSDENIED;
  804. }
  805. return(sc);
  806. }
  807. // We can't just rename in place (because the tree is ordered)
  808. CDirEntry *pdeRename;
  809. SEntryBuffer ebRename;
  810. msfChk(FindEntry(sidParent, pdfn, DEOP_REMOVE, &ebRename));
  811. sc = GetDirEntry(ebRename.sid, FB_DIRTY, &pdeRename);
  812. msfAssert(SUCCEEDED(sc) && aMsg("Could get dir entry to rename"));
  813. msfChk(sc);
  814. pdeRename->SetName(pdfnNew);
  815. ReleaseEntry(ebRename.sid);
  816. // If this InsertEntry fails, we've potentially lost the entry. This
  817. // doesn't matter becase:
  818. // a) The only way we could fail is if we couldn't read or write
  819. // the disk (hard error)
  820. // b) No one's going to call RenameEntry anyways
  821. // c) If we're transacted, the whole operation is made robust by
  822. // CopyOnWrite mode
  823. // d) If we're direct, we already know we can fail in ways that leave
  824. // the Docfile corrupt.
  825. sc = InsertEntry(sidParent, ebRename.sid, pdfnNew);
  826. msfAssert(SUCCEEDED(sc) && aMsg("Couldn't reinsert renamed dir entry"));
  827. msfChk(sc);
  828. Err:
  829. return sc;
  830. }
  831. //+-------------------------------------------------------------------------
  832. //
  833. // Member: CDirectory::DestroyAllChildren
  834. //
  835. // Synopsis: destroy all child entries
  836. //
  837. // Effects: destroys child tree
  838. //
  839. // Arguments: [sidParent] -- storage entry
  840. //
  841. // Returns: S_OK or error code
  842. //
  843. // Modifies: sidParent's entry
  844. //
  845. // Algorithm: While there's a child
  846. // destroy it
  847. //
  848. // History: 16-Nov-92 AlexT Created
  849. //
  850. // Notes: We may want to consider a more efficient implementation
  851. //
  852. //--------------------------------------------------------------------------
  853. SCODE CDirectory::DestroyAllChildren(
  854. SID const sidParent,
  855. ULONG ulDepth)
  856. {
  857. SCODE sc;
  858. CDirEntry *pdeParent, *pdeChild;
  859. SID sidChild;
  860. CDfName dfnChild;
  861. ULONG ulCount = 0;
  862. const ULONG ulMax = _cdsTable * _cdeEntries;
  863. for (;;)
  864. {
  865. CDfName dfnChild;
  866. if (ulCount > ulMax || ulDepth > ulMax)
  867. msfErr (Err, STG_E_DOCFILECORRUPT);
  868. msfChk(GetDirEntry(sidParent, FB_NONE, &pdeParent));
  869. sidChild = pdeParent->GetChild();
  870. ReleaseEntry(sidParent);
  871. if (sidChild == NOSTREAM)
  872. break;
  873. msfChk(GetDirEntry(sidChild, FB_NONE, &pdeChild));
  874. dfnChild.Set(pdeChild->GetName());
  875. ReleaseEntry(sidChild);
  876. msfChk(DestroyChild(sidParent, &dfnChild, ulDepth + 1));
  877. ulCount++;
  878. }
  879. Err:
  880. return(sc);
  881. }
  882. //+-------------------------------------------------------------------------
  883. //
  884. // Member: CDirectory::DestroyChild
  885. //
  886. // Synopsis: destroy a named child
  887. //
  888. // Effects: destroys named child's entry
  889. //
  890. // Arguments: [sidParent] -- storage entry
  891. // [pdfn] -- child name
  892. //
  893. // Returns: S_OK, STG_E_FILENOTFOUND, or other error code
  894. //
  895. // Modifies: child's entry
  896. //
  897. // Algorithm: Find and remove child
  898. // Free child entry
  899. //
  900. // History: 16-Nov-92 AlexT Created
  901. //
  902. //--------------------------------------------------------------------------
  903. SCODE CDirectory::DestroyChild(
  904. SID const sidParent,
  905. CDfName const *pdfn,
  906. ULONG ulDepth)
  907. {
  908. SCODE sc;
  909. SEntryBuffer ebChild;
  910. msfAssert(pdfn != NULL);
  911. // Find the entry
  912. msfChk(FindEntry(sidParent, pdfn, DEOP_FIND, &ebChild));
  913. msfAssert(ebChild.sid != NOSTREAM);
  914. // Before we remove this entry, we need to destroy it (including all
  915. // its children). Note that we can't hold onto the entry because it
  916. // might have children which get destroyed, which have children which
  917. // get destroyed, etc.
  918. if (STORAGELIKE(ebChild.dwType))
  919. {
  920. msfChk(DestroyAllChildren(ebChild.sid, ulDepth));
  921. }
  922. CDirEntry *pdeChild;
  923. msfChk(GetDirEntry(ebChild.sid, FB_DIRTY, &pdeChild));
  924. if (STREAMLIKE(ebChild.dwType))
  925. {
  926. // Deallocate any used streams
  927. SECT sectStart = pdeChild->GetStart();
  928. pdeChild->SetStart(ENDOFCHAIN);
  929. #ifdef LARGE_STREAMS
  930. msfChkTo(EH_Rel, _pmsParent->KillStream(sectStart,
  931. pdeChild->GetSize(IsLargeSector())));
  932. #else
  933. msfChkTo(EH_Rel, _pmsParent->KillStream(sectStart,
  934. pdeChild->GetSize()));
  935. #endif
  936. }
  937. // remove the entry from the tree
  938. msfChkTo(EH_Rel, FindEntry(sidParent, pdfn, DEOP_REMOVE, &ebChild));
  939. pdeChild->SetFlags(STGTY_INVALID);
  940. pdeChild->ZeroName(); // zero out the name for security
  941. if (ebChild.sid < _sidFirstFree)
  942. {
  943. _sidFirstFree = ebChild.sid;
  944. }
  945. EH_Rel:
  946. ReleaseEntry(ebChild.sid);
  947. Err:
  948. return(sc);
  949. }
  950. //+-------------------------------------------------------------------------
  951. //
  952. // Method: CDirectory::StatEntry
  953. //
  954. // Synopsis: For a given handle, fill in the Multistream specific
  955. // information of a STATSTG.
  956. //
  957. // Arguments: [sid] -- SID that information is requested on.
  958. // [pib] -- Fast iterator buffer to fill in.
  959. // [pstatstg] -- STATSTG to fill in.
  960. //
  961. // Returns: Appropriate status code
  962. //
  963. // Algorithm: Fill in information
  964. //
  965. // History: 25-Mar-92 PhilipLa Created.
  966. //
  967. //--------------------------------------------------------------------------
  968. SCODE CDirectory::StatEntry(SID const sid,
  969. SIterBuffer *pib,
  970. STATSTGW *pstat)
  971. {
  972. SCODE sc;
  973. CDirEntry *pde = NULL;
  974. size_t cbString = 0;
  975. msfAssert(pib == NULL || pstat == NULL);
  976. msfChk(GetDirEntry(sid, FB_NONE, &pde));
  977. SHORT sLength = pde->GetName()->GetLength();
  978. // The entry name must be a NULL terminated wide char string
  979. // or else it can cause an infinite loop in IEnumSTATSTG::Next
  980. // or overflow the CDfName internal buffer
  981. //
  982. if (sLength > CBSTORAGENAME ||
  983. FAILED(StringCbLength((WCHAR*) pde->GetName()->GetBuffer(),
  984. CBSTORAGENAME, &cbString)) ||
  985. sLength != cbString + sizeof(L'\0'))
  986. msfErr (EH_Rel, STG_E_DOCFILECORRUPT);
  987. if (pde->GetFlags() != STGTY_STORAGE && pde->GetFlags() != STGTY_STREAM)
  988. msfErr (EH_Rel, STG_E_DOCFILECORRUPT);
  989. if (pib)
  990. {
  991. pib->dfnName.Set(pde->GetName());
  992. pib->type = pde->GetFlags();
  993. }
  994. else
  995. {
  996. pstat->type = pde->GetFlags();
  997. msfMemTo(EH_Rel, pstat->pwcsName = (WCHAR *)TaskMemAlloc(sLength));
  998. memcpy(pstat->pwcsName, pde->GetName()->GetBuffer(), sLength);
  999. pstat->ctime = pde->GetTime(WT_CREATION);
  1000. pstat->mtime = pde->GetTime(WT_MODIFICATION);
  1001. // Don't currently keep access times
  1002. pstat->atime = pstat->mtime;
  1003. if (pstat->type == STGTY_STORAGE)
  1004. {
  1005. ULISet32(pstat->cbSize, 0);
  1006. pstat->clsid = pde->GetClassId();
  1007. pstat->grfStateBits = pde->GetUserFlags();
  1008. }
  1009. else if (pstat->type == STGTY_STREAM)
  1010. {
  1011. #ifdef LARGE_STREAMS
  1012. pstat->cbSize.QuadPart = pde->GetSize(IsLargeSector());
  1013. #else
  1014. ULISet32(pstat->cbSize, pde->GetSize());
  1015. #endif
  1016. pstat->clsid = CLSID_NULL;
  1017. pstat->grfStateBits = 0;
  1018. }
  1019. }
  1020. EH_Rel:
  1021. ReleaseEntry(sid);
  1022. Err:
  1023. return sc;
  1024. }
  1025. #ifdef CHKDSK
  1026. //+-------------------------------------------------------------------------
  1027. //
  1028. // Member: CDirectory::InitCorrupted, public
  1029. //
  1030. // Synposis: Sets up a Directory instance and reads in all tables
  1031. // from a corrupted stream.
  1032. //
  1033. // Arguments: [pmsParent] -- Pointer to parent Mstream
  1034. //
  1035. // Returns: S_OK.
  1036. //
  1037. // Algorithm: Determine number of tables needed by querying FAT.
  1038. // Resize array to hold appropriate number of tables.
  1039. // Read in each table from disk.
  1040. // Set parent pointer.
  1041. //
  1042. // History: 18-Jul-91 PhilipLa Created.
  1043. // 24-Aug-92 t-chrisy copied from Init routine
  1044. // force corrupted dir object to instantiate.
  1045. //
  1046. // Notes:
  1047. //
  1048. //---------------------------------------------------------------------------
  1049. SCODE CDirectory::InitCorrupted(DIRINDEX cSect)
  1050. {
  1051. msfDebugOut((DEB_DIR,"In CDirectory::setup(%lu)\n",cSect));
  1052. SCODE sc;
  1053. _cdeEntries = _pmsParent->GetSectorSize() / sizeof(CDirEntry);
  1054. _dv.InitCommon(_pmsParent->GetSectorSize());
  1055. sc = _dv.Init(_pmsParent, 1));
  1056. if (FAILED(sc))
  1057. msfDebugOut((DEB_DIR,"Error in CDirVector::Init. Cannot recover\n"));
  1058. _cdsTable = cSect;
  1059. DIRINDEX i;
  1060. for (i = 0; i < cSect; i++)
  1061. {
  1062. ULONG ulRetval;
  1063. CDirEntry *pds;
  1064. msfChk(_dv.GetBlock(i, &pds));
  1065. sc = _pmsParent->ReadSect(SIDDIR,i,pds,ulRetval);
  1066. if (!FAILED(sc))
  1067. {
  1068. if (ulRetval != _pmsParent->GetSectorSize())
  1069. msfDebugOut((DEB_DIR, "STG_E_READFAULT\n"));
  1070. }
  1071. }
  1072. msfDebugOut((DEB_DIR,"Out CDirectory::setup()\n"));
  1073. sc = S_OK;
  1074. Err:
  1075. return sc;
  1076. }
  1077. #endif
  1078. //+-------------------------------------------------------------------------
  1079. //
  1080. // Member: CDirectory::GetDirEntry
  1081. //
  1082. // Synopsis: Get a directory entry with given permissions
  1083. //
  1084. // Arguments: [sid] -- SID
  1085. // [dwFlags] -- permissions
  1086. // [ppde] -- placeholder for directory entry
  1087. //
  1088. // Returns: S_OK if call completed OK.
  1089. //
  1090. // Algorithm:
  1091. //
  1092. // History: ??-???-?? PhilipLa Created.
  1093. // 19-Jan-93 AlexT Made non-inline for code savings
  1094. //
  1095. //--------------------------------------------------------------------------
  1096. SCODE CDirectory::GetDirEntry(
  1097. const SID sid,
  1098. const DWORD dwFlags,
  1099. CDirEntry **ppde)
  1100. {
  1101. SCODE sc;
  1102. CDirSect *pds;
  1103. DIRINDEX id;
  1104. id = sid / _cdeEntries;
  1105. msfChk(_dv.GetTable(id, dwFlags, &pds));
  1106. *ppde = pds->GetEntry((DIROFFSET)(sid % _cdeEntries));
  1107. Err:
  1108. return sc;
  1109. }
  1110. //+-------------------------------------------------------------------------
  1111. //
  1112. // Member: CDirectory::ReleaseEntry
  1113. //
  1114. // Synopsis: Releases a directory entry
  1115. //
  1116. // Arguments: [sid] -- SID
  1117. //
  1118. // Returns: S_OK if call completed OK.
  1119. //
  1120. // Algorithm:
  1121. //
  1122. // History: ??-???-?? PhilipLa Created.
  1123. // 19-Jan-93 AlexT Made non-inline for code savings
  1124. //
  1125. //--------------------------------------------------------------------------
  1126. void CDirectory::ReleaseEntry(SID sid)
  1127. {
  1128. _dv.ReleaseTable(sid / _cdeEntries);
  1129. }