-
Notifications
You must be signed in to change notification settings - Fork 632
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(fs): undo deprecation of exists
and add permission and type check to it
#2785
Conversation
This PR would also close #2594 |
You might want to double-check the code examples in the separate functions as they seem to incorrectly use |
I would also like to feature tests that involves an existing file / directory where the user has no read-permission on, but the current way is not very suitable. I can commit a file or directory that I cannot read, obviously. To include those tests, I'd need to create a file and directory, remove their user permissions, execute the test, add user permissions back and remove the file and directory again. Is this overkill? Is this recommend? @bartlomieju @kt3k |
Maybe it's too late for me, could you please comment on the affected lines, directly? |
I like this. My concerns, neither of which, I have strong opinions on:
|
@iuioiua Thank you, I was missing the comments, copy/paste caught me here.
Please have a look at our final posts in the discussion thread. Since we abstract from
In my experience, most tools follow symlinks, so should A user might create a symlink to have a specific folder or file in another location (i.e. to sync it with the cloud). A Deno script should not break due to this. So, we abstract from Checking a symlink is such a rare occurrence that we would prefer the user falls back to an own
I'm not sure. I tried to follow existing code, there is no such file starting with |
I agree with this opinion. We already use the word |
Yeah, when I first saw the PR title, I thought it was related to streams 😅 |
readable
, readableDir
and readableFile
isReadable
, isReadableDir
and isReadableFile
I'm currently rewriting the tests to get rid of usage of
Thus, I falsy assumed that import * as asserts from "https://deno.land/std@0.160.0/testing/asserts.ts";
async function isReadable(path: string | URL): Promise<boolean> {
try {
await Deno.stat(path);
return true;
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
return false;
}
throw error;
}
}
Deno.test("failing test", async function () {
const tempDirPath = await Deno.makeTempDir();
const tempFilePath = path.join(tempDirPath, "0.ts");
await Deno.create(tempFilePath);
try {
await Deno.chmod(tempFilePath, 0o000);
asserts.assertEquals(await isReadable(tempFilePath), false); // exists, but not readable
} catch (e) {
throw e;
} finally {
await Deno.remove(tempDirPath, { recursive: true });
}
}); So it seems a file that a user cannot read its contents from can still be accessed with Even when I was able to check the permissions, it would rather encourage a re-implementation of node's I'm seeking some advice at this point. |
I'll have to admit I also expected To be honest, I think returning true in the case of failing permissions would be fine for most use cases. But then |
@jespertheend It's good to know that I booted Windows, created two files ( Now I launched deno as > Deno.stat("C:\\ProgramData\\test.txt")
Promise {
<rejected> PermissionDenied: Access is denied. (os error 5), stat 'C:\ProgramData\test.txt'
at async Object.stat (deno:runtime/js/30_fs.js:314:17)
}
> Deno.lstat("C:\\ProgramData\\test.txt")
Promise {
<rejected> PermissionDenied: Access is denied. (os error 5), stat 'C:\ProgramData\test.txt'
at async Object.lstat (deno:runtime/js/30_fs.js:297:17)
}
> Deno.stat("C:\\ProgramData\\test2.txt")
Promise {
{
isFile: true,
isDirectory: false,
isSymlink: false,
size: 0,
mtime: 2022-10-18T18:16:46.311Z,
atime: 2022-10-18T18:16:46.311Z,
birthtime: 2022-10-18T18:16:46.311Z,
dev: null,
ino: null,
mode: null,
nlink: null,
uid: null,
gid: null,
rdev: null,
blksize: null,
blocks: null
}
} So, on Windows On other systems On Windows I tested the same with directories and the behavior is the same to files. So in favor of consistent behavior, we should include the permission check, since it will raise an error on Windows anyways. I thought about catching the If I could get the current user ID and group ID, I could compare it with So I can really only ensure it's readable by reading the directory / opening the file, which I don't like, ... or I catch I really want consistent behavior across the platforms. |
Would it make sense to release without the permissions check first and then add it in a follow up PR once |
@jespertheend It would be possible, although my biggest concern is the changing behavior of the implementation between the platforms and between concurrent releases. I really want to thrive for a better solution. I committed an implementation (incl. tests) that relies on the
Whatsoever, these issues are neglectable, but should be mentioned. EDIT: There is no check on links without permissions necessary. MacOS is still able to follow links without read permission, it seems the read permission is only necessary for tools like $ echo OK > test
$ ln -s test test-link
$ sudo chmod -h 000 test-link
$ ls -hal
total 2
-rw-r--r-- 1 marty staff 3B Oct 19 04:38 test
ls: ./test-link: Permission denied
l--------- 1 marty staff 4B Oct 19 04:38 test-link
$ readlink test-link
$ cat test-link
OK So this is not even a concern anymore. :) |
I've combined |
isReadable
, isReadableDir
and isReadableFile
isReadable
@jespertheend Please do and thanks in advance. My Parallels license has expired and I currently have limited time to setup a new Windows VM in a different system. I also have disk issues at the moment (limited space, errors when trying to expand its space) as well as I couldn't get UTM (QEMU) to work in a short time. Would be good if I could focus on all that later. Basically, you want to |
@martin-braun It seems like the there are two issues:
If you want I can commit the if statements to fix the first issue. Though I think you would have to give me write access to your fork, so it might be easier to just add these yourself. There are 6 places in total that need this. |
@jespertheend First of all, thanks a lot. The first issue was an easy fix, thanks to your help. I guess I forgot about these In regards of the 2nd issue: Could you please check the contents of const tempDirPath = await Deno.makeTempDir({ prefix: 'deno_exists_test_' }); fixes the issue? @iuioiua Is this a known limitation of the Windows test machine or even the Windows OS? If it is, I could bypass this by using a relative directory instead, although I remember we wanted to get rid of the |
@martin-braun The folder is completely empty. Or at least that's the case for the 'existsDirLink' test. The prefix only adds a prefix to the name of the directory, but it doesn't change the location so it still runs into the same issue. |
Hey I think this should be good to go once the next workflow runs. |
Great to see the Windows test passed, but lint failed due to something unrelated.
|
Core team discussed this last week and now we are in favor of landing this. Thank you for your effort and discussions for long time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
🎉 |
🎉🎉🎉 Nice work! Glad it landed. |
I'm glad we made it eventually. :) |
Thank you so much for all your work! |
IntroducesUndos the deprecation and enhancesreadable
exists
of thefs
module.exists
was deprecated due to TOCTOU issues, but there are valid use cases to have such function:try
/catch
Deno.lstat
/Deno.stat
to compensate the deprecation ofexists
Improvements compared to the former
exists
:exists
was returningfalse
on Windows systems if the file was not readable, but it was returningtrue
on POSIX systems (with exceptions, even if the file was not readable, this is not the case anymore: Options were added that provide anisReadable
flag to effectively check if the file can be read as well, for Windows and POSIX systemsisDirectory
andisFile
were added to the options to address those cases, otherwise the user would still rely on manually callingDeno.lstat
/Deno.stat
afterwards which would defeat the purpose of this implementation and introduce more TOCTOU / race conditionsDeno.stat
insteadDeno.lstat
to follow symlinks and ensure the option flags are working properly on links as wellReferences:
cc @lambdalisue @twome @jespertheend @dionjwa @dev-nicolaos