📄 etc.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. * *---------------------------------------------------------------------- *//* * etc.c (file) * * File management * Various functions */#include "fminfo.h"#include "diskio.h"#define TSD_LTL_POS_0 0#define TSD_LTL_POS_1 1#define TSD_LTL_POS_2 2#define TSD_LTL_POS_3 3#define TSD_LTL_POS_4 4#define TSD_CFN_VAL_M1 (-1)#define TSD_FCN_VAL_0X001F (TC)0x001f#define TSD_FCN_VAL_0XFF00 (TC)0xff00#define TSD_DSN_SFT_16 16LOCAL DfShortName* getSFNp( SFN *sfn, FID fid );/* ======================================================================== *//* * Data transfer to application tasks *//* * Data transfer from application tasks */EXPORT ER fmGetAplData( VP to, VP from, W len ){ ER err; /* Check the address space. */ err = CheckSpaceR(from, len); if ( err != E_OK ) { DEBUG_PRINT(("CheckSpace err = %d\n", err)); return err; } /* Memory transfer */ memcpy(to, from, (size_t)len); return E_OK;}/* * Data transfer with applications */EXPORT ER fmSetAplData( VP to, VP from, W len ){ ER err; /* Check the address space. */ err = CheckSpaceRW(to, len); if ( err != E_OK ) { DEBUG_PRINT(("CheckSpace err = %d\n", err)); return err; } /* Memory transfer */ memcpy(to, from, (size_t)len); return E_OK;}/* * Character string transfer from applications */EXPORT WER fmGetAplStr( TC *to, TC *from, W max ){ W len; /* Check the address space */ len = CheckStrSpaceR(from, max); if ( (ER)len < E_OK ) { DEBUG_PRINT(("CheckStrSpace err = %d\n", (ER)len)); return (ER)len; } /* Memory transfer */ memcpy(to, from, (size_t)((UW)len * sizeof(TC))); return E_OK;}/* ======================================================================== *//* * Analyze the path name. *//* * Cut out the path name. * Analyze the path name from the position of *pathp, and return the first token to *name. * Return the location advanced by one token to *pathp. * Return the type of the token to the return value. */EXPORT PTYPE fmGetPathToken( TC **pathp, PathToken name ){ TC *p = *pathp; TC c; PTYPE type; W i; switch ( *p ) { case TC_FDLM: type = PT_CON; /* Connection name */ p++; /* Omit / at the start. */ break; case TC_FOWN: type = PT_OWN; /* Work file */ break; default: type = PT_NAM; /* File name */ break; } i = 0; while ( (c = *(p++)) != TC_FDLM ) { if ( c == TNULL ) { p--; /* Return to the location of TNULL. */ break; } *(name++) = c; if ( ++i >= PathTokenLen ) { break; } } *name = TNULL; *pathp = p; return type;}/* * Fetch the file name. * Fetch only the portion of file name from the file name (*name) including the occurrence * order, and return it to *name. Return the occurrence order to the return value. */EXPORT W fmGetFileName( PathToken name ){ TC *p; /* Cut out the file name. */ p = tc_strchr(name, TC_FSEP); if ( p == NULL ) { return 0; /* The occurrence order is not specified. */ } *p = TNULL; /* Fetch the occurrence order. */ return tc_atoi(p + 1);}/* * Check the validity of the connection name, file system name, and file name (excluding the occurrence order). * Check the followings. * * Whether invalid character is not included. * * Whether it is not empty. */EXPORT ER fmCheckFileName( TC *name, W max ){ TC c; W i = TSD_CFN_VAL_M1; while ( (++i < max) && ((c = *(name++)) != TNULL) ) { /* Control code and Special code are invalid. */ if ( (c <= TSD_FCN_VAL_0X001F) || (c >= TSD_FCN_VAL_0XFF00) ) { return E_FNAME; } } if ( i == 0 ) { return E_FNAME; } return E_OK;}/* * Check the validity of the path name. * Check the followings. * * Whether invalid character is not included. * * Whether it is not empty. */EXPORT ER fmCheckPathName( PathName name ){ TC c; W i = 0; while ( (++i <= PathNameLen) && ((c = *(name++)) != TNULL) ) { /* Special code for path name is OK. */ if ( (c == TC_FDLM) || (c == TC_FSEP) || (c == TC_FOWN) ) { continue; } /* Control code and Special code are invalid. */ if ( (c <= TSD_FCN_VAL_0X001F) || (c >= TSD_FCN_VAL_0XFF00) ) { return E_FNAME; } } if ( i == 0 ) { return E_FNAME; } return E_OK;}/* ======================================================================== *//* * File name *//* * Generate file abbreviated name. */EXPORT DfShortName fmShortFileName( FileName name ){ DfShortName sn = 0; W cnt = sizeof(FileName) / sizeof(UW); while ( --cnt >= 0 ) { if ( *name != TNULL ) { sn ^= (UW)*(name++) << TSD_DSN_SFT_16; } if ( *name != TNULL ) { sn ^= (UW)*(name++); } sn = ROR1(sn); } return sn;}/* * Obtain the file name. */EXPORT ER fmpGetFileName( FID fid, FileName name, FsInfo *fsinfo ){ DfFileHeaderBlock *fh; ID mid; ER err; fh = fmpMapFileHeader(fid, NULL, &mid, fsinfo); if ( fh == NULL ) { err = (ER)mid; goto err_ret; } (void)fmpConvEndianTC(name, (TC*)fh->head.name, FileNameLen, fsinfo); fmpUnmapDisk(mid, MD_RDONLY); err = fmpCheckDiskError(NULL, fsinfo); if ( err < E_OK ) { goto err_ret; } return E_OK;err_ret: DEBUG_PRINT(("fmpGetFileName err = %d\n", err)); return err;}/* ======================================================================== *//* * Convert the endian. *//* * Convert the endian of character string. */EXPORT W fmConvEndianTC( TC *to, TC *from, W max, BOOL bigEndian ){ TC ch; W i; for ( i = 0; i < max; ++i ) { *(to++) = ch = fmConvEndianH(*(from++), bigEndian); if ( ch == TNULL ) { break; } } while ( i < --max ) { *(to++) = TNULL; /* Fill the remainder with 0. */ } return i;}/* * Convert the endian of UH data string. */EXPORT void fmConvEndianHs( UH *to, UH *from, W len, BOOL bigEndian ){ while ( --len >= 0 ) { *(to++) = fmConvEndianH(*(from++), bigEndian); }}/* ======================================================================== *//* * Time *//* * Obtain the current time (GMT). */EXPORT STIME fmGetTime( void ){ STIME now = 0;#if USE_CLOCK_MANAGER#ifdef DEBUG ER err = tkse_get_tim2(&now, NULL); if ( err < E_OK ) { DEBUG_PRINT(("fmGetTime err = %d\n", err)); }#else tkse_get_tim2(&now, NULL);#endif#endif return now;}/* * Update the time stamp. * mode F_READ|F_EXCUTE Update the date/time of access. * F_WRITE Update the date/time of update. */EXPORT ER fmpSetTimeStamp( OFCB *ofcb, UW mode ){ FsInfo *fsinfo = ofcb->fsinfo; DfFileHeader *fhd; STIME now; ID mid; mode &= F_WRITE|F_READ|F_EXCUTE; /* Do nothing if the file system is not writable. */ if ( isNoWriteFS(fsinfo) != 0 ) { return E_OK; } /* Process the time stamp update control option. */ if ( ((fmInfo.updTimeStamp & UTS_RecordRead) != 0U) && ((mode & ~(UW)(F_READ|F_EXCUTE)) == 0U) ) { return E_OK; } /* Current time */ now = fmGetTime(); now = (STIME)fmpConvEndianW((UW)now, fsinfo); /* Map the file header. */ fhd = fmpMapDskAdr(ofcb->fhead, sizeof(DfFileHeader), ofcb, &mid, fsinfo); if ( fhd == NULL ) { return (ER)mid; } if ( (mode & (F_READ|F_EXCUTE)) != 0U ) { /* Update the date/time of access. */ fhd->atime = now; } if ( (mode & F_WRITE) != 0U ) { /* Update the date/time of update. */ fhd->mtime = now; } fmpUnmapDisk(mid, MD_WRITE); return fmpCheckDiskError(ofcb, fsinfo);}/* * Update the time stamp. * mode F_READ|F_EXCUTE Update the date/time of access. * F_WRITE Update the date/time of update. * Return MD_WRITE when writing is performed to fh. * Otherwise, return MD_RDONLY. * However, when err < E_OK, treat it as MD_WRITE. */EXPORT WER fmpSetTimeStampFh( DfFileHeader *fh, UW mode, FsInfo *fsinfo ){ STIME now; ER err; /* Do nothing if the file system is not writable. */ if ( isNoWriteFS(fsinfo) != 0 ) { return MD_RDONLY; } /* Current time */ now = fmGetTime(); now = (STIME)fmpConvEndianW((UW)now, fsinfo); if ( (mode & (F_READ|F_EXCUTE)) != 0U ) { /* Update the date/time of access. */ fh->atime = now; } if ( (mode & F_WRITE) != 0U ) { /* Update the date/time of update. */ fh->mtime = now; } err = fmpCheckDiskError(NULL, fsinfo); if ( err < E_OK ) { return err; } return MD_WRITE;}/* ======================================================================== *//* * Logical block list *//* * Create new logical block list. */EXPORT ER fmNewLBlks( LBlks *lb ){ LBList *lp; lb->nlblk = 0; QueInit(&lb->list); lp = (LBList*)Vmalloc(sizeof(LBList)); if ( lp == NULL ) { return E_SYSMEM; } QueInsert(&lp->q, &lb->list); lb->next = &lp->lblk[0]; return E_OK;}/* * Delete the logical block list. */EXPORT void fmDeleteLBlks( LBlks *lb ){ LBList *lp; while ( (lp = (LBList*)QueRemoveNext(&lb->list)) != NULL ) { Vfree((VB*)lp); }}/* * Add the logical block to the logical block list. */EXPORT ER fmAddLBlks( LBlks *lb, LogBlk lblk ){ LBList *lp; *(lb->next++) = lblk; lb->nlblk++; if ( (lb->nlblk % nLBlks) == 0 ) { /* Add LBList. */ lp = (LBList*)Vmalloc(sizeof(LBList)); if ( lp == NULL ) { return E_SYSMEM; } QueInsert(&lp->q, &lb->list); lb->next = &lp->lblk[0]; } return E_OK;}/* * Return the location of the next entry of the logical block list to *lblk. * At first, call it with *lblk = NULL. * Return FALSE when reach the end. */EXPORT BOOL fmNextLBlks( LBlks *lb, LogBlk **lblk ){ if ( *lblk == NULL ) { /* Start */ lb->read = (LBList*)lb->list.next; *lblk = &lb->read->lblk[0]; return ( *lblk != lb->next ); } /* Advance to the next. */ (*lblk)++; if ( *lblk > &lb->read->lblk[nLBlks - 1] ) { /* Move to the next LBList. */ lb->read = (LBList*)lb->read->q.next; *lblk = &lb->read->lblk[0]; } return ( *lblk != lb->next );}/* ======================================================================== *//* * Index record address *//* * Extend the index level. * Extend the index level of *idxadr with the location of new root indirect index * defined as newroot. */EXPORT void fmpExpandIdxAdr( IdxAdr *idxadr, DskAdr newroot ){ W i; for ( i = MaxIndexLevel - 1; i > 0; --i ) { idxadr->iidx[i] = idxadr->iidx[i - 1]; } idxadr->iidx[0] = newroot;}/* ======================================================================== *//* * Retrieve a file name. *//* * Prepare to retrieve a file name. * When the file name to be retrieved is constant, set fname to the file name. * The speed becomes higher because the computation of abbreviated name is required only once. * Since fname stores only the address, the call side must hold the memory of fname * until fmpCloseSFN is executed. * When the file name is not specified, fname = NULL. */EXPORT ER fmpOpenSFN( SFN *sfn, FileName fname, FsInfo *fsinfo ){ memset(sfn, 0, (size_t)sizeof(SFN)); if ( fname != NULL ) { /* Save the file name and abbreviated name. */ sfn->fname = fname; sfn->sname = fmShortFileName(fname); } sfn->fsinfo = fsinfo; sfn->idx = N_SFN_MAPINFO - 1; return E_OK;}/* * Finish retrieving the file name. */EXPORT ER fmpCloseSFN( SFN *sfn ){ struct sfn_mapinfo *mi; ER err; /* Unmap all. */ for ( mi = sfn->mi; mi < &sfn->mi[N_SFN_MAPINFO]; mi++ ) { if ( mi->mid == 0 ) { continue; } fmpUnmapDisk(mi->mid, MD_RDONLY); } err = fmpCheckDiskError(NULL, sfn->fsinfo); if ( err < E_OK ) { sfn->error = err; DEBUG_PRINT(("fmpCloseSFN err = %d\n", err)); } return sfn->error;}/* * Return the address of the abbreviated name of the file of fid in the file abbreviated name table. * The returned address is valid until getSFNp() is called next time. * Do not access the abbreviated names (addresses) of before and after it. */LOCAL DfShortName* getSFNp( SFN *sfn, FID fid ){ struct sfn_mapinfo *mi; W n, nf; FsInfo *fsinfo = sfn->fsinfo; ER err; /* Find from the ones already mapped. */ for ( mi = sfn->mi; mi < &sfn->mi[N_SFN_MAPINFO]; mi++ ) { if ( mi->mid == 0 ) { continue; } n = fid - mi->topfid; if ( (n >= 0) && (n < mi->nfid) ) { /* Some are already mapped. */ return mi->mapbase + n; } } /* Nothing is mapped. */ sfn->idx = (sfn->idx + 1) % N_SFN_MAPINFO; mi = &sfn->mi[sfn->idx]; if ( mi->mid != 0 ) { /* Unmap the ones already mapped now. */ fmpUnmapDisk(mi->mid, MD_RDONLY); mi->mid = 0; } /* Perform a new mapping. */ nf = (W)(fsinfo->sblk / sizeof(DfShortName)); mi->topfid = (UH)(fid - (fid % nf)); n = fsinfo->nfmax - mi->topfid; if ( nf > n ) { nf = n; } mi->nfid = (UH)nf; mi->mapbase = fmpMapDskAdrS((DfShortName*)fsinfo->fsnt + mi->topfid, (nf * (W)sizeof(DfShortName)), MAP_SYS(fsinfo), &err, fsinfo); if ( mi->mapbase == NULL ) { goto err_ret; } mi->mid = (ID)err; return mi->mapbase + (fid - mi->topfid);err_ret: sfn->error = err; DEBUG_PRINT(("getSFNp err = %d\n", err)); return &sfn->dummy;}/* * Judge whether the file name matches. * Judge whether the file name of the file of fid matches with fname. * When fname == NULL, use fname specified with fmpOpenSFN. * If it matches, return 1. If not matches, return 0. */EXPORT WER fmpMatchSFN( SFN *sfn, FID fid, FileName fname ){ FsInfo *fsinfo = sfn->fsinfo; DfShortName sname, sn; FileName nm; BOOL match; ER err; if ( fid >= fsinfo->nfmax ) { err = E_NOEXS; goto err_ret; } if ( fname == NULL ) { fname = sfn->fname; sname = sfn->sname; } else { sname = fmShortFileName(fname); } /* Abbreviated name of the file of fid */ sn = fmpConvEndianW(*getSFNp(sfn, fid), fsinfo); /* Abbreviated name matched? */ match = ( sname == sn ); if ( match != 0 ) { /* Obtain the file name. */ err = fmpGetFileName(fid, nm, fsinfo); if ( err < E_OK ) { goto err_ret; } /* File name matched? */ match = ( tc_strncmp(fname, nm, FileNameLen) == 0 ); } return match;err_ret: DEBUG_PRINT(("fmpMatchSFN err = %d\n", err)); return err;}/* ======================================================================== *//* * LINK generation *//* * Generate LINK from the link index. */EXPORT void fmpLIdxToLINK( LINK *lnk, DfLinkIndex *lidx, FsInfo *fsinfo ){ BOOL bigEndian = fsinfo->bigEndian; tc_strncpy(lnk->fs_name, fsinfo->fsName, FsNameLen); lnk->f_id = fmConvEndianH(lidx->fid, bigEndian); lnk->atr1 = fmConvEndianH(lidx->atr[TSD_LTL_POS_0], bigEndian); lnk->atr2 = fmConvEndianH(lidx->atr[TSD_LTL_POS_1], bigEndian); lnk->atr3 = fmConvEndianH(lidx->atr[TSD_LTL_POS_2], bigEndian); lnk->atr4 = fmConvEndianH(lidx->atr[TSD_LTL_POS_3], bigEndian); lnk->atr5 = fmConvEndianH(lidx->atr[TSD_LTL_POS_4], bigEndian);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -