// 클러스터 링크 테이블 내의 오프셋에 한 섹터를 씀 // 내부적으로 사용하는 함수, 캐시 사용 static BOOL kInternalWriteClusterLinkTableWithCache(DWORD dwOffset,BYTE* pbBuffer) { CACHEBUFFER* pstCacheBuffer; // 캐시에 해당 클러스터 링크 테이블이 있는지 확인 pstCacheBuffer = kFindCacheBuffer(CACHE_CLUSTERLINKTABLEAREA,dwOffset); // 캐시 버퍼에 있다면 캐시에 씀 if(pstCacheBuffer!=NULL) { kMemCpy(pstCacheBuffer->pbBuffer,pbBuffer,512); // 쓰기룰 수행했으므로 버퍼의 내용을 수정된 것으로 표시 pstCacheBuffer->bChanged = TRUE; return TRUE; } // 캐시 버퍼에 없다면 캐시 버퍼를 할당받아서 캐시 내용을 갱신 pstCacheBuffer = kAllocateCacheBufferWithFlush(CACHE_CLUSTERLINKTABLEAREA); if(pstCacheBuffer==NULL) { return FALSE; } // 캐시 버퍼에 쓰고, 태그 정보를 갱신 kMemCpy(pstCacheBuffer->pbBuffer,pbBuffer,512); pstCacheBuffer->dwTag = dwOffset; // 쓰기를 수행했으므로 버퍼의 내용을 수정된 것으로 표시 pstCacheBuffer->bChanged = TRUE; return TRUE; }
// 데이터 영역의 오프셋에서 한 클러스터를 읽음 // 내부적으로 사용하는 함수, 캐시 사용 static BOOL kInternalReadClusterWithCache(DWORD dwOffset,BYTE* pbBuffer) { CACHEBUFFER* pstCacheBuffer; // 캐시에 해당 데이터 클러스터가 있는지 확인 pstCacheBuffer = kFindCacheBuffer(CACHE_DATAAREA,dwOffset); // 캐시 버퍼에 있다면 캐시의 내용을 복사 if(pstCacheBuffer!=NULL) { kMemCpy(pbBuffer,pstCacheBuffer->pbBuffer,FILESYSTEM_CLUSTERSIZE); return TRUE; } // 캐시 버퍼에 없다면 하드 디스크에서 직접 읽음 if(kInternalReadClusterWithoutCache(dwOffset,pbBuffer)==FALSE) { return FALSE; } // 캐시 버퍼를 할당받아서 캐시 내용을 갱신 pstCacheBuffer = kAllocateCacheBufferWithFlush(CACHE_DATAAREA); if(pstCacheBuffer==NULL) { return FALSE; } // 케시 버퍼에 읽은 내용을 복사한 후 태그 정보를 갱신 kMemCpy(pstCacheBuffer->pbBuffer,pbBuffer,FILESYSTEM_CLUSTERSIZE); pstCacheBuffer->dwTag = dwOffset; // 읽기를 수행했으므로 버퍼의 내용을 수정되지 않은 것으로 표시 pstCacheBuffer->bChanged = FALSE; return TRUE; }
// 데이터 영역의 오프셋에 한 클러스터를 씀 // 내부적으로 사용하는 함수, 캐시 사용 static BOOL kInternalWriteClusterWithCache(DWORD dwOffset,BYTE* pbBuffer) { CACHEBUFFER* pstCacheBuffer; // 캐시 버퍼에 해당 데이터가 클러스터가 있는지 확인 pstCacheBuffer = kFindCacheBuffer(CACHE_DATAAREA,dwOffset); // 캐시 버퍼에 있다면 캐시에 씀 if(pstCacheBuffer!=NULL) { kMemCpy(pstCacheBuffer->pbBuffer,pbBuffer,FILESYSTEM_CLUSTERSIZE); // 쓰기를 수행햇으므로 버퍼의 내용을 수정된 것으로 표시 pstCacheBuffer->bChanged = TRUE; return TRUE; } // 캐시 버퍼에 없다면 캐시를 할당받아서 캐시 내용을 갱신 pstCacheBuffer = kAllocateCacheBufferWithFlush(CACHE_DATAAREA); if(pstCacheBuffer==NULL) { return FALSE; } // 캐시 버퍼에 쓰고, 태그 정보를 갱신 kMemCpy(pstCacheBuffer->pbBuffer,pbBuffer,FILESYSTEM_CLUSTERSIZE); pstCacheBuffer->dwTag = dwOffset; // 쓰기를 수행했으므로 버퍼의 내용을 수정된 것으로 표시 pstCacheBuffer->bChanged = TRUE; return TRUE; }
/** * 인터럽트가 발생했을 때, 다른 태스크를 찾아 전환 * 반드시 인터럽트나 예외가 발생했을 때 호출해야 함 */ BOOL kScheduleInInterrupt( void ) { TCB* pstRunningTask, * pstNextTask; char* pcContextAddress; BOOL bPreviousFlag; // 임계 영역 시작 bPreviousFlag = kLockForSystemData(); // 전환할 태스크가 없으면 종료 pstNextTask = kGetNextTaskToRun(); if( pstNextTask == NULL ) { // 임계 영역 끝 kUnlockForSystemData( bPreviousFlag ); return FALSE; } //========================================================================== // 태스크 전환 처리 // 인터럽트 핸들러에서 저장한 콘텍스트를 다른 콘텍스트로 덮어쓰는 방법으로 처리 //========================================================================== pcContextAddress = ( char* ) IST_STARTADDRESS + IST_SIZE - sizeof( CONTEXT ); // 현재 수행중인 태스크의 정보를 수정한 뒤 콘텍스트 전환 pstRunningTask = gs_stScheduler.pstRunningTask; gs_stScheduler.pstRunningTask = pstNextTask; // 유휴 태스크에서 전환되었다면 사용한 Tick Count를 증가시킴 if( ( pstRunningTask->qwFlags & TASK_FLAGS_IDLE ) == TASK_FLAGS_IDLE ) { gs_stScheduler.qwSpendProcessorTimeInIdleTask += TASK_PROCESSORTIME; } // 태스크 종료 플래그가 설정된 경우, 콘텍스트를 저장하지 않고 대기 리스트에만 삽입 if( pstRunningTask->qwFlags & TASK_FLAGS_ENDTASK ) { kAddListToTail( &( gs_stScheduler.stWaitList ), pstRunningTask ); } // 태스크가 종료되지 않으면 IST에 있는 콘텍스트를 복사하고, 현재 태스크를 준비 리스트로 // 옮김 else { kMemCpy( &( pstRunningTask->stContext ), pcContextAddress, sizeof( CONTEXT ) ); kAddTaskToReadyList( pstRunningTask ); } // 임계 영역 끝 kUnlockForSystemData( bPreviousFlag ); // 전환해서 실행할 태스크를 Running Task로 설정하고 콘텍스트를 IST에 복사해서 // 자동으로 태스크 전환이 일어나도록 함 kMemCpy( pcContextAddress, &( pstNextTask->stContext ), sizeof( CONTEXT ) ); // 프로세서 사용 시간을 업데이트 gs_stScheduler.iProcessorTime = TASK_PROCESSORTIME; return TRUE; }
/** * 램 디스크의 정보를 반환 */ BOOL kReadRDDInformation( BOOL bPrimary, BOOL bMaster, HDDINFORMATION* pstHDDInformation ) { // 자료구조 초기화 kMemSet( pstHDDInformation, 0, sizeof( HDDINFORMATION ) ); // 총 섹터 수와 시리얼 번호, 그리고 모델 번호만 설정 pstHDDInformation->dwTotalSectors = gs_stRDDManager.dwTotalSectorCount; kMemCpy( pstHDDInformation->vwSerialNumber, "0000-0000", 9 ); kMemCpy( pstHDDInformation->vwModelNumber, "MINT RAM Disk v1.0", 18 ); return TRUE; }
// 루트 디렉터리의 해당 인덱스에 디렉터리 엔트리를 설정 static BOOL kSetDirectoryEntryData(int iIndex,DIRECTORYENTRY* pstEntry) { DIRECTORYENTRY* pstRootEntry; // 파일 시스템을 인식하지 못했거나 인덱스가 올바르지 않으면 실패 if((gs_stFileSystemManager.bMounted==FALSE)||(iIndex<0)||(iIndex>=FILESYSTEM_MAXDIRECTORYENTRYCOUNT)) { kPrintf("FileSystem not mounted (Index=%d)\n",iIndex); return FALSE; } // 루트 디렉터리를 읽음 if(kReadCluster(0,gs_vbTempBuffer)==FALSE) { kPrintf("kReadCluster error\n"); return FALSE; } // 루트 디렉터리에 있는 해당 데이터를 갱신 pstRootEntry = (DIRECTORYENTRY*)gs_vbTempBuffer; kMemCpy(pstRootEntry+iIndex,pstEntry,sizeof(DIRECTORYENTRY)); // 루트 디렉터리에 씀 if(kWriteCluster(0,gs_vbTempBuffer)==FALSE) { kPrintf("kWriteCluster error\n"); return FALSE; } return TRUE; }
// 루트 디렉터리에서 파일 이름이 일치하는 엔트리를 찾아서 인덱스를 반환 static int kFindDirectoryEntry(const char* pcFileName,DIRECTORYENTRY* pstEntry) { DIRECTORYENTRY* pstRootEntry; int i; int iLength; // 파일 시스템을 인식하지 못했으면 실패 if(gs_stFileSystemManager.bMounted==FALSE) { return -1; } // 루트 디렉터리를 읽음 if(kReadCluster(0,gs_vbTempBuffer)==FALSE) { return -1; } iLength = kStrLen(pcFileName); // 루트 디렉터리 안에서 루프를 돌면서 파일 이름이 일치하는 엔트리를 반환 pstRootEntry = (DIRECTORYENTRY*)gs_vbTempBuffer; for(i=0;i<FILESYSTEM_MAXDIRECTORYENTRYCOUNT;i++) { if(kMemCmp(pstRootEntry[i].vcFileName,pcFileName,iLength)==0) { kMemCpy(pstEntry,pstRootEntry+i,sizeof(DIRECTORYENTRY)); return i; } } return -1; }
/** * \n, \t와 같은 문자가 포함된 문자열을 출력한 후, 화면상의 다음 출력할 위치를 * 반환 */ int kConsolePrintString( const char* pcBuffer ) { CHARACTER* pstScreen = ( CHARACTER* ) CONSOLE_VIDEOMEMORYADDRESS; int i, j; int iLength; int iPrintOffset; // 문자열을 출력할 위치를 저장 iPrintOffset = gs_stConsoleManager.iCurrentPrintOffset; // 문자열의 길이만큼 화면에 출력 iLength = kStrLen( pcBuffer ); for( i = 0 ; i < iLength ; i++ ) { // 개행 처리 if( pcBuffer[ i ] == '\n' ) { // 출력할 위치를 80의 배수 컬럼으로 옮김 // 현재 라인의 남은 문자열의 수만큼 더해서 다음 라인으로 위치시킴 iPrintOffset += ( CONSOLE_WIDTH - ( iPrintOffset % CONSOLE_WIDTH ) ); } // 탭 처리 else if( pcBuffer[ i ] == '\t' ) { // 출력할 위치를 8의 배수 컬럼으로 옮김 iPrintOffset += ( 8 - ( iPrintOffset % 8 ) ); } // 일반 문자열 출력 else { // 비디오 메모리에 문자와 속성을 설정하여 문자를 출력하고 // 출력할 위치를 다음으로 이동 pstScreen[ iPrintOffset ].bCharactor = pcBuffer[ i ]; pstScreen[ iPrintOffset ].bAttribute = CONSOLE_DEFAULTTEXTCOLOR; iPrintOffset++; } // 출력할 위치가 화면의 최댓값(80 * 25)을 벗어났으면 스크롤 처리 if( iPrintOffset >= ( CONSOLE_HEIGHT * CONSOLE_WIDTH ) ) { // 가장 윗줄을 제외한 나머지를 한줄 위로 복사 kMemCpy( CONSOLE_VIDEOMEMORYADDRESS, CONSOLE_VIDEOMEMORYADDRESS + CONSOLE_WIDTH * sizeof( CHARACTER ), ( CONSOLE_HEIGHT - 1 ) * CONSOLE_WIDTH * sizeof( CHARACTER ) ); // 가장 마지막 라인은 공백으로 채움 for( j = ( CONSOLE_HEIGHT - 1 ) * ( CONSOLE_WIDTH ) ; j < ( CONSOLE_HEIGHT * CONSOLE_WIDTH ) ; j++ ) { // 공백 출력 pstScreen[ j ].bCharactor = ' '; pstScreen[ j ].bAttribute = CONSOLE_DEFAULTTEXTCOLOR; } // 출력할 위치를 가장 아래쪽 라인의 처음으로 설정 iPrintOffset = ( CONSOLE_HEIGHT - 1 ) * CONSOLE_WIDTH; } } return iPrintOffset; }
// Return parameter and its length int kGetNextParameter( PARAMETERLIST * pstList, char * pcParameter ) { int i; int iLength; // If there is no parameter, exit if( pstList->iLength <= pstList->iCurrentPosition ) { return 0; } // Search white space for ( i = pstList->iCurrentPosition ; i < pstList->iLength ; i++ ) { if ( pstList->pcBuffer[i] == ' ' ) { break; } } // Copy parameter and return length kMemCpy( pcParameter, pstList->pcBuffer + pstList->iCurrentPosition, i ); iLength = i - pstList->iCurrentPosition; pcParameter[iLength] = '\0'; // Update parameter position pstList->iCurrentPosition += iLength + 1; return iLength; }
// 파일을 생성 static BOOL kCreateFile(const char* pcFileName,DIRECTORYENTRY* pstEntry,int* piDirectoryEntryIndex) { DWORD dwCluster; // 빈 클러스터를 찾아서 할당된 것으로 설정 dwCluster = kFindFreeCluster(); if((dwCluster==FILESYSTEM_LASTCLUSTER)||(kSetClusterLinkData(dwCluster,FILESYSTEM_LASTCLUSTER)==FALSE)) { return FALSE; } // 빈 디렉터리 엔트리를 검색 *piDirectoryEntryIndex = kFindFreeDirectoryEntry(); if(*piDirectoryEntryIndex==-1) { // 실패하면 할당받은 클러스터를 반환해야 함 kSetClusterLinkData(dwCluster,FILESYSTEM_FREECLUSTER); return FALSE; } // 디렉터리 엔트리를 설정 kMemCpy(pstEntry->vcFileName,pcFileName,kStrLen(pcFileName)+1); pstEntry->dwStartClusterIndex = dwCluster; pstEntry->dwFileSize = 0; // 디렉터리 엔트리를 등록 if(kSetDirectoryEntryData(*piDirectoryEntryIndex,pstEntry)==FALSE) { // 실패하여 할당받은 클러스털르 반환해야 함 kSetClusterLinkData(dwCluster,FILESYSTEM_FREECLUSTER); return FALSE; } return TRUE; }
/** * 공백으로 구분된 파라미터의 내용과 길이를 반환 */ int kGetNextParameter( PARAMETERLIST* pstList, char* pcParameter ) { int i; int iLength; // 더 이상 파라미터가 없으면 나감 if( pstList->iLength <= pstList->iCurrentPosition ) { return 0; } // 버퍼의 길이만큼 이동하면서 공백을 검색 for( i = pstList->iCurrentPosition ; i < pstList->iLength ; i++ ) { if( pstList->pcBuffer[ i ] == ' ' ) { break; } } // 파라미터를 복사하고 길이를 반환 kMemCpy( pcParameter, pstList->pcBuffer + pstList->iCurrentPosition, i ); iLength = i - pstList->iCurrentPosition; pcParameter[ iLength ] = '\0'; // 파라미터의 위치 업데이트 pstList->iCurrentPosition += iLength + 1; return iLength; }
/** * 램 디스크에 여러 섹터를 씀 */ int kWriteRDDSector( BOOL bPrimary, BOOL bMaster, DWORD dwLBA, int iSectorCount, char* pcBuffer ) { int iRealWriteCount; // LBA 어드레스부터 끝까지 쓸 수 있는 섹터 수와 써야 할 섹터 수를 비교해서 // 실제로 쓸 수 있는 수를 계산 iRealWriteCount = MIN( gs_stRDDManager.dwTotalSectorCount - (dwLBA + iSectorCount), iSectorCount ); // 데이터를 실제로 쓸 섹터 수만큼 램 디스크 메모리에 복사 kMemCpy( gs_stRDDManager.pbBuffer + ( dwLBA * 512 ), pcBuffer, iRealWriteCount * 512 ); return iRealWriteCount; }
/** * 램 디스크에서 여러 섹터를 읽어서 반환 */ int kReadRDDSector( BOOL bPrimary, BOOL bMaster, DWORD dwLBA, int iSectorCount, char* pcBuffer ) { int iRealReadCount; // LBA 어드레스부터 끝까지 읽을 수 있는 섹터 수와 읽어야 할 섹터 수를 비교해서 // 실제로 읽을 수 있는 수를 계산 iRealReadCount = MIN( gs_stRDDManager.dwTotalSectorCount - (dwLBA + iSectorCount), iSectorCount ); // 램 디스크 메모리에서 데이터를 실제로 읽을 섹터 수만큼 복사해서 반환 kMemCpy( pcBuffer, gs_stRDDManager.pbBuffer + ( dwLBA * 512 ), iRealReadCount * 512 ); return iRealReadCount; }
/** * 루트 디렉터리의 해당 인덱스에 위치하는 디렉터리 엔트리를 반환 */ BOOL kGetDirectoryEntryData( int iIndex, DIRECTORYENTRY* pstEntry ) { DIRECTORYENTRY* pstRootEntry; // 파일 시스템을 인식하지 못했거나 인덱스가 올바르지 않으면 실패 if( ( gs_stFileSystemManager.bMounted == FALSE ) || ( iIndex < 0 ) || ( iIndex >= FILESYSTEM_MAXDIRECTORYENTRYCOUNT ) ) { return FALSE; } // 루트 디렉터리를 읽음 if( kReadCluster( 0, gs_vbTempBuffer ) == FALSE ) { return FALSE; } // 루트 디렉터리에 있는 해당 데이터를 갱신 pstRootEntry = ( DIRECTORYENTRY* ) gs_vbTempBuffer; kMemCpy( pstEntry, pstRootEntry + iIndex, sizeof( DIRECTORYENTRY ) ); return TRUE; }
/** * 인터럽트가 발생했을 때, 다른 태스크를 찾아 전환 * 반드시 인터럽트나 예외가 발생했을 때 호출해야 함 */ BOOL kScheduleInInterrupt( void ) { TCB* pstRunningTask, * pstNextTask; char* pcContextAddress; BYTE bCurrentAPICID; QWORD qwISTStartAddress; // 현재 로컬 APIC ID 확인 bCurrentAPICID = kGetAPICID(); // 임계 영역 시작 kLockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); // 전환할 태스크가 없으면 종료 pstNextTask = kGetNextTaskToRun( bCurrentAPICID ); if( pstNextTask == NULL ) { // 임계 영역 끝 kUnlockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); return FALSE; } //========================================================================== // 태스크 전환 처리 // 인터럽트 핸들러에서 저장한 콘텍스트를 다른 콘텍스트로 덮어쓰는 방법으로 처리 //========================================================================== // IST의 끝부분부터 코어 0 -> 코어 15 순으로 64Kbyte씩 쓰고 있으므로, 로컬 APIC ID를 // 이용해서 IST 어드레스를 계산 qwISTStartAddress = IST_STARTADDRESS + IST_SIZE - ( IST_SIZE / MAXPROCESSORCOUNT * bCurrentAPICID ); pcContextAddress = ( char* ) qwISTStartAddress - sizeof( CONTEXT ); pstRunningTask = gs_vstScheduler[ bCurrentAPICID ].pstRunningTask; gs_vstScheduler[ bCurrentAPICID ].pstRunningTask = pstNextTask; // 유휴 태스크에서 전환되었다면 사용한 Tick Count를 증가시킴 if( ( pstRunningTask->qwFlags & TASK_FLAGS_IDLE ) == TASK_FLAGS_IDLE ) { gs_vstScheduler[ bCurrentAPICID ].qwSpendProcessorTimeInIdleTask += TASK_PROCESSORTIME; } // 태스크 종료 플래그가 설정된 경우, 콘텍스트를 저장하지 않고 대기 리스트에만 삽입 if( pstRunningTask->qwFlags & TASK_FLAGS_ENDTASK ) { kAddListToTail( &( gs_vstScheduler[ bCurrentAPICID ].stWaitList ), pstRunningTask ); } // 태스크가 종료되지 않으면 IST에 있는 콘텍스트를 복사하고, 현재 태스크를 준비 리스트로 // 옮김 else { kMemCpy( &( pstRunningTask->stContext ), pcContextAddress, sizeof( CONTEXT ) ); } // 다음에 수행할 태스크가 FPU를 쓴 태스크가 아니라면 TS bit 설정 if( gs_vstScheduler[ bCurrentAPICID ].qwLastFPUUsedTaskID != pstNextTask->stLink.qwID ) { kSetTS(); } else { kClearTS(); } // 임계 영역 끝 kUnlockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); // 전환해서 실행할 태스크를 Running Task로 설정하고 콘텍스트를 IST에 복사해서 // 자동으로 태스크 전환이 일어나도록 함 kMemCpy( pcContextAddress, &( pstNextTask->stContext ), sizeof( CONTEXT ) ); // 종료하는 태스크가 아니면 스케줄러에 태스크 추가 if( ( pstRunningTask->qwFlags & TASK_FLAGS_ENDTASK ) != TASK_FLAGS_ENDTASK ) { // 스케줄러에 태스크를 추가, 부하 분산을 고려함 kAddTaskToSchedulerWithLoadBalancing( pstRunningTask ); } // 프로세서 사용 시간을 업데이트 gs_vstScheduler[ bCurrentAPICID ].iProcessorTime = TASK_PROCESSORTIME; return TRUE; }
// 파일 시스템의 정보를 반환 void kGetFileSystemInformation(FILESYSTEMMANAGER* pstManager) { kMemCpy(pstManager,&gs_stFileSystemManager,sizeof(gs_stFileSystemManager)); }
/** * 접근한 시간을 전체적으로 낮춤 */ static void kCutDownAccessTime( int iCacheTableIndex ) { CACHEBUFFER stTemp; CACHEBUFFER* pstCacheBuffer; BOOL bSorted; int i, j; // 캐시 테이블의 최대 개수를 넘어서면 실패 if( iCacheTableIndex > CACHE_MAXCACHETABLEINDEX ) { return ; } // 접근 시간이 아직 최대치를 넘지 않았다면 접근 시간을 줄일 필요 없음 if( gs_stCacheManager.vdwAccessTime[ iCacheTableIndex ] < 0xfffffffe ) { return ; } // 캐시 버퍼를 접근 시간으로 오름차순으로 정렬함 // 버블 정렬(Bouble Sort) 사용 pstCacheBuffer = gs_stCacheManager.vvstCacheBuffer[ iCacheTableIndex ]; for( j = 0 ; j < gs_stCacheManager.vdwMaxCount[ iCacheTableIndex ] - 1 ; j++ ) { // 기본은 정렬된 것으로 저장 bSorted = TRUE; for( i = 0 ; i < gs_stCacheManager.vdwMaxCount[ iCacheTableIndex ] - 1 - j ; i++ ) { // 인접한 두 데이터를 비교하여 접근 시간이 큰 것을 우측(i+1)에 위치시킴 if( pstCacheBuffer[ i ].dwAccessTime > pstCacheBuffer[ i + 1 ].dwAccessTime ) { // 두 데이터를 교환하므로 정렬되지 않은 것으로 표시 bSorted = FALSE; // i번째 캐시와 i+1번째 캐시를 교환 kMemCpy( &stTemp, &( pstCacheBuffer[ i ] ), sizeof( CACHEBUFFER ) ); kMemCpy( &( pstCacheBuffer[ i ] ), &( pstCacheBuffer[ i + 1 ] ), sizeof( CACHEBUFFER ) ); kMemCpy( &( pstCacheBuffer[ i + 1 ] ), &stTemp, sizeof( CACHEBUFFER ) ); } } // 다 정렬되었으면 루프를 빠져 나감 if( bSorted == TRUE ) { break; } } // 오름차순으로 정렬했으므로, 인덱스가 증가할수록 접근 시간 큰(최신) 캐시 버퍼임 // 접근 시간을 0부터 순차적으로 설정하여 데이터 갱신 for( i = 0 ; i < gs_stCacheManager.vdwMaxCount[ iCacheTableIndex ] ; i++ ) { pstCacheBuffer[ i ].dwAccessTime = i; } // 접근 시간을 파일 시스템 캐시 자료구조에 저장하여 다음부터는 변경된 값으로 // 접근 시간을 설정하도록 함 gs_stCacheManager.vdwAccessTime[ iCacheTableIndex ] = i; }
/** * 화면 버퍼의 변경된 내용을 GUI 콘솔 셸 윈도우 화면에 업데이트 */ static void kProcessConsoleBuffer( QWORD qwWindowID ) { int i; int j; CONSOLEMANAGER* pstManager; CHARACTER* pstScreenBuffer; CHARACTER* pstPreviousScreenBuffer; RECT stLineArea; BOOL bChanged; static QWORD s_qwLastTickCount = 0; BOOL bFullRedraw; // 콘솔을 관리하는 자료구조를 반환 받아 화면 버퍼의 어드레스를 저장하고 // 이전 화면 버퍼의 어드레스도 저장 pstManager = kGetConsoleManager(); pstScreenBuffer = pstManager->pstScreenBuffer; pstPreviousScreenBuffer = gs_vstPreviousScreenBuffer; // 화면을 전체를 업데이트 한 지 5초가 지났으면 무조건 화면 전체를 다시 그림 if( kGetTickCount() - s_qwLastTickCount > 5000 ) { s_qwLastTickCount = kGetTickCount(); bFullRedraw = TRUE; } else { bFullRedraw = FALSE; } // 화면 버퍼의 높이만큼 반복 for( j = 0 ; j < CONSOLE_HEIGHT ; j++ ) { // 처음에는 변경되지 않은 것으로 플래그 설정 bChanged = FALSE; // 현재 라인에 변화가 있는지 비교하여 변경 여부 플래그를 처리 for( i = 0 ; i < CONSOLE_WIDTH ; i++ ) { // 문자를 비교하여 다르거나 전체를 새로 그려야 하면 이전 화면 버퍼에 // 업데이트하고 변경 여부 플래그를 설정 if( ( pstScreenBuffer->bCharactor != pstPreviousScreenBuffer->bCharactor ) || ( bFullRedraw == TRUE ) ) { // 문자를 화면에 출력 kDrawText( qwWindowID, i * FONT_ENGLISHWIDTH + 2, j * FONT_ENGLISHHEIGHT + WINDOW_TITLEBAR_HEIGHT, RGB( 0, 255, 0 ), RGB( 0, 0, 0 ), &( pstScreenBuffer->bCharactor ), 1); // 이전 화면 버퍼로 값을 옮겨 놓고 현재 라인에 이전과 // 다른 데이터가 있음을 표시 kMemCpy( pstPreviousScreenBuffer, pstScreenBuffer, sizeof( CHARACTER ) ); bChanged = TRUE; } pstScreenBuffer++; pstPreviousScreenBuffer++; } // 현재 라인에서 변경된 데이터가 있다면 현재 라인만 화면에 업데이트 if( bChanged == TRUE ) { // 현재 라인의 영역을 계산 kSetRectangleData( 2, j * FONT_ENGLISHHEIGHT + WINDOW_TITLEBAR_HEIGHT, 5 + FONT_ENGLISHWIDTH * CONSOLE_WIDTH, ( j + 1 ) * FONT_ENGLISHHEIGHT + WINDOW_TITLEBAR_HEIGHT - 1, &stLineArea ); // 윈도우의 일부만 화면 업데이트 kUpdateScreenByWindowArea( qwWindowID, &stLineArea ); } } }
/** * MP 설정 테이블의 정보를 모두 화면에 출력 */ void kPrintMPConfigurationTable( void ) { MPCONFIGRUATIONMANAGER* pstMPConfigurationManager; QWORD qwMPFloatingPointerAddress; MPFLOATINGPOINTER* pstMPFloatingPointer; MPCONFIGURATIONTABLEHEADER* pstMPTableHeader; PROCESSORENTRY* pstProcessorEntry; BUSENTRY* pstBusEntry; IOAPICENTRY* pstIOAPICEntry; IOINTERRUPTASSIGNMENTENTRY* pstIOAssignmentEntry; LOCALINTERRUPTASSIGNMENTENTRY* pstLocalAssignmentEntry; QWORD qwBaseEntryAddress; char vcStringBuffer[ 20 ]; WORD i; BYTE bEntryType; // 화면에 출력할 문자열 char* vpcInterruptType[ 4 ] = { "INT", "NMI", "SMI", "ExtINT" }; char* vpcInterruptFlagsPO[ 4 ] = { "Conform", "Active High", "Reserved", "Active Low" }; char* vpcInterruptFlagsEL[ 4 ] = { "Conform", "Edge-Trigger", "Reserved", "Level-Trigger"}; //========================================================================== // MP 설정 테이블 처리 함수를 먼저 호출하여 시스템 처리에 필요한 정보를 저장 //========================================================================== kPrintf( "================ MP Configuration Table Summary ================\n" ); pstMPConfigurationManager = kGetMPConfigurationManager(); if( ( pstMPConfigurationManager->qwBaseEntryStartAddress == 0 ) && ( kAnalysisMPConfigurationTable() == FALSE ) ) { kPrintf( "MP Configuration Table Analysis Fail\n" ); return ; } kPrintf( "MP Configuration Table Analysis Success\n" ); kPrintf( "MP Floating Pointer Address : 0x%Q\n", pstMPConfigurationManager->pstMPFloatingPointer ); kPrintf( "PIC Mode Support : %d\n", pstMPConfigurationManager->bUsePICMode ); kPrintf( "MP Configuration Table Header Address : 0x%Q\n", pstMPConfigurationManager->pstMPConfigurationTableHeader ); kPrintf( "Base MP Configuration Table Entry Start Address : 0x%Q\n", pstMPConfigurationManager->qwBaseEntryStartAddress ); kPrintf( "Processor Count : %d\n", pstMPConfigurationManager->iProcessorCount ); kPrintf( "ISA Bus ID : %d\n", pstMPConfigurationManager->bISABusID ); kPrintf( "Press any key to continue... ('q' is exit) : " ); if( kGetCh() == 'q' ) { kPrintf( "\n" ); return ; } kPrintf( "\n" ); //========================================================================== // MP 플로팅 포인터 정보를 출력 //========================================================================== kPrintf( "=================== MP Floating Pointer ===================\n" ); pstMPFloatingPointer = pstMPConfigurationManager->pstMPFloatingPointer; kMemCpy( vcStringBuffer, pstMPFloatingPointer->vcSignature, 4 ); vcStringBuffer[ 4 ] = '\0'; kPrintf( "Signature : %s\n", vcStringBuffer ); kPrintf( "MP Configuration Table Address : 0x%Q\n", pstMPFloatingPointer->dwMPConfigurationTableAddress ); kPrintf( "Length : %d * 16 Byte\n", pstMPFloatingPointer->bLength ); kPrintf( "Version : %d\n", pstMPFloatingPointer->bRevision ); kPrintf( "CheckSum : 0x%X\n", pstMPFloatingPointer->bCheckSum ); kPrintf( "Feature Byte 1 : 0x%X ", pstMPFloatingPointer->vbMPFeatureByte[ 0 ] ); // MP 설정 테이블 사용 여부 출력 if( pstMPFloatingPointer->vbMPFeatureByte[ 0 ] == 0 ) { kPrintf( "(Use MP Configuration Table)\n" ); } else { kPrintf( "(Use Default Configuration)\n" ); } // PIC 모드 지원 여부 출력 kPrintf( "Feature Byte 2 : 0x%X ", pstMPFloatingPointer->vbMPFeatureByte[ 1 ] ); if( pstMPFloatingPointer->vbMPFeatureByte[ 2 ] & MP_FLOATINGPOINTER_FEATUREBYTE2_PICMODE ) { kPrintf( "(PIC Mode Support)\n" ); } else { kPrintf( "(Virtual Wire Mode Support)\n" ); } //========================================================================== // MP 설정 테이블 헤더 정보를 출력 //========================================================================== kPrintf( "\n=============== MP Configuration Table Header ===============\n" ); pstMPTableHeader = pstMPConfigurationManager->pstMPConfigurationTableHeader; kMemCpy( vcStringBuffer, pstMPTableHeader->vcSignature, 4 ); vcStringBuffer[ 4 ] = '\0'; kPrintf( "Signature : %s\n", vcStringBuffer ); kPrintf( "Length : %d Byte\n", pstMPTableHeader->wBaseTableLength ); kPrintf( "Version : %d\n", pstMPTableHeader->bRevision ); kPrintf( "CheckSum : 0x%X\n", pstMPTableHeader->bCheckSum ); kMemCpy( vcStringBuffer, pstMPTableHeader->vcOEMIDString, 8 ); vcStringBuffer[ 8 ] = '\0'; kPrintf( "OEM ID String : %s\n", vcStringBuffer ); kMemCpy( vcStringBuffer, pstMPTableHeader->vcProductIDString, 12 ); vcStringBuffer[ 12 ] = '\0'; kPrintf( "Product ID String : %s\n", vcStringBuffer ); kPrintf( "OEM Table Pointer : 0x%X\n", pstMPTableHeader->dwOEMTablePointerAddress ); kPrintf( "OEM Table Size : %d Byte\n", pstMPTableHeader->wOEMTableSize ); kPrintf( "Entry Count : %d\n", pstMPTableHeader->wEntryCount ); kPrintf( "Memory Mapped I/O Address Of Local APIC : 0x%X\n", pstMPTableHeader->dwMemoryMapIOAddressOfLocalAPIC ); kPrintf( "Extended Table Length : %d Byte\n", pstMPTableHeader->wExtendedTableLength ); kPrintf( "Extended Table Checksum : 0x%X\n", pstMPTableHeader->bExtendedTableChecksum ); kPrintf( "Press any key to continue... ('q' is exit) : " ); if( kGetCh() == 'q' ) { kPrintf( "\n" ); return ; } kPrintf( "\n" ); //========================================================================== // 기본 MP 설정 테이블 엔트리 정보를 출력 //========================================================================== kPrintf( "\n============= Base MP Configuration Table Entry =============\n" ); qwBaseEntryAddress = pstMPFloatingPointer->dwMPConfigurationTableAddress + sizeof( MPCONFIGURATIONTABLEHEADER ); for( i = 0 ; i < pstMPTableHeader->wEntryCount ; i++ ) { bEntryType = *( BYTE* ) qwBaseEntryAddress; switch( bEntryType ) { // 프로세스 엔트리 정보 출력 case MP_ENTRYTYPE_PROCESSOR: pstProcessorEntry = ( PROCESSORENTRY* ) qwBaseEntryAddress; kPrintf( "Entry Type : Processor\n" ); kPrintf( "Local APIC ID : %d\n", pstProcessorEntry->bLocalAPICID ); kPrintf( "Local APIC Version : 0x%X\n", pstProcessorEntry->bLocalAPICVersion ); kPrintf( "CPU Flags : 0x%X ", pstProcessorEntry->bCPUFlags ); // Enable/Disable 출력 if( pstProcessorEntry->bCPUFlags & MP_PROCESSOR_CPUFLAGS_ENABLE ) { kPrintf( "(Enable, " ); } else { kPrintf( "(Disable, " ); } // BSP/AP 출력 if( pstProcessorEntry->bCPUFlags & MP_PROCESSOR_CPUFLAGS_BSP ) { kPrintf( "BSP)\n" ); } else { kPrintf( "AP)\n" ); } kPrintf( "CPU Signature : 0x%X\n", pstProcessorEntry->vbCPUSignature ); kPrintf( "Feature Flags : 0x%X\n\n", pstProcessorEntry->dwFeatureFlags ); // 프로세스 엔트리의 크기만큼 어드레스를 증가시켜 다음 엔트리로 이동 qwBaseEntryAddress += sizeof( PROCESSORENTRY ); break; // 버스 엔트리 정보 출력 case MP_ENTRYTYPE_BUS: pstBusEntry = ( BUSENTRY* ) qwBaseEntryAddress; kPrintf( "Entry Type : Bus\n" ); kPrintf( "Bus ID : %d\n", pstBusEntry->bBusID ); kMemCpy( vcStringBuffer, pstBusEntry->vcBusTypeString, 6 ); vcStringBuffer[ 6 ] = '\0'; kPrintf( "Bus Type String : %s\n\n", vcStringBuffer ); // 버스 엔트리의 크기만큼 어드레스를 증가시켜 다음 엔트리로 이동 qwBaseEntryAddress += sizeof( BUSENTRY ); break; // I/O APIC 엔트리 case MP_ENTRYTYPE_IOAPIC: pstIOAPICEntry = ( IOAPICENTRY* ) qwBaseEntryAddress; kPrintf( "Entry Type : I/O APIC\n" ); kPrintf( "I/O APIC ID : %d\n", pstIOAPICEntry->bIOAPICID ); kPrintf( "I/O APIC Version : 0x%X\n", pstIOAPICEntry->bIOAPICVersion ); kPrintf( "I/O APIC Flags : 0x%X ", pstIOAPICEntry->bIOAPICFlags ); // Enable/Disable 출력 if( pstIOAPICEntry->bIOAPICFlags == 1 ) { kPrintf( "(Enable)\n" ); } else { kPrintf( "(Disable)\n" ); } kPrintf( "Memory Mapped I/O Address : 0x%X\n\n", pstIOAPICEntry->dwMemoryMapAddress ); // I/O APIC 엔트리의 크기만큼 어드레스를 증가시켜 다음 엔트리로 이동 qwBaseEntryAddress += sizeof( IOAPICENTRY ); break; // I/O 인터럽트 지정 엔트리 case MP_ENTRYTYPE_IOINTERRUPTASSIGNMENT: pstIOAssignmentEntry = ( IOINTERRUPTASSIGNMENTENTRY* ) qwBaseEntryAddress; kPrintf( "Entry Type : I/O Interrupt Assignment\n" ); kPrintf( "Interrupt Type : 0x%X ", pstIOAssignmentEntry->bInterruptType ); // 인터럽트 타입 출력 kPrintf( "(%s)\n", vpcInterruptType[ pstIOAssignmentEntry->bInterruptType ] ); kPrintf( "I/O Interrupt Flags : 0x%X ", pstIOAssignmentEntry->wInterruptFlags ); // 극성과 트리거 모드 출력 kPrintf( "(%s, %s)\n", vpcInterruptFlagsPO[ pstIOAssignmentEntry->wInterruptFlags & 0x03 ], vpcInterruptFlagsEL[ ( pstIOAssignmentEntry->wInterruptFlags >> 2 ) & 0x03 ] ); kPrintf( "Source BUS ID : %d\n", pstIOAssignmentEntry->bSourceBUSID ); kPrintf( "Source BUS IRQ : %d\n", pstIOAssignmentEntry->bSourceBUSIRQ ); kPrintf( "Destination I/O APIC ID : %d\n", pstIOAssignmentEntry->bDestinationIOAPICID ); kPrintf( "Destination I/O APIC INTIN : %d\n\n", pstIOAssignmentEntry->bDestinationIOAPICINTIN ); // I/O 인터럽트 지정 엔트리의 크기만큼 어드레스를 증가시켜 다음 엔트리로 이동 qwBaseEntryAddress += sizeof( IOINTERRUPTASSIGNMENTENTRY ); break; // 로컬 인터럽트 지정 엔트리 case MP_ENTRYTYPE_LOCALINTERRUPTASSIGNMENT: pstLocalAssignmentEntry = ( LOCALINTERRUPTASSIGNMENTENTRY* ) qwBaseEntryAddress; kPrintf( "Entry Type : Local Interrupt Assignment\n" ); kPrintf( "Interrupt Type : 0x%X ", pstLocalAssignmentEntry->bInterruptType ); // 인터럽트 타입 출력 kPrintf( "(%s)\n", vpcInterruptType[ pstLocalAssignmentEntry->bInterruptType ] ); kPrintf( "I/O Interrupt Flags : 0x%X ", pstLocalAssignmentEntry->wInterruptFlags ); // 극성과 트리거 모드 출력 kPrintf( "(%s, %s)\n", vpcInterruptFlagsPO[ pstLocalAssignmentEntry->wInterruptFlags & 0x03 ], vpcInterruptFlagsEL[ ( pstLocalAssignmentEntry->wInterruptFlags >> 2 ) & 0x03 ] ); kPrintf( "Source BUS ID : %d\n", pstLocalAssignmentEntry->bSourceBUSID ); kPrintf( "Source BUS IRQ : %d\n", pstLocalAssignmentEntry->bSourceBUSIRQ ); kPrintf( "Destination Local APIC ID : %d\n", pstLocalAssignmentEntry->bDestinationLocalAPICID ); kPrintf( "Destination Local APIC LINTIN : %d\n\n", pstLocalAssignmentEntry->bDestinationLocalAPICLINTIN ); // 로컬 인터럽트 지정 엔트리의 크기만큼 어드레스를 증가시켜 다음 엔트리로 이동 qwBaseEntryAddress += sizeof( LOCALINTERRUPTASSIGNMENTENTRY ); break; default : kPrintf( "Unknown Entry Type. %d\n", bEntryType ); break; } // 3개를 출력하고 나면 키 입력을 대기 if( ( i != 0 ) && ( ( ( i + 1 ) % 3 ) == 0 ) ) { kPrintf( "Press any key to continue... ('q' is exit) : " ); if( kGetCh() == 'q' ) { kPrintf( "\n" ); return ; } kPrintf( "\n" ); } } }
/** * 이벤트 큐에 수신된 이벤트 처리 */ BOOL kProcessEventQueueData( void ) { EVENT vstEvent[ WINDOWMANAGER_DATAACCUMULATECOUNT ]; int iEventCount; WINDOWEVENT* pstWindowEvent; WINDOWEVENT* pstNextWindowEvent; QWORD qwWindowID; RECT stArea; RECT stOverlappedArea; int i; int j; //-------------------------------------------------------------------------- // 윈도우 매니저 태스크의 이벤트 큐에 수신된 이벤트를 통합하는 부분 //-------------------------------------------------------------------------- for( i = 0 ; i < WINDOWMANAGER_DATAACCUMULATECOUNT ; i++ ) { // 이벤트가 수신되기를 기다림 if( kReceiveEventFromWindowManagerQueue( &( vstEvent[ i ] ) ) == FALSE ) { // 처음부터 이벤트가 수신되지 않았으면 종료 if( i == 0 ) { return FALSE; } else { break; } } pstWindowEvent = &( vstEvent[ i ].stWindowEvent ); // 윈도우 ID로 업데이트하는 이벤트가 수신되면 윈도우 영역을 이벤트 데이터에 삽입 if( vstEvent[ i ].qwType == EVENT_WINDOWMANAGER_UPDATESCREENBYID ) { // 윈도우의 크기를 이벤트 자료구조에 삽입 if( kGetWindowArea( pstWindowEvent->qwWindowID, &stArea ) == FALSE ) { kSetRectangleData( 0, 0, 0, 0, &( pstWindowEvent->stArea ) ); } else { kSetRectangleData( 0, 0, kGetRectangleWidth( &stArea ) - 1, kGetRectangleHeight( &stArea ) - 1, &( pstWindowEvent->stArea ) ); } } } // 저장된 이벤트를 검사하면서 합칠 수 있는 이벤트는 하나로 만듦 iEventCount = i; for( j = 0 ; j < iEventCount ; j++ ) { // 수신된 이벤트 중에 이벤트 중에서 이번에 처리할 것과 같은 윈도우에서 // 발생하는 윈도우 이벤트를 검색 pstWindowEvent = &( vstEvent[ j ].stWindowEvent ); if( ( vstEvent[ j ].qwType != EVENT_WINDOWMANAGER_UPDATESCREENBYID ) && ( vstEvent[ j ].qwType != EVENT_WINDOWMANAGER_UPDATESCREENBYWINDOWAREA ) && ( vstEvent[ j ].qwType != EVENT_WINDOWMANAGER_UPDATESCREENBYSCREENAREA ) ) { continue; } // 수신한 이벤트의 끝까지 루프를 수행하면서 수신된 이벤트를 검사 for( i = j + 1 ; i < iEventCount ; i++ ) { pstNextWindowEvent = &( vstEvent[ i ].stWindowEvent ); // 화면 업데이트가 아니거나 윈도우 ID가 일치하지 않으면 제외 if( ( ( vstEvent[ i ].qwType != EVENT_WINDOWMANAGER_UPDATESCREENBYID ) && ( vstEvent[ i ].qwType != EVENT_WINDOWMANAGER_UPDATESCREENBYWINDOWAREA ) && ( vstEvent[ i ].qwType != EVENT_WINDOWMANAGER_UPDATESCREENBYSCREENAREA ) ) || ( pstWindowEvent->qwWindowID != pstNextWindowEvent->qwWindowID ) ) { continue; } // 겹치는 영역을 계산하여 겹치지 않으면 제외 if( kGetOverlappedRectangle( &( pstWindowEvent->stArea ), &( pstNextWindowEvent->stArea ), &stOverlappedArea ) == FALSE ) { continue; } // 두 영역이 일치하거나 어느 한쪽이 포함되면 이벤트를 통합 if( kMemCmp( &( pstWindowEvent->stArea ), &stOverlappedArea, sizeof( RECT ) ) == 0 ) { // 현재 이벤트의 윈도우의 영역이 겹치는 영역과 일치한다면 // 다음 이벤트의 윈도우 영역이 현재 윈도우 영역과 같거나 포함함 // 따라서 현재 이벤트에 다음 이벤트의 윈도우 영역을 복사하고 // 다음 이벤트는 삭제 kMemCpy( &( pstWindowEvent->stArea ), &( pstNextWindowEvent->stArea ), sizeof( RECT ) ); vstEvent[ i ].qwType = EVENT_UNKNOWN; } else if( kMemCmp( &( pstNextWindowEvent->stArea ), &stOverlappedArea, sizeof( RECT ) ) == 0 ) { // 다음 이벤트의 윈도우의 영역이 겹치는 영역과 일치한다면 // 현재 이벤트의 윈도우 영역이 다음 윈도우 영역과 같거나 포함함 // 따라서 윈도우 영역을 복사하지 않고 다음 이벤트를 삭제 vstEvent[ i ].qwType = EVENT_UNKNOWN; } } } // 통합된 이벤트를 모두 처리 for( i = 0 ; i < iEventCount ; i++ ) { pstWindowEvent = &( vstEvent[ i ].stWindowEvent ); // 타입 별로 처리 switch( vstEvent[ i ].qwType ) { // 현재 윈도우가 있는 영역을 화면에 업데이트 case EVENT_WINDOWMANAGER_UPDATESCREENBYID: // 윈도우의 내부 영역을 화면에 업데이트 case EVENT_WINDOWMANAGER_UPDATESCREENBYWINDOWAREA: // 윈도우를 기준으로 한 좌표를 화면 좌표로 변환하여 업데이트 처리 if( kConvertRectClientToScreen( pstWindowEvent->qwWindowID, &( pstWindowEvent->stArea ), &stArea ) == TRUE ) { // 윈도우 영역은 위에서 했으므로 그대로 화면 업데이트 함수를 호출 kRedrawWindowByArea( &stArea, pstWindowEvent->qwWindowID ); } break; // 화면 좌표로 전달된 영역을 화면에 업데이트 case EVENT_WINDOWMANAGER_UPDATESCREENBYSCREENAREA: kRedrawWindowByArea( &( pstWindowEvent->stArea ), WINDOW_INVALIDID ); break; default: break; } } return TRUE; }
// 파일을 읽어 버퍼로 복사 DWORD kReadFile(void* pvBuffer,DWORD dwSize,DWORD dwCount,FILE* pstFile) { DWORD dwTotalCount; DWORD dwReadCount; DWORD dwOffsetInCluster; DWORD dwCopySize; FILEHANDLE* pstFileHandle; DWORD dwNextClusterIndex; // 핸들이 파일 타입이 아니면 실패 if((pstFile==NULL)||(pstFile->bType!=FILESYSTEM_TYPE_FILE)) { return 0; } pstFileHandle = &(pstFile->stFileHandle); // 파일의 끝이거나 마지막 클러스터면 종료 if((pstFileHandle->dwCurrentOffset==pstFileHandle->dwFileSize)||(pstFileHandle->dwCurrentClusterIndex==FILESYSTEM_LASTCLUSTER)) { return 0; } // 파일 끝과 비교해서 실제로 읽을 수 있는 값을 계산 dwTotalCount = MIN(dwSize*dwCount,pstFileHandle->dwFileSize-pstFileHandle->dwCurrentOffset); // 동기화 kLock(&(gs_stFileSystemManager.stMutex)); // 계산된 값만큼 다 읽을 때까지 반복 dwReadCount=0; while(dwReadCount!=dwTotalCount) { //===================================================================================== // 클러스터를 읽어서 버퍼에 복사 //===================================================================================== // 현재 클러스터를 읽음 if(kReadCluster(pstFileHandle->dwCurrentClusterIndex,gs_vbTempBuffer)==FALSE) { break; } // 클러스터 내에서 파일 포인터가 존재하는 오프셋을 계산 dwOffsetInCluster = pstFileHandle->dwCurrentOffset%FILESYSTEM_CLUSTERSIZE; // 여러 클러스터에 걸쳐져 있다면 현재 클러스터에서 남은 만큼 읽고 다음 클러스터로 이동 dwCopySize = MIN(FILESYSTEM_CLUSTERSIZE-dwOffsetInCluster,dwTotalCount-dwReadCount); kMemCpy((char*)pvBuffer+dwReadCount,gs_vbTempBuffer+dwOffsetInCluster,dwCopySize); // 읽은 바이트 수와 파일 포인터의 위치를 갱신 dwReadCount +=dwCopySize; pstFileHandle->dwCurrentOffset +=dwCopySize; //===================================================================================== // 현재 클러스터를 끝까지 다 읽었으면 다음 클러스터로 이동 //===================================================================================== if((pstFileHandle->dwCurrentOffset%FILESYSTEM_CLUSTERSIZE)==0) { // 현재 클러스터의 링크 데이터를 찾아 다음 클러스터를 얻음 if(kGetClusterLinkData(pstFileHandle->dwCurrentClusterIndex,&dwNextClusterIndex)==FALSE) { break; } // 클러스터 정보를 갱신 pstFileHandle->dwPreviousClusterIndex=pstFileHandle->dwCurrentClusterIndex; pstFileHandle->dwCurrentClusterIndex=dwNextClusterIndex; } } // 동기화 kUnlock(&(gs_stFileSystemManager.stMutex)); // 읽은 바이트 수를 반환 return dwReadCount; }
// 버퍼의 데이터를 파일에 씀 DWORD kWriteFile(const void* pvBuffer,DWORD dwSize,DWORD dwCount,FILE* pstFile) { DWORD dwWriteCount; DWORD dwTotalCount; DWORD dwOffsetInCluster; DWORD dwCopySize; DWORD dwAllocatedClusterIndex; DWORD dwNextClusterIndex; DWORD dwUpperFileSize; FILEHANDLE* pstFileHandle; // 핸들이 파일 타입이 아니면 실패 if((pstFile==NULL)||(pstFile->bType!=FILESYSTEM_TYPE_FILE)) { return 0; } pstFileHandle = &(pstFile->stFileHandle); // FileSize를 클러스터 크기 단위로 구한 수 dwUpperFileSize = ((pstFileHandle->dwFileSize+FILESYSTEM_CLUSTERSIZE)/FILESYSTEM_CLUSTERSIZE)*FILESYSTEM_CLUSTERSIZE; // 총 바이트 수 dwTotalCount = dwSize*dwCount; // 동기화 kLock(&(gs_stFileSystemManager.stMutex)); // 다 쓸 때가지 반복 dwWriteCount=0; while(dwWriteCount!=dwTotalCount) { // 클러스터 내에서 파일 포인터가 존재하는 오프셋을 계산 dwOffsetInCluster = pstFileHandle->dwCurrentOffset%FILESYSTEM_CLUSTERSIZE; dwCopySize = MIN(FILESYSTEM_CLUSTERSIZE-dwOffsetInCluster,dwTotalCount-dwWriteCount); dwAllocatedClusterIndex=-1; // 클러스터 시작 부분이면 kReadCluster가 필요없고, 시작 부분이 아니면 kReadCluster가 필요하다. if(dwUpperFileSize<=(pstFileHandle->dwCurrentOffset+dwCopySize)) { // 빈 클러스터 검색 dwAllocatedClusterIndex = kFindFreeCluster(); if(dwAllocatedClusterIndex==FILESYSTEM_LASTCLUSTER) { break; } // 검색된 클러스터를 마지막 클러스터로 설정 if(kSetClusterLinkData(dwAllocatedClusterIndex,FILESYSTEM_LASTCLUSTER)==FALSE) { break; } } if(pstFileHandle->dwCurrentOffset%FILESYSTEM_CLUSTERSIZE!=0) { if(pstFileHandle->dwCurrentClusterIndex==FILESYSTEM_LASTCLUSTER) { if(kReadCluster(pstFileHandle->dwPreviousClusterIndex,gs_vbTempBuffer)==FALSE) { break; } } else { if(kReadCluster(pstFileHandle->dwCurrentClusterIndex,gs_vbTempBuffer)==FALSE) { break; } } } // 여러 클러스터에 걸쳐 있다면 현재 클러스터에서 남은 만큼 쓰고 다음 클러스터로 이동 kMemCpy(gs_vbTempBuffer+dwOffsetInCluster,(char*)pvBuffer+dwWriteCount,dwCopySize); // 임시 버퍼에 삽입된 값을 디스크에 씀 if(pstFileHandle->dwCurrentClusterIndex==FILESYSTEM_LASTCLUSTER) { if(kWriteCluster(pstFileHandle->dwPreviousClusterIndex,gs_vbTempBuffer)==FALSE) { break; } } else { if(kWriteCluster(pstFileHandle->dwCurrentClusterIndex,gs_vbTempBuffer)==FALSE) { break; } } // 쓴 바이트 수와 파일 포인터의 위치를 갱신 dwWriteCount+=dwCopySize; pstFileHandle->dwCurrentOffset+=dwCopySize; // 파일에 할당된 마지막 클러스터까지 Offset이 이동된 경우 이전에 할당된 클러스터와 연결시키기 if(dwOffsetInCluster+dwCopySize==FILESYSTEM_CLUSTERSIZE) { if(dwAllocatedClusterIndex!=-1) { if(kSetClusterLinkData(pstFileHandle->dwCurrentClusterIndex,dwAllocatedClusterIndex)==FALSE) { break; } pstFileHandle->dwPreviousClusterIndex = pstFileHandle->dwCurrentClusterIndex; pstFileHandle->dwCurrentClusterIndex = dwAllocatedClusterIndex; } else { if(kGetClusterLinkData(pstFileHandle->dwCurrentClusterIndex,&dwNextClusterIndex)==FALSE) { break; } // 클러스터 정보를 갱신 pstFileHandle->dwPreviousClusterIndex = pstFileHandle->dwCurrentClusterIndex; pstFileHandle->dwCurrentClusterIndex = dwNextClusterIndex; } } } //========================================================================================= // 파일 크기가 변했다면 루트 디렉터리에 있는 디렉터리 엔트리 정보를 갱신 //========================================================================================= if(pstFileHandle->dwFileSize<pstFileHandle->dwCurrentOffset) { pstFileHandle->dwFileSize=pstFileHandle->dwCurrentOffset; kUpdateDirectoryEntry(pstFileHandle); } // 동기화 kUnlock(&(gs_stFileSystemManager.stMutex)); return dwWriteCount; }