虎之助の徒然記

マイナポイントの申込をしたが、現在、申込可能なサービスが少ない!

 本日7月1日からマイナポイントの申込が開始されました。早速、申込を行いました。

f:id:toranosuke_blog:20200701171246j:plain

1. マイナポイントの申込

 初日ということもあり、マイナポイントのホームページへの少しアクセスが集中して反応が鈍いですが、特に問題なく申請できました。

 パソコンからの申請でしたので、必要なものは、ICカードリーダ、マイナンバーカード(+4桁のPINコード)は最低揃えないといけないですが、カードリーダ機能が付いたスマホならアプリをインストールして申請できるみたいです。

 自分の分はPayPay、母親の分はpasmoと紐付けしました。

2. 対応サービス

 初日時点では、申込ができる決済サービスは、ホームページで公表している登録事業者より、かなり少ないです(付録1)。

 メジャーな電子マネー・QRコードは申込可能ですが、クレジットカードへの対応が3つのみで、寂しい限りです。主なものを適当にピックアップすると、

  • 電子マネー:楽天Edy、WAON、 nanaco、PASMO、Suica(×JRE POINT)
  • QRコード:PayPay、LINE Pay、楽天ペイ、d払い、au PAY、FamiPay、メルペイ
  • クレジットカード:dカード、au PAYカード、楽天カード

 一覧は総務省のホームページから確認できますが、ポイントの付与タイミングなどの情報を含む一覧はマイナポイントの申請ページからしか確認できないようです(ログインにマイナンバーカードが必要)。

 付与タイミングが分かる画面のスクショを付録2につけておきます。ご参考まで(一回申請してしまうと、この一覧画面に入れなくなります)。

3. PayPayの申し込みのやり直し

 PayPayには、「PayPayチャージ特典」と「PayPay決済特典」があります。何も考えずチャージ特典を選んでしまいましたが、考えてみると、もっぱらクレジットカード引き落としで利用して、チャージでは利用していないので、決済特典に申請し直しました。当日中なら取り消し(と再申請)が可能なようです(トラブらないと信じたい)。

 他のサービスにも、いろいろと罠があるかもしれませんので、よく確認した方が良いでしょう。

 PayPay決済特典の申請画面を付録につけておきます。

4. おわりに

 マイナポイントは、一般にはまだあまり知られていないような気がします。私自身は、マイナンバーカードの電子署名の更新手続きで市役所に行ったときに、マイナポイントの存在を知りました。サービス開始の9月頃になると、マイナポイントの宣伝をもう少しするのでしょうか。

 2020年9月1日からサービス開始ですが、予約(マイキーID設定)(?~2020/8月迄?)、申込(2020/7/1-2021/3月)、サービス期間(2020/9/1~2021/3/31)で3段階に分けているのは、謎です。マイナンバーカード申請に係る自治体負荷を分散させるためなのかもしれませんが、非常に分かりにくいです。

 既にマイナンバーカードを作った人は、楽に5000円のポイントを得られますが、持っていない多くの人は、マイナンバーカードの作成が面倒で諦めそうですよね。多少は、マイナンバーカードの普及に寄与するかもしれませんが、デジタルデバイドの拡大になる施策という気がします。

 発行するマイナポイント総額が、話題の電通さまの外郭団体への事業委託費と大差なかったりすると、何のための事業なのかという気がしますが、どうなることやら。

 マイナポイント事業で交付枚数が飛躍的に増えることは望めないと思います。マイナンバーカードの交付枚数2000万枚、5割利用とすると、500億円分のマイナポイントの事業の委託費が350億円。2000万カードが申請したとしてもポイントはせいぜい1000億円。自治体の対応コストも考えると、配布ポイントよりも、運営コストの方が高い事業なのかもしれません。

 総務省の事業も電通に再委託 ポイント還元事業めぐり:東京新聞 TOKYO Web

 「まだマイナンバーカード持たないの」1人5000円分のポイント還元、7月からの申請は大混乱?(税理士ドットコム) - Yahoo!ニュース

(2020/7/1)

付録1. 7月1日時点の登録サービス

登録されているサービスの全てが、現時点で申込可能というわけではありません。

https://mynumbercard.point.soumu.go.jp/service_search/ f:id:toranosuke_blog:20200701134520j:plainf:id:toranosuke_blog:20200701134539j:plain

付録2. 7月1日時点で申込可能サービス

https://id.mykey.soumu.go.jp/mypage/MKRAS010/(マイナンバーカードが必要)の「マイナポイント」→「申込」から参照可能

● 電子マネー

f:id:toranosuke_blog:20200701142345j:plain f:id:toranosuke_blog:20200701142358j:plain

● QRコード

f:id:toranosuke_blog:20200701142402j:plain

f:id:toranosuke_blog:20200701142418j:plain

● プリペイドカード

f:id:toranosuke_blog:20200701142431j:plain

● クレジットカード

f:id:toranosuke_blog:20200701142444j:plain

● デビットカード

f:id:toranosuke_blog:20200701142516j:plain

● その他

f:id:toranosuke_blog:20200701142537j:plain

付録3. PayPay決済特典の申請画面

 「決済サービスID」と「セキュリティカード1」は、PayPayアプリで調べることができます。私の場合、決済サービスIDは電話番号でした。

f:id:toranosuke_blog:20200701160350j:plain

セブンイレブンアプリ・イトーヨーカドーアプリでログインできない原因は、アカウントが古すぎたこと!

 セブンイレブンアプリ・イトーヨーカドーアプリでログインできない原因がやっと分かりました。

 原因は、あまりにも古いアカウントだったこと。一旦、omni7のホームページにログインして、会員規約に同意、個人情報の確認・更新をすれば、セブンイレブンアプリも、イトーヨーカドーアプリもトラブルなく、ログインできました。

1. アプリにログインできない

 イトーヨーカドーで買い物する際に店員さんに「イトーヨーカドーアプリありますか?」と言われるので、アプリを入れたのですが、ログインできません(涙)。セブンイレブンアプリも同じです。

 セブンイレブンアプリ・イトーヨーカドーアプリの登録には、7iD会員が必要です。

 随分と昔にセブンネットショッピングのために作ったアカウントがありましたが、それが現在は7iD会員にも継承されているとのこと。

 実際、私のセブンネットショッピングに登録したID(メールアドレス)を7iDとして認識しているようでした(新規登録しようとすると、既に登録されていると言われる)。

 古いアカウントだったので、ログインできない原因は、パスワード忘れだろうと、パスワードを更新しましたが、それでもダメ。

 一通り、ネットで検索して原因究明を試みたのですが、解決しませんでした。

 ID・パスワード、アプリのバグ、サーバー側の問題ということではなさそうでした。

2. omni7のホームページにログインしたら解決

 そこで、ブラウザでomni7のホームページでログインしてみました。

 7iDアカウントでログインすると、会員規約への同意や個人情報の確認・更新を求められました。数年ぶりのログインです(たぶん、2012年10月にパスワードを変更して以来なので、6年ぶり)。

 一旦、同意や情報の更新を済ませた後に、セブンイレブンアプリ・イトーヨーカドーアプリに同じ7iDでログインすると、無事にログインすることができました。

f:id:toranosuke_blog:20190201172056p:plain:w250
初ログイン時のメッセージ(セブンイレブンアプリ)

3. 最後に

 ずっと使っていなかったアカウントだったので、新しくなった会員規約に同意していなかったことが、ログインできなかった原因です(たぶん)。

 セブンイレブンアプリ・イトーヨーカドーアプリはログインできないトラブルが多いようですが、以前にセブン&アイ関連のアカウントを作ったことがある方は、omni7のホームページでのでログインを試してはいかがでしょうか?

 ちなみに、omni7のホームページのところに出てくるアイコンは、以下です。

f:id:toranosuke_blog:20190201180611j:plain:w500

 左から、「セブンネットショッピング」「西武・そごう」「イトーヨーカドー」「アカチャンホンポ」「Loft」「セブンイレブンのネットサービス」「デニーズ」「omniモール」。いつのまにか、7iD会員になっているかもしれません。

 ご参考になれば幸いです。

(2019/2/1)



nanacoギフト 10,000円



nanacoギフト 5,000円



nanacoギフト 3,000円

3つのタブレットスタンドを比較した(Anker、Amazon、サンワサプライ)

Anker・Amazon・サンワサプライのタブレットスタンドの3機種についてまとめました。

1. 3つのタブレットスタンド

 いままで購入したタブレットスタンドは、3機種。Anker、Amazonベーシック、サンワサプライのタブレット用のスタンドです。

● Ankerタブレット用スタンド (2014年11月購入)


Ankerタブレット用スタンド

最大負荷5kg
Amazon (販売終了)



Ankerの後継機は、こちら

● Amazonベーシックタブレットスタンド(2018年9月購入)


Amazonベーシック タブレットスタンド
マルチアングル ポータブルスタンド(タブレット、キンドル、スマートフォン用)

99.1mm×86.4mm×21.6mm、166g、最大負荷4.99kg


● サンワサプライ iPadスタンド(2014年11月購入)


サンワサプライ iPadスタンド
PDA-STN7W


ポリカーボネート、102mm×84mm×22mm、74g



製品情報

2. 外観と重さ

f:id:toranosuke_blog:20190131203023j:plain:w500
f:id:toranosuke_blog:20190131203034j:plain:w500
黒がAnker、グレーがAmazon、白がサンワサプライ。

基本的な構造、大きさはほぼ同じ。折りたためば小さくなる。素材は、Ankerはアルミ、Amazonは亜鉛合金、サンワサプライはプラスチックで、サンワサプライは軽い。支えの部分は、いずれもプラスチック。Amazonは、ボディ部分に空間があるので、放熱にもよいのかも。

f:id:toranosuke_blog:20190131203117j:plain:w300 f:id:toranosuke_blog:20190131203011j:plain:w300

FireHD7 (9.6mm)、FireHD8 (9.7mm)、MediaPad X1 7.0 (7.2mm+カバー)を載せた。
サンワサプライは、約1cmのタブレット厚だと、溝におさまらない(iPadはOK)。

f:id:toranosuke_blog:20190131203045j:plain:w200 f:id:toranosuke_blog:20190131203056j:plain:w200 f:id:toranosuke_blog:20190131203106j:plain:w200
Anker Amazon サンワサプライ
179.2g 165.8g 73.7g

 本体が金属製のAnker、Amazonは170g~180g、サンワサプライは、74gです。机に置くのであれば、サンワサプライだと軽く、重いAnkerやAmazonの方が安定感があります。

3. 最後に

 今持っているものの中では、Anker・Amazonは、同じような使い勝手ですが、Ankerの方がお気に入りです。Amazonのシルバーは安っぽく感じます。黒だったらどちらでもよいのかも。サンワサプライは、軽いので持ち運びにはいいのかもしれませんが、据え置きで使うなら重い方が安定します。

 次に購入するとしたら、重く安定し、安いAmazonのブラックです。

(2019/1/31)

気になるタブレットスタンド
  • 楽天ROOMに気になるタブレットスタンド(と急速充電器)についてまとめてます(随時更新)。
その他の製品

 同様の構造のタブレット用スタンドには、他にUGREEN、JEDirect、DAMENG、Tecbossの製品があります。

  • UGREEN
    • ABS樹脂製、107mm×120mm、40.8g、最大負荷550g
    • 40gと軽量で、最大負荷が550gと小さい。華奢か?
    • スマホ用の製品もあるので、要注意(最大負荷350g)。
  • JEDirect
    • アルミ素材、100mm×90mm×40mm、198g、最大負荷6kg。
  • DAMENG
    • ABS素材、120mm×78mm×14mm、28g、最大負荷5kg。
    • 超軽量!(だけど、華奢じゃないのかな?)
  • Tecboss
    • アルミ素材、70mm×107mm、90g、最大負荷は不明。
    • 幅が70mmと短い(安定性が悪いかも)

 筆者が知っているブランドは、UGREENだけで、他はこれまで聞いたことはありません。UGREEN製品も、持ってはいませんが。

10ポートのUSB充電器 Anker PowerPort10 を買った

 久しぶりの記事。小ネタです。

1. Ankerの10ポートUSB充電器を買いました

 困ったもので、USB給電が必要なガジェットが溢れています。ポート不足とケーブルがぐちゃぐちゃなので、ポート数が多いUSB充電器を購入し整理することにしました。

 調べたところ、ポート数としては、10ポートが最大のようで、この中から、Ankerの10ポートのUSB充電器(PowerPort10)を購入しました。


Anker PowerPort 10
(60W 10ポート USB急速充電器)


【PSE認証済/PowerIQ搭載】
iPhone XS/XS Max/XR, iPad, Galaxy S9 / S9+ 等対応 (ブラック)



このUSB充電器の特徴は、

  • Anker製品!
  • 各ポート最大2.4AまでOK
  • 全体で60Wまで
  • 急速充電可能

f:id:toranosuke_blog:20190131144010j:plain
製品ホームページより

 実物を見ると、写真で想像していたものよりかなり小型でした。旅行に10台もデバイスを持っていくことはないので、出番はありませんが、旅行鞄にポイっと入れられる大きさです(本体よりもAC電源ケーブルの方がジャマかも)。

 1Aのポートが混在しないのも、良い点です。全部が2A給電となると、2A×5V×10=100W となり、60Wオーバーですが、10台もあると一度にフルに給電する必要もないでしょうし、必要であっても、適当に内蔵回路で調整しているのでしょう。

 Anker製品は、基本的にコストパフォーマンスは悪くはないと思います。

 今回の製品も、最安値の製品よりも1000円以上高くなりますが、このぐらいの差なら、充電回りということもあり、安心できるAnker製品を購入しました(Apple製品は、電源の安定性にうるさい)。

2. 実物は意外と小さい

f:id:toranosuke_blog:20190131113706j:plain:w400
10ポートのUSB充電器
f:id:toranosuke_blog:20190131113734j:plain:w400
タバコよりも一回り大きいぐらいでコンパクト
f:id:toranosuke_blog:20190131113906j:plain:w400
付属品はケーブルと簡単なマニュアルなど

 設置後の写真は、、、整理した後でも、悲惨な状態なので、省略します(笑)。

3. 最後に

 現在、スマホ1台、ファブレット1台、タブレット2台、Amazon Echo1台、携帯ラジオ、電子タバコ(glo)1台の計7台をつなげていますが、特に問題はありません。今のところ、満足しています。

(2019/1/31)

AnkerのUSB充電器

 Ankerの10ポート、6ポート、4ポートの製品。

 4ポートの製品はプラグ式で、旅行などにも持っていって邪魔にならない大きさです。

他社のUSB充電器(10ポート)

タブレット・スマホのスタンドと一体型の充電ステーション。
魅力的だけど、実際には、スマホ・タブレット以外にもいろんなものつなげるからなぁ~。


サンワサプライは高すぎます。それ以外は、筆者は聞いたことがないブランドです。

気になる急速充電器

 楽天ROOMに気になる急速充電器について、リストしています(随時更新)。

【Python】numpy 整数の演算結果が float64 に。摩訶不思議なデータ型変換ルール。

【概要】 numpyで扱っていた整数が、いつのまにか float64 の浮動小数になっていました。pyhonでは、被演算子のデータ型の組み合わせによっては、演算結果のデータ型が変更されます。動的型付けの影響です。調べてみると、この変換にはいろいろなパターンがあります。そして、整数の演算同士の演算でも、その結果が浮動小数となる摩訶不思議なデータ型の変換ルールがあることも分かりました。

1. はじめに

 GPTテーブルを読み取るPythonスクリプト(関連記事は、ここ)を書いていて、困ったのが、セクタ数をバイト数に変換する際、numpy.uint64 のつもりの演算結果が float64 の浮動小数になってしまったこと。これでは、ファイルの頭出し ( f.seek() ) ができません。

 とりあえずの解決策は見つけたのですが、動作は良く理解していないままでした。本稿では、uint64の演算がfloat64 へ変換されるケースについて、まず述べます。その後、pythonにおける演算結果のデータ型の割り付け規則についてまとめます。

 なお、本稿は、python3 での動作について述べています。python2 の場合は動作が異なります(付録B参照)。

2. uint64 の演算結果が、float64 になる

2.1 整数が浮動小数になって、f.seek できない

 numpyのfloat32のスカラー値 (numpy.float32) と ( numpy ではない ) 普通のスカラー値の整数 (<class 'int'>) や浮動小数 (<class 'float'>) との演算を行うと、自動的に numpy.float64 の浮動小数になるそうです*1

 このようなデータ型の変更は、numpy.float32に限らず、numpy.unit64の場合にも発生します。

 例えば、セクタ数 (sector=2)をバイト数 (byte=1024) に変換するつもりで以下のように演算すると、byte は numpy.float64 の変数になってしまいます。

>>> import numpy as np
>>>
>>> sector = np.array(2,'uint64')
>>> 
>>> sector
array(2, dtype=uint64)
>>> type(sector)
<class 'numpy.ndarray'>
>>> sector.dtype
dtype('uint64')

この uint64 の numpy の変数 sector を用いて、バイト数に変換して、ファイルを f.seek(sector*512) しようとすると、エラーとなります。

>>> f = open('tmpfile','rb')
>>> f.seek(sector*512)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'numpy.float64' object cannot be interpreted as an integer

 sector*512 は、numpy.float64 の変数になっているようです。

>>> byte = sector*512
>>> byte
1024.0
>>> type(byte)
<class 'numpy.float64'>
>>> byte.dtype
dtype('float64')

 float64 になった値をint() や astype() で整数に変換すればよいのかしれませんが、美しくありません。

2.2 float64 への昇格問題

 これは、型の昇格というpythonの動作によるものです。普通のスカラー値、numpy によるスカラー値 ( 0次元配列)、numpy の配列の3つの場合について、乗算をした結果は、次の表のようになります。

512
<class 'int'>
-
np.array(512,'uint64')
<class 'numpy.ndarray'>
'uint64'
np.array([512],'uint64')
<class 'numpy.ndarray'>
'uint64'
2
<class 'int'>
-
1024
<class 'int'>
-
1024.0
<class 'numpy.float64'>
'float64'
[1024]
<class 'numpy.ndarray'>
'uint64'
np.array(2,'uint64')
<class 'numpy.ndarray'>
'uint64'
1024.0
<class 'numpy.float64'>
'float64'
1024
<class 'numpy.uint64'>
'uint64'
[1024]
<class 'numpy.ndarray'>
'uint64'
np.array([2],'uint64')
<class 'numpy.ndarray'>
'uint64'
[1024]
<class 'numpy.ndarray'>
'uint64'
[1024]
<class 'numpy.ndarray'>
'uint64'
[1024]
<class 'numpy.ndarray'>
'uint64'

乗算結果の上段は、print()の結果、中段はtype()の結果、下段はdtype属性。

 この表から、次のことが分かります。

  • float64 に型変換されるのは、普通のスカラー値 (<class 'int') と numpy のスカラー値との間で演算が行われた場合のみ。
  • それ以外は、すべて整数型のまま。

 整数同士の演算結果が浮動小数に型変換されるのは、奇妙な仕様です。

3. データ型変換のルール

 前節で調べたのは、型の組合せの極一部です。主な整数型、浮動小数型について、プログラムを作って調べました(付録A参照)。

3.1 調べたデータ型

 調査対象は、普通のスカラー値の int ( <class 'int'>)、普通のスカラー値の float( <class 'float'>)、numpy の整数 ( 32ビット、64ビット、符号有無)、浮動小数(32ビット、64ビット )、及び、それらの配列の計14個の型です。

  • 普通のスカラー値のint (i)
  • 普通のスカラー値のfloat (f)
  • numpyのint32 (i4)、uint32 (u4) 、int64 (i8)、uint64 (u8)、及び、それらの配列
  • numpyのfloat32 (f4), float64(f8)、及び、それらの配列

3.2 データ型の変換テーブルと変換ルール

 これらの型の演算結果の組合せは、以下の図のテーブル(マトリックス)に示す通りです。[ ]の場合は、配列です。最上段、最左列がそれぞれの被演算子のデータ型、それぞれの被演算子と演算を行った結果をテーブルにしています。上右三角の部分と左下三角の部分は同じ結果となるので、省略しています。

3.2.1 加算・減算・乗算の場合のデータ型の変換テーブル

 演算は、加算・減算・乗算、いずれの場合も同じ結果です。除算は異なります。

f:id:toranosuke_blog:20180928224221p:plain
 14個のデータ型の演算結果のデータ型。

 i, f は、<class 'int'>、<class 'float'>、それ以外は numpy の型コードによる表記(例えば、i4 であれば int32、[i4] は int32 の配列)。赤は整数が浮動小数に変換される場合、青色は、型の昇格がある場合、オレンジは型の降格がある場合、灰色は符号が変わる場合。赤・青の細線は被演算子のいずれかが昇格・降格の場合、太線は被演算子の両方にとって昇格の場合。スカラー型の int、float は、それぞれ int64、float64 の精度として、昇格・降格を判定。

f:id:toranosuke_blog:20180928193435p:plain

 スカラー値、0次元配列(スカラー値相当)のみ。64ビットの符号なし整数 (uint64) と符号あり整数 (int, int32, int64) の時に64ビットの浮動小数 (float64) に変換される。

f:id:toranosuke_blog:20180928193453p:plain
配列のみ。

3.2.2 加算・減算・乗算の場合のデータ型の変換ルール

 この結果から次の変換ルールがあることが分かります。

  • 型の順位:float64 > float32 > int64, uint64 >int32, uint32
  • スカラー同士の演算
    • 同じ順位の型同士の演算で、型は変わらない。
    • float32、float64との演算 ⇒ float64
    • 符号なし整数と符号あり整数の演算は、昇格する。
      • uint32 と int32 ⇒ int64
      • uint64 とint, int32, int64 ⇒ float64
    • 型の順位が異なる場合は、順位が上位の型に合わせる
      • int32とint64 ⇒ int64
      • uint32とint64 ⇒ int64
      • uint32とuint64 ⇒ uint64
  • 配列とスカラーの演算
    • float32の配列とスカラーの演算 ⇒ float32の配列
    • float64の配列とスカラーの演算 ⇒ float64の配列
    • 整数配列とfloat32, float64の演算 ⇒ float64の配列
    • 整数配列と整数型スカラーの演算 ⇒ 入力配列の型と同じ型の配列
       スカラーの型順位が上位の場合、スカラーのデータ型が降格する。
  • 配列と配列の演算
    • スカラー同士の演算に準じる。

 動的型付けの演算では、何らかの変換ルールで、演算結果のデータ型を決める必要があります。uint64 と符号あり整数型の演算の場合を除けば、概ね理解できる変換ルールです。

 符号なし整数と符号ありの整数は昇格させるという基準で設定されている変換ルールと思いますが、だからと言って、昇格した先のデータ型が浮動小数というのは、理解しがたい仕様です。

3.2.3 除算の場合のデータ型の変換ルール

 除算の場合の変換テーブルは、以下の図の通りです。

f:id:toranosuke_blog:20180928230322p:plain
除算のデータ型。

 変換ルールは、次の通りです。

  • 除算の場合は、基本的にfloat64を出力する。
  • 但し、
    • float32とfloat32の演算 ⇒ float32
    • float32の配列とfloat32の配列 ⇒ float32の配列
    • float32の配列とスカラーの演算 ⇒ float32の配列

3.3 摩訶不思議なデータ型の変換ルール

 pythonは予め出力のデータがを決めない動的型付けのため、被演算子に基づき決めた何らかのデータ変換ルールに従って、演算を行う必要があります。そのデータ変換ルールが、前節で説明したような変換ルールだったわけです。

 概ね、理解できる変換ルールですが、整数同士の演算を浮動小数点に昇格させてしまうのは、直感的に予想できない変換ルールです。また、uint64 の主たる使用目的の一つはアドレス指定と思います。

 そうであれば、uint64を浮動小数へ変換するルールは、奇異なルール、摩訶不思議なルールと言わざるを得ません。

 浮動小数で困る場合には、int() や astype() などで整数型へ変換を行えば済む話かもしれません。それでも、float64 への昇格ではなく、64ビットの整数への変換の方が分かりやすく、適切な仕様ではないでしょうか。

4. 最後に

 pythonのデータ型の変換についてまとめました。pythonでは、uint64型と符号あり整数型の演算が浮動小数に変換されるという摩訶不思議なデータ型の変換ルールがあり、注意が必要です。

 私のような Python 初心者でなくても、はまりそうな点ではないかと思います。

(2018/9/29)

関連記事

付録A:演算結果のデータ型を表示するスクリプト

 python3のスクリプトです。動作確認は、ubuntu18.04で行っています。

 python2のスクリプトも作っています(python3との違いは、print文の関係のみ)。python2のスクリプトと実験結果と合わせて、ここ (Googleドライブ) に置いておきます。

#!/usr/bin/python3
#
# ckeck_types.py
# 
# make tables of data types converted with operation in python. 
#
# copyright (c) 2018 Toranosuke Tenyu

import sys
import numpy as np

def add_bra(cc,bra=False):

    if bra == True:
        return "["+cc+"]"
    else:
        return cc

def cc (dd):

    ti = type(2)
    tf = type(2.0)

    bra = "[" in "{}".format(dd)

    if hasattr(dd,"dtype"):
        code = dd.dtype
        if code == 'int32':
            return add_bra('i4',bra)
        if code == 'uint32':
            return add_bra('u4',bra)
        if code == 'int64':
            return add_bra('i8',bra)
        if code == 'uint64':
            return add_bra('u8',bra)
        if code == 'float32':
            return add_bra('f4',bra)
        if code == 'float64':
            return add_bra('f8',bra)
    else:
        code = type(dd)
        if code == ti :
            return 'i'
        if code == tf :
            return 'f'

def print_dtype(dd,dd_print=False):

    if dd_print:
        print("%5s"%dd,"%5s"%cc(dd),end=" ")
    else:
        print("%5s"%cc(dd),end=" ")
            

def print_conv(data,dd_print=False,dd_trig=True,op="mul"):

    if dd_print:
        print("%10s"%"",end="  ")
    else:
        print("%5s"%"",end=" ")

    for dd in data:
        print_dtype(dd,dd_print)

    print("")

    for dd2 in data:
        print_dtype(dd2,dd_print)

        for dd1 in data:

            if op == "mul":
                val = dd2*dd1
            elif op == "add":
                val = dd2+dd1
            elif op == "sub":
                val = dd2-dd1
            else:
                val = dd2/dd1
                
            print_dtype(val,dd_print)
            if dd_trig :
                if cc(dd1) == cc(dd2):
                    break

        print("")
            

        
if __name__ == '__main__': 

    i2 = 2
    f2 = 2.0

    # print orignal data
    # dd_print = True
    dd_print = False

    # print only lower triangular matrix
    dd_trig = True
    #dd_trig = False

    op = "mul"
    # op = "add"
    # op = "sub"
    # op = "div"

    print(sys.version)

    print("")
    
    data = [
        i2,
        f2,
        np.array(i2  ,'i4'),
        np.array([i2],'i4'),
        np.array(i2  ,'u4'),
        np.array([i2],'u4'),
        np.array(i2  ,'i8'),
        np.array([i2],'i8'),
        np.array(i2  ,'u8'),
        np.array([i2],'u8'),
        np.array(f2  ,'f4'),
        np.array([f2],'f4'),
        np.array(f2  ,'f8'),
        np.array([f2],'f8')
    ]
    print_conv(data,dd_print,dd_trig,op)
    print("")

    data = [
        i2,
        f2,
        np.array(i2  ,'i4'),
        np.array(i2  ,'u4'),
        np.array(i2  ,'i8'),
        np.array(i2  ,'u8'),
        np.array(f2  ,'f4'),
        np.array(f2  ,'f8')
    ]
    print_conv(data,dd_print,dd_trig,op)
    print("")

    data = [
        np.array([i2],'i4'),
        np.array([i2],'u4'),
        np.array([i2],'i8'),
        np.array([i2],'u8'),
        np.array([f2],'f4'),
        np.array([f2],'f8')
    ]
    print_conv(data,dd_print,dd_trig,op)
    print("")

付録B. python2との違い

 python2とpython3で加算・乗算・乗算については、同一動作でした。

 しかし、除算については、python3と動作が異なります。変換テーブルは、以下の通りです。

f:id:toranosuke_blog:20180929153135p:plain
Python2の除算演算における変換規則。

 この変換規則は、加算・減算・乗算の変換規則と同一です。つまり、python2では四則演算の全てで同じ変換規則を使っています。

 一方、python3では、加算・減算・乗算に関しては、python2と同じですが、除算に関しては、基本的に float64 を出力するように変更されています。

 つまり、python2とpython3の違いは、除算結果のデータ型の変換ルールの違いとなります。

GPTテーブルを読み取るプログラムを作って、Windowsディスクを調べた(in Python)

【概要】GPTテーブルを読み取って、テキストで出力する Python プログラムを作りました。gdisk ではテキスト出力できない GPT ヘッダの位置を読み出す目的で作りましたが、GPT テーブル内に入っている他の情報もすべて出力します。このプログラムを使って、Windows でディスクのパーティションテーブルが正常に設定されているか、調査しました。

1. はじめに

 クローンディスクを作っていて気になったのが、Windowsでは、GUIDパーティションテーブル (GUID Partition Talbe; GPT) の第2GPTヘッダを正しい位置、つまり、ディスクの末尾に配置しているか、という点です(関連記事は、ここ)。

 Windowsで作ったディスクを gdisk で覗くと、次のエラーメッセージが出力されます。

The protective MBR's 0xEE partition is oversized! Auto-repairing.

 gdisk のソースコードを読めばいいのかもしれませんが、この原因をよく理解していませんでした。パーティションサイズの認識に何らかの異常があるのですが、このエラー自体は深刻なものではなく、自動修復しても構わない程度のもののようです*1

 最初に疑ったのは、Windows。Windowsでは認識したことになっているディスクサイズが実際のディスクサイズと違うのではないか?その影響が、先のエラーメッセージとなって現れたと推測しました。このことを確認する一つの方法が、第2GPTヘッダの位置が適切な場所、つまり、ディスク末尾に置かれているか、ということです。

 GPTテーブルを読み取るプログラムは、このような背景から生まれました。

 なお、使用した言語は、Pythonです。Python 初心者なので、変なところがあると思います。ご指導・ご鞭撻のほどよろしくお願い致します。

2. Pythonプログラム

2.1 仕様

 GPTヘッダの情報を全てテキストで出力します。入力は、dd ダンプしたハードディスクイメージか、gdisk で保存したGPTデータです。

 gdisk の CUI で取り出せない主なデータは、第1と第2のGPTヘッダの位置情報とCRCの値、MBRぐらいです。それ以外の情報は、gdiskでもほぼすべてテキスト出力できます。

 今回作った read-gpt-table.py では、gdisk でテキスト出力できない GPTヘッダの位置情報を含めて、すべてのデータを出力します。

 目的や入出力が異なりますが、GPTテーブルを読み出すCのプログラムもあります。今回の目的には合致しませんでしたが、参考にさせて頂きました。
 ● GUID Partition Table を読む - jou4のブログ

2.2 コード

 GPTテーブルを読み取るためのプログラム read-gpt-table.py を付録A につけておきます。使い方は、次の通りです。

$ read-gpt-table.py 
Usage: read-gpt-table.py file [option]
 Read GPT table from file.
 Option:
  --dd    : file is a dd-dumped image. (default)
  --gdisk : file is a GPT table saved by gdisk.

 Caution:
     gdisk may repair GPT header automatically.
     To get GPT header as is, use dd-dumped image.

 注にも書きましたが、gdiskでは、自動的にGPTヘッダを修復してしまうことがあるので、変更を加えないそのままのGPTヘッダを読み取りたい場合には、ddダンプしたファイルを使った方がよいです。

 なお、動作確認は、ubuntu/lubuntu 18.04 の pyhonの3.6.6で行っています。

2.3 使い方

● ddダンプしたファイルの場合

$ dd if=/dev/sdX of=foo.img
$ read-gpt-table.py foo.img --dd 

● gdiskのGPTデータの場合

$ gdisk /dev/sdX
 ( command 'b' を実行し、foo.gpt に保存 )
$ read-gpt-table.py foo.gpt --gdisk

3. WindowsのGPTテーブルを調べた

3.1 gdiskで保存されるGPTテーブル

 GPTテーブルのほとんどの情報は、gdiskのCUIから読み出すことができます。しかし、筆者が知りたかったGPTヘッダの位置情報については、CUIからは調べることはできません。

 一方、gdiskのコマンド 'b' によって保存されたバイナリのファイルには、GPTテーブルのすべての情報が保存されますので *2、このバイナリファイルを解析することで、知りたい情報を得ることができます。

 このデータファイルの構造は、下記の計35セクタ ( =17,920 バイト)です。

  • [MBR(1), 第1GPTヘッダ(1), 第2GPTヘッダ(1), パーティションエントリー(32)]
 ddダンプしたファイルでは、ファイルの先頭に [MBR, 第1GPTヘッダ, パーティションエントリー]の計34セクタが配置され、第2GPTヘッダやパーティションエントリーのコピーはディスク末尾に配置されますので、プログラミングの際には、少々、注意を払う必要があります。

 但し、gdiskが保存するGPTデータは、メモリ上に展開されたパーティション情報です。gdiskのマニュアルには、バックアップコマンド b について以下の説明があります。

Save partition data to a backup file. You can back up your current in-memory partition table to a disk file using this option. The resulting file is a binary file consisting of the protective MBR, the main GPT header, the backup GPT header, and one copy of the partition table, in that order. Note that the backup is of the current in-memory data structures, so if you launch the program, make changes, and then use this option, the backup will reflect your changes.

 この説明を読むと、前述の "Auto-repairing" が実施された場合にも、自動修復された状態のGPTテーブルがファイルに出力されそうです。

3.2 WindowsのGPTテーブルに異常なし

 次の二つのディスクについて、GPTテーブルを調査しました。

  • Windowsシステムが入った1TBのHDD
  • Windowsシステムが入った500GBのSSD

 プログラムの出力例を付録Bに示します。

 HDDの場合でも、SSDの場合でも、ddダンプしたファイルから読み取ったGPTテーブルと、gdiskのGPTデータから読み取ったGPTテーブルとの間では、MBRの極一部を除き同一でした。

 一番気になっていた第2GPTの位置ですが、ディスク末尾の最終セクタへのオフセット値を示していて、正常です。また、ddダンプしたディスクイメージの末尾の1セクタ(512バイト)から読み込んだ第2GPTテーブルにも異常は見られませんでした。

 Windowsが作ったパーティションテーブルだからと言って、GPTについては、おかしなことをやっているわけではなさそうです。

 但し、「GPTについては」です。

3.3 WindowsのMBRはいい加減

 gdiskの結果とddの結果で異なる部分は、MBRの部分でした。これは、MBRの第1パーティションの全セクタ数で、例えば、SSDの場合には以下となります。

