mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
feat(runtime): improve error messages of runtime fs (#11984)
This commit annotates errors returned from FS Deno APIs to include paths that were passed to the API calls. Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
This commit is contained in:
parent
423b02d889
commit
668b400ff2
17 changed files with 589 additions and 135 deletions
|
@ -82,10 +82,14 @@ unitTest(
|
||||||
);
|
);
|
||||||
|
|
||||||
unitTest({ permissions: { write: true } }, function chmodSyncFailure() {
|
unitTest({ permissions: { write: true } }, function chmodSyncFailure() {
|
||||||
assertThrows(() => {
|
|
||||||
const filename = "/badfile.txt";
|
const filename = "/badfile.txt";
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.chmodSync(filename, 0o777);
|
Deno.chmodSync(filename, 0o777);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`chmod '${filename}'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { write: false } }, function chmodSyncPerm() {
|
unitTest({ permissions: { write: false } }, function chmodSyncPerm() {
|
||||||
|
@ -170,10 +174,14 @@ unitTest(
|
||||||
);
|
);
|
||||||
|
|
||||||
unitTest({ permissions: { write: true } }, async function chmodFailure() {
|
unitTest({ permissions: { write: true } }, async function chmodFailure() {
|
||||||
await assertRejects(async () => {
|
|
||||||
const filename = "/badfile.txt";
|
const filename = "/badfile.txt";
|
||||||
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
await Deno.chmod(filename, 0o777);
|
await Deno.chmod(filename, 0o777);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`chmod '${filename}'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { write: false } }, async function chmodPerm() {
|
unitTest({ permissions: { write: false } }, async function chmodPerm() {
|
||||||
|
|
|
@ -48,9 +48,13 @@ unitTest(
|
||||||
const { uid, gid } = await getUidAndGid();
|
const { uid, gid } = await getUidAndGid();
|
||||||
const filePath = Deno.makeTempDirSync() + "/chown_test_file.txt";
|
const filePath = Deno.makeTempDirSync() + "/chown_test_file.txt";
|
||||||
|
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.chownSync(filePath, uid, gid);
|
Deno.chownSync(filePath, uid, gid);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`chown '${filePath}'`,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -63,9 +67,13 @@ unitTest(
|
||||||
const { uid, gid } = await getUidAndGid();
|
const { uid, gid } = await getUidAndGid();
|
||||||
const filePath = (await Deno.makeTempDir()) + "/chown_test_file.txt";
|
const filePath = (await Deno.makeTempDir()) + "/chown_test_file.txt";
|
||||||
|
|
||||||
await assertRejects(async () => {
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
await Deno.chown(filePath, uid, gid);
|
await Deno.chown(filePath, uid, gid);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`chown '${filePath}'`,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -72,9 +72,13 @@ unitTest(
|
||||||
const fromFilename = tempDir + "/from.txt";
|
const fromFilename = tempDir + "/from.txt";
|
||||||
const toFilename = tempDir + "/to.txt";
|
const toFilename = tempDir + "/to.txt";
|
||||||
// We skip initial writing here, from.txt does not exist
|
// We skip initial writing here, from.txt does not exist
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.copyFileSync(fromFilename, toFilename);
|
Deno.copyFileSync(fromFilename, toFilename);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`copy '${fromFilename}' -> '${toFilename}'`,
|
||||||
|
);
|
||||||
|
|
||||||
Deno.removeSync(tempDir, { recursive: true });
|
Deno.removeSync(tempDir, { recursive: true });
|
||||||
},
|
},
|
||||||
|
@ -162,9 +166,13 @@ unitTest(
|
||||||
const fromFilename = tempDir + "/from.txt";
|
const fromFilename = tempDir + "/from.txt";
|
||||||
const toFilename = tempDir + "/to.txt";
|
const toFilename = tempDir + "/to.txt";
|
||||||
// We skip initial writing here, from.txt does not exist
|
// We skip initial writing here, from.txt does not exist
|
||||||
await assertRejects(async () => {
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
await Deno.copyFile(fromFilename, toFilename);
|
await Deno.copyFile(fromFilename, toFilename);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`copy '${fromFilename}' -> '${toFilename}'`,
|
||||||
|
);
|
||||||
|
|
||||||
Deno.removeSync(tempDir, { recursive: true });
|
Deno.removeSync(tempDir, { recursive: true });
|
||||||
},
|
},
|
||||||
|
|
|
@ -52,8 +52,12 @@ unitTest(
|
||||||
{ permissions: { read: true, write: true } },
|
{ permissions: { read: true, write: true } },
|
||||||
function dirChdirError() {
|
function dirChdirError() {
|
||||||
const path = Deno.makeTempDirSync() + "test";
|
const path = Deno.makeTempDirSync() + "test";
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.chdir(path);
|
Deno.chdir(path);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`chdir '${path}'`,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,13 @@
|
||||||
|
|
||||||
// deno-lint-ignore-file no-deprecated-deno-api
|
// deno-lint-ignore-file no-deprecated-deno-api
|
||||||
|
|
||||||
import { assert, assertEquals, assertRejects, unitTest } from "./test_util.ts";
|
import {
|
||||||
|
assert,
|
||||||
|
assertEquals,
|
||||||
|
assertRejects,
|
||||||
|
assertThrows,
|
||||||
|
unitTest,
|
||||||
|
} from "./test_util.ts";
|
||||||
import { copy } from "../../../test_util/std/io/util.ts";
|
import { copy } from "../../../test_util/std/io/util.ts";
|
||||||
|
|
||||||
unitTest(function filesStdioFileDescriptors() {
|
unitTest(function filesStdioFileDescriptors() {
|
||||||
|
@ -361,6 +367,32 @@ unitTest(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { write: true, read: true } },
|
||||||
|
async function openNotFound() {
|
||||||
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
|
await Deno.open("bad_file_name");
|
||||||
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`open 'bad_file_name'`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { write: true, read: true } },
|
||||||
|
function openSyncNotFound() {
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
Deno.openSync("bad_file_name");
|
||||||
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`open 'bad_file_name'`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
unitTest(
|
unitTest(
|
||||||
{ permissions: { read: true, write: true } },
|
{ permissions: { read: true, write: true } },
|
||||||
async function createFile() {
|
async function createFile() {
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
import { assert, assertEquals, assertThrows, unitTest } from "./test_util.ts";
|
import {
|
||||||
|
assert,
|
||||||
|
assertEquals,
|
||||||
|
assertRejects,
|
||||||
|
assertThrows,
|
||||||
|
unitTest,
|
||||||
|
} from "./test_util.ts";
|
||||||
|
|
||||||
unitTest(
|
unitTest(
|
||||||
{ permissions: { read: true, write: true } },
|
{ permissions: { read: true, write: true } },
|
||||||
|
@ -50,9 +56,13 @@ unitTest(
|
||||||
// newname is already created.
|
// newname is already created.
|
||||||
Deno.writeFileSync(newName, new TextEncoder().encode("newName"));
|
Deno.writeFileSync(newName, new TextEncoder().encode("newName"));
|
||||||
|
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.linkSync(oldName, newName);
|
Deno.linkSync(oldName, newName);
|
||||||
}, Deno.errors.AlreadyExists);
|
},
|
||||||
|
Deno.errors.AlreadyExists,
|
||||||
|
`link '${oldName}' -> '${newName}'`,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -63,9 +73,13 @@ unitTest(
|
||||||
const oldName = testDir + "/oldname";
|
const oldName = testDir + "/oldname";
|
||||||
const newName = testDir + "/newname";
|
const newName = testDir + "/newname";
|
||||||
|
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.linkSync(oldName, newName);
|
Deno.linkSync(oldName, newName);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`link '${oldName}' -> '${newName}'`,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -125,3 +139,58 @@ unitTest(
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { read: true, write: true } },
|
||||||
|
async function linkExists() {
|
||||||
|
const testDir = Deno.makeTempDirSync();
|
||||||
|
const oldName = testDir + "/oldname";
|
||||||
|
const newName = testDir + "/newname";
|
||||||
|
Deno.writeFileSync(oldName, new TextEncoder().encode("oldName"));
|
||||||
|
// newname is already created.
|
||||||
|
Deno.writeFileSync(newName, new TextEncoder().encode("newName"));
|
||||||
|
|
||||||
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
|
await Deno.link(oldName, newName);
|
||||||
|
},
|
||||||
|
Deno.errors.AlreadyExists,
|
||||||
|
`link '${oldName}' -> '${newName}'`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { read: true, write: true } },
|
||||||
|
async function linkNotFound() {
|
||||||
|
const testDir = Deno.makeTempDirSync();
|
||||||
|
const oldName = testDir + "/oldname";
|
||||||
|
const newName = testDir + "/newname";
|
||||||
|
|
||||||
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
|
await Deno.link(oldName, newName);
|
||||||
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`link '${oldName}' -> '${newName}'`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { read: false, write: true } },
|
||||||
|
async function linkReadPerm() {
|
||||||
|
await assertRejects(async () => {
|
||||||
|
await Deno.link("oldbaddir", "newbaddir");
|
||||||
|
}, Deno.errors.PermissionDenied);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { read: true, write: false } },
|
||||||
|
async function linkWritePerm() {
|
||||||
|
await assertRejects(async () => {
|
||||||
|
await Deno.link("oldbaddir", "newbaddir");
|
||||||
|
}, Deno.errors.PermissionDenied);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
|
@ -59,15 +59,23 @@ unitTest(
|
||||||
);
|
);
|
||||||
|
|
||||||
unitTest({ permissions: { write: true } }, function mkdirErrSyncIfExists() {
|
unitTest({ permissions: { write: true } }, function mkdirErrSyncIfExists() {
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.mkdirSync(".");
|
Deno.mkdirSync(".");
|
||||||
}, Deno.errors.AlreadyExists);
|
},
|
||||||
|
Deno.errors.AlreadyExists,
|
||||||
|
`mkdir '.'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { write: true } }, async function mkdirErrIfExists() {
|
unitTest({ permissions: { write: true } }, async function mkdirErrIfExists() {
|
||||||
await assertRejects(async () => {
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
await Deno.mkdir(".");
|
await Deno.mkdir(".");
|
||||||
}, Deno.errors.AlreadyExists);
|
},
|
||||||
|
Deno.errors.AlreadyExists,
|
||||||
|
`mkdir '.'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest(
|
unitTest(
|
||||||
|
|
|
@ -40,15 +40,23 @@ unitTest({ permissions: { read: false } }, function readDirSyncPerm() {
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { read: true } }, function readDirSyncNotDir() {
|
unitTest({ permissions: { read: true } }, function readDirSyncNotDir() {
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.readDirSync("cli/tests/testdata/fixture.json");
|
Deno.readDirSync("cli/tests/testdata/fixture.json");
|
||||||
}, Error);
|
},
|
||||||
|
Error,
|
||||||
|
`readdir 'cli/tests/testdata/fixture.json'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { read: true } }, function readDirSyncNotFound() {
|
unitTest({ permissions: { read: true } }, function readDirSyncNotFound() {
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.readDirSync("bad_dir_name");
|
Deno.readDirSync("bad_dir_name");
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`readdir 'bad_dir_name'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { read: true } }, async function readDirSuccess() {
|
unitTest({ permissions: { read: true } }, async function readDirSuccess() {
|
||||||
|
@ -94,3 +102,13 @@ unitTest(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
unitTest({ permissions: { read: true } }, async function readDirNotFound() {
|
||||||
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
|
await Deno.readDir("bad_dir_name")[Symbol.asyncIterator]().next();
|
||||||
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`readdir 'bad_dir_name'`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
|
@ -44,9 +44,13 @@ unitTest({ permissions: { read: false } }, function readLinkSyncPerm() {
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { read: true } }, function readLinkSyncNotFound() {
|
unitTest({ permissions: { read: true } }, function readLinkSyncNotFound() {
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.readLinkSync("bad_filename");
|
Deno.readLinkSync("bad_filename");
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`readlink 'bad_filename'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest(
|
unitTest(
|
||||||
|
@ -84,3 +88,13 @@ unitTest({ permissions: { read: false } }, async function readLinkPerm() {
|
||||||
await Deno.readLink("/symlink");
|
await Deno.readLink("/symlink");
|
||||||
}, Deno.errors.PermissionDenied);
|
}, Deno.errors.PermissionDenied);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
unitTest({ permissions: { read: true } }, async function readLinkNotFound() {
|
||||||
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
|
await Deno.readLink("bad_filename");
|
||||||
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`readlink 'bad_filename'`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
|
@ -80,15 +80,23 @@ unitTest(
|
||||||
const subPathInfo = Deno.statSync(subPath);
|
const subPathInfo = Deno.statSync(subPath);
|
||||||
assert(subPathInfo.isDirectory); // check exist first
|
assert(subPathInfo.isDirectory); // check exist first
|
||||||
|
|
||||||
await assertRejects(async () => {
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
await Deno[method](path);
|
await Deno[method](path);
|
||||||
}, Error);
|
},
|
||||||
|
Error,
|
||||||
|
`remove '${path}'`,
|
||||||
|
);
|
||||||
// TODO(ry) Is Other really the error we should get here? What would Go do?
|
// TODO(ry) Is Other really the error we should get here? What would Go do?
|
||||||
|
|
||||||
// NON-EXISTENT DIRECTORY/FILE
|
// NON-EXISTENT DIRECTORY/FILE
|
||||||
await assertRejects(async () => {
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
await Deno[method]("/baddir");
|
await Deno[method]("/baddir");
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`remove '/baddir'`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -210,10 +218,14 @@ unitTest(
|
||||||
unitTest({ permissions: { write: true } }, async function removeAllFail() {
|
unitTest({ permissions: { write: true } }, async function removeAllFail() {
|
||||||
for (const method of REMOVE_METHODS) {
|
for (const method of REMOVE_METHODS) {
|
||||||
// NON-EXISTENT DIRECTORY/FILE
|
// NON-EXISTENT DIRECTORY/FILE
|
||||||
await assertRejects(async () => {
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
// Non-existent
|
// Non-existent
|
||||||
await Deno[method]("/baddir", { recursive: true });
|
await Deno[method]("/baddir", { recursive: true });
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`remove '/baddir'`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,13 @@ unitTest(
|
||||||
Error,
|
Error,
|
||||||
"Not a directory",
|
"Not a directory",
|
||||||
);
|
);
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
Deno.renameSync(olddir, file);
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
`rename '${olddir}' -> '${file}'`,
|
||||||
|
);
|
||||||
|
|
||||||
const fileLink = testDir + "/fileLink";
|
const fileLink = testDir + "/fileLink";
|
||||||
const dirLink = testDir + "/dirLink";
|
const dirLink = testDir + "/dirLink";
|
||||||
|
@ -242,6 +249,13 @@ unitTest(
|
||||||
Deno.errors.PermissionDenied,
|
Deno.errors.PermissionDenied,
|
||||||
"Access is denied",
|
"Access is denied",
|
||||||
);
|
);
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
Deno.renameSync(olddir, emptydir);
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
`rename '${olddir}' -> '${emptydir}'`,
|
||||||
|
);
|
||||||
|
|
||||||
// should succeed on Windows
|
// should succeed on Windows
|
||||||
Deno.renameSync(olddir, file);
|
Deno.renameSync(olddir, file);
|
||||||
|
|
|
@ -108,9 +108,13 @@ unitTest({ permissions: { read: false } }, function statSyncPerm() {
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { read: true } }, function statSyncNotFound() {
|
unitTest({ permissions: { read: true } }, function statSyncNotFound() {
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.statSync("bad_file_name");
|
Deno.statSync("bad_file_name");
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`stat 'bad_file_name'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { read: true } }, function lstatSyncSuccess() {
|
unitTest({ permissions: { read: true } }, function lstatSyncSuccess() {
|
||||||
|
@ -148,9 +152,13 @@ unitTest({ permissions: { read: false } }, function lstatSyncPerm() {
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { read: true } }, function lstatSyncNotFound() {
|
unitTest({ permissions: { read: true } }, function lstatSyncNotFound() {
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.lstatSync("bad_file_name");
|
Deno.lstatSync("bad_file_name");
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`stat 'bad_file_name'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest(
|
unitTest(
|
||||||
|
@ -228,8 +236,10 @@ unitTest({ permissions: { read: false } }, async function statPerm() {
|
||||||
unitTest({ permissions: { read: true } }, async function statNotFound() {
|
unitTest({ permissions: { read: true } }, async function statNotFound() {
|
||||||
await assertRejects(
|
await assertRejects(
|
||||||
async () => {
|
async () => {
|
||||||
await Deno.stat("bad_file_name"), Deno.errors.NotFound;
|
await Deno.stat("bad_file_name");
|
||||||
},
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`stat 'bad_file_name'`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -268,9 +278,13 @@ unitTest({ permissions: { read: false } }, async function lstatPerm() {
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ permissions: { read: true } }, async function lstatNotFound() {
|
unitTest({ permissions: { read: true } }, async function lstatNotFound() {
|
||||||
await assertRejects(async () => {
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
await Deno.lstat("bad_file_name");
|
await Deno.lstat("bad_file_name");
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`stat 'bad_file_name'`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest(
|
unitTest(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
import {
|
import {
|
||||||
assert,
|
assert,
|
||||||
|
assertRejects,
|
||||||
assertThrows,
|
assertThrows,
|
||||||
pathToAbsoluteFileUrl,
|
pathToAbsoluteFileUrl,
|
||||||
unitTest,
|
unitTest,
|
||||||
|
@ -45,6 +46,21 @@ unitTest(function symlinkSyncPerm() {
|
||||||
}, Deno.errors.PermissionDenied);
|
}, Deno.errors.PermissionDenied);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { read: true, write: true } },
|
||||||
|
function symlinkSyncAlreadyExist() {
|
||||||
|
const existingFile = Deno.makeTempFileSync();
|
||||||
|
const existingFile2 = Deno.makeTempFileSync();
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
Deno.symlinkSync(existingFile, existingFile2);
|
||||||
|
},
|
||||||
|
Deno.errors.AlreadyExists,
|
||||||
|
`symlink '${existingFile}' -> '${existingFile2}'`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
unitTest(
|
unitTest(
|
||||||
{ permissions: { read: true, write: true } },
|
{ permissions: { read: true, write: true } },
|
||||||
async function symlinkSuccess() {
|
async function symlinkSuccess() {
|
||||||
|
@ -77,3 +93,18 @@ unitTest(
|
||||||
assert(newNameInfoStat.isDirectory, "NOT DIRECTORY");
|
assert(newNameInfoStat.isDirectory, "NOT DIRECTORY");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { read: true, write: true } },
|
||||||
|
async function symlinkAlreadyExist() {
|
||||||
|
const existingFile = Deno.makeTempFileSync();
|
||||||
|
const existingFile2 = Deno.makeTempFileSync();
|
||||||
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
|
await Deno.symlink(existingFile, existingFile2);
|
||||||
|
},
|
||||||
|
Deno.errors.AlreadyExists,
|
||||||
|
`symlink '${existingFile}' -> '${existingFile2}'`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
|
@ -91,3 +91,31 @@ unitTest({ permissions: { write: false } }, async function truncatePerm() {
|
||||||
await Deno.truncate("/test_truncatePermission.txt");
|
await Deno.truncate("/test_truncatePermission.txt");
|
||||||
}, Deno.errors.PermissionDenied);
|
}, Deno.errors.PermissionDenied);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { read: true, write: true } },
|
||||||
|
function truncateSyncNotFound() {
|
||||||
|
const filename = "/badfile.txt";
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
Deno.truncateSync(filename);
|
||||||
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`truncate '${filename}'`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { read: true, write: true } },
|
||||||
|
async function truncateSyncNotFound() {
|
||||||
|
const filename = "/badfile.txt";
|
||||||
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
|
await Deno.truncate(filename);
|
||||||
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
`truncate '${filename}'`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
|
@ -160,9 +160,13 @@ unitTest(
|
||||||
const atime = 1000;
|
const atime = 1000;
|
||||||
const mtime = 50000;
|
const mtime = 50000;
|
||||||
|
|
||||||
assertThrows(() => {
|
assertThrows(
|
||||||
|
() => {
|
||||||
Deno.utimeSync("/baddir", atime, mtime);
|
Deno.utimeSync("/baddir", atime, mtime);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
"utime '/baddir'",
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -271,9 +275,13 @@ unitTest(
|
||||||
const atime = 1000;
|
const atime = 1000;
|
||||||
const mtime = 50000;
|
const mtime = 50000;
|
||||||
|
|
||||||
await assertRejects(async () => {
|
await assertRejects(
|
||||||
|
async () => {
|
||||||
await Deno.utime("/baddir", atime, mtime);
|
await Deno.utime("/baddir", atime, mtime);
|
||||||
}, Deno.errors.NotFound);
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
"utime '/baddir'",
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ fn get_hyper_error_class(_error: &hyper::Error) -> &'static str {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn get_nix_error_class(error: &nix::Error) -> &'static str {
|
pub fn get_nix_error_class(error: &nix::Error) -> &'static str {
|
||||||
match error {
|
match error {
|
||||||
nix::Error::ECHILD => "NotFound",
|
nix::Error::ECHILD => "NotFound",
|
||||||
nix::Error::EINVAL => "TypeError",
|
nix::Error::EINVAL => "TypeError",
|
||||||
|
|
|
@ -23,7 +23,7 @@ use std::cell::RefCell;
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::env::{current_dir, set_current_dir, temp_dir};
|
use std::env::{current_dir, set_current_dir, temp_dir};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Seek, SeekFrom};
|
use std::io::{Error, Seek, SeekFrom};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
@ -163,7 +163,9 @@ fn op_open_sync(
|
||||||
_: (),
|
_: (),
|
||||||
) -> Result<ResourceId, AnyError> {
|
) -> Result<ResourceId, AnyError> {
|
||||||
let (path, open_options) = open_helper(state, args)?;
|
let (path, open_options) = open_helper(state, args)?;
|
||||||
let std_file = open_options.open(path)?;
|
let std_file = open_options.open(&path).map_err(|err| {
|
||||||
|
Error::new(err.kind(), format!("{}, open '{}'", err, path.display()))
|
||||||
|
})?;
|
||||||
let tokio_file = tokio::fs::File::from_std(std_file);
|
let tokio_file = tokio::fs::File::from_std(std_file);
|
||||||
let resource = StdFileResource::fs_file(tokio_file);
|
let resource = StdFileResource::fs_file(tokio_file);
|
||||||
let rid = state.resource_table.add(resource);
|
let rid = state.resource_table.add(resource);
|
||||||
|
@ -177,8 +179,11 @@ async fn op_open_async(
|
||||||
) -> Result<ResourceId, AnyError> {
|
) -> Result<ResourceId, AnyError> {
|
||||||
let (path, open_options) = open_helper(&mut state.borrow_mut(), args)?;
|
let (path, open_options) = open_helper(&mut state.borrow_mut(), args)?;
|
||||||
let tokio_file = tokio::fs::OpenOptions::from(open_options)
|
let tokio_file = tokio::fs::OpenOptions::from(open_options)
|
||||||
.open(path)
|
.open(&path)
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
Error::new(err.kind(), format!("{}, open '{}'", err, path.display()))
|
||||||
|
})?;
|
||||||
let resource = StdFileResource::fs_file(tokio_file);
|
let resource = StdFileResource::fs_file(tokio_file);
|
||||||
let rid = state.borrow_mut().resource_table.add(resource);
|
let rid = state.borrow_mut().resource_table.add(resource);
|
||||||
Ok(rid)
|
Ok(rid)
|
||||||
|
@ -503,7 +508,9 @@ fn op_chdir(
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let d = PathBuf::from(&directory);
|
let d = PathBuf::from(&directory);
|
||||||
state.borrow_mut::<Permissions>().read.check(&d)?;
|
state.borrow_mut::<Permissions>().read.check(&d)?;
|
||||||
set_current_dir(&d)?;
|
set_current_dir(&d).map_err(|err| {
|
||||||
|
Error::new(err.kind(), format!("{}, chdir '{}'", err, directory))
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +538,9 @@ fn op_mkdir_sync(
|
||||||
use std::os::unix::fs::DirBuilderExt;
|
use std::os::unix::fs::DirBuilderExt;
|
||||||
builder.mode(mode);
|
builder.mode(mode);
|
||||||
}
|
}
|
||||||
builder.create(path)?;
|
builder.create(&path).map_err(|err| {
|
||||||
|
Error::new(err.kind(), format!("{}, mkdir '{}'", err, path.display()))
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +566,9 @@ async fn op_mkdir_async(
|
||||||
use std::os::unix::fs::DirBuilderExt;
|
use std::os::unix::fs::DirBuilderExt;
|
||||||
builder.mode(mode);
|
builder.mode(mode);
|
||||||
}
|
}
|
||||||
builder.create(path)?;
|
builder.create(&path).map_err(|err| {
|
||||||
|
Error::new(err.kind(), format!("{}, mkdir '{}'", err, path.display()))
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -578,6 +589,9 @@ fn op_chmod_sync(
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let path = Path::new(&args.path).to_path_buf();
|
let path = Path::new(&args.path).to_path_buf();
|
||||||
let mode = args.mode & 0o777;
|
let mode = args.mode & 0o777;
|
||||||
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(err.kind(), format!("{}, chmod '{}'", err, path.display()))
|
||||||
|
};
|
||||||
|
|
||||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
debug!("op_chmod_sync {} {:o}", path.display(), mode);
|
debug!("op_chmod_sync {} {:o}", path.display(), mode);
|
||||||
|
@ -585,14 +599,14 @@ fn op_chmod_sync(
|
||||||
{
|
{
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
let permissions = PermissionsExt::from_mode(mode);
|
let permissions = PermissionsExt::from_mode(mode);
|
||||||
std::fs::set_permissions(&path, permissions)?;
|
std::fs::set_permissions(&path, permissions).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// TODO Implement chmod for Windows (#4357)
|
// TODO Implement chmod for Windows (#4357)
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
{
|
{
|
||||||
// Still check file/dir exists on Windows
|
// Still check file/dir exists on Windows
|
||||||
let _metadata = std::fs::metadata(&path)?;
|
let _metadata = std::fs::metadata(&path).map_err(err_mapper)?;
|
||||||
Err(generic_error("Not implemented"))
|
Err(generic_error("Not implemented"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -612,18 +626,21 @@ async fn op_chmod_async(
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_chmod_async {} {:o}", path.display(), mode);
|
debug!("op_chmod_async {} {:o}", path.display(), mode);
|
||||||
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(err.kind(), format!("{}, chmod '{}'", err, path.display()))
|
||||||
|
};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
let permissions = PermissionsExt::from_mode(mode);
|
let permissions = PermissionsExt::from_mode(mode);
|
||||||
std::fs::set_permissions(&path, permissions)?;
|
std::fs::set_permissions(&path, permissions).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// TODO Implement chmod for Windows (#4357)
|
// TODO Implement chmod for Windows (#4357)
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
{
|
{
|
||||||
// Still check file/dir exists on Windows
|
// Still check file/dir exists on Windows
|
||||||
let _metadata = std::fs::metadata(&path)?;
|
let _metadata = std::fs::metadata(&path).map_err(err_mapper)?;
|
||||||
Err(not_supported())
|
Err(not_supported())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -654,10 +671,16 @@ fn op_chown_sync(
|
||||||
);
|
);
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
|
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 = args.uid.map(Uid::from_raw);
|
||||||
let nix_gid = args.gid.map(Gid::from_raw);
|
let nix_gid = args.gid.map(Gid::from_raw);
|
||||||
chown(&path, nix_uid, nix_gid)?;
|
chown(&path, nix_uid, nix_gid).map_err(|err| {
|
||||||
|
custom_error(
|
||||||
|
get_nix_error_class(&err),
|
||||||
|
format!("{}, chown '{}'", err.desc(), path.display()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// TODO Implement chown for Windows
|
// TODO Implement chown for Windows
|
||||||
|
@ -688,10 +711,16 @@ async fn op_chown_async(
|
||||||
);
|
);
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
|
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 = args.uid.map(Uid::from_raw);
|
||||||
let nix_gid = args.gid.map(Gid::from_raw);
|
let nix_gid = args.gid.map(Gid::from_raw);
|
||||||
chown(&path, nix_uid, nix_gid)?;
|
chown(&path, nix_uid, nix_gid).map_err(|err| {
|
||||||
|
custom_error(
|
||||||
|
get_nix_error_class(&err),
|
||||||
|
format!("{}, chown '{}'", err.desc(), path.display()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// TODO Implement chown for Windows
|
// TODO Implement chown for Windows
|
||||||
|
@ -722,31 +751,34 @@ fn op_remove_sync(
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
use std::os::windows::prelude::MetadataExt;
|
use std::os::windows::prelude::MetadataExt;
|
||||||
|
|
||||||
let metadata = std::fs::symlink_metadata(&path)?;
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(err.kind(), format!("{}, remove '{}'", err, path.display()))
|
||||||
|
};
|
||||||
|
let metadata = std::fs::symlink_metadata(&path).map_err(err_mapper)?;
|
||||||
|
|
||||||
debug!("op_remove_sync {} {}", path.display(), recursive);
|
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)?;
|
std::fs::remove_file(&path).map_err(err_mapper)?;
|
||||||
} else if recursive {
|
} else if recursive {
|
||||||
std::fs::remove_dir_all(&path)?;
|
std::fs::remove_dir_all(&path).map_err(err_mapper)?;
|
||||||
} else if file_type.is_symlink() {
|
} else if file_type.is_symlink() {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
std::fs::remove_file(&path)?;
|
std::fs::remove_file(&path).map_err(err_mapper)?;
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
{
|
{
|
||||||
use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY;
|
use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY;
|
||||||
if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
|
if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||||
std::fs::remove_dir(&path)?;
|
std::fs::remove_dir(&path).map_err(err_mapper)?;
|
||||||
} else {
|
} else {
|
||||||
std::fs::remove_file(&path)?;
|
std::fs::remove_file(&path).map_err(err_mapper)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if file_type.is_dir() {
|
} else if file_type.is_dir() {
|
||||||
std::fs::remove_dir(&path)?;
|
std::fs::remove_dir(&path).map_err(err_mapper)?;
|
||||||
} else {
|
} else {
|
||||||
// pipes, sockets, etc...
|
// pipes, sockets, etc...
|
||||||
std::fs::remove_file(&path)?;
|
std::fs::remove_file(&path).map_err(err_mapper)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -767,32 +799,34 @@ async fn op_remove_async(
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
use std::os::windows::prelude::MetadataExt;
|
use std::os::windows::prelude::MetadataExt;
|
||||||
|
let err_mapper = |err: Error| {
|
||||||
let metadata = std::fs::symlink_metadata(&path)?;
|
Error::new(err.kind(), format!("{}, remove '{}'", err, path.display()))
|
||||||
|
};
|
||||||
|
let metadata = std::fs::symlink_metadata(&path).map_err(err_mapper)?;
|
||||||
|
|
||||||
debug!("op_remove_async {} {}", path.display(), recursive);
|
debug!("op_remove_async {} {}", 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)?;
|
std::fs::remove_file(&path).map_err(err_mapper)?;
|
||||||
} else if recursive {
|
} else if recursive {
|
||||||
std::fs::remove_dir_all(&path)?;
|
std::fs::remove_dir_all(&path).map_err(err_mapper)?;
|
||||||
} else if file_type.is_symlink() {
|
} else if file_type.is_symlink() {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
std::fs::remove_file(&path)?;
|
std::fs::remove_file(&path).map_err(err_mapper)?;
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
{
|
{
|
||||||
use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY;
|
use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY;
|
||||||
if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
|
if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||||
std::fs::remove_dir(&path)?;
|
std::fs::remove_dir(&path).map_err(err_mapper)?;
|
||||||
} else {
|
} else {
|
||||||
std::fs::remove_file(&path)?;
|
std::fs::remove_file(&path).map_err(err_mapper)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if file_type.is_dir() {
|
} else if file_type.is_dir() {
|
||||||
std::fs::remove_dir(&path)?;
|
std::fs::remove_dir(&path).map_err(err_mapper)?;
|
||||||
} else {
|
} else {
|
||||||
// pipes, sockets, etc...
|
// pipes, sockets, etc...
|
||||||
std::fs::remove_file(&path)?;
|
std::fs::remove_file(&path).map_err(err_mapper)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -824,11 +858,24 @@ fn op_copy_file_sync(
|
||||||
// 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.is_file() {
|
||||||
return Err(custom_error("NotFound", "File not found"));
|
return Err(custom_error(
|
||||||
|
"NotFound",
|
||||||
|
format!(
|
||||||
|
"File not found, copy '{}' -> '{}'",
|
||||||
|
from.display(),
|
||||||
|
to.display()
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!("{}, copy '{}' -> '{}'", err, from.display(), to.display()),
|
||||||
|
)
|
||||||
|
};
|
||||||
// returns size of from as u64 (we ignore)
|
// returns size of from as u64 (we ignore)
|
||||||
std::fs::copy(&from, &to)?;
|
std::fs::copy(&from, &to).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,11 +900,24 @@ async fn op_copy_file_async(
|
||||||
// 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.is_file() {
|
||||||
return Err(custom_error("NotFound", "File not found"));
|
return Err(custom_error(
|
||||||
|
"NotFound",
|
||||||
|
format!(
|
||||||
|
"File not found, copy '{}' -> '{}'",
|
||||||
|
from.display(),
|
||||||
|
to.display()
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!("{}, copy '{}' -> '{}'", err, from.display(), to.display()),
|
||||||
|
)
|
||||||
|
};
|
||||||
// returns size of from as u64 (we ignore)
|
// returns size of from as u64 (we ignore)
|
||||||
std::fs::copy(&from, &to)?;
|
std::fs::copy(&from, &to).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -956,10 +1016,13 @@ fn op_stat_sync(
|
||||||
let lstat = args.lstat;
|
let lstat = args.lstat;
|
||||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
debug!("op_stat_sync {} {}", path.display(), lstat);
|
debug!("op_stat_sync {} {}", path.display(), lstat);
|
||||||
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(err.kind(), format!("{}, stat '{}'", err, path.display()))
|
||||||
|
};
|
||||||
let metadata = if lstat {
|
let metadata = if lstat {
|
||||||
std::fs::symlink_metadata(&path)?
|
std::fs::symlink_metadata(&path).map_err(err_mapper)?
|
||||||
} else {
|
} else {
|
||||||
std::fs::metadata(&path)?
|
std::fs::metadata(&path).map_err(err_mapper)?
|
||||||
};
|
};
|
||||||
Ok(get_stat(metadata))
|
Ok(get_stat(metadata))
|
||||||
}
|
}
|
||||||
|
@ -979,10 +1042,13 @@ async fn op_stat_async(
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_stat_async {} {}", path.display(), lstat);
|
debug!("op_stat_async {} {}", path.display(), lstat);
|
||||||
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(err.kind(), format!("{}, stat '{}'", err, path.display()))
|
||||||
|
};
|
||||||
let metadata = if lstat {
|
let metadata = if lstat {
|
||||||
std::fs::symlink_metadata(&path)?
|
std::fs::symlink_metadata(&path).map_err(err_mapper)?
|
||||||
} else {
|
} else {
|
||||||
std::fs::metadata(&path)?
|
std::fs::metadata(&path).map_err(err_mapper)?
|
||||||
};
|
};
|
||||||
Ok(get_stat(metadata))
|
Ok(get_stat(metadata))
|
||||||
})
|
})
|
||||||
|
@ -1058,7 +1124,11 @@ fn op_read_dir_sync(
|
||||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
|
|
||||||
debug!("op_read_dir_sync {}", path.display());
|
debug!("op_read_dir_sync {}", path.display());
|
||||||
let entries: Vec<_> = std::fs::read_dir(path)?
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(err.kind(), format!("{}, readdir '{}'", err, path.display()))
|
||||||
|
};
|
||||||
|
let entries: Vec<_> = std::fs::read_dir(&path)
|
||||||
|
.map_err(err_mapper)?
|
||||||
.filter_map(|entry| {
|
.filter_map(|entry| {
|
||||||
let entry = entry.unwrap();
|
let entry = entry.unwrap();
|
||||||
// Not all filenames can be encoded as UTF-8. Skip those for now.
|
// Not all filenames can be encoded as UTF-8. Skip those for now.
|
||||||
|
@ -1096,7 +1166,11 @@ async fn op_read_dir_async(
|
||||||
}
|
}
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_read_dir_async {}", path.display());
|
debug!("op_read_dir_async {}", path.display());
|
||||||
let entries: Vec<_> = std::fs::read_dir(path)?
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(err.kind(), format!("{}, readdir '{}'", err, path.display()))
|
||||||
|
};
|
||||||
|
let entries: Vec<_> = std::fs::read_dir(&path)
|
||||||
|
.map_err(err_mapper)?
|
||||||
.filter_map(|entry| {
|
.filter_map(|entry| {
|
||||||
let entry = entry.unwrap();
|
let entry = entry.unwrap();
|
||||||
// Not all filenames can be encoded as UTF-8. Skip those for now.
|
// Not all filenames can be encoded as UTF-8. Skip those for now.
|
||||||
|
@ -1145,7 +1219,18 @@ fn op_rename_sync(
|
||||||
permissions.write.check(&oldpath)?;
|
permissions.write.check(&oldpath)?;
|
||||||
permissions.write.check(&newpath)?;
|
permissions.write.check(&newpath)?;
|
||||||
debug!("op_rename_sync {} {}", oldpath.display(), newpath.display());
|
debug!("op_rename_sync {} {}", oldpath.display(), newpath.display());
|
||||||
std::fs::rename(&oldpath, &newpath)?;
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!(
|
||||||
|
"{}, rename '{}' -> '{}'",
|
||||||
|
err,
|
||||||
|
oldpath.display(),
|
||||||
|
newpath.display()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
std::fs::rename(&oldpath, &newpath).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1169,7 +1254,18 @@ async fn op_rename_async(
|
||||||
oldpath.display(),
|
oldpath.display(),
|
||||||
newpath.display()
|
newpath.display()
|
||||||
);
|
);
|
||||||
std::fs::rename(&oldpath, &newpath)?;
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!(
|
||||||
|
"{}, rename '{}' -> '{}'",
|
||||||
|
err,
|
||||||
|
oldpath.display(),
|
||||||
|
newpath.display()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
std::fs::rename(&oldpath, &newpath).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -1198,7 +1294,18 @@ fn op_link_sync(
|
||||||
permissions.write.check(&newpath)?;
|
permissions.write.check(&newpath)?;
|
||||||
|
|
||||||
debug!("op_link_sync {} {}", oldpath.display(), newpath.display());
|
debug!("op_link_sync {} {}", oldpath.display(), newpath.display());
|
||||||
std::fs::hard_link(&oldpath, &newpath)?;
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!(
|
||||||
|
"{}, link '{}' -> '{}'",
|
||||||
|
err,
|
||||||
|
oldpath.display(),
|
||||||
|
newpath.display()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
std::fs::hard_link(&oldpath, &newpath).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,7 +1328,18 @@ async fn op_link_async(
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_link_async {} {}", oldpath.display(), newpath.display());
|
debug!("op_link_async {} {}", oldpath.display(), newpath.display());
|
||||||
std::fs::hard_link(&oldpath, &newpath)?;
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!(
|
||||||
|
"{}, link '{}' -> '{}'",
|
||||||
|
err,
|
||||||
|
oldpath.display(),
|
||||||
|
newpath.display()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
std::fs::hard_link(&oldpath, &newpath).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -1259,10 +1377,21 @@ fn op_symlink_sync(
|
||||||
oldpath.display(),
|
oldpath.display(),
|
||||||
newpath.display()
|
newpath.display()
|
||||||
);
|
);
|
||||||
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!(
|
||||||
|
"{}, symlink '{}' -> '{}'",
|
||||||
|
err,
|
||||||
|
oldpath.display(),
|
||||||
|
newpath.display()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use std::os::unix::fs::symlink;
|
use std::os::unix::fs::symlink;
|
||||||
symlink(&oldpath, &newpath)?;
|
symlink(&oldpath, &newpath).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
|
@ -1271,8 +1400,8 @@ fn op_symlink_sync(
|
||||||
|
|
||||||
match args.options {
|
match args.options {
|
||||||
Some(options) => match options._type.as_ref() {
|
Some(options) => match options._type.as_ref() {
|
||||||
"file" => symlink_file(&oldpath, &newpath)?,
|
"file" => symlink_file(&oldpath, &newpath).map_err(err_mapper)?,
|
||||||
"dir" => symlink_dir(&oldpath, &newpath)?,
|
"dir" => symlink_dir(&oldpath, &newpath).map_err(err_mapper)?,
|
||||||
_ => return Err(type_error("unsupported type")),
|
_ => return Err(type_error("unsupported type")),
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -1280,9 +1409,9 @@ fn op_symlink_sync(
|
||||||
match old_meta {
|
match old_meta {
|
||||||
Ok(metadata) => {
|
Ok(metadata) => {
|
||||||
if metadata.is_file() {
|
if metadata.is_file() {
|
||||||
symlink_file(&oldpath, &newpath)?
|
symlink_file(&oldpath, &newpath).map_err(err_mapper)?
|
||||||
} else if metadata.is_dir() {
|
} else if metadata.is_dir() {
|
||||||
symlink_dir(&oldpath, &newpath)?
|
symlink_dir(&oldpath, &newpath).map_err(err_mapper)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => return Err(type_error("you must pass a `options` argument for non-existent target path in windows".to_string())),
|
Err(_) => return Err(type_error("you must pass a `options` argument for non-existent target path in windows".to_string())),
|
||||||
|
@ -1308,10 +1437,21 @@ async fn op_symlink_async(
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_symlink_async {} {}", oldpath.display(), newpath.display());
|
debug!("op_symlink_async {} {}", oldpath.display(), newpath.display());
|
||||||
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!(
|
||||||
|
"{}, symlink '{}' -> '{}'",
|
||||||
|
err,
|
||||||
|
oldpath.display(),
|
||||||
|
newpath.display()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use std::os::unix::fs::symlink;
|
use std::os::unix::fs::symlink;
|
||||||
symlink(&oldpath, &newpath)?;
|
symlink(&oldpath, &newpath).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
|
@ -1320,8 +1460,8 @@ async fn op_symlink_async(
|
||||||
|
|
||||||
match args.options {
|
match args.options {
|
||||||
Some(options) => match options._type.as_ref() {
|
Some(options) => match options._type.as_ref() {
|
||||||
"file" => symlink_file(&oldpath, &newpath)?,
|
"file" => symlink_file(&oldpath, &newpath).map_err(err_mapper)?,
|
||||||
"dir" => symlink_dir(&oldpath, &newpath)?,
|
"dir" => symlink_dir(&oldpath, &newpath).map_err(err_mapper)?,
|
||||||
_ => return Err(type_error("unsupported type")),
|
_ => return Err(type_error("unsupported type")),
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -1329,9 +1469,9 @@ async fn op_symlink_async(
|
||||||
match old_meta {
|
match old_meta {
|
||||||
Ok(metadata) => {
|
Ok(metadata) => {
|
||||||
if metadata.is_file() {
|
if metadata.is_file() {
|
||||||
symlink_file(&oldpath, &newpath)?
|
symlink_file(&oldpath, &newpath).map_err(err_mapper)?
|
||||||
} else if metadata.is_dir() {
|
} else if metadata.is_dir() {
|
||||||
symlink_dir(&oldpath, &newpath)?
|
symlink_dir(&oldpath, &newpath).map_err(err_mapper)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => return Err(type_error("you must pass a `options` argument for non-existent target path in windows".to_string())),
|
Err(_) => return Err(type_error("you must pass a `options` argument for non-existent target path in windows".to_string())),
|
||||||
|
@ -1355,7 +1495,15 @@ fn op_read_link_sync(
|
||||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
|
|
||||||
debug!("op_read_link_value {}", path.display());
|
debug!("op_read_link_value {}", path.display());
|
||||||
let target = std::fs::read_link(&path)?.into_os_string();
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!("{}, readlink '{}'", err, path.display()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let target = std::fs::read_link(&path)
|
||||||
|
.map_err(err_mapper)?
|
||||||
|
.into_os_string();
|
||||||
let targetstr = into_string(target)?;
|
let targetstr = into_string(target)?;
|
||||||
Ok(targetstr)
|
Ok(targetstr)
|
||||||
}
|
}
|
||||||
|
@ -1372,7 +1520,15 @@ async fn op_read_link_async(
|
||||||
}
|
}
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_read_link_async {}", path.display());
|
debug!("op_read_link_async {}", path.display());
|
||||||
let target = std::fs::read_link(&path)?.into_os_string();
|
let err_mapper = |err: Error| {
|
||||||
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!("{}, readlink '{}'", err, path.display()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let target = std::fs::read_link(&path)
|
||||||
|
.map_err(err_mapper)?
|
||||||
|
.into_os_string();
|
||||||
let targetstr = into_string(target)?;
|
let targetstr = into_string(target)?;
|
||||||
Ok(targetstr)
|
Ok(targetstr)
|
||||||
})
|
})
|
||||||
|
@ -1444,8 +1600,17 @@ fn op_truncate_sync(
|
||||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
|
|
||||||
debug!("op_truncate_sync {} {}", path.display(), len);
|
debug!("op_truncate_sync {} {}", path.display(), len);
|
||||||
let f = std::fs::OpenOptions::new().write(true).open(&path)?;
|
let err_mapper = |err: Error| {
|
||||||
f.set_len(len)?;
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!("{}, truncate '{}'", err, path.display()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let f = std::fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.open(&path)
|
||||||
|
.map_err(err_mapper)?;
|
||||||
|
f.set_len(len).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1462,8 +1627,17 @@ async fn op_truncate_async(
|
||||||
}
|
}
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_truncate_async {} {}", path.display(), len);
|
debug!("op_truncate_async {} {}", path.display(), len);
|
||||||
let f = std::fs::OpenOptions::new().write(true).open(&path)?;
|
let err_mapper = |err: Error| {
|
||||||
f.set_len(len)?;
|
Error::new(
|
||||||
|
err.kind(),
|
||||||
|
format!("{}, truncate '{}'", err, path.display()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let f = std::fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.open(&path)
|
||||||
|
.map_err(err_mapper)?;
|
||||||
|
f.set_len(len).map_err(err_mapper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -1740,7 +1914,9 @@ fn op_utime_sync(
|
||||||
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
||||||
|
|
||||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
filetime::set_file_times(path, atime, mtime)?;
|
filetime::set_file_times(&path, atime, mtime).map_err(|err| {
|
||||||
|
Error::new(err.kind(), format!("{}, utime '{}'", err, path.display()))
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1762,7 +1938,9 @@ async fn op_utime_async(
|
||||||
.check(&path)?;
|
.check(&path)?;
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
filetime::set_file_times(path, atime, mtime)?;
|
filetime::set_file_times(&path, atime, mtime).map_err(|err| {
|
||||||
|
Error::new(err.kind(), format!("{}, utime '{}'", err, path.display()))
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
|
Loading…
Add table
Reference in a new issue