Skip to content
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

fs: add mkstemp functions #33549

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

fs: add mkstemp functions #33549

wants to merge 7 commits into from

Conversation

targos
Copy link
Member

@targos targos commented May 25, 2020

  • fs.mkstemp and fs.mkstempSync return path and fd.
  • fsPromises.mkstemp returns path and handle.

@nodejs/fs

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

* fs.mkstemp and fs.mkstempSync return `path` and `fd`.
* fsPromises.mkstemp returns `path` and `handle`.
@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. labels May 25, 2020
@targos targos added fs Issues and PRs related to the fs subsystem / file system. semver-minor PRs that contain new features and should be released in the next minor version. and removed lib / src Issues and PRs related to general changes in the lib or src directory. labels May 25, 2020
@targos
Copy link
Member Author

targos commented May 25, 2020

/cc @addaleax

src/node_file.cc Outdated Show resolved Hide resolved
Copy link
Member

@vdeturckheim vdeturckheim left a comment

LGTM

@nodejs-github-bot

This comment has been minimized.

@nodejs-github-bot

This comment has been minimized.

@nodejs-github-bot
Copy link
Contributor

nodejs-github-bot commented May 25, 2020

doc/api/fs.md Outdated Show resolved Hide resolved
doc/api/fs.md Outdated Show resolved Hide resolved
test/parallel/test-fs-mkstemp.js Outdated Show resolved Hide resolved
@benjamingr
Copy link
Member

benjamingr commented May 25, 2020

I think a disposer API for the promises side would have been nicer. I maintain tmp-promise and in my experience that's the more popular API.

I'd also steal some tests from tmp but that can be in a follow up PR :]

@benjamingr benjamingr closed this May 25, 2020
@benjamingr benjamingr reopened this May 25, 2020
doc/api/fs.md Outdated Show resolved Hide resolved
Co-authored-by: Benjamin Gruenbaum <inglor@gmail.com>
doc/api/fs.md Show resolved Hide resolved
@targos
Copy link
Member Author

targos commented May 25, 2020

I think a disposer API for the promises side would have been nicer. I maintain tmp-promise and in my experience that's the more popular API.

I'd also steal some tests from tmp but that can be in a follow up PR :]

I don't understand what you are suggesting, sorry.

@benjamingr
Copy link
Member

benjamingr commented May 25, 2020

@targos in tmp-promise there are two APIs, one is similar to the one outlined here and the other looks a bit like

fs.promises.withMkstemp(async (file) => {
  // when the promise returned from this async function settles, file is automatically closed
});

This makes for better error handling most of the time. I am not saying we should ship this sort of API or that if we do we shouldn't ship the one already in this PR - only that in my (anecdotal) experience as a maintainer of tmp-promise it's the more popular one.

doc/api/fs.md Show resolved Hide resolved
@@ -398,6 +399,24 @@ async function getHandle(dest) {
);
}

// Create a file with `mkstemp`.
Copy link
Member

@benjamingr benjamingr May 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we'd have a lot more tests here (for prefix behavior, prefix with X, the warning with promises, etc) but I'm fine with that being a TODO for now.

Copy link
Member

@benjamingr benjamingr left a comment

I like the disposer API from above better but this worked nicely (I just spent 30 minutes playing with this), actual code looks good to me and adding this API doesn't mean we can't add that API in the future anyway.

@targos targos added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label May 25, 2020
@nodejs-github-bot
Copy link
Contributor

nodejs-github-bot commented May 25, 2020

@targos
Copy link
Member Author

targos commented May 25, 2020

@nodejs-github-bot
Copy link
Contributor

nodejs-github-bot commented May 29, 2020

@targos
Copy link
Member Author

targos commented May 30, 2020

@nodejs/platform-aix PTAL

@richardlau
Copy link
Member

richardlau commented May 30, 2020

I can take a look on Monday but my suspicion would be that the value of the template (i.e. req->path) passed into the mkstemp C call on completion is undefined in the error case.

Copy link
Member

@bnoordhuis bnoordhuis left a comment

LGTM. The AIX failure looks like it's happening on the libuv or libc level. Needs further investigation but I don't think it's caused by this PR.

@bnoordhuis
Copy link
Member

bnoordhuis commented May 30, 2020

That sounds plausible. POSIX allows it to be unspecified. I'll open a libuv PR to clobber req->path on error to flush out such applications bugs.

@targos targos added the blocked PRs that are blocked by other issues or PRs. label May 31, 2020
@BridgeAR BridgeAR force-pushed the master branch 2 times, most recently from 8ae28ff to 2935f72 Compare May 31, 2020
@richardlau
Copy link
Member

richardlau commented Jun 1, 2020

I can take a look on Monday but my suspicion would be that the value of the template (i.e. req->path) passed into the mkstemp C call on completion is undefined in the error case.

Yes, looks like that's the case here:

diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c
index f5b2b94207..ce9683cb51 100644
--- a/deps/uv/src/unix/fs.c
+++ b/deps/uv/src/unix/fs.c
@@ -336,7 +336,9 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
   if (req->cb != NULL)
     uv_rwlock_rdlock(&req->loop->cloexec_lock);

+printf("before mkstemp, path: %s\n", path);
   r = mkstemp(path);
+printf("after mkstemp, path: %s\n", path);

   /* In case of failure `uv__cloexec` will leave error in `errno`,
    * so it is enough to just set `r` to `-1`.
bash-4.4$ ./tools/test.py parallel/test-fs-error-messages
=== release test-fs-error-messages ===
Path: parallel/test-fs-error-messages
before mkstemp, path: /home/riclau/sandbox/github/nodejs/test/.tmp.0/non-existent/foo/barXXXXXX
after mkstemp, path:
before mkstemp, path: /home/riclau/sandbox/github/nodejs/test/.tmp.0/non-existent/foo/barXXXXXX
after mkstemp, path:
(node:13172966) internal/test/binding: These APIs are for internal testing only. Do not use them.
(Use `node --trace-warnings ...` to show where the warning was created)
assert.js:920
    throw err;
    ^

AssertionError [ERR_ASSERTION]: The input did not match the regular expression /^\/home\/riclau\/sandbox\/github\/nodejs\/test\/\.tmp\.0\/non\-existent\/foo\/bar/. Input:

''

    at validateError (/home/riclau/sandbox/github/nodejs/test/parallel/test-fs-error-messages.js:670:12)
    at /home/riclau/sandbox/github/nodejs/test/common/index.js:363:15
    at fs.js:163:23
    at FSReqCallback.oncomplete (fs.js:1893:14) {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: '',
  expected: /^\/home\/riclau\/sandbox\/github\/nodejs\/test\/\.tmp\.0\/non\-existent\/foo\/bar/,
  operator: 'match'
}
Command: out/Release/node --expose-internals /home/riclau/sandbox/github/nodejs/test/parallel/test-fs-error-messages.js
[00:00|% 100|+   0|-   1]: Done
bash-4.4$

POSIX doesn't specify what happens to the template string in the error case: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html

The Linux documentation also points out that the template may be undefined for some errors (EEXIST): https://www.man7.org/linux/man-pages/man3/mkstemp.3.html

So it's not safe to assume the contents of the template (req->path) if the mkstemp call fails as the test is currently doing. If we deem it useful from a debugging/errors point of view in Node.js we should probably store a copy of the template before making the call into libuv.

@addaleax addaleax removed the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Jun 19, 2020
@targos
Copy link
Member Author

targos commented Jul 14, 2020

@bnoordhuis I'm not sure anymore. Is this blocked on work that should be done on the libuv side, or should I do something here to fix the issue?

@bnoordhuis
Copy link
Member

bnoordhuis commented Jul 14, 2020

@targos There's still some work to be done in libuv but nothing critical, it doesn't have to hold up this PR. I'd go with Richard's suggestion:

we should probably store a copy of the template before making the call into libuv

@targos
Copy link
Member Author

targos commented Jul 14, 2020

I'd go with Richard's suggestion:

we should probably store a copy of the template before making the call into libuv

Okay, can you help me do it? I don't know how I could access the value from the AfterMkstemp callback.

@targos targos added the help wanted Issues that need assistance from volunteers or PRs that need help to proceed. label Jul 17, 2020
vtjnash pushed a commit to libuv/libuv that referenced this pull request Aug 12, 2020
Contents of template variable passed for posix call mkstemp on error
code EINVAL is unknown. On AIX platform, template will get clobbered
on EINVAL and any attempt to read template might result in error.

In libuv, req->path is passed directly to the mkstemp call and
behavior of this string on error is platform dependent. To avoid
portability issues, it's better to have a common behavior on all
platform. For both unix and windows platform libuv will rewrite path
with an empty string on all error cases.

Fixes: #2913
Refs: nodejs/node#33549
Refs: #2933
PR-URL: #2938
Reviewed-By: Jameson Nash <vtjnash@gmail.com>
@aduh95
Copy link
Contributor

aduh95 commented Oct 16, 2020

@targos does the change made to libuv by @vtjnash help unblock this?

@targos
Copy link
Member Author

targos commented Oct 17, 2020

It doesn't. I still need help for #33549 (comment)

JeffroMF pushed a commit to JeffroMF/libuv that referenced this pull request May 16, 2022
Contents of template variable passed for posix call mkstemp on error
code EINVAL is unknown. On AIX platform, template will get clobbered
on EINVAL and any attempt to read template might result in error.

In libuv, req->path is passed directly to the mkstemp call and
behavior of this string on error is platform dependent. To avoid
portability issues, it's better to have a common behavior on all
platform. For both unix and windows platform libuv will rewrite path
with an empty string on all error cases.

Fixes: libuv#2913
Refs: nodejs/node#33549
Refs: libuv#2933
PR-URL: libuv#2938
Reviewed-By: Jameson Nash <vtjnash@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocked PRs that are blocked by other issues or PRs. c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to the fs subsystem / file system. help wanted Issues that need assistance from volunteers or PRs that need help to proceed. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet