hbkit 0.4.7__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,46 @@
1
+ # Changelog
2
+
3
+ ## 0.5.0
4
+
5
+ ### New
6
+
7
+ - **Backup versions.** `list`, `get`, `verify`, `info`, `doctor` and `tui` read any
8
+ version: `--version N`, `--version @YYYY-MM-DD[ HH:MM[:SS]]` / `--before '…'` (newest
9
+ complete version that started no later than that local time), `--allow-incomplete`.
10
+ The default is still the newest version, but now the newest *complete* one, read for
11
+ every share alike.
12
+ - **`hbk <archive> versions [--porcelain]`** lists versions with start time and status.
13
+ It needs no password.
14
+ - `list` accepts the same glob as `get` when the pattern contains `*`, `?` or `[`.
15
+ - `--` ends the options.
16
+ - Each backup version gets its own cached index; superseded ones are deleted.
17
+
18
+ ### Changed — check your scripts
19
+
20
+ Exit codes are now distinct and documented (README, "Exit codes"):
21
+
22
+ | situation | 0.4.8 | 0.5.0 |
23
+ |---|---|---|
24
+ | password missing (non-interactive) | 1 | 3 |
25
+ | wrong password | 1 or 2 | 3 |
26
+ | glob/pattern matched nothing (`get`, `verify`) | 1 | 5 |
27
+ | pattern matched nothing (`list`) | 0 | 5 |
28
+ | not enough disk space | 1 | 6 |
29
+ | usage error / usage text shown | 1 | 2 |
30
+ | interrupted `get`/`verify` | 0 or 1 | 130 |
31
+ | unexpected internal error | 1 | 2 |
32
+ | requested version missing / not complete | — | 4 |
33
+ | output pipe closed (`… \| head`), `list`/`versions`/`info` | 1 (traceback) | 0 |
34
+ | output pipe closed, `get`/`verify` | 1 (traceback) | 141 |
35
+
36
+ Arguments and options a command used to ignore are refused with code 2: a stray word
37
+ after the destination (an unquoted path with a space), `--strict` outside `get`, `-j` on
38
+ `list`/`info`/`doctor`, a repeated option, `--porcelain` outside `versions`.
39
+
40
+ `hbk --version` alone still prints hbkit's version; `hbk --version 3 <archive> …` now
41
+ selects backup version 3.
42
+
43
+ ### Fixed
44
+
45
+ - Resuming into a directory that holds another version's restore no longer keeps a file
46
+ just because its size matches; the restore record now names each file's source.
@@ -231,7 +231,75 @@ Reconstruct paths by joining `pname_id_v2 -> name_id_v2`. Roots are rows whose p
231
231
  absent from the table or which are self-parented. `mode` is a POSIX mode word — use
232
232
  `S_ISDIR` to separate directories from files.
233
233
 
