📄 rwrec.c
字号:
goto err_ret; } /* Update the total byte count */ size = (W)fmpConvEndianW((UW)fh->size, fsinfo) + diffsize; fh->size = (W)fmpConvEndianW((UW)size, fsinfo); fmpUnmapDisk(mid, MD_WRITE); err = fmpCheckDiskError(ofcb, fsinfo); if ( err < E_OK ) { goto err_ret; } return E_OK;err_ret: DEBUG_PRINT(("changeFileSize err = %d\n", err)); return err;}/* * Move the data between the logical blocks. * Copy the area from start th byte to just before end th byte of fromLBlk * to the start of toLBlk, and free the source area. */LOCAL ER blockMove( UW toLBlk, UW fromLBlk, W start, W end, OFCB *ofcb ){ FsInfo *fsinfo = ofcb->fsinfo; VB *to, *from; ID toMid, fromMid; ER err; to = fmpMapLogBlk(toLBlk, ofcb, &toMid, fsinfo); if ( to == NULL ) { err = (ER)toMid; goto err_ret1; } from = fmpMapLogBlk(fromLBlk, ofcb, &fromMid, fsinfo); if ( from == NULL ) { err = (ER)fromMid; goto err_ret2; } /* Copy */ memcpy(to, from + start, (size_t)(end - start)); /* Free the data area of old block. */ err = fmpMergeFragment(fromLBlk, from, start, end, ofcb); if ( err < E_OK ) { goto err_ret3; } fmpUnmapDisk(fromMid, (UW)err); fmpUnmapDisk(toMid, MD_WRITE); return fmpCheckDiskError(ofcb, fsinfo);err_ret3: fmpUnmapDisk(fromMid, MD_RDONLY);err_ret2: fmpUnmapDisk(toMid, MD_WRITE);err_ret1: DEBUG_PRINT(("blockCopy err = %d\n", err)); return err;}/* * Register the new block in the index record. * Register it after dividing into parts of 255 or less blocks * to conform to the format of the record index. * Return the number of blocks that are successfully registered in *sz. (Also when error occurred) */LOCAL ER appendBlockRCB( RCB *rcb, RIdx *ri, LLogBlk lnew, W *sz ){ UW adr, cnt; LogBlk new; ER err; adr = lnew.adr; cnt = lnew.cnt; while ( cnt > TSD_ABR_CT1_255_U ) { new.adr = adr; new.cnt = TSD_ABR_CT1_255; err = fmpAppendBlockRCB(rcb, ri, new); if ( err < E_OK ) { goto err_ret; } adr += TSD_ABR_CT1_255_U; cnt -= TSD_ABR_CT1_255_U; } new.adr = adr; new.cnt = cnt; err = fmpAppendBlockRCB(rcb, ri, new); if ( err < E_OK ) { goto err_ret; } *sz = (W)lnew.cnt; return E_OK;err_ret: /* The number of blocks that are successfully registered. */ *sz = (W)(lnew.cnt - cnt); /* Release the blocks that cannot be registered in the record index. */ lnew.adr = adr; lnew.cnt = cnt; (void)fmpFreeBlock(lnew, ri->ofcb); DEBUG_PRINT(("appendBlockRCB err = %d\n", err)); return err;}/* * Reserve a free space from the fragment area to extend the record size. * However, when size is larger than the free space of the fragment area, * it is not allocated unless the end is a boundary of the logical block. * The current record size must be 0. */LOCAL WER expandRSizeFromFragmentSpace( RCB *rcb, W size, OFCB *ofcb ){ FsInfo *fsinfo = ofcb->fsinfo; W keep; DskAdr dadr; LogAdr ladr; DfNormalIndex *nidx; ID mid; ER err; /* Reserve a free space from the fragment area. */ keep = fmpAllocateFragment(&dadr, size, ofcb); if ( keep < E_OK ) { err = (ER)keep; goto err_ret; } if ( keep > 0 ) { /* Register in the record index */ nidx = fmpMapDskAdr(rcb->idxadr.ridx, sizeof(DfNormalIndex), ofcb, &mid, fsinfo); if ( nidx == NULL ) { err = (ER)mid; goto err_ret; } ladr = fmpDAdrToLAdr(dadr, fsinfo); nidx->offset = fmpConvEndianH((UH)ladr.offset, fsinfo); nidx->size = fmpConvEndianW((UW)keep, fsinfo); nidx->blk.cnt = 1; nidx->blk.adr = fmpConvEndian3B(ladr.blk, fsinfo); fmpUnmapDisk(mid, MD_WRITE); err = fmpCheckDiskError(ofcb, fsinfo); if ( err < E_OK ) { goto err_ret; } /* Update RCB */ rcb->rsize = keep; } return keep;err_ret: DEBUG_PRINT(("expandRSizeFromFragmentSpace err = %d\n", err)); return err;}/* * Reserve a free space from just after the logical block located at the current * record end to extend the record size. However, when unable to extend * because there are other record data in the back in the end logical block, * copy the current data in the end logical block to the new logical block to extend it. */LOCAL WER expandRSizeFromLastBlock( RCB *rcb, W size, W units, OFCB *ofcb ){ FsInfo *fsinfo = ofcb->fsinfo; RIdx ri; DfRecordIndex *ridx; W cp; LogBlk lb; UW lblk; W use, offset; W keep = 0; ER err; err = fmpOpenRIdx(&ri, &rcb->idxadr, ofcb); if ( err < E_OK ) { goto err_ret1; } /* Find the logical block at the record end. */ use = fmpFindLastDataBlkAdr(&ri, &lb); if ( use < E_OK ) { err = (ER)use; goto err_ret2; } /* Record index corresponding to the record end. */ ridx = fmpGetMapAdr(&ri, &cp); /* Focus the address on one block at the end. */ if ( lb.cnt == 1 ) { lblk = lb.adr; offset = ( ridx->type[0] == 0 )? fmpConvEndianH(ridx->n.offset, fsinfo): 0; } else { lblk = lb.adr + lb.cnt - 1U; use = use - (fsinfo->sblk * (lb.cnt - 1)); offset = 0; } if ( use < fsinfo->sblk ) { /* Reserve a free space of the end block. */ keep = fmpResizeFragment(lblk, use, size, ofcb); if ( keep < E_OK ) { err = (ER)keep; goto err_ret2; } if ( keep == 0 ) { /* Reserve new block, and copy the data of the end block. */ LLogBlk new; W sz; ER apdErr; size += use - offset; /* Add the copied block size. */ /* Reserve new block. */ keep = fmpAllocateBlock(&new, size, units, lblk, ofcb); if ( keep <= 0 ) { err = (ER)keep; goto err_ret2; } keep -= use - offset; if ( offset > 0 ) { /* Change the record start offset. */ ridx->n.offset = 0; } /* Deregister the end block from the record index. */ ridx->c.blk[cp].cnt--; fmpSetRIdxMapFlag(&ri, MD_WRITE); /* Resister the new block. */ apdErr = appendBlockRCB(rcb, &ri, new, &sz); if ( apdErr < E_OK ) { /* Set keep to the number of the blocks that successfully registered. */ keep = (sz * fsinfo->sblk) - (use - offset); if ( sz <= 0 ) { err = apdErr; goto err_ret4; } } /* Move the data from old block to new block. */ err = blockMove(new.adr, lblk, offset, use, ofcb); if ( err < E_OK ) { goto err_ret3; } if ( apdErr < E_OK ) { err = apdErr; goto err_ret3; } } } if ( keep > 0 ) { /* Update the record size. */ err = fmpAddRSizeRCB(rcb, keep, ofcb); if ( err < E_OK ) { goto err_ret2; } } err = fmpCloseRIdx(&ri); if ( err < E_OK ) { goto err_ret1; } return keep;err_ret4: /* Restore the setting of the end record. */ if ( offset > 0 ) { ridx->n.offset = fmpConvEndianH((UH)offset, fsinfo); } ridx->c.blk[cp].cnt++;err_ret3: if ( keep > 0 ) { /* Increase the record size as much as the reserved size. */ (void)fmpAddRSizeRCB(rcb, keep, ofcb); }err_ret2: (void)fmpCloseRIdx(&ri);err_ret1: DEBUG_PRINT(("expandRSizeFromLastBlock err = %d\n", err)); return err;}/* * Reserve new free logical block to extend the record size. * Current record end must conform to a boundary of the logical block. * Return the reserved size to *size. (It is correctly set if not E_OK) */LOCAL ER expandRSizeFromNewBlock( RCB *rcb, W *size, W units, OFCB *ofcb ){ FsInfo *fsinfo = ofcb->fsinfo; RIdx ri; LogBlk lb; UW lblk; W need = *size; /* Size expected to be reserved */ W keep = 0; /* Size that has been reserved */ ER err; err = fmpOpenRIdx(&ri, &rcb->idxadr, ofcb); if ( err < E_OK ) { goto err_ret1; } /* Find the logical block at the record end. */ err = fmpFindLastDataBlkAdr(&ri, &lb); if ( err < E_OK ) { goto err_ret2; } /* Block number of the record end. (If the record is free, the block number is at an appropriate location.) */ if ( lb.cnt != 0 ) { lblk = lb.adr + lb.cnt - 1U; } else { lblk = fmpGetMapBlkRIdx(&ri); } while ( keep < need ) { LLogBlk new; W alloc; W sz; /* Reserve new block. */ alloc = fmpAllocateBlock(&new, need - keep, units, lblk, ofcb); if ( alloc < E_OK ) { err = (ER)alloc; goto err_ret3; } /* Register the new block. */ err = appendBlockRCB(rcb, &ri, new, &sz); if ( err < E_OK ) { /* Add the number of the blocks that successfully registered to keep. */ keep += sz * fsinfo->sblk; goto err_ret3; } keep += alloc; lblk = new.adr + new.cnt - 1U; } if ( keep > 0 ) { /* Update the record size. */ err = fmpAddRSizeRCB(rcb, keep, ofcb); if ( err < E_OK ) { goto err_ret2; } } err = fmpCloseRIdx(&ri); if ( err < E_OK ) { goto err_ret1; } *size = keep; return E_OK;err_ret3: if ( keep > 0 ) { /* Increase the record size as much as the reserved size. */ (void)fmpAddRSizeRCB(rcb, keep, ofcb); }err_ret2: (void)fmpCloseRIdx(&ri);err_ret1: DEBUG_PRINT(("expandRSizeFromNewBlock err = %d\n", err)); *size = keep; return err;}/* * Extend the record size. */LOCAL ER expandRecordSize( RCB *rcb, W rsize, UW units, OFCB *ofcb ){ W keep, size; ER err; units *= TSD_ERS_UNI_1024; /* From KByte to Byte */ /* Size expected to be extended */ size = rsize - rcb->rsize; keep = 0; if ( (rcb->rsize == 0) && (units == 0U) ) { /* Reserve from the fragment area. */ err = expandRSizeFromFragmentSpace(rcb, size, ofcb); if ( err < E_OK ) { goto err_ret2; } keep += (W)err; } if ( (size > keep) && (rcb->rsize > 0) ) { /* Reserve from the logical block at the record end. */ err = expandRSizeFromLastBlock(rcb, size - keep, (W)units, ofcb); if ( err < E_OK ) { goto err_ret2; } keep += (W)err; } if ( size > keep ) { W sz = size - keep; /* Reserve from the new logical block. */ err = expandRSizeFromNewBlock(rcb, &sz, (W)units, ofcb); keep += sz; if ( err < E_OK ) { goto err_ret2; } } /* Update the total byte count of the file of the file header. */ err = changeFileSize(ofcb, keep); if ( err < E_OK ) { goto err_ret1; } return E_OK;err_ret2: if ( keep > 0 ) { /* Increase the file size as much as the reserved size. */ (void)changeFileSize(ofcb, keep); }err_ret1: DEBUG_PRINT(("expandRecordSize err = %d\n", err)); return err;}/* ------------------------------------------------------------------------ *//* * Write the data record. * offset, buf, size, and units are based on the parameter of wri_rec */EXPORT ER fmpWriteDataRecord( RCB *rcb, OFCB *ofcb, W offset, B *buf, W size, UW units ){ W rsize; ER err, error = E_OK; /* Size of the whole record after writing the data. */ rsize = offset + size; if ( rsize > rcb->rsize ) { /* Extend the record size. */ err = expandRecordSize(rcb, rsize, units, ofcb); if ( err < E_OK ) { if ( err != E_NODSK ) { goto err_ret; } error = err; } } if ( buf != NULL ) { /* Check the write buffer area. */ err = CheckSpaceR(buf, size); if ( err < E_OK ) { goto err_ret; } /* When the disk is full, write the record as much as the extended size. */ if ( rsize > rcb->rsize ) { size = rcb->rsize - offset; } if ( size > 0 ) { /* Write the record. */ err = rwDataRecord(buf, rcb, offset, size, ofcb, Write); if ( err < E_OK ) { goto err_ret; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -