Windows NT 4.0 source code leak
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.

1554 lines
38 KiB

4 years ago
  1. #ifdef M5_FORMAT //{
  2. // Multistream File (MSF) Implementation
  3. //
  4. // Revision History
  5. // When Who What
  6. // 4/92 jangr created in support of the minimal build proposal
  7. // 7/93 v-danwh added MSFCreateCopy
  8. // 8/93 jangr added MSFAppendStream and MSFReadStream2
  9. // eliminated requirement that streams be a multiple of
  10. // cbPg in size
  11. // open using appropriate share modes for safe
  12. // concurrency of read/read and no concurrency of
  13. // read/write or write/write
  14. // 2/94 jangr redesigned stream table structure to eliminate
  15. // limits and improve efficiency
  16. // eliminated MSFCreateCopy
  17. //
  18. // REVIEW: TO DO
  19. // * implement memory mapped file primitives
  20. // Behaviour: implements a multistream file, where each stream is assigned
  21. // a stream number. All operations are transacted. Logical change occurs
  22. // atomically at Commit time only. Operations include Open, Replace, Append,
  23. // Read, and Delete stream, and Commit and Close. Can query for the size of
  24. // a stream or for an unused stream no.
  25. //
  26. // A MSF is implemented as a sequence of pages. A page can contain
  27. // HDR -- header structure, including stream table stream info
  28. // FPM -- free page map: maps a page number (PN) to a boolean
  29. // where TRUE => page free
  30. // DATA -- a stream data page
  31. //
  32. // The first few pages of a MSF are special:
  33. // PN Type/Name Description
  34. // 0 HDR hdr page 0: master index
  35. // 1 FPM fpm0 first free page map
  36. // 2 FPM fpm1 second free page map
  37. //
  38. // According to hdr.pnFpm, the first or the second free page map is valid.
  39. //
  40. // There is one special stream, snST, the "stream table" stream. The stream
  41. // table maps a stream number (SN) into a stream info (SI). A stream info
  42. // stores the stream size and an index to the subarray of the page numbers
  43. // (PNs) that each stream uses.
  44. //
  45. // This organization enables efficient two-phase commit. At commit time,
  46. // after one or more streams have been written (to new pages), a new
  47. // ST stream is written and the new FPM is written. Then, a single
  48. // write to hdr swaps the roles of the two FPM sets and atomically
  49. // updates the MSF to reflect the new location of the ST stream.
  50. #include <stddef.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <io.h>
  54. #include <sys\stat.h>
  55. #include <fcntl.h>
  56. #include <share.h>
  57. #include <assert.h>
  58. #include <memory.h>
  59. #include <string.h>
  60. #include <malloc.h>
  61. #include <limits.h>
  62. #define MSF_IMP // for declspec()
  63. #include "msf.h"
  64. typedef unsigned short ushort;
  65. typedef ushort PN; // page number
  66. typedef ushort SPN; // stream page number
  67. typedef unsigned char BYTE;
  68. typedef BYTE* PB;
  69. typedef void* PV;
  70. const CB cbPg = 4096;
  71. const PN pnNil = (PN)-1;
  72. const PN pnMax = cbPg*CHAR_BIT-1; // max no of pgs in msf
  73. const PN pnHdr = 0;
  74. const PN pnFpm0 = 1;
  75. const PN pnFpm1 = 2;
  76. const PN pnDataMin = 3;
  77. const SPN spnNil = (SPN)-1;
  78. const SN snSt = 0; // stream info stream
  79. const SN snUserMin = 1; // first valid user sn
  80. const SN snMax = 4096; // max no of streams in msf
  81. const SPN spnMax = pnMax; // max no of pgs in a stream
  82. #define cpnForCb(cb) (((cb) + ::cbPg - 1) / ::cbPg)
  83. struct SI { // stream info
  84. CB cb; // length of stream, cbNil if stream does not exist
  85. PN* mpspnpn;
  86. SI() : cb(cbNil), mpspnpn(0) { }
  87. BOOL isValid() {
  88. return cb != cbNil;
  89. }
  90. BOOL allocForCb(CB cb_) {
  91. cb = cb_;
  92. if (!!(mpspnpn = new PN[spnMac()])) {
  93. for (SPN spn = 0; spn < spnMac(); spn++)
  94. mpspnpn[spn] = pnNil;
  95. return TRUE;
  96. } else
  97. return FALSE;
  98. }
  99. void dealloc() { // idempotent
  100. if (mpspnpn) {
  101. delete [] mpspnpn;
  102. mpspnpn = 0;
  103. }
  104. *this = SI();
  105. }
  106. SPN spnMac() {
  107. return (SPN)cpnForCb(cb);
  108. }
  109. };
  110. static SI siNil;
  111. struct FPM { // free page map
  112. enum {
  113. BPL = sizeof(long)*CHAR_BIT,
  114. lgBPL = 5,
  115. ilMax = cbPg/sizeof(long)
  116. };
  117. long rgl[ilMax];
  118. long mppnil(PN pn) {
  119. return pn >> lgBPL;
  120. }
  121. long mppnmask(PN pn) {
  122. return 1L << (pn & (BPL-1));
  123. }
  124. BOOL isFreePn(PN pn) {
  125. return !!(rgl[mppnil(pn)] & mppnmask(pn));
  126. }
  127. void allocPn(PN pn) {
  128. assert(pn != pnNil && isFreePn(pn));
  129. rgl[mppnil(pn)] &= ~mppnmask(pn);
  130. }
  131. void freePn(PN pn) {
  132. if (pn != pnNil)
  133. rgl[mppnil(pn)] |= mppnmask(pn);
  134. }
  135. void setAll() {
  136. memset(rgl, ~0, sizeof rgl);
  137. }
  138. void clearAll() {
  139. memset(rgl, 0, sizeof rgl);
  140. }
  141. void add(FPM& fpm) {
  142. for (int il = 0; il < ilMax; il++)
  143. rgl[il] |= fpm.rgl[il];
  144. }
  145. PN nextPn() {
  146. for (int il = 0; il < ilMax && rgl[il] == 0; il++)
  147. ;
  148. if (il == ilMax)
  149. return pnNil;
  150. long l = rgl[il];
  151. for (int i = 0; i < BPL && !(l & mppnmask(i)); i++)
  152. ;
  153. assert(i < BPL);
  154. PN pn = (PN)(il*BPL + i);
  155. allocPn(pn);
  156. return pn;
  157. }
  158. };
  159. struct ST { // (in memory) stream table
  160. SI mpsnsi[snMax];
  161. enum { cbMaxSerialization = snMax*sizeof(SI) + sizeof(SN) + sizeof(ushort) + pnMax*sizeof(PN) };
  162. enum serOp { ser, deser, size };
  163. ~ST() {
  164. dealloc();
  165. }
  166. void dealloc() { // idempotent because SI::dealloc() is
  167. for (SN sn = 0; sn < snMax; sn++)
  168. mpsnsi[sn].dealloc();
  169. }
  170. SN snMinFree() {
  171. for (SN sn = snUserMin; sn < snMax; sn++)
  172. if (!mpsnsi[sn].isValid())
  173. return sn;
  174. return snNil;
  175. }
  176. SN snMac() {
  177. // Find snMac, the largest sn such that mpsnsi[snMac-1].isValid(),
  178. // or 0 if there does not exist any mpsnsi[sn].isValid().
  179. for (SN sn = snMax; sn > 0 && !mpsnsi[sn-1].isValid(); sn--)
  180. ;
  181. return sn;
  182. }
  183. BOOL serialize(serOp op, PB pb, CB* pcb) {
  184. SN snMac = (op == deser) ? 0 : this->snMac();
  185. PB pbEnd = pb;
  186. switch (op) {
  187. case ser:
  188. *((SN*&)pbEnd)++ = snMac;
  189. *((ushort*&)pbEnd)++ = 0;
  190. memcpy(pbEnd, mpsnsi, snMac*sizeof(SI));
  191. pbEnd += snMac*sizeof(SI);
  192. break;
  193. case deser:
  194. snMac = *((SN*&)pbEnd)++;
  195. ((ushort*&)pbEnd)++;
  196. memcpy(mpsnsi, pbEnd, snMac*sizeof(SI));
  197. pbEnd += snMac*sizeof(SI);
  198. break;
  199. case size:
  200. pbEnd += sizeof(SN) + sizeof(ushort) + snMac*sizeof(SI);
  201. break;
  202. }
  203. for (SN sn = 0; sn < snMac; sn++) {
  204. SI si = mpsnsi[sn];
  205. if (si.isValid()) {
  206. switch (op) {
  207. case ser:
  208. memcpy(pbEnd, si.mpspnpn, si.spnMac()*sizeof(PN));
  209. break;
  210. case deser:
  211. if (!si.allocForCb(si.cb))
  212. return FALSE;
  213. memcpy(si.mpspnpn, pbEnd, si.spnMac()*sizeof(PN));
  214. mpsnsi[sn] = si;
  215. break;
  216. }
  217. (PN*&)pbEnd += si.spnMac();
  218. }
  219. }
  220. if (op == deser) {
  221. for ( ; sn < snMax; sn++)
  222. mpsnsi[sn] = siNil;
  223. }
  224. *pcb = pbEnd - pb;
  225. return TRUE;
  226. }
  227. };
  228. struct PG {
  229. char rgb[cbPg];
  230. };
  231. union HDR { // page 0
  232. struct {
  233. char szMagic[0x2C];
  234. CB cbPg; // page size
  235. PN pnFpm; // page no. of valid FPM
  236. PN pnMac; // current no. of pages
  237. SI siSt; // stream table stream info
  238. PN mpspnpnSt[cpnForCb(ST::cbMaxSerialization)];
  239. };
  240. PG pg;
  241. };
  242. static char szHdrMagic[0x2c] = "Microsoft C/C++ program database 2.00\r\n\x1a\x4a\x47";
  243. class MSF { // multistream file
  244. public:
  245. MSF() : fd(-1) { }
  246. BOOL Open(const char* name, BOOL fWrite, MSF_EC* pec);
  247. CB GetCbStream(SN sn);
  248. SN GetFreeSn();
  249. BOOL ReadStream(SN sn, PV pvBuf, CB cbBuf);
  250. BOOL ReadStream(SN sn, OFF off, PV pvBuf, CB* pcbBuf);
  251. BOOL WriteStream(SN sn, OFF off, PV pvBuf, CB cbBuf);
  252. BOOL ReplaceStream(SN sn, PV pvBuf, CB cbBuf);
  253. BOOL AppendStream(SN sn, PV pvBuf, CB cbBuf);
  254. BOOL DeleteStream(SN sn);
  255. BOOL Commit();
  256. BOOL Close();
  257. private:
  258. HDR hdr;
  259. FPM fpm;
  260. FPM fpmFreed;
  261. ST st;
  262. int fd;
  263. void init();
  264. BOOL load();
  265. BOOL create(const char* name, MSF_EC* pec);
  266. BOOL internalReplaceStream(SN sn, PV pvBuf, CB cbBuf);
  267. BOOL internalDeleteStream(SN sn);
  268. BOOL readWriteStream(SI si, OFF off, PV pvBuf, CB* pcbBuf,
  269. BOOL (MSF::*pRW)(PN*, OFF, CB, PV),
  270. BOOL (MSF::*pRWPn)(PN*, PV));
  271. BOOL validSn(SN sn) {
  272. return 0 <= sn && sn < snMax;
  273. }
  274. BOOL validUserSn(SN sn) {
  275. return validSn(sn) && sn != snSt;
  276. }
  277. BOOL extantSn(SN sn) {
  278. return validSn(sn) && st.mpsnsi[sn].cb != cbNil;
  279. }
  280. BOOL validPn(PN pn) {
  281. return 0 <= pn && pn < pnMax;
  282. }
  283. BOOL extantPn(PN pn) {
  284. return validPn(pn) && pn < hdr.pnMac;
  285. }
  286. PN allocPn() {
  287. PN pn = fpm.nextPn();
  288. if (pn != pnNil) {
  289. assert(pn <= hdr.pnMac);
  290. if (pn < hdr.pnMac)
  291. return pn;
  292. else if (_chsize(fd, (hdr.pnMac + 1)*cbPg) == 0) {
  293. ++hdr.pnMac;
  294. return pn;
  295. } else {
  296. fpm.freePn(pn); // back out
  297. return pnNil;
  298. }
  299. }
  300. return pnNil;
  301. }
  302. void freePn(PN pn) {
  303. fpmFreed.freePn(pn);
  304. }
  305. BOOL readPn(PN pn, PV buf) {
  306. return readPnOffCb(pn, 0, cbPg, buf);
  307. }
  308. BOOL readPpn(PN* ppn, PV buf) {
  309. return readPn(*ppn, buf);
  310. }
  311. BOOL readPnOffCb(PN pn, OFF off, CB cb, PV buf) {
  312. assert(extantPn(pn));
  313. return seekPnOff(pn, off) && _read(fd, buf, cb) == cb;
  314. }
  315. BOOL readPpnOffCb(PN* ppn, OFF off, CB cb, PV buf) {
  316. return readPnOffCb(*ppn, off, cb, buf);
  317. }
  318. BOOL writePn(PN pn, PV buf) {
  319. return writePnCb(pn, cbPg, buf);
  320. }
  321. BOOL writePnCb(PN pn, CB cb, PV buf) {
  322. return writePnOffCb(pn, 0, cb, buf);
  323. }
  324. BOOL writePnOffCb(PN pn, OFF off, CB cb, void *buf) {
  325. assert(extantPn(pn));
  326. return seekPnOff(pn, off) && _write(fd, buf, cb) == cb;
  327. }
  328. BOOL writeNewDataPgs(SI* psi, SPN spn, PV pvBuf, CB cbBuf) {
  329. for ( ; cbBuf >= cbPg; cbBuf -= cbPg) {
  330. if (!writeNewPn(&psi->mpspnpn[spn], pvBuf))
  331. return FALSE;
  332. spn++;
  333. pvBuf = (PB)pvBuf + cbPg;
  334. }
  335. return (cbBuf == 0) || writeNewPnCb(&psi->mpspnpn[spn], cbBuf, pvBuf);
  336. }
  337. BOOL writeNewPn(PN *ppn, PV buf) {
  338. return writeNewPnCb(ppn, cbPg, buf);
  339. }
  340. BOOL writeNewPnCb(PN *ppn, CB cb, PV buf) {
  341. assert(cb > 0);
  342. PN pn = allocPn();
  343. if (pn != pnNil && writePnCb(pn, cb, buf)) {
  344. freePn(*ppn);
  345. *ppn = pn;
  346. return TRUE;
  347. }
  348. return FALSE;
  349. }
  350. BOOL replacePnOffCb(PN *ppn, OFF off, CB cb, PV buf) {
  351. assert(off >= 0 && cb > 0 && off + cb < cbPg);
  352. PG pg;
  353. if (!readPn(*ppn, &pg))
  354. return FALSE;
  355. memcpy(pg.rgb + off, buf, cb);
  356. return writeNewPn(ppn, &pg);
  357. }
  358. BOOL seekPn(PN pn) {
  359. return seekPnOff(pn, 0);
  360. }
  361. BOOL seekPnOff(PN pn, OFF off) {
  362. assert(extantPn(pn) || pn <= hdr.pnMac + 1);
  363. assert(off <= cbPg);
  364. off += pn*cbPg;
  365. return (pn < pnMax) && _lseek(fd, off, SEEK_SET) == off;
  366. }
  367. #if defined(_DEBUG)
  368. void checkInvariants() {
  369. // check that every page is either free, freed, or in use in exactly one stream
  370. FPM fpmInUse;
  371. fpmInUse.clearAll();
  372. for (SN sn = 0; sn < snMax; sn++) {
  373. SI si = st.mpsnsi[sn];
  374. if (!si.isValid())
  375. continue;
  376. for (SPN spn = 0; spn < si.spnMac(); spn++) {
  377. PN pn = si.mpspnpn[spn];
  378. assert(!fpm.isFreePn(pn));
  379. assert(!fpmFreed.isFreePn(pn));
  380. assert(!fpmInUse.isFreePn(pn));
  381. fpmInUse.freePn(pn);
  382. }
  383. }
  384. for (PN pn = pnDataMin; pn < pnMax; pn++)
  385. assert(fpm.isFreePn(pn) + fpmFreed.isFreePn(pn) + fpmInUse.isFreePn(pn) == 1);
  386. }
  387. #endif
  388. };
  389. BOOL MSF::Open(const char *name, BOOL fWrite, MSF_EC* pec) {
  390. *pec = MSF_EC_OK;
  391. fd = fWrite ? _sopen(name, O_BINARY|O_RDWR, SH_DENYRW)
  392. : _sopen(name, O_BINARY|O_RDONLY, SH_DENYWR);
  393. if (fd >= 0) {
  394. hdr.pnMac = 1; // extantPn(pnHdr) must be TRUE for first readPn()!
  395. if (readPn(pnHdr, &hdr) &&
  396. memcmp(hdr.szMagic, szHdrMagic, sizeof szHdrMagic) == 0 &&
  397. hdr.cbPg == cbPg)
  398. {
  399. return load();
  400. }
  401. else {
  402. *pec = MSF_EC_FORMAT;
  403. _close(fd);
  404. fd = -1;
  405. return FALSE;
  406. }
  407. } else if (fWrite) {
  408. return create(name, pec);
  409. } else {
  410. *pec = MSF_EC_NOT_FOUND;
  411. return FALSE;
  412. }
  413. }
  414. BOOL MSF::load() {
  415. // load free page map
  416. if (!readPn(hdr.pnFpm, &fpm))
  417. return FALSE;
  418. // Build the stream table stream info from the header, then
  419. // load the stream table stream and deserialize it
  420. CB cb = hdr.siSt.cb;
  421. SI siSt;
  422. if (!siSt.allocForCb(cb))
  423. return FALSE;
  424. memcpy(siSt.mpspnpn, hdr.mpspnpnSt, siSt.spnMac()*sizeof(PN));
  425. PB pbSt = new BYTE[cb];
  426. if (!pbSt ||
  427. !readWriteStream(siSt, 0, pbSt, &cb, &MSF::readPpnOffCb, &MSF::readPpn) ||
  428. cb != siSt.cb ||
  429. !st.serialize(ST::deser, pbSt, &cb))
  430. return FALSE;
  431. delete [] pbSt;
  432. // The st.mpsnsi[snSt] just loaded is bogus: it is the ST stream in effect
  433. // prior to the previous Commit. Replace it with the good copy saved
  434. // in the MSF hdr.
  435. if (st.mpsnsi[snSt].isValid())
  436. st.mpsnsi[snSt].dealloc();
  437. st.mpsnsi[snSt] = siSt;
  438. init();
  439. #if defined(_DEBUG)
  440. checkInvariants();
  441. #endif
  442. return TRUE;
  443. }
  444. void MSF::init() {
  445. hdr.pnFpm = (hdr.pnFpm == pnFpm0) ? pnFpm1 : pnFpm0;
  446. fpmFreed.clearAll(); // no pages recently freed
  447. }
  448. // Create MSF: create file, hand craft initial hdr,, fpm0, and commit.
  449. BOOL MSF::create(const char *name, MSF_EC* pec) {
  450. if ((fd = _sopen(name, O_BINARY|O_RDWR|O_CREAT, SH_DENYRW,
  451. S_IREAD|S_IWRITE)) < 0)
  452. {
  453. *pec = MSF_EC_FILE_SYSTEM;
  454. return FALSE;
  455. }
  456. // init hdr
  457. memset(&hdr, 0, sizeof hdr);
  458. memcpy(&hdr.szMagic, szHdrMagic, sizeof szHdrMagic);
  459. hdr.cbPg = cbPg;
  460. hdr.pnFpm = pnFpm0;
  461. hdr.pnMac = pnDataMin;
  462. // (each SI in st.mpsnsi is already siNil)
  463. // init fpm0: mark all non-special pages free
  464. fpm.setAll();
  465. for (PN pn = 0; pn < pnDataMin; pn++)
  466. if (fpm.nextPn() != pn)
  467. assert(FALSE);
  468. fpmFreed.clearAll(); // no pages freed yet
  469. // store it!
  470. if (Commit())
  471. return TRUE;
  472. else {
  473. _close(fd);
  474. fd = -1;
  475. *pec = MSF_EC_FILE_SYSTEM;
  476. return FALSE;
  477. }
  478. }
  479. BOOL MSF::Commit() {
  480. #if defined(_DEBUG)
  481. checkInvariants();
  482. #endif
  483. // write the new stream table to disk as a special stream
  484. CB cbSt;
  485. PB pbSt;
  486. if (!st.serialize(ST::size, 0, &cbSt) ||
  487. !(pbSt = new BYTE[cbSt]) ||
  488. !st.serialize(ST::ser, pbSt, &cbSt) ||
  489. !internalReplaceStream(snSt, pbSt, cbSt))
  490. return FALSE;
  491. delete [] pbSt;
  492. // copy the stream table stream info into the header
  493. hdr.siSt = st.mpsnsi[snSt];
  494. assert(hdr.siSt.spnMac()*sizeof(PN) <= sizeof hdr.mpspnpnSt);
  495. memcpy(hdr.mpspnpnSt, hdr.siSt.mpspnpn, hdr.siSt.spnMac()*sizeof(PN));
  496. // mark pages that have been freed to the next FPM as free.
  497. fpm.add(fpmFreed);
  498. // save the free page map
  499. if (!writePn(hdr.pnFpm, &fpm))
  500. return FALSE;
  501. // at this point, all pages but hdr safely reside on disk
  502. if (!writePn(pnHdr, &hdr))
  503. return FALSE;
  504. init();
  505. return TRUE;
  506. }
  507. BOOL MSF::Close() {
  508. st.dealloc();
  509. if (_close(fd) >= 0) {
  510. fd = -1;
  511. return TRUE;
  512. }
  513. else {
  514. return FALSE;
  515. }
  516. }
  517. CB MSF::GetCbStream(SN sn) {
  518. return validUserSn(sn) && extantSn(sn) ? st.mpsnsi[sn].cb : cbNil;
  519. }
  520. SN MSF::GetFreeSn() {
  521. return st.snMinFree();
  522. }
  523. BOOL MSF::ReadStream(SN sn, PV pvBuf, CB cbBuf)
  524. {
  525. CB cbT = cbBuf;
  526. return ReadStream(sn, 0, pvBuf, &cbT) && cbT == cbBuf;
  527. }
  528. BOOL MSF::ReadStream(SN sn, OFF off, PV pvBuf, CB* pcbBuf) {
  529. return validUserSn(sn) && extantSn(sn) &&
  530. readWriteStream(st.mpsnsi[sn], off, pvBuf, pcbBuf,
  531. &MSF::readPpnOffCb, &MSF::readPpn);
  532. }
  533. // Overwrite a piece of a stream. Will not grow the stream, will fail instead.
  534. BOOL MSF::WriteStream(SN sn, OFF off, PV pvBuf, CB cbBuf) {
  535. return validUserSn(sn) && extantSn(sn) &&
  536. off + cbBuf <= GetCbStream(sn) &&
  537. readWriteStream(st.mpsnsi[sn], off, pvBuf, &cbBuf,
  538. &MSF::replacePnOffCb, &MSF::writeNewPn);
  539. }
  540. // Read or write a piece of a stream.
  541. BOOL MSF::readWriteStream(SI si, OFF off, PV pvBuf, CB* pcbBuf,
  542. BOOL (MSF::*pRW)(PN*, OFF, CB, PV),
  543. BOOL (MSF::*pRWPn)(PN*, PV))
  544. {
  545. // ensure off and *pcbBuf remain within the stream
  546. if (off < 0 || off > si.cb || *pcbBuf < 0)
  547. return FALSE;
  548. if (off + *pcbBuf > si.cb)
  549. *pcbBuf = si.cb - off;
  550. if (*pcbBuf == 0)
  551. return TRUE;
  552. CB cb = *pcbBuf;
  553. SPN spn = (SPN)(off / cbPg);
  554. OFF offPg = off % cbPg;
  555. // first partial page, if any
  556. if (offPg != 0) {
  557. CB cbFirst = __min(cbPg - offPg, cb);
  558. if (!(this->*pRW)(&si.mpspnpn[spn], offPg, cbFirst, pvBuf))
  559. return FALSE;
  560. cb -= cbFirst;
  561. spn++;
  562. pvBuf = (PB)pvBuf + cbFirst;
  563. }
  564. // intermediate full pages, if any
  565. for ( ; cb >= cbPg; cb -= cbPg, spn++, pvBuf = (PB)pvBuf + cbPg)
  566. if (!(this->*pRWPn)(&si.mpspnpn[spn], (PB)pvBuf))
  567. return FALSE;
  568. // last partial page, if any
  569. if (cb > 0 && !(this->*pRW)(&si.mpspnpn[spn], 0, cb, pvBuf))
  570. return FALSE;
  571. return TRUE;
  572. }
  573. BOOL MSF::ReplaceStream(SN sn, PV pvBuf, CB cbBuf) {
  574. return validUserSn(sn) && internalReplaceStream(sn, pvBuf, cbBuf);
  575. }
  576. BOOL MSF::internalReplaceStream(SN sn, PV pvBuf, CB cbBuf) {
  577. if (!validSn(sn) || cbBuf < 0)
  578. return FALSE;
  579. if (extantSn(sn))
  580. internalDeleteStream(sn);
  581. SI si;
  582. if (!si.allocForCb(cbBuf) || !writeNewDataPgs(&si, 0, pvBuf, cbBuf))
  583. return FALSE;
  584. st.mpsnsi[sn] = si;
  585. return TRUE;
  586. }
  587. BOOL MSF::AppendStream(SN sn, PV pvBuf, CB cbBuf) {
  588. if (!validUserSn(sn) || !extantSn(sn) || cbBuf < 0)
  589. return FALSE;
  590. if (cbBuf == 0)
  591. return TRUE;
  592. SI si = st.mpsnsi[sn];
  593. if (si.spnMac() < cpnForCb(si.cb + cbBuf)) {
  594. // allocate a new SI, copied from the old one
  595. SI siNew;
  596. if (!siNew.allocForCb(si.cb + cbBuf))
  597. return FALSE;
  598. memcpy(siNew.mpspnpn, si.mpspnpn, si.spnMac()*sizeof(PN));
  599. for (SPN spn = si.spnMac(); spn < siNew.spnMac(); spn++)
  600. siNew.mpspnpn[spn] = pnNil;
  601. siNew.cb = si.cb; // so far, nothing has been appended
  602. si.dealloc(); // free original SI
  603. si = siNew;
  604. }
  605. OFF offLast = si.cb % cbPg;
  606. if (offLast) {
  607. // fill any space on the last page of the stream
  608. PN pnLast = si.mpspnpn[si.spnMac() - 1];
  609. CB cbFirst = __min(cbPg - offLast, cbBuf);
  610. if (!writePnOffCb(pnLast, offLast, cbFirst, pvBuf))
  611. return FALSE;
  612. si.cb += cbFirst;
  613. cbBuf -= cbFirst;
  614. pvBuf = (PB)pvBuf + cbFirst;
  615. }
  616. if (cbBuf > 0) {
  617. // append additional data and update the stream map
  618. if (!writeNewDataPgs(&si, si.spnMac(), pvBuf, cbBuf))
  619. return FALSE;
  620. si.cb += cbBuf;
  621. }
  622. st.mpsnsi[sn] = si;
  623. return TRUE;
  624. }
  625. BOOL MSF::DeleteStream(SN sn) {
  626. return validUserSn(sn) && internalDeleteStream(sn);
  627. }
  628. BOOL MSF::internalDeleteStream(SN sn) {
  629. if (!extantSn(sn))
  630. return FALSE;
  631. SI si = st.mpsnsi[sn];
  632. for (SPN spn = 0; spn < si.spnMac(); spn++)
  633. freePn(si.mpspnpn[spn]);
  634. si.dealloc();
  635. st.mpsnsi[sn] = siNil;
  636. return TRUE;
  637. }
  638. extern "C" {
  639. // open MSF; return MSF* or NULL if error
  640. MSF* MSFOpen(const char *name, BOOL fWrite, MSF_EC *pec) {
  641. MSF* pmsf = new MSF;
  642. if (pmsf) {
  643. if (pmsf->Open(name, fWrite, pec))
  644. return pmsf;
  645. delete pmsf;
  646. }
  647. else
  648. *pec = MSF_EC_OUT_OF_MEMORY;
  649. return NULL;
  650. }
  651. // return first available SN, or snNil if all in use
  652. SN MSFGetFreeSn(MSF* pmsf) {
  653. return pmsf->GetFreeSn();
  654. }
  655. // return size of stream or cbNil if stream does not exist
  656. CB MSFGetCbStream(MSF* pmsf, SN sn) {
  657. return pmsf->GetCbStream(sn);
  658. }
  659. // read cbBuf bytes of stream into pvBuf; return TRUE if successful
  660. BOOL MSFReadStream(MSF* pmsf, SN sn, PV pvBuf, CB cbBuf) {
  661. return pmsf->ReadStream(sn, pvBuf, cbBuf);
  662. }
  663. // read *pcbBuf bytes of stream into pvBuf; set *pcbBuf and return TRUE if successful
  664. BOOL MSFReadStream2(MSF* pmsf, SN sn, OFF off, PV pvBuf, CB* pcbBuf) {
  665. return pmsf->ReadStream(sn, off, pvBuf, pcbBuf);
  666. }
  667. // overwrite stream with pvBuf; return TRUE if successful
  668. BOOL MSFWriteStream(MSF* pmsf, SN sn, OFF off, PV pvBuf, CB cbBuf) {
  669. return pmsf->WriteStream(sn, off, pvBuf, cbBuf);
  670. }
  671. // overwrite stream with pvBuf; return TRUE if successful
  672. BOOL MSFReplaceStream(MSF* pmsf, SN sn, PV pvBuf, CB cbBuf) {
  673. return pmsf->ReplaceStream(sn, pvBuf, cbBuf);
  674. }
  675. // append pvBuf to end of stream; return TRUE if successful
  676. BOOL MSFAppendStream(MSF* pmsf, SN sn, PV pvBuf, CB cbBuf) {
  677. return pmsf->AppendStream(sn, pvBuf, cbBuf);
  678. }
  679. // remove stream from the MSF; return TRUE if successful
  680. BOOL MSFDeleteStream(MSF* pmsf, SN sn) {
  681. return pmsf->DeleteStream(sn);
  682. }
  683. // commit all pending changes; return TRUE if successful
  684. BOOL MSFCommit(MSF* pmsf) {
  685. return pmsf->Commit();
  686. }
  687. // close MSF; return TRUE if successful
  688. BOOL MSFClose(MSF* pmsf) {
  689. BOOL fRet = pmsf->Close();
  690. delete pmsf;
  691. return fRet;
  692. }
  693. } // extern "C"
  694. #else // }{
  695. // Multistream File (MSF) Implementation
  696. //
  697. // Revision History
  698. // When Who What
  699. // 4/92 jangr created in support of the minimal build proposal
  700. // 7/93 v-danwh added MSFCreateCopy
  701. // 8/93 jangr added MSFAppendStream and MSFReadStream2
  702. // eliminated requirement that streams be a multiple of
  703. // cbPg in size
  704. // open using appropriate share modes for safe
  705. // concurrency of read/read and no concurrency of
  706. // read/write or write/write
  707. //
  708. // REVIEW: TO DO
  709. // * check that stream is opened for write before permitting
  710. // write, append, or commit.
  711. // * check that at most one write or append is done per stream per transaction
  712. // * implemented memory mapped file primitives
  713. // * increase size of ST to permit more streams/PDB.
  714. // A MSF is implemented as a sequence of pages. A page can contain
  715. // PG0 -- special page 0 structure: master index
  716. // FPM -- free page map: maps a page number (PN) to a boolean
  717. // where TRUE => page free
  718. // ST -- stream table: maps a stream number (SN) to stream info (SI):
  719. // - si.pn -- a page number
  720. // - si.cb -- length of stream
  721. // where si.pn is
  722. // - the PN of its stream map (SM), if !si.isOnePgStm()
  723. // - the PN of its single data page, if si.isOnePgStm()
  724. // SM -- stream map: maps a stream (data) page number (SPN) to actual PN
  725. // DATA -- a stream data page
  726. //
  727. // The first few pages of a MSF are special:
  728. // PN Type/Name Description
  729. // 0 PG0 pg0 page 0: master index
  730. // 1 ST st0 first stream table
  731. // 2 FPM fpm0 first free page map
  732. // 3 ST st1 second stream table
  733. // 4 FPM fpm1 second free page map
  734. //
  735. // According to pg0.pnSt and pg0.pnFpm, the first or the second stream table
  736. // and free page map are valid. The ST is used to find the SM for each
  737. // stream. Each SM locates the data pages for that stream.
  738. //
  739. // This organization enables efficient two-phase commit. After one or
  740. // more streams have been written (to new pages), the new ST and FPM
  741. // are written to the not-in-use set of ST and FPM pages. A single
  742. // write to pg0 swaps the roles of the two ST,FPM sets and atomically
  743. // updates the MSF to reflect the new contents of the written streams.
  744. //
  745. // MSF limits are a function of cbPg:
  746. // cbPg pnMax snMax spnMax comments
  747. // 256 2K 32 128 up to 32 32 KB streams in a max 512 KB MSF
  748. // 512 4K 64 256 up to 64 128 KB streams in a max 2 MB MSF
  749. // 1K 8K 128 512 up to 128 512 KB streams in a max 8 MB MSF
  750. // 2K 16K 256 1K up to 256 2 MB streams in a max 32 MB MSF
  751. // 4K 32K 512 2K up to 512 8 MB streams in a max 128 MB MSF
  752. // 8K 64K 1024 4K up to 1024 32 MB streams in a max 512 MB MSF
  753. // 16K 64K 2048 8K up to 2048 128 MB streams in a max 1 GB MSF
  754. #include <stddef.h>
  755. #include <stdio.h>
  756. #include <stdlib.h>
  757. #include <io.h>
  758. #include <sys\stat.h>
  759. #include <fcntl.h>
  760. #include <share.h>
  761. #include <assert.h>
  762. #include <memory.h>
  763. #include <string.h>
  764. #include <malloc.h>
  765. #include <assert.h>
  766. #include <limits.h>
  767. #include "msf.h"
  768. typedef unsigned short ushort;
  769. typedef ushort PN; // page number
  770. typedef ushort SPN; // stream page number
  771. typedef unsigned char BYTE;
  772. typedef BYTE* PB;
  773. #ifdef MSF_PAGE_SIZE
  774. #define cbPg MSF_PAGE_SIZE
  775. #else
  776. #define cbPg 4096
  777. #endif
  778. #ifndef OUT
  779. #define OUT /* out parameter */
  780. #endif
  781. #ifndef IN
  782. #define IN /* in parameter */
  783. #endif
  784. const PN pnNil = (PN)-1;
  785. const SPN spnNil = (SPN)-1;
  786. #if cbPg <= 4096
  787. // cbPg <= 4K, pn limited to no of bits in a fpm:
  788. const PN pnMax = cbPg*CHAR_BIT - 2; // max no of pgs in msf
  789. #else
  790. // cbPg >4K, pn limited to expressive range of a PN, sans pnNil:
  791. const PN pnMax = pnNil - 1; // max no of pgs in msf
  792. #endif
  793. struct SI { // stream info
  794. PN pn; // isOnePgStm(si) ? PN of DATA : PN of SM
  795. CB cb; // length of stream, cbNil if stream does not exist
  796. BOOL isOnePgStm() { return 0 <= cb && cb <= cbPg; }
  797. BOOL operator==(const SI& that) { return pn == that.pn && cb == that.cb; }
  798. BOOL operator!=(const SI& that) { return !(*this == that); }
  799. };
  800. const SI siNil = { pnNil, cbNil };
  801. const SN snMax = cbPg/sizeof(SI); // max no of streams in msf
  802. const SPN spnMax = cbPg/sizeof(PN); // max no of pgs in a stream
  803. const long magic = 0x3147534a; // :-)
  804. struct FPM { // free page map
  805. enum {
  806. BPL = sizeof(long)*CHAR_BIT,
  807. lgBPL = 5,
  808. ilMax = cbPg/sizeof(long)
  809. };
  810. long rgl[ilMax];
  811. long mppnil(PN pn) { return pn >> lgBPL; }
  812. long mppnmask(PN pn) { return 1L << (pn & (BPL-1)); }
  813. void allocPn(PN pn) { rgl[mppnil(pn)] &= ~mppnmask(pn); }
  814. void freePn(PN pn) { rgl[mppnil(pn)] |= mppnmask(pn); }
  815. PN nextPn();
  816. void setAll() { memset(rgl, ~0, sizeof rgl); }
  817. void clearAll() { memset(rgl, 0, sizeof rgl); }
  818. void add(FPM& fpm);
  819. };
  820. PN FPM::nextPn() {
  821. for (int il = 0; il < ilMax && rgl[il] == 0; il++)
  822. ;
  823. if (il == ilMax)
  824. return pnNil;
  825. long l = rgl[il];
  826. for (int i = 0; i < BPL && !(l & mppnmask(i)); i++)
  827. ;
  828. assert(i < BPL);
  829. PN pn = (PN)(il*BPL + i);
  830. allocPn(pn);
  831. return pn;
  832. }
  833. void FPM::add(FPM& fpm) {
  834. for (int il = 0; il < ilMax; il++)
  835. rgl[il] |= fpm.rgl[il];
  836. }
  837. union PG0 { // page 0
  838. struct {
  839. char szMagic[0x2C];
  840. CB cbPage; // page size
  841. ushort cpgSt; // no. of pages in an ST
  842. ushort cpgFpm; // no. of pages in a FPM
  843. PN pnSt; // page no. of valid ST
  844. PN pnFpm; // page no. of valid FPM
  845. PN pnMac; // current no. of pages
  846. };
  847. char rgb[cbPg];
  848. };
  849. static char szPg0Magic[0x2c] = "Microsoft C/C++ program database 1.02\r\n\x1a\x4a\x47";
  850. struct PG {
  851. char rgb[cbPg];
  852. };
  853. enum { pnPg0, pnSt0, pnFpm0, pnSt1, pnFpm1, pnSpecialMax };
  854. struct ST { // stream table
  855. SI mpsnsi[snMax];
  856. };
  857. struct SM { // stream map
  858. PN mpspnpn[spnMax];
  859. };
  860. class MSF { // multistream file
  861. public:
  862. BOOL Open(const char* name, BOOL fWrite, MSF_EC* pec);
  863. CB GetCbStream(SN sn);
  864. SN GetFreeSn();
  865. BOOL ReadStream(SN sn, OUT void* pvBuf, CB cbBuf);
  866. BOOL ReadStream(SN sn, OFF off, OUT void* pvBuf, IN OUT CB* pcbBuf);
  867. BOOL WriteStream(SN sn, OFF off, void* pvBuf, CB cbBuf);
  868. BOOL ReplaceStream(SN sn, void* pvBuf, CB cbBuf);
  869. BOOL AppendStream(SN sn, void* pvBuf, CB cbBuf);
  870. BOOL DeleteStream(SN sn);
  871. BOOL Copy(MSF* pmsfFrom);
  872. BOOL Commit();
  873. BOOL Pack();
  874. BOOL Close();
  875. private:
  876. void init();
  877. BOOL readPn(PN pn, void* pv);
  878. BOOL readPnOffCb(PN pn, OFF off, CB cb, void* pv);
  879. BOOL replacePnOffCb(PN *ppn, OFF off, CB cb, void* buf);
  880. BOOL writePn(PN pn, void* pv);
  881. BOOL writePnCb(PN pn, CB cb, void* pv);
  882. BOOL writePnOffCb(PN pn, OFF off, CB cb, void* pv);
  883. BOOL writeNewPn(PN* ppn, void* pv);
  884. BOOL writeNewPnCb(PN* ppn, CB cb, void* pv);
  885. BOOL writeNewDataPgsAndSm(PN* ppnSM, SM* psm, SPN spn, void* pvBuf, CB cbBuf);
  886. BOOL seekPn(PN pn);
  887. BOOL seekPnOff(PN pn, OFF off);
  888. BOOL readSm(SN sn, SM* psm);
  889. BOOL validPn(PN pn) { return 0 <= pn && pn < pnMax; }
  890. BOOL extantPn(PN pn) { return validPn(pn) && pn < pg0.pnMac; }
  891. PN allocPn();
  892. void freePn(PN pn);
  893. BOOL validSn(SN sn) { return 0 <= sn && sn < snMax; }
  894. BOOL extantSn(SN sn) { return validSn(sn) && st.mpsnsi[sn].pn != pnNil; }
  895. BOOL isOnePgStmSn(SN sn) { return extantSn(sn) &&
  896. st.mpsnsi[sn].isOnePgStm(); }
  897. // memory resident MSF pages; first three must be written on commit
  898. PG0 pg0;
  899. ST st;
  900. FPM fpm;
  901. FPM fpmFreed;
  902. // other state
  903. int fd;
  904. };
  905. BOOL MSF::Open(const char *name, BOOL fWrite, MSF_EC* pec) {
  906. *pec = MSF_EC_OK;
  907. fd = fWrite ? _sopen(name, O_BINARY|O_RDWR, SH_DENYRW)
  908. : _sopen(name, O_BINARY|O_RDONLY, SH_DENYWR);
  909. if (fd >= 0) {
  910. pg0.pnMac = 1; // extantPn(0) must be TRUE for first readPn()!
  911. if (readPn(0, &pg0) &&
  912. memcmp(pg0.szMagic, szPg0Magic, sizeof szPg0Magic) == 0 &&
  913. pg0.cbPage == cbPg &&
  914. readPn(pg0.pnSt, &st) &&
  915. readPn(pg0.pnFpm, &fpm))
  916. {
  917. init();
  918. return TRUE;
  919. }
  920. else {
  921. *pec = MSF_EC_FORMAT;
  922. _close(fd);
  923. fd = -1;
  924. return FALSE;
  925. }
  926. } else if (fWrite) {
  927. // Create MSF: create file, hand craft initial pg0, st0, fpm0,
  928. // and commit.
  929. if ((fd = _sopen(name, O_BINARY|O_RDWR|O_CREAT, SH_DENYRW,
  930. S_IREAD|S_IWRITE)) < 0) {
  931. *pec = MSF_EC_FILE_SYSTEM;
  932. return FALSE;
  933. }
  934. // init pg0
  935. memset(&pg0, 0, sizeof pg0);
  936. memcpy(&pg0.szMagic, szPg0Magic, sizeof szPg0Magic);
  937. pg0.cbPage = cbPg;
  938. pg0.cpgSt = 1;
  939. pg0.cpgFpm = 1;
  940. pg0.pnSt = pnSt0;
  941. pg0.pnFpm = pnFpm0;
  942. pg0.pnMac = pnSpecialMax;
  943. // init st0: mark all streams invalid
  944. for (SN sn = 0; sn < snMax; sn++)
  945. st.mpsnsi[sn] = siNil;
  946. // init fpm0: mark all non-special pages free
  947. fpm.setAll();
  948. for (PN pn = 0; pn < pnSpecialMax; pn++)
  949. if (pn != fpm.nextPn())
  950. return FALSE;
  951. fpmFreed.clearAll(); // no pages freed yet
  952. // store it!
  953. if (Commit())
  954. return TRUE;
  955. else {
  956. _close(fd);
  957. fd = -1;
  958. *pec = MSF_EC_FILE_SYSTEM;
  959. return FALSE;
  960. }
  961. } else {
  962. *pec = MSF_EC_NOT_FOUND;
  963. return FALSE;
  964. }
  965. }
  966. CB MSF::GetCbStream(SN sn) {
  967. return extantSn(sn) ? st.mpsnsi[sn].cb : cbNil;
  968. }
  969. SN MSF::GetFreeSn() {
  970. for (SN sn = 0; sn < snMax; sn++)
  971. if (!extantSn(sn))
  972. return sn;
  973. return snNil;
  974. }
  975. BOOL MSF::ReadStream(SN sn, OUT void* pvBuf, CB cbBuf)
  976. {
  977. CB cbT = cbBuf;
  978. return ReadStream(sn, 0, pvBuf, &cbT) && cbT == cbBuf;
  979. }
  980. BOOL MSF::ReadStream(SN sn, OFF off, OUT void* pvBuf, IN OUT CB *pcbBuf) {
  981. if (!extantSn(sn))
  982. return FALSE;
  983. // ensure off and *pcbBuf remain within the stream
  984. CB cbStm = GetCbStream(sn);
  985. if (off < 0 || off > cbStm || *pcbBuf < 0)
  986. return FALSE;
  987. if (off + *pcbBuf > cbStm)
  988. *pcbBuf = cbStm - off;
  989. if (*pcbBuf == 0)
  990. return TRUE;
  991. if (isOnePgStmSn(sn)) {
  992. // simple one page case
  993. assert(off + *pcbBuf <= cbPg);
  994. return readPnOffCb(st.mpsnsi[sn].pn, off, *pcbBuf, pvBuf);
  995. } else {
  996. // multiple page case
  997. SM sm;
  998. CB cb = *pcbBuf;
  999. SPN spn = off / cbPg;
  1000. OFF offPg = off % cbPg;
  1001. if (!readSm(sn, &sm))
  1002. return FALSE;
  1003. // first partial page, if any
  1004. if (offPg != 0) {
  1005. CB cbFirst = __min(cbPg - offPg, cb);
  1006. if (!readPnOffCb(sm.mpspnpn[spn], offPg, cbFirst, pvBuf))
  1007. return FALSE;
  1008. cb -= cbFirst;
  1009. spn++;
  1010. pvBuf = (PB)pvBuf + cbFirst;
  1011. }
  1012. // intermediate full pages, if any
  1013. for ( ; cb >= cbPg; cb -= cbPg, spn++, pvBuf = (PB)pvBuf + cbPg)
  1014. if (!readPn(sm.mpspnpn[spn], (PB)pvBuf))
  1015. return FALSE;
  1016. // last partial page, if any
  1017. if (cb > 0 && !readPnOffCb(sm.mpspnpn[spn], 0, cb, pvBuf))
  1018. return FALSE;
  1019. return TRUE;
  1020. }
  1021. }
  1022. // Overwrite a piece of a stream. Will not grow the stream, will fail instead.
  1023. //
  1024. BOOL MSF::WriteStream(SN sn, OFF off, void* pvBuf, CB cbBuf) {
  1025. if (!validSn(sn) || off < 0 || cbBuf < 0 || off + cbBuf > GetCbStream(sn))
  1026. return FALSE;
  1027. if (cbBuf == 0)
  1028. return TRUE;
  1029. SI si = st.mpsnsi[sn];
  1030. if (si.isOnePgStm()) {
  1031. PN pnWas = si.pn;
  1032. if (!replacePnOffCb(&si.pn, off, cbBuf, pvBuf))
  1033. return FALSE;
  1034. freePn(pnWas);
  1035. }
  1036. else {
  1037. // multiple page case
  1038. SPN spn = off / cbPg;
  1039. OFF offPg = off % cbPg;
  1040. SM sm;
  1041. SM smWas;
  1042. if (!readSm(sn, &sm))
  1043. return FALSE;
  1044. smWas = sm;
  1045. // first partial page, if any
  1046. if (offPg != 0) {
  1047. CB cbFirst = __min(cbPg - offPg, cbBuf);
  1048. if (!replacePnOffCb(&sm.mpspnpn[spn], offPg, cbFirst, pvBuf))
  1049. return FALSE;
  1050. cbBuf -= cbFirst;
  1051. spn++;
  1052. pvBuf = (PB)pvBuf + cbFirst;
  1053. }
  1054. // intermediate full pages, if any
  1055. for ( ; cbBuf >= cbPg; cbBuf -= cbPg, spn++, pvBuf = (PB)pvBuf + cbPg)
  1056. if (!writeNewPn(&sm.mpspnpn[spn], (PB)pvBuf))
  1057. return FALSE;
  1058. // last partial page, if any
  1059. if (cbBuf > 0)
  1060. if (!replacePnOffCb(&sm.mpspnpn[spn], 0, cbBuf, pvBuf))
  1061. return FALSE;
  1062. // update SM
  1063. PN pnSmWas = si.pn;
  1064. if (!writeNewPn(&si.pn, &sm))
  1065. return FALSE;
  1066. freePn(pnSmWas);
  1067. // free changed pages
  1068. CB cb;
  1069. for (cb = 0, spn = 0; cb < si.cb; cb += cbPg, spn++)
  1070. if (sm.mpspnpn[spn] != smWas.mpspnpn[spn])
  1071. freePn(smWas.mpspnpn[spn]);
  1072. }
  1073. st.mpsnsi[sn] = si;
  1074. return TRUE;
  1075. }
  1076. BOOL MSF::ReplaceStream(SN sn, void* pvBuf, CB cbBuf) {
  1077. if (!validSn(sn) || cbBuf < 0)
  1078. return FALSE;
  1079. SI si = siNil;
  1080. si.cb = cbBuf;
  1081. if (cbBuf <= cbPg) {
  1082. // write single page case
  1083. if (!writeNewPnCb(&si.pn, cbBuf, pvBuf))
  1084. return FALSE;
  1085. } else {
  1086. // write multiple pages case
  1087. SM sm;
  1088. if (!writeNewDataPgsAndSm(&si.pn, &sm, 0, pvBuf, cbBuf))
  1089. return FALSE;
  1090. }
  1091. if (extantSn(sn))
  1092. DeleteStream(sn);
  1093. st.mpsnsi[sn] = si;
  1094. return TRUE;
  1095. }
  1096. BOOL MSF::AppendStream(SN sn, void* pvBuf, CB cbBuf) {
  1097. if (!extantSn(sn) || cbBuf < 0)
  1098. return FALSE;
  1099. if (cbBuf == 0)
  1100. return TRUE;
  1101. SI si = st.mpsnsi[sn];
  1102. SM sm;
  1103. if (!si.isOnePgStm() && !readSm(sn, &sm))
  1104. return FALSE;
  1105. OFF offLast = si.cb % cbPg;
  1106. if (offLast || si.cb == 0) {
  1107. // fill any space on the last page of the stream
  1108. PN pnLast = si.isOnePgStm() ? si.pn : sm.mpspnpn[si.cb / cbPg];
  1109. CB cbFirst = __min(cbPg - offLast, cbBuf);
  1110. if (!writePnOffCb(pnLast, offLast, cbFirst, pvBuf))
  1111. return FALSE;
  1112. si.cb += cbFirst;
  1113. cbBuf -= cbFirst;
  1114. pvBuf = (PB)pvBuf + cbFirst;
  1115. }
  1116. if (cbBuf > 0) {
  1117. // Still more to append; must allocate new pages, write to them,
  1118. // and update the stream map.
  1119. PN pnSmOld = si.isOnePgStm() ? pnNil : si.pn;
  1120. // if necessary, make an n-page stream from the one page stream.
  1121. if (si.isOnePgStm())
  1122. sm.mpspnpn[0] = si.pn;
  1123. // append additional data and update the stream map
  1124. if (!writeNewDataPgsAndSm(&si.pn, &sm, si.cb / cbPg, pvBuf, cbBuf))
  1125. return FALSE;
  1126. si.cb += cbBuf;
  1127. // free the old SM, if present
  1128. if (pnSmOld != pnNil)
  1129. freePn(pnSmOld);
  1130. }
  1131. st.mpsnsi[sn] = si;
  1132. return TRUE;
  1133. }
  1134. BOOL MSF::DeleteStream(SN sn) {
  1135. if (!extantSn(sn))
  1136. return FALSE;
  1137. SI si = st.mpsnsi[sn];
  1138. // free old pages
  1139. if (si.isOnePgStm())
  1140. freePn(si.pn);
  1141. else {
  1142. SM sm;
  1143. CB cb;
  1144. SPN spn;
  1145. if (!readPn(si.pn, &sm))
  1146. return FALSE;
  1147. for (cb = 0, spn = 0; cb < si.cb; cb += cbPg, spn++)
  1148. freePn(sm.mpspnpn[spn]);
  1149. freePn(si.pn);
  1150. }
  1151. st.mpsnsi[sn] = siNil;
  1152. return TRUE;
  1153. }
  1154. BOOL MSF::writeNewDataPgsAndSm(PN* ppnSm, SM* psm, SPN spn, void* pvBuf, CB cbBuf) {
  1155. for ( ; cbBuf >= cbPg && spn < spnMax; cbBuf -= cbPg, spn++, pvBuf = (PB)pvBuf + cbPg)
  1156. if (!writeNewPn(&psm->mpspnpn[spn], pvBuf))
  1157. return FALSE;
  1158. if (cbBuf > 0 && (spn >= spnMax || !writeNewPnCb(&psm->mpspnpn[spn], cbBuf, pvBuf)))
  1159. return FALSE;
  1160. // nil out remaining SM entries
  1161. for (spn++; spn < spnMax; spn++)
  1162. psm->mpspnpn[spn] = pnNil;
  1163. // write new SM
  1164. return writeNewPn(ppnSm, psm);
  1165. }
  1166. BOOL MSF::Copy(MSF* pmsfFrom) {
  1167. // copy each valid stream from pmsfFrom to this.
  1168. for (SN sn = 0; sn < snMax; sn++) {
  1169. CB cb = pmsfFrom->GetCbStream(sn);
  1170. if (cb != cbNil) {
  1171. PB pbBuf = new BYTE[cb];
  1172. if (!pbBuf)
  1173. return FALSE;
  1174. BOOL fOK = pmsfFrom->ReadStream(sn, pbBuf, cb) && ReplaceStream(sn, pbBuf, cb);
  1175. delete [] pbBuf;
  1176. if (!fOK)
  1177. return FALSE;
  1178. }
  1179. }
  1180. return TRUE;
  1181. }
  1182. BOOL MSF::Commit() {
  1183. // mark pages that have been freed to the next FPM as free.
  1184. fpm.add(fpmFreed);
  1185. // save the free page map and the stream table
  1186. if (!writePn(pg0.pnFpm, &fpm) || !writePn(pg0.pnSt, &st))
  1187. return FALSE;
  1188. // at this point, all pages but pg0 safely reside on disk
  1189. if (!writePn(0, &pg0))
  1190. return FALSE;
  1191. init();
  1192. return TRUE;
  1193. }
  1194. BOOL MSF::Pack() {
  1195. return FALSE; // not yet implemented
  1196. }
  1197. BOOL MSF::Close() {
  1198. if (_close(fd) >= 0) {
  1199. fd = -1;
  1200. return TRUE;
  1201. }
  1202. else {
  1203. return FALSE;
  1204. }
  1205. }
  1206. void MSF::init() {
  1207. pg0.pnSt = (pg0.pnSt == pnSt0) ? pnSt1 : pnSt0;
  1208. pg0.pnFpm = (pg0.pnFpm == pnFpm0) ? pnFpm1 : pnFpm0;
  1209. fpmFreed.clearAll(); // no pages recently freed
  1210. }
  1211. BOOL MSF::readSm(SN sn, SM* psm) {
  1212. assert(extantSn(sn));
  1213. assert(!st.mpsnsi[sn].isOnePgStm());
  1214. return readPn(st.mpsnsi[sn].pn, psm);
  1215. }
  1216. BOOL MSF::readPn(PN pn, void* buf) {
  1217. return readPnOffCb(pn, 0, cbPg, buf);
  1218. }
  1219. BOOL MSF::readPnOffCb(PN pn, OFF off, CB cb, void* buf) {
  1220. assert(extantPn(pn));
  1221. return seekPnOff(pn, off) && _read(fd, buf, cb) == cb;
  1222. }
  1223. BOOL MSF::replacePnOffCb(PN *ppn, OFF off, CB cb, void* buf) {
  1224. assert(off >= 0 && cb >= 0 && off + cb < cbPg);
  1225. PG pg;
  1226. if (!readPn(*ppn, &pg))
  1227. return FALSE;
  1228. memcpy(pg.rgb + off, buf, cb);
  1229. return writeNewPn(ppn, &pg);
  1230. }
  1231. BOOL MSF::writePn(PN pn, void* buf) {
  1232. return writePnCb(pn, cbPg, buf);
  1233. }
  1234. BOOL MSF::writePnCb(PN pn, CB cb, void* buf) {
  1235. return writePnOffCb(pn, 0, cb, buf);
  1236. }
  1237. BOOL MSF::writePnOffCb(PN pn, OFF off, CB cb, void *buf) {
  1238. assert(extantPn(pn));
  1239. return seekPnOff(pn, off) && _write(fd, buf, cb) == cb;
  1240. }
  1241. BOOL MSF::writeNewPn(PN *ppn, void* buf) {
  1242. return writeNewPnCb(ppn, cbPg, buf);
  1243. }
  1244. BOOL MSF::writeNewPnCb(PN *ppn, CB cb, void* buf) {
  1245. PN pn = allocPn();
  1246. if (pn != pnNil && (cb == 0 || writePnCb(pn, cb, buf))) {
  1247. *ppn = pn;
  1248. return TRUE;
  1249. }
  1250. return FALSE;
  1251. }
  1252. BOOL MSF::seekPn(PN pn) {
  1253. return seekPnOff(pn, 0);
  1254. }
  1255. BOOL MSF::seekPnOff(PN pn, OFF off) {
  1256. assert(extantPn(pn) || pn <= pg0.pnMac + 1);
  1257. assert(off <= cbPg);
  1258. off += pn*cbPg;
  1259. return (pn < pnMax) && _lseek(fd, off, SEEK_SET) == off;
  1260. }
  1261. PN MSF::allocPn() {
  1262. PN pn = fpm.nextPn();
  1263. if (pn != pnNil) {
  1264. assert(pn <= pg0.pnMac);
  1265. if (pn < pg0.pnMac)
  1266. return pn;
  1267. else if (_chsize(fd, (pg0.pnMac + 1)*cbPg) == 0) {
  1268. ++pg0.pnMac;
  1269. return pn;
  1270. } else {
  1271. fpm.freePn(pn); // back out
  1272. return pnNil;
  1273. }
  1274. }
  1275. return pnNil;
  1276. }
  1277. void MSF::freePn(PN pn) {
  1278. fpmFreed.freePn(pn); // pages freed to new FPM
  1279. }
  1280. extern "C" {
  1281. // open MSF; return MSF* or NULL if error
  1282. MSF* MSFOpen(const char *name, BOOL fWrite, MSF_EC *pec) {
  1283. MSF* pmsf = new MSF;
  1284. if (pmsf) {
  1285. if (pmsf->Open(name, fWrite, pec))
  1286. return pmsf;
  1287. delete pmsf;
  1288. }
  1289. else
  1290. *pec = MSF_EC_OUT_OF_MEMORY;
  1291. return NULL;
  1292. }
  1293. // return first available SN, or snNil if all in use
  1294. SN MSFGetFreeSn(MSF* pmsf) {
  1295. return pmsf->GetFreeSn();
  1296. }
  1297. // return size of stream or cbNil if stream does not exist
  1298. CB MSFGetCbStream(MSF* pmsf, SN sn) {
  1299. return pmsf->GetCbStream(sn);
  1300. }
  1301. // read cbBuf bytes of stream into pvBuf; return TRUE if successful
  1302. BOOL MSFReadStream(MSF* pmsf, SN sn, OUT void* pvBuf, CB cbBuf) {
  1303. return pmsf->ReadStream(sn, pvBuf, cbBuf);
  1304. }
  1305. // read *pcbBuf bytes of stream into pvBuf; set *pcbBuf and return TRUE if successful
  1306. BOOL MSFReadStream2(MSF* pmsf, SN sn, OFF off, OUT void* pvBuf, IN OUT CB* pcbBuf) {
  1307. return pmsf->ReadStream(sn, off, pvBuf, pcbBuf);
  1308. }
  1309. // overwrite stream with pvBuf; return TRUE if successful
  1310. BOOL MSFWriteStream(MSF* pmsf, SN sn, OFF off, void* pvBuf, CB cbBuf) {
  1311. return pmsf->WriteStream(sn, off, pvBuf, cbBuf);
  1312. }
  1313. // overwrite stream with pvBuf; return TRUE if successful
  1314. BOOL MSFReplaceStream(MSF* pmsf, SN sn, void* pvBuf, CB cbBuf) {
  1315. return pmsf->ReplaceStream(sn, pvBuf, cbBuf);
  1316. }
  1317. // append pvBuf to end of stream; return TRUE if successful
  1318. BOOL MSFAppendStream(MSF* pmsf, SN sn, void* pvBuf, CB cbBuf) {
  1319. return pmsf->AppendStream(sn, pvBuf, cbBuf);
  1320. }
  1321. // remove stream from the MSF; return TRUE if successful
  1322. BOOL MSFDeleteStream(MSF* pmsf, SN sn) {
  1323. return pmsf->DeleteStream(sn);
  1324. }
  1325. // commit all pending changes; return TRUE if successful
  1326. BOOL MSFCommit(MSF* pmsf) {
  1327. return pmsf->Commit();
  1328. }
  1329. // pack MSF on disk; return TRUE if successful
  1330. BOOL MSFPack(MSF* pmsf) {
  1331. return pmsf->Pack();
  1332. }
  1333. // close MSF; return TRUE if successful
  1334. BOOL MSFClose(MSF* pmsf) {
  1335. BOOL fRet = pmsf->Close();
  1336. delete pmsf;
  1337. return fRet;
  1338. }
  1339. // create a new MSF with the same contents.
  1340. MSF* MSFCreateCopy (MSF* pmsf, const char *pCopyName) {
  1341. MSF* pmsfNew = new MSF;
  1342. MSF_EC msfEc;
  1343. if (pmsfNew) {
  1344. if (pmsfNew->Open(pCopyName, TRUE, &msfEc) && pmsfNew->Copy(pmsf))
  1345. return pmsfNew;
  1346. delete pmsfNew;
  1347. }
  1348. return NULL;
  1349. }
  1350. } // extern "C"
  1351. #endif //}