📄 rwrec.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel / Standard Extension * * Copyright (C) 2006 by Ken Sakamura. All rights reserved. * T-Kernel / Standard Extension is distributed * under the T-License for T-Kernel / Standard Extension. *---------------------------------------------------------------------- * * Version: 1.00.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2006/8/11. * *---------------------------------------------------------------------- *//* * rwrec.c (file) * * File management * Record read/write */#include "fileio.h"#include "diskio.h"#include "dskalloc.h"#define HASH_AREA_SZ 16 /* Hash Function for 16Byte area */#define MAX_RANK 7 /* max rank set */#define DSK_NOT_USE (-1) /* unused entries */#define TSD_WLR_VAL_0 0#define TSD_WLR_VAL_1 1#define TSD_WLR_VAL_2 2#define TSD_WLR_VAL_3 3#define TSD_WLR_VAL_4 4#define TSD_GRB_PRE_M1 (-1)#define TSD_ERS_UNI_1024 1024U#define TSD_FWR_VAL_M1 (-1)#define TSD_ABR_CT1_255 255#define TSD_ABR_CT1_255_U 255U/* * Read/Write flag */typedef enum { Read = MD_RDONLY, /* Read */ Write = MD_WRITE /* Write */} RW;LOCAL W afterBlkPos( LogBlk *lblk, W pos, FsInfo *fsinfo );LOCAL W beforeBlkPos( LogBlk *lblk, W pos, FsInfo *fsinfo );LOCAL ER rwDataRecord( VB *buf, RCB *rcb, W start, W size, OFCB *ofcb, RW rw );LOCAL ER readDataRecord( RCB *rcb, OFCB *ofcb, FM_REA_REC_PARA *cmdPara );LOCAL ER readLinkRecord( RCB *rcb, OFCB *ofcb, FM_REA_REC_PARA *cmdPara );LOCAL ER changeFileSize( OFCB *ofcb, W diffsize );LOCAL ER blockMove( UW toLBlk, UW fromLBlk, W start, W end, OFCB *ofcb );LOCAL ER appendBlockRCB( RCB *rcb, RIdx *ri, LLogBlk lnew, W *sz );LOCAL WER expandRSizeFromFragmentSpace( RCB *rcb, W size, OFCB *ofcb );LOCAL WER expandRSizeFromLastBlock( RCB *rcb, W size, W units, OFCB *ofcb );LOCAL ER expandRSizeFromNewBlock( RCB *rcb, W *size, W units, OFCB *ofcb );LOCAL ER expandRecordSize( RCB *rcb, W rsize, UW units, OFCB *ofcb );LOCAL ER writeLinkRecord( RCB *rcb, OFCB *ofcb, FM_WRI_REC_PARA *cmdPara );LOCAL WER getRecordBlockList( RCB *rcb, OFCB *ofcb, PhyBlk blklst[], W *offset, W max );/* * Return the block that includes the area after pos of *lblk * Return the location of pos in new *lblk to the return value. */LOCAL W afterBlkPos( LogBlk *lblk, W pos, FsInfo *fsinfo ){ W nblk, offset; nblk = pos / fsinfo->sblk; offset = pos % fsinfo->sblk; lblk->cnt -= nblk; lblk->adr += nblk; return offset;}/* * Return the block that includes the area before pos of *lblk * Return the location of pos in new *lblk to the return value. */LOCAL W beforeBlkPos( LogBlk *lblk, W pos, FsInfo *fsinfo ){ W nblk; nblk = pos / fsinfo->sblk; lblk->cnt = nblk + 1; return pos;}/* * Create the logical block list for the record map. * Create the logical block list in lb to map the size bytes from * start th byte of the record data of *rcb. * Since the lb is on a logical block basis, return the offset * from the start to start th byte to the return value. */EXPORT WER fmpMakeLBlks( LBlks *lb, RCB *rcb, W start, W size, OFCB *ofcb ){ FsInfo *fsinfo = ofcb->fsinfo; RIdx ri; DfRecordIndex *ridx; W cp; LogBlk lblk; W end, total, blktp; W mapoff; ER err; /* Location of map end */ end = start + size - 1; /* Prepare to obtain the record index. */ err = fmpOpenRIdx(&ri, &rcb->idxadr, ofcb); if ( err < E_OK ) { goto err_ret1; } /* Obtain the location of the first data block and normal index. */ err = fmpGetDataBlkAdr(&ri, &lblk); if ( err < E_OK ) { goto err_ret2; } ridx = fmpGetMapAdr(&ri, &cp); blktp = - (W)fmpConvEndianH(ridx->n.offset, fsinfo); total = blktp + (lblk.cnt * fsinfo->sblk); while ( total <= start ) { /* Obtain the location of the data blocks after the first one from the connection index. */ err = fmpGetDataBlkAdr(&ri, &lblk); if ( err < E_OK ) { goto err_ret2; } blktp = total; total += lblk.cnt * fsinfo->sblk; } /* Add to the map block list. */ if ( total > end ) { (void)beforeBlkPos(&lblk, end - blktp, fsinfo); } mapoff = afterBlkPos(&lblk, start - blktp, fsinfo); err = fmAddLBlks(lb, lblk); if ( err < E_OK ) { goto err_ret2; } while ( total <= end ) { /* Obtain the location of the data blocks after the first one from the connection index. */ err = fmpGetDataBlkAdr(&ri, &lblk); if ( err < E_OK ) { goto err_ret2; } blktp = total; total += lblk.cnt * fsinfo->sblk; /* Add to the map block list. */ if ( total > end ) { (void)beforeBlkPos(&lblk, end - blktp, fsinfo); } err = fmAddLBlks(lb, lblk); if ( err < E_OK ) { goto err_ret2; } } err = fmpCloseRIdx(&ri); if ( err < E_OK ) { goto err_ret1; } return mapoff;err_ret2: (void)fmpCloseRIdx(&ri);err_ret1: DEBUG_PRINT(("fmpMakeLBlks err = %d\n", err)); return err;}/* * Read/Write the record data. * Read/Write the size bytes from start th byte of the record data of *rcb. * * rw = Read Read the record and store it in buf. * rw = Write Write to the record from buf. */LOCAL ER rwDataRecord( VB *buf, RCB *rcb, W start, W size, OFCB *ofcb, RW rw ){ FsInfo *fsinfo = ofcb->fsinfo; LBlks lb; W offset; MapModeClr clear; ER err; /* Prepare the block list. */ err = fmNewLBlks(&lb); if ( err < E_OK ) { goto err_ret1; } /* Create the record block list. */ offset = fmpMakeLBlks(&lb, rcb, start, size, ofcb); if ( offset < 0 ) { err = (ER)offset; goto err_ret2; } /* Map the whole record at once to read/write */ { VB *mp; ID mid; if ( rw == Write ) { /* When writing, prevent unnecessary reading from occurring. */ clear = MapUnsettle; if ( offset > 0 ) { clear |= MapNoClrTop; } if ( ((offset + size) % fsinfo->sblk) > 0 ) { clear |= MapNoClrEnd; } } else { clear = MapNoClr; } /* Map the whole record. */ mp = fmpMapLogBlks(&lb, ofcb, clear, &mid, fsinfo); if ( mp == NULL ) { err = (ER)mid; if ( (ER)((UW)err & EC_MASK) == E_IO ) { goto err_ret2; } } else { mp += offset; /* Read/Write */ if ( rw == Read ) { memcpy(buf, mp, (size_t)size); }else{ memcpy(mp, buf, (size_t)size); } fmpUnmapDisk(mid, rw); err = E_OK; } } /* Read/Write the record on a logical block basis. */ if ( err < E_OK ) { LogBlk *lblk = NULL; W sz, b, i; VB *mp; ID mid; while ( fmNextLBlks(&lb, &lblk) != 0 ) { b = lblk->adr; for ( i = lblk->cnt; i > 0; --i ) { sz = fsinfo->sblk - offset; if ( sz > size ) { sz = size; } /* When writing to the whole logical block, prevent unnecessary writing from occurring. */ clear = ( (rw == Write) && (sz == fsinfo->sblk) )? MapUnsettle: MapNoClr; /* Map one logical block. */ mp = fmpMapLogBlkC((UW)b++, ofcb, clear, &mid, fsinfo); if ( mp == NULL ) { err = (ER)mid; goto err_ret2; } mp += offset; /* Read/Write */ if ( rw == Read ) { memcpy(buf, mp, (size_t)sz); }else{ memcpy(mp, buf, (size_t)sz); } buf += sz; size -= sz; fmpUnmapDisk(mid, rw); offset = 0; } } } err = fmpCheckDiskError(ofcb, fsinfo); if ( err < E_OK ) { goto err_ret2; } /* Release the block list. */ fmDeleteLBlks(&lb); return E_OK;err_ret2: fmDeleteLBlks(&lb);err_ret1: DEBUG_PRINT(("rwDataRecord err = %d\n", err)); return err;}/* ------------------------------------------------------------------------ *//* * Read the data record. */LOCAL ER readDataRecord( RCB *rcb, OFCB *ofcb, FM_REA_REC_PARA *cmdPara ){ W size; ER err; /* Read size */ size = rcb->rsize - cmdPara->offset; if ( cmdPara->size < size ) { size = cmdPara->size; } if ( size <= 0 ) { return E_OK; } /* Check the read buffer area. */ err = CheckSpaceRW(cmdPara->buf, size); if ( err < E_OK ) { goto err_ret; } /* Read the record */ err = rwDataRecord(cmdPara->buf, rcb, cmdPara->offset, size, ofcb, Read); if ( err < E_OK ) { goto err_ret; } return E_OK;err_ret: DEBUG_PRINT(("readDataRecord err = %d\n", err)); return err;}/* * Read the link record */LOCAL ER readLinkRecord( RCB *rcb, OFCB *ofcb, FM_REA_REC_PARA *cmdPara ){ FsInfo *fsinfo = ofcb->fsinfo; DfLinkIndex *lidx; LINK *lnk; ID mid; ER err; /* Parameter check */ if ( (cmdPara->offset != 0) || (cmdPara->size < (W)sizeof(LINK)) ) { return E_PAR; } /* Check the LINK storing area. */ lnk = (LINK*)cmdPara->buf; err = CheckSpaceRW(lnk, sizeof(LINK)); if ( err < E_OK ) { return err; } /* Map the record index. */ lidx = fmpMapDskAdr(rcb->idxadr.ridx, sizeof(DfLinkIndex), ofcb, &mid, fsinfo); if ( lidx == NULL ) { return (ER)mid; } /* Read LINK */ fmpLIdxToLINK(lnk, lidx, fsinfo); fmpUnmapDisk(mid, MD_RDONLY); return fmpCheckDiskError(ofcb, fsinfo);}/* * Read the record. */EXPORT void fmpReadRecord( FmCmdPkt *pkt ){ FM_REA_REC_PARA *cmdPara = (FM_REA_REC_PARA*)pkt->cmd.para; FD *fd; OFCB *ofcb; RCB *rcb; ER err; /* Obtain FD and OFCB. */ fd = getFDp(cmdPara->fd); ofcb = fd->ofcb; /* Check the open mode */ err = fmpCheckFileOpenMode(fd, F_READ); if ( err < E_OK ) { goto err_ret; } /* Obtain the current record. */ err = fmpSetRCB(rcb = fd->crcb, ofcb); if ( err < E_OK ) { goto err_ret; } /* Parameter check */ if ( (cmdPara->offset < 0) || (cmdPara->size < 0) ) { err = E_PAR; goto err_ret; } /* Check the record lock. */ if ( isLockRecord(fd, rcb) != 0 ) { err = E_LOCK; goto err_ret; } if ( !((cmdPara->buf == NULL) || (cmdPara->size == 0)) ) { if ( isLinkRecord(rcb->rtype) != 0 ) { /* Read the link record. */ err = readLinkRecord(rcb, ofcb, cmdPara); if ( err < E_OK ) { goto err_ret; } } else { /* Read the data record. */ err = readDataRecord(rcb, ofcb, cmdPara); if ( err < E_OK ) { goto err_ret; } } } /* Return r_size and subtype. */ if ( cmdPara->r_size != NULL ) { err = CheckSpaceRW(cmdPara->r_size, sizeof(W)); if ( err < E_OK ) { goto err_ret; } *cmdPara->r_size = rcb->rsize - cmdPara->offset; } if ( cmdPara->subtype != NULL ) { err = CheckSpaceRW(cmdPara->subtype, sizeof(UH)); if ( err < E_OK ) { goto err_ret; } *cmdPara->subtype = rcb->stype; } /* Update the time stamp. */ err = fmpSetTimeStamp(ofcb, F_READ); if ( err < E_OK ) { goto err_ret; } pkt->cmd.ret = (W)rcb->rtype; setSyncAtExit(SAE_OPENF, ofcb->fsinfo); return;err_ret: DEBUG_PRINT(("fmpReadRecord err = %d\n", err)); pkt->cmd.ret = err; setSyncAtExit(SAE_OPENF, ofcb->fsinfo); return;}/* ------------------------------------------------------------------------ *//* * Update the total byte count of the file. * Increase/Decrease the total byte count of the file of the file header by diffsize. */LOCAL ER changeFileSize( OFCB *ofcb, W diffsize ){ FsInfo *fsinfo = ofcb->fsinfo; DfFileHeader *fh; W size; ID mid; ER err; /* Map the file header. */ fh = fmpMapDskAdr(ofcb->fhead, sizeof(DfFileHeader), ofcb, &mid, fsinfo); if ( fh == NULL ) { err = (ER)mid;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -