1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

不要なメタデータを排除したアーカイブが欲しい!

1
Last updated at Posted at 2026-03-15

TL;DR

  • 既存フォーマット(tar, zip, 7z)は優秀だが、メタデータを完全に省略できない
  • PNA (Portable Network Archive) は「名前」と「中身」以外すべてオプショナル
  • 再現可能ビルド、プライバシー保護、ストリーミング処理に強い

正直に言います

99%のユースケースでは tar や zip で十分です。

でも、残り1%で本当に困る場面がある。この記事は、その1%に該当する人のために書きました。

困った場面①:メタデータが漏れる

アーカイブを外部に公開するとき、意図せず情報が漏れることがあります。

$ tar tvf suspicious.tar
-rw-r--r-- john/developers 1234 2024-03-15 09:23 secret.txt
  • ユーザー名 john
  • グループ名 developers
  • ファイル更新日時

「別に見られても困らない」?本当にそうでしょうか。

  • 開発者の実名や社内グループ構造が推測される
  • タイムスタンプから開発スケジュールが推測される
  • ファイルシステムの種類や環境が推測される

セキュリティ監査で「不要な情報は含めるな」と言われても、既存フォーマットでは難しい。

困った場面②:再現可能ビルドが壊れる

CI/CDで「同じソースから同じ成果物」を作りたい。当たり前の要求に思えますが、アーカイブが絡むと途端に難しくなります。

# 開発マシンでアーカイブ(uid=501, user=alice)
$ tar cvf a.tar myfile.txt

# CIランナーでアーカイブ(uid=1001, user=runner)
$ tar cvf b.tar myfile.txt

# 同じファイルなのにハッシュが一致しない
$ sha256sum a.tar b.tar
3a7f8b2c...  a.tar
9e8f7a6b...  b.tar  # uid/gid/usernameが異なるため不一致

tarはファイルの所有者情報やタイムスタンプを自動的に記録します。ビルド環境が変われば、ファイルの内容が同一でもアーカイブのハッシュは変わります。

--mtime--owner で固定値を指定すれば回避できます:

$ tar --mtime='1970-01-01' --owner=0 --group=0 -cvf reproducible.tar myfile.txt

しかし:

  • 毎回オプションを指定する必要がある(忘れると壊れる)
  • メタデータフィールド自体は存在する(固定値が埋め込まれる)
  • ツールやスクリプトごとに対応が必要

zipも同様で、タイムスタンプを固定するには外部ツールや後処理が必要です。

PNAという選択肢

Portable Network Archive (PNA) は、これらの問題を設計レベルで解決するために作られたアーカイブフォーマットです。CLIツールとして提供されており、Rust以外の環境でもシェルから直接利用できます。

設計思想:メタデータはオプショナル

PNAでは、エントリに必須なのは:

  • ファイル名(エントリ識別子)
  • ファイル本体(ペイロード)

それ以外はすべて省略可能。 タイムスタンプ、パーミッション、所有者情報、拡張属性——必要なければ記録しません。

# 最小構成でアーカイブ
$ pna create -f minimal.pna myfile.txt

# メタデータを保持してアーカイブ
$ pna create -f full.pna --keep-timestamp --keep-permission myfile.txt

他の特徴

機能 PNA tar zip 7z
ストリーミング書き込み △※1
ストリーミング読み込み
per-fileの圧縮
ソリッド圧縮 △※2
暗号化(256-bit AES) △※3
メタデータ省略 △※4
分割アーカイブ

※1 zip: central directoryが末尾にあるため完全なストリーミングは不可
※2 tar: .tar.gz等の外部圧縮で類似の効果は得られるが、エントリ間の辞書共有ではなくバイト列全体の圧縮であり、per-fileアクセスは失われる
※3 zip: AES暗号化は拡張仕様で実装依存
※4 tar: オプションで固定値にはできるが、フィールド自体は存在する

実際に使ってみる

インストール

# macOS / Linux
curl --proto '=https' --tlsv1.2 -LsSf \
  'https://github.com/ChanTsune/Portable-Network-Archive/releases/latest/download/portable-network-archive-installer.sh' | sh

# または cargo
cargo install portable-network-archive

基本操作

# 作成
$ pna create -f archive.pna file1.txt file2.txt dir/

# 展開
$ pna extract -f archive.pna

# 一覧
$ pna list -f archive.pna

再現可能なアーカイブを作る

# メタデータを含めない(デフォルト)
$ pna create -f reproducible.pna src/

# 何度実行しても同じハッシュ
$ sha256sum reproducible.pna
a1b2c3d4...  reproducible.pna

なぜ再現可能になるのか

tarやzipでは、メタデータフィールドが仕様上必須です。タイムスタンプやオーナー情報は「記録しない」という選択ができず、固定値で埋める必要があります。固定値自体はバイト列として存在するため、ツールやバージョンによって埋め方が異なるリスクが残ります。

PNAではオプショナルなチャンクを物理的に省略します。アーカイブに残るのはファイル名とデータ本体だけなので、同じ入力からは常に同じバイト列が生成されます。

具体的には、以下の条件が揃えば同一ハッシュが保証されます:

  • 入力ファイルの内容とファイル名が同一
  • 圧縮アルゴリズムとそのパラメータが同一
  • エントリの追加順序が同一

暗号化 + 圧縮

# AES-256 + zstd圧縮
$ pna create -f secure.pna \
    --compression zstd \
    --encryption aes \
    --password \
    sensitive-data/

