@daugasauron/dolly 0.1.5 → 0.1.6

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.
Files changed (76) hide show
  1. package/README.md +51 -78
  2. package/coi-serviceworker.js +23 -8
  3. package/dist/dolly-build-id.mjs +1 -1
  4. package/dist/dolly-image-build-id.mjs +1 -1
  5. package/dist/dolly-process-0.wasm +0 -0
  6. package/dist/dolly-process-abi.mjs +1 -1
  7. package/dist/dolly-process-dso.mjs +19 -11
  8. package/dist/dolly-process-worker.mjs +88 -33
  9. package/dist/dolly-runtime-worker.mjs +1544 -0
  10. package/dist/dolly.wasm +0 -0
  11. package/host/dso/dso.mjs +2 -2
  12. package/host/dso/module.json +4 -1
  13. package/host/http/abi.mjs +3 -1
  14. package/host/http/broker.mjs +17 -7
  15. package/host/http/http.mjs +19 -5
  16. package/host/http/module.json +3 -1
  17. package/host/http/policy.mjs +13 -6
  18. package/host/http/refusals.mjs +77 -0
  19. package/host/input/abi.mjs +1 -1
  20. package/host/modules.mjs +64 -23
  21. package/host/nena/module.json +2 -1
  22. package/host/nena/nena.mjs +2 -0
  23. package/host/packages/abi.mjs +27 -0
  24. package/host/packages/module.json +6 -4
  25. package/host/packages/packages.mjs +23 -8
  26. package/host/packages/service.mjs +46 -20
  27. package/host/packages/transport.mjs +123 -0
  28. package/host/packages/worker.mjs +13 -9
  29. package/host/requirements.mjs +1 -1
  30. package/host/runtime/abi.mjs +32 -0
  31. package/host/runtime/lease-bridge.mjs +13 -8
  32. package/host/runtime/module.json +3 -3
  33. package/host/runtime/runtime.mjs +3 -3
  34. package/host/snapshot/abi.mjs +2 -1
  35. package/host/snapshot/module.json +1 -1
  36. package/host/snapshot/snapshot.mjs +80 -57
  37. package/host/snapshot/transport.mjs +10 -3
  38. package/host/snapshot/ui.mjs +64 -39
  39. package/host/stack/module.json +1 -0
  40. package/host/stack/stack.mjs +1 -1
  41. package/host/threads/module.json +6 -1
  42. package/host/threads/threads.mjs +32 -13
  43. package/package.json +2 -2
  44. package/{src → page}/browser.mjs +37 -23
  45. package/page/generated.mjs +8 -0
  46. package/{src → page}/image-entry.mjs +10 -6
  47. package/{src → page}/image-inputs.mjs +11 -0
  48. package/{src → page}/image-names.mjs +2 -2
  49. package/{src → page}/kernel-plugin.mjs +1 -1
  50. package/{src → page}/pack-store.mjs +1 -1
  51. package/{src → page}/packaged-snapshot.mjs +56 -46
  52. package/{src → page}/process-constants.mjs +72 -15
  53. package/{src → page}/process-supervisor.mjs +155 -227
  54. package/{src → page}/snapshot-records.mjs +63 -44
  55. package/{src → page}/static-asset.mjs +36 -20
  56. package/{src → page}/version.mjs +1 -1
  57. package/{src → page}/worker-image.mjs +20 -9
  58. package/{src → site}/build-worker.mjs +36 -25
  59. package/{src → site}/custom-image.mjs +2 -10
  60. package/{src → site}/dollyfile-graph.mjs +1 -1
  61. package/{src → site}/dollyfile-view.mjs +1 -1
  62. package/{src → site}/image-artifact.mjs +9 -8
  63. package/{src → site}/image-build.mjs +4 -4
  64. package/{src → site}/image-builder.mjs +5 -4
  65. package/site/offline.mjs +53 -0
  66. package/{src → site}/session-store.mjs +47 -38
  67. package/src/runtime-worker.mjs +0 -57
  68. /package/{src → page}/build-log.mjs +0 -0
  69. /package/{src → page}/images.mjs +0 -0
  70. /package/{src → page}/page-chords.mjs +0 -0
  71. /package/{src → page}/page-indicators.mjs +0 -0
  72. /package/{src → page}/process-abi.mjs +0 -0
  73. /package/{src → page}/sha256.mjs +0 -0
  74. /package/{src → page}/terminal-text.mjs +0 -0
  75. /package/{src → page}/wasm-interface.mjs +0 -0
  76. /package/{src → site}/alphabetical.mjs +0 -0
@@ -2,18 +2,18 @@
2
2
  // one's metadata, checked against the catalog and the recipes the directory
3
3
  // serves, and its packs: streamed into a booting kernel, or merged in path
4
4
  // order into the image's canonical snapshot.
5
- import { DOLLY_IMAGE_BUILD_ID } from "../dist/dolly-image-build-id.mjs";
5
+ import { DOLLY_IMAGE_BUILD_ID } from "./generated.mjs";
6
6
  import { DOLLY_IMAGES, imageBase } from "./images.mjs";
7
- import { imageInputs, imageInputsMatch } from "./image-inputs.mjs";
7
+ import { imageInputs, imageInputsMatch, recipesDigest } from "./image-inputs.mjs";
8
8
  import { hostRequirements } from "../host/requirements.mjs";
9
- import { siteReference, sitePath, decodeStaticAsset, sha256 } from "./static-asset.mjs";
10
- import { scanSnapshotRecords, validateSnapshotPacks, MAX_SNAPSHOT_BYTES as snapshotSizeLimit } from "./snapshot-records.mjs";
9
+ import { siteReference, decodeStaticAsset, hex } from "./static-asset.mjs";
10
+ import { scanSnapshotRecords, validateSnapshotPacks, snapshotHeader, recordHeader, MAX_SNAPSHOT_BYTES as snapshotSizeLimit } from "./snapshot-records.mjs";
11
+ import { DOLLY_SNAPSHOT_MAX_PATHS } from "../host/runtime/abi.mjs";
11
12
  import { unretainedPath } from "./image-names.mjs";
12
13
  import { openPackStore } from "./pack-store.mjs";
13
14
  import { Sha256 } from "./sha256.mjs";
14
15
  const definitionOf = image => DOLLY_IMAGES.find(definition => definition.image === image);
15
16
  const encoder = new TextEncoder();
16
- const expectedRecipes = image => definitionOf(image).recipes;
17
17
 
18
18
  function validSnapshotPath(path) {
19
19
  return typeof path === "string" && path.startsWith("/") && path.length > 1 &&
@@ -23,21 +23,6 @@ function validSnapshotPath(path) {
23
23
  !unretainedPath(path);
24
24
  }
25
25
 
26
- // The recipes the directory serves for IMAGE (its page shows them) are the ones
27
- // that built the image a boot runs. They are fetched together.
28
- export async function verifyVisibleRecipes(image) {
29
- await Promise.all(expectedRecipes(image).map(async recipe => {
30
- const response = await fetch(new URL(sitePath(recipe.sourcePath).slice(1), imageBase), {
31
- credentials: "same-origin", redirect: "error",
32
- });
33
- if (!response.ok) throw new Error(`${recipe.sourcePath} returned HTTP ${response.status}`);
34
- const bytes = await response.arrayBuffer();
35
- if (bytes.byteLength !== recipe.byteLength || await sha256(bytes) !== recipe.sha256) {
36
- throw new Error(`${recipe.sourcePath} does not match the packaged snapshot recipe`);
37
- }
38
- }));
39
- }
40
-
41
26
  // The image a FROM, COPY or INSTALL row names: its recipe at that path and pin.
42
27
  const referenced = ({ location, sha256 }) => DOLLY_IMAGES.find(candidate =>
43
28
  siteReference(candidate.dollyfile) === location && candidate.sha256 === sha256);
@@ -64,6 +49,14 @@ async function importMetadata(image) {
64
49
  }
65
50
  }
66
51
 
52
+ // The metadata an image starts from: its own, checked against its catalog
53
+ // record (its recipes, the pins of its inputs, its modules). That the snapshots
54
+ // of its inputs are the ones it was built on is the build's and the release's
55
+ // to check (loadPackagedSnapshotMetadata, scripts/site-release.mjs).
56
+ export async function loadImageMetadata(image) {
57
+ return checkedMetadata(image, await importMetadata(image), null);
58
+ }
59
+
67
60
  // An image's metadata, checked against the catalog and the metadata of every
68
61
  // image it is built from, which are fetched together.
