📄 cpmbdos.cpp
字号:
} else { DirScanPrep(pX->pFcb, &pX->nTrk, &pX->nSec); pX->ivec = CREAT2; pX->cmnd = DD_READ; pX->pDma = (char*)DirBuf; message msg(nId, 3, 3, (void*)pX); pTx->PostMsg(nChan, &msg); }}///////////////// At this point, the outer packet has the result of a directory// scan for the file we want to kill off. If it was found, we can// simply set its flag char to "erased" and issue the rewrite.// If not found, it's only an error if we were looking for the// first extent - not found on subsequent extents is an Ok situation.//void CpmBdos::Remov1 (XfReq *pX){ if (FALSE == pX->bRes) { message msg(nId, pX->pFcb->de.nExtent ? FS_Ok : FS_NotFound); pTx->PostMsg(pX->uProc, &msg); } else { DIRENT *pDir = (DIRENT*)(pX->pDma + pX->pFcb->de.nRes1); pDir->nUsrNmbr = 0xF7; pX->ivec = REMOV2; pX->cmnd = DD_WRITE; message msg(nId, 4, 4, (void*)pX); pTx->PostMsg(nChan, &msg); }}/////////////// If the rewrite worked, we must unallocate (in our in-memory bit map)// all blocks associated with this file. If the extent was full, there// may be another which needs to be crossed off..//void CpmBdos::Remov2 (XfReq *pX){ if (FALSE == pX->bRes) DoRetry(pX); else { BOOL bDone; if (nAlb > 8) { BYTE *pB = pX->pFcb->de.nAllocBlk; int idx; for (idx = 0; *pB && (idx < nAlb); pB++, idx++) DeAllocBlk((UINT16)*pB); bDone = ((idx < nAlb) && (pX->pFcb->de.nRcnt < 7)) ? TRUE : FALSE; } else { UINT16 *pN = (UINT16*)pX->pFcb->de.nAllocBlk; int idx; for (idx = 0; *pN && (idx < nAlb); pN++, idx++) DeAllocBlk(*pN); bDone = ((idx < nAlb) && (pX->pFcb->de.nRcnt < 7)) ? TRUE : FALSE; } if (bDone) { message msg(nId, FS_Ok); pTx->PostMsg(pX->uProc, &msg); } else { ++pX->pFcb->de.nExtent; Remov(pX); } }}///////////////// we arrive here when the nested dir scan has located the dir block// (which was cunningly transferred to the inner XfReq sec/trk vars)// so from here we issue the re-write..//void CpmBdos::Close1 (XfReq *pX){ pX->ivec = CLOSE2; pX->cmnd = DD_WRITE; char *cp = (char*)pX->pDma; memcpy(cp+pX->pFcb->de.nRes1, (char*)&pX->pFcb->de, sizeof(DIRENT)); message msg(nId, 5, 5, (void*)pX); pTx->PostMsg(nChan, &msg);}///////////////// ..and we arrive here after the write attempt has taken place.//void CpmBdos::Close2 (XfReq *pX){ if (FALSE == pX->bRes) DoRetry(pX); else { message msg(nId, FS_Ok); pTx->PostMsg(pX->uProc, &msg); }} /////////////// This is the loop point for the scan for a free directory entry as// flagged by an 0xE5 (never used) or 0xF7 (erased) flag. If one is// found, it is allocated as a zero length file. <nRes1> of the FCB// is set to the logical entry number for convenience and the block// containing the entry rewritten.//// CAUTION: There should be a lock placed on the block someplace to// prevent the classic "lost update" scenario being enacted yet again.// this is left as an exercise for the user (ho, ho, ho).//void CpmBdos::Creat2 (XfReq *pX){ if (FALSE == pX->bRes) DoRetry(pX); else { int idx; for (idx = 0; idx < 4; idx++) { DIRENT *pDir = (DIRENT*)(pX->pDma + (idx * 32)); if ((0xF7 == pDir->nUsrNmbr) || (0xE5 == pDir->nUsrNmbr)) { memset((char*)pDir, 0, sizeof(DIRENT)); memcpy(pDir->fname, pX->pFcb->de.fname, FILENAME_LEN); pX->ivec = CREAT3; pX->cmnd = DD_WRITE; ReGenerate(pX, 6); //message msg(nId, 6, 6, (void*)pX); //pTx->PostMsg(nChan, &msg); return; } } if (--(pX->pFcb->de.nRcnt) <= 0) { message msg(nId, FS_DiskFull); pTx->PostMsg(pX->uProc, &msg); } else { ++(pX->pFcb->de.nRes2); if (pX->pFcb->de.nRes2 >= (nBls / 128)) { ++(pX->pFcb->de.nRes1); pX->pFcb->de.nRes2 = 0; } BlkDecode(pX->pFcb->de.nRes1, pX->pFcb->de.nRes2, &(pX->nTrk), &(pX->nSec)); ReGenerate(pX, 7); //message msg(nId, 7, 7, (void*)pX); //pTx->PostMsg(nChan, &msg); } }}////////////////// This is a common usage point for all operations that entail a rewrite// to the Directory. We check the return code, vectoring to the retry// code if needs be, otherwise check for attached transfers and act..//void CpmBdos::Creat3 (XfReq *pX){ if (FALSE == pX->bRes) DoRetry(pX); else { if (NULL == pX->pNxt) { pX->pFcb->nCurRec = 0; message msg(nId, FS_Ok); pTx->PostMsg(pX->uProc, &msg); } else { XfReq *pInner = pX->pNxt; memcpy((char*)&pInner->pFcb->de, (char*)&pX->pFcb->de, sizeof(DIRENT)); pInner->pFcb->nCurRec = 0; delete pX; NxtFunc(pInner); } }}//////////////////// arrive here after an attempted record read - retry on error, or// perform house keeping of FCB and tidy up.//void CpmBdos::Read1 (XfReq *pX){ if (FALSE == pX->bRes) DoRetry(pX); else { ++pX->pFcb->nCurRec; message msg(nId, FS_Ok); pTx->PostMsg(pX->uProc, &msg); } }//////////////////// Arrive here after an attempted record write - retry on error, or// perform house keeping of FCB and reply to the caller. Scenarios://// 1. A previously written record has been re-written:// No extra action.// 2. The record was after the last used and:// - the current block is the cardinal last for the extent, or// - is the last allocation block of the extent:// Increment <nRcnt> (range is 0..nRpb-1; 0..7 for IBM 3740).//// This will set <nRcnt> to nRpb-1 when the last record of the last// block of the extent is used - indicating to <Write> that a new// extent must be opened before further writes can take place.//// When a new allocation block is added, <nRcnt> is zeroed.//void CpmBdos::Write1 (XfReq *pX){ if (FALSE == pX->bRes) DoRetry(pX); else { ++pX->pFcb->nCurRec; BYTE nRpb = nBls / 128; BYTE nAbs = pX->pFcb->nCurRec / nRpb; BYTE nRec = pX->pFcb->nCurRec % nRpb; if ((pX->pFcb->de.nRcnt < nRec) && ((nAbs == nAlb-1) || (0 == pX->pFcb->de.nAllocBlk[nAbs+1]))) pX->pFcb->de.nRcnt = nRec; message msg(nId, FS_Ok); pTx->PostMsg(pX->uProc, &msg); }}/////////////////////////////////////////////////////////////////////////// These Members are PROTECTED//----------------------------------------------------------------------// Scan the directory for the first file matching the name in the passed// FCB and extent matching the FCB extent number. We start by requesting// the first record of block zero, setting <nRes1> as the block counter// <nRes2> as record of block counter and <nRcnt> as the total records// for the search. These will be replaced by the Dir entry detail, if found.// void CpmBdos::Open (XfReq *pX){ DirScanPrep(pX->pFcb, &pX->nTrk, &pX->nSec); pX->ivec = OPEN1; pX->cmnd = DD_READ; pX->pDma = (char*)DirBuf; message msg(nId, 8, 8, (void*)pX); pTx->PostMsg(nChan, &msg);}/////////////// This activity must fail if the file exists - so we begin by nesting// this transfer request inside one that will try to open a file of the// same name.//void CpmBdos::Creat (XfReq *pX){ XfReq *pNew = new XfReq(nId); if (pNew && (pNew->pFcb = new FCB)) { memcpy((char*)pNew->pFcb, (char*)pX->pFcb, sizeof(FCB)); pX->ivec = CREAT1; pNew->pNxt = pX; pNew->ivec = OPEN1; pNew->cmnd = DD_READ; pNew->pDma = (char*)DirBuf; pNew->pFnCb = this; DirScanPrep(pNew->pFcb, &pNew->nTrk, &pNew->nSec); message msg(nId, 9, 9, (void*)pNew); pTx->PostMsg(nChan, &msg); }}////////////////// Read a record sequentially (at this time random access is provisioned// for, but not implemented). There are 3 scenarios://// 1. The record is within the scope of the current extent - we simply// calculate its disk location and ask for a transfer.// 2. The record is in the next extent (and there is one). Open the next// extent by upping the FCB extent number and callin Open1, then// return here to continue as for (1) above.// 3. We are at EOF - either in this extent (easy to test), or we need// another extent and there isn't one.//void CpmBdos::Read (XfReq *pX, UINT16 nType){ pX->ivec = READ1; pX->cmnd = DD_READ; BYTE nRpb = nBls / 128; BYTE nAbs = pX->pFcb->nCurRec / nRpb; BYTE nRec = pX->pFcb->nCurRec % nRpb; if ((nRec > pX->pFcb->de.nRcnt) && (0 == pX->pFcb->de.nAllocBlk[nAbs+1])) { message msg(pX->uProc, FS_EOF); pTx->PostMsg(nChan, &msg); return; } if (pX->pFcb->de.nAllocBlk[nAbs]) { BlkDecode(pX->pFcb->de.nAllocBlk[nAbs], nRec, &pX->nTrk, &pX->nSec); message msg(nId, 10, 10, (void*)pX); pTx->PostMsg(nChan, &msg); } else { XfReq *pNew = new XfReq; memcpy((char*)pNew->pFcb, (char*)pX->pFcb, sizeof(FCB)); pX->ivec = READ0; pNew->pNxt = pX; pNew->ivec = OPEN1; pNew->cmnd = DD_READ; pNew->pFcb->de.nExtent++; pNew->pDma = (char*)DirBuf; DirScanPrep(pNew->pFcb, &pNew->nTrk, &pNew->nSec); message msg(nId, 11, 11, (void*)pNew); pTx->PostMsg(nChan, &msg); }}////////////////// Write a (sequential) record (random access is provisioned for, but not// implemented). This is VERY similar to read, but different enough to// warrant its own entry point. There are 3 scenarios://// 1. The record is within the scope of the current extent:// Simply calculate its disk location and ask for a transfer.// (we can't do any FCB housekeeping until we know the write worked).//// 2. The record is beyond the current allocation block and the next// allocation block is zero - get a free block (if possible) and// use its first record.//// 3. The record is beyond the last block of this extent. Here there are// two sub-scenarios:// 3a. There is a next extent - open it and proceed as for (1).// 3b. There is no next extent - create one and proceed as for (3).// Note that (3b) may fail if there are no directory entries available,// even though there may still be disk blocks available.//void CpmBdos::Write (XfReq *pX, UINT16 nType){ pX->ivec = WRITE1; pX->cmnd = DD_WRITE; BYTE nRpb = nBls / 128; BYTE nAbs = pX->pFcb->nCurRec / nRpb; BYTE nRec = pX->pFcb->nCurRec % nRpb; // // Scenario 1 // if (pX->pFcb->de.nAllocBlk[nAbs]) { BlkDecode(pX->pFcb->de.nAllocBlk[nAbs], nRec, &pX->nTrk, &pX->nSec); message msg(nId, 12, 12, (void*)pX); pTx->PostMsg(nChan, &msg); return; } // // Scenario 2 // if (0 == pX->pFcb->de.nAllocBlk[nAbs]) { pX->pFcb->de.nAllocBlk[nAbs] = GetFreeBlk(); if (0 == pX->pFcb->de.nAllocBlk[nAbs]) { message msg(pX->uProc, FS_DiskFull); pTx->PostMsg(nChan, &msg); return; } else { AllocBlk(pX->pFcb->de.nAllocBlk[nAbs]); pX->pFcb->de.nRcnt = 0; BlkDecode(pX->pFcb->de.nAllocBlk[nAbs], nRec, &pX->nTrk, &pX->nSec); message msg(nId, 13, 13, (void*)pX); pTx->PostMsg(nChan, &msg); return; } } // // Scenario 3 (note temporary cop-out) // if (TRUE) { message msg(pX->uProc, FS_DiskFull); pTx->PostMsg(nChan, &msg); return; }}//////////////// A file Close operation needs to locate the Dir block containing the// current extent and update the record (if it's chaged)..//void CpmBdos::Close (XfReq *pX){ XfReq *pNew = new XfReq; if (pNew && (pNew->pFcb = new FCB)) { memcpy((char*)pNew->pFcb, (char*)pX->pFcb, sizeof(FCB)); pX->ivec = CLOSE1; pNew->pNxt = pX; pNew->pFnCb = this; pNew->ivec = OPEN1; pNew->cmnd = DD_READ; pNew->pDma = (char*)DirBuf; DirScanPrep(pNew->pFcb, &pNew->nTrk, &pNew->nSec); message msg(nId, 14, 14, (void*)pNew); pTx->PostMsg(nChan, &msg); }}///////////////// delete a current file - first we must be able to open it..//void CpmBdos::Remov (XfReq *pX){ XfReq *pNew = new XfReq; if (pNew && (pNew->pFcb = new FCB)) { memcpy((char*)pNew->pFcb, (char*)pX->pFcb, sizeof(FCB)); pX->ivec = REMOV1; pNew->pNxt = pX; pNew->pFnCb = this; pNew->ivec = OPEN1; pNew->cmnd = DD_READ; pNew->pDma = (char*)DirBuf; DirScanPrep(pNew->pFcb, &pNew->nTrk, &pNew->nSec); message msg(nId, 15, 15, (void*)pNew); pTx->PostMsg(nChan, &msg); }}/////////////////////////////////// eof ////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -