NAR 와이어 형식¶
NAR (Nix Archive)은 Nix가 파일시스템 트리를 직렬화하는 데 사용하는 결정론적 아카이브 형식입니다. 핵심 속성은 재현성입니다 — 동일한 파일시스템 내용은 타임스탬프, 소유권, inode 번호 등 기타 메타데이터에 관계없이 항상 동일한 바이트 시퀀스를 생성합니다.
와이어 프리미티브¶
모든 데이터는 단일 프리미티브를 사용하여 프레이밍됩니다:
문자열/블롭 인코딩¶
┌──────────────────┬────────────────────┬─────────────┐
│ uint64_le(len) │ raw bytes (len) │ 제로 패딩 │
│ (8 바이트) │ │ 8바이트 │
│ │ │ 경계까지 │
└──────────────────┴────────────────────┴─────────────┘
- 길이는 항상 리틀엔디안 uint64 (8바이트)
- 내용은 길이 바로 뒤에 위치
- 패딩: 8바이트 정렬을 위한
(8 - len % 8) % 8개의 제로 바이트 - 빈 문자열: 길이 = 0, 내용 바이트 없음, 패딩 없음
예제:
| 문자열 | 길이 (16진수 LE) | 내용 | 패딩 | 합계 |
|---|---|---|---|---|
"" |
00 00 00 00 00 00 00 00 |
(없음) | (없음) | 8 바이트 |
"(" |
01 00 00 00 00 00 00 00 |
28 |
7개 제로 | 16 바이트 |
"type" |
04 00 00 00 00 00 00 00 |
74 79 70 65 |
4개 제로 | 16 바이트 |
"regular" |
07 00 00 00 00 00 00 00 |
72 65 67 75 6c 61 72 |
1개 제로 | 16 바이트 |
"hello" |
05 00 00 00 00 00 00 00 |
68 65 6c 6c 6f |
3개 제로 | 16 바이트 |
NAR의 모든 토큰 — 키워드, 이름, 콘텐츠 블롭 — 은 같은 인코딩을 사용합니다.
문법¶
nar = str("nix-archive-1") node
node = str("(") entry str(")")
entry = str("type") (regular | symlink | directory)
regular = str("regular") [str("executable") str("")]
str("contents") str(<file-data>)
symlink = str("symlink") str("target") str(<target-path>)
directory = str("directory") { dir_entry }
dir_entry = str("entry") str("(")
str("name") str(<entry-name>)
str("node") node
str(")")
str(x)는 위에서 설명한 와이어 인코딩입니다.
파일 타입¶
일반 파일¶
str("(")
str("type") str("regular")
[str("executable") str("")] ← 실행 비트가 설정된 경우에만
str("contents") str(<data>)
str(")")
실행 플래그가 보존되는 유일한 퍼미션 정보입니다. 0644 vs 0755 같은 모드 비트는 실행 가능 여부로만 축소됩니다.
심링크¶
대상은 그대로 저장됩니다 (해석하지 않음). 상대 및 절대 심링크 모두 지원됩니다.
디렉터리¶
str("(")
str("type") str("directory")
str("entry") str("(")
str("name") str("a.txt")
str("node") <a.txt의 재귀 노드>
str(")")
str("entry") str("(")
str("name") str("b.txt")
str("node") <b.txt의 재귀 노드>
str(")")
str(")")
엔트리는 반드시 정렬되어야 함
디렉터리 엔트리는 이름순으로 반드시 사전식 정렬되어야 합니다. 이것은 결정성을 위해 중요합니다.
NAR이 보존하는 것¶
| 보존됨 | 보존되지 않음 |
|---|---|
| 파일 내용 | 타임스탬프 (mtime, ctime, atime) |
| 파일 타입 (일반, 심링크, 디렉터리) | 소유권 (uid, gid) |
| 실행 비트 | 퍼미션 모드 (+x 이상) |
| 심링크 대상 | inode 번호 |
| 디렉터리 구조 | 확장 속성 |
| 엔트리 이름 | 하드 링크 (별도 파일로 직렬화) |
풀이 예제¶
"hello" (5바이트, 실행 불가)를 포함한 파일의 NAR 직렬화:
오프셋 바이트 의미
------ ----- -----
0x00 0e 00 00 00 00 00 00 00 "nix-archive-1"의 길이 = 14
0x08 6e 69 78 2d 61 72 63 68 "nix-arch"
0x10 69 76 65 2d 31 00 00 00 "ive-1" + 2바이트 패딩
0x18 01 00 00 00 00 00 00 00 "("의 길이 = 1
0x20 28 00 00 00 00 00 00 00 "(" + 7바이트 패딩
0x28 04 00 00 00 00 00 00 00 "type"의 길이 = 4
0x30 74 79 70 65 00 00 00 00 "type" + 4바이트 패딩
0x38 07 00 00 00 00 00 00 00 "regular"의 길이 = 7
0x40 72 65 67 75 6c 61 72 00 "regular" + 1바이트 패딩
0x48 08 00 00 00 00 00 00 00 "contents"의 길이 = 8
0x50 63 6f 6e 74 65 6e 74 73 "contents" (패딩 불필요)
0x58 05 00 00 00 00 00 00 00 콘텐츠의 길이 = 5
0x60 68 65 6c 6c 6f 00 00 00 "hello" + 3바이트 패딩
0x68 01 00 00 00 00 00 00 00 ")"의 길이 = 1
0x70 29 00 00 00 00 00 00 00 ")" + 7바이트 패딩
합계: 120 바이트
SHA-256: 0a430879c266f8b57f4092a0f935cf3facd48bbccde5760d4748ca4051716969
"hello"를 포함한 파일에 대한 nix hash path의 출력과 일치합니다.