SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|

2017-06-14(Wed) 世にも奇妙なmicroSD

  先日、某サイトから、安価な16GBのmicroSDカードを購入した。さほど、厳格に用途を決めていたわけではないし、とりあえず工作中のmp3プレイヤにでも使ってみようと、Windows10マシンでFAT32フォーマットし、Linuxマシンからmp3ファイル、flacファイルを書き込み、mp3プレイヤに挿し込んだ。

  ……あれ? いきなり1曲目の途中から再生された……ような……早送りすると、2曲目以降は普通だが……あれ? 十数曲目以降が、1曲目の途中からの再生ばかりになってしまう。……なんだこれ?

  mp3プレイヤの側も工作中なこともあり、どっちが異常なのかわからない。とりあえず、microSDを抜いて、Linuxマシンに挿し込むと……スーパーブロックが壊れているって? ……なんだこれ?

  LinuxマシンでFATを扱ったことがマズいのかしらん? と、思い、ファイルの書き込みまでWindows10マシンで完結させても、やっぱりおかしな症状が出る。いろいろと試してみると、microSDカードを挿して、書いて、抜いて、挿すと、もう、書いた内容がおかしくなっている。これ、microSDカードがおかしいんやないか?

  以前に「抜くと元に戻るSDカード」を経験して以来「ここ一番にはSanDisk」を励行してきたのだが、それを外した途端にトラブるもんかねぇ。

  購入元に連絡したところ、即座に代品を送ってくれ、翌日には代品が手元に届くという素晴らしい対応だった。んが、不良品を返送する前に、再テストしてみたところ、なんと、代品にも同じ現象が出てしまった。どうも、ある程度の容量を書き込むと、microSDを抜き差しせずとも、先頭部分がブッ壊れるっぽい。

  と、ここでピンときた。以前に、見た目はxxGBなのに、実際にはxxGBの容量を持たない詐欺的なSDカードがあると聞いたことがある。改めて考えれば、一定の場所でループ構造にしている、つまり、上位ビットを捨てることで実現している、と考えるのが妥当なわけで、そうであれば今回の事象に合致する。

  というわけで、こんなプログラムを書いてみた。デバイスの先頭からシーケンシャル番号で領域を書きツブしながら、先頭部分の変化を監視する、というものだ。

 #!/usr/bin/env ruby
 
 # SD カードチェッカ
 
 class Integer
     def to_h
         sprintf('%d', self).to_s.reverse.scan(/.{1,3}/).join(',').reverse
     end
 end
 
 dev = ARGV[0]
 check_max = 8 * 1024 * 1024 * 1024                              # 8Gbytes
 puts('device = %s, check_max = %16s' % [dev, check_max.to_h])
 
 adr = 0; open(dev, 'w') {|fh|
 
     last_md5 = nil; while(adr < check_max)
         puts('%16s .. ' % adr.to_h)
 
         chunk = ''; (1024 * 1024 / 8).times {                   # 1Mbytes
             chunk << [adr >> 32, adr & 0xFFFFFFFF].pack('N*'); adr += 8
         }
         fh.write(chunk)
         fh.fsync
 
         system('dd if=%s of=/tmp/_sdcard_checker_ bs=4096 count=1 iflag=direct >/dev/null 2>&1' % dev)
         md5 = `md5sum /tmp/_sdcard_checker_`.split(/\s/)[0]
         puts('  %s %s' % [md5, last_md5])
         last_md5 and last_md5 != md5 and raise('Unmatch!')
         last_md5 = md5
     end
 }
 
 puts('%16s finished.' % adr.to_h)
 
 __END__

  イザ、実行ッ!

# sdcard_checker /dev/sdb
device = /dev/sdb, check_max =    8,589,934,592
               0 .. 
  fa9971f35ad33faaaf100800b4b85b8c 
       1,048,576 .. 
  fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       2,097,152 .. 
  fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       3,145,728 .. 
  fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       4,194,304 .. 
  fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
    :
    :
    :
   1,609,564,160 .. 
  fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
   1,610,612,736 .. 
  fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
    :
    :
    :

  ……んが、1.5GBくらい書いても先頭部分に異常が出ない。そんなバカな。もしかして、よく読まれる部分を避けるとか、そんな高度な詐欺行為を働いている?

  それならばと、プログラムを変更してみた。今度は、同じようにデバイスの先頭からシーケンシャル番号で領域を書きツブしながらも、先頭部分だけでなく、書きツブした部分をトビトビに監視する、というものだ。イザ、実行ッ!

 #!/usr/bin/env ruby
 
 # SD カードチェッカ 2
 
 class Integer
     def to_h
         sprintf('%d', self).to_s.reverse.scan(/.{1,3}/).join(',').reverse
     end
 end
 
 dev = ARGV[0]
 check_max = 8 * 1024 * 1024 * 1024                              # 8Gbytes
 #check_step = 128 * 1024 * 1024                                 # 128Mbytes
 check_step = 63 * 1024 * 1024                                   # 63Mbytes
 puts('device = %s, check_max = %16s' % [dev, check_max.to_h])
 
 adr = 0; open(dev, 'w') {|fh|
 
     check_md5s = {}; while(adr < check_max)
         puts('%16s .. ' % adr.to_h)
 
         chunk = ''; (1024 * 1024 / 8).times {                   # 1Mbytes
             chunk << [adr >> 32, adr & 0xFFFFFFFF].pack('N*'); adr += 8
         }
         fh.write(chunk)
         fh.fsync
 
         check_adr = 0; while(check_adr < adr)
             system('dd if=%s of=/tmp/_sdcard_checker_ bs=4096 count=1 skip=%d iflag=direct >/dev/null 2>&1' % [dev, check_adr >> 12])
             md5 = `md5sum /tmp/_sdcard_checker_`.split(/\s/)[0]
             check_md5s[check_adr] ||= md5
             puts('%16s %16s %s %s' % [check_adr.to_h, check_adr >> 12, md5, check_md5s[check_adr]])
             check_md5s[check_adr] != md5 and raise('Unmatch!')
             check_adr += check_step
         end
     end
 }
 
 puts('%16s finished.' % adr.to_h)
 
 __END__

  出た。128MBトビトビに監視していたら、256MBを書いた直後、書いたばかりの部分がブッ壊れる症状が出た。

