디바이스 read한 뒤 파싱하면 이상한 값이...

you의 이미지

요즘 거의 매일 질문올리는 사람입니다. -_-;;
너그러이 봐주시고요 ^^

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

main()
{
  int fd, index=0, i, j, total=0;
  char buf[512];
  unsigned char data[4+1];

  fd=open("/dev/fd0", O_RDONLY);
  lseek(fd, 1024, SEEK_SET);
  read(fd, buf, 512);

  for(i=3; i>=0; i--)
    data[i]=*((unsigned char *)buf + index++);
  data[4]='\0';

  for(i=0, j=3; i<4; i++, j--){
    printf("%02x", data[i]);
    total+=data[i]<<8*j;
  }
  printf("\n%u\n", total);
}

위의 코드는
플로피를 ext2로 포맷한뒤에
그 첫번째 블록그룹에서 수퍼블록의 일부를 read하고
그 첫번째 필드(4바이트) - inode의 총수- 를 파싱해서 hex와 dec로 출력합니다.
테스트 결과 잘 작동합니다.
(inode의 총 수가 144(?)였덩가? hex로는 0xb8입니다.)

근데 문제는
이걸 실제코드에 적용했을때입니다.
여기서 file system unique id 같은 출력하는 부분은 무시하시구요...
(다른 FS라서리...)

int parse_dump(char *dev, char *file)
{
  char buf[BUFSIZE];
  int fdin, n;
  FILE *fpout;

  if((fdin=open(dev, O_RDONLY))<0){
    fprintf(stderr, "open error - read\n");
    return(1);
  }

  if((fpout=fopen(file, "w"))==NULL){
    fprintf(stderr, "fopen  error - write\n");
    return(2);
  } 

  if((n=read(fdin, buf, BUFSIZE))<0){
    fprintf(stderr, "read error\n");
    return 10;
  }

  fprintf(fpout, "file system unique id : 0x");
  parse(buf, sizeof(long), fpout);

  fprintf(fpout, "number of blocks in this file system : 0x");
  parse(buf, sizeof(long), fpout);

중략...

  close(fdin);
  fclose(fpout);

  return 0;
}

void parse(void *Data, int nBytes, FILE *fpout)
{
  int i, j, index=0, total=0x0;
  unsigned char Buffer[0x8 + 1];

  for(i=nBytes-1; i>=0; i--)
    Buffer[i]=*((unsigned char *)Data + index++);
  Buffer[nBytes]='\0';

  for(i=0, j=nBytes-1; i<nBytes; i++, j--){
    fprintf(fpout, "%02x", Buffer[i]);
    total+=Buffer[i]<<8*j;
  }
  fprintf(fpout, "\t%u\n", total);
}

이렇게 해서 플로피의 수퍼블록을 읽어들이면
이상한 값이 파싱됩니다.

Quote:
file system unique id : 0x30303030 808464432
number of blocks in this file system : 0x30303030 808464432
number of free blocks in this file system : 0x20384220 540557856
logical block size, bytes : 0x30203030 807415856
number of blocks in a block group : 0x2030 8240

첫번째 필드인 inode 총수 - 위에는 unique id로 되있는데 그건 다른 FS라서 그런거구요, 테스트는 ext2로 했으므로 inode총수입니다 - 는 0x30303030(?)인가? 로 되고
나머지 필드들도 거의 이값 비슷하게 됩니다.
위의 테스트 코드에서는 잘되는데
왜 여기선 안되는지 도저히 모르겠네요
아.
그리고 read()한 다음에 함수-parse()- 호출해서 offset이 계속 그대로 있으므로 모든 필드가 같은 값일거라 생각해서
수정해봤습니다.

void parse(int fdin, int nBytes, FILE *fpout)
{
  int i, j, index=0, total=0x0;
  unsigned char Buffer[0x8 + 1], Data[0x8 + 1];

  if(read(fdin, Data, nBytes)<0){
    fprintf(stderr, "read error\n");
    exit(-1);
  }

  for(i=nBytes-1; i>=0; i--)
    Buffer[i]=*((unsigned char *)Data + index++);
  Buffer[nBytes]='\0';

  for(i=0, j=nBytes-1; i<nBytes; i++, j--){
    fprintf(fpout, "%02x", Buffer[i]);
    total+=Buffer[i]<<8*j;
  }
  fprintf(fpout, "\t%u\n", total);
}

read()를 함수내에서 계속 호출하므로 offset은 계속 전진하지 않나요?
그럼에도 결과는 별 차이 없었습니다.
아무래도 다른 문제가 있는것 같은데 도저히 모르겠네요 ㅠㅠ
허접한 소스지만
잘 부탁드립니다.

kslee80의 이미지

/*
 * Structure of the super block
 */
struct ext2_super_block {
    __u32   s_inodes_count;     /* Inodes count */
    __u32   s_blocks_count;     /* Blocks count */
    __u32   s_r_blocks_count;   /* Reserved blocks count */
    __u32   s_free_blocks_count;    /* Free blocks count */
    __u32   s_free_inodes_count;    /* Free inodes count */
    __u32   s_first_data_block; /* First Data Block */
    __u32   s_log_block_size;   /* Block size */
    __s32   s_log_frag_size;    /* Fragment size */
    __u32   s_blocks_per_group; /* # Blocks per group */
    __u32   s_frags_per_group;  /* # Fragments per group */
    __u32   s_inodes_per_group; /* # Inodes per group */
    __u32   s_mtime;        /* Mount time */
    __u32   s_wtime;        /* Write time */
    __u16   s_mnt_count;        /* Mount count */
    __s16   s_max_mnt_count;    /* Maximal mount count */
    __u16   s_magic;        /* Magic signature */
    __u16   s_state;        /* File system state */
    __u16   s_errors;       /* Behaviour when detecting errors */
    __u16   s_minor_rev_level;  /* minor revision level */
    __u32   s_lastcheck;        /* time of last check */
    __u32   s_checkinterval;    /* max. time between checks */
    __u32   s_creator_os;       /* OS */
    __u32   s_rev_level;        /* Revision level */
    __u16   s_def_resuid;       /* Default uid for reserved blocks */
    __u16   s_def_resgid;       /* Default gid for reserved blocks */
    /*
     * These fields are for EXT2_DYNAMIC_REV superblocks only.
     *
     * Note: the difference between the compatible feature set and
     * the incompatible feature set is that if there is a bit set
     * in the incompatible feature set that the kernel doesn't
     * know about, it should refuse to mount the filesystem.
     *
     * e2fsck's requirements are more strict; if it doesn't know
     * about a feature in either the compatible or incompatible
     * feature set, it must abort and not try to meddle with
     * things it doesn't understand...
     */
    __u32   s_first_ino;        /* First non-reserved inode */
    __u16   s_inode_size;       /* size of inode structure */
    __u16   s_block_group_nr;   /* block group # of this superblock */
    __u32   s_feature_compat;   /* compatible feature set */
    __u32   s_feature_incompat;     /* incompatible feature set */
    __u32   s_feature_ro_compat;    /* readonly-compatible feature set */
    __u8    s_uuid[16];     /* 128-bit uuid for volume */
    char    s_volume_name[16];  /* volume name */
    char    s_last_mounted[64];     /* directory where last mounted */
    __u32   s_algorithm_usage_bitmap; /* For compression */
    /*
     * Performance hints.  Directory preallocation should only
     * happen if the EXT2_COMPAT_PREALLOC flag is on.
     */
    __u8    s_prealloc_blocks;  /* Nr of blocks to try to preallocate*/
    __u8    s_prealloc_dir_blocks;  /* Nr to preallocate for dirs */
    __u16   s_padding1;
    __u32   s_reserved[204];    /* Padding to the end of the block */
};

이 코드를 보시면 알겠지만, EXT2 의 경우에는 SuperBlock 의 첫번째 필드가
Inode Count 이지요.

struct reiserfs_super_block
{
  __u32 s_block_count;
  __u32 s_free_blocks;                  /* free blocks count    */
  __u32 s_root_block;               /* root block number    */
  __u32 s_journal_block;            /* journal block number    */
  __u32 s_journal_dev;              /* journal device number  */

  /* Since journal size is currently a #define in a header file, if
  ** someone creates a disk with a 16MB journal and moves it to a
  ** system with 32MB journal default, they will overflow their journal
  ** when they mount the disk.  s_orig_journal_size, plus some checks
  ** while mounting (inside journal_init) prevent that from happening
  */

                /* great comment Chris. Thanks.  -Hans */

  __u32 s_orig_journal_size;
  __u32 s_journal_trans_max ;           /* max number of blocks in a transaction.  */
  __u32 s_journal_block_count ;         /* total size of the journal. can change over time  */
  __u32 s_journal_max_batch ;           /* max number of blocks to batch into a trans */
  __u32 s_journal_max_commit_age ;      /* in seconds, how old can an async commit be */
  __u32 s_journal_max_trans_age ;       /* in seconds, how old can a transaction be */
  __u16 s_blocksize;                    /* block size           */
  __u16 s_oid_maxsize;          /* max size of object id array, see get_objectid() commentary  */
  __u16 s_oid_cursize;          /* current size of object id array */
  __u16 s_state;                        /* valid or error       */
  char s_magic[12];                     /* reiserfs magic string indicates that file system is reiserfs */
  __u32 s_hash_function_code;       /* indicate, what hash function is being use to sort names in a directory*/
  __u16 s_tree_height;                  /* height of disk tree */
  __u16 s_bmap_nr;                      /* amount of bitmap blocks needed to address each block of file system */
  __u16 s_version;      /* I'd prefer it if this was a string,
                                   something like "3.6.4", and maybe
                                   16 bytes long mostly unused. We
                                   don't need to save bytes in the
                                   superblock. -Hans */
  __u16 s_reserved;
  __u32 s_inode_generation;
  __u32 s_flags;               /* Right now used only by inode-attributes, if enabled */
  unsigned char s_uuid[16];            /* filesystem unique identifier */
  unsigned char s_label[16];           /* filesystem volume label */
  char s_unused[88] ;                  /* zero filled by mkreiserfs and
                                        * reiserfs_convert_objectid_map_v1()
                                        * so any additions must be updated
                                        * there as well. */
} __attribute__ ((__packed__));

이건 ReiserFS 의 SuperBlock Structure 입니다. 보시다시피,
첫번째 4 Byte 가 Inode Count 가 아닌, Block Count 입니다.

파일시스템이 틀린 경우에 적용되질 않는다고 하셨기에,
한번 다른 파일시스템의 SuperBlock 를 본 겁니다만,
이런식으로 SuperBlock Structure 가 파일시스템마다 틀리기 때문에,
다른 파일시스템에 그대로 적용하기는 힘들 겁니다.
Portable 하게 하기 위해서는 차라리 저 Structure 의 필드값을 사용하는게
나을듯 싶습니다.

PS) 저 코드들은 다 커널소스상에 include/linux/ 안에 있습니다.
EXT2 SuperBlock Structure 는 ext2_fs.h 안에,
ReiserFS SuperBlock Structure 는 reiserfs_fs_sb.h 안에 있습니다.
리눅스상에서 지원하는 다른 파일시스템 역시 비슷한 식으로
Structure 를 만들어서 접근할테니, 커널소스상에 헤더들을 보면
많은 도움이 될듯 싶네요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.