@poe-platform/safe-bash 0.1.620 → 0.1.622

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,3 @@
1
+ export declare function parseZipDate(input: string, option: "t" | "tt"): number;
2
+ export declare function zipDateMatches(modified: Date, from: number | undefined, until: number | undefined): boolean;
3
+ //# sourceMappingURL=dates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../../../src/commands/archive/zip/dates.ts"],"names":[],"mappings":"AA2BA,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI,GAAG,MAAM,CAOtE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAO3G"}
@@ -0,0 +1,49 @@
1
+ import { ZipFailure } from "./options.js";
2
+ function integer(input, start, width) {
3
+ let offset = start;
4
+ while (" \t\r\n\v\f".includes(input[offset] ?? "\0"))
5
+ offset++;
6
+ const end = offset + width;
7
+ let sign = 1;
8
+ if (input[offset] === "+" || input[offset] === "-") {
9
+ sign = input[offset] === "-" ? -1 : 1;
10
+ offset++;
11
+ }
12
+ let digits = 0;
13
+ let value = 0;
14
+ while (offset < end && input[offset] !== undefined && input[offset] >= "0" && input[offset] <= "9") {
15
+ value = value * 10 + Number(input[offset++]);
16
+ digits++;
17
+ }
18
+ return digits ? { value: value * sign, end: offset } : undefined;
19
+ }
20
+ function fields(input, iso) {
21
+ const first = integer(input, 0, iso ? 4 : 2);
22
+ if (!first || iso && input[first.end] !== "-")
23
+ return;
24
+ const second = integer(input, first.end + (iso ? 1 : 0), 2);
25
+ if (!second || iso && input[second.end] !== "-")
26
+ return;
27
+ const third = integer(input, second.end + (iso ? 1 : 0), iso ? 2 : 4);
28
+ if (!third)
29
+ return;
30
+ return iso ? [first.value, second.value, third.value] : [third.value, first.value, second.value];
31
+ }
32
+ export function parseZipDate(input, option) {
33
+ const result = fields(input, true) ?? fields(input, false);
34
+ if (!result || result[1] < 1 || result[1] > 12 || result[2] < 1 || result[2] > 31) {
35
+ throw new ZipFailure(16, "Invalid command arguments", `invalid date entered for -${option} option - use mmddyyyy or yyyy-mm-dd`);
36
+ }
37
+ const [year, month, day] = result;
38
+ return year < 1980 ? 2162688 : (year - 1980) * 33554432 + month * 2097152 + day * 65536;
39
+ }
40
+ export function zipDateMatches(modified, from, until) {
41
+ if (from === undefined && until === undefined)
42
+ return true;
43
+ const rounded = new Date(Math.ceil(Math.floor(modified.getTime() / 1000) / 2) * 2000);
44
+ const key = rounded.getFullYear() < 1980 ? 2162688 : (rounded.getFullYear() - 1980) * 33554432
45
+ + (rounded.getMonth() + 1) * 2097152 + rounded.getDate() * 65536
46
+ + rounded.getHours() * 2048 + rounded.getMinutes() * 32 + rounded.getSeconds() / 2;
47
+ return (from === undefined || key >= from) && (until === undefined || key < until);
48
+ }
49
+ //# sourceMappingURL=dates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dates.js","sourceRoot":"","sources":["../../../../src/commands/archive/zip/dates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,SAAS,OAAO,CAAC,KAAa,EAAE,KAAa,EAAE,KAAa;IAC1D,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,OAAO,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;QAAE,MAAM,EAAE,CAAC;IAC/D,MAAM,GAAG,GAAG,MAAM,GAAG,KAAK,CAAC;IAC3B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC;QAAC,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,CAAC;IAAC,CAAC;IACxG,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,CAAE,IAAI,GAAG,IAAI,KAAK,CAAC,MAAM,CAAE,IAAI,GAAG,EAAE,CAAC;QACrG,KAAK,GAAG,KAAK,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC7C,MAAM,EAAE,CAAC;IACX,CAAC;IACD,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACnE,CAAC;AAED,SAAS,MAAM,CAAC,KAAa,EAAE,GAAY;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,IAAI,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG;QAAE,OAAO;IACtD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,GAAG;QAAE,OAAO;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AACnG,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,MAAkB;IAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC3D,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;QAClF,MAAM,IAAI,UAAU,CAAC,EAAE,EAAE,2BAA2B,EAAE,6BAA6B,MAAM,sCAAsC,CAAC,CAAC;IACnI,CAAC;IACD,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC;IAClC,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,GAAG,GAAG,KAAK,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAc,EAAE,IAAwB,EAAE,KAAyB;IAChG,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC3D,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACtF,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,GAAG,QAAQ;UAC1F,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,KAAK;UAC9D,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACrF,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC;AACrF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type ArchiveLimits } from "../internal.js";
2
+ export declare function zipEnvironmentArguments(env: Readonly<Record<string, string>>, argv: readonly string[], limits: ArchiveLimits): readonly string[];
3
+ //# sourceMappingURL=environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../../../src/commands/archive/zip/environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAM1D,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,aAAa,GAAG,SAAS,MAAM,EAAE,CAyChJ"}
@@ -0,0 +1,62 @@
1
+ import { fail } from "../internal.js";
2
+ function whitespace(character) {
3
+ return character === " " || character === "\t" || character === "\n" || character === "\r" || character === "\v" || character === "\f";
4
+ }
5
+ export function zipEnvironmentArguments(env, argv, limits) {
6
+ let value = "";
7
+ let selectedBytes = 0;
8
+ for (const key of ["ZIPOPT", "ZIP_OPTS"]) {
9
+ const candidate = env[key] ?? "";
10
+ if (Buffer.byteLength(candidate) > limits.maxArgumentBytes)
11
+ fail("environment argument byte limit exceeded");
12
+ let start = 0;
13
+ while (whitespace(candidate[start]))
14
+ start++;
15
+ if (start < candidate.length) {
16
+ value = candidate.slice(start);
17
+ selectedBytes = Buffer.byteLength(candidate);
18
+ break;
19
+ }
20
+ }
21
+ if (!value)
22
+ return argv;
23
+ if (value.includes("\0") || Buffer.from(value).toString("utf8") !== value)
24
+ fail("invalid environment argument text");
25
+ let bytes = selectedBytes;
26
+ for (const argument of argv) {
27
+ bytes += Buffer.byteLength(argument);
28
+ if (bytes > limits.maxArgumentBytes)
29
+ fail("argument byte limit exceeded");
30
+ }
31
+ const defaults = [];
32
+ let offset = 0;
33
+ while (offset < value.length) {
34
+ let argument = "";
35
+ if (value[offset] === '"') {
36
+ offset++;
37
+ while (offset < value.length && value[offset] !== '"') {
38
+ if (value[offset] === "\\") {
39
+ offset++;
40
+ if (offset === value.length)
41
+ break;
42
+ }
43
+ argument += value[offset++];
44
+ }
45
+ if (value[offset] === '"')
46
+ offset++;
47
+ }
48
+ else {
49
+ const start = offset;
50
+ while (offset < value.length && !whitespace(value[offset]))
51
+ offset++;
52
+ argument = value.slice(start, offset);
53
+ }
54
+ if (defaults.length + argv.length >= limits.maxArgumentBytes)
55
+ fail("argument count limit exceeded");
56
+ defaults.push(argument);
57
+ while (whitespace(value[offset]))
58
+ offset++;
59
+ }
60
+ return [...defaults, ...argv];
61
+ }
62
+ //# sourceMappingURL=environment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.js","sourceRoot":"","sources":["../../../../src/commands/archive/zip/environment.ts"],"names":[],"mappings":"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"}
@@ -9,24 +9,24 @@ export class ZipFailure extends Error {
9
9
  }
10
10
  const longOptions = {
11
11
  "recurse-paths": "r", quiet: "q", "junk-paths": "j", "no-dir-entries": "D",
12
- symlinks: "y", test: "T", "names-stdin": "@", update: "u", freshen: "f",
12
+ symlinks: "y", test: "T", "names-stdin": "@", update: "u", freshen: "f", filesync: "FS",
13
13
  delete: "d", include: "i", exclude: "x", suffixes: "n", store: "0", "compression-method": "Z",
14
14
  "compress-1": "1", "compress-2": "2", "compress-3": "3", "compress-4": "4",
15
15
  "compress-5": "5", "compress-6": "6", "compress-7": "7", "compress-8": "8",
16
- "compress-9": "9", "force-zip64": "fz", "strip-extra": "X", "force-descriptors": "fd", "no-wild": "nw", "wild-stop-dirs": "ws", "recurse-patterns": "R",
16
+ "compress-9": "9", "force-zip64": "fz", "strip-extra": "X", "force-descriptors": "fd", "no-wild": "nw", "wild-stop-dirs": "ws", "recurse-patterns": "R", "from-date": "t", "before-date": "tt", "copy-entries": "U", "output-file": "O", "must-match": "MM",
17
17
  };
18
18
  // Include unimplemented Unix options when resolving abbreviations: a partial
19
19
  // implementation must not make native-ambiguous prefixes uniquely resolvable.
20
20
  const reservedOptions = [
21
21
  "adjust-sfx", "temp-path", "entry-comments", "display-bytes", "display-counts",
22
22
  "display-dots", "display-globaldots", "dot-size", "display-usize", "display-volume",
23
- "difference-archive", "encrypt", "fix", "fixfix", "fifo", "filesync",
23
+ "difference-archive", "encrypt", "fix", "fixfix", "fifo",
24
24
  "grow", "help", "more-help", "junk-sfx",
25
25
  "DOS-names", "to-crlf", "from-crlf", "logfile-path", "log-append", "log-info",
26
- "license", "move", "must-match", "latest-time", "output-file",
26
+ "license", "move", "latest-time",
27
27
  "paths", "password", "regex", "split-size", "split-pause",
28
28
  "split-verbose", "split-bell", "show-command", "show-debug", "show-files",
29
- "show-options", "from-date", "before-date", "unzip-command", "copy-entries",
29
+ "show-options", "unzip-command",
30
30
  "verbose", "version", "archive-comment",
31
31
  ];
32
32
  export function normalizeZipOption(argument) {
@@ -46,7 +46,7 @@ export function normalizeZipOption(argument) {
46
46
  throw new ZipFailure(16, "Invalid command arguments", `unsupported option: ${argument}`);
47
47
  if (negate && short !== "fz" && short !== "X")
48
48
  throw new ZipFailure(16, "Invalid command arguments", `option ${matched} is not negatable`);
49
- if (equal >= 0 && short !== "i" && short !== "x" && short !== "n" && short !== "Z") {
49
+ if (equal >= 0 && short !== "i" && short !== "x" && short !== "n" && short !== "Z" && short !== "t" && short !== "tt" && short !== "O") {
50
50
  throw new ZipFailure(16, "Invalid command arguments", `option '${matched}' does not allow a value`);
51
51
  }
52
52
  return `-${short}${negate ? "-" : ""}${equal < 0 ? "" : argument.slice(equal)}`;
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","sourceRoot":"","sources":["../../../../src/commands/archive/zip/options.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../../../src/commands/archive/zip/options.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../../src/commands/archive/zip.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0D,KAAK,iBAAiB,EAAiB,MAAM,0BAA0B,CAAC;AAOzI,OAAO,EAAwF,KAAK,sBAAsB,EAAsB,MAAM,eAAe,CAAC;AA+ctK,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,sBAA2B,GAAG,iBAAiB,CA0CxF"}
1
+ {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../../src/commands/archive/zip.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0D,KAAK,iBAAiB,EAAiB,MAAM,0BAA0B,CAAC;AAOzI,OAAO,EAAwF,KAAK,sBAAsB,EAAsB,MAAM,eAAe,CAAC;AA8kBtK,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,sBAA2B,GAAG,iBAAiB,CA2CxF"}
@@ -1,3 +1,5 @@
1
+ import { parseZipDate, zipDateMatches } from "./zip/dates.js";
2
+ import { zipEnvironmentArguments } from "./zip/environment.js";
1
3
  import { collectBytes, dirname, getCommandArguments, writeBytes } from "../../contracts/index.js";
2
4
  import { shellValueByteLength, shellValueBytes } from "../../contracts/value.js";
3
5
  import { writeFileOutput } from "../../contracts/filesystem-output.js";
@@ -13,10 +15,11 @@ import { normalizeZipOption, ZipFailure } from "./zip/options.js";
13
15
  const defaultStoreSuffixes = [".Z", ".zip", ".zoo", ".arc", ".lzh", ".arj"];
14
16
  async function parse(scope, limits) {
15
17
  const context = scope.context;
16
- if (context.args.length > limits.maxArgumentBytes)
18
+ const args = zipEnvironmentArguments(context.env, context.args, limits);
19
+ if (args.length > limits.maxArgumentBytes)
17
20
  fail("argument count limit exceeded");
18
21
  let bytes = 0;
19
- for (const argument of context.args) {
22
+ for (const argument of args) {
20
23
  const size = Buffer.byteLength(argument);
21
24
  if (size > limits.maxArgumentBytes - bytes)
22
25
  fail("argument byte limit exceeded");
@@ -35,6 +38,7 @@ async function parse(scope, limits) {
35
38
  text(shellValueBytes(value));
36
39
  }
37
40
  let archive;
41
+ let output;
38
42
  let action = "add";
39
43
  let recursive = false;
40
44
  let recursivePatterns = false;
@@ -45,6 +49,10 @@ async function parse(scope, limits) {
45
49
  let omitDirectories = false;
46
50
  let storeLinks = false;
47
51
  let test = false;
52
+ let mustMatch = false;
53
+ let filesync = false;
54
+ let fromDate;
55
+ let beforeDate;
48
56
  let descriptors = false;
49
57
  let zip64;
50
58
  let metadata = "default";
@@ -57,8 +65,8 @@ async function parse(scope, limits) {
57
65
  const operands = [];
58
66
  const includes = [];
59
67
  const excludes = [];
60
- for (let index = 0; index < context.args.length; index++) {
61
- const original = context.args[index];
68
+ for (let index = 0; index < args.length; index++) {
69
+ const original = args[index];
62
70
  checkPath(original, limits);
63
71
  const argument = literal ? original : normalizeZipOption(original);
64
72
  if (!literal && argument === "--") {
@@ -87,8 +95,8 @@ async function parse(scope, limits) {
87
95
  zip64 = argument[offset + 2] !== "-";
88
96
  offset += zip64 ? 1 : 2;
89
97
  }
90
- else if (flag === "d" || flag === "u" || flag === "f") {
91
- const next = flag === "d" ? "delete" : flag === "u" ? "update" : "freshen";
98
+ else if (flag === "d" || flag === "u" || flag === "f" || flag === "U") {
99
+ const next = flag === "d" ? "delete" : flag === "u" ? "update" : flag === "U" ? "copy" : "freshen";
92
100
  if (action !== "add" && action !== next)
93
101
  throw new ZipFailure(16, "Invalid command arguments", "specify just one action");
94
102
  action = next;
@@ -102,6 +110,18 @@ async function parse(scope, limits) {
102
110
  stopAtDirectories = true;
103
111
  offset++;
104
112
  }
113
+ else if (flag === "M" && argument[offset + 1] === "M") {
114
+ if (argument[offset + 2] === "-")
115
+ throw new ZipFailure(16, "Invalid command arguments", "option MM is not negatable");
116
+ mustMatch = true;
117
+ offset++;
118
+ }
119
+ else if (flag === "F" && argument[offset + 1] === "S") {
120
+ if (argument[offset + 2] === "-")
121
+ throw new ZipFailure(16, "Invalid command arguments", "option FS is not negatable");
122
+ filesync = true;
123
+ offset++;
124
+ }
105
125
  else if (flag === "q")
106
126
  quiet = true;
107
127
  else if (flag === "j")
@@ -124,10 +144,35 @@ async function parse(scope, limits) {
124
144
  if (level === 0)
125
145
  method = "store";
126
146
  }
147
+ else if (flag === "O") {
148
+ let value = argument.slice(offset + 1) || args[++index];
149
+ if (value?.startsWith("="))
150
+ value = value.slice(1);
151
+ if (value === undefined)
152
+ throw new ZipFailure(16, "Invalid command arguments", "option O requires a value");
153
+ output = value;
154
+ break;
155
+ }
156
+ else if (flag === "t") {
157
+ const option = argument[offset + 1] === "t" ? "tt" : "t";
158
+ if (option === "tt")
159
+ offset++;
160
+ let value = argument.slice(offset + 1);
161
+ if (!value)
162
+ value = args[++index] ?? "";
163
+ if (value.startsWith("="))
164
+ value = value.slice(1);
165
+ const date = parseZipDate(value, option);
166
+ if (option === "t")
167
+ fromDate = date;
168
+ else
169
+ beforeDate = date;
170
+ break;
171
+ }
127
172
  else if (flag === "n" || flag === "Z") {
128
173
  let value = argument.slice(offset + 1);
129
174
  if (!value) {
130
- const next = context.args[index + 1];
175
+ const next = args[index + 1];
131
176
  if (next === undefined || next.startsWith("-") && next !== "-")
132
177
  throw new ZipFailure(16, "Invalid command arguments", `option '${flag}' requires a value`);
133
178
  value = next;
@@ -166,8 +211,8 @@ async function parse(scope, limits) {
166
211
  const value = argument.slice(offset + 1);
167
212
  append(value.startsWith("=") ? value.slice(1) : value);
168
213
  }
169
- while (!attached && index + 1 < context.args.length) {
170
- const next = context.args[index + 1];
214
+ while (!attached && index + 1 < args.length) {
215
+ const next = args[index + 1];
171
216
  if (next === "@") {
172
217
  index++;
173
218
  break;
@@ -196,6 +241,8 @@ async function parse(scope, limits) {
196
241
  }
197
242
  }
198
243
  if (archive === undefined) {
244
+ if (includes.length || excludes.length)
245
+ throw new ZipFailure(16, "Invalid command arguments", "nothing to select from");
199
246
  if (action !== "add")
200
247
  throw new ZipFailure(16, "Invalid command arguments", "expected archive name");
201
248
  archive = "-";
@@ -205,6 +252,15 @@ async function parse(scope, limits) {
205
252
  if (archive !== "-" && !archive.slice(archive.lastIndexOf("/") + 1).includes("."))
206
253
  archive += ".zip";
207
254
  checkPath(archive, limits);
255
+ if (output !== undefined) {
256
+ if (!output.slice(output.lastIndexOf("/") + 1).includes("."))
257
+ output += ".zip";
258
+ checkPath(output, limits);
259
+ if (action === "add" && archive !== "-" && !operands.length && !stdinNames)
260
+ action = "copy";
261
+ }
262
+ if (action === "copy" && output === undefined)
263
+ throw new ZipFailure(16, "Invalid command arguments", "-U (--copy) requires -O (--out)");
208
264
  const names = [];
209
265
  if (stdinNames) {
210
266
  const input = await collectBytes(scope.stdin, { maxBytes: limits.maxFilesFromBytes, signal: context.signal });
@@ -234,7 +290,9 @@ async function parse(scope, limits) {
234
290
  }
235
291
  if (recursivePatterns && !names.length && !operands.length)
236
292
  throw new ZipFailure(16, "Invalid command arguments", "nothing to select from");
237
- return { action, archive, recursive, recursivePatterns, noWild, stopAtDirectories, quiet, junkPaths, omitDirectories, storeLinks, test, descriptors, zip64, metadata, includes, excludes, level, method, suffixes, operands: [...names, ...operands], firstOperand };
293
+ if (filesync && action !== "add")
294
+ throw new ZipFailure(16, "Invalid command arguments", "can't use -d, -f, -u, -U, or -g with filesync -FS\n");
295
+ return { args, action, archive, output, recursive, recursivePatterns, noWild, stopAtDirectories, quiet, junkPaths, omitDirectories, storeLinks, test, mustMatch, filesync, fromDate, beforeDate, descriptors, zip64, metadata, includes, excludes, level, method, suffixes, operands: [...names, ...operands], firstOperand };
238
296
  }
239
297
  function memberName(path, limits) {
240
298
  if (path.startsWith("//") && !path.startsWith("///"))
@@ -288,7 +346,7 @@ async function prepare(scope, parsed, budget) {
288
346
  throw new ZipFailure(16, "Invalid command arguments", "can't use -d, -f, -u, -U, or -g on stdout\n");
289
347
  let publication;
290
348
  if (parsed.archive !== "-") {
291
- const outputName = vfsPath(context.cwd, parsed.archive);
349
+ const outputName = vfsPath(context.cwd, parsed.output ?? parsed.archive);
292
350
  const parentName = dirname(outputName);
293
351
  const parent = await scope.operation(() => context.fs.realpath(parentName, { signal: context.signal }));
294
352
  const parentStat = await scope.operation(() => context.fs.lstat(parent, { signal: context.signal }));
@@ -298,20 +356,47 @@ async function prepare(scope, parsed, budget) {
298
356
  publication = { output, parentName, parent, parentStat, existing };
299
357
  }
300
358
  const output = publication?.output;
301
- const existing = publication?.existing;
359
+ let input = publication?.output;
360
+ let existing = publication?.existing;
361
+ if (parsed.output !== undefined) {
362
+ if (parsed.archive === "-") {
363
+ input = undefined;
364
+ existing = undefined;
365
+ }
366
+ else {
367
+ const name = vfsPath(context.cwd, parsed.archive);
368
+ try {
369
+ const parent = await scope.operation(() => context.fs.realpath(dirname(name), { signal: context.signal }));
370
+ input = `${parent === "/" ? "" : parent}/${name.slice(name.lastIndexOf("/") + 1)}`;
371
+ existing = await scope.stat(input);
372
+ }
373
+ catch (error) {
374
+ context.signal.throwIfAborted();
375
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "EACCES"))
376
+ throw new ZipFailure(18, "File not found or no read permission", parsed.archive);
377
+ throw error;
378
+ }
379
+ if (input === output || existing && publication?.existing && sameIdentity(existing, publication.existing))
380
+ throw new ZipFailure(16, "Invalid command arguments", `--out path must be different than in path: ${parsed.archive}`);
381
+ }
382
+ }
383
+ if ((parsed.action === "copy" || parsed.output !== undefined && parsed.archive !== "-") && !existing)
384
+ throw new ZipFailure(18, "File not found or no read permission", parsed.archive);
385
+ if (publication?.existing && (publication.existing.type !== "file" || !hasIdentity(publication.existing) || publication.existing.nlink !== 1))
386
+ fail("output archive requires a regular, single-link file with known backing identity");
302
387
  if (parsed.archive === "-" && parsed.test && !parsed.quiet)
303
388
  await budget.output("\tzip warning: can't use -T on stdout, -T ignored\n");
304
389
  if (existing && (existing.type !== "file" || !hasIdentity(existing) || existing.nlink !== 1))
305
390
  fail("updating archive requires a regular, single-link file with known backing identity; archive aliases are unsupported");
306
391
  let archive = { entries: [], comment: new Uint8Array() };
307
- if (existing && publication) {
392
+ if (existing && input) {
308
393
  if (!Number.isSafeInteger(existing.size) || existing.size < 0 || existing.size > limits.maxArchiveBytes)
309
394
  fail("archive byte limit exceeded");
310
- const bytes = await collectBytes(scope.input(publication.output), { maxBytes: limits.maxArchiveBytes, signal: context.signal });
395
+ const bytes = await collectBytes(scope.input(input), { maxBytes: limits.maxArchiveBytes, signal: context.signal });
311
396
  if (bytes.length !== existing.size)
312
397
  fail("archive changed while reading");
313
398
  archive = await readZipArchive(bytes, limits, context.signal);
314
- const current = await scope.stat(publication.output);
399
+ const current = await scope.stat(input);
315
400
  if (!current || !unchanged(existing, current))
316
401
  fail("archive changed while reading");
317
402
  }
@@ -320,8 +405,10 @@ async function prepare(scope, parsed, budget) {
320
405
  await budget.output(`\tzip warning: ${parsed.archive} not found or empty\n`);
321
406
  const selected = new Map();
322
407
  const deleted = new Set();
408
+ const synchronized = new Map();
323
409
  const selection = new Selection([...parsed.includes, ...parsed.excludes], limits, context.signal, { noWild: parsed.noWild, stopAtDirectories: parsed.stopAtDirectories });
324
410
  const recursiveSelection = parsed.recursivePatterns ? new Selection(parsed.operands, limits, context.signal, { noWild: parsed.noWild, stopAtDirectories: parsed.stopAtDirectories, trailingComponents: true }) : undefined;
411
+ let archiveOperandMatches;
325
412
  const ancestors = [];
326
413
  let visits = 0;
327
414
  let work = 0;
@@ -364,6 +451,13 @@ async function prepare(scope, parsed, budget) {
364
451
  return;
365
452
  const prior = old.get(name);
366
453
  const modified = new Date();
454
+ if (!zipDateMatches(modified, parsed.fromDate, parsed.beforeDate))
455
+ return;
456
+ if (parsed.filesync) {
457
+ if (synchronized.has(name) && synchronized.get(name) !== source)
458
+ throw new ZipFailure(16, "Invalid command arguments", "cannot repeat names in zip file");
459
+ synchronized.set(name, source);
460
+ }
367
461
  if (parsed.action === "freshen" && !prior || prior && (parsed.action === "update" || parsed.action === "freshen") && Math.floor(modified.getTime() / 1000) <= Math.floor(prior.modified.getTime() / 1000))
368
462
  return;
369
463
  const bytes = await collectBytes(scope.stdin, { maxBytes: Math.min(limits.maxEntryBytes, limits.maxTotalBytes - budget.totalBytes), signal: context.signal });
@@ -380,14 +474,34 @@ async function prepare(scope, parsed, budget) {
380
474
  }
381
475
  catch (error) {
382
476
  context.signal.throwIfAborted();
383
- if (typeof error !== "object" || error === null || !("code" in error) || error.code !== "ENOENT")
477
+ if (typeof error !== "object" || error === null || !("code" in error))
384
478
  throw error;
479
+ if (parsed.mustMatch && error.code === "EACCES")
480
+ throw new ZipFailure(18, "File not found or no read permission", source);
481
+ if (error.code !== "ENOENT")
482
+ throw error;
483
+ if (parsed.mustMatch && !old.has(name)) {
484
+ if (!archiveOperandMatches) {
485
+ const fallback = new Selection(parsed.operands.map(operand => {
486
+ const pattern = memberName(operand, limits);
487
+ return parsed.junkPaths ? pattern.slice(pattern.lastIndexOf("/") + 1) : pattern;
488
+ }), limits, context.signal, { noWild: parsed.noWild, stopAtDirectories: parsed.stopAtDirectories });
489
+ for (const entry of archive.entries)
490
+ await fallback.matches(entry.name);
491
+ archiveOperandMatches = new Set([...fallback.matched].map(index => parsed.operands[index]));
492
+ }
493
+ if (archiveOperandMatches.has(source))
494
+ return;
495
+ if (!parsed.quiet)
496
+ await budget.output(`\tzip warning: name not matched: ${source}\n`);
497
+ throw new ZipFailure(18, "File not found or no read permission", source);
498
+ }
385
499
  if (!parsed.quiet && !old.has(name))
386
500
  await budget.output(`\tzip warning: name not matched: ${source}\n`);
387
501
  return;
388
502
  }
389
503
  checkPath(canonical, limits);
390
- if (canonical === output || (existing && sameIdentity(existing, stat)))
504
+ if (canonical === output || canonical === input || (existing && sameIdentity(existing, stat)) || (publication?.existing && sameIdentity(publication.existing, stat)))
391
505
  return;
392
506
  const symlink = parsed.storeLinks && stat.type === "symlink";
393
507
  if (stat.type !== "file" && stat.type !== "directory" && !symlink) {
@@ -395,19 +509,26 @@ async function prepare(scope, parsed, budget) {
395
509
  await budget.output(`\tzip warning: ignoring special file: ${source}\n`);
396
510
  return;
397
511
  }
398
- if (existing && !hasIdentity(stat))
512
+ if ((existing || publication?.existing) && !hasIdentity(stat))
399
513
  fail("cannot exclude archive aliases when source backing identity is unknown");
400
514
  const directory = stat.type === "directory";
401
515
  if (directory && name && !name.endsWith("/"))
402
516
  name += "/";
403
- const included = await filterName(name, selection, parsed.includes.length) && (!recursiveSelection || await recursiveSelection.matches(name, true));
517
+ const included = zipDateMatches(new Date(stat.mtimeMs), parsed.fromDate, parsed.beforeDate) && await filterName(name, selection, parsed.includes.length) && (!recursiveSelection || await recursiveSelection.matches(name, true));
404
518
  const sourceName = name;
405
519
  if (parsed.junkPaths)
406
520
  name = directory ? "" : name.slice(name.lastIndexOf("/") + 1);
407
521
  const prior = old.get(name);
522
+ if (parsed.filesync && name && included && !(directory && parsed.omitDirectories)) {
523
+ if (synchronized.has(name) && synchronized.get(name) !== source)
524
+ throw new ZipFailure(16, "Invalid command arguments", "cannot repeat names in zip file");
525
+ synchronized.set(name, source);
526
+ }
527
+ const current = parsed.filesync && prior && prior.size === (directory ? 0 : stat.size)
528
+ && Math.ceil(Math.floor(stat.mtimeMs / 1000) / 2) === Math.ceil(Math.floor(prior.modified.getTime() / 1000) / 2);
408
529
  const eligible = parsed.action !== "update" && parsed.action !== "freshen"
409
530
  || (prior ? Math.floor(stat.mtimeMs / 1000) > Math.floor(prior.modified.getTime() / 1000) : parsed.action === "update");
410
- if (name && included && eligible && !(directory && parsed.omitDirectories)) {
531
+ if (name && included && eligible && !current && !(directory && parsed.omitDirectories)) {
411
532
  checkPath(name, limits);
412
533
  const previous = selected.get(name);
413
534
  if (previous && previous.source !== source) {
@@ -428,8 +549,17 @@ async function prepare(scope, parsed, budget) {
428
549
  fail(`source changed while reading: ${source}`);
429
550
  bytes = Buffer.from(target);
430
551
  }
431
- else
432
- bytes = await collectBytes(scope.input(path), { maxBytes: stat.size, signal: context.signal });
552
+ else {
553
+ try {
554
+ bytes = await collectBytes(scope.input(path), { maxBytes: stat.size, signal: context.signal });
555
+ }
556
+ catch (error) {
557
+ context.signal.throwIfAborted();
558
+ if (parsed.mustMatch && typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "EACCES"))
559
+ throw new ZipFailure(18, "File not found or no read permission", `was zipping ${source}`);
560
+ throw error;
561
+ }
562
+ }
433
563
  if (!directory && bytes.length !== stat.size)
434
564
  fail(`source changed while reading: ${source}`);
435
565
  const current = await inspectSource(scope, path, parsed.storeLinks);
@@ -458,7 +588,16 @@ async function prepare(scope, parsed, budget) {
458
588
  }
459
589
  }
460
590
  };
461
- if (parsed.action === "delete") {
591
+ if (parsed.action === "copy") {
592
+ const operands = new Selection(parsed.operands, limits, context.signal, { noWild: parsed.noWild, stopAtDirectories: parsed.stopAtDirectories });
593
+ for (const entry of archive.entries) {
594
+ if (await operands.matches(entry.name) && await filterName(entry.name, selection, parsed.includes.length) && zipDateMatches(entry.modified, parsed.fromDate, parsed.beforeDate)) {
595
+ await budget.member(entry.size);
596
+ selected.set(entry.name, { entry, source: entry.name });
597
+ }
598
+ }
599
+ }
600
+ else if (parsed.action === "delete") {
462
601
  if (!parsed.quiet && parsed.recursive)
463
602
  await budget.output("\tzip warning: invalid option(s) used with -d; ignored.\n");
464
603
  if (!parsed.quiet && !archive.entries.length)
@@ -466,10 +605,16 @@ async function prepare(scope, parsed, budget) {
466
605
  const operands = new Selection(parsed.recursivePatterns ? [] : parsed.operands, limits, context.signal, { noWild: parsed.noWild, stopAtDirectories: parsed.stopAtDirectories });
467
606
  if (parsed.operands.length && !parsed.recursivePatterns) {
468
607
  for (const entry of archive.entries) {
469
- if (await operands.matches(entry.name) && await filterName(entry.name, selection, parsed.includes.length))
608
+ if (await operands.matches(entry.name) && await filterName(entry.name, selection, parsed.includes.length) && zipDateMatches(entry.modified, parsed.fromDate, parsed.beforeDate))
470
609
  deleted.add(entry.name);
471
610
  }
472
611
  }
612
+ if (parsed.mustMatch && !parsed.recursivePatterns) {
613
+ for (const [index, operand] of parsed.operands.entries()) {
614
+ if (!operands.matched.has(index))
615
+ throw new ZipFailure(18, "File not found or no read permission", operand);
616
+ }
617
+ }
473
618
  if (!parsed.quiet) {
474
619
  for (const [index, operand] of parsed.operands.entries()) {
475
620
  if (!operands.matched.has(index))
@@ -485,11 +630,23 @@ async function prepare(scope, parsed, budget) {
485
630
  for (const operand of operands)
486
631
  await visit(operand, memberName(operand, limits), 0);
487
632
  }
633
+ if (parsed.filesync) {
634
+ if (!synchronized.size)
635
+ throw new ZipFailure(12, "Nothing to do!", parsed.archive);
636
+ for (const entry of archive.entries)
637
+ if (!synchronized.has(entry.name))
638
+ deleted.add(entry.name);
639
+ if (!selected.size && !deleted.size) {
640
+ if (!parsed.quiet)
641
+ await budget.output("Archive is current\n");
642
+ return { kind: "current" };
643
+ }
644
+ }
488
645
  if (!selected.size && (parsed.action === "freshen" || parsed.action === "update" && (existing || !parsed.includes.length)))
489
646
  return undefined;
490
- if (!selected.size && !deleted.size && (parsed.action === "delete" || parsed.recursivePatterns || !parsed.includes.length)) {
647
+ if (!selected.size && !deleted.size && (parsed.action === "delete" || parsed.action === "copy" || parsed.recursivePatterns || parsed.fromDate !== undefined || parsed.beforeDate !== undefined || !parsed.includes.length)) {
491
648
  const detail = parsed.action !== "delete" && parsed.recursive && parsed.firstOperand >= 0
492
- ? `try: zip ${context.args.slice(0, parsed.firstOperand).join(" ")} . -i ${context.args.slice(parsed.firstOperand).join(" ")}`
649
+ ? `try: zip ${parsed.args.slice(0, parsed.firstOperand).join(" ")} . -i ${parsed.args.slice(parsed.firstOperand).join(" ")}`
493
650
  : parsed.archive;
494
651
  throw new ZipFailure(12, "Nothing to do!", detail);
495
652
  }
@@ -517,6 +674,14 @@ async function prepare(scope, parsed, budget) {
517
674
  continue;
518
675
  }
519
676
  const replacement = selected.get(entry.name);
677
+ if (parsed.action === "copy") {
678
+ if (replacement) {
679
+ entries.push(replacement.entry);
680
+ queue(` copying: ${entry.name}\n`);
681
+ selected.delete(entry.name);
682
+ }
683
+ continue;
684
+ }
520
685
  if (replacement) {
521
686
  entries.push(replacement.entry);
522
687
  append(replacement.entry, true);
@@ -533,7 +698,7 @@ async function prepare(scope, parsed, budget) {
533
698
  }
534
699
  if (!entries.length)
535
700
  queue("\tzip warning: zip file empty\n");
536
- if (parsed.archive === "-")
701
+ if (!publication)
537
702
  return { kind: "stream", archive: { entries, comment: archive.comment }, progress };
538
703
  const bytes = await writeZipArchive({ entries, comment: archive.comment }, limits, context.signal, false, parsed.zip64 === true);
539
704
  if (parsed.test && parsed.archive !== "-") {
@@ -580,6 +745,8 @@ export function createZipCommand(options = {}) {
580
745
  const prepared = await prepare(scope, parsed, budget);
581
746
  if (!prepared)
582
747
  return { exitCode: 12 };
748
+ if (prepared.kind === "current")
749
+ return { exitCode: 0 };
583
750
  if (prepared.kind === "file") {
584
751
  const publication = prepared.publication;
585
752
  if (!publication)