バイト数ddの値
(修復前)
gdiskの値
(修復後)
ブートフラグ 1 0x 00
最初のセクタ(CHS方式) 3 0x 00 20 00
パーティション識別子 1 0x EE (=GPT)
最後のセクタ(CHS方式) 3 0x FF FF FF
最初のセクタ(LBA方式) 4 0x 00 00 00 01
パーティションの全セクタ数4 0x FF FF FF FF 0x 3A 38 60 2F
(=976,773,167)
MBRの第1パーティションの情報 (500GBのSSDの場合)。

 Windowsの場合、パーティションの最初のセクタ数(LBA)は正しいようですが、パーティションの全セクタ数は実際の数字を反映せず、0xFFFFFFFFが設定されています。

 gdiskは、パーティションサイズが0xFFFFFFFFというのは大きすぎる (The protective MBR's 0xEE partition is oversized!) と判定し、自動修復(Auto-repairing) して、GPTが管理するセクタ数(=ディスクの全セクタ数-1)をMBRの第1パーティションの全セクタ数として設定しているようです。HDDの場合も同様に修正されています。

 Windowsとしては、パーティションサイズが-1 (0xFFFFFFFF) という設定は、サイズ不明ということなのでしょう。パーティションサイズを取得できないわけではないので、手抜き実装としか思えません。

 CHS方式のセクタ数も不正確と思いますが、gdisk は修復していません。CHS方式でのディスク管理は廃れた方式なので、gdisk も相手にしなかったということでしょうね。

 やはり、Windows。MBR については、いい加減な実装をしていました。

4. 結論

 Windowsでは、第2GPTヘッダーが正しく配置されないという疑念がありましたが、特に問題なさそうです。

 但し、WindowsのMBRのパーティションサイズは正しく入力されていません。gdiskでは、Windowsが設定した不適切なのMBRの値を自動的に正しい値に設定し直しているようです。

 モヤモヤしていたことなので、疑念が晴れてスッキリしました。また、Pythonの勉強にもなりました。

(2018/9/24)

関連記事

付録A:GPTテーブルを読み取るPythonプログラム

ソースコードとサンプルデータは、ここ(Googleドライブ)に置いておきます。

#!/usr/bin/python3
#
# read-gpt-table.py
# 
#   Read and print GPT partition table from a file saved with dd or gdisk.
# 
#   Copyright (C) 2018 Toranosuke Tenyu
#
#

### structure of GPT table in dd-dumped image ###
# LBA0       is MBR
# LBA1       is 1st GPT Header
# LBA2-33    is partition entries (128 entries)
# last LBA   is 2nd GPT Header (the end of disk)
#
# see:  https://en.wikipedia.org/wiki/GUID_Partition_Table

### structure of GPT table in GPT data saved with gdisk ###
#
# LBA0       is MBR
# LBA1       is 1st GPT Header
# LBA2       is 2nd GPT Header
# LBA3-LBA34 is partition entries (128 entries)
#
# The size of GPT data by gdisk is 35 sectors (17920 bytes)
# The size of LBA is 1 sector.

import sys
import numpy as np

### gpt header dtype (512 byte)
gpt_dtype = np.dtype([
    ('signature',          'S8'),
    ('revision',           '>u4'),
    ('header_size',        '<u4'),
    ('crc32_1',            '<u4'),
    ('reserved_1',         '<u4'),
    ('loc_1st_gpt',        '<u8'),
    ('loc_2nd_gpt',        '<u8'),
    ('first_usable_sector','<u8'),
    ('last_usable_sector', '<u8'),
    ('disk_guid',          'u1',16),
    ('starting_lba',       '<u8'),
    ('num_of_entry',       '<u4'),
    ('size_of_entry',      '<u4'),
    ('crc32_2',            '<u4'),
    ('reserved_2',         'u1',420)
])

### read GPT Header 
def read_gpt(filename, offset=512):

    # open gpt file
    fp = open(filename,'rb')
    fp.seek(offset)

    # read GPT Header from file
    gpt = np.fromfile(fp,dtype=gpt_dtype,count=1)

    # close file
    fp.close()

    return gpt

### print GPT Header ###
def print_gpt(gpt):
    print('signature             : %s' %gpt['signature'].tostring().decode('ascii'))
    print('revision              : 0x%08x'%gpt['revision'][0])
    print('header size           : %d'%gpt['header_size'])
    print('crc32(1)              : %d'%gpt['crc32_1'])
    print('reserved(2)           : %d'%gpt['reserved_1'])
    print('1st GPT location      : %d'%gpt['loc_1st_gpt'])
    print('2nd GPT location      : %d'%gpt['loc_2nd_gpt'])
    print('first usable sector   : %d'%gpt['first_usable_sector'])
    print('last usable sector    : %d'%gpt['last_usable_sector'])
    print('disk_guid             : %s'%guid_toString(gpt['disk_guid'][0]))
    print('starting LBA          : %d'%gpt['starting_lba'])
    print('number of entry       : %d'%gpt['num_of_entry'])
    print('size of entry         : %d'%gpt['size_of_entry'])
    print('crc32(2)              : %d'%gpt['crc32_2'])

# Convert binary GUID to string
def guid_toString(guid):

    # print(guid)

    guid_ascii =''

    # data1 (ulong)
    guid_ascii += f'%02X'%guid[3]
    guid_ascii += f'%02X'%guid[2]
    guid_ascii += f'%02X'%guid[1]
    guid_ascii += f'%02X'%guid[0]
    guid_ascii += '-'

    # data2 (ushort)
    guid_ascii += f'%02X'%guid[5]
    guid_ascii += f'%02X'%guid[4]
    guid_ascii += '-'

    # data3 (ushort)
    guid_ascii += f'%02X'%guid[7]
    guid_ascii += f'%02X'%guid[6]
    guid_ascii += '-'

    # data4 (uchar[8])
    guid_ascii += f'%02X'%guid[8]
    guid_ascii += f'%02X'%guid[9]
    guid_ascii += '-'
    guid_ascii += f'%02X'%guid[10]
    guid_ascii += f'%02X'%guid[11]
    guid_ascii += f'%02X'%guid[12]
    guid_ascii += f'%02X'%guid[13]
    guid_ascii += f'%02X'%guid[14]
    guid_ascii += f'%02X'%guid[15]

    return guid_ascii

### partition entry (128 byte/entry) ###

entry_dtype = np.dtype([
    ('type_guid',      'u1',16),
    ('unique_guid',    'u1',16),
    ('first_lba',      '<u8'),
    ('last_lba' ,      '<u8'),
    ('attribute_flag', '<u8'),
    ('partition_name', '<u2',36)
])

def read_entry(filename,offset=1024,npart=-1):

    # open file
    fp = open(filename,'rb')
    fp.seek(offset)

    # read partition entry from file
    entry = np.fromfile(fp,dtype=entry_dtype,count=npart)
    
    # close file
    fp.close()

    return entry

def print_entry(entry):

    count = 0
    for item in entry:
        if item['first_lba'] != 0 :
            print('partition type guid   :', guid_toString(item['type_guid']))
            print('unique partition guid :', guid_toString(item['unique_guid']))
            print('first_lba             :', item['first_lba'])
            print('last_lba              :', item['last_lba'])
            print('attribute flags       : 0x%016X'%item['attribute_flag'])
            print('partition name        : \'{}\''.format(item['partition_name'].tostring().decode('utf-16-le').strip('\0')))
            print('')
            count += 1

    print('Number of valid entries = %d\n'%count)

### MBR ###
def read_mbr(filename,offset=0):
    fp = open(filename,'rb')
    fp.seek(offset)
    
    mbr = np.fromfile(fp,dtype='<u1',count=512)
    fp.close()
    return mbr

def print_mbr(mbr):
    count=1
    for item in mbr :
        if item != 0 :
            print('%02X '%item,end='')
        else :
            print('-- ',end='')
        if count%16 == 0 :
            print('')
        count += 1
    print(' ')

def print_usage():
    print('Usage: {} file [option]'.format(__file__))
    print(' Read GPT table from file.')
    print(' Option:')
    print('  --dd    : file is a dd-dumped image. (default)')
    print('  --gdisk : file is a GPT table saved by gdisk.')
    print('')
    print(' Caution:')
    print('     gdisk may repair GPT header automatically.')
    print('     To get GPT header as is, use dd-dumped image.')

def args_parser():
    args = sys.argv

    if (len(args) == 2 ):
        return 'dd'         # read GPT table from dd-dump (default)

    if (len(args) == 3):
        if ( args[2] == '--gdisk' ):
            return 'gdisk'   # read GPT table  saved by gdisk
        if ( args[2] == '--dd' ):
            return 'dd'

    print_usage()
    sys.exit()

if __name__ == '__main__':

    # set file_type = 'dd' or 'gdisk'
    file_type = args_parser()

    filename = sys.argv[1]

    bsize = 512

    ### read & print GPT header

    if ( file_type == 'gdisk' ):

        # read from gdisk file 

        print('### 1st GPT Header ###')
        gpt_header1 = read_gpt(filename,bsize)
        print_gpt(gpt_header1)
        print('')

        print('### 2nd GPT Header ###')
        gpt_header2 = read_gpt(filename,2*bsize)
        print_gpt(gpt_header2)
        print('')

        print('### Partition Entry ###')
        entry_list = read_entry(filename,3*bsize)
        print('Number of entries = %d\n'%entry_list.size)
        print_entry(entry_list)

        print('### MBR ###')
        mbr = read_mbr(filename,0)
        print_mbr(mbr)
    else:
        # read from dd-dump file        

        print('### 1st GPT Header ###')
        gpt_header1 = read_gpt(filename,bsize)
        print_gpt(gpt_header1)
        print('')

       print('### 2nd GPT Header ###')

        # escape from converting into float64
        uint64_512 = np.array([512],dtype=np.uint64)
        uint64_loc = gpt_header1['loc_2nd_gpt'][0]*uint64_512[0]
        
        gpt_header2 = read_gpt(filename,uint64_loc)
        print_gpt(gpt_header2)
        print('')

        print('### Partition Entry ###')
        entry_list = read_entry(filename,2*bsize,128)
        print('Number of entries = %d\n'%entry_list.size)
        print_entry(entry_list)
        
        print('### MBR ###')
        mbr = read_mbr(filename,0)
        print_mbr(mbr)

    sys.exit()

付録B:read-gpt-table.pyの実行結果

### 1st GPT Header ###
signature             : EFI PART
revision              : 0x00000100
header size           : 92
crc32(1)              : 2997411310
reserved(2)           : 0
1st GPT location      : 1
2nd GPT location      : 1953525167
first usable sector   : 34
last usable sector    : 1953525134
disk_guid             : B45D2A5C-F9A4-478D-818B-D8E6280ABEA4
starting LBA          : 2
number of entry       : 128
size of entry         : 128
crc32(2)              : 3723135598

### 2nd GPT Header ###
signature             : EFI PART
revision              : 0x00000100
header size           : 92
crc32(1)              : 288711948
reserved(2)           : 0
1st GPT location      : 1953525167
2nd GPT location      : 1
first usable sector   : 34
last usable sector    : 1953525134
disk_guid             : B45D2A5C-F9A4-478D-818B-D8E6280ABEA4
starting LBA          : 1953525135
number of entry       : 128
size of entry         : 128
crc32(2)              : 3723135598

### Partition Entry ###
Number of entries = 128

partition type guid   : C12A7328-F81F-11D2-BA4B-00A0C93EC93B
unique partition guid : CC2D4D60-A1FB-4D4E-9542-C603A9BA1CCD
first_lba             : 2048
last_lba              : 534527
attribute flags       : 0x8000000000000000
partition name        : 'EFI system partition'

partition type guid   : E3C9E316-0B5C-4DB8-817D-F92DF00215AE
unique partition guid : 91297EAC-45C5-4BDC-8F28-CC0978A7084F
first_lba             : 534528
last_lba              : 567295
attribute flags       : 0x8000000000000000
partition name        : 'Microsoft reserved partition'

partition type guid   : EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
unique partition guid : 79886FBF-71C1-4E37-9922-A2C336CA8720
first_lba             : 567296
last_lba              : 1926947658
attribute flags       : 0x0000000000000000
partition name        : 'Basic data partition'

partition type guid   : DE94BBA4-06D1-4D40-A16A-BFD50179D6AC
unique partition guid : 6ABF2C3A-3420-48A2-968D-5F3FCBA7EF1B
first_lba             : 1926948864
last_lba              : 1929021439
attribute flags       : 0x8000000000000001
partition name        : ''

partition type guid   : DE94BBA4-06D1-4D40-A16A-BFD50179D6AC
unique partition guid : 932D4253-8484-440A-856C-2A8E03037CBE
first_lba             : 1929022863
last_lba              : 1953525134
attribute flags       : 0x8000000000000001
partition name        : 'Basic data partition'

Number of valid entries = 5

### MBR ###
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
02 -- EE FF FF FF 01 -- -- -- FF FF FF FF -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- -- -- -- -- -- -- 55 AA 

*1:"The oversized 0xEE partition ...(snip)... could indicate something strange to do with disk size detection." (Rod Smith, gdiskの開発者)
https://superuser.com/questions/1023343/after-upgrading-from-windows-7-to-windows-10-system-thinks-gpt-partition-is-mbr#comment1424307_1023702

*2: GPTテーブルの構造については、「GUIパーティションテーブル」(wikipedia)やその英語版に解説があります。これを参考にしました。

Win10 1803 が VirtualBox にも悪さした

【概要】 Windows10の1803アップグレードで、CryptSvc が原因で chrome が動作異常を起こすことを報告しましたが、VirtualBox にも悪影響を与えていました。とりあえずの回避方法を紹介します。

1. Windows10 1803アップグレード

 何かと安定しないと言われる1803アップグレード。既にChromeについての異常動作については紹介しました(関連記事は、ここ)。

 この原因は、CryptSvcの暴走ですが、VirtualBoxでも、起動時にCryptSvcが暴走し、正常起動できない状態となりました。

2. ソフトウェアのバージョン

  • Windows 10 Home (x64) 1803、ビルド:17134.254
  • VirtualBox:5.2.18 r124319
  • ゲストOS:Ubuntu18.04

3. 症状

3.1 ゲストOSのUbuntuが起動しない

 VirtualBoxからゲストOSのUbuntuを起動しようとしても、応答せず、起動しません。

f:id:toranosuke_blog:20180922112649p:plain:w400
画面が真っ暗でUbuntuが起動しない。

 このとき、CryptSvc (Cryptographic Services)の負荷が上昇します。

 f:id:toranosuke_blog:20180922113240p:plain:w500
私のdynabookの場合、通常は0%のCPU使用率が数%程度となる。

3.2 CryptSvcを停止しても起動しない

 CyptSvcの暴走が原因のようなので、CryptSvcを停止しましたが、今度は異なるエラーで起動しません。

f:id:toranosuke_blog:20180922113728p:plain:w500
今度は、ubuntuの起動以前の段階で停止しているようです。

3.3 原因の推測

 CryptSvcが起動していれば、ubuntuを起動するフェーズに入れるが、ubuntuを起動するフェーズに入ると、CryptSvcが暴走し起動を阻害するので、一旦、CryptSvcが停止させる必要がある、といったところではないかと思います。

① ubuntuの起動フェーズに入る(CyptSvcが必要)→ CryptSvcが暴走する
② ubuntuの起動中に待ち状態になる(画面が黒)← CryptSvcが起動を阻害する
③ CryptSvcを停止する → 待ち状態が解消し、起動が進行する

4. とりあえずの解決策

 この問題は、以下の方法で回避できます。

  • ubuntuの起動中にCryptSvcを再起動する

 CryptSvcの停止のタイミングにシビアな印象はありませんが、タスクマネージャからの停止だと面倒なので、スクリプトを書いておくと楽です。

net stop CryptSvc
net start CryptSvc

 上記のバッチファイルを管理者特権で実行すれば、CryptSvcが再起動します(ちょっとだけ楽にするために改良したスクリプトは、ここ)。

 なお、根本的な解決方法の一つはクリアインストールです。私の場合、諸事情でWin10をクリアインストールする羽目になって、この問題は根本的に解決しました(笑)。

5. 最後に

 Microsoftさん、CyptSvcの暴走問題を早く解決してくださいませ。

(2018/9/22)

関連記事