ストリーミング処理

# 標準入出力でパイプ処理
$ tar cf - src/ | pna create -f - --stdin | curl -X PUT ...

# ネットワーク経由で直接展開
$ curl -s https://example.com/data.pna | pna extract -f -

いつPNAを使うべきか

向いているケース

  1. 再現可能ビルドが必要

    • CI/CDでキャッシュキーとしてアーカイブのハッシュを使いたい
    • 「同じ入力→同じ出力」を保証したい
  2. プライバシーが重要

    • 公開するアーカイブに環境情報を含めたくない
    • セキュリティ監査で情報漏洩を指摘された
  3. ストリーミング + 暗号化

    • ネットワーク経由でリアルタイム処理したい
    • かつ、暗号化も必要
  4. per-file圧縮 + ソリッド圧縮の選択

    • 通常はper-fileで個別アクセス可能に
    • 配布用はソリッドで最大圧縮

向いていないケース

  • とにかく互換性重視 → zip/tarを使う
  • 既存ツールチェーンに組み込みたい → zip/tarを使う
  • チームメンバーが新しいツールを覚えたくない → zip/tarを使う

正直に言います。普及度では圧倒的に負けています。 そこは認めた上で、「この場面ではPNAが最適解」というニッチを狙っています。

技術的な背景

PNAはPNG画像フォーマットのチャンク構造に着想を得ています。

PNGから継承した設計原則

PNGのチャンク構造は3つの利点を持ちます:

  1. 未知チャンクのスキップ — 読み取り側が知らないチャンクは長さを見て飛ばせる
  2. チャンク単位の整合性検証 — 各チャンクにCRCが付き、破損を局所的に検出できる
  3. 拡張性 — 新しいチャンクタイプを追加しても既存ツールが壊れない

PNAはこの3原則をアーカイブに転用しました。

チャンクタイプの命名規則

PNGでは、チャンクタイプの4文字の大文字/小文字にそれぞれ意味があります。PNAもこの規則をそのまま継承しています。

文字位置 大文字 小文字
1文字目 Critical(必須、理解できなければエラー) Ancillary(補助的、無視しても安全)
2文字目 Public(標準仕様) Private(アプリ独自)
3文字目 予約(大文字固定)
4文字目 Unsafe to copy(不明なら複製禁止) Safe to copy(不明でも複製可)

たとえば FHED(ファイルヘッダ)は全大文字なので Critical/Public。一方 cTIM(作成日時)は小文字始まりなので Ancillary — つまりチャンク名そのものが「これは省略してよい」という情報を持っているのです。

この設計により、将来新しいメタデータチャンクが追加されても、古いツールは未知の ancillary チャンクを安全にスキップできます。

チャンクの物理レイアウト

各チャンクは以下のバイト列で構成されます:

オフセット サイズ 内容
0 4 bytes データ長(ビッグエンディアン)
4 4 bytes チャンクタイプ(ASCII 4文字)
8 N bytes チャンクデータ
8+N 4 bytes CRC-32

アーカイブの全体構造

┌──────────────────────────────────────┐
│ Archive Header                       │
├──────────────────────────────────────┤
│ Entry 1                              │
│  ├─ File Header Chunk (FHED)         │
│  ├─ [Ancillary] Timestamp (cTIM)     │
│  ├─ [Ancillary] Permission (fPRM)    │
│  ├─ File Data Chunk (FDAT)           │
│  └─ File End Chunk (FEND)            │
├──────────────────────────────────────┤
│ Entry 2                              │
│  └─ ...                              │
├──────────────────────────────────────┤
│ Archive End (AEND)                   │
└──────────────────────────────────────┘

Ancillaryチャンク(タイムスタンプ、パーミッション等)は「チャンクが存在しない」という形で物理的に省略されます。既存フォーマットのように「ダミー値を入れる」必要がないため、ファイルシステム由来のメタデータを一切含まないアーカイブが可能です。

PNGから変えた点

  • エントリの導入 — PNGは単一画像だが、PNAは複数ファイルを扱うためエントリ概念を追加
  • 圧縮・暗号化の柔軟性 — PNGはフィルタ+DEFLATE固定だが、PNAはチャンクデータ層でzstd/AES等を選択可能
  • ソリッドモード — 複数エントリを1つの圧縮ストリームにまとめる選択肢を追加

ライブラリとしての利用

Rustライブラリ libpna も提供しています。

use libpna::{Archive, EntryBuilder, WriteOptions};
use std::fs::File;
use std::io::Write;

fn main() -> std::io::Result<()> {
    let file = File::create("example.pna")?;
    let mut archive = Archive::write_header(file)?;

    // メタデータなしでエントリを追加
    let mut entry = EntryBuilder::new_file(
        "hello.txt".into(),
        WriteOptions::builder().build(),
    )?;
    entry.write_all(b"Hello, PNA!")?;
    archive.add_entry(entry.build()?)?;

    archive.finalize()?;
    Ok(())
}

まとめ

PNAは「tar/zipを置き換える」ことを目指していません。

「tar/zipでは解決しにくい問題を、設計レベルで解決する」 ことを目指しています。

  • 再現可能ビルドが必要なとき
  • メタデータ漏洩を防ぎたいとき
  • ストリーミング + 暗号化が必要なとき

もしこれらに該当するなら、PNAを試してみてください。

リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?