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.

1131 lines
28 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1996.
  5. //
  6. // File: dir.cxx
  7. //
  8. // Contents: Directory Functions
  9. //
  10. //---------------------------------------------------------------
  11. #include "msfhead.cxx"
  12. #include "h/dirfunc.hxx"
  13. #include "mread.hxx"
  14. #define DEB_DIR (DEB_ITRACE | 0x00040000)
  15. //+-------------------------------------------------------------------------
  16. //
  17. // Member: CMStream::KillStream, public
  18. //
  19. // Synopsis: Eliminate a given chain
  20. //
  21. // Arguments: [sectStart] -- Beginning of chain to eliminate
  22. //
  23. // Returns: S_OK if call completed OK.
  24. //
  25. // Algorithm:
  26. //
  27. // Notes:
  28. //
  29. //--------------------------------------------------------------------------
  30. inline SCODE CMStream::KillStream(SECT sectStart, ULONGLONG ulSize)
  31. {
  32. CFat *pfat;
  33. pfat = (ulSize < MINISTREAMSIZE) ?&_fatMini: &_fat;
  34. return pfat->SetChainLength(sectStart, 0);
  35. }
  36. //+-------------------------------------------------------------------------
  37. //
  38. // Member: GetNewDirEntryArray, public
  39. //
  40. // Synopsis: Obtain a new array of CDirEntry(s)
  41. //
  42. // Arguments: [cbSector] -- size of a sector
  43. //
  44. // Returns: New CDirEntry array
  45. //
  46. // Algorithm: calculates the number of entries need for the array and
  47. // allocate it
  48. //
  49. // Notes:
  50. //
  51. //--------------------------------------------------------------------------
  52. inline CDirEntry* GetNewDirEntryArray(USHORT cbSector)
  53. {
  54. CDirEntry *temp;
  55. DIROFFSET cdeEntries = (USHORT) (cbSector / sizeof(CDirEntry));
  56. temp = new CDirEntry[cdeEntries];
  57. return temp;
  58. }
  59. //+-------------------------------------------------------------------------
  60. //
  61. // Member: CDirEntry::Init, public
  62. //
  63. // Synopsis: Initializes member data
  64. //
  65. // Arguments: [mse] -- multi-stream entry flags for the directory entry
  66. //
  67. // Returns: void
  68. //
  69. // Algorithm:
  70. //
  71. // Notes:
  72. //
  73. //--------------------------------------------------------------------------
  74. inline void CDirEntry::Init(MSENTRYFLAGS mse)
  75. {
  76. msfAssert(sizeof(CDirEntry) == DIRENTRYSIZE);
  77. memset(this, 0, sizeof(CDirEntry));
  78. msfAssert(mse <= 0xff);
  79. _mse = (BYTE) mse;
  80. _bflags = 0;
  81. _dfn.Set((WORD)0, (BYTE *)NULL);
  82. _sidLeftSib = _sidRightSib = _sidChild = NOSTREAM;
  83. if (STORAGELIKE(_mse))
  84. {
  85. _clsId = IID_NULL;
  86. _dwUserFlags = 0;
  87. }
  88. if (STREAMLIKE(_mse))
  89. {
  90. _sectStart = ENDOFCHAIN;
  91. _ulSize = 0;
  92. }
  93. }
  94. //+-------------------------------------------------------------------------
  95. //
  96. // Method: CDirEntry::CDirEntry, public
  97. //
  98. // Synopsis: Constructor for CDirEntry class
  99. //
  100. // Effects:
  101. //
  102. // Notes:
  103. //
  104. //--------------------------------------------------------------------------
  105. CDirEntry::CDirEntry()
  106. {
  107. msfAssert(sizeof(CDirEntry) == DIRENTRYSIZE);
  108. Init(STGTY_INVALID);
  109. }
  110. //+-------------------------------------------------------------------------
  111. //
  112. // Method: CDirSect::Init, public
  113. //
  114. // Synopsis: Initializer for directory sectors
  115. //
  116. // Arguments: [cdeEntries] -- Number of DirEntries in the sector
  117. //
  118. // Returns: S_OK if call completed OK.
  119. //
  120. // Notes:
  121. //
  122. //--------------------------------------------------------------------------
  123. SCODE CDirSect::Init(USHORT cbSector)
  124. {
  125. msfDebugOut((DEB_DIR,"Allocating sector with size %u\n",cbSector));
  126. DIROFFSET cdeEntries = (USHORT) (cbSector / sizeof(CDirEntry));
  127. for (ULONG i = 0; i < cdeEntries; i++)
  128. {
  129. _adeEntry[i].Init(STGTY_INVALID);
  130. }
  131. return S_OK;
  132. }
  133. //+-------------------------------------------------------------------------
  134. //
  135. // Method: CDirectory::CDirectory
  136. //
  137. // Synopsis: Default constructor
  138. //
  139. // Notes:
  140. //
  141. //--------------------------------------------------------------------------
  142. CDirectory::CDirectory(USHORT cbSector)
  143. : _pmsParent(NULL),
  144. _dv(cbSector)
  145. {
  146. _cdsTable = _cdeEntries = 0;
  147. _sidFirstFree = 0;
  148. }
  149. //+---------------------------------------------------------------------------
  150. //
  151. // Member: CDirectory::Empty, public
  152. //
  153. // Synopsis: Empty all the control structures of this instance
  154. //
  155. // Arguments: None.
  156. //
  157. // Returns: void.
  158. //
  159. //----------------------------------------------------------------------------
  160. void CDirectory::Empty(void)
  161. {
  162. _dv.Empty();
  163. _pmsParent = NULL;
  164. _cdsTable = 0;
  165. _cdeEntries = 0;
  166. _sidFirstFree = 0;
  167. }
  168. //+-------------------------------------------------------------------------
  169. //
  170. // Member: CDirectory::GetFree, public
  171. //
  172. // Synposis: Locates a free directory entry
  173. //
  174. // Arguments: [psid] Stream ID of free directory entry.
  175. //
  176. // Returns: S_OK if successful
  177. //
  178. // Algorithm: Do a linear search of all available directories.
  179. // If no free spot is found, resize the directory and
  180. // perform the search again.
  181. //
  182. // Notes:
  183. //
  184. //---------------------------------------------------------------------------
  185. SCODE CDirectory::GetFree(SID* psid)
  186. {
  187. msfDebugOut((DEB_DIR,"In CDirectory::GetFree()\n"));
  188. SCODE sc = S_OK;
  189. CDirSect * pds;
  190. DIRINDEX ipdsStart;
  191. DIROFFSET ideStart;
  192. SidToPair(_sidFirstFree, &ipdsStart, &ideStart);
  193. while (TRUE)
  194. {
  195. DIRINDEX ipds;
  196. for (ipds = ipdsStart; ipds < _cdsTable; ipds++)
  197. {
  198. msfChk(_dv.GetTable(ipds, FB_NONE, &pds));
  199. for (DIROFFSET ide = ideStart; ide < _cdeEntries; ide++)
  200. {
  201. if (pds->GetEntry(ide)->IsFree())
  202. {
  203. msfDebugOut((DEB_ITRACE,"GetFree found sid %lu\n",
  204. PairToSid(ipds,ide)));
  205. *psid = PairToSid(ipds, ide);
  206. _sidFirstFree = *psid + 1;
  207. _dv.ReleaseTable(ipds);
  208. return S_OK;
  209. }
  210. }
  211. _dv.ReleaseTable(ipds);
  212. ideStart = 0;
  213. }
  214. ipdsStart = ipds;
  215. msfChk(Resize(_cdsTable+1));
  216. }
  217. Err:
  218. return sc;
  219. }
  220. //+-------------------------------------------------------------------------
  221. //
  222. // Member: CDirectory::FindGreaterEntry
  223. //
  224. // Synopsis: finds next entry (for iteration)
  225. //
  226. // Arguments: [sidStart] -- child sid to start looking
  227. // [pdfn] -- previous entry name
  228. // [psidResult] -- place holder for returned sid
  229. //
  230. // Requires: sidStart != NOSTREAM
  231. //
  232. // Returns: S_OK, STG_E_NOMOREFILES, or other error
  233. //
  234. // Modifies: psidResult
  235. //
  236. // Algorithm: Iterate by returning the sid that has a name larger
  237. // than the given name.
  238. //
  239. // Notes: This method is called recursively
  240. //
  241. //--------------------------------------------------------------------------
  242. SCODE CDirectory::FindGreaterEntry(SID sidStart, CDfName const *pdfn,
  243. SID *psidResult)
  244. {
  245. SCODE sc;
  246. CDirEntry *pde;
  247. msfAssert(sidStart != NOSTREAM);
  248. msfChk(GetDirEntry(sidStart, FB_NONE, &pde));
  249. int iCmp;
  250. iCmp = NameCompare(pdfn, pde->GetName());
  251. if (iCmp < 0)
  252. {
  253. // Since the last name returned is less than this name,
  254. // the sid to return must either be to our left or this sid
  255. SID sidLeft = pde->GetLeftSib();
  256. // We can't hold onto sidStart as we recurse, (because we'll ask for
  257. // a page each time we recurse)
  258. ReleaseEntry(sidStart);
  259. if (sidLeft == sidStart)
  260. {
  261. //Corrupt docfile - return error.
  262. return STG_E_DOCFILECORRUPT;
  263. }
  264. if ((sidLeft == NOSTREAM) ||
  265. (sc = FindGreaterEntry(sidLeft, pdfn, psidResult)) == STG_E_NOMOREFILES)
  266. {
  267. // There was no left child with a name greater than pdfn, so
  268. // we return ourself
  269. *psidResult = sidStart;
  270. sc = S_OK;
  271. }
  272. }
  273. else
  274. {
  275. // The last name returned is greater than this one, so we've already
  276. // returned this sidStart. Look in the right subtree.
  277. SID sidRight = pde->GetRightSib();
  278. // We can't hold onto sidStart as we recurse, (because we'll ask for
  279. // a page each time we recurse)
  280. ReleaseEntry(sidStart);
  281. if (sidRight == sidStart)
  282. {
  283. //Corrupt docfile - return error.
  284. return STG_E_DOCFILECORRUPT;
  285. }
  286. if (sidRight == NOSTREAM)
  287. sc = STG_E_NOMOREFILES;
  288. else
  289. sc = FindGreaterEntry(sidRight, pdfn, psidResult);
  290. }
  291. Err:
  292. return(sc);
  293. }
  294. //+-------------------------------------------------------------------------
  295. //
  296. // Method: CDirectory::SetStart, public
  297. //
  298. // Synopsis: Set starting sector for a dir entry
  299. //
  300. // Arguments: [sid] -- SID of entry to be modified
  301. // [sect] -- New starting sector for entry
  302. //
  303. // Returns: SID of modified entry
  304. //
  305. // Notes:
  306. //
  307. //--------------------------------------------------------------------------
  308. SCODE CDirectory::SetStart(const SID sid, const SECT sect)
  309. {
  310. SCODE sc;
  311. CDirEntry *pde;
  312. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  313. pde->SetStart(sect);
  314. ReleaseEntry(sid);
  315. Err:
  316. return sc;
  317. }
  318. //+-------------------------------------------------------------------------
  319. //
  320. // Member: CDirectory::SetChild, public
  321. //
  322. // Synposis: Set the child SID of an entry
  323. //
  324. // Effects: Modifies a single directory entry. Causes a one sector
  325. // stream write.
  326. //
  327. // Arguments: [sid] -- Stream ID of entry to be set
  328. // [sidChild] -- SID of first child of this stream
  329. //
  330. // Returns: SID of modified entry
  331. //
  332. // Algorithm: Change child field on entry, then write to stream.
  333. //
  334. //---------------------------------------------------------------------------
  335. SCODE CDirectory::SetChild(const SID sid, const SID sidChild)
  336. {
  337. SCODE sc;
  338. CDirEntry *pde;
  339. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  340. pde->SetChild(sidChild);
  341. ReleaseEntry(sid);
  342. Err:
  343. return sc;
  344. }
  345. //+-------------------------------------------------------------------------
  346. //
  347. // Member: CDirectory::SetSize, public
  348. //
  349. // Synposis: Set the size 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. // [cbSize] -- Size
  356. //
  357. // Returns: SID of modified entry
  358. //
  359. // Algorithm: Change size field on entry, then write to stream.
  360. //
  361. //---------------------------------------------------------------------------
  362. SCODE CDirectory::SetSize(const SID sid, const ULONGLONG cbSize)
  363. {
  364. SCODE sc;
  365. CDirEntry *pde;
  366. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  367. pde->SetSize(cbSize);
  368. ReleaseEntry(sid);
  369. Err:
  370. return sc;
  371. }
  372. //+-------------------------------------------------------------------------
  373. //
  374. // Member: CDirectory::SetTime, public
  375. //
  376. // Synposis: Set the time of an entry
  377. //
  378. // Effects: Modifies a single directory entry. Causes a one sector
  379. // stream write.
  380. //
  381. // Arguments: [sid] -- Stream ID of entry to be set
  382. // [tt] - WT_*
  383. // [nt] - New time
  384. //
  385. // Returns: SID of modified entry
  386. //
  387. // Algorithm: Change time field on entry, then write to stream.
  388. //
  389. //---------------------------------------------------------------------------
  390. SCODE CDirectory::SetTime(const SID sid, WHICHTIME tt, TIME_T nt)
  391. {
  392. SCODE sc;
  393. CDirEntry *pde;
  394. // We don't support ACCESS times, so just ignore sets
  395. if (tt == WT_ACCESS)
  396. return S_OK;
  397. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  398. pde->SetTime(tt, nt);
  399. ReleaseEntry(sid);
  400. Err:
  401. return sc;
  402. }
  403. //+-------------------------------------------------------------------------
  404. //
  405. // Member: CDirectory::SetFlags, public
  406. //
  407. // Synposis: Set the flags of an entry
  408. //
  409. // Effects: Modifies a single directory entry. Causes a one sector
  410. // stream write.
  411. //
  412. // Arguments: [sid] -- Stream ID of entry to be set
  413. // [mse] - New flags
  414. //
  415. // Returns: Status code
  416. //
  417. // Algorithm: Change Luid field on entry, then write to stream.
  418. //
  419. //---------------------------------------------------------------------------
  420. SCODE CDirectory::SetFlags(const SID sid, const MSENTRYFLAGS mse)
  421. {
  422. SCODE sc;
  423. CDirEntry *pde;
  424. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  425. pde->SetFlags(mse);
  426. ReleaseEntry(sid);
  427. Err:
  428. return sc;
  429. }
  430. //+-------------------------------------------------------------------------
  431. //
  432. // Member: CDirectory::SetClassId, public
  433. //
  434. // Synposis: Set the class ID of an entry
  435. //
  436. // Effects: Modifies a single directory entry. Causes a one sector
  437. // stream write.
  438. //
  439. // Arguments: [sid] -- Stream ID of entry to be set
  440. // [cls] - Class ID
  441. //
  442. // Returns: Appropriate status code
  443. //
  444. //---------------------------------------------------------------------------
  445. SCODE CDirectory::SetClassId(const SID sid, const GUID cls)
  446. {
  447. SCODE sc;
  448. CDirEntry *pde;
  449. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  450. pde->SetClassId(cls);
  451. ReleaseEntry(sid);
  452. Err:
  453. return sc;
  454. }
  455. //+-------------------------------------------------------------------------
  456. //
  457. // Member: CDirectory::SetUserFlags, public
  458. //
  459. // Synposis: Set the user flags of an entry
  460. //
  461. // Effects: Modifies a single directory entry. Causes a one sector
  462. // stream write.
  463. //
  464. // Arguments: [sid] -- Stream ID of entry to be set
  465. // [dwUserFlags] - Flags
  466. // [dwMask] - Mask
  467. //
  468. // Returns: Appropriate status code
  469. //
  470. //---------------------------------------------------------------------------
  471. SCODE CDirectory::SetUserFlags(SID const sid,
  472. DWORD dwUserFlags,
  473. DWORD dwMask)
  474. {
  475. SCODE sc;
  476. CDirEntry *pde;
  477. msfChk(GetDirEntry(sid, FB_DIRTY, &pde));
  478. pde->SetUserFlags(dwUserFlags, dwMask);
  479. ReleaseEntry(sid);
  480. Err:
  481. return sc;
  482. }
  483. //+-------------------------------------------------------------------------
  484. //
  485. // Member: CDirectory::resize, private
  486. //
  487. // Synposis: Resize a directory.
  488. //
  489. // Effects: Reallocates space for directory table, copying over
  490. // old pointers as necessary. Any new tables needed are
  491. // created here.
  492. //
  493. // Arguments: [uNewsize] -- New size for Directory
  494. //
  495. // Returns: void
  496. //
  497. // Algorithm: Allocate a new array of pointers of the necessary size.
  498. // Then, copy over all pointers from old array and allocate
  499. // new CDirSects for all new tables.
  500. //
  501. // Notes:
  502. //
  503. //---------------------------------------------------------------------------
  504. SCODE CDirectory::Resize(DIRINDEX uNewsize)
  505. {
  506. msfDebugOut((DEB_DIR,"In CDirectory::Resize(%i)\n",uNewsize));
  507. SCODE sc;
  508. if (uNewsize == _cdsTable) return S_OK;
  509. SECT sect;
  510. //GetESect call will make sure we have enough Fat space.
  511. msfChk(_pmsParent->GetESect(SIDDIR, uNewsize - 1, &sect));
  512. msfChk(_pmsParent->SetSize());
  513. msfChk(_dv.Resize(uNewsize));
  514. ULONG ipds;
  515. for (ipds = _cdsTable; ipds < uNewsize; ipds++)
  516. {
  517. CDirSect *pds;
  518. msfChk(_dv.GetTable(ipds, FB_NEW, &pds));
  519. SECT sect;
  520. msfChk(_pmsParent->GetESect(SIDDIR, ipds, &sect));
  521. _dv.SetSect(ipds, sect);
  522. _dv.ReleaseTable(ipds);
  523. }
  524. _cdsTable = uNewsize;
  525. msfChk(_pmsParent->GetHeader()->SetDirLength (_cdsTable));
  526. Err:
  527. return sc;
  528. }
  529. //+-------------------------------------------------------------------------
  530. //
  531. // Member: CDirectory::Init, public
  532. //
  533. // Synposis: Sets up a Directory instance and reads in all tables
  534. // from the stream
  535. //
  536. // Arguments: [cSect] -- Number of sectors in directory
  537. //
  538. // Returns: S_OK if call completed OK.
  539. // STG_E_READFAULT if not enough bytes were read for
  540. // a DirSector
  541. // Error code of read if read returned an error.
  542. //
  543. // Algorithm: Create array to hold appropriate number of tables.
  544. // Read in each table from disk.
  545. //
  546. //---------------------------------------------------------------------------
  547. SCODE CDirectory::Init(
  548. CMStream *pmsParent,
  549. DIRINDEX cSect)
  550. {
  551. msfDebugOut((DEB_DIR,"In CDirectory::Init(%lu)\n",cSect));
  552. SCODE sc;
  553. _pmsParent = pmsParent;
  554. _cdeEntries = (DIROFFSET)
  555. ( _pmsParent->GetSectorSize() / sizeof(CDirEntry));
  556. msfChk(_dv.Init(_pmsParent, cSect));
  557. _cdsTable = cSect;
  558. msfDebugOut((DEB_DIR,"Out CDirectory::Init()\n"));
  559. Err:
  560. return sc;
  561. }
  562. //+-------------------------------------------------------------------------
  563. //
  564. // Member: CDirectory::InitNew, public
  565. //
  566. // Synposis: Sets up a new Directory instance for a new Mstream
  567. //
  568. // Arguments: None.
  569. //
  570. // Returns: S_OK if call completed OK.
  571. // STG_E_WRITEFAULT if not enough bytes were written.
  572. // Error code of write if write failed.
  573. //
  574. // Algorithm: Write initial DirSector to disk.
  575. //
  576. // Notes:
  577. //
  578. //---------------------------------------------------------------------------
  579. SCODE CDirectory::InitNew(CMStream *pmsParent)
  580. {
  581. SCODE sc;
  582. #ifndef _MSC_VER
  583. #define ROOT_ENTRY "Root Entry"
  584. WCHAR *wcsRoot = new WCHAR[sizeof(ROOT_ENTRY)+1];
  585. _tbstowcs(wcsRoot, ROOT_ENTRY, sizeof(ROOT_ENTRY));
  586. CDfName const dfnRoot(wcsRoot);
  587. #else
  588. CDfName const dfnRoot(L"Root Entry");
  589. #endif
  590. msfDebugOut((DEB_DIR,"In CDirectory::setupnew()\n"));
  591. _pmsParent = pmsParent;
  592. _cdeEntries = (DIROFFSET)
  593. (_pmsParent->GetSectorSize() / sizeof(CDirEntry));
  594. msfChk(_dv.Init(_pmsParent, 1));
  595. CDirSect *pds;
  596. msfChk(_dv.GetTable(0, FB_NEW, &pds));
  597. _dv.SetSect(0, _pmsParent->GetHeader()->GetDirStart());
  598. _dv.ReleaseTable(0);
  599. _cdsTable = 1;
  600. SID sidRoot;
  601. msfChk(GetFree(&sidRoot));
  602. CDirEntry *pdeTemp;
  603. msfChk(GetDirEntry(sidRoot, FB_DIRTY, &pdeTemp));
  604. pdeTemp->Init(STGTY_ROOT);
  605. msfAssert(sidRoot == SIDROOT);
  606. pdeTemp->SetName(&dfnRoot);
  607. ReleaseEntry(sidRoot);
  608. msfDebugOut((DEB_DIR,"Exiting CDirectory::setupnew()\n"));
  609. Err:
  610. return sc;
  611. }
  612. //+-------------------------------------------------------------------------
  613. //
  614. // Method: CDirectory::CreateEntry, public
  615. //
  616. // Synopsis: Create a new directory entry
  617. //
  618. // Arguments: [sidParent] -- SID of parent for new entry
  619. // [pwcsName] -- Name of new entry
  620. // [mef] -- Flags for new entry
  621. // [psidNew] -- Return location for new SID
  622. //
  623. // Returns: S_OK if call completed OK.
  624. //
  625. // Algorithm: Search directory for entry of the same name. If one
  626. // is found, return STG_E_FILEALREADYEXISTS.
  627. // If not, create a new entry and return its SID.
  628. //
  629. //--------------------------------------------------------------------------
  630. SCODE CDirectory::CreateEntry(
  631. SID sidParent,
  632. CDfName const *pdfn,
  633. MSENTRYFLAGS mef,
  634. SID *psidNew)
  635. {
  636. SCODE sc;
  637. SID sidNew;
  638. CDirEntry *pdeNew;
  639. SEntryBuffer eb;
  640. sc = IsEntry(sidParent, pdfn, &eb);
  641. if (sc != STG_E_FILENOTFOUND)
  642. {
  643. if (SUCCEEDED(sc))
  644. sc = STG_E_FILEALREADYEXISTS;
  645. return(sc);
  646. }
  647. // Allocate new sid
  648. msfChk(GetFree(psidNew));
  649. sidNew = *psidNew;
  650. msfChk(GetDirEntry(sidNew, FB_DIRTY, &pdeNew));
  651. // Initialize new entry
  652. pdeNew->Init(mef);
  653. TIME_T timetemp;
  654. DfGetTOD(&timetemp);
  655. pdeNew->SetTime(WT_CREATION, timetemp);
  656. pdeNew->SetTime(WT_MODIFICATION, timetemp);
  657. pdeNew->SetName(pdfn);
  658. ReleaseEntry(sidNew);
  659. // Insert new entry into the tree
  660. msfChk(InsertEntry(sidParent, sidNew, pdfn));
  661. Err:
  662. return sc;
  663. }
  664. //+-------------------------------------------------------------------------
  665. //
  666. // Member: CDirectory::RenameEntry, public
  667. //
  668. // Synopsis: Rename an entry
  669. //
  670. // Arguments: [sidParent] -- Sid of parent of entry to be renamed
  671. // [pwcsName] -- Old name of entry to be renamed
  672. // [pwcsName] -- New name
  673. //
  674. // Returns: S_OK if call completed OK.
  675. //
  676. // Algorithm: Remove old entry
  677. // Rename entry
  678. // Insert as new entry
  679. //
  680. // Notes:
  681. //
  682. //--------------------------------------------------------------------------
  683. SCODE CDirectory::RenameEntry(SID const sidParent,
  684. CDfName const *pdfn,
  685. CDfName const *pdfnNew)
  686. {
  687. // Make sure new name doesn't already exist
  688. SCODE sc;
  689. SEntryBuffer eb;
  690. sc = IsEntry(sidParent, pdfnNew, &eb);
  691. if (sc != STG_E_FILENOTFOUND)
  692. {
  693. if (SUCCEEDED(sc))
  694. {
  695. // Entry did exist - fail this call
  696. sc = STG_E_ACCESSDENIED;
  697. }
  698. return(sc);
  699. }
  700. // We can't just rename in place (because the tree is ordered)
  701. CDirEntry *pdeRename;
  702. SEntryBuffer ebRename;
  703. msfChk(FindEntry(sidParent, pdfn, DEOP_REMOVE, &ebRename));
  704. sc = GetDirEntry(ebRename.sid, FB_DIRTY, &pdeRename);
  705. msfAssert(SUCCEEDED(sc) && aMsg("Could get dir entry to rename"));
  706. msfChk(sc);
  707. pdeRename->SetName(pdfnNew);
  708. ReleaseEntry(ebRename.sid);
  709. // If this InsertEntry fails, we've potentially lost the entry. This
  710. // doesn't matter becase:
  711. // a) The only way we could fail is if we couldn't read or write
  712. // the disk (hard error)
  713. // b) No one's going to call RenameEntry anyways
  714. // c) If we're transacted, the whole operation is made robust by
  715. // CopyOnWrite mode
  716. // d) If we're direct, we already know we can fail in ways that leave
  717. // the Docfile corrupt.
  718. sc = InsertEntry(sidParent, ebRename.sid, pdfnNew);
  719. msfAssert(SUCCEEDED(sc) && aMsg("Couldn't reinsert renamed dir entry"));
  720. msfChk(sc);
  721. Err:
  722. return sc;
  723. }
  724. //+-------------------------------------------------------------------------
  725. //
  726. // Member: CDirectory::DestroyAllChildren
  727. //
  728. // Synopsis: destroy all child entries
  729. //
  730. // Effects: destroys child tree
  731. //
  732. // Arguments: [sidParent] -- storage entry
  733. //
  734. // Returns: S_OK or error code
  735. //
  736. // Modifies: sidParent's entry
  737. //
  738. // Algorithm: While there's a child
  739. // destroy it
  740. //
  741. // Notes: We may want to consider a more efficient implementation
  742. //
  743. //--------------------------------------------------------------------------
  744. SCODE CDirectory::DestroyAllChildren(
  745. SID const sidParent)
  746. {
  747. SCODE sc;
  748. CDirEntry *pdeParent, *pdeChild;
  749. SID sidChild;
  750. CDfName dfnChild;
  751. for (;;)
  752. {
  753. CDfName dfnChild;
  754. msfChk(GetDirEntry(sidParent, FB_NONE, &pdeParent));
  755. sidChild = pdeParent->GetChild();
  756. ReleaseEntry(sidParent);
  757. if (sidChild == NOSTREAM)
  758. break;
  759. msfChk(GetDirEntry(sidChild, FB_NONE, &pdeChild));
  760. dfnChild.Set(pdeChild->GetName());
  761. ReleaseEntry(sidChild);
  762. msfChk(DestroyChild(sidParent, &dfnChild));
  763. }
  764. Err:
  765. return(sc);
  766. }
  767. //+-------------------------------------------------------------------------
  768. //
  769. // Member: CDirectory::DestroyChild
  770. //
  771. // Synopsis: destroy a named child
  772. //
  773. // Effects: destroys named child's entry
  774. //
  775. // Arguments: [sidParent] -- storage entry
  776. // [pdfn] -- child name
  777. //
  778. // Returns: S_OK, STG_E_FILENOTFOUND, or other error code
  779. //
  780. // Modifies: child's entry
  781. //
  782. // Algorithm: Find and remove child
  783. // Free child entry
  784. //
  785. //--------------------------------------------------------------------------
  786. SCODE CDirectory::DestroyChild(
  787. SID const sidParent,
  788. CDfName const *pdfn)
  789. {
  790. SCODE sc;
  791. SEntryBuffer ebChild;
  792. msfAssert(pdfn != NULL);
  793. // remove the entry from the tree
  794. msfChk(FindEntry(sidParent, pdfn, DEOP_REMOVE, &ebChild));
  795. msfAssert(ebChild.sid != NOSTREAM);
  796. // Before we remove this entry, we need to destroy it (including all
  797. // its children). Note that we can't hold onto the entry because it
  798. // might have children which get destroyed, which have children which
  799. // get destroyed, etc.
  800. if (STORAGELIKE(ebChild.dwType))
  801. {
  802. msfChk(DestroyAllChildren(ebChild.sid));
  803. }
  804. CDirEntry *pdeChild;
  805. msfChk(GetDirEntry(ebChild.sid, FB_DIRTY, &pdeChild));
  806. if (STREAMLIKE(ebChild.dwType))
  807. {
  808. // Deallocate any used streams
  809. msfChkTo(EH_Rel, _pmsParent->KillStream(pdeChild->GetStart(),
  810. pdeChild->GetSize(IsLargeSector())));
  811. }
  812. pdeChild->SetFlags(STGTY_INVALID);
  813. if (ebChild.sid < _sidFirstFree)
  814. {
  815. _sidFirstFree = ebChild.sid;
  816. }
  817. EH_Rel:
  818. ReleaseEntry(ebChild.sid);
  819. Err:
  820. return(sc);
  821. }
  822. //+-------------------------------------------------------------------------
  823. //
  824. // Method: CDirectory::StatEntry
  825. //
  826. // Synopsis: For a given handle, fill in the Multistream specific
  827. // information of a STATSTG.
  828. //
  829. // Arguments: [sid] -- SID that information is requested on.
  830. // [pName] -- name of the next key to fill in
  831. // [pstatstg] -- STATSTG to fill in.
  832. //
  833. // Returns: S_OK
  834. //
  835. // Modifies: [pName] -- if it is not null
  836. // [pstatstg] -- if it is not null
  837. //
  838. // Algorithm: Fill in time information and size and then return
  839. //
  840. //--------------------------------------------------------------------------
  841. SCODE CDirectory::StatEntry(SID const sid,
  842. CDfName *pName,
  843. STATSTGW *pstatstg)
  844. {
  845. SCODE sc;
  846. CDirEntry *pde;
  847. msfChk(GetDirEntry(sid, FB_NONE, &pde));
  848. if (pName)
  849. {
  850. pName->Set(pde->GetName());
  851. }
  852. if (pstatstg)
  853. {
  854. pstatstg->type = pde->GetFlags();
  855. // allocate memory
  856. msfChk(DfAllocWCS((WCHAR *)pde->GetName()->GetBuffer(),
  857. &pstatstg->pwcsName));
  858. wcscpy(pstatstg->pwcsName, (WCHAR*) pde->GetName()->GetBuffer());
  859. pstatstg->mtime = pde->GetTime(WT_MODIFICATION);
  860. pstatstg->ctime = pde->GetTime(WT_CREATION);
  861. pstatstg->atime = pstatstg->mtime; // don't currently keep access times
  862. // Don't use REAL_STGTY here because we want this
  863. // to function properly for both property and non-property builds
  864. if ((pstatstg->type & STGTY_REAL) == STGTY_STORAGE)
  865. {
  866. pstatstg->cbSize.QuadPart = 0;
  867. pstatstg->clsid = pde->GetClassId();
  868. pstatstg->grfStateBits = pde->GetUserFlags();
  869. }
  870. else
  871. {
  872. pstatstg->cbSize.QuadPart = pde->GetSize(IsLargeSector());
  873. pstatstg->clsid = CLSID_NULL;
  874. pstatstg->grfStateBits = 0;
  875. }
  876. }
  877. Err:
  878. ReleaseEntry(sid);
  879. return sc;
  880. }
  881. //+-------------------------------------------------------------------------
  882. //
  883. // Member: CDirectory::GetDirEntry
  884. //
  885. // Synopsis: Get a directory entry with given permissions
  886. //
  887. // Arguments: [sid] -- SID
  888. // [dwFlags] -- permissions
  889. // [ppde] -- placeholder for directory entry
  890. //
  891. // Returns: S_OK if call completed OK.
  892. //
  893. // Algorithm:
  894. //
  895. //--------------------------------------------------------------------------
  896. SCODE CDirectory::GetDirEntry(
  897. const SID sid,
  898. const DWORD dwFlags,
  899. CDirEntry **ppde)
  900. {
  901. SCODE sc;
  902. CDirSect *pds;
  903. DIRINDEX id = sid / _cdeEntries;
  904. msfChk(_dv.GetTable(id, dwFlags, &pds));
  905. *ppde = pds->GetEntry((DIROFFSET)(sid % _cdeEntries));
  906. Err:
  907. return sc;
  908. }
  909. //+-------------------------------------------------------------------------
  910. //
  911. // Member: CDirectory::ReleaseEntry
  912. //
  913. // Synopsis: Releases a directory entry
  914. //
  915. // Arguments: [sid] -- SID
  916. //
  917. // Returns: S_OK if call completed OK.
  918. //
  919. // Algorithm:
  920. //
  921. //--------------------------------------------------------------------------
  922. void CDirectory::ReleaseEntry(SID sid)
  923. {
  924. _dv.ReleaseTable(sid / _cdeEntries);
  925. }