📄 dosvdirlib.c
字号:
** RETURNS: number of levels in path.** ERRNO:* S_dosFsLib_ILLEGAL_PATH* S_dosFsLib_ILLEGAL_NAME*/LOCAL int dosVDirPathParse ( DOS_VOLUME_DESC_ID pVolDesc, u_char * path, PATH_ARRAY_ID pnamePtrArray ) { FAST u_int numPathLevels; FAST u_char * pName; FAST u_char * pRegChar; /* last not DOT and not SPACE char */ pnamePtrArray[0].pName = NULL; /* go throw path string from left to right */ pName = path; numPathLevels = 0; while( *pName != EOS ) /* there is 'break' in loop also */ { /* pass slashes */ if( *pName == SLASH || *pName == BACK_SLASH ) { pName++; continue; } /* process special names ( "." ".." ) */ if( *pName == DOT ) { /* "/./" - ignore "current directory" */ if( *(pName + 1) == EOS || *(pName + 1) == SLASH || *(pName + 1) == BACK_SLASH ) { pName ++; continue; } /* "/../" - goto one level back */ if( (*(pName + 1) == DOT) && ( *(pName + 2) == EOS || *(pName + 2) == SLASH || *(pName + 2) == BACK_SLASH ) ) { if( numPathLevels > 0 ) numPathLevels --; pName +=2; continue; } } /* if( *pName == DOT ) */ /* regular name: insert it into array */ if( numPathLevels >= DOS_MAX_DIR_LEVELS ) break; /* max level overloaded */ pnamePtrArray[numPathLevels].pName = pName; pnamePtrArray[numPathLevels + 1].pName = NULL; pRegChar = NULL; while( *pName != SLASH && *pName != BACK_SLASH && *pName != EOS ) { if( *pName != DOT || *pName == SPACE ) pRegChar = pName; pName++; } /* name can not contain only dots */ if( pRegChar == NULL ) { errnoSet( S_dosFsLib_ILLEGAL_NAME ); return ERROR; } pnamePtrArray[numPathLevels].nameLen = pRegChar + 1 - pnamePtrArray[numPathLevels].pName; numPathLevels++; } /* while( *pName != EOS ) */ /* check result */ if( *pName != EOS ) /* path termination has not been reached */ { errnoSet( S_dosFsLib_ILLEGAL_PATH ); return ERROR; }#ifdef DEBUG DBG_MSG( 600, "path: %s, result: \n", path ,0,0,0,0,0,0,0); pName = (void *)pnamePtrArray; for( ; pnamePtrArray->pName != NULL; pnamePtrArray++ ) { int i = pnamePtrArray - (PATH_ARRAY_ID)pName + 1; DBG_PRN_STR( 600, "%s : %d", pnamePtrArray->pName, pnamePtrArray->nameLen, i ); } DBG_PRN_STR(600, "\b\b \n", "", 0, 0);#endif /* DEBUG */ return numPathLevels; } /* dosVDirPathParse() */ /***************************************************************************** dosVDirChkSum - count checksum for long name alias.** RETURNS: N/A.*/LOCAL u_char dosVDirChkSum ( u_char * alias ) { u_int i; u_char chkSum; for( chkSum = 0, i = 0; i < DOS_STDNAME_LEN + DOS_STDEXT_LEN; i++ ) { chkSum = ( ( ( chkSum & 1 ) << 7 ) | ( ( chkSum & 0xfe ) >> 1 ) ) + alias[ i ]; } return chkSum; } /* dosVDirChkSum() */ /***************************************************************************** dosVDirTDDecode - decode time-date field from disk format.** This routine decodes required date-time field in the directory* entry into time_t format.* * Parameter which defines which time field to decode. It* can be one of:* DH_TIME_CREAT, DH_TIME_MODIFY, DH_TIME_ACCESS.** RETURNS: time in time_t format.**/LOCAL time_t dosVDirTDDecode ( DOS_DIR_PDESCR_ID pDirDesc, u_char * pDirent, /* directory entry buffer */ u_int which /* what field to decode: one of */ /* DH_TIME_CREAT, DH_TIME_MODIFY or DH_TIME_ACCESS */ ) { struct tm tm = {0}; /* broken down time buffer */ UINT16 dtBuf; /* 16-bit buffer */ u_char tOff = 0, dOff = 0; /* field offset */ switch( which ) { case DH_TIME_CREAT: tOff = pDirDesc->deDesc.creatTimeOff; dOff = pDirDesc->deDesc.creatDateOff; break; case DH_TIME_MODIFY: tOff = pDirDesc->deDesc.modifTimeOff; dOff = pDirDesc->deDesc.modifDateOff; break; case DH_TIME_ACCESS: tOff = pDirDesc->deDesc.accessTimeOff; dOff = pDirDesc->deDesc.accessDateOff; break; default: assert( FALSE ); } if( dOff != (u_char)NONE ) { dtBuf = DISK_TO_VX_16( pDirent + dOff ); tm.tm_mday = dtBuf & 0x1f; /* ANSI months are zero-based */ tm.tm_mon = ((dtBuf >> 5) & 0x0f) - 1; /* DOS starts at 1980, ANSI starts at 1900 */ tm.tm_year = ((dtBuf >> 9) & 0x7f) + 1980 - 1900; } if( tOff != (u_char)NONE ) { dtBuf = DISK_TO_VX_16( pDirent + tOff ); tm.tm_sec = (dtBuf & 0x1f) << 1; tm.tm_min = (dtBuf >> 5) & 0x3f; tm.tm_hour = (dtBuf >> 11) & 0x1f; } /* encode into time_t format */ return mktime( &tm ); } /* dosVDirTDDecode() *//***************************************************************************** dosVDirTDEncode - encode time-date to disk format.** This routine takes time value is provided in <curTime> argument* and encodes it into directory entry format.* * Parameter <timesMask> defines which time fields to fill. Following* values can be bitwise or-ed:* DH_TIME_CREAT, DH_TIME_MODIFY, DH_TIME_ACCESS.** RETURNS: N/A.*/LOCAL void dosVDirTDEncode ( DOS_DIR_PDESCR_ID pDirDesc, u_char * pDirEnt, u_int timesMask, time_t curTime /* time to encode */ ) { struct tm tm; /* buffer for split time-date */ u_char timeB[2], dateB[2]; /* buffers for encoding */ localtime_r( &curTime, &tm ); /* encode time */ VX_TO_DISK_16( ( tm.tm_sec >> 1 ) | ( tm.tm_min << 5 ) | ( tm.tm_hour << 11 ), timeB ); /* * encode date; * in <pDate> year is related to 1980, but in tm, - to 1900 */ tm.tm_year = ( tm.tm_year < 80 )? 80 : tm.tm_year; VX_TO_DISK_16( tm.tm_mday | ( ( tm.tm_mon + 1 ) << 5 ) | ( ( tm.tm_year - 80 ) << 9 ), dateB ); /* put time-date into directory entry buffer */ if( timesMask & DH_TIME_CREAT && pDirDesc->deDesc.creatDateOff != (u_char)NONE ) { pDirEnt[ pDirDesc->deDesc.creatTimeOff ] = timeB[0]; pDirEnt[ pDirDesc->deDesc.creatTimeOff + 1 ] = timeB[1]; pDirEnt[ pDirDesc->deDesc.creatDateOff ] = dateB[0]; pDirEnt[ pDirDesc->deDesc.creatDateOff + 1 ] = dateB[1]; } if( timesMask & DH_TIME_MODIFY && pDirDesc->deDesc.modifDateOff != (u_char)NONE ) { pDirEnt[ pDirDesc->deDesc.modifTimeOff ] = timeB[0]; pDirEnt[ pDirDesc->deDesc.modifTimeOff + 1 ] = timeB[1]; pDirEnt[ pDirDesc->deDesc.modifDateOff ] = dateB[0]; pDirEnt[ pDirDesc->deDesc.modifDateOff + 1 ] = dateB[1]; } if( timesMask & DH_TIME_ACCESS && pDirDesc->deDesc.accessDateOff != (u_char)NONE ) { if( pDirDesc->deDesc.accessTimeOff != (u_char)NONE ) { pDirEnt[ pDirDesc->deDesc.accessTimeOff ] = timeB[0]; pDirEnt[ pDirDesc->deDesc.accessTimeOff + 1 ] = timeB[1]; } pDirEnt[ pDirDesc->deDesc.accessDateOff ] = dateB[0]; pDirEnt[ pDirDesc->deDesc.accessDateOff + 1 ] = dateB[1]; } } /* dosVDirTDEncode() */ /***************************************************************************** dosVDirCharEncode - validate and encode character.** RETURNS: OK or ERROR.*/LOCAL STATUS dosVDirCharEncode ( u_char * pSrc, u_char * pDst, const u_char * codeTbl /* characters table */ /* ( shortNamesChar or longNamesChar ) */ ) { /* allow all high characters */ if( *pSrc & 0x80 ) { *pDst = *pSrc; } else if( codeTbl[ *pSrc ] != INVALID_CHAR ) { *pDst = codeTbl[ *pSrc ]; } else { return ERROR; } return OK; } /* dosVDirCharEncode() */ /***************************************************************************** dosVDirNameEncodeShort - encode name in short style.** This routine encodes incoming file name into 8+3 uppercase format.* During encoding the* name is verified to be composed of valid characters.** RETURNS: STRICT_SHORT, if name is valid short and uppercase,* NOT_STRICT_SHORT, if name is short, but not uppercase,* NO_SHORT, if name can not be encoded as short.* */LOCAL SHORT_ENCODE dosVDirNameEncodeShort ( DOS_DIR_PDESCR_ID pDirDesc, PATH_ARRAY_ID pNamePtr, /* name buffer */ u_char * pDstName /* buffer for name in disk format */ ) { u_char * pSrc; /* source name dynamic ptr */ u_char * pDstBuf; /* for debug output only */ int i,j; /* work */ SHORT_ENCODE retVal = STRICT_SHORT; /* extension length (0 - no extension) */ u_char extLen = pDirDesc->deDesc.extLen; pDstBuf = pDstName; bfill( (char *)pDstName, pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen, SPACE ); /* encode name and check it by the way */ DBG_MSG( 600, "",0,0,0,0,0,0,0,0 ); DBG_PRN_STR( 600, "%s\n", pNamePtr->pName, pNamePtr->nameLen, 0 ); for( i = 0, pSrc = pNamePtr->pName; i < min( pDirDesc->deDesc.nameLen, pNamePtr->nameLen ); i++, pDstName++, pSrc++ ) { /* check for extension */ if( extLen != 0 && *pSrc == DOT ) break; if( dosVDirCharEncode( pSrc, pDstName, shortNamesChar ) == ERROR ) goto error; if( *pDstName != *pSrc ) retVal = NOT_STRICT_SHORT; } /* check state */ if( i == pNamePtr->nameLen ) goto retOK; /* name finished */ if( *pSrc != DOT ) /* name too long */ goto error; pSrc++; /* pass DOT */ pDstName += pDirDesc->deDesc.nameLen - i; i++; /* encode extension */ for( j = 0; j < extLen && i < pNamePtr->nameLen; i++, j++, pDstName++, pSrc++ ) { if( dosVDirCharEncode( pSrc, pDstName, shortNamesChar ) == ERROR ) goto error; if( *pDstName != *pSrc ) retVal = NOT_STRICT_SHORT; } /* check status */ if( i < pNamePtr->nameLen ) /* extension too long */ goto error;retOK: /* * A space in a short file name is indeed technically allowed, but * in order to be compatible with M$ Scandisk and Norton Disk Doctor * we mangle 8.3 names if they contain a space. This will prevent * ScanDisk and Norton Disk Doctor from reporting a (false) orphaned * LFN entry on the alias, and offering to correct it. Both will * correct it by marking the LFN invalid (fragmenting the disk...) * and simply using the short file name, which destroys the case * sensitive part of the filename. * Basically, this code is added to appease the windoze tools * that complain about our file system, since that supposedly * looks bad....but windo$e should NOT need to mangle a short * filename with a space....but Windows 95 OSR2 does just that.. * Note only with "3D MAZES.SCR" style. * Not with "NAME . " filenames. */ /* check backwards through name, wont be more than 11 chars (0-10) */ i = pNamePtr->nameLen - 1; while (i > 1) /* ignore 0 and 1 chars, name won't begin with space.*/ { /* ignore "name " type filenames */ if (*(pNamePtr->pName + i) != SPACE) break; /* found non-space char, break */ i--; } if (i != 1) /* don't care if "2 " style name */ { while (i > 0) /* now look for a space */ { if (*(pNamePtr->pName + i) == SPACE) { goto error; /* windoze likes it a longname */ } i--; } } DBG_PRN_STR( 600, "result: %s\n", pDstBuf,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -