📄 dosfslib.c
字号:
if( pVolDesc->mounted ) return OK; return ERROR; } /* dosFsVolMount() *//***************************************************************************** dosFsFdFree - free a file descriptor** This routine marks a file descriptor as free and decreases* reference count of a referenced file handle.** RETURNS: N/A.*/LOCAL void dosFsFdFree ( DOS_FILE_DESC_ID pFd ) { DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc; assert( pFd != NULL ); DBG_MSG( 600, "pFd = %p\n", pFd ,0,0,0,0,0,0,0); semTake( & pFd->pVolDesc->devSem, WAIT_FOREVER ); assert( pFd->pFileHdl->nRef != 0 ); pFd->pFileHdl->nRef --; pFd->busy = 0; semGive( & pVolDesc->devSem ); } /* dosFsFdFree() */ /***************************************************************************** dosFsFdGet - get an available file descriptor** This routine obtains a free dosFs file descriptor.** RETURNS: Pointer to file descriptor, or NULL, if none available.** ERRNO:* S_dosFsLib_NO_FREE_FILE_DESCRIPTORS**/LOCAL DOS_FILE_DESC_ID dosFsFdGet ( DOS_VOLUME_DESC_ID pVolDesc ) { FAST DOS_FILE_DESC_ID pFd = pVolDesc->pFdList; FAST DOS_FILE_DESC_ID pFdFree = NULL; FAST DOS_FILE_HDL_ID pFileHdl = pVolDesc->pFhdlList; FAST DOS_FILE_HDL_ID pFileHdlFree = NULL; if( semTake( & pVolDesc->devSem, WAIT_FOREVER ) == ERROR ) return NULL; /* allocate file descriptor */ for( pFd = pVolDesc->pFdList; pFd < pVolDesc->pFdList + pVolDesc->maxFiles; pFd++ ) { if( ! pFd->busy ) { pFdFree = pFd; break; } } if( pFdFree == NULL ) { errnoSet( S_dosFsLib_NO_FREE_FILE_DESCRIPTORS ); pFd = NULL; goto ret; } DBG_MSG( 600, "pFdFree = %p\n", pFdFree ,0,0,0,0,0,0,0); bzero( (char *)pFdFree, sizeof( *pFdFree ) ); pFdFree->pVolDesc = pVolDesc; pFdFree->busy = TRUE; pFdFree->pVolDesc->nBusyFd ++; /* allocate file handle */ for( pFileHdl = pVolDesc->pFhdlList; pFileHdl < pVolDesc->pFhdlList + pVolDesc->maxFiles; pFileHdl++ ) { if( pFileHdl->nRef == 0 ) { pFileHdlFree = pFileHdl; break; } } assert( pFileHdlFree != NULL ); bzero( (char *)pFileHdlFree, sizeof( *pFileHdlFree ) ); pFileHdlFree->nRef = 1; pFdFree->pFileHdl = pFileHdlFree; DBG_MSG( 600, "pFileHdlFree = %p\n", pFileHdlFree,0,0,0,0,0,0,0 ); ret: semGive( & pVolDesc->devSem ); return pFdFree; } /* dosFsFdGet() *//***************************************************************************** dosFsHdlDeref - unify file descriptors of the same file.** All file descriptors, that are opened for one file* have to share the same file handle in order to* prevent confusion when file is changed and accessed through* several file descriptors simultaneously.** This routine lookups throw list of file handles and* references <pFd> to the file handle, that already describes the* same file, if such exists. File handle, that has been used* by <pFd> is freed.** RETURNS: N/A.*/LOCAL void dosFsHdlDeref ( DOS_FILE_DESC_ID pFd ) { FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc; FAST DOS_DIR_HDL_ID pDirHdlFd = & pFd->pFileHdl->dirHdl; /* dir handle ptr */ FAST DOS_FILE_HDL_ID pFhdlLCur = pVolDesc->pFhdlList; /* loop file handle */ FAST DOS_DIR_HDL_ID pDirHdlCur = NULL; /* dir handle of the */ /* loop file handle */ FAST int i; /* loop counter */ semTake( & pVolDesc->devSem, WAIT_FOREVER ); /* loop by file handles list */ for( i = 0; i < pVolDesc->maxFiles; i++, pFhdlLCur++ ) { if( pFhdlLCur->nRef == 0 || pFhdlLCur == pFd->pFileHdl || pFhdlLCur->deleted || pFhdlLCur->obsolet ) { continue; } /* compare directory handles */ pDirHdlCur = & pFhdlLCur->dirHdl; if( pDirHdlCur->sector == pDirHdlFd->sector && pDirHdlCur->offset == pDirHdlFd->offset ) { /* the same directory entry */ assert( pDirHdlCur->parDirStartCluster == pDirHdlFd->parDirStartCluster ); DBG_MSG( 600, " use %p instead of %p\n", pFhdlLCur, pFd->pFileHdl,0,0,0,0,0,0 ); /* free file handle in <pFd> */ assert( pFd->pFileHdl->nRef == 1 ); bzero( (char *)pFd->pFileHdl, sizeof( *pFd->pFileHdl ) ); /* deference <pFd> */ pFd->pFileHdl = pFhdlLCur; pFhdlLCur->nRef ++; break; } } semGive( & pVolDesc->devSem ); } /* dosFsHdlDeref() */ /***************************************************************************** dosFsSeek - change file's current character position** This routine sets the specified file's current character position to* the specified position. This only changes the pointer, doesn't affect* the hardware at all.** If the new offset pasts the end-of-file (EOF), attempts to read data* at this location will fail (return 0 bytes).** For a write if the seek is done past EOF, then use dosFsFillGap* to fill the remaining space in the file.** RETURNS: OK, or ERROR if invalid file position.** ERRNO:* S_dosFsLib_NOT_FILE**/ LOCAL STATUS dosFsSeek ( DOS_FILE_DESC_ID pFd, /* file descriptor pointer */ fsize_t newPos /* ptr to desired character */ /* position in file */ ) { fsize_t sizeBuf = pFd->pFileHdl->size; /* backup directory size */ u_int nSec; /* sector offset of new position */ /* from seek start sector */ u_int startSec; /* cluster number to count clusters from */ STATUS retStat = ERROR; DBG_MSG( 500, "pFd = %p: newPos = %lu, " "current pos = %lu, size = %lu\n", pFd, newPos, pFd->pos, pFd->pFileHdl->size,0,0,0,0 ); pFd->seekOutPos = 0; if( newPos == pFd->pos ) /* nothing to do ? */ return OK; /* there is no field storing actual directory length */ if( pFd->pFileHdl->attrib & DOS_ATTR_DIRECTORY ) { pFd->pFileHdl->size = DOS_MAX_FSIZE; } /* in case of seek passed EOF, only store the new position */ if( newPos > pFd->pFileHdl->size ) { pFd->seekOutPos = newPos; return OK; } /* * to very simplify all process, let us pose at start * of current cluster */ if( pFd->curSec > 0 ) /* file is not just open */ { /* * now provide special support to the extreme case, * when contiguous block have been passed and position * stopped directly following it. In this case let return * one cluster back. It may be important, when * seek is called from close() in order to stand to * the last file position. */ if( pFd->nSec == 0 ) /* contiguous block exhausted */ { pFd->nSec = 1; pFd->curSec -= 1; pFd->pos -= pFd->nSec << pFd->pVolDesc->secSizeShift; } else /* goto start of the current sector */ { pFd->pos -= OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ); } } /* if( pFd->curSec > 0 ) */ /* * count number of sectors to move and * check for seek within current contiguous block */ if( newPos < pFd->pos || pFd->curSec == 0 ) /* backward */ { /* number of sector from file start to move to */ nSec = NSECTORS( pFd->pVolDesc, min( newPos, pFd->pFileHdl->size - 1 ) ); /* begin seeking from file start */ startSec = FH_FILE_START; DBG_MSG(550, "SEEK_SET : startClust = %lu\n", pFd->pFileHdl->startClust ,0,0,0,0,0,0,0); } else /* forward */ { /* * count number of sectors from current position. * If newPos == size, temporary move into (size-1), that is * last valid byte in file. */ nSec = min( newPos, pFd->pFileHdl->size - 1 ) - pFd->pos; nSec = NSECTORS( pFd->pVolDesc, nSec ); if( nSec < pFd->nSec ) /* within current block ? */ { pFd->nSec -= nSec; pFd->curSec += nSec; DBG_MSG(500, "within current cluster group\n", 0,0,0,0,0,0,0,0 ); goto retOK; } /* begin seeking from current sector */ startSec = pFd->curSec; DBG_MSG(550, "SEEK_CUR : startSec = %lu\n", startSec,0,0,0,0,0,0,0 ); } /* go ! */ if( pFd->pVolDesc->pFatDesc->seek( pFd, startSec, nSec ) == ERROR ) { goto ret; }retOK: pFd->pos = newPos; retStat = OK; /* * special case, when the seek is done into the file last position, * and this position is also first position in sector. * Remember, that if newPos == size, we actually have moved * into (size-1) */ if( newPos == pFd->pFileHdl->size && OFFSET_IN_SEC( pFd->pVolDesc, newPos ) == 0 ) { pFd->nSec --; pFd->curSec ++; }ret: pFd->pFileHdl->size = sizeBuf; return retStat; } /* dosFsSeek() *//***************************************************************************** dosFsSeekDir - set current offset in directory.** This routine sets current offset in directory. It takes special* care of contiguous root.** File semaphore should be taken prior calling this routine.** RETURNS: OK or ERROR, if seek is out of directory chain.*/LOCAL STATUS dosFsSeekDir ( DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */ DIR * pDir /* seek for dd_cookie position */ ) { fsize_t newOffset = DD_COOKIE_TO_POS( pDir ); if( pFd->pos == newOffset ) /* at the place */ return OK; /* special process for contiguous root */ if( IS_ROOT( pFd ) && pFd->pVolDesc->pDirDesc->rootNSec > 0 ) { /* check for seek out of root */ if( newOffset >= ( pFd->pVolDesc->pDirDesc->rootNSec << pFd->pVolDesc->secSizeShift ) ) { errnoSet( S_dosFsLib_INVALID_PARAMETER ); return ERROR; } pFd->pos = newOffset; newOffset = NSECTORS( pFd->pVolDesc, newOffset ); pFd->curSec = pFd->pVolDesc->pDirDesc->rootStartSec + newOffset; pFd->nSec = pFd->pVolDesc->pDirDesc->rootNSec - newOffset; return OK; } /* regular directory */ return dosFsSeek( pFd, (fsize_t)newOffset ); } /* dosFsSeekDir() *//***************************************************************************** dosFsIsDirEmpty - check if directory is empty.** This routine checks if directory is not a root directory and* whether it contains entries unless "." and "..".** RETURNS: OK if directory is empty and not root, else ERROR.** ERRNO:* S_dosFsLib_DIR_NOT_EMPTY**/LOCAL STATUS dosFsIsDirEmpty ( DOS_FILE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -