@vibe-agent-toolkit/utils 0.2.0-rc.11 → 0.2.0-rc.12

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 (322) hide show
  1. package/README.md +111 -9
  2. package/dist/archive/archive.d.ts +129 -0
  3. package/dist/archive/archive.d.ts.map +1 -0
  4. package/dist/archive/archive.js +223 -0
  5. package/dist/archive/archive.js.map +1 -0
  6. package/dist/archive/entries.d.ts +132 -0
  7. package/dist/archive/entries.d.ts.map +1 -0
  8. package/dist/archive/entries.js +223 -0
  9. package/dist/archive/entries.js.map +1 -0
  10. package/dist/archive/limits.d.ts +39 -0
  11. package/dist/archive/limits.d.ts.map +1 -0
  12. package/dist/archive/limits.js +59 -0
  13. package/dist/archive/limits.js.map +1 -0
  14. package/dist/archive/records.d.ts +14 -0
  15. package/dist/archive/records.d.ts.map +1 -0
  16. package/dist/archive/records.js +3 -0
  17. package/dist/archive/records.js.map +1 -0
  18. package/dist/archive/tar-reader.d.ts +18 -0
  19. package/dist/archive/tar-reader.d.ts.map +1 -0
  20. package/dist/archive/tar-reader.js +173 -0
  21. package/dist/archive/tar-reader.js.map +1 -0
  22. package/dist/archive/zip-reader.d.ts +76 -0
  23. package/dist/archive/zip-reader.d.ts.map +1 -0
  24. package/dist/archive/zip-reader.js +376 -0
  25. package/dist/archive/zip-reader.js.map +1 -0
  26. package/dist/archive.d.ts +14 -0
  27. package/dist/archive.d.ts.map +1 -0
  28. package/dist/archive.js +12 -0
  29. package/dist/archive.js.map +1 -0
  30. package/dist/asset-reference.d.ts +17 -1
  31. package/dist/asset-reference.d.ts.map +1 -1
  32. package/dist/asset-reference.js +31 -7
  33. package/dist/asset-reference.js.map +1 -1
  34. package/dist/dirent-kind.d.ts +13 -40
  35. package/dist/dirent-kind.d.ts.map +1 -1
  36. package/dist/dirent-kind.js +21 -69
  37. package/dist/dirent-kind.js.map +1 -1
  38. package/dist/entrypoint.d.ts +2 -2
  39. package/dist/entrypoint.d.ts.map +1 -1
  40. package/dist/entrypoint.js +4 -3
  41. package/dist/entrypoint.js.map +1 -1
  42. package/dist/env-flag.d.ts +2 -0
  43. package/dist/env-flag.d.ts.map +1 -1
  44. package/dist/env-flag.js +2 -0
  45. package/dist/env-flag.js.map +1 -1
  46. package/dist/errors/confirmed-absent.d.ts +41 -0
  47. package/dist/errors/confirmed-absent.d.ts.map +1 -0
  48. package/dist/errors/confirmed-absent.js +43 -0
  49. package/dist/errors/confirmed-absent.js.map +1 -0
  50. package/dist/errors/errno-table.d.ts +177 -0
  51. package/dist/errors/errno-table.d.ts.map +1 -0
  52. package/dist/errors/errno-table.js +343 -0
  53. package/dist/errors/errno-table.js.map +1 -0
  54. package/dist/errors/fs-boundary.d.ts +36 -0
  55. package/dist/errors/fs-boundary.d.ts.map +1 -0
  56. package/dist/errors/fs-boundary.js +121 -0
  57. package/dist/errors/fs-boundary.js.map +1 -0
  58. package/dist/errors/fs-fault.d.ts +176 -0
  59. package/dist/errors/fs-fault.d.ts.map +1 -0
  60. package/dist/errors/fs-fault.js +215 -0
  61. package/dist/errors/fs-fault.js.map +1 -0
  62. package/dist/errors/git-errno.d.ts +13 -0
  63. package/dist/errors/git-errno.d.ts.map +1 -0
  64. package/dist/errors/git-errno.js +45 -0
  65. package/dist/errors/git-errno.js.map +1 -0
  66. package/dist/errors/path-present.d.ts +72 -0
  67. package/dist/errors/path-present.d.ts.map +1 -0
  68. package/dist/errors/path-present.js +110 -0
  69. package/dist/errors/path-present.js.map +1 -0
  70. package/dist/errors/rag-index-empty.d.ts +16 -0
  71. package/dist/errors/rag-index-empty.d.ts.map +1 -0
  72. package/dist/errors/rag-index-empty.js +16 -0
  73. package/dist/errors/rag-index-empty.js.map +1 -0
  74. package/dist/errors/suppressed-faults.d.ts +34 -0
  75. package/dist/errors/suppressed-faults.d.ts.map +1 -0
  76. package/dist/errors/suppressed-faults.js +66 -0
  77. package/dist/errors/suppressed-faults.js.map +1 -0
  78. package/dist/file-crawler.d.ts +13 -18
  79. package/dist/file-crawler.d.ts.map +1 -1
  80. package/dist/file-crawler.js +140 -24
  81. package/dist/file-crawler.js.map +1 -1
  82. package/dist/fs-utils.d.ts +75 -50
  83. package/dist/fs-utils.d.ts.map +1 -1
  84. package/dist/fs-utils.js +148 -158
  85. package/dist/fs-utils.js.map +1 -1
  86. package/dist/fs.d.ts +4 -4
  87. package/dist/fs.d.ts.map +1 -1
  88. package/dist/fs.js +4 -4
  89. package/dist/fs.js.map +1 -1
  90. package/dist/git-snapshot.d.ts +25 -17
  91. package/dist/git-snapshot.d.ts.map +1 -1
  92. package/dist/git-snapshot.js +65 -11
  93. package/dist/git-snapshot.js.map +1 -1
  94. package/dist/git-tracker.d.ts +11 -3
  95. package/dist/git-tracker.d.ts.map +1 -1
  96. package/dist/git-tracker.js +29 -6
  97. package/dist/git-tracker.js.map +1 -1
  98. package/dist/git-utils.d.ts.map +1 -1
  99. package/dist/git-utils.js +7 -35
  100. package/dist/git-utils.js.map +1 -1
  101. package/dist/git.d.ts +1 -1
  102. package/dist/git.d.ts.map +1 -1
  103. package/dist/git.js +1 -1
  104. package/dist/git.js.map +1 -1
  105. package/dist/gitignore-checker.d.ts.map +1 -1
  106. package/dist/gitignore-checker.js +5 -4
  107. package/dist/gitignore-checker.js.map +1 -1
  108. package/dist/in-order.d.ts +93 -0
  109. package/dist/in-order.d.ts.map +1 -0
  110. package/dist/in-order.js +165 -0
  111. package/dist/in-order.js.map +1 -0
  112. package/dist/index.d.ts +20 -4
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +30 -4
  115. package/dist/index.js.map +1 -1
  116. package/dist/kill-process-tree.d.ts +43 -0
  117. package/dist/kill-process-tree.d.ts.map +1 -0
  118. package/dist/kill-process-tree.js +48 -0
  119. package/dist/kill-process-tree.js.map +1 -0
  120. package/dist/link-following.d.ts +115 -0
  121. package/dist/link-following.d.ts.map +1 -0
  122. package/dist/link-following.js +283 -0
  123. package/dist/link-following.js.map +1 -0
  124. package/dist/listing-refusal.d.ts +44 -0
  125. package/dist/listing-refusal.d.ts.map +1 -1
  126. package/dist/listing-refusal.js +79 -2
  127. package/dist/listing-refusal.js.map +1 -1
  128. package/dist/name-fold.d.ts +25 -0
  129. package/dist/name-fold.d.ts.map +1 -0
  130. package/dist/name-fold.js +40 -0
  131. package/dist/name-fold.js.map +1 -0
  132. package/dist/path-containment.d.ts +3 -1
  133. package/dist/path-containment.d.ts.map +1 -1
  134. package/dist/path-containment.js +13 -7
  135. package/dist/path-containment.js.map +1 -1
  136. package/dist/path-utils.d.ts +14 -17
  137. package/dist/path-utils.d.ts.map +1 -1
  138. package/dist/path-utils.js +37 -55
  139. package/dist/path-utils.js.map +1 -1
  140. package/dist/process.d.ts +2 -0
  141. package/dist/process.d.ts.map +1 -1
  142. package/dist/process.js +2 -0
  143. package/dist/process.js.map +1 -1
  144. package/dist/project-utils.d.ts.map +1 -1
  145. package/dist/project-utils.js +8 -9
  146. package/dist/project-utils.js.map +1 -1
  147. package/dist/safe-exec.d.ts +6 -2
  148. package/dist/safe-exec.d.ts.map +1 -1
  149. package/dist/safe-exec.js +1 -1
  150. package/dist/safe-exec.js.map +1 -1
  151. package/dist/skill-targets.d.ts.map +1 -1
  152. package/dist/skill-targets.js +3 -1
  153. package/dist/skill-targets.js.map +1 -1
  154. package/dist/skill-test/spawn-claude.d.ts +0 -15
  155. package/dist/skill-test/spawn-claude.d.ts.map +1 -1
  156. package/dist/skill-test/spawn-claude.js +11 -50
  157. package/dist/skill-test/spawn-claude.js.map +1 -1
  158. package/dist/special-file.d.ts +18 -0
  159. package/dist/special-file.d.ts.map +1 -0
  160. package/dist/special-file.js +21 -0
  161. package/dist/special-file.js.map +1 -0
  162. package/dist/terminating-signals.d.ts +129 -0
  163. package/dist/terminating-signals.d.ts.map +1 -0
  164. package/dist/terminating-signals.js +210 -0
  165. package/dist/terminating-signals.js.map +1 -0
  166. package/dist/test-helpers.d.ts +9 -5
  167. package/dist/test-helpers.d.ts.map +1 -1
  168. package/dist/test-helpers.js +18 -21
  169. package/dist/test-helpers.js.map +1 -1
  170. package/dist/test-scratch-guard.d.ts +34 -0
  171. package/dist/test-scratch-guard.d.ts.map +1 -0
  172. package/dist/test-scratch-guard.js +45 -0
  173. package/dist/test-scratch-guard.js.map +1 -0
  174. package/dist/testing/archive-fixtures.d.ts +147 -0
  175. package/dist/testing/archive-fixtures.d.ts.map +1 -0
  176. package/dist/testing/archive-fixtures.js +449 -0
  177. package/dist/testing/archive-fixtures.js.map +1 -0
  178. package/dist/testing/executables.d.ts +6 -0
  179. package/dist/testing/executables.d.ts.map +1 -1
  180. package/dist/testing/executables.js +20 -9
  181. package/dist/testing/executables.js.map +1 -1
  182. package/dist/testing/fault-fs-preload.d.ts +16 -0
  183. package/dist/testing/fault-fs-preload.d.ts.map +1 -0
  184. package/dist/testing/fault-fs-preload.js +22 -0
  185. package/dist/testing/fault-fs-preload.js.map +1 -0
  186. package/dist/testing/fault-fs.d.ts +115 -0
  187. package/dist/testing/fault-fs.d.ts.map +1 -0
  188. package/dist/testing/fault-fs.js +411 -0
  189. package/dist/testing/fault-fs.js.map +1 -0
  190. package/dist/testing/fault-spec.d.ts +83 -0
  191. package/dist/testing/fault-spec.d.ts.map +1 -0
  192. package/dist/testing/fault-spec.js +132 -0
  193. package/dist/testing/fault-spec.js.map +1 -0
  194. package/dist/testing/hostile-tree.d.ts.map +1 -1
  195. package/dist/testing/hostile-tree.js +3 -4
  196. package/dist/testing/hostile-tree.js.map +1 -1
  197. package/dist/testing/platform-gates.d.ts +8 -0
  198. package/dist/testing/platform-gates.d.ts.map +1 -1
  199. package/dist/testing/platform-gates.js +24 -0
  200. package/dist/testing/platform-gates.js.map +1 -1
  201. package/dist/testing/temp-dir.d.ts +31 -0
  202. package/dist/testing/temp-dir.d.ts.map +1 -1
  203. package/dist/testing/temp-dir.js +63 -0
  204. package/dist/testing/temp-dir.js.map +1 -1
  205. package/dist/testing/tier-timeout.d.ts +34 -0
  206. package/dist/testing/tier-timeout.d.ts.map +1 -0
  207. package/dist/testing/tier-timeout.js +45 -0
  208. package/dist/testing/tier-timeout.js.map +1 -0
  209. package/dist/testing/tree-snapshot.d.ts +71 -0
  210. package/dist/testing/tree-snapshot.d.ts.map +1 -0
  211. package/dist/testing/tree-snapshot.js +163 -0
  212. package/dist/testing/tree-snapshot.js.map +1 -0
  213. package/dist/testing.d.ts +6 -0
  214. package/dist/testing.d.ts.map +1 -1
  215. package/dist/testing.js +8 -1
  216. package/dist/testing.js.map +1 -1
  217. package/dist/text-file.d.ts +14 -1
  218. package/dist/text-file.d.ts.map +1 -1
  219. package/dist/text-file.js +41 -8
  220. package/dist/text-file.js.map +1 -1
  221. package/dist/timing-dump.d.ts.map +1 -1
  222. package/dist/timing-dump.js +2 -10
  223. package/dist/timing-dump.js.map +1 -1
  224. package/dist/tree-change/apply-decisions.d.ts +101 -0
  225. package/dist/tree-change/apply-decisions.d.ts.map +1 -0
  226. package/dist/tree-change/apply-decisions.js +139 -0
  227. package/dist/tree-change/apply-decisions.js.map +1 -0
  228. package/dist/tree-change/apply.d.ts +98 -0
  229. package/dist/tree-change/apply.d.ts.map +1 -0
  230. package/dist/tree-change/apply.js +364 -0
  231. package/dist/tree-change/apply.js.map +1 -0
  232. package/dist/tree-change/copy-decisions.d.ts +58 -0
  233. package/dist/tree-change/copy-decisions.d.ts.map +1 -0
  234. package/dist/tree-change/copy-decisions.js +66 -0
  235. package/dist/tree-change/copy-decisions.js.map +1 -0
  236. package/dist/tree-change/copy-tree.d.ts +125 -0
  237. package/dist/tree-change/copy-tree.d.ts.map +1 -0
  238. package/dist/tree-change/copy-tree.js +279 -0
  239. package/dist/tree-change/copy-tree.js.map +1 -0
  240. package/dist/tree-change/files.d.ts +167 -0
  241. package/dist/tree-change/files.d.ts.map +1 -0
  242. package/dist/tree-change/files.js +423 -0
  243. package/dist/tree-change/files.js.map +1 -0
  244. package/dist/tree-change/followed-walk.d.ts +54 -0
  245. package/dist/tree-change/followed-walk.d.ts.map +1 -0
  246. package/dist/tree-change/followed-walk.js +81 -0
  247. package/dist/tree-change/followed-walk.js.map +1 -0
  248. package/dist/tree-change/host-chain.d.ts +48 -0
  249. package/dist/tree-change/host-chain.d.ts.map +1 -0
  250. package/dist/tree-change/host-chain.js +85 -0
  251. package/dist/tree-change/host-chain.js.map +1 -0
  252. package/dist/tree-change/identity-compare.d.ts +61 -0
  253. package/dist/tree-change/identity-compare.d.ts.map +1 -0
  254. package/dist/tree-change/identity-compare.js +115 -0
  255. package/dist/tree-change/identity-compare.js.map +1 -0
  256. package/dist/tree-change/identity.d.ts +62 -0
  257. package/dist/tree-change/identity.d.ts.map +1 -0
  258. package/dist/tree-change/identity.js +152 -0
  259. package/dist/tree-change/identity.js.map +1 -0
  260. package/dist/tree-change/index.d.ts +24 -0
  261. package/dist/tree-change/index.d.ts.map +1 -0
  262. package/dist/tree-change/index.js +14 -0
  263. package/dist/tree-change/index.js.map +1 -0
  264. package/dist/tree-change/link-chain.d.ts +180 -0
  265. package/dist/tree-change/link-chain.d.ts.map +1 -0
  266. package/dist/tree-change/link-chain.js +377 -0
  267. package/dist/tree-change/link-chain.js.map +1 -0
  268. package/dist/tree-change/link-containment.d.ts +105 -0
  269. package/dist/tree-change/link-containment.d.ts.map +1 -0
  270. package/dist/tree-change/link-containment.js +196 -0
  271. package/dist/tree-change/link-containment.js.map +1 -0
  272. package/dist/tree-change/link-walk.d.ts +49 -0
  273. package/dist/tree-change/link-walk.d.ts.map +1 -0
  274. package/dist/tree-change/link-walk.js +69 -0
  275. package/dist/tree-change/link-walk.js.map +1 -0
  276. package/dist/tree-change/plan.d.ts +206 -0
  277. package/dist/tree-change/plan.d.ts.map +1 -0
  278. package/dist/tree-change/plan.js +320 -0
  279. package/dist/tree-change/plan.js.map +1 -0
  280. package/dist/tree-change/readable-tree.d.ts +44 -0
  281. package/dist/tree-change/readable-tree.d.ts.map +1 -0
  282. package/dist/tree-change/readable-tree.js +52 -0
  283. package/dist/tree-change/readable-tree.js.map +1 -0
  284. package/dist/tree-change/rollback-error.d.ts +29 -0
  285. package/dist/tree-change/rollback-error.d.ts.map +1 -0
  286. package/dist/tree-change/rollback-error.js +31 -0
  287. package/dist/tree-change/rollback-error.js.map +1 -0
  288. package/dist/tree-change/staging-names.d.ts +27 -0
  289. package/dist/tree-change/staging-names.d.ts.map +1 -0
  290. package/dist/tree-change/staging-names.js +40 -0
  291. package/dist/tree-change/staging-names.js.map +1 -0
  292. package/dist/tree-change/tree-walk.d.ts +81 -0
  293. package/dist/tree-change/tree-walk.d.ts.map +1 -0
  294. package/dist/tree-change/tree-walk.js +212 -0
  295. package/dist/tree-change/tree-walk.js.map +1 -0
  296. package/dist/win32-namespace.d.ts +24 -0
  297. package/dist/win32-namespace.d.ts.map +1 -0
  298. package/dist/win32-namespace.js +31 -0
  299. package/dist/win32-namespace.js.map +1 -0
  300. package/dist/yaml/surgical-yaml.d.ts +12 -3
  301. package/dist/yaml/surgical-yaml.d.ts.map +1 -1
  302. package/dist/yaml/surgical-yaml.js +16 -6
  303. package/dist/yaml/surgical-yaml.js.map +1 -1
  304. package/eslint/README.md +12 -4
  305. package/eslint/rules/fs-binding-scan.cjs +278 -0
  306. package/eslint/rules/no-adhoc-errno.cjs +364 -0
  307. package/eslint/rules/no-bare-symlink-in-tests.cjs +2 -3
  308. package/eslint/rules/no-blind-catch.cjs +1 -1
  309. package/eslint/rules/no-destructive-fs.cjs +359 -0
  310. package/eslint/rules/no-existssync.cjs +70 -0
  311. package/eslint/rules/no-fragile-entrypoint-guard.cjs +3 -2
  312. package/eslint/rules/no-link-following-fs.cjs +68 -0
  313. package/eslint/rules/no-literal-process-exit.cjs +3 -16
  314. package/eslint/rules/no-literal-test-timeout.cjs +214 -0
  315. package/eslint/rules/no-raw-signal-listener.cjs +224 -0
  316. package/eslint/rules/no-stdout-outside-writer.cjs +135 -0
  317. package/package.json +10 -2
  318. package/dist/errors/errno.d.ts +0 -51
  319. package/dist/errors/errno.d.ts.map +0 -1
  320. package/dist/errors/errno.js +0 -112
  321. package/dist/errors/errno.js.map +0 -1
  322. package/eslint/rules/no-fs-promises-cp.cjs +0 -43
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The decisions of a tree copy that touch no filesystem: what it does about an entry already at a
3
+ * name it is about to create, when two names are one, and the refusal two source entries with one
4
+ * destination name get. `copy-tree.ts` is the half that makes the calls.
5
+ */
6
+ import { FsFaultError } from '../errors/fs-fault.js';
7
+ /**
8
+ * What a tree copy does about an entry ALREADY at a name it is about to create, below its root:
9
+ * - `fresh`: the destination is new (a staged tree): anything there is refused (`EEXIST`), never adopted.
10
+ * - `merge`: the destination is the caller's own output written again (a build directory): a real
11
+ * directory is adopted; a file or a link is REMOVED and made anew — never written through.
12
+ *
13
+ * Under both, an entry the copy itself made is never taken for one that was "already there": two
14
+ * source names that are one name at the destination are refused ({@link aliasFault}).
15
+ */
16
+ export type CopyOnto = 'fresh' | 'merge';
17
+ /** One entry the walk hands the copy: where it is, and where it is relative to the root (forward slashes). */
18
+ export interface CopiedEntry {
19
+ readonly path: string;
20
+ readonly relative: string;
21
+ }
22
+ /** The directory, relative to the root, that `relative` is in (`''`: the root). */
23
+ export declare const parentOf: (relative: string) => string;
24
+ /** The entry name of `relative`. */
25
+ export declare const nameOf: (relative: string) => string;
26
+ /**
27
+ * Whether two entry names are one name on a filesystem that folds letter case or Unicode form
28
+ * (APFS, NTFS, exFAT, SMB). Asked only AFTER the OS answered `EEXIST` for the second of them, to say
29
+ * which earlier entry it collided with: it names the pair, it never decides that there is one.
30
+ */
31
+ export declare function sameNameWhereFolded(a: string, b: string): boolean;
32
+ /**
33
+ * Whether a sibling this copy made, whose name folds to the name that just answered `EEXIST`, is the
34
+ * entry it collided with — asked only when identity did not find one that is.
35
+ *
36
+ * It is not when the OS proved them TWO entries: both are there, each with an identity, none shared.
37
+ * That is a tree that keeps the two names apart (case-sensitive), and what stands at the colliding
38
+ * name was there before this copy — a `merge`'s previous output, to take over as any other.
39
+ *
40
+ * @param sameness - What identity answered for the sibling's copy against the colliding name
41
+ * @param collidingPresent - Whether the colliding name holds an entry the copy can examine
42
+ */
43
+ export declare function foldedNameIsTwin(sameness: 'same' | 'different' | 'unknown', collidingPresent: boolean): boolean;
44
+ /**
45
+ * What a copy does at a name that already holds an entry it did not make.
46
+ *
47
+ * @param onto - The copy's mode
48
+ * @param kind - What the copy is about to make there
49
+ * @param thereIsDirectory - Whether the entry there is a real directory (not a link to one); read only under `merge`
50
+ * @returns `refuse` (rethrow the `EEXIST`), `adopt` (keep the directory), or `replace` (remove the file or link, make it anew)
51
+ */
52
+ export declare function mayTakeOver(onto: CopyOnto, kind: 'directory' | 'leaf', thereIsDirectory: boolean): 'refuse' | 'adopt' | 'replace';
53
+ /**
54
+ * Two source entries that are ONE name where the copy goes: the source's own layout cannot be
55
+ * copied there. A `source` fault (origin `content`) whatever side the tree is read on, naming both.
56
+ */
57
+ export declare function aliasFault(first: CopiedEntry, second: CopiedEntry, cause: unknown): FsFaultError;
58
+ //# sourceMappingURL=copy-decisions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-decisions.d.ts","sourceRoot":"","sources":["../../src/tree-change/copy-decisions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;AAEzC,8GAA8G;AAC9G,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,mFAAmF;AACnF,eAAO,MAAM,QAAQ,GAAI,UAAU,MAAM,KAAG,MAAsF,CAAC;AAEnI,oCAAoC;AACpC,eAAO,MAAM,MAAM,GAAI,UAAU,MAAM,KAAG,MAAuD,CAAC;AAKlG;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,EAAE,gBAAgB,EAAE,OAAO,GAAG,OAAO,CAE/G;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE,gBAAgB,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAKjI;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAUhG"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The decisions of a tree copy that touch no filesystem: what it does about an entry already at a
3
+ * name it is about to create, when two names are one, and the refusal two source entries with one
4
+ * destination name get. `copy-tree.ts` is the half that makes the calls.
5
+ */
6
+ import { FsFaultError } from '../errors/fs-fault.js';
7
+ /** The directory, relative to the root, that `relative` is in (`''`: the root). */
8
+ export const parentOf = (relative) => (relative.includes('/') ? relative.slice(0, relative.lastIndexOf('/')) : '');
9
+ /** The entry name of `relative`. */
10
+ export const nameOf = (relative) => relative.slice(relative.lastIndexOf('/') + 1);
11
+ /** A name as a case- and normalisation-insensitive filesystem compares it, near enough to find a pair to name. */
12
+ const folded = (name) => name.normalize('NFKD').toLowerCase();
13
+ /**
14
+ * Whether two entry names are one name on a filesystem that folds letter case or Unicode form
15
+ * (APFS, NTFS, exFAT, SMB). Asked only AFTER the OS answered `EEXIST` for the second of them, to say
16
+ * which earlier entry it collided with: it names the pair, it never decides that there is one.
17
+ */
18
+ export function sameNameWhereFolded(a, b) {
19
+ return folded(a) === folded(b);
20
+ }
21
+ /**
22
+ * Whether a sibling this copy made, whose name folds to the name that just answered `EEXIST`, is the
23
+ * entry it collided with — asked only when identity did not find one that is.
24
+ *
25
+ * It is not when the OS proved them TWO entries: both are there, each with an identity, none shared.
26
+ * That is a tree that keeps the two names apart (case-sensitive), and what stands at the colliding
27
+ * name was there before this copy — a `merge`'s previous output, to take over as any other.
28
+ *
29
+ * @param sameness - What identity answered for the sibling's copy against the colliding name
30
+ * @param collidingPresent - Whether the colliding name holds an entry the copy can examine
31
+ */
32
+ export function foldedNameIsTwin(sameness, collidingPresent) {
33
+ return !(sameness === 'different' && collidingPresent);
34
+ }
35
+ /**
36
+ * What a copy does at a name that already holds an entry it did not make.
37
+ *
38
+ * @param onto - The copy's mode
39
+ * @param kind - What the copy is about to make there
40
+ * @param thereIsDirectory - Whether the entry there is a real directory (not a link to one); read only under `merge`
41
+ * @returns `refuse` (rethrow the `EEXIST`), `adopt` (keep the directory), or `replace` (remove the file or link, make it anew)
42
+ */
43
+ export function mayTakeOver(onto, kind, thereIsDirectory) {
44
+ if (onto === 'fresh')
45
+ return 'refuse';
46
+ // A merge never swaps one kind for the other: a directory is not deleted for a file, nor a file for a directory.
47
+ if (thereIsDirectory !== (kind === 'directory'))
48
+ return 'refuse';
49
+ return kind === 'directory' ? 'adopt' : 'replace';
50
+ }
51
+ /**
52
+ * Two source entries that are ONE name where the copy goes: the source's own layout cannot be
53
+ * copied there. A `source` fault (origin `content`) whatever side the tree is read on, naming both.
54
+ */
55
+ export function aliasFault(first, second, cause) {
56
+ return new FsFaultError({
57
+ side: 'source',
58
+ faultClass: 'occupied',
59
+ errno: 'EEXIST',
60
+ path: second.path,
61
+ origin: 'content',
62
+ action: `copy both ${first.path} and ${second.path}: where the copy goes their two names are one name (they differ only in letter case or Unicode form), so one would overwrite the other`,
63
+ cause,
64
+ });
65
+ }
66
+ //# sourceMappingURL=copy-decisions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-decisions.js","sourceRoot":"","sources":["../../src/tree-change/copy-decisions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAmBrD,mFAAmF;AACnF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAEnI,oCAAoC;AACpC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAU,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAElG,kHAAkH;AAClH,MAAM,MAAM,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;AAE9E;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,CAAS,EAAE,CAAS;IACtD,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAA0C,EAAE,gBAAyB;IACpG,OAAO,CAAC,CAAC,QAAQ,KAAK,WAAW,IAAI,gBAAgB,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,IAAc,EAAE,IAA0B,EAAE,gBAAyB;IAC/F,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,QAAQ,CAAC;IACtC,iHAAiH;IACjH,IAAI,gBAAgB,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC;QAAE,OAAO,QAAQ,CAAC;IACjE,OAAO,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAkB,EAAE,MAAmB,EAAE,KAAc;IAChF,OAAO,IAAI,YAAY,CAAC;QACtB,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,UAAU;QACtB,KAAK,EAAE,QAAQ;QACf,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,aAAa,KAAK,CAAC,IAAI,QAAQ,MAAM,CAAC,IAAI,wIAAwI;QAC1L,KAAK;KACN,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * `copyTree`: copy a directory tree by the same walk `proveTreeReadable` proves it
3
+ * with, reading each file from the very handle the walk judged a regular file.
4
+ */
5
+ import { type FsSide } from '../errors/fs-fault.js';
6
+ import { type CopyOnto } from './copy-decisions.js';
7
+ import { type FileUnderOptions } from './files.js';
8
+ import type { ProveTreeReadableOptions } from './readable-tree.js';
9
+ import { type TreeVisitor } from './tree-walk.js';
10
+ /** Where a tree copy goes: `relative` (forward slashes; `''` for the root itself) under `root`. */
11
+ interface CopyDestination {
12
+ /**
13
+ * A directory that is the CALLER's: one it made, or one its user named. Made with its parents
14
+ * when absent — whatever stands above it is the caller's too, a link in the user's own layout
15
+ * (`~/.claude` kept in a dotfiles repository) included — and adopted when a real directory. A link
16
+ * or a file AT its name is never adopted ({@link claimRoot}).
17
+ */
18
+ readonly root: string;
19
+ /**
20
+ * Where under `root` the copy goes. Everything between the two is inside a tree that may hold
21
+ * what an earlier copy kept — links included — so each component must be a real directory
22
+ * (`makeDirectoryUnder`): a link or a file standing there refuses the copy, naming it.
23
+ */
24
+ readonly relative: string;
25
+ }
26
+ /** What {@link copyTree} is told: the walk, the side its reads are on, and what it does about what is already there. */
27
+ export interface CopyTreeOptions extends ProveTreeReadableOptions {
28
+ /** Required: only the caller knows whether its destination is new ({@link CopyOnto}). */
29
+ readonly onto: CopyOnto;
30
+ }
31
+ /**
32
+ * The visitor that writes the copy of each entry the walk accepts under `dest`; every read of the
33
+ * copied tree is on `side`.
34
+ *
35
+ * Every create below the root is EXCLUSIVE and never follows a link: a file is opened `wx`, a
36
+ * directory made by a plain `mkdir`, a link made only where nothing is. So a create that finds
37
+ * something answers `EEXIST`, and what happens then is decided in this order:
38
+ *
39
+ * 1. The entry there is one THIS copy made — the same entry by identity, or (where the OS will not
40
+ * say) a sibling whose name is the same once case and Unicode form are folded: two source names,
41
+ * one destination name. Refused as the source's layout (`aliasFault`), under either mode.
42
+ * 2. `fresh`: refused as it is (`EEXIST`), for the caller's boundary to classify.
43
+ * 3. `merge`: a real directory is adopted; a file or a link is removed (the link, never its target)
44
+ * and the entry made anew; anything else — a directory where a file goes, a link where a
45
+ * directory goes — is refused as it is (`mayTakeOver`).
46
+ *
47
+ * Where the copy goes is made by {@link claimDestination}: the root is the caller's (made with its
48
+ * parents when absent, adopted when a real directory, refused `EEXIST` when a link or a file — a link
49
+ * taken for it would put the whole copy where it points), and every directory from the root down to
50
+ * the copy is a real one or is refused as the layout of the tree it is in.
51
+ *
52
+ * Exported for `copyTree` and for the suite that hands it two entries by name — a real alias needs
53
+ * a case-sensitive source and a case-folding destination, which no one temp directory offers.
54
+ */
55
+ export declare function copyVisitor(where: CopyDestination, copied: string, side: FsSide, onto: CopyOnto): TreeVisitor;
56
+ /**
57
+ * Copy the directory `source` to `relative` under `root` ({@link CopyDestination}).
58
+ *
59
+ * `root` is a directory the caller made or its user named: created, with its parents, when absent;
60
+ * adopted when a real directory; refused, `EEXIST`, when a link or a file stands there. `relative`
61
+ * is `''` for a copy onto `root` itself. A copy that goes INSIDE a tree — a pool skill into a staged
62
+ * plugin that earlier copies filled, links kept — names that tree's root and where under it, and
63
+ * every directory between the two must then be a real one (made when absent): a link or a file
64
+ * there is a `source` fault (origin `content`, class `occupied`) naming it, never followed. So a
65
+ * caller cannot reach through a link by how deep its destination is: the only directory taken on
66
+ * trust is the one it declares as `root`.
67
+ *
68
+ * Entries are walked, and refused, exactly as `proveTreeReadable` proves them (see
69
+ * `tree-walk.ts`): a `follow-contained` link is copied as what it points at, inside
70
+ * the source only; a `preserve` link is copied as a link, its target string
71
+ * verbatim and never followed — its chain is read by text alone to give the copy its `file`/`dir`
72
+ * type, and one through a network or device path is refused (a `refused` fault on `options.side`)
73
+ * before anything is made; an entry `filter` excludes is never touched; a named
74
+ * pipe, socket or device is refused unopened. Each file is copied from the handle
75
+ * `fstat` judged, with its mode. Each directory takes its source's mode with the
76
+ * owner's rwx kept (`| 0o700`): a read-only source must not become a copy nothing
77
+ * can fill or remove.
78
+ *
79
+ * Below the copy's own directory nothing already there is ever adopted or written through, and two source
80
+ * entries that are one name there are refused as the source's layout (a `source` fault
81
+ * naming both): see {@link copyVisitor} and `options.onto`.
82
+ *
83
+ * The copy names no side for what it WRITES: a failure writing the copy is the raw
84
+ * errno, for the caller's boundary to classify — a link this host cannot create, and an
85
+ * `EEXIST` for something already at a name of a `fresh` destination, included. What it READS is on the side the caller names, as the proof's reads
86
+ * are: a refusal is a classified fault on `options.side` (origin `content`) naming
87
+ * the entry. Only the caller knows whether the tree is an input (`source`), VAT's
88
+ * staging (`environment`) or a copy already made into user state (`destination`).
89
+ *
90
+ * @param source - The directory to copy
91
+ * @param root - The directory the caller made or owns, which the copy goes into or under
92
+ * @param relative - Where under `root` the copy goes, forward slashes; `''` for `root` itself
93
+ * @param options - `links`, `filter` and `side`, exactly as `proveTreeReadable` was given them, and `onto`
94
+ */
95
+ export declare function copyTree(source: string, root: string, relative: string, options: CopyTreeOptions): Promise<void>;
96
+ /** What {@link copyRegularFile} is told: the file it reads, and (as `writeFileUnder` is) the entry already where the copy goes. */
97
+ export interface CopyRegularFileOptions extends FileUnderOptions {
98
+ /** The side of the verb the file is on, as for {@link copyTree}. */
99
+ readonly side: FsSide;
100
+ /** What the file is, for a refused read's message: `read <reading>` (`linked file docs/a.md`). */
101
+ readonly reading: string;
102
+ }
103
+ /**
104
+ * Copy ONE regular file to `relative` under `root`, as {@link copyTree} copies a file: opened
105
+ * without blocking and judged by `fstat` on that handle (a named pipe, socket or device is refused
106
+ * before a byte is read, never waited on), its bytes copied from that very handle, its mode
107
+ * carried over.
108
+ *
109
+ * The copy is made as `writeFileUnder` makes a file — it is the same primitive: every directory of
110
+ * `relative` must be a real directory (made by a plain `mkdir` when absent), the file is created
111
+ * exclusively, and its bytes and mode go to that handle. So it never writes through a link, at the
112
+ * file's name or on the way to it; `options.existing` decides a regular file already there.
113
+ *
114
+ * Every read is a classified fault on `options.side` (origin `content`), naming what was read. An
115
+ * entry in the copy's way is a `source` fault (origin `content`, class `occupied`) naming it; any
116
+ * other failure writing is the raw errno, for the caller's boundary to classify.
117
+ *
118
+ * @param source - The file to copy
119
+ * @param root - The root of the tree the copy goes into, which the caller made
120
+ * @param relative - Where the copy goes, relative to `root`, forward slashes
121
+ * @param options - The side `source` is on and what it is; `existing` and `writing`, for the copy
122
+ */
123
+ export declare function copyRegularFile(source: string, root: string, relative: string, options: CopyRegularFileOptions): Promise<void>;
124
+ export {};
125
+ //# sourceMappingURL=copy-tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-tree.d.ts","sourceRoot":"","sources":["../../src/tree-change/copy-tree.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAmB,KAAK,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAKrE,OAAO,EAAgC,KAAK,QAAQ,EAAwE,MAAM,qBAAqB,CAAC;AACxJ,OAAO,EAAE,KAAK,gBAAgB,EAAqC,MAAM,YAAY,CAAC;AAEtF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAA8B,KAAK,WAAW,EAAY,MAAM,gBAAgB,CAAC;AAqDxF,mGAAmG;AACnG,UAAU,eAAe;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AA+BD,wHAAwH;AACxH,MAAM,WAAW,eAAgB,SAAQ,wBAAwB;IAC/D,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,WAAW,CAgE7G;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtH;AAED,mIAAmI;AACnI,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kGAAkG;IAClG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBpI"}
@@ -0,0 +1,279 @@
1
+ /**
2
+ * `copyTree`: copy a directory tree by the same walk `proveTreeReadable` proves it
3
+ * with, reading each file from the very handle the walk judged a regular file.
4
+ */
5
+ import fs from 'node:fs/promises';
6
+ import { isAlreadyExistsError, isPathAbsentError } from '../errors/errno-table.js';
7
+ import { classifyFsFault } from '../errors/fs-fault.js';
8
+ import { linkCopyType } from '../link-following.js';
9
+ import { safePath } from '../path-core.js';
10
+ import { openForReading } from '../text-file.js';
11
+ import { aliasFault, foldedNameIsTwin, mayTakeOver, nameOf, parentOf, sameNameWhereFolded } from './copy-decisions.js';
12
+ import { makeDirectoryUnder, openFileUnder } from './files.js';
13
+ import { sameEntry } from './identity.js';
14
+ import { readingTree, treeReadFault, walkTree } from './tree-walk.js';
15
+ /** The owner's read, write and search bits, kept on every copied directory so its owner can always fill and remove it. */
16
+ const OWNER_RWX = 0o700;
17
+ /** The bytes of an open file being copied; a read failure is `readFault`'s. A write failure never reaches this catch: the writer's loop ends the generator with `return()`, not `throw()`. */
18
+ async function* sourceBytes(source, readFault) {
19
+ try {
20
+ yield* source.createReadStream({ autoClose: false, start: 0 });
21
+ }
22
+ catch (error) {
23
+ throw readFault(error);
24
+ }
25
+ }
26
+ /**
27
+ * Copy the bytes of an open file — one already judged a regular file on that very handle — into
28
+ * `claimed`, a file this copy has just made exclusively (opened `wx`), and carry its permission bits
29
+ * over, so a script stays executable — never its setuid, setgid or sticky bit. The ONE file copy of the tree copy and the
30
+ * single-file copy: bytes and mode both go to that very handle, never to a path, so nothing swapped
31
+ * in after the claim — a link least of all — is written or chmod-ed through. Closes `claimed`.
32
+ */
33
+ async function copyOpenFileInto(handle, claimed, mode, readFault) {
34
+ try {
35
+ // On the handle, not through a stream of it: a stream owns the handle it writes and closes it
36
+ // with itself, before the mode could be set on it.
37
+ await claimed.writeFile(sourceBytes(handle, readFault));
38
+ // The permission bits only: setuid, setgid and sticky never travel with a copy.
39
+ await claimed.chmod(mode & 0o777);
40
+ }
41
+ catch (error) {
42
+ // The copy's own failure is the answer: a close refused after it is not a second one.
43
+ await claimed.close().catch(() => undefined);
44
+ throw error;
45
+ }
46
+ await claimed.close();
47
+ }
48
+ /**
49
+ * Make the root of a copy: with its parents when nothing is there, adopted when a real directory
50
+ * is. A link there — to a directory included — or a file is never adopted: the plain `mkdir` is the
51
+ * OS's own `EEXIST` for it, raw, as for any entry of a `fresh` destination.
52
+ */
53
+ async function claimRoot(into) {
54
+ const there = await fs.lstat(into).catch((error) => {
55
+ if (isPathAbsentError(error))
56
+ return undefined;
57
+ throw error;
58
+ });
59
+ if (there === undefined)
60
+ await fs.mkdir(into, { recursive: true });
61
+ else if (!there.isDirectory())
62
+ await fs.mkdir(into);
63
+ }
64
+ /**
65
+ * Make the directory a copy goes into ({@link CopyDestination}): the root as the caller's, every
66
+ * component under it as a real directory or not at all.
67
+ *
68
+ * @param copied - What is copied, for a refusal's message
69
+ * @returns The directory's path
70
+ */
71
+ async function claimDestination(into, copied) {
72
+ await claimRoot(into.root);
73
+ return into.relative === '' ? into.root : await makeDirectoryUnder(into.root, into.relative, `the copy of ${copied}`);
74
+ }
75
+ /**
76
+ * Make the directory a copy's own entry goes IN, for a source that is not a directory at all — a
77
+ * root that is a link, kept as one (`links: 'preserve'`): the destination root's parents as the
78
+ * caller's, every component under the root as a real directory or not at all.
79
+ *
80
+ * @param copied - What is copied, for a refusal's message
81
+ */
82
+ async function claimParentOfDestination(into, copied) {
83
+ if (into.relative === '') {
84
+ await fs.mkdir(parentOf(into.root), { recursive: true });
85
+ return;
86
+ }
87
+ await claimRoot(into.root);
88
+ const parent = parentOf(into.relative);
89
+ if (parent !== '')
90
+ await makeDirectoryUnder(into.root, parent, `the copy of ${copied}`);
91
+ }
92
+ /**
93
+ * The visitor that writes the copy of each entry the walk accepts under `dest`; every read of the
94
+ * copied tree is on `side`.
95
+ *
96
+ * Every create below the root is EXCLUSIVE and never follows a link: a file is opened `wx`, a
97
+ * directory made by a plain `mkdir`, a link made only where nothing is. So a create that finds
98
+ * something answers `EEXIST`, and what happens then is decided in this order:
99
+ *
100
+ * 1. The entry there is one THIS copy made — the same entry by identity, or (where the OS will not
101
+ * say) a sibling whose name is the same once case and Unicode form are folded: two source names,
102
+ * one destination name. Refused as the source's layout (`aliasFault`), under either mode.
103
+ * 2. `fresh`: refused as it is (`EEXIST`), for the caller's boundary to classify.
104
+ * 3. `merge`: a real directory is adopted; a file or a link is removed (the link, never its target)
105
+ * and the entry made anew; anything else — a directory where a file goes, a link where a
106
+ * directory goes — is refused as it is (`mayTakeOver`).
107
+ *
108
+ * Where the copy goes is made by {@link claimDestination}: the root is the caller's (made with its
109
+ * parents when absent, adopted when a real directory, refused `EEXIST` when a link or a file — a link
110
+ * taken for it would put the whole copy where it points), and every directory from the root down to
111
+ * the copy is a real one or is refused as the layout of the tree it is in.
112
+ *
113
+ * Exported for `copyTree` and for the suite that hands it two entries by name — a real alias needs
114
+ * a case-sensitive source and a case-folding destination, which no one temp directory offers.
115
+ */
116
+ export function copyVisitor(where, copied, side, onto) {
117
+ const dest = where.relative === '' ? where.root : safePath.join(where.root, where.relative);
118
+ const target = (relative) => (relative === '' ? dest : safePath.join(dest, relative));
119
+ /** What this copy made, by the directory (relative to the root) it made it in. */
120
+ const made = new Map();
121
+ const madeIn = (parent) => {
122
+ const list = made.get(parent) ?? [];
123
+ made.set(parent, list);
124
+ return list;
125
+ };
126
+ const twinOf = async (entry, into) => {
127
+ const siblings = madeIn(parentOf(entry.relative));
128
+ const byIdentity = siblings.find((each) => sameEntry(target(each.relative), into) === 'same');
129
+ if (byIdentity !== undefined)
130
+ return byIdentity;
131
+ const byName = siblings.find((each) => sameNameWhereFolded(nameOf(each.relative), nameOf(entry.relative)));
132
+ if (byName === undefined)
133
+ return undefined;
134
+ // Absent or unexaminable alike: then the collision is all there is to go on, and the name decides.
135
+ const present = await fs.lstat(into).then(() => true, () => false);
136
+ return foldedNameIsTwin(sameEntry(target(byName.relative), into), present) ? byName : undefined;
137
+ };
138
+ /**
139
+ * Claim `entry`'s place by `claim` — an exclusive create, and nothing else, so it can be asked
140
+ * twice — and hand back what it made (`undefined`: a directory a merge adopted).
141
+ */
142
+ const create = async (entry, kind, claim) => {
143
+ const into = target(entry.relative);
144
+ const claimed = await claim(into).catch(async (error) => {
145
+ if (!isAlreadyExistsError(error))
146
+ throw error;
147
+ const twin = await twinOf(entry, into);
148
+ if (twin !== undefined)
149
+ throw aliasFault(twin, entry, error);
150
+ const takeOver = mayTakeOver(onto, kind, onto === 'merge' ? (await fs.lstat(into)).isDirectory() : false);
151
+ if (takeOver === 'refuse')
152
+ throw error;
153
+ if (takeOver === 'adopt')
154
+ return undefined;
155
+ await fs.unlink(into);
156
+ return claim(into);
157
+ });
158
+ madeIn(parentOf(entry.relative)).push(entry);
159
+ return claimed;
160
+ };
161
+ return {
162
+ async directory(entry, stats) {
163
+ const into = target(entry.relative);
164
+ if (entry.relative === '')
165
+ await claimDestination(where, copied);
166
+ else
167
+ await create(entry, 'directory', (path) => fs.mkdir(path));
168
+ await fs.chmod(into, (stats.mode & 0o7777) | OWNER_RWX);
169
+ },
170
+ async file(entry, handle, stats) {
171
+ const claimed = await create(entry, 'leaf', (into) => fs.open(into, 'wx'));
172
+ if (claimed !== undefined)
173
+ await copyOpenFileInto(handle, claimed, stats.mode, (error) => treeReadFault(side, entry.path, error));
174
+ },
175
+ async link(entry) {
176
+ const linkTarget = await readingTree(side, entry.path, () => fs.readlink(entry.path));
177
+ // Typed from the chain read by its text, before anything is made: an untyped `symlink` has
178
+ // Node on Windows ask the kernel to follow the target to pick `file` or `dir`, so a network or
179
+ // device text — at any hop — is refused here, on the copied tree's side, never handed on.
180
+ const type = await readingTree(side, entry.path, () => Promise.resolve().then(() => linkCopyType(entry.path, copied)));
181
+ // The source itself is a link: there is no copied directory to hold it, so its place is made first.
182
+ if (entry.relative === '')
183
+ await claimParentOfDestination(where, copied);
184
+ // Verbatim. A host that cannot make the link (Windows without the privilege: EPERM; a
185
+ // filesystem with none: ENOTSUP) raises the raw errno, a write like any other, for the
186
+ // caller's boundary to classify.
187
+ await create(entry, 'leaf', (into) => fs.symlink(linkTarget, into, type));
188
+ },
189
+ };
190
+ }
191
+ /**
192
+ * Copy the directory `source` to `relative` under `root` ({@link CopyDestination}).
193
+ *
194
+ * `root` is a directory the caller made or its user named: created, with its parents, when absent;
195
+ * adopted when a real directory; refused, `EEXIST`, when a link or a file stands there. `relative`
196
+ * is `''` for a copy onto `root` itself. A copy that goes INSIDE a tree — a pool skill into a staged
197
+ * plugin that earlier copies filled, links kept — names that tree's root and where under it, and
198
+ * every directory between the two must then be a real one (made when absent): a link or a file
199
+ * there is a `source` fault (origin `content`, class `occupied`) naming it, never followed. So a
200
+ * caller cannot reach through a link by how deep its destination is: the only directory taken on
201
+ * trust is the one it declares as `root`.
202
+ *
203
+ * Entries are walked, and refused, exactly as `proveTreeReadable` proves them (see
204
+ * `tree-walk.ts`): a `follow-contained` link is copied as what it points at, inside
205
+ * the source only; a `preserve` link is copied as a link, its target string
206
+ * verbatim and never followed — its chain is read by text alone to give the copy its `file`/`dir`
207
+ * type, and one through a network or device path is refused (a `refused` fault on `options.side`)
208
+ * before anything is made; an entry `filter` excludes is never touched; a named
209
+ * pipe, socket or device is refused unopened. Each file is copied from the handle
210
+ * `fstat` judged, with its mode. Each directory takes its source's mode with the
211
+ * owner's rwx kept (`| 0o700`): a read-only source must not become a copy nothing
212
+ * can fill or remove.
213
+ *
214
+ * Below the copy's own directory nothing already there is ever adopted or written through, and two source
215
+ * entries that are one name there are refused as the source's layout (a `source` fault
216
+ * naming both): see {@link copyVisitor} and `options.onto`.
217
+ *
218
+ * The copy names no side for what it WRITES: a failure writing the copy is the raw
219
+ * errno, for the caller's boundary to classify — a link this host cannot create, and an
220
+ * `EEXIST` for something already at a name of a `fresh` destination, included. What it READS is on the side the caller names, as the proof's reads
221
+ * are: a refusal is a classified fault on `options.side` (origin `content`) naming
222
+ * the entry. Only the caller knows whether the tree is an input (`source`), VAT's
223
+ * staging (`environment`) or a copy already made into user state (`destination`).
224
+ *
225
+ * @param source - The directory to copy
226
+ * @param root - The directory the caller made or owns, which the copy goes into or under
227
+ * @param relative - Where under `root` the copy goes, forward slashes; `''` for `root` itself
228
+ * @param options - `links`, `filter` and `side`, exactly as `proveTreeReadable` was given them, and `onto`
229
+ */
230
+ export async function copyTree(source, root, relative, options) {
231
+ await walkTree(source, options, options.side, copyVisitor({ root, relative }, source, options.side, options.onto));
232
+ }
233
+ /**
234
+ * Copy ONE regular file to `relative` under `root`, as {@link copyTree} copies a file: opened
235
+ * without blocking and judged by `fstat` on that handle (a named pipe, socket or device is refused
236
+ * before a byte is read, never waited on), its bytes copied from that very handle, its mode
237
+ * carried over.
238
+ *
239
+ * The copy is made as `writeFileUnder` makes a file — it is the same primitive: every directory of
240
+ * `relative` must be a real directory (made by a plain `mkdir` when absent), the file is created
241
+ * exclusively, and its bytes and mode go to that handle. So it never writes through a link, at the
242
+ * file's name or on the way to it; `options.existing` decides a regular file already there.
243
+ *
244
+ * Every read is a classified fault on `options.side` (origin `content`), naming what was read. An
245
+ * entry in the copy's way is a `source` fault (origin `content`, class `occupied`) naming it; any
246
+ * other failure writing is the raw errno, for the caller's boundary to classify.
247
+ *
248
+ * @param source - The file to copy
249
+ * @param root - The root of the tree the copy goes into, which the caller made
250
+ * @param relative - Where the copy goes, relative to `root`, forward slashes
251
+ * @param options - The side `source` is on and what it is; `existing` and `writing`, for the copy
252
+ */
253
+ export async function copyRegularFile(source, root, relative, options) {
254
+ // Every read — the open, the `fstat`, the stream, the close — names what was read, on its side.
255
+ const readFault = (error) => classifyFsFault(error, { side: options.side, origin: 'content', action: `read ${options.reading}`, path: source });
256
+ const reading = async (read) => {
257
+ try {
258
+ return await read();
259
+ }
260
+ catch (error) {
261
+ throw readFault(error);
262
+ }
263
+ };
264
+ const handle = await reading(() => openForReading(source));
265
+ try {
266
+ const stats = await reading(() => handle.stat());
267
+ // Only once the source is open and judged: a `replace` removes nothing for a copy that cannot be read.
268
+ const claimed = await openFileUnder(root, relative, options);
269
+ await copyOpenFileInto(handle, claimed, stats.mode, readFault);
270
+ }
271
+ catch (error) {
272
+ // The copy's own failure is the answer: a close refused after it is not a second one.
273
+ await handle.close().catch(() => undefined);
274
+ throw error;
275
+ }
276
+ // The close is a read of the source, too: a refusal of it is on the source's side.
277
+ await reading(() => handle.close());
278
+ }
279
+ //# sourceMappingURL=copy-tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-tree.js","sourceRoot":"","sources":["../../src/tree-change/copy-tree.ts"],"names":[],"mappings":"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"}