69
62
  export async function loadPackagedSnapshotMetadata(image) {
@@ -75,19 +68,18 @@ export async function loadPackagedSnapshotMetadata(image) {
75
68
  }
76
69
 
77
70
  // METADATA, checked as IMAGE's against the catalog and CHECKED, the metadata
78
- // of the images it is built from.
71
+ // of the images it is built from, unless CHECKED is null.
79
72
  function checkedMetadata(image, metadata, checked) {
80
- const recipes = expectedRecipes(image);
81
73
  if (metadata === null || typeof metadata !== "object" ||
82
74
  metadata.image !== image || metadata.buildId !== DOLLY_IMAGE_BUILD_ID ||
83
75
  metadata.formatVersion !== 2 || metadata.identityVersion !== 2 ||
84
- JSON.stringify(metadata.recipes) !== JSON.stringify(recipes) ||
76
+ !Array.isArray(metadata.recipes) || recipesDigest(metadata.recipes) !== definitionOf(image).recipesSha256 ||
85
77
  JSON.stringify(hostRequirements(metadata.hostRequirements)) !== JSON.stringify(definitionOf(image).hostRequirements) ||
86
78
  !Number.isSafeInteger(metadata.byteLength) || metadata.byteLength <= 0 ||
87
79
  metadata.byteLength > snapshotSizeLimit || metadata.encoding !== "packs" ||
88
80
  !/^[0-9a-f]{64}$/.test(metadata.sha256) ||
89
81
  !Array.isArray(metadata.manifest) || metadata.manifest.length === 0 ||
90
- metadata.manifest.length > 100_000) {
82
+ metadata.manifest.length > DOLLY_SNAPSHOT_MAX_PATHS) {
91
83
  throw new Error("The packaged system snapshot metadata does not match this Dolly build");
92
84
  }
93
85
  validateSnapshotPacks(metadata);
@@ -117,6 +109,7 @@ function checkedMetadata(image, metadata, checked) {
117
109
  throw new Error(`The packaged system snapshot is missing ${required}`);
118
110
  }
119
111
  }
112
+ if (checked === null) return metadata;
120
113
  const expectedInputs = definitionOf(image).artifacts.map(reference =>
121
114
  ({ recipeSha256: reference.sha256, sha256: checked.get(referenced(reference).image).sha256 }));
122
115
  if (!imageInputsMatch(inputs, expectedInputs)) throw new Error("The packaged system snapshot has stale image inputs");
@@ -129,13 +122,32 @@ function checkedMetadata(image, metadata, checked) {
129
122
  // checked against its declared length. The consumer checks each part against
130
123
  // its digest and then calls its verified(), which keeps a downloaded pack; a
131
124
  // part it does not verify is not kept, or no longer.
125
+ // Packs are asked for ahead of the one being read, at most PREFETCH_PACKS of
126
+ // them and PREFETCH_BYTES of compressed bytes (one at least), and handed over
127
+ // in order: on a network their round trips overlap instead of adding up.
128
+ const PREFETCH_PACKS = 8, PREFETCH_BYTES = 64 * 1024 * 1024;
132
129
  async function* packagedSnapshotParts(metadata, signal) {
133
130
  const packs = validateSnapshotPacks(metadata), store = await openPackStore(metadata.image, packs);
134
- let complete = false;
131
+ const opened = async pack => {
132
+ const kept = await store.kept(pack);
133
+ return kept ? { part: kept, downloaded: false }
134
+ : { part: await store.keeping(pack, await downloadedPack(pack, signal)), downloaded: true };
135
+ };
136
+ const ahead = [];
137
+ let next = 0, aheadBytes = 0, complete = false;
135
138
  try {
136
- for (const pack of packs) {
139
+ while (next < packs.length || ahead.length) {
137
140
  signal?.throwIfAborted();
138
- const part = await store.kept(pack) ?? await store.keeping(pack, await downloadedPack(pack, signal));
141
+ while (next < packs.length && (!ahead.length ||
142
+ ahead.length < PREFETCH_PACKS && aheadBytes + packs[next].encodedByteLength <= PREFETCH_BYTES)) {
143
+ const pack = packs[next++], opening = opened(pack);
144
+ opening.catch(() => {});
145
+ ahead.push({ pack, opening });
146
+ aheadBytes += pack.encodedByteLength;
147
+ }
148
+ const { pack, opening } = ahead.shift();
149
+ aheadBytes -= pack.encodedByteLength;
150
+ const { part } = await opening;
139
151
  let verified = false;
140
152
  try {
141
153
  yield { ...pack, body: part.body, verified: () => { verified = true; return part.keep(); } };
@@ -145,6 +157,14 @@ async function* packagedSnapshotParts(metadata, signal) {
145
157
  }
146
158
  complete = true;
147
159
  } finally {
160
+ // Packs asked for and never read: their downloads stop and are not kept;
161
+ // a kept one stays kept.
162
+ for (const { opening } of ahead) {
163
+ void opening.then(({ part, downloaded }) => {
164
+ void part.body.cancel().catch(() => {});
165
+ if (downloaded) void part.discard();
166
+ }, () => {});
167
+ }
148
168
  store.close(complete);
149
169
  }
150
170
  }
@@ -205,37 +225,27 @@ function streamOf(bytes) {
205
225
  }, { highWaterMark: 0 });
206
226
  }
207
227
 
208
- // The sink owns incremental hashing. Every part is checked before another is
209
- // requested; the caller verifies the complete canonical image before booting.
228
+ // Each part's bytes go to `write` as they arrive and are checked against the
229
+ // pack's digest (WebCrypto's SHA-256, which is native) before `endPart` and
230
+ // before another part is read; a mismatch ends the restore.
210
231
  export async function streamPackagedSystemSnapshot(metadata, write, endPart, signal) {
211
232
  for await (const part of packagedSnapshotParts(metadata, signal)) {
233
+ const bytes = new Uint8Array(part.byteLength);
212
234
  let size = 0;
213
235
  for await (const chunk of chunksOf(gunzip(part.body), signal)) {
214
236
  if (chunk.length > part.byteLength - size) throw new Error("snapshot exceeds declared size");
237
+ bytes.set(chunk, size);
215
238
  await write(chunk);
216
239
  size += chunk.length;
217
240
  }
218
- if (size !== part.byteLength || await endPart() !== part.sha256) throw new Error("snapshot integrity mismatch");
241
+ if (size !== part.byteLength || hex(await crypto.subtle.digest("SHA-256", bytes)) !== part.sha256) {
242
+ throw new Error("snapshot integrity mismatch");
243
+ }
244
+ await endPart();
219
245
  await part.verified();
220
246
  }
221
247
  }
222
248
 
223
- function snapshotHeader(count) {
224
- const bytes = new Uint8Array(16), view = new DataView(bytes.buffer);
225
- bytes.set(encoder.encode("DOLLYSNP"));
226
- view.setUint32(8, 2, true);
227
- view.setUint32(12, count, true);
228
- return bytes;
229
- }
230
-
231
- function recordHeader(kind, path, size) {
232
- const bytes = new Uint8Array(16 + path.length), view = new DataView(bytes.buffer);
233
- view.setUint32(0, kind, true);
234
- view.setUint32(4, path.length, true);
235
- view.setBigUint64(8, BigInt(size), true);
236
- bytes.set(path, 16);
237
- return bytes;
238
- }
239
249
 
240
250
  function compareBytes(left, right) {
241
251
  for (let index = 0; index < Math.min(left.length, right.length); index += 1) {
@@ -117,6 +117,7 @@ export const DOLLY_PROCESS_TERMINAL_MODE_SET = 4;
117
117
  export const DOLLY_PROCESS_TERMINAL_SIZE = 5;
118
118
  export const DOLLY_PROCESS_TERMINAL_PUBLISH_RESULT = 6;
119
119
  export const DOLLY_PROCESS_TERMINAL_FOREGROUND = 7;
120
+ export const DOLLY_PROCESS_TERMINAL_SIZE_SET = 8;
120
121
  export const DOLLY_PROCESS_LOCK_SHARED = 0;
121
122
  export const DOLLY_PROCESS_LOCK_EXCLUSIVE = 1;
122
123
  export const DOLLY_PROCESS_LOCK_UNLOCK = 2;
@@ -204,41 +205,97 @@ export const DOLLY_ERRNO = Object.freeze({
204
205
  });
205
206
  export const DOLLY_PROCESS_SIZEOF = Object.freeze({
206
207
  dolly_process_vector_sizes: 16,
208
+ dolly_process_exit_request: 8,
207
209
  dolly_process_fd_io_request: 16,
208
210
  dolly_process_fd_pread_request: 24,
209
211
  dolly_process_fd_truncate_request: 16,
210
212
  dolly_process_fd_request: 8,
211
213
  dolly_process_timestamp: 16,
212
214
  dolly_process_fd_times_request: 40,
215
+ dolly_process_io_result: 8,
213
216
  dolly_process_fd_dup_request: 16,
217
+ dolly_process_fd_dup_response: 8,
214
218
  dolly_process_fd_flags: 8,
215
219
  dolly_process_fd_lock_request: 32,
216
220
  dolly_process_fd_lock_response: 24,
221
+ dolly_process_pipe_request: 8,
222
+ dolly_process_pipe_response: 8,
217
223
  dolly_process_poll_request: 16,
218
224
  dolly_process_poll_query: 8,
219
225
  dolly_process_poll_response: 16,
220
226
  dolly_process_poll_result: 8,
221
- dolly_process_directory_entry: 24,
222
227
  dolly_process_directory_request: 24,
223
- dolly_process_stat_response: 88,
224
- dolly_process_filesystem_stat_response: 96,
225
- dolly_process_spawn_request: 72,
226
- dolly_process_fd_mapping: 8,
228
+ dolly_process_directory_entry: 24,
229
+ dolly_process_fd_seek_request: 16,
230
+ dolly_process_fd_seek_response: 8,
231
+ dolly_process_clock_request: 16,
232
+ dolly_process_clock_response: 8,
233
+ dolly_process_clock_sleep_request: 16,
227
234
  dolly_process_exec_state: 16,
235
+ dolly_process_fd_mapping: 8,
236
+ dolly_process_spawn_request: 72,
237
+ dolly_process_spawn_response: 8,
228
238
  dolly_process_exec_request: 48,
229
- dolly_process_pipe_request: 8,
230
- dolly_process_two_path_request: 16,
231
- dolly_process_path_times_request: 48,
232
- dolly_process_terminal_request: 24,
233
- dolly_process_terminal_response: 16,
234
- dolly_process_clock_sleep_request: 16,
235
- dolly_process_exit_request: 8,
236
239
  dolly_process_wait_request: 8,
237
240
  dolly_process_wait_response: 16,
241
+ dolly_process_info_response: 8,
238
242
  dolly_process_signal_request: 8,
239
- dolly_process_alarm: 16,
240
243
  dolly_process_signal_dispositions: 8,
241
- dolly_process_fd_seek_request: 16,
242
- dolly_process_clock_request: 16,
244
+ dolly_process_alarm: 16,
245
+ dolly_process_terminal_request: 24,
246
+ dolly_process_terminal_response: 16,
243
247
  dolly_process_path_request: 16,
248
+ dolly_process_path_times_request: 48,
249
+ dolly_process_path_open_response: 8,
250
+ dolly_process_stat_response: 88,
251
+ dolly_process_filesystem_stat_response: 96,
252
+ dolly_process_two_path_request: 16,
253
+ });
254
+ export const DOLLY_PROCESS_OFFSETOF = Object.freeze({
255
+ dolly_process_vector_sizes: Object.freeze({"count":0, "reserved":4, "bytes":8}),
256
+ dolly_process_exit_request: Object.freeze({"status":0, "signal_number":4}),
257
+ dolly_process_fd_io_request: Object.freeze({"descriptor":0, "reserved":4, "size":8}),
258
+ dolly_process_fd_pread_request: Object.freeze({"descriptor":0, "reserved":4, "offset":8, "size":16}),
259
+ dolly_process_fd_truncate_request: Object.freeze({"descriptor":0, "reserved":4, "size":8}),
260
+ dolly_process_fd_request: Object.freeze({"descriptor":0, "reserved":4}),
261
+ dolly_process_timestamp: Object.freeze({"seconds":0, "nanoseconds":8, "flags":12}),
262
+ dolly_process_fd_times_request: Object.freeze({"descriptor":0, "reserved":4, "access":8, "modification":24}),
263
+ dolly_process_io_result: Object.freeze({"size":0}),
264
+ dolly_process_fd_dup_request: Object.freeze({"source_descriptor":0, "target_descriptor":4, "flags":8, "reserved":12}),
265
+ dolly_process_fd_dup_response: Object.freeze({"descriptor":0, "reserved":4}),
266
+ dolly_process_fd_flags: Object.freeze({"descriptor":0, "flags":4}),
267
+ dolly_process_fd_lock_request: Object.freeze({"descriptor":0, "flags":4, "type":8, "whence":12, "start":16, "length":24}),
268
+ dolly_process_fd_lock_response: Object.freeze({"type":0, "pid":4, "start":8, "length":16}),
269
+ dolly_process_pipe_request: Object.freeze({"flags":0, "reserved":4}),
270
+ dolly_process_pipe_response: Object.freeze({"read_descriptor":0, "write_descriptor":4}),
271
+ dolly_process_poll_request: Object.freeze({"deadline_nanoseconds":0, "count":8, "reserved":12}),
272
+ dolly_process_poll_query: Object.freeze({"descriptor":0, "events":4, "reserved":6}),
273
+ dolly_process_poll_response: Object.freeze({"ready":0, "count":4, "reserved":8}),
274
+ dolly_process_poll_result: Object.freeze({"events":0, "reserved":2, "reserved2":4}),
275
+ dolly_process_directory_request: Object.freeze({"descriptor":0, "maximum_entries":4, "cookie":8, "reserved":16}),
276
+ dolly_process_directory_entry: Object.freeze({"inode":0, "next_cookie":8, "file_type":16, "name_size":20}),
277
+ dolly_process_fd_seek_request: Object.freeze({"descriptor":0, "whence":4, "offset":8}),
278
+ dolly_process_fd_seek_response: Object.freeze({"offset":0}),
279
+ dolly_process_clock_request: Object.freeze({"clock_id":0, "reserved":4, "precision_nanoseconds":8}),
280
+ dolly_process_clock_response: Object.freeze({"nanoseconds":0}),
281
+ dolly_process_clock_sleep_request: Object.freeze({"clock_id":0, "flags":4, "deadline_nanoseconds":8}),
282
+ dolly_process_exec_state: Object.freeze({"blocked_signals":0, "ignored_signals":4, "pending_signals":8, "reserved":12}),
283
+ dolly_process_fd_mapping: Object.freeze({"source_descriptor":0, "target_descriptor":4}),
284
+ dolly_process_spawn_request: Object.freeze({"flags":0, "argument_count":4, "environment_count":8, "cwd_size":12, "mapping_count":16, "descriptor_inheritance":20, "reserved":24, "path_size":28, "argument_bytes":32, "environment_bytes":40, "deadline_nanoseconds":48, "signals":56}),
285
+ dolly_process_spawn_response: Object.freeze({"pid":0, "reserved":4}),
286
+ dolly_process_exec_request: Object.freeze({"signals":0, "argument_count":16, "environment_count":20, "path_size":24, "reserved":28, "argument_bytes":32, "environment_bytes":40}),
287
+ dolly_process_wait_request: Object.freeze({"pid":0, "flags":4}),
288
+ dolly_process_wait_response: Object.freeze({"pid":0, "status":4, "signal_number":8, "reserved":12}),
289
+ dolly_process_info_response: Object.freeze({"pid":0, "parent_pid":4}),
290
+ dolly_process_signal_request: Object.freeze({"pid":0, "signal_number":4}),
291
+ dolly_process_signal_dispositions: Object.freeze({"ignored_signals":0, "handled_signals":4}),
292
+ dolly_process_alarm: Object.freeze({"value_nanoseconds":0, "interval_nanoseconds":8}),
293
+ dolly_process_terminal_request: Object.freeze({"operation":0, "descriptor":4, "flags":8, "reserved":12, "deadline_nanoseconds":16}),
294
+ dolly_process_terminal_response: Object.freeze({"value":0, "columns":8, "rows":12}),
295
+ dolly_process_path_request: Object.freeze({"directory_descriptor":0, "flags":4, "reserved":8, "path_size":12}),
296
+ dolly_process_path_times_request: Object.freeze({"directory_descriptor":0, "flags":4, "reserved":8, "path_size":12, "access":16, "modification":32}),
297
+ dolly_process_path_open_response: Object.freeze({"descriptor":0, "reserved":4}),
298
+ dolly_process_stat_response: Object.freeze({"device":0, "inode":8, "size":16, "access_nanoseconds":24, "modification_nanoseconds":32, "change_nanoseconds":40, "blocks":48, "mode":56, "link_count":60, "user":64, "group":68, "block_size":72, "file_type":76, "reserved":80}),
299
+ dolly_process_filesystem_stat_response: Object.freeze({"type":0, "block_size":8, "blocks":16, "blocks_free":24, "blocks_available":32, "files":40, "files_free":48, "maximum_name_length":56, "fragment_size":64, "flags":72, "filesystem_id":80, "reserved":88}),
300
+ dolly_process_two_path_request: Object.freeze({"old_directory_descriptor":0, "new_directory_descriptor":4, "old_path_size":8, "new_path_size":12}),
244
301
  });