콘텐츠로 이동

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("symlink")
  str("target") str(<target>)
str(")")

대상은 그대로 저장됩니다 (해석하지 않음). 상대 및 절대 심링크 모두 지원됩니다.

디렉터리

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의 출력과 일치합니다.