본문 바로가기
코스웨어/12년 내장형하드웨어

[ 임베디드 파일 시스템] 데이터 영역 실습

by 알 수 없는 사용자 2013. 1. 9.
728x90
반응형

실습전에 실습용 디스크의 시작이 MBR인지 BR인지 체크하시기 바랍니다.

책의 예제에서는 BR이 디스크의 0번섹터에 잇다는 가정하에 코딩된것이고

저의 USB는 MBR이 존재하여 BR로 점프하는 코드가 삽입되어 있습니다.


그리고 책의 예제에서 동적할당을 받는데, free()함수가 없습니다. 추가했습니다.


FAT_exam2.c

FAT_exam2.ex_


#include <stdio.h>
#include <windows.h>
#include <stdlib.h>

#define U8  unsigned char
#define S8  char
#define U16 unsigned short
#define U32  unsigned int
#define  U64  unsigned __int64

#pragma pack (1)
typedef struct _FAT16_BPB_struct
{
  U8  JmpBoot[3];
  U8  OEMName[8];
  U16  BytsPerSec;
  U8  SecPerClus;
  U16 RsvdSecCnt;
  U8  NumFATs;
  U16  RootEntCnt;
  U16  TotSec16;
  U8  Media;
  U16  FATs16;
  U16  SecPerTrk;
  U16  NumHeads;
  U32  HiddSec;
  U32  TotSec32;
  //------------
  U8  DriverNumber;
  U8  Reserved1;
  U8  BootSignal;
  U32  VolumID;
  U8  VolumeLabel[11];
  U8  FileSysType[8];
  //------------ FAT16
  U8  BootCodeArea[448];
  U16  Signature;
}FAT16_BPB;

typedef struct _DIR_struct
{
  U8  Name[11];
  U8  Attr;
  U8  NTRes;
  U8  CrtTimeTenth;
  U16  CrtTime;
  U16  CrtDate;
  U16  LstAccDate;
  U16  FstClusHi;
  U16  WriteTime;
  U16  WriteDate;
  U16  FstClusLow;
  U32  FileSize;
}DirEntry;

typedef struct _LONG_DIR_struct
{
  U8  Order;
  U8  Name1[10];
  U8  Attr;
  U8  Type;
  U8  chksum;
  U8  Name2[12];
  U16  FstClusLo;
  U8  Name3[4];
}LongDirEntry;
#pragma pack ()

typedef struct _VOL_struct
{
  U32 Drive;
  U32  VolBeginSec;
  U32  FirstDataSec;
  U32  RootDirSec;
  U32 RootEntCnt;
  U32 RootDirSecCnt;
  U32 FATSize;
  U32 FATStartSec;
  U32  TotalClusCnt;
  U32 TotalSec;
  U32 DataSecSize;
  U32  ClusterSize;
  U32  SecPerClus;
}VolStruct;

void print_longName(LongDirEntry *pLongDir, U32 EntryNum);
U32  show_dir(DirEntry *pDir);
U32 HDD_read(U8 drv, U32 SecAddr, U32 blocks, U8 *buf);
U32 Get_BPB_info(FAT16_BPB *BPB, VolStruct *pVol);
void HexDump(U8 *addr, U32 len);

VolStruct gVol;

int main(void)
{
  U8 buf[512];
  U8 *pRootBuf;
  U32 MyBr;

  gVol.Drive = 0x1;
  gVol.VolBeginSec = 0x0;

  HDD_read(gVol.Drive, gVol.VolBeginSec, 1, buf);    // 나의 USB에는 MBR이 있음
  MyBr = *((unsigned int *)(buf + 446 + 8));
  
  HDD_read(gVol.Drive, MyBr , 1, buf);        // 그래서 BR부분을 한번 더 읽어야 함
    
  if(0 == Get_BPB_info((FAT16_BPB *)buf, &gVol))    // FAT16이 아닐경우 0이 돌아오면서 종료
  {
    printf("It is not FAT16 File System \n");

    return 1;
  }
      
  pRootBuf = (U8 *)malloc(gVol.RootDirSecCnt * 512);  // 동적할당을 받는다
  
  if(0 == HDD_read(gVol.Drive, MyBr + gVol.RootDirSec, gVol.RootDirSecCnt, pRootBuf))
  {
    printf("Root Dir Read Failed\n");
    free(pRootBuf);

    return 1;
  }
    
  show_dir((DirEntry *)pRootBuf);

  free(pRootBuf);

  return 0;
}

U32  show_dir(DirEntry *pDir)
{
  U32 i;
  U32 y;
  U32 LongEntryEn = 0;

  for(i = 0;i <= gVol.RootEntCnt;i++)
  {
    switch( (U8)pDir[i].Name[0])
    {
      case 0x00:
        return 1;
      case 0xE5:
        continue;
    }

    if(0x0== pDir[i].Attr)
    {
      LongEntryEn = 1;
      continue;
    }

    printf("--------Entry Number %d--------\n", i);

    if(0x10 == pDir[i].Attr)
    {
      printf("Directory Name : ");
    }
    else
    {
      printf("File Name : ");
    }

    if(1 == LongEntryEn)
    {
      print_longName((LongDirEntry *)pDir, i-1);
      LongEntryEn = 0;
    }
    else
    {
      for(y = 0;y < 11;y++)
      {
        printf("%c", pDir[i].Name[y]);
      }
    }
    printf("\n");
    printf("File Size                : %d\n", pDir[i].FileSize);
    printf("Start Cluster            : %d\n", (pDir[i].FstClusLow | pDir[i].FstClusHi << 16) );
  }

  return 1;
}