234
- `Config/version_info.db` lists backup versions with timestamps and completion status.
234
+ ### 5.1 Backup versions [V for the columns below, I for their meaning]
235
+
236
+ Each backup run is a **version** with an integer id (1, 2, 3, …). A version writes one
237
+ `Config/@Share/<share>/<id>.db` per share it covered. Everything else — `virtual_file`,
238
+ `file_chunk`, `chunk_index`, the buckets — is shared by all versions, so the same file in
239
+ two versions differs only in its `version_list` row (`size`, `mtime_sec`,
240
+ `off_virtual_file`). Reading an older version means reading an older `<id>.db`; nothing
241
+ below the share databases changes.
242
+
243
+ `Config/version_info.db`, observed on Hyper Backup 4.2.2-4262 (DSM 7, two versions):
244
+
245
+ ```sql
246
+ CREATE TABLE version_info (
247
+ id INTEGER PRIMARY KEY AUTOINCREMENT, -- the version id, as in <id>.db
248
+ timestamp INTEGER, -- unix seconds, when the version started
249
+ name TEXT, source TEXT, -- source is encrypted on encrypted archives
250
+ share TEXT, -- "share1,share2," - shares in this version
251
+ status TEXT, -- 'Complete' for a finished version
252
+ statistics TEXT, -- JSON: sizes and per-kind counts
253
+ diff_size INTEGER, locked INTEGER NOT NULL default 0, share_info BLOB,
254
+ missing_src TEXT, tag_db_magic BLOB, tag_db_file_size_thr INTEGER,
255
+ has_suspend_dup INTEGER DEFAULT 0, bad_share TEXT DEFAULT '',
256
+ internal_share TEXT DEFAULT '',
257
+ suspend_history TEXT DEFAULT '', -- JSON events: create, complete, ...
258
+ enc_cksum BLOB DEFAULT NULL, depose_time INTEGER DEFAULT -1);
259
+ ```
260
+
261
+ Only `id`, `timestamp` and `status` are relied on. `'Complete'` and `'Failure'` are the
262
+ status values seen so far; hbkit treats **any value other than `'Complete'` as not
263
+ complete** rather than guessing what it means. `timestamp` matched the `create` event in
264
+ `suspend_history`. [V]
265
+
266
+ A second archive (Hyper Backup 4.2.2-4262, encrypted) was read at 8 and again at 11
267
+ versions. Version 8 is a `Failure`: a run that stopped on an error. Its `suspend_history`
268
+ ends in event 5 `fail` where finished versions end in event 6 `complete`, and in the
269
+ 8-version copy its `<id>.db` file lists existed, holding what was backed up before the
270
+ error. Reading it would silently give an incomplete restore, which is why it is never the
271
+ default. The next successful run became version 9 and deleted version 8's `<id>.db` files
272
+ (`Config/version_delete.prog` was written then, with `is_rotate=false`), but left its
273
+ `version_info` row, now naming shares that have no file list for it. `id` is
274
+ `AUTOINCREMENT`, so ids are never reused. [V for the values]
275
+
276
+ Version 11 is a run Hyper Backup reported as **partially completed**, because a source
277
+ folder of the task had been renamed away. It is recorded as `'Complete'`, with event 6
278
+ `complete` in `suspend_history`, like any finished version. Only `missing_src` differs: it
279
+ holds the missing source in the same `/*eNC00*...*/` form as `source` (`NULL` on every
280
+ other version). Its file lists omit that folder and are otherwise whole, so hbkit reads it
281
+ by default. Whether other causes of "partially completed" (unreadable files, say) are also
282
+ recorded as `'Complete'` is not known. hbkit cannot decrypt `missing_src` yet: it is not
283
+ encoded like file names. [V for the values, ? for other causes and the encoding]
284
+
285
+ `Config/@Share/<share>/complete_list.db` holds `complete_list(version_id INTEGER PRIMARY
286
+ KEY)`. It is **not** a reliable completion record: on the same archive the `@AppConfig`
287
+ share's list was empty although both versions were `Complete` in `version_info`, while
288
+ the data share listed both. On the second archive (11 versions) the data share listed
289
+ every `Complete` version but not the `Failure` one, and `@AppConfig` was again empty. hbkit
290
+ does not use it. [V for the observation, ? for meaning]
291
+
292
+ On that archive version 1 had `depose_time` set to the start time of version 2, while
293
+ version 2 kept the default `-1`. On the second archive each `Complete` version had the
294
+ start time of the next **`Complete`** version (version 7 holds version 9's, skipping the
295
+ failed 8), the newest `Complete` version had `0` and the `Failure` version `-1`: it looks
296
+ like "superseded as the newest good version at". The meaning is not known and hbkit
297
+ ignores it, as it does `bad_share` and `locked`.
298
+ [V for the values, ? for meaning]
299
+
300
+ The same archive also showed `Pool/vkey.db` with one row per version (`version_id` 1, 2),
301
+ and index shards with a `_dup` sibling (`0.idx_dup`) instead of a generation suffix; the
302
+ `_dup` copies are ignored.
235
303
 