# sdcard_checker2 /dev/sdb
device = /dev/sdb, check_max =    8,589,934,592
               0 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       1,048,576 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       2,097,152 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       3,145,728 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       4,194,304 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
    :
    :
    :
     267,386,880 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
     134,217,728            32768 01517d88da540a8eb5d44af02f122649 01517d88da540a8eb5d44af02f122649
     268,435,456 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
     134,217,728            32768 01517d88da540a8eb5d44af02f122649 01517d88da540a8eb5d44af02f122649
     268,435,456            65536 ba2930882b4da3d3ddd5b8697fc127d5 ba2930882b4da3d3ddd5b8697fc127d5
     269,484,032 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
     134,217,728            32768 01517d88da540a8eb5d44af02f122649 01517d88da540a8eb5d44af02f122649
     268,435,456            65536 5aa7b9d34285ac27f76b54f5ff4560fc ba2930882b4da3d3ddd5b8697fc127d5
/home/mitsu/develop/petit_tools/sdcard_checker:33:in `block in <main>': Unmatch! (RuntimeError)
	from /home/mitsu/develop/petit_tools/sdcard_checker:17:in `open'
	from /home/mitsu/develop/petit_tools/sdcard_checker:17:in `<main>'

  試しに。中途半端に63MBトビトビに監視してみても、256MBチョイを書いた直後、書いたばかりの部分がブッ壊れる症状が出た。

# sdcard_checker2 /dev/sdb
device = /dev/sdb, check_max =    8,589,934,592
               0 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       1,048,576 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       2,097,152 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       3,145,728 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
       4,194,304 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
    :
    :
    :
     329,252,864 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
      66,060,288            16128 2ed7a89c5a42bb4040bff4894be82bdb 2ed7a89c5a42bb4040bff4894be82bdb
     132,120,576            32256 919cfe23e7079f9077e4360ad127f628 919cfe23e7079f9077e4360ad127f628
     198,180,864            48384 c5d3ae3f1ac1b256bb20b044cc491719 c5d3ae3f1ac1b256bb20b044cc491719
     264,241,152            64512 dc83f09e6ee934dcc90677af587a629d dc83f09e6ee934dcc90677af587a629d
     330,301,440 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
      66,060,288            16128 2ed7a89c5a42bb4040bff4894be82bdb 2ed7a89c5a42bb4040bff4894be82bdb
     132,120,576            32256 919cfe23e7079f9077e4360ad127f628 919cfe23e7079f9077e4360ad127f628
     198,180,864            48384 c5d3ae3f1ac1b256bb20b044cc491719 c5d3ae3f1ac1b256bb20b044cc491719
     264,241,152            64512 dc83f09e6ee934dcc90677af587a629d dc83f09e6ee934dcc90677af587a629d
     330,301,440            80640 f005f81d5ee41aa397fc39db563060fe f005f81d5ee41aa397fc39db563060fe
     331,350,016 .. 
               0                0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
      66,060,288            16128 2ed7a89c5a42bb4040bff4894be82bdb 2ed7a89c5a42bb4040bff4894be82bdb
     132,120,576            32256 919cfe23e7079f9077e4360ad127f628 919cfe23e7079f9077e4360ad127f628
     198,180,864            48384 c5d3ae3f1ac1b256bb20b044cc491719 c5d3ae3f1ac1b256bb20b044cc491719
     264,241,152            64512 dc83f09e6ee934dcc90677af587a629d dc83f09e6ee934dcc90677af587a629d
     330,301,440            80640 d207d5474108dac6a8961a17d6f73fa2 f005f81d5ee41aa397fc39db563060fe
/home/mitsu/develop/petit_tools/sdcard_checker:33:in `block in <main>': Unmatch! (RuntimeError)
	from /home/mitsu/develop/petit_tools/sdcard_checker:17:in `open'
	from /home/mitsu/develop/petit_tools/sdcard_checker:17:in `<main>'

  この症状は、代品もまったく同じで、これはもう仕組まれたものと考えて間違いないだろう。要するに「容量偽装」というわけだ。まぁ、ウェアレベリングの仕組みに意図しない不具合があった、という見方もできなくはないけれど。無理に、先頭部分のみパーティションを確保して使う方法もあろうが、さすがに256MBじゃ、いまどき使い物にならんわな。

  しかし、悪意だと仮定して、ここまでしてクソ製品を売ることにどれほどの意義があるんだろう。これをカメラに挿して旅行に出かけた人がどれほど悲しいことになるか、考えたことはあるんだろうか。販売店にも迷惑がかかるし、そもそも貴重な資源をクソの山にすることに罪悪感はないのだろうか。いったい誰が得をするっていうんだ。

  ったく、時間の無駄だったぜッ!! などと悪態をつきながらも、ここ数日、心のどこかで、やや楽しみながらこういう試行をして記事にしてしまったオイラは、やや得をしたのかもしれんけど……。