void print_longName(LongDirEntry *pLongDir, U32 EntryNum)
{
  wchar_t filename[512];
  char final[512];
  U32  nameOffset = 0;

  do
  {
    memcpy(&filename[nameOffset], pLongDir[EntryNum].Name1, 10);
    nameOffset = nameOffset + 5;
    memcpy(&filename[nameOffset], pLongDir[EntryNum].Name2, 12);
    nameOffset = nameOffset + 6;
    memcpy(&filename[nameOffset], pLongDir[EntryNum].Name3, 4);
    nameOffset = nameOffset + 2;
  }while0 == (pLongDir[EntryNum--].Order & 0x40) );

  filename[nameOffset] = 0x0000;

  wcstombs(final, filename, 512);

  printf("%s", final);

  return ;
}

U32 Get_BPB_info(FAT16_BPB *BPB, VolStruct *pVol)
{
  if0 == BPB->RootEntCnt || 0xAA55 != BPB->Signature )
  {
    return 0;
  }

  if0 != BPB->TotSec16 )
  {
    pVol->TotalSec = BPB->TotSec16;
  }
  else
  {
    pVol->TotalSec = BPB->TotSec32;
  }

  pVol->FATSize = BPB->FATs16;                // FAT영역의 섹터 수

  pVol->FATStartSec = pVol->VolBeginSec + BPB->RsvdSecCnt;  // 루트 디렉토리의 Directory Entry 개수

  pVol->RootEntCnt = BPB->RootEntCnt;              // 루트디렉토리 시작섹터

  pVol->RootDirSec = pVol->VolBeginSec + BPB->RsvdSecCnt + (BPB->NumFATs * BPB->FATs16);

  pVol->RootDirSecCnt = ((BPB->RootEntCnt * 32) + (BPB->BytsPerSec - 1)) / BPB->BytsPerSec;  // 루트디렉토리의 섹터수

  pVol->FirstDataSec = pVol->VolBeginSec + BPB->RsvdSecCnt + (BPB->NumFATs * pVol->FATSize) + pVol->RootDirSecCnt;  // 첫번째 데이터 섹터를 구하는 코드

  pVol->DataSecSize = pVol->TotalSec - (BPB->RsvdSecCnt + (BPB->NumFATs * pVol->FATSize) + pVol->RootDirSecCnt);    // 데이터 영역의 섹터 수

  pVol->TotalClusCnt = pVol->DataSecSize / BPB->SecPerClus;  // 볼륨의 총 클러스터 개수

  pVol->ClusterSize = BPB->SecPerClus * BPB->BytsPerSec;    // 클러스터의 크기

  pVol->SecPerClus = BPB->SecPerClus;              // 클러스터가 몇 개의 섹터를 차지하는가

  return 1;
}

U32 HDD_read(U8 drv, U32 SecAddr, U32 blocks, U8* buf)
{
  U32 ret;
  U32 ldistanceLow;
  U32 ldistanceHigh;
  U32 dwpointer;
  U32 bytestoread;
  U32 numread;
  char cur_drv[100];
  HANDLE g_hDevice;

  sprintf(cur_drv,"\\\\.\\physicalDrive%d",(U32)drv);
  
  g_hDevice = CreateFile(cur_drv, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);  // 하드드라이버 연다
  
  if(g_hDevice == INVALID_HANDLE_VALUE)  // 에러 체크
  {
    return 0;
  }

  ldistanceLow = SecAddr << 9;
  ldistanceHigh = SecAddr >> (32 - 9);
  dwpointer = SetFilePointer(g_hDevice, ldistanceLow, (long *)&ldistanceHigh, FILE_BEGIN);  // 파일포인터를 이동시킨다 (제일 처음으로)
                                                // FILE_BEGIN 제일 처음으로 이동 (win32표준 :: lseek)

  if(0xFFFFFFFF != dwpointer)    // -1인지 체크
  {
    bytestoread = blocks * 512;
    ret = ReadFile(g_hDevice, buf, bytestoread, (unsigned long *)&numread, NULL);

    if(ret)
    {
      ret = 1;
    }
    else
    {
      ret = 0;
    }
  }

  CloseHandle(g_hDevice);
  return ret;
}

void HexDump(U8 *addr, U32 len)
{
  U8 *s = addr;
  U8 *endPtr = (U8 *)((U32)addr+len);
  U32 i;
  U32 remainder = len%16;

  printf("\n  Offset                     Hex Value                          Ascii value\n");

  while(s+16 <= endPtr)
  {
    printf("0x%08LX  ", (long)(s-addr));

    for(i = 0;i < 16;i++)
    {
      printf("%02X ", s[i]);
    }
    printf(" ");

    for(i = 0;i < 16;i++)
    {
      if(s[i] >= 32 && s[i] <= 125)
      {
        printf("%c", s[i]);
      }
      else
      {
        printf(".");
      }
    }
    s = s + 16;
    printf("\n");
  }

  if(remainder)
  {
    printf("0x08LX ", (long)(s-addr));

    for(i = 0;i < remainder;i++)
    {
      printf("%02X ", s[i]);
    }
    for(i = 0;i < (16-remainder);i++)
    {
      printf("  ");
    }

    printf(" ");
    for(i = 0;i < remainder;i++)
    {
      if(s[i] >= 32 && s[i] <= 125)
      {
        printf("%c", s[i]);
      }
      else
      {
        printf(".");
      }
    }
    for(i = 0;i < (16 - remainder);i++)
    {
      printf(" ");
    }
    printf("\n");
  }
  
  return ;
}


728x90