236
304
  Entries named `@eaDir`, or ending `@SynoEAStream` / `@SynoResource`, are Synology
237
305
  metadata — thumbnails, extended attributes, resource forks — not user data. In the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: hbkit
3
- Version: 0.4.7
3
+ Version: 0.5.0
4
4
  Summary: Recover files from Synology Hyper Backup (.hbk) archives without Synology software
5
5
  Project-URL: Homepage, https://github.com/YordiLorenzo/hbkit
6
6
  Project-URL: Source, https://github.com/YordiLorenzo/hbkit
@@ -97,8 +97,9 @@ live progress bar, throughput, ETA and a failure log.
97
97
 
98
98
  ```sh
99
99
  hbk <archive> doctor # probe an archive, prove it's readable
100
- hbk <archive> info # task name, codec, shares, encryption
101
- hbk <archive> list [pattern] # search the file index
100
+ hbk <archive> info # task name, codec, shares, versions
101
+ hbk <archive> versions [--porcelain] # backup versions, start times, status
102
+ hbk <archive> list [pattern|glob] # search the file index
102
103
  hbk <archive> get <glob> <dest> [-j N] # extract, preserving tree and mtimes
103
104
  hbk <archive> get <glob> <dest> --strict # ...re-verifying checksums on resume
104
105
  hbk <archive> verify <glob> [-j N] # integrity-check, write nothing
@@ -114,7 +115,81 @@ For encrypted archives pass `-p/--password`, set `HBK_PASSWORD`, or let it promp
114
115
  shows a password field when it detects encryption.
115
116
 
116
117
  `<archive>` is a `.hbk` directory, or any drive or folder containing one — it will find it.
117
- Globs match the full archive path, which begins with the share name.
118
+ Globs match the full archive path, which begins with a slash and the share name
119
+ (`"/Photos/*"`, not `"Photos/*"`). `list` takes either plain text (case-insensitive
120
+ substring) or, if it contains `*`, `?` or `[`, the same glob `get` would use.
121
+
122
+ ### Backup versions
123
+
124
+ Hyper Backup keeps many versions of the same data. `list`, `get`, `verify`, `info`,
125
+ `doctor` and `tui` read the **newest complete** version unless told otherwise:
126
+
127
+ | option | reads |
128
+ |---|---|
129
+ | *(none)* | the newest complete version |
130
+ | `--version N` | exactly version `N` (the numbers `versions` prints) |
131
+ | `--version @2026-10-15` | the newest complete version that started **by the end of** that day |
132
+ | `--version '@2026-10-15 03:30'` | … that started no later than 03:30:59 that day |
133
+ | `--before '2026-10-15 23:59'` | the same as `--version '@2026-10-15 23:59'` |
134
+ | `--allow-incomplete` | also accept a version whose backup did not finish |
135
+
136
+ Dates are in the local time of the machine running `hbk` (set `TZ` to change it); a bare
137
+ date runs to local midnight (also on daylight-saving days), a minute to :59, a time with
138
+ seconds is exact. A clock time that does not exist on a spring-forward night is read as
139
+ the hour after; one that occurs twice in autumn means its first occurrence. A version
140
+ counts as complete only if Hyper Backup recorded its status
141
+ as `Complete`, which it also does for a "partially completed" backup, at least one that
142
+ skipped a missing source folder; an unfinished or failed one is refused unless you pass `--allow-incomplete`, which
143
+ on its own reads the newest version whether or not it finished. If no version is
144
+ complete, commands exit with code 4 rather than showing an empty archive.
145
+
146
+ Every share is read from the **same** version, so the default and `--version N` for the
147
+ newest complete `N` give identical results; a share that was not part of that version is
148
+ absent rather than silently taken from an older one. Archives without
149
+ `Config/version_info.db` fall back to the newest database of each share. If the file is
150
+ there but cannot be read (damaged, an unknown layout, caught mid-write, or with no
151
+ versions in it), hbkit cannot tell finished versions from unfinished ones, so it refuses
152
+ (code 2) unless you pass
153
+ `--allow-incomplete`, which then reads the newest file list of each share and says that
154
+ completion was not checked. Whenever there is a choice, the version being read is
155
+ printed on stderr.
156
+
157
+ ```sh
158
+ hbk "$HBK_DIR" versions # human-readable, marks the default
159
+ hbk "$HBK_DIR" versions --porcelain # id<TAB>ISO time<TAB>unix time<TAB>status
160
+ hbk "$HBK_DIR" list "/db_staging/firebird/*" --version @2026-10-15
161
+ hbk "$HBK_DIR" get "/db_staging/firebird/*.gbk" "$TMP" --version @2026-10-15 -j 8
162
+ ```
163
+
164
+ `--porcelain` prints one line per version, oldest first, for example
165
+ `12 2026-10-15T03:00:04+02:00 1792026004 Complete`. `versions` needs no password: the
166
+ version list is stored unencrypted. Each version gets its own index in the cache, so
167
+ switching between them only builds each index once. A rebuilt index replaces the stale
168
+ one for the same archive and version.
169
+
170
+ ### Exit codes
171
+
172
+ Scripts can rely on these:
173
+
174
+ | code | meaning |
175
+ |---|---|
176
+ | 0 | success |
177
+ | 1 | one or more files failed to extract or verify — a checksum mismatch or an unreadable chunk; the failures are listed on stdout |
178
+ | 2 | usage error (including a malformed `--version`), the archive is missing, unreadable or of an unsupported layout, or an unexpected internal error |
179
+ | 3 | the archive is encrypted and no password was given, or it is wrong |
180
+ | 4 | the requested version does not exist, is not complete, or no version matches the date |
181
+ | 5 | the glob (`get`, `verify`) or pattern (`list`) matched no file |
182
+ | 6 | the destination does not have enough free space (`get`) |
183
+ | 130 | interrupted (Ctrl-C) |
184
+ | 141 | `get`, `verify` or another command that acts rather than only prints stopped because its output pipe closed (`… \| head`) before it finished; the outcome is unknown. `list`, `versions` and `info` exit 0 then; a pipe that closes after a command finished keeps that command's code (Linux and macOS; on Windows a closed pipe is a non-zero I/O error for every command) |
185
+
186
+ `doctor` has its own simple contract: 0 when the archive is recoverable, 1 otherwise, with
187
+ the reason in its report. Any argument or option a command would ignore — a second
188
+ `--version`, `--strict` outside `get`, a stray word after the destination (an unquoted
189
+ path with a space) — is refused with code 2 rather than silently dropped. `--version`
190
+ on its own prints hbkit's version; followed by anything it selects a backup version. To
191
+ search for a name that starts with `-`, end the options with `--`:
192
+ `hbk <archive> list -- -draft`.
118
193
 
119
194
  **Start with `doctor`.** It reports the layout it found and then *proves* the archive is
120
195
  readable by rebuilding a random sample of real files with full checksum verification:
@@ -140,7 +215,12 @@ readable by rebuilding a random sample of real files with full checksum verifica
140
215
 
141
216
  ## Behaviour worth knowing
142
217
 
143
- - **Resumable.** Correctly-sized files are skipped, so re-running a big job is cheap.
218
+ - **Resumable.** Correctly-sized files are skipped, so re-running a big job is cheap. A
219
+ file recorded as restored from a *different* backup version is extracted again even if
220
+ its size matches, so restoring another version into the same directory is safe. A file
221
+ whose record does not name its source — restored by hbkit before 0.5 — is extracted
222
+ again once too, since nothing says which version it came from. (A file with no record
223
+ at all, e.g. copied in by hand, is still judged by size alone; `--strict` refuses it.)
144
224
  - **Crash-safe.** Files are written to `.part` and atomically renamed, so an interrupted
145
225
  run never leaves a truncated file that a later resume would trust.
146
226
  - **Layout preserved.** Output goes to `<dest>/<share>/<original path>` with original mtimes.
@@ -148,7 +228,7 @@ readable by rebuilding a random sample of real files with full checksum verifica
148
228
  - **Sidecars skipped.** `@eaDir`, `@SynoEAStream` and `@SynoResource` are Synology
149
229
  metadata — thumbnails and xattr streams, not your data. In one real archive they were
150
230
  half of all entries but under 1% of the bytes.
151
- - **Index cached** per archive in `~/.cache/hbkit` (override with `HBK_CACHE`), rebuilt
231
+ - **Index cached** per archive and version in `~/.cache/hbkit` (override with `HBK_CACHE`), rebuilt
152
232
  automatically when the archive changes. Browsing 1.1M files is instant after the first
153
233
  open; building it takes ~10s locally, ~48s over a network mount.
154
234
 
@@ -271,6 +351,10 @@ Read this before trusting it with the only copy of anything.
271
351
  archive (unencrypted, LZ4, single version, single pool) and a small encrypted one from
272
352
  the same DSM version, both verified byte-exact, plus a 7-version encrypted archive from
273
353
  Hyper Backup 4.2.2 reported in [#4](https://github.com/YordiLorenzo/hbkit/issues/4).
354
+ Version selection was checked byte-exact on a small two-version encrypted Hyper Backup
355
+ 4.2.2 archive (each version's copy of a changed file, by number and by date), and on
356
+ synthetic archives; the version list comes from `Config/version_info.db`, whose layout
357
+ is checked before use.
274
358
  Older record layouts (16-byte `chunk_index`, 28-byte bucket records) and zlib chunks
275
359
  are implemented from disassembly but have not met a real archive of that kind. `doctor`
276
360
  exists precisely so you can find out in seconds rather than mid-restore.
@@ -68,8 +68,9 @@ live progress bar, throughput, ETA and a failure log.
68
68
 
69
69
  ```sh
70
70
  hbk <archive> doctor # probe an archive, prove it's readable
71
- hbk <archive> info # task name, codec, shares, encryption
72
- hbk <archive> list [pattern] # search the file index
71
+ hbk <archive> info # task name, codec, shares, versions
72
+ hbk <archive> versions [--porcelain] # backup versions, start times, status
73
+ hbk <archive> list [pattern|glob] # search the file index
73
74
  hbk <archive> get <glob> <dest> [-j N] # extract, preserving tree and mtimes
74
75
  hbk <archive> get <glob> <dest> --strict # ...re-verifying checksums on resume
75
76
  hbk <archive> verify <glob> [-j N] # integrity-check, write nothing
@@ -85,7 +86,81 @@ For encrypted archives pass `-p/--password`, set `HBK_PASSWORD`, or let it promp
85
86
  shows a password field when it detects encryption.
86
87
 
87
88
  `<archive>` is a `.hbk` directory, or any drive or folder containing one — it will find it.
88
- Globs match the full archive path, which begins with the share name.
89
+ Globs match the full archive path, which begins with a slash and the share name
90
+ (`"/Photos/*"`, not `"Photos/*"`). `list` takes either plain text (case-insensitive
91
+ substring) or, if it contains `*`, `?` or `[`, the same glob `get` would use.
92
+
93
+ ### Backup versions
94
+
95
+ Hyper Backup keeps many versions of the same data. `list`, `get`, `verify`, `info`,
96
+ `doctor` and `tui` read the **newest complete** version unless told otherwise:
97
+
98
+ | option | reads |
99
+ |---|---|
100
+ | *(none)* | the newest complete version |
101
+ | `--version N` | exactly version `N` (the numbers `versions` prints) |
102
+ | `--version @2026-10-15` | the newest complete version that started **by the end of** that day |
103
+ | `--version '@2026-10-15 03:30'` | … that started no later than 03:30:59 that day |
104
+ | `--before '2026-10-15 23:59'` | the same as `--version '@2026-10-15 23:59'` |
105
+ | `--allow-incomplete` | also accept a version whose backup did not finish |
106
+
107
+ Dates are in the local time of the machine running `hbk` (set `TZ` to change it); a bare
108
+ date runs to local midnight (also on daylight-saving days), a minute to :59, a time with
109
+ seconds is exact. A clock time that does not exist on a spring-forward night is read as
110
+ the hour after; one that occurs twice in autumn means its first occurrence. A version
111
+ counts as complete only if Hyper Backup recorded its status
112
+ as `Complete`, which it also does for a "partially completed" backup, at least one that
113
+ skipped a missing source folder; an unfinished or failed one is refused unless you pass `--allow-incomplete`, which
114
+ on its own reads the newest version whether or not it finished. If no version is
115
+ complete, commands exit with code 4 rather than showing an empty archive.
116
+
117
+ Every share is read from the **same** version, so the default and `--version N` for the
118
+ newest complete `N` give identical results; a share that was not part of that version is
119
+ absent rather than silently taken from an older one. Archives without
120
+ `Config/version_info.db` fall back to the newest database of each share. If the file is
121
+ there but cannot be read (damaged, an unknown layout, caught mid-write, or with no
122
+ versions in it), hbkit cannot tell finished versions from unfinished ones, so it refuses
123
+ (code 2) unless you pass
124
+ `--allow-incomplete`, which then reads the newest file list of each share and says that
125
+ completion was not checked. Whenever there is a choice, the version being read is
126
+ printed on stderr.
127
+
128
+ ```sh
129
+ hbk "$HBK_DIR" versions # human-readable, marks the default
130
+ hbk "$HBK_DIR" versions --porcelain # id<TAB>ISO time<TAB>unix time<TAB>status
131
+ hbk "$HBK_DIR" list "/db_staging/firebird/*" --version @2026-10-15
132
+ hbk "$HBK_DIR" get "/db_staging/firebird/*.gbk" "$TMP" --version @2026-10-15 -j 8
133
+ ```
134
+
135
+ `--porcelain` prints one line per version, oldest first, for example
136
+ `12 2026-10-15T03:00:04+02:00 1792026004 Complete`. `versions` needs no password: the
137
+ version list is stored unencrypted. Each version gets its own index in the cache, so
138
+ switching between them only builds each index once. A rebuilt index replaces the stale
139
+ one for the same archive and version.
140
+
141
+ ### Exit codes
142
+
143
+ Scripts can rely on these:
144
+
145
+ | code | meaning |
146
+ |---|---|
147
+ | 0 | success |
148
+ | 1 | one or more files failed to extract or verify — a checksum mismatch or an unreadable chunk; the failures are listed on stdout |
149
+ | 2 | usage error (including a malformed `--version`), the archive is missing, unreadable or of an unsupported layout, or an unexpected internal error |
150
+ | 3 | the archive is encrypted and no password was given, or it is wrong |
151
+ | 4 | the requested version does not exist, is not complete, or no version matches the date |
152
+ | 5 | the glob (`get`, `verify`) or pattern (`list`) matched no file |
153
+ | 6 | the destination does not have enough free space (`get`) |
154
+ | 130 | interrupted (Ctrl-C) |
155
+ | 141 | `get`, `verify` or another command that acts rather than only prints stopped because its output pipe closed (`… \| head`) before it finished; the outcome is unknown. `list`, `versions` and `info` exit 0 then; a pipe that closes after a command finished keeps that command's code (Linux and macOS; on Windows a closed pipe is a non-zero I/O error for every command) |
156
+
157
+ `doctor` has its own simple contract: 0 when the archive is recoverable, 1 otherwise, with
158
+ the reason in its report. Any argument or option a command would ignore — a second
159
+ `--version`, `--strict` outside `get`, a stray word after the destination (an unquoted
160
+ path with a space) — is refused with code 2 rather than silently dropped. `--version`
161
+ on its own prints hbkit's version; followed by anything it selects a backup version. To
162
+ search for a name that starts with `-`, end the options with `--`:
163
+ `hbk <archive> list -- -draft`.
89
164
 
90
165
  **Start with `doctor`.** It reports the layout it found and then *proves* the archive is
91
166
  readable by rebuilding a random sample of real files with full checksum verification:
@@ -111,7 +186,12 @@ readable by rebuilding a random sample of real files with full checksum verifica
111
186
 
112
187
  ## Behaviour worth knowing
113
188
 
114
- - **Resumable.** Correctly-sized files are skipped, so re-running a big job is cheap.
189
+ - **Resumable.** Correctly-sized files are skipped, so re-running a big job is cheap. A
190
+ file recorded as restored from a *different* backup version is extracted again even if
191
+ its size matches, so restoring another version into the same directory is safe. A file
192
+ whose record does not name its source — restored by hbkit before 0.5 — is extracted
193
+ again once too, since nothing says which version it came from. (A file with no record
194
+ at all, e.g. copied in by hand, is still judged by size alone; `--strict` refuses it.)
115
195
  - **Crash-safe.** Files are written to `.part` and atomically renamed, so an interrupted
116
196
  run never leaves a truncated file that a later resume would trust.
117
197
  - **Layout preserved.** Output goes to `<dest>/<share>/<original path>` with original mtimes.
@@ -119,7 +199,7 @@ readable by rebuilding a random sample of real files with full checksum verifica
119
199
  - **Sidecars skipped.** `@eaDir`, `@SynoEAStream` and `@SynoResource` are Synology
120
200
  metadata — thumbnails and xattr streams, not your data. In one real archive they were
121
201
  half of all entries but under 1% of the bytes.
122
- - **Index cached** per archive in `~/.cache/hbkit` (override with `HBK_CACHE`), rebuilt
202
+ - **Index cached** per archive and version in `~/.cache/hbkit` (override with `HBK_CACHE`), rebuilt
123
203
  automatically when the archive changes. Browsing 1.1M files is instant after the first
124
204
  open; building it takes ~10s locally, ~48s over a network mount.
125
205
 
@@ -242,6 +322,10 @@ Read this before trusting it with the only copy of anything.
242
322
  archive (unencrypted, LZ4, single version, single pool) and a small encrypted one from
243
323
  the same DSM version, both verified byte-exact, plus a 7-version encrypted archive from
244
324
  Hyper Backup 4.2.2 reported in [#4](https://github.com/YordiLorenzo/hbkit/issues/4).
325
+ Version selection was checked byte-exact on a small two-version encrypted Hyper Backup
326
+ 4.2.2 archive (each version's copy of a changed file, by number and by date), and on
327
+ synthetic archives; the version list comes from `Config/version_info.db`, whose layout
328
+ is checked before use.
245
329
  Older record layouts (16-byte `chunk_index`, 28-byte bucket records) and zlib chunks
246
330
  are implemented from disassembly but have not met a real archive of that kind. `doctor`
247
331
  exists precisely so you can find out in seconds rather than mid-restore.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hbkit"
7
- version = "0.4.7"
7
+ version = "0.5.0"
8
8
  description = "Recover files from Synology Hyper Backup (.hbk) archives without Synology software"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -43,4 +43,4 @@ hbk-tui = "hbkit.tui:main"
43
43
  packages = ["src/hbkit"]
44
44
 
45
45
  [tool.hatch.build.targets.sdist]
46
- include = ["src/hbkit", "tests", "README.md", "FORMAT.md", "LICENSE"]
46
+ include = ["src/hbkit", "tests", "README.md", "FORMAT.md", "CHANGELOG.md", "LICENSE"]
@@ -1,6 +1,6 @@
1
1
  """hbkit - recover files from Synology Hyper Backup (.hbk) archives without Synology software."""
2
2
 
3
- __version__ = "0.4.7"
3
+ __version__ = "0.5.0"
4
4
 
5
5
  from .archive import (Archive, NeedPassword, UnsupportedArchive, # noqa: F401
6
6
  find_archive_root, is_archive)