【ラズパイ】SDカードリーダでのデータ転送

# はじめに
ラズパイ（Raspberry Pi）を使って実験をしていたところ，とある原因によりOSが起動できなくなってしまいました．しかしながら，保存したデータを救出する必要があり，それに苦戦したので，その記録を残したいと思います．


# 前提
上述の通り，ラズパイではOSを起動できないため，SDカードのデータをカードリーダ（USB接続）を用いて読み出します．また，今回はWindows PCを用います．
WindowsではLinuxのフォーマット形式であるext4を（そのままでは）読むことができません．以下のようなサードパーティ製のソフトウェアを利用する手もありますが，有料であったり，あるいは，セキュリティ的な問題が発生する場合もあると思います．

https://www.paragon-software.com/jp/home/linuxfs-windows/

今回は，無料でデータを読み出したいという前提の元，その方法をまとめます．


# 準備
まずは，読み出す前に，以下の2つを準備する必要があります．

- WSL2
- USBIPD

WSL2とは，Windows上で利用することができるLinuxシステムであり，今回ext4形式でフォーマットされたストレージに記録されたデータを読み出すために利用します．
また，USBIPDとは，WSL2でUSB接続されたデバイスを認識するために必要となるソフトウェアになります．


## WSL2のインストール
WSL2のインストール手順の詳細な説明をしたいところですが，これだけで1本の記事ができてしまうので，詳細な説明については他の方に任せたいと思います．（USBIPDとは異なり，比較的多くの記事が公開されているので，それほどは困らないと思います）
公式の記事と

https://learn.microsoft.com/ja-jp/windows/wsl/install

参考になりそうな記事を挙げておきます．

https://qiita.com/zakoken/items/61141df6aeae9e3f8e36

https://qiita.com/SAITO_Keita/items/148f794a5b358e5cb87b


## USBIPDのインストール
先にも述べたように，WSL2にUSB接続したデバイスを認識させるためにインストールします．なお，公式ドキュメントは以下です．

https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb

まずは，以下のページからUSBIPDのインストーラをダウンロードします．

https://github.com/dorssel/usbipd-win/releases

ダウンロード後は`.msi`ファイルを実行して下さい．ここでダウンロードを信頼するかを確認するポップアップが表示される可能性がありますが，そのままダウンロードしてください．

# データの読み出し手順
ここまで準備ができれば，SDカードからのデータ読み出しはすぐそこです．まずは読み出しの手順について，その概観を示します．（シーケンス図の基本原則に従えていない箇所もありますが，ご容赦下さい…）

```mermaid
sequenceDiagram
    participant SD as SD (USB)
    participant Win as Windows (Host)
    participant WSL as WSL2 (Linux)

    Note left of SD: USBカードリーダの（物理的な）接続
    SD ->> Win: カードリーダのマウント（接続）
    
    Note left of SD: WSL2へのSDカードのマウント（接続）（USBIPD）
    Win ->> SD: カードリーダのアンマウント（切断）
    SD ->> WSL: カードリーダのマウント（接続）
    
    Note left of SD: データの読み出し
    SD ->> WSL: データの送信
    WSL ->> Win: データの送信
    
    Note left of SD: カードリーダの取り出し（USBIPD）
    WSL ->> SD: カードリーダのアンマウント（切断）
    SD ->> Win: カードリーダのマウント（接続）
    Win ->> SD: カードリーダのアンマウント（切断）
```

以上の操作を全て覚える必要は無いですが，今，自分がどの操作の段階にあるかを理解しておくことでエラーを解消する手助けになると思います．


## Step1. USBカードリーダの（物理的な）接続
ラズパイから取り出したSDカードをUSBで接続します．
このときにWindows側で認識できる（エクスプローラで開くことができる）ディレクトリはLinuxの起動に関連した部分（パーティション）のみなので，もしSDカードを接続後に勝手にエクスプローラが開いていたら閉じて下さい．シーケンス図の通り，カードリーダを切断する必要があるため，エクスプローラが開いたままだとWSL2への接続に失敗します．

:::note
USBカードリーダ自体の切断はしないようにして下さい．
:::


## Step2. WSL2へのSDカードのマウント（接続）
続いて，USBIPDを用いてSDカードの接続（マウント）先をWSL2に変更します．[準備](#準備)の章でインストールしたUSBIPDを用いて実行します．
まずは，Powershellを**管理者権限で**起動してください．起動後に，以下のコマンドから接続したUSBデバイス（SDカード）が認識されているかを確認して下さい．

```powershell
> usbipd list
```

無事にSDカードが認識されていれば，そのデバイスのバスIDを使って，以下のコマンドを実行して下さい．

```powershell
> usbipd bind --busid <busid>
```

もし認識されていない場合は，再度，USBを抜き差ししてみて下さい．（私はそれで認識するようになりました）

:::note
次のコマンドからは管理者権限が無くても実行可能です．
:::

次に，デバイスを以下のコマンドでWSL2にマウント（接続）します．このとき，Windows側でファイル操作がおこなわれていると接続できないので，注意して下さい．

```powershell
> usbipd attach --wsl --busid <busid>
```

無事に成功すれば，これでWSL2のLinuxディストリビューション内からSDカードを認識することができます．もし接続に失敗していれば，Windows側で何かしらのファイル操作がおこなわれていないかを確認してみて下さい
なお，デバイスを確認するLinuxコマンドは以下です．

```bash
~$ lsblk
```

## Step3. データの読み出し
ここまで来れば，データの読み出しは目の前です．通常のLinux OSと同様に，接続したデバイスをマウントします．

```bash
# /dev/sdxを/mnt/devにマウント
~$ sudo mount /dev/sdx /mnt/dev
```

以上のコマンドを実行するとSDカードのディレクトリがLinux (on WSL2)から確認できるようになっているはずです．そこからは，お好きな方法でWindowsにデータを転送して下さい．

本記事では，参考までに，`Robocopy`を用いた方法を紹介します．

https://learn.microsoft.com/ja-jp/windows-server/administration/windows-commands/robocopy

`Robocopy`とはWindowsコマンドの1つであり，通常のコピーに比べるとリッチな機能を提供してくれるようです．（説明に間違いがあったらすみません．）

```powershell
# WSL2にマウントしたSDカードのディレクトリをWindowsにコピー
# WSL2内のディレクトリは\\wsl.localhost\<Name of Linux Distribution>\<Full Path of Directory>で指定可能
# Ubuntu内の/mnt/devであれば，\\wsl.localhost\Ubuntu\mnt\dev
# /mnt/devをC:\Download\dataにコピーする場合
> robocopy \\wsl.localhost\Ubuntu\mnt\dev C:\Download\data /E /MT:32
```

上記のコマンドを実行することで，CLIでデータを転送することができます．


## Step4. カードリーダの取り出し
最後に，SDカードを取り出すための手順を紹介します．
[Step3](#step3-データの読み出し)の時点でSDカードはWSL2に接続されています．このまま引き抜いてしまうとデータの破損などの恐れがあります．そのため，まずはカードリーダの接続（マウント）先をWindowsに変更してあげる必要があります．
先ほどとは逆の手順で，まずはLinuxから

```bash
~$ sudo umount /mnt/dev
```

続いてWindows (USBIPD)で

```powershell
> usbipd detach --busid <busid>
```

を実行すると接続が解除されます．
ここまで来れば，普段通りのUSBデバイスを取り外す手順で完了です．


# 最後に
本記事の内容があまり記事になっておらず（少なくとも私は検索で見つけられませんでした），久々に苦戦しました．
どなたかの参考になれば幸いです．