mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
perf: fs optimizations - part 1 (#15873)
This commit is contained in:
parent
11ced3c10e
commit
698a340ad7
7 changed files with 595 additions and 320 deletions
1
cli/bench/fs/.gitignore
vendored
Normal file
1
cli/bench/fs/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.json
|
26
cli/bench/fs/README.md
Normal file
26
cli/bench/fs/README.md
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
## `fs` benchmarks
|
||||||
|
|
||||||
|
### adding new benchmarks
|
||||||
|
|
||||||
|
```js
|
||||||
|
const copyFileSync = getFunction("copyFileSync");
|
||||||
|
bench(() => copyFileSync("test", "test2"));
|
||||||
|
|
||||||
|
// For functions with side-effects, clean up after `bench` like so:
|
||||||
|
const removeSync = getFunction("removeSync");
|
||||||
|
removeSync("test2");
|
||||||
|
```
|
||||||
|
|
||||||
|
### running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
deno run -A --unstable run.mjs
|
||||||
|
node run.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### view report
|
||||||
|
|
||||||
|
```bash
|
||||||
|
deno run --allow-net=127.0.0.1:9000 serve.jsx
|
||||||
|
# View rendered report at http://127.0.0.1:9000/
|
||||||
|
```
|
66
cli/bench/fs/run.mjs
Normal file
66
cli/bench/fs/run.mjs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
let total = 5;
|
||||||
|
let current = "";
|
||||||
|
const values = {};
|
||||||
|
const runtime = typeof Deno !== "undefined" ? "deno" : "node";
|
||||||
|
|
||||||
|
function bench(fun, count = 100000) {
|
||||||
|
if (total === 5) console.log(fun.toString());
|
||||||
|
const start = Date.now();
|
||||||
|
for (let i = 0; i < count; i++) fun();
|
||||||
|
const elapsed = Date.now() - start;
|
||||||
|
const rate = Math.floor(count / (elapsed / 1000));
|
||||||
|
console.log(`time ${elapsed} ms rate ${rate}`);
|
||||||
|
values[current] = values[current] || [];
|
||||||
|
values[current].push(rate);
|
||||||
|
if (--total) bench(fun, count);
|
||||||
|
else total = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fs;
|
||||||
|
if (runtime === "node") {
|
||||||
|
fs = await import("fs");
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFunction = runtime === "deno"
|
||||||
|
? (name) => {
|
||||||
|
current = name;
|
||||||
|
return Deno[name];
|
||||||
|
}
|
||||||
|
: (name) => {
|
||||||
|
current = name;
|
||||||
|
return fs[name];
|
||||||
|
};
|
||||||
|
|
||||||
|
const writeFileSync = getFunction("writeFileSync");
|
||||||
|
writeFileSync("test", new Uint8Array(1024 * 1024), { truncate: true });
|
||||||
|
|
||||||
|
const copyFileSync = getFunction("copyFileSync");
|
||||||
|
bench(() => copyFileSync("test", "test2"), 10000);
|
||||||
|
|
||||||
|
const truncateSync = getFunction("truncateSync");
|
||||||
|
bench(() => truncateSync("test", 0));
|
||||||
|
|
||||||
|
const lstatSync = getFunction("lstatSync");
|
||||||
|
bench(() => lstatSync("test"));
|
||||||
|
|
||||||
|
const { uid, gid } = lstatSync("test");
|
||||||
|
|
||||||
|
const chownSync = getFunction("chownSync");
|
||||||
|
bench(() => chownSync("test", uid, gid));
|
||||||
|
|
||||||
|
const chmodSync = getFunction("chmodSync");
|
||||||
|
bench(() => chmodSync("test", 0o666));
|
||||||
|
|
||||||
|
// const cwd = getFunction("cwd");
|
||||||
|
// bench(() => cwd());
|
||||||
|
|
||||||
|
// const chdir = getFunction("chdir");
|
||||||
|
// bench(() => chdir("/"));
|
||||||
|
|
||||||
|
const readFileSync = getFunction("readFileSync");
|
||||||
|
writeFileSync("test", new Uint8Array(1024), { truncate: true });
|
||||||
|
bench(() => readFileSync("test"));
|
||||||
|
|
||||||
|
writeFileSync(new URL(`./${runtime}.json`, import.meta.url), new TextEncoder().encode(JSON.stringify(values, null, 2)), { truncate: true });
|
57
cli/bench/fs/serve.jsx
Normal file
57
cli/bench/fs/serve.jsx
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
/** @jsx h */
|
||||||
|
import results from "./deno.json" assert { type: "json" };
|
||||||
|
import nodeResults from "./node.json" assert { type: "json" };
|
||||||
|
import { h, ssr } from "https://crux.land/nanossr@0.0.4";
|
||||||
|
import { router } from "https://crux.land/router@0.0.11";
|
||||||
|
|
||||||
|
function once(fn) {
|
||||||
|
let called = false;
|
||||||
|
let result;
|
||||||
|
return function () {
|
||||||
|
if (!called) {
|
||||||
|
called = true;
|
||||||
|
result = fn();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = once(() =>
|
||||||
|
Object.entries(results).map(([name, data]) => (
|
||||||
|
<tr>
|
||||||
|
<td class="border px-4 py-2">{name}</td>
|
||||||
|
<td class="border px-4 py-2">
|
||||||
|
{data.reduce((a, b) => a + b, 0) / data.length} ops/sec
|
||||||
|
</td>
|
||||||
|
<td class="border px-4 py-2">
|
||||||
|
{nodeResults[name].reduce((a, b) => a + b, 0) /
|
||||||
|
nodeResults[name].length} ops/sec
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<table class="table-auto">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="px-4 py-2">Benchmark</th>
|
||||||
|
<th class="px-4 py-2">Deno</th>
|
||||||
|
<th class="px-4 py-2">Node</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{body()}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { serve } = Deno;
|
||||||
|
serve(router({
|
||||||
|
"/": () => ssr(() => <App />),
|
||||||
|
}));
|
|
@ -11,16 +11,19 @@
|
||||||
ObjectPrototypeIsPrototypeOf,
|
ObjectPrototypeIsPrototypeOf,
|
||||||
SymbolAsyncIterator,
|
SymbolAsyncIterator,
|
||||||
SymbolIterator,
|
SymbolIterator,
|
||||||
|
Function,
|
||||||
|
ObjectEntries,
|
||||||
|
Uint32Array,
|
||||||
} = window.__bootstrap.primordials;
|
} = window.__bootstrap.primordials;
|
||||||
const { pathFromURL } = window.__bootstrap.util;
|
const { pathFromURL } = window.__bootstrap.util;
|
||||||
const build = window.__bootstrap.build.build;
|
const build = window.__bootstrap.build.build;
|
||||||
|
|
||||||
function chmodSync(path, mode) {
|
function chmodSync(path, mode) {
|
||||||
ops.op_chmod_sync({ path: pathFromURL(path), mode });
|
ops.op_chmod_sync(pathFromURL(path), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chmod(path, mode) {
|
async function chmod(path, mode) {
|
||||||
await core.opAsync("op_chmod_async", { path: pathFromURL(path), mode });
|
await core.opAsync("op_chmod_async", pathFromURL(path), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
function chownSync(
|
function chownSync(
|
||||||
|
@ -28,7 +31,7 @@
|
||||||
uid,
|
uid,
|
||||||
gid,
|
gid,
|
||||||
) {
|
) {
|
||||||
ops.op_chown_sync({ path: pathFromURL(path), uid, gid });
|
ops.op_chown_sync(pathFromURL(path), uid, gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chown(
|
async function chown(
|
||||||
|
@ -38,7 +41,9 @@
|
||||||
) {
|
) {
|
||||||
await core.opAsync(
|
await core.opAsync(
|
||||||
"op_chown_async",
|
"op_chown_async",
|
||||||
{ path: pathFromURL(path), uid, gid },
|
pathFromURL(path),
|
||||||
|
uid,
|
||||||
|
gid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,20 +51,21 @@
|
||||||
fromPath,
|
fromPath,
|
||||||
toPath,
|
toPath,
|
||||||
) {
|
) {
|
||||||
ops.op_copy_file_sync({
|
ops.op_copy_file_sync(
|
||||||
from: pathFromURL(fromPath),
|
pathFromURL(fromPath),
|
||||||
to: pathFromURL(toPath),
|
pathFromURL(toPath),
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function copyFile(
|
async function copyFile(
|
||||||
fromPath,
|
fromPath,
|
||||||
toPath,
|
toPath,
|
||||||
) {
|
) {
|
||||||
await core.opAsync("op_copy_file_async", {
|
await core.opAsync(
|
||||||
from: pathFromURL(fromPath),
|
"op_copy_file_async",
|
||||||
to: pathFromURL(toPath),
|
pathFromURL(fromPath),
|
||||||
});
|
pathFromURL(toPath),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cwd() {
|
function cwd() {
|
||||||
|
@ -148,36 +154,111 @@
|
||||||
path,
|
path,
|
||||||
options = {},
|
options = {},
|
||||||
) {
|
) {
|
||||||
ops.op_remove_sync({
|
ops.op_remove_sync(
|
||||||
path: pathFromURL(path),
|
pathFromURL(path),
|
||||||
recursive: !!options.recursive,
|
!!options.recursive,
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function remove(
|
async function remove(
|
||||||
path,
|
path,
|
||||||
options = {},
|
options = {},
|
||||||
) {
|
) {
|
||||||
await core.opAsync("op_remove_async", {
|
await core.opAsync(
|
||||||
path: pathFromURL(path),
|
"op_remove_async",
|
||||||
recursive: !!options.recursive,
|
pathFromURL(path),
|
||||||
});
|
!!options.recursive,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renameSync(oldpath, newpath) {
|
function renameSync(oldpath, newpath) {
|
||||||
ops.op_rename_sync({
|
ops.op_rename_sync(
|
||||||
oldpath: pathFromURL(oldpath),
|
pathFromURL(oldpath),
|
||||||
newpath: pathFromURL(newpath),
|
pathFromURL(newpath),
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rename(oldpath, newpath) {
|
async function rename(oldpath, newpath) {
|
||||||
await core.opAsync("op_rename_async", {
|
await core.opAsync(
|
||||||
oldpath: pathFromURL(oldpath),
|
"op_rename_async",
|
||||||
newpath: pathFromURL(newpath),
|
pathFromURL(oldpath),
|
||||||
});
|
pathFromURL(newpath),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract the FsStat object from the encoded buffer.
|
||||||
|
// See `runtime/ops/fs.rs` for the encoder.
|
||||||
|
//
|
||||||
|
// This is not a general purpose decoder. There are 4 types:
|
||||||
|
//
|
||||||
|
// 1. date
|
||||||
|
// offset += 4
|
||||||
|
// 1/0 | extra padding | high u32 | low u32
|
||||||
|
// if date[0] == 1, new Date(u64) else null
|
||||||
|
//
|
||||||
|
// 2. bool
|
||||||
|
// offset += 2
|
||||||
|
// 1/0 | extra padding
|
||||||
|
//
|
||||||
|
// 3. u64
|
||||||
|
// offset += 2
|
||||||
|
// high u32 | low u32
|
||||||
|
//
|
||||||
|
// 4. ?u64 converts a zero u64 value to JS null on Windows.
|
||||||
|
function createByteStruct(types) {
|
||||||
|
// types can be "date", "bool" or "u64".
|
||||||
|
// `?` prefix means optional on windows.
|
||||||
|
let offset = 0;
|
||||||
|
let str =
|
||||||
|
'const unix = Deno.build.os === "darwin" || Deno.build.os === "linux"; return {';
|
||||||
|
for (let [name, type] of ObjectEntries(types)) {
|
||||||
|
const optional = type.startsWith("?");
|
||||||
|
if (optional) type = type.slice(1);
|
||||||
|
|
||||||
|
if (type == "u64") {
|
||||||
|
if (!optional) {
|
||||||
|
str += `${name}: view[${offset}] + view[${offset + 1}] * 2**32,`;
|
||||||
|
} else {
|
||||||
|
str += `${name}: (unix ? (view[${offset}] + view[${
|
||||||
|
offset + 1
|
||||||
|
}] * 2**32) : (view[${offset}] + view[${
|
||||||
|
offset + 1
|
||||||
|
}] * 2**32) || null),`;
|
||||||
|
}
|
||||||
|
} else if (type == "date") {
|
||||||
|
str += `${name}: view[${offset}] === 0 ? null : new Date(view[${
|
||||||
|
offset + 2
|
||||||
|
}] + view[${offset + 3}] * 2**32),`;
|
||||||
|
offset += 2;
|
||||||
|
} else {
|
||||||
|
str += `${name}: !!(view[${offset}] + view[${offset + 1}] * 2**32),`;
|
||||||
|
}
|
||||||
|
offset += 2;
|
||||||
|
}
|
||||||
|
str += "};";
|
||||||
|
// ...so you don't like eval huh? don't worry, it only executes during snapshot :)
|
||||||
|
return [new Function("view", str), new Uint32Array(offset)];
|
||||||
|
}
|
||||||
|
|
||||||
|
const [statStruct, statBuf] = createByteStruct({
|
||||||
|
isFile: "bool",
|
||||||
|
isDirectory: "bool",
|
||||||
|
isSymlink: "bool",
|
||||||
|
size: "u64",
|
||||||
|
mtime: "date",
|
||||||
|
atime: "date",
|
||||||
|
birthtime: "date",
|
||||||
|
dev: "?u64",
|
||||||
|
ino: "?u64",
|
||||||
|
mode: "?u64",
|
||||||
|
nlink: "?u64",
|
||||||
|
uid: "?u64",
|
||||||
|
gid: "?u64",
|
||||||
|
rdev: "?u64",
|
||||||
|
blksize: "?u64",
|
||||||
|
blocks: "?u64",
|
||||||
|
});
|
||||||
|
|
||||||
function parseFileInfo(response) {
|
function parseFileInfo(response) {
|
||||||
const unix = build.os === "darwin" || build.os === "linux";
|
const unix = build.os === "darwin" || build.os === "linux";
|
||||||
return {
|
return {
|
||||||
|
@ -185,9 +266,9 @@
|
||||||
isDirectory: response.isDirectory,
|
isDirectory: response.isDirectory,
|
||||||
isSymlink: response.isSymlink,
|
isSymlink: response.isSymlink,
|
||||||
size: response.size,
|
size: response.size,
|
||||||
mtime: response.mtime != null ? new Date(response.mtime) : null,
|
mtime: response.mtimeSet !== null ? new Date(response.mtime) : null,
|
||||||
atime: response.atime != null ? new Date(response.atime) : null,
|
atime: response.atimeSet !== null ? new Date(response.atime) : null,
|
||||||
birthtime: response.birthtime != null
|
birthtime: response.birthtimeSet !== null
|
||||||
? new Date(response.birthtime)
|
? new Date(response.birthtime)
|
||||||
: null,
|
: null,
|
||||||
// Only non-null if on Unix
|
// Only non-null if on Unix
|
||||||
|
@ -204,7 +285,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function fstatSync(rid) {
|
function fstatSync(rid) {
|
||||||
return parseFileInfo(ops.op_fstat_sync(rid));
|
ops.op_fstat_sync(rid, statBuf);
|
||||||
|
return statStruct(statBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fstat(rid) {
|
async function fstat(rid) {
|
||||||
|
@ -220,11 +302,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function lstatSync(path) {
|
function lstatSync(path) {
|
||||||
const res = ops.op_stat_sync({
|
ops.op_stat_sync(
|
||||||
path: pathFromURL(path),
|
pathFromURL(path),
|
||||||
lstat: true,
|
true,
|
||||||
});
|
statBuf,
|
||||||
return parseFileInfo(res);
|
);
|
||||||
|
return statStruct(statBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function stat(path) {
|
async function stat(path) {
|
||||||
|
@ -236,11 +319,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function statSync(path) {
|
function statSync(path) {
|
||||||
const res = ops.op_stat_sync({
|
ops.op_stat_sync(
|
||||||
path: pathFromURL(path),
|
pathFromURL(path),
|
||||||
lstat: false,
|
false,
|
||||||
});
|
statBuf,
|
||||||
return parseFileInfo(res);
|
);
|
||||||
|
return statStruct(statBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
function coerceLen(len) {
|
function coerceLen(len) {
|
||||||
|
@ -252,19 +336,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function ftruncateSync(rid, len) {
|
function ftruncateSync(rid, len) {
|
||||||
ops.op_ftruncate_sync({ rid, len: coerceLen(len) });
|
ops.op_ftruncate_sync(rid, coerceLen(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ftruncate(rid, len) {
|
async function ftruncate(rid, len) {
|
||||||
await core.opAsync("op_ftruncate_async", { rid, len: coerceLen(len) });
|
await core.opAsync("op_ftruncate_async", rid, coerceLen(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
function truncateSync(path, len) {
|
function truncateSync(path, len) {
|
||||||
ops.op_truncate_sync({ path, len: coerceLen(len) });
|
ops.op_truncate_sync(path, coerceLen(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function truncate(path, len) {
|
async function truncate(path, len) {
|
||||||
await core.opAsync("op_truncate_async", { path, len: coerceLen(len) });
|
await core.opAsync("op_truncate_async", path, coerceLen(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
function umask(mask) {
|
function umask(mask) {
|
||||||
|
@ -272,11 +356,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function linkSync(oldpath, newpath) {
|
function linkSync(oldpath, newpath) {
|
||||||
ops.op_link_sync({ oldpath, newpath });
|
ops.op_link_sync(oldpath, newpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function link(oldpath, newpath) {
|
async function link(oldpath, newpath) {
|
||||||
await core.opAsync("op_link_async", { oldpath, newpath });
|
await core.opAsync("op_link_async", oldpath, newpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toUnixTimeFromEpoch(value) {
|
function toUnixTimeFromEpoch(value) {
|
||||||
|
@ -305,11 +389,9 @@
|
||||||
atime,
|
atime,
|
||||||
mtime,
|
mtime,
|
||||||
) {
|
) {
|
||||||
ops.op_futime_sync({
|
const [atimeSec, atimeNsec] = toUnixTimeFromEpoch(atime);
|
||||||
rid,
|
const [mtimeSec, mtimeNsec] = toUnixTimeFromEpoch(mtime);
|
||||||
atime: toUnixTimeFromEpoch(atime),
|
ops.op_futime_sync(rid, atimeSec, atimeNsec, mtimeSec, mtimeNsec);
|
||||||
mtime: toUnixTimeFromEpoch(mtime),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function futime(
|
async function futime(
|
||||||
|
@ -317,11 +399,16 @@
|
||||||
atime,
|
atime,
|
||||||
mtime,
|
mtime,
|
||||||
) {
|
) {
|
||||||
await core.opAsync("op_futime_async", {
|
const [atimeSec, atimeNsec] = toUnixTimeFromEpoch(atime);
|
||||||
|
const [mtimeSec, mtimeNsec] = toUnixTimeFromEpoch(mtime);
|
||||||
|
await core.opAsync(
|
||||||
|
"op_futime_async",
|
||||||
rid,
|
rid,
|
||||||
atime: toUnixTimeFromEpoch(atime),
|
atimeSec,
|
||||||
mtime: toUnixTimeFromEpoch(mtime),
|
atimeNsec,
|
||||||
});
|
mtimeSec,
|
||||||
|
mtimeNsec,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function utimeSync(
|
function utimeSync(
|
||||||
|
@ -329,11 +416,15 @@
|
||||||
atime,
|
atime,
|
||||||
mtime,
|
mtime,
|
||||||
) {
|
) {
|
||||||
ops.op_utime_sync({
|
const [atimeSec, atimeNsec] = toUnixTimeFromEpoch(atime);
|
||||||
path: pathFromURL(path),
|
const [mtimeSec, mtimeNsec] = toUnixTimeFromEpoch(mtime);
|
||||||
atime: toUnixTimeFromEpoch(atime),
|
ops.op_utime_sync(
|
||||||
mtime: toUnixTimeFromEpoch(mtime),
|
pathFromURL(path),
|
||||||
});
|
atimeSec,
|
||||||
|
atimeNsec,
|
||||||
|
mtimeSec,
|
||||||
|
mtimeNsec,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function utime(
|
async function utime(
|
||||||
|
@ -341,11 +432,16 @@
|
||||||
atime,
|
atime,
|
||||||
mtime,
|
mtime,
|
||||||
) {
|
) {
|
||||||
await core.opAsync("op_utime_async", {
|
const [atimeSec, atimeNsec] = toUnixTimeFromEpoch(atime);
|
||||||
path: pathFromURL(path),
|
const [mtimeSec, mtimeNsec] = toUnixTimeFromEpoch(mtime);
|
||||||
atime: toUnixTimeFromEpoch(atime),
|
await core.opAsync(
|
||||||
mtime: toUnixTimeFromEpoch(mtime),
|
"op_utime_async",
|
||||||
});
|
pathFromURL(path),
|
||||||
|
atimeSec,
|
||||||
|
atimeNsec,
|
||||||
|
mtimeSec,
|
||||||
|
mtimeNsec,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function symlinkSync(
|
function symlinkSync(
|
||||||
|
@ -353,11 +449,11 @@
|
||||||
newpath,
|
newpath,
|
||||||
options,
|
options,
|
||||||
) {
|
) {
|
||||||
ops.op_symlink_sync({
|
ops.op_symlink_sync(
|
||||||
oldpath: pathFromURL(oldpath),
|
pathFromURL(oldpath),
|
||||||
newpath: pathFromURL(newpath),
|
pathFromURL(newpath),
|
||||||
options,
|
options?.type,
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function symlink(
|
async function symlink(
|
||||||
|
@ -365,11 +461,12 @@
|
||||||
newpath,
|
newpath,
|
||||||
options,
|
options,
|
||||||
) {
|
) {
|
||||||
await core.opAsync("op_symlink_async", {
|
await core.opAsync(
|
||||||
oldpath: pathFromURL(oldpath),
|
"op_symlink_async",
|
||||||
newpath: pathFromURL(newpath),
|
pathFromURL(oldpath),
|
||||||
options,
|
pathFromURL(newpath),
|
||||||
});
|
options?.type,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fdatasyncSync(rid) {
|
function fdatasyncSync(rid) {
|
||||||
|
|
|
@ -394,11 +394,14 @@ async fn op_fsync_async(
|
||||||
fn op_fstat_sync(
|
fn op_fstat_sync(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
rid: ResourceId,
|
rid: ResourceId,
|
||||||
) -> Result<FsStat, AnyError> {
|
out_buf: &mut [u32],
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
let metadata = StdFileResource::with_file(state, rid, |std_file| {
|
let metadata = StdFileResource::with_file(state, rid, |std_file| {
|
||||||
std_file.metadata().map_err(AnyError::from)
|
std_file.metadata().map_err(AnyError::from)
|
||||||
})?;
|
})?;
|
||||||
Ok(get_stat(metadata))
|
let stat = get_stat(metadata);
|
||||||
|
stat.write(out_buf);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
|
@ -579,40 +582,34 @@ async fn op_mkdir_async(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[op]
|
||||||
#[serde(rename_all = "camelCase")]
|
fn op_chmod_sync(
|
||||||
pub struct ChmodArgs {
|
state: &mut OpState,
|
||||||
path: String,
|
path: String,
|
||||||
mode: u32,
|
mode: u32,
|
||||||
}
|
) -> Result<(), AnyError> {
|
||||||
|
let path = Path::new(&path);
|
||||||
#[op]
|
let mode = mode & 0o777;
|
||||||
fn op_chmod_sync(state: &mut OpState, args: ChmodArgs) -> Result<(), AnyError> {
|
|
||||||
let path = Path::new(&args.path);
|
|
||||||
let mode = args.mode & 0o777;
|
|
||||||
|
|
||||||
state.borrow_mut::<Permissions>().write.check(path)?;
|
state.borrow_mut::<Permissions>().write.check(path)?;
|
||||||
debug!("op_chmod_sync {} {:o}", path.display(), mode);
|
|
||||||
raw_chmod(path, mode)
|
raw_chmod(path, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_chmod_async(
|
async fn op_chmod_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: ChmodArgs,
|
path: String,
|
||||||
|
mode: u32,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let path = Path::new(&args.path).to_path_buf();
|
let path = Path::new(&path).to_path_buf();
|
||||||
let mode = args.mode & 0o777;
|
let mode = mode & 0o777;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || raw_chmod(&path, mode))
|
||||||
debug!("op_chmod_async {} {:o}", path.display(), mode);
|
|
||||||
raw_chmod(&path, mode)
|
|
||||||
})
|
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
@ -637,30 +634,21 @@ fn raw_chmod(path: &Path, _raw_mode: u32) -> Result<(), AnyError> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[op]
|
||||||
#[serde(rename_all = "camelCase")]
|
fn op_chown_sync(
|
||||||
pub struct ChownArgs {
|
state: &mut OpState,
|
||||||
path: String,
|
path: String,
|
||||||
uid: Option<u32>,
|
uid: Option<u32>,
|
||||||
gid: Option<u32>,
|
gid: Option<u32>,
|
||||||
}
|
) -> Result<(), AnyError> {
|
||||||
|
let path = Path::new(&path).to_path_buf();
|
||||||
#[op]
|
|
||||||
fn op_chown_sync(state: &mut OpState, args: ChownArgs) -> Result<(), AnyError> {
|
|
||||||
let path = Path::new(&args.path).to_path_buf();
|
|
||||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
debug!(
|
|
||||||
"op_chown_sync {} {:?} {:?}",
|
|
||||||
path.display(),
|
|
||||||
args.uid,
|
|
||||||
args.gid,
|
|
||||||
);
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use crate::errors::get_nix_error_class;
|
use crate::errors::get_nix_error_class;
|
||||||
use nix::unistd::{chown, Gid, Uid};
|
use nix::unistd::{chown, Gid, Uid};
|
||||||
let nix_uid = args.uid.map(Uid::from_raw);
|
let nix_uid = uid.map(Uid::from_raw);
|
||||||
let nix_gid = args.gid.map(Gid::from_raw);
|
let nix_gid = gid.map(Gid::from_raw);
|
||||||
chown(&path, nix_uid, nix_gid).map_err(|err| {
|
chown(&path, nix_uid, nix_gid).map_err(|err| {
|
||||||
custom_error(
|
custom_error(
|
||||||
get_nix_error_class(&err),
|
get_nix_error_class(&err),
|
||||||
|
@ -679,9 +667,11 @@ fn op_chown_sync(state: &mut OpState, args: ChownArgs) -> Result<(), AnyError> {
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_chown_async(
|
async fn op_chown_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: ChownArgs,
|
path: String,
|
||||||
|
uid: Option<u32>,
|
||||||
|
gid: Option<u32>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let path = Path::new(&args.path).to_path_buf();
|
let path = Path::new(&path).to_path_buf();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
|
@ -689,18 +679,12 @@ async fn op_chown_async(
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!(
|
|
||||||
"op_chown_async {} {:?} {:?}",
|
|
||||||
path.display(),
|
|
||||||
args.uid,
|
|
||||||
args.gid,
|
|
||||||
);
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use crate::errors::get_nix_error_class;
|
use crate::errors::get_nix_error_class;
|
||||||
use nix::unistd::{chown, Gid, Uid};
|
use nix::unistd::{chown, Gid, Uid};
|
||||||
let nix_uid = args.uid.map(Uid::from_raw);
|
let nix_uid = uid.map(Uid::from_raw);
|
||||||
let nix_gid = args.gid.map(Gid::from_raw);
|
let nix_gid = gid.map(Gid::from_raw);
|
||||||
chown(&path, nix_uid, nix_gid).map_err(|err| {
|
chown(&path, nix_uid, nix_gid).map_err(|err| {
|
||||||
custom_error(
|
custom_error(
|
||||||
get_nix_error_class(&err),
|
get_nix_error_class(&err),
|
||||||
|
@ -717,20 +701,13 @@ async fn op_chown_async(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct RemoveArgs {
|
|
||||||
path: String,
|
|
||||||
recursive: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_remove_sync(
|
fn op_remove_sync(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: RemoveArgs,
|
path: String,
|
||||||
|
recursive: bool,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&path);
|
||||||
let recursive = args.recursive;
|
|
||||||
|
|
||||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
|
|
||||||
|
@ -742,7 +719,6 @@ fn op_remove_sync(
|
||||||
};
|
};
|
||||||
let metadata = std::fs::symlink_metadata(&path).map_err(err_mapper)?;
|
let metadata = std::fs::symlink_metadata(&path).map_err(err_mapper)?;
|
||||||
|
|
||||||
debug!("op_remove_sync {} {}", path.display(), recursive);
|
|
||||||
let file_type = metadata.file_type();
|
let file_type = metadata.file_type();
|
||||||
if file_type.is_file() {
|
if file_type.is_file() {
|
||||||
std::fs::remove_file(&path).map_err(err_mapper)?;
|
std::fs::remove_file(&path).map_err(err_mapper)?;
|
||||||
|
@ -772,10 +748,10 @@ fn op_remove_sync(
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_remove_async(
|
async fn op_remove_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: RemoveArgs,
|
path: String,
|
||||||
|
recursive: bool,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&path);
|
||||||
let recursive = args.recursive;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
|
@ -820,36 +796,29 @@ async fn op_remove_async(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct CopyFileArgs {
|
|
||||||
from: String,
|
|
||||||
to: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_copy_file_sync(
|
fn op_copy_file_sync(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: CopyFileArgs,
|
from: String,
|
||||||
|
to: String,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let from = PathBuf::from(&args.from);
|
let from_path = PathBuf::from(&from);
|
||||||
let to = PathBuf::from(&args.to);
|
let to_path = PathBuf::from(&to);
|
||||||
|
|
||||||
let permissions = state.borrow_mut::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&from)?;
|
permissions.read.check(&from_path)?;
|
||||||
permissions.write.check(&to)?;
|
permissions.write.check(&to_path)?;
|
||||||
|
|
||||||
debug!("op_copy_file_sync {} {}", from.display(), to.display());
|
|
||||||
// On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput
|
// On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput
|
||||||
// See https://github.com/rust-lang/rust/issues/54800
|
// See https://github.com/rust-lang/rust/issues/54800
|
||||||
// Once the issue is resolved, we should remove this workaround.
|
// Once the issue is resolved, we should remove this workaround.
|
||||||
if cfg!(unix) && !from.is_file() {
|
if cfg!(unix) && !from_path.is_file() {
|
||||||
return Err(custom_error(
|
return Err(custom_error(
|
||||||
"NotFound",
|
"NotFound",
|
||||||
format!(
|
format!(
|
||||||
"File not found, copy '{}' -> '{}'",
|
"File not found, copy '{}' -> '{}'",
|
||||||
from.display(),
|
from_path.display(),
|
||||||
to.display()
|
to_path.display()
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -857,21 +826,80 @@ fn op_copy_file_sync(
|
||||||
let err_mapper = |err: Error| {
|
let err_mapper = |err: Error| {
|
||||||
Error::new(
|
Error::new(
|
||||||
err.kind(),
|
err.kind(),
|
||||||
format!("{}, copy '{}' -> '{}'", err, from.display(), to.display()),
|
format!(
|
||||||
|
"{}, copy '{}' -> '{}'",
|
||||||
|
err,
|
||||||
|
from_path.display(),
|
||||||
|
to_path.display()
|
||||||
|
),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
use libc::chmod;
|
||||||
|
use libc::clonefile;
|
||||||
|
use libc::stat;
|
||||||
|
use libc::unlink;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
let from = CString::new(from).unwrap();
|
||||||
|
let to = CString::new(to).unwrap();
|
||||||
|
|
||||||
|
// SAFETY: `from` and `to` are valid C strings.
|
||||||
|
// std::fs::copy does open() + fcopyfile() on macOS. We try to use
|
||||||
|
// clonefile() instead, which is more efficient.
|
||||||
|
unsafe {
|
||||||
|
let mut st = std::mem::zeroed();
|
||||||
|
let ret = stat(from.as_ptr(), &mut st);
|
||||||
|
if ret != 0 {
|
||||||
|
return Err(err_mapper(Error::last_os_error()).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if st.st_size > 128 * 1024 {
|
||||||
|
// Try unlink. If it fails, we are going to try clonefile() anyway.
|
||||||
|
let _ = unlink(to.as_ptr());
|
||||||
|
// Matches rust stdlib behavior for io::copy.
|
||||||
|
// https://github.com/rust-lang/rust/blob/3fdd578d72a24d4efc2fe2ad18eec3b6ba72271e/library/std/src/sys/unix/fs.rs#L1613-L1616
|
||||||
|
if clonefile(from.as_ptr(), to.as_ptr(), 0) == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Do a regular copy. fcopyfile() is an overkill for < 128KB
|
||||||
|
// files.
|
||||||
|
let mut buf = [0u8; 128 * 1024];
|
||||||
|
let mut from_file =
|
||||||
|
std::fs::File::open(&from_path).map_err(err_mapper)?;
|
||||||
|
let mut to_file =
|
||||||
|
std::fs::File::create(&to_path).map_err(err_mapper)?;
|
||||||
|
loop {
|
||||||
|
let nread = from_file.read(&mut buf).map_err(err_mapper)?;
|
||||||
|
if nread == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
to_file.write_all(&buf[..nread]).map_err(err_mapper)?;
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clonefile() failed, fall back to std::fs::copy().
|
||||||
|
}
|
||||||
|
|
||||||
// returns size of from as u64 (we ignore)
|
// returns size of from as u64 (we ignore)
|
||||||
std::fs::copy(&from, &to).map_err(err_mapper)?;
|
std::fs::copy(&from_path, &to_path).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_copy_file_async(
|
async fn op_copy_file_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: CopyFileArgs,
|
from: String,
|
||||||
|
to: String,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let from = PathBuf::from(&args.from);
|
let from = PathBuf::from(&from);
|
||||||
let to = PathBuf::from(&args.to);
|
let to = PathBuf::from(&to);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
|
@ -880,7 +908,6 @@ async fn op_copy_file_async(
|
||||||
permissions.write.check(&to)?;
|
permissions.write.check(&to)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("op_copy_file_async {} {}", from.display(), to.display());
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
// On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput
|
// On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput
|
||||||
// See https://github.com/rust-lang/rust/issues/54800
|
// See https://github.com/rust-lang/rust/issues/54800
|
||||||
|
@ -910,30 +937,57 @@ async fn op_copy_file_async(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> Option<u64> {
|
fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> (u64, bool) {
|
||||||
match maybe_time {
|
match maybe_time {
|
||||||
Ok(time) => {
|
Ok(time) => (
|
||||||
let msec = time
|
time
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.map(|t| t.as_millis() as u64)
|
.map(|t| t.as_millis() as u64)
|
||||||
.unwrap_or_else(|err| err.duration().as_millis() as u64);
|
.unwrap_or_else(|err| err.duration().as_millis() as u64),
|
||||||
Some(msec)
|
true,
|
||||||
}
|
),
|
||||||
Err(_) => None,
|
Err(_) => (0, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
macro_rules! create_struct_writer {
|
||||||
#[serde(rename_all = "camelCase")]
|
(pub struct $name:ident { $($field:ident: $type:ty),* $(,)? }) => {
|
||||||
pub struct FsStat {
|
impl $name {
|
||||||
|
fn write(self, buf: &mut [u32]) {
|
||||||
|
let mut offset = 0;
|
||||||
|
$(
|
||||||
|
let value = self.$field as u64;
|
||||||
|
buf[offset] = value as u32;
|
||||||
|
buf[offset + 1] = (value >> 32) as u32;
|
||||||
|
#[allow(unused_assignments)]
|
||||||
|
{
|
||||||
|
offset += 2;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct $name {
|
||||||
|
$($field: $type),*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
create_struct_writer! {
|
||||||
|
pub struct FsStat {
|
||||||
is_file: bool,
|
is_file: bool,
|
||||||
is_directory: bool,
|
is_directory: bool,
|
||||||
is_symlink: bool,
|
is_symlink: bool,
|
||||||
size: u64,
|
size: u64,
|
||||||
// In milliseconds, like JavaScript. Available on both Unix or Windows.
|
// In milliseconds, like JavaScript. Available on both Unix or Windows.
|
||||||
mtime: Option<u64>,
|
mtime_set: bool,
|
||||||
atime: Option<u64>,
|
mtime: u64,
|
||||||
birthtime: Option<u64>,
|
atime_set: bool,
|
||||||
|
atime: u64,
|
||||||
|
birthtime_set: bool,
|
||||||
|
birthtime: u64,
|
||||||
// Following are only valid under Unix.
|
// Following are only valid under Unix.
|
||||||
dev: u64,
|
dev: u64,
|
||||||
ino: u64,
|
ino: u64,
|
||||||
|
@ -944,6 +998,7 @@ pub struct FsStat {
|
||||||
rdev: u64,
|
rdev: u64,
|
||||||
blksize: u64,
|
blksize: u64,
|
||||||
blocks: u64,
|
blocks: u64,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -964,15 +1019,22 @@ fn get_stat(metadata: std::fs::Metadata) -> FsStat {
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
let (mtime, mtime_set) = to_msec(metadata.modified());
|
||||||
|
let (atime, atime_set) = to_msec(metadata.accessed());
|
||||||
|
let (birthtime, birthtime_set) = to_msec(metadata.created());
|
||||||
|
|
||||||
FsStat {
|
FsStat {
|
||||||
is_file: metadata.is_file(),
|
is_file: metadata.is_file(),
|
||||||
is_directory: metadata.is_dir(),
|
is_directory: metadata.is_dir(),
|
||||||
is_symlink: metadata.file_type().is_symlink(),
|
is_symlink: metadata.file_type().is_symlink(),
|
||||||
size: metadata.len(),
|
size: metadata.len(),
|
||||||
// In milliseconds, like JavaScript. Available on both Unix or Windows.
|
// In milliseconds, like JavaScript. Available on both Unix or Windows.
|
||||||
mtime: to_msec(metadata.modified()),
|
mtime_set,
|
||||||
atime: to_msec(metadata.accessed()),
|
mtime,
|
||||||
birthtime: to_msec(metadata.created()),
|
atime_set,
|
||||||
|
atime,
|
||||||
|
birthtime_set,
|
||||||
|
birthtime,
|
||||||
// Following are only valid under Unix.
|
// Following are only valid under Unix.
|
||||||
dev: usm!(dev),
|
dev: usm!(dev),
|
||||||
ino: usm!(ino),
|
ino: usm!(ino),
|
||||||
|
@ -996,12 +1058,12 @@ pub struct StatArgs {
|
||||||
#[op]
|
#[op]
|
||||||
fn op_stat_sync(
|
fn op_stat_sync(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: StatArgs,
|
path: String,
|
||||||
) -> Result<FsStat, AnyError> {
|
lstat: bool,
|
||||||
let path = PathBuf::from(&args.path);
|
out_buf: &mut [u32],
|
||||||
let lstat = args.lstat;
|
) -> Result<(), AnyError> {
|
||||||
|
let path = PathBuf::from(&path);
|
||||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
debug!("op_stat_sync {} {}", path.display(), lstat);
|
|
||||||
let err_mapper = |err: Error| {
|
let err_mapper = |err: Error| {
|
||||||
Error::new(err.kind(), format!("{}, stat '{}'", err, path.display()))
|
Error::new(err.kind(), format!("{}, stat '{}'", err, path.display()))
|
||||||
};
|
};
|
||||||
|
@ -1010,7 +1072,11 @@ fn op_stat_sync(
|
||||||
} else {
|
} else {
|
||||||
std::fs::metadata(&path).map_err(err_mapper)?
|
std::fs::metadata(&path).map_err(err_mapper)?
|
||||||
};
|
};
|
||||||
Ok(get_stat(metadata))
|
|
||||||
|
let stat = get_stat(metadata);
|
||||||
|
stat.write(out_buf);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
|
@ -1185,26 +1251,20 @@ async fn op_read_dir_async(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct RenameArgs {
|
|
||||||
oldpath: String,
|
|
||||||
newpath: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_rename_sync(
|
fn op_rename_sync(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: RenameArgs,
|
oldpath: String,
|
||||||
|
newpath: String,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
let oldpath = PathBuf::from(&oldpath);
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&newpath);
|
||||||
|
|
||||||
let permissions = state.borrow_mut::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&oldpath)?;
|
permissions.read.check(&oldpath)?;
|
||||||
permissions.write.check(&oldpath)?;
|
permissions.write.check(&oldpath)?;
|
||||||
permissions.write.check(&newpath)?;
|
permissions.write.check(&newpath)?;
|
||||||
debug!("op_rename_sync {} {}", oldpath.display(), newpath.display());
|
|
||||||
let err_mapper = |err: Error| {
|
let err_mapper = |err: Error| {
|
||||||
Error::new(
|
Error::new(
|
||||||
err.kind(),
|
err.kind(),
|
||||||
|
@ -1223,10 +1283,11 @@ fn op_rename_sync(
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_rename_async(
|
async fn op_rename_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: RenameArgs,
|
oldpath: String,
|
||||||
|
newpath: String,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
let oldpath = PathBuf::from(&oldpath);
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&newpath);
|
||||||
{
|
{
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
let permissions = state.borrow_mut::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
|
@ -1235,11 +1296,6 @@ async fn op_rename_async(
|
||||||
permissions.write.check(&newpath)?;
|
permissions.write.check(&newpath)?;
|
||||||
}
|
}
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!(
|
|
||||||
"op_rename_async {} {}",
|
|
||||||
oldpath.display(),
|
|
||||||
newpath.display()
|
|
||||||
);
|
|
||||||
let err_mapper = |err: Error| {
|
let err_mapper = |err: Error| {
|
||||||
Error::new(
|
Error::new(
|
||||||
err.kind(),
|
err.kind(),
|
||||||
|
@ -1258,17 +1314,14 @@ async fn op_rename_async(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[op]
|
||||||
#[serde(rename_all = "camelCase")]
|
fn op_link_sync(
|
||||||
pub struct LinkArgs {
|
state: &mut OpState,
|
||||||
oldpath: String,
|
oldpath: String,
|
||||||
newpath: String,
|
newpath: String,
|
||||||
}
|
) -> Result<(), AnyError> {
|
||||||
|
let oldpath = PathBuf::from(&oldpath);
|
||||||
#[op]
|
let newpath = PathBuf::from(&newpath);
|
||||||
fn op_link_sync(state: &mut OpState, args: LinkArgs) -> Result<(), AnyError> {
|
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
|
||||||
|
|
||||||
let permissions = state.borrow_mut::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&oldpath)?;
|
permissions.read.check(&oldpath)?;
|
||||||
|
@ -1276,7 +1329,6 @@ fn op_link_sync(state: &mut OpState, args: LinkArgs) -> Result<(), AnyError> {
|
||||||
permissions.read.check(&newpath)?;
|
permissions.read.check(&newpath)?;
|
||||||
permissions.write.check(&newpath)?;
|
permissions.write.check(&newpath)?;
|
||||||
|
|
||||||
debug!("op_link_sync {} {}", oldpath.display(), newpath.display());
|
|
||||||
let err_mapper = |err: Error| {
|
let err_mapper = |err: Error| {
|
||||||
Error::new(
|
Error::new(
|
||||||
err.kind(),
|
err.kind(),
|
||||||
|
@ -1295,10 +1347,11 @@ fn op_link_sync(state: &mut OpState, args: LinkArgs) -> Result<(), AnyError> {
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_link_async(
|
async fn op_link_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: LinkArgs,
|
oldpath: String,
|
||||||
|
newpath: String,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
let oldpath = PathBuf::from(&oldpath);
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&newpath);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
|
@ -1310,7 +1363,6 @@ async fn op_link_async(
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_link_async {} {}", oldpath.display(), newpath.display());
|
|
||||||
let err_mapper = |err: Error| {
|
let err_mapper = |err: Error| {
|
||||||
Error::new(
|
Error::new(
|
||||||
err.kind(),
|
err.kind(),
|
||||||
|
@ -1329,38 +1381,19 @@ async fn op_link_async(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct SymlinkArgs {
|
|
||||||
oldpath: String,
|
|
||||||
newpath: String,
|
|
||||||
#[cfg(not(unix))]
|
|
||||||
options: Option<SymlinkOptions>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct SymlinkOptions {
|
|
||||||
_type: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_symlink_sync(
|
fn op_symlink_sync(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: SymlinkArgs,
|
oldpath: String,
|
||||||
|
newpath: String,
|
||||||
|
_type: Option<String>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
let oldpath = PathBuf::from(&oldpath);
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&newpath);
|
||||||
|
|
||||||
state.borrow_mut::<Permissions>().write.check_all()?;
|
state.borrow_mut::<Permissions>().write.check_all()?;
|
||||||
state.borrow_mut::<Permissions>().read.check_all()?;
|
state.borrow_mut::<Permissions>().read.check_all()?;
|
||||||
|
|
||||||
debug!(
|
|
||||||
"op_symlink_sync {} {}",
|
|
||||||
oldpath.display(),
|
|
||||||
newpath.display()
|
|
||||||
);
|
|
||||||
let err_mapper = |err: Error| {
|
let err_mapper = |err: Error| {
|
||||||
Error::new(
|
Error::new(
|
||||||
err.kind(),
|
err.kind(),
|
||||||
|
@ -1382,8 +1415,8 @@ fn op_symlink_sync(
|
||||||
{
|
{
|
||||||
use std::os::windows::fs::{symlink_dir, symlink_file};
|
use std::os::windows::fs::{symlink_dir, symlink_file};
|
||||||
|
|
||||||
match args.options {
|
match _type {
|
||||||
Some(options) => match options._type.as_ref() {
|
Some(ty) => match ty.as_ref() {
|
||||||
"file" => symlink_file(&oldpath, &newpath).map_err(err_mapper)?,
|
"file" => symlink_file(&oldpath, &newpath).map_err(err_mapper)?,
|
||||||
"dir" => symlink_dir(&oldpath, &newpath).map_err(err_mapper)?,
|
"dir" => symlink_dir(&oldpath, &newpath).map_err(err_mapper)?,
|
||||||
_ => return Err(type_error("unsupported type")),
|
_ => return Err(type_error("unsupported type")),
|
||||||
|
@ -1409,10 +1442,12 @@ fn op_symlink_sync(
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_symlink_async(
|
async fn op_symlink_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: SymlinkArgs,
|
oldpath: String,
|
||||||
|
newpath: String,
|
||||||
|
_type: Option<String>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
let oldpath = PathBuf::from(&oldpath);
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&newpath);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
|
@ -1421,7 +1456,6 @@ async fn op_symlink_async(
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_symlink_async {} {}", oldpath.display(), newpath.display());
|
|
||||||
let err_mapper = |err: Error| {
|
let err_mapper = |err: Error| {
|
||||||
Error::new(
|
Error::new(
|
||||||
err.kind(),
|
err.kind(),
|
||||||
|
@ -1443,8 +1477,8 @@ async fn op_symlink_async(
|
||||||
{
|
{
|
||||||
use std::os::windows::fs::{symlink_dir, symlink_file};
|
use std::os::windows::fs::{symlink_dir, symlink_file};
|
||||||
|
|
||||||
match args.options {
|
match _type {
|
||||||
Some(options) => match options._type.as_ref() {
|
Some(ty) => match ty.as_ref() {
|
||||||
"file" => symlink_file(&oldpath, &newpath).map_err(err_mapper)?,
|
"file" => symlink_file(&oldpath, &newpath).map_err(err_mapper)?,
|
||||||
"dir" => symlink_dir(&oldpath, &newpath).map_err(err_mapper)?,
|
"dir" => symlink_dir(&oldpath, &newpath).map_err(err_mapper)?,
|
||||||
_ => return Err(type_error("unsupported type")),
|
_ => return Err(type_error("unsupported type")),
|
||||||
|
@ -1521,20 +1555,13 @@ async fn op_read_link_async(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct FtruncateArgs {
|
|
||||||
rid: ResourceId,
|
|
||||||
len: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_ftruncate_sync(
|
fn op_ftruncate_sync(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: FtruncateArgs,
|
rid: u32,
|
||||||
|
len: i32,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let rid = args.rid;
|
let len = len as u64;
|
||||||
let len = args.len as u64;
|
|
||||||
StdFileResource::with_file(state, rid, |std_file| {
|
StdFileResource::with_file(state, rid, |std_file| {
|
||||||
std_file.set_len(len).map_err(AnyError::from)
|
std_file.set_len(len).map_err(AnyError::from)
|
||||||
})?;
|
})?;
|
||||||
|
@ -1544,10 +1571,10 @@ fn op_ftruncate_sync(
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_ftruncate_async(
|
async fn op_ftruncate_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: FtruncateArgs,
|
rid: ResourceId,
|
||||||
|
len: i32,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let rid = args.rid;
|
let len = len as u64;
|
||||||
let len = args.len as u64;
|
|
||||||
|
|
||||||
StdFileResource::with_file_blocking_task(state, rid, move |std_file| {
|
StdFileResource::with_file_blocking_task(state, rid, move |std_file| {
|
||||||
std_file.set_len(len)?;
|
std_file.set_len(len)?;
|
||||||
|
@ -1556,20 +1583,13 @@ async fn op_ftruncate_async(
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct TruncateArgs {
|
|
||||||
path: String,
|
|
||||||
len: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_truncate_sync(
|
fn op_truncate_sync(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: TruncateArgs,
|
path: String,
|
||||||
|
len: u64,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&path);
|
||||||
let len = args.len;
|
|
||||||
|
|
||||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
|
|
||||||
|
@ -1591,10 +1611,11 @@ fn op_truncate_sync(
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_truncate_async(
|
async fn op_truncate_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: TruncateArgs,
|
path: String,
|
||||||
|
len: u64,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&path);
|
||||||
let len = args.len;
|
|
||||||
{
|
{
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
|
@ -1797,23 +1818,18 @@ async fn op_make_temp_file_async(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct FutimeArgs {
|
|
||||||
rid: ResourceId,
|
|
||||||
atime: (i64, u32),
|
|
||||||
mtime: (i64, u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_futime_sync(
|
fn op_futime_sync(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: FutimeArgs,
|
rid: ResourceId,
|
||||||
|
atime_secs: i64,
|
||||||
|
atime_nanos: u32,
|
||||||
|
mtime_secs: i64,
|
||||||
|
mtime_nanos: u32,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
super::check_unstable(state, "Deno.futimeSync");
|
super::check_unstable(state, "Deno.futimeSync");
|
||||||
let rid = args.rid;
|
let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
|
||||||
let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
|
let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
|
||||||
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
|
||||||
|
|
||||||
StdFileResource::with_file(state, rid, |std_file| {
|
StdFileResource::with_file(state, rid, |std_file| {
|
||||||
filetime::set_file_handle_times(std_file, Some(atime), Some(mtime))
|
filetime::set_file_handle_times(std_file, Some(atime), Some(mtime))
|
||||||
|
@ -1826,12 +1842,15 @@ fn op_futime_sync(
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_futime_async(
|
async fn op_futime_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: FutimeArgs,
|
rid: ResourceId,
|
||||||
|
atime_secs: i64,
|
||||||
|
atime_nanos: u32,
|
||||||
|
mtime_secs: i64,
|
||||||
|
mtime_nanos: u32,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
super::check_unstable2(&state, "Deno.futime");
|
super::check_unstable2(&state, "Deno.futime");
|
||||||
let rid = args.rid;
|
let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
|
||||||
let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
|
let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
|
||||||
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
|
||||||
|
|
||||||
StdFileResource::with_file_blocking_task(state, rid, move |std_file| {
|
StdFileResource::with_file_blocking_task(state, rid, move |std_file| {
|
||||||
filetime::set_file_handle_times(std_file, Some(atime), Some(mtime))?;
|
filetime::set_file_handle_times(std_file, Some(atime), Some(mtime))?;
|
||||||
|
@ -1840,21 +1859,20 @@ async fn op_futime_async(
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct UtimeArgs {
|
|
||||||
path: String,
|
|
||||||
atime: (i64, u32),
|
|
||||||
mtime: (i64, u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_utime_sync(state: &mut OpState, args: UtimeArgs) -> Result<(), AnyError> {
|
fn op_utime_sync(
|
||||||
|
state: &mut OpState,
|
||||||
|
path: String,
|
||||||
|
atime_secs: i64,
|
||||||
|
atime_nanos: u32,
|
||||||
|
mtime_secs: i64,
|
||||||
|
mtime_nanos: u32,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
super::check_unstable(state, "Deno.utime");
|
super::check_unstable(state, "Deno.utime");
|
||||||
|
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&path);
|
||||||
let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
|
let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
|
||||||
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
|
||||||
|
|
||||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
filetime::set_file_times(&path, atime, mtime).map_err(|err| {
|
filetime::set_file_times(&path, atime, mtime).map_err(|err| {
|
||||||
|
@ -1866,13 +1884,17 @@ fn op_utime_sync(state: &mut OpState, args: UtimeArgs) -> Result<(), AnyError> {
|
||||||
#[op]
|
#[op]
|
||||||
async fn op_utime_async(
|
async fn op_utime_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: UtimeArgs,
|
path: String,
|
||||||
|
atime_secs: i64,
|
||||||
|
atime_nanos: u32,
|
||||||
|
mtime_secs: i64,
|
||||||
|
mtime_nanos: u32,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
super::check_unstable(&state.borrow(), "Deno.utime");
|
super::check_unstable(&state.borrow(), "Deno.utime");
|
||||||
|
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&path);
|
||||||
let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
|
let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
|
||||||
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
|
||||||
|
|
||||||
state
|
state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
|
|
@ -302,6 +302,9 @@ pub struct FfiDescriptor(pub PathBuf);
|
||||||
|
|
||||||
impl UnaryPermission<ReadDescriptor> {
|
impl UnaryPermission<ReadDescriptor> {
|
||||||
pub fn query(&self, path: Option<&Path>) -> PermissionState {
|
pub fn query(&self, path: Option<&Path>) -> PermissionState {
|
||||||
|
if self.global_state == PermissionState::Granted {
|
||||||
|
return PermissionState::Granted;
|
||||||
|
}
|
||||||
let path = path.map(|p| resolve_from_cwd(p).unwrap());
|
let path = path.map(|p| resolve_from_cwd(p).unwrap());
|
||||||
if self.global_state == PermissionState::Denied
|
if self.global_state == PermissionState::Denied
|
||||||
&& match path.as_ref() {
|
&& match path.as_ref() {
|
||||||
|
@ -454,6 +457,9 @@ impl Default for UnaryPermission<ReadDescriptor> {
|
||||||
|
|
||||||
impl UnaryPermission<WriteDescriptor> {
|
impl UnaryPermission<WriteDescriptor> {
|
||||||
pub fn query(&self, path: Option<&Path>) -> PermissionState {
|
pub fn query(&self, path: Option<&Path>) -> PermissionState {
|
||||||
|
if self.global_state == PermissionState::Granted {
|
||||||
|
return PermissionState::Granted;
|
||||||
|
}
|
||||||
let path = path.map(|p| resolve_from_cwd(p).unwrap());
|
let path = path.map(|p| resolve_from_cwd(p).unwrap());
|
||||||
if self.global_state == PermissionState::Denied
|
if self.global_state == PermissionState::Denied
|
||||||
&& match path.as_ref() {
|
&& match path.as_ref() {
|
||||||
|
|
Loading…
Reference in a new issue