📄 dosvdirlib.c
字号:
*dirent = DOS_DEL_MARK; for( which = PUT_CURRENT; nEnt > 0; nEnt --, which = PUT_NEXT ) { if( dosVDirDeStore( &workFd, 0, 1, &dirent, which ) == ERROR ) { return ERROR; } } return OK; } /* dosVDirEntryDel() */ /***************************************************************************** dosVDirFullEntGet - get VFAT full directory entry from disk.** This routine reads entry out of directory pointed by <pFd>. * It puts into buffer <pEntry> full long name and alias.* Invalid entries (with inconsistent checksum and so on)* are usually passed, but deleted if check disk is in progress.** <which> argument defines which entry to get and may be* RD_FIRST, RD_CURRENT and RD_NEXT.** RETURNS: OK or ERROR if directory chain end reached.*/LOCAL STATUS dosVDirFullEntGet ( DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */ u_char * pEntry, RDE_OPTION which, /* which entry to get */ DIRENT_PTR_ID pLnPtr, /* to fill with long name start ptr */ u_int * nEntries /* entries counter in directory */ ) { DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc; STATUS status = ERROR; u_char * pDst = pEntry; /* current destination position */ int entNum = NONE; /* expected sequence number of */ /* current entry per long name */ int numEnt = 0; /* number of entries per long name */ u_char chkSum = 0; /* alias checksum */ u_char atrribOff = pDirDesc->deDesc.atrribOff; assert( nEntries != NULL ); pLnPtr->sector = pLnPtr->offset = 0; for( (status = dosVDirDirentGet( pFd, pDst, which )); status != ERROR; (status = dosVDirDirentGet( pFd, pDst, RD_NEXT )) ) { if( *pDst != LAST_DIRENT ) (*nEntries)++; /* * return just a short name, volume label, deleted * or last entry in directory */ if( (entNum == NONE && *(pDst + atrribOff ) != DOS_ATTR_VFAT) || /* just a short || */ *pDst == DOS_DEL_MARK || /* deleted || */ *pDst == LAST_DIRENT || /* last */ ((*(pDst + atrribOff ) & DOS_ATTR_VOL_LABEL) != 0 && (*(pDst + atrribOff ) != DOS_ATTR_VFAT)) ) /* vol label */ { bcopy( (char *)pDst, (char *)pEntry, DOS_DIRENT_STD_LEN ); goto retShort; } /* === long name representation === */ if( *(pDst + atrribOff ) == DOS_ATTR_VFAT ) { /* last (top) entry per long name */ /* * TBD: * Windows checks characters following EOS in last * per long name entry to be 0xff, so * some entries, that are accepted by this library * can be ignored as erroneous by Win. */ if( (*pDst & DOS_VLAST_ENTRY) != 0 ) { /* check for erroneous long names */ if( entNum != NONE ) /* long name already started */ { ERR_MSG( 10, "Bad long name structure (breached))\n", 0,0,0,0,0,0 ); DBG_MSG(0, "Long name interrupted on ent %u by " "other long name at sec %u, off %u\n", entNum, pFd->curSec, OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ), 0,0,0,0,0 ); /* remove invalid entries ( if check disk in progress */ assert( numEnt != 0 ); dosVDirEntryDel( pFd->pVolDesc, pLnPtr, numEnt - entNum, FALSE ); /* let now deal with this name */ bcopy( (char *)pDst, (char *)pEntry, DOS_DIRENT_STD_LEN ); pDst = pEntry; } numEnt = entNum = *pDst & VFAT_ENTNUM_MASK; if( entNum > VFAT_MAX_ENT ) { ERR_MSG( 10, "Bad long name structure (too long)\n", 0,0,0,0,0,0 ); DBG_MSG( 0, "max number of entries per long name (%u) " " overloaded (%u); (sec %u, off %u)\n", VFAT_MAX_ENT, entNum, pFd->curSec, OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ), 0,0,0,0); goto errCont; } chkSum = *(pDst + DOS_VFAT_CHKSUM_OFF); pLnPtr->sector = pFd->curSec; pLnPtr->offset = pFd->pos; } else if( entNum == NONE ) /* no long name started yet */ { DBG_MSG( 0, "Long name internal entry without first one " "( sec %u, off %u )\n", pFd->curSec, OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ), 0,0,0,0,0,0 ); goto errCont; } else if( entNum != (*pDst & VFAT_ENTNUM_MASK) ) { ERR_MSG( 10, "Malformed long name structure\n", 0,0,0,0,0,0 ); DBG_MSG( 0, "invalid entry num in long name " "internal entry (start: sec %u, off %u; " "current: sec %u, off %u)\n", pLnPtr->sector, pLnPtr->offset, pFd->curSec, OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ), 0,0,0,0); goto errCont; } else /* one more entry in long name; check entry number */ { /* control checksum */ if( chkSum != *(pDst + DOS_VFAT_CHKSUM_OFF) ) { ERR_MSG( 10, "Malformed long name structure\n", 0,0,0,0,0,0 ); DBG_MSG( 0, "ChkSum changed in long name internal " "entry (start: sec %u, off %u; " "current: sec %u, off %u)\n", pLnPtr->sector, pLnPtr->offset, pFd->curSec, OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ), 0,0,0,0); goto errCont; } } /* else */ /* expected next entry of long name */ entNum --; /* next expected */ pDst += DOS_DIRENT_STD_LEN; continue; /* get the next entry in this long name */ } /* if( *(pDst + atrribOff ) == DOS_ATTR_VFAT ) */ /* = long name alias encountered; count and control checksum = */ assert( entNum != NONE ); if( entNum != 0 || dosVDirChkSum( pDst ) != chkSum ) { /* * alias appeared before long name finished or * checksum error. * It is abnormal situation, but in fact the short name * may be OK. So return the short name. */ ERR_MSG( 10, "Bad long name structure\n", 0,0,0,0,0,0 ); DBG_MSG( 0, "start: sec %u, off %u \n", pLnPtr->sector, pLnPtr->offset, 0,0,0,0,0,0 ); goto retShort;#if FALSE /* HELP dead code which followed above goto */ /* remove invalid entries ( if check disk in progress */ dosVDirEntryDel( pFd->pVolDesc, pLnPtr, numEnt - entNum, FALSE ); bcopy( (char *)pDst, (char *)pEntry, DOS_DIRENT_STD_LEN ); goto ret;#endif } /* full long name and alias extracted */ goto ret; errCont: /* remove invalid entries ( if check disk in progress */ dosVDirEntryDel( pFd->pVolDesc, pLnPtr, numEnt - entNum, FALSE ); entNum = NONE; pDst = pEntry; pLnPtr->sector = pLnPtr->offset = 0; } /* for( (status ... */ ret: return status;retShort: if( entNum != NONE ) { ERR_MSG(10, "Erroneous long name\n", 0,0,0,0,0,0); DBG_MSG(0, "ent %u at sec %u, off %u\n", entNum, pFd->curSec, OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ), 0,0,0,0,0); /* remove invalid entries ( if check disk in progress ) */ assert( numEnt != 0 ); dosVDirEntryDel( pFd->pVolDesc, pLnPtr, numEnt - entNum, FALSE ); bcopy( (char *)pDst, (char *)pEntry, DOS_DIRENT_STD_LEN ); } pLnPtr->sector = pLnPtr->offset = 0; /* short name */ return OK; } /* dosVDirFullEntGet() */ /***************************************************************************** dosVDirNameCmp - compare long names.** This routine compares long names' directory entries.** If <caseSens> is TRUE case sensitive comparison is performed.** RETURNS: OK if names are identical or ERROR.*/LOCAL STATUS dosVDirNameCmp ( DOS_DIR_PDESCR_ID pDirDesc, u_char * pName, /* incoming name */ u_char * pDiskName, /* name to compare with */ BOOL caseSens /* lkup case sensitively */ ) { int entNum = (*pName & VFAT_ENTNUM_MASK); int i = 0; /* loop counter */ if( entNum != (*pDiskName & VFAT_ENTNUM_MASK) ) return ERROR; for( ; entNum > 0; pName += DOS_DIRENT_STD_LEN, pDiskName += DOS_DIRENT_STD_LEN, entNum -- ) { for( i = 0; i < CHAR_PER_VENTRY; i++ ) { if( caseSens ) { if( pName[ chOffsets[ i ] ] != pDiskName[ chOffsets[ i ] ] ) { return ERROR; } } else if( toupper( pName[ chOffsets[ i ] ] ) != toupper( pDiskName[ chOffsets[ i ] ] ) ) { return ERROR; } if( pName[ chOffsets[ i ] ] == 0 ) break; } } /* for( ; entNum ... */ return OK; } /* dosVDirNameCmp() */ /***************************************************************************** dosVDirLkupInDir - lookup directory for specified name.** This routine searches directory, that is pointed by <pFd> for name, that* is pointed by <pNamePtr> structure and fills <pFd> in accordance with* directory entry data, if found.** If name not found, <pFreeEnt> will be filled with pointer onto* deleted entry in directory large enough to create entry* with name is being searched for, or onto free space in last directory* cluster. If both of them not found, <pFreeEnt->sector> is set to 0.** If <caseSens> is TRUE the name is searched case sensitively.** RETURNS: OK or ERROR if name not found or invalid name.*/LOCAL STATUS dosVDirLkupInDir ( DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */ PATH_ARRAY_ID pNamePtr, /* name buffer */ DIRENT_PTR_ID pFreeEnt, /* empty entry in directory */ int *pFreeEntLen, /* Return numbers of free chanks */ BOOL caseSens /* lkup case sensitively */ ) { DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc; u_char * pName = pDirDesc->nameBuf; /* src name in disk format */ u_char * pNameAl; /* name alias in <pLName> buffer */ u_char * pDiskName = pDirDesc->nameBuf + MAX_VFAT_FULL_DIRENT; /* directory entry buffer */ STATUS status = ERROR; /* search result status */ u_int nEntries; /* number of entries in directory */ size_t freeChankLen = 0; /* num of contiguous deleted entries */ DIRENT_PTR lnPtr = {0}; /* ptr to long name start on disk */ u_int which; SHORT_ENCODE shortNameEncode; /* encodding of short name */ short aliasOff = 0; /* offset of alias in disk name buffer */ short nEntInName; /* number of entries per name, */ /* if will be created */ *pFreeEntLen = 0; /* No free entries to start with */ DBG_MSG( 400, "pFd = %p ", pFd,0,0,0,0,0,0,0 ); DBG_PRN_STR( 400, " name: %s\n", pNamePtr->pName, pNamePtr->nameLen, 0 ); pFreeEnt->deNum = 0; pFreeEnt->sector = 0; pFreeEnt->offset = 0; /* protect buffers */ if( semTake( pDirDesc->bufSem, WAIT_FOREVER ) == ERROR ) return ERROR; /* prepare name */ shortNameEncode = NOT_STRICT_SHORT; nEntInName = dosVDirNameEncode( pDirDesc, pNamePtr, pName, &shortNameEncode ); if( nEntInName == (short)ERROR ) goto ret; aliasOff = DOS_DIRENT_STD_LEN * (nEntInName - 1); pNameAl = pName + aliasOff; /* * strict short name does not require extra long entries. * * Do not compare short alias, if case sensitive * lkup in progress for name, that contains lower case characters */ if( shortNameEncode == STRICT_SHORT ) nEntInName = 1; else if( caseSens ) *pNameAl = EOS; nEntries = 0; for( which = RD_FIRST; 1; which = RD_NEXT ) { status = dosVDirFullEntGet( pFd, pDiskName, which, &lnPtr, &nEntries ); if( status == ERROR || *pDiskName == LAST_DIRENT ) break; /* pass deleted entry, that later can be used to store new entry */ if( *pDiskName == DOS_DEL_MARK ) { if( freeChankLen == 0 ) { pFreeEnt->deNum = nEntries; pFreeEnt->sector = pFd->curSec; /* new empty chain */ pFreeEnt->offset = pFd->pos; } freeChankLen ++; continue; } /* non empty entry interrupts empty chain */ if( freeChankLen < (size_t)nEntInName ) freeChankLen = 0; /* long name entry */ if( *(pDiskName + pDirDesc->deDesc.atrribOff) == DOS_ATTR_VFAT ) { /* compare long names */ if( dosVDirNameCmp( pDirDesc, pName, pDiskName, caseSens ) == OK ) { goto ret; } continue; } /* pass volume label */ if( ( *(pDiskName + pDirDesc->deDesc.atrribOff) & DOS_ATTR_VOL_LABEL ) != 0 ) { continue; } /* compare short names, that does not have long version */ if( bcmp( (char *)pNameAl, (char *)pDiskName, DOS_STDNAME_LEN + DOS_STDEXT_LEN ) == 0 ) { aliasOff = 0; goto ret; } } /* if no appropriate free space found, reset pointers */ if( freeChankLen < (size_t)nEntInName ) { pFreeEnt->deNum = nEntries + ((status == ERROR)? 1 : 0); pFreeEnt->sector = 0; pFreeEnt->offset = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -