Skip to content

fs: add uv_fs_realpath()#531

Closed
jhamhader wants to merge 1 commit intolibuv:v1.xfrom
jhamhader:realpath
Closed

fs: add uv_fs_realpath()#531
jhamhader wants to merge 1 commit intolibuv:v1.xfrom
jhamhader:realpath

Conversation

@jhamhader
Copy link
Copy Markdown
Contributor

Add uv_fs_realpath() - returns the full resolved absolute path of a
file or directory.

See nodejs/node#2680

Comment thread src/unix/fs.c
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If I understand realpath docs properly, if we pass NULL as the second parameter, it will take care of the memory allocation and return the path. In fact, the patch which I wanted to submit had just this

static ssize_t uv__fs_realpath(uv_fs_t* req) {
  req->ptr = realpath(req->path, NULL);
  return req->ptr == NULL ? -1 : 0;
}

I am not sure if it is correct though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

True, realpath() does that, however, I thought it would be better to allocate using uv__malloc() - for profiling (valgrind?) and we free that memory using its counterpart uv__free().

Also, sorry for white-boxing - seems like at least glibc allocates PATH_MAX as well, so no memory is spared when calling realpath with NULL :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That looks ok to me, Yuval.

On Friday, September 18, 2015, Yuval Brik notifications@github.com wrote:

In src/unix/fs.c
#531 (comment):

  • if (len == -1) {
    +#if defined(PATH_MAX)
  • len = PATH_MAX;
    +#else
  • len = 4096;
    +#endif
  • }
  • buf = uv__malloc(len + 1);
  • if (buf == NULL) {
  • errno = ENOMEM;
  • return -1;
  • }
  • if (realpath(req->path, buf) == NULL) {

True, realpath() does that, but I thought it would be better to allocate
using uv__malloc() - for profiling and valgrind. Also, as we freeing that
memory using its counterpart uv__free().


Reply to this email directly or view it on GitHub
https://github.com/libuv/libuv/pull/531/files#r39887331.

/Saúl
bettercallsaghul.com

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

POSIX pedantry: If resolved_name is a null pointer, the behavior of realpath() is implementation-defined.

On older versions of OS X, for example, passing in NULL segfaults.

Copy link
Copy Markdown

@ChALkeR ChALkeR Apr 22, 2016

Choose a reason for hiding this comment

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

A bit late note:

@bnoordhuis

POSIX pedantry: If resolved_name is a null pointer, the behavior of realpath() is implementation-defined.

That was correct for older POSIX versions only, in the current version passing a NULL pointer as the resolved_name is properly documented: http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While true, it's irrelevant until we drop support for OS X 10.6 (where passing NULL segfaults.)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

drop support for OS X 10.6

Ref: nodejs/node#5731

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Also, #758 suggests dropping OS X 10.6 support in libuv.

@bnoordhuis
Copy link
Copy Markdown
Member

Tests look good to me.

Comment thread docs/src/fs.rst Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Add a ".. versionadded:: 1.8.0" below.

@saghul
Copy link
Copy Markdown
Member

saghul commented Sep 21, 2015

Left some minor comments.

@jhamhader jhamhader force-pushed the realpath branch 2 times, most recently from 3c4046f to 8829eff Compare September 23, 2015 07:37
@jhamhader
Copy link
Copy Markdown
Contributor Author

  • Added the Windows implementation (using GetFinalPathNameByHandleW())
  • Refactored out a common readlink and realpath code into fs__wide_to_utf8()
  • Fixed tests
  • @saghul: added versionadded, fixed styling, realpath(3)

Comment thread docs/src/fs.rst Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Leave a newline here.

@saghul
Copy link
Copy Markdown
Member

saghul commented Sep 23, 2015

I just took a quick peek.

Added the Windows implementation (using GetFinalPathNameByHandleW())

This is going to be a problem, since it's only supported in Windows >= Vista, and we still support XP. Now, since XP doesn't support symlinks (IIRC), maybe we can have some fallback path which basically copies the input into the output? (not sure if we'd need to do anything about specifying the drive). @piscisaureus WDYT?

@piscisaureus
Copy link
Copy Markdown
Contributor

This is going to be a problem, since it's only supported in Windows >= Vista, and we still support XP. Now, since XP doesn't support symlinks (IIRC),

Windows XP does support junctions, which are treated by libuv as a type of symlink.

maybe we can have some fallback path which basically copies the input into the output?

That sounds like meh... maybe we could just return UV_ENOSYS on XP ?

@saghul
Copy link
Copy Markdown
Member

saghul commented Sep 24, 2015

That sounds like meh... maybe we could just return UV_ENOSYS on XP ?

I thought of it, but this PR originates from Node wanting to use it instead of the JavaScript implementation, so IMHO returning UV_ENOSYS would complicate the code there...

@jhamhader jhamhader force-pushed the realpath branch 2 times, most recently from 3cadc57 to e7c76b6 Compare September 26, 2015 19:46
@jhamhader
Copy link
Copy Markdown
Contributor Author

Not being highly familiar with Windows myself (a linux enthusiast), do you think we can somehow progress on this? Some ideas over Stack Overflow seem not very neat.
MSDN purposes using CreateFileMapping(), MapViewOfFile() and GetMappedFileName(), however - mapping of directories and zero-length files cannot be obtained.

Another issue I would like to raise: GetFinalPathNameByHandle() will return the full path with an upper-case drive letter. Is there a convention in libuv about that? I know node.js currently returns a lower-case drive letter.

@jhamhader
Copy link
Copy Markdown
Contributor Author

@saghul @piscisaureus would really appreciate your opinion.

@bnoordhuis
Copy link
Copy Markdown
Member

Probably worth noting that nodejs/node#3594 proposes to replace node's lovingly handcrafted fs.realpathSync() with a call to uv_fs_realpath(). fs.realpathSync() is used by the module loader so returning UV_ENOSYS on Windows XP would break node completely on that platform.

@saghul
Copy link
Copy Markdown
Member

saghul commented Nov 4, 2015

@bnoordhuis How about this: we return UV_ENOSYS on XP. Then Node caches that and uses the current lovingly crafted code as a fallback. Once v2 is a thing and XP support is gone the fallback can be removed and go to code heaven.

I really don't want anyone losing time here because of Windows XP...

@bnoordhuis
Copy link
Copy Markdown
Member

I'm not in love with that because it means double the complexity and double the surface area for bugs and incompatibilities in node.js. I guess we can land this PR while leaving out the node.js changes but that kind of nullifies the goal of this PR.

Comment thread docs/src/fs.rst Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please mention what we use on Windows and the fact that it doesn't work on XP.

@saghul
Copy link
Copy Markdown
Member

saghul commented Dec 4, 2015

New CI: https://ci.nodejs.org/job/libuv+any-pr+multi/208/

Also left some comments.

@saghul
Copy link
Copy Markdown
Member

saghul commented Dec 4, 2015

Test pass, good job! Can you take care of the last issues a pointed out? Other than that I think this is ready to land.

@jhamhader
Copy link
Copy Markdown
Contributor Author

Pushed. Can you review the phrasing of the Windows XP note?

Comment thread docs/src/fs.rst
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry to be nitpicky here... can you add that it returns UV_ENOSYS?

@saghul
Copy link
Copy Markdown
Member

saghul commented Dec 4, 2015

Some last comments, almost there!

Add uv_fs_realpath() - returns the full resolved absolute path of a
file or directory.
@jhamhader
Copy link
Copy Markdown
Contributor Author

Pushed. Please tell me if anything else is required.

@saghul
Copy link
Copy Markdown
Member

saghul commented Dec 4, 2015

LGTM, great work!

I'll run the CI once more and land it.
On Dec 4, 2015 9:16 PM, "Yuval Brik" notifications@github.com wrote:

Pushed. Please tell me if anything else is required.


Reply to this email directly or view it on GitHub
#531 (comment).

saghul pushed a commit that referenced this pull request Dec 5, 2015
Equivalent to realpath(3), returns the full resolved absolute path of a
file or directory.

PR-URL: #531
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
@saghul
Copy link
Copy Markdown
Member

saghul commented Dec 5, 2015

Thanks a lot Yuval, and great work! ✨ Landed in e76b883

@saghul saghul closed this Dec 5, 2015
MylesBorins pushed a commit to MylesBorins/node-glob that referenced this pull request Apr 22, 2016
fs.realpath has been optimized to utilize `ev_fs_realpath()`, a new api
in libuv. The libuv api has slightly different behavior. There are two
particular issues that are causing problems for glob

* `ev_fs_realpath()` throwing before `fs.readdir` ELOOP
* The removal of the cache

In the past glob was relying on `fs.readdir` to throw when handling
recursive symbolically linked directories. It is now possible that the
call to libuv can throw before. The behavior is currently different on
osx and linux causing the test suite to fail on all of the flavors of
linux we are running in CI.

This commit adds an extra check for 'ELOOP' and sets appropriately.

There is an a check included to make sure that real

ref: libuv/libuv#531
ref: nodejs/node#3594
MylesBorins pushed a commit to MylesBorins/node-glob that referenced this pull request Apr 22, 2016
fs.realpath has been optimized to utilize `ev_fs_realpath()`, a new api
in libuv. The libuv api has slightly different behavior. There are two
particular issues that are causing problems for glob

* `ev_fs_realpath()` throwing before `fs.readdir` ELOOP
* The removal of the cache

In the past glob was relying on `fs.readdir` to throw when handling
recursive symbolically linked directories. It is now possible that the
call to libuv can throw before. The behavior is currently different on
osx and linux causing the test suite to fail on all of the flavors of
linux we are running in CI.

This commit adds an extra check for 'ELOOP' and sets appropriately.

The commit includes an extra check to make sure that `real` is truthy
Without that extra check the test suite was reporting garbage data in the results.
This was only happening with the async implementation.

This commit has not done anything regarding the removal of the cache
As long as the cache doesn't include a value called "encoding"
everything will be fine.

There has not been any benchmarking done on this change.

ref: libuv/libuv#531
ref: nodejs/node#3594
MylesBorins pushed a commit to MylesBorins/node-glob that referenced this pull request Apr 22, 2016
fs.realpath has been optimized to utilize `uv_fs_realpath()`, a new api
in libuv. The libuv api has slightly different behavior. There are two
particular issues that are causing problems for glob

* `ev_fs_realpath()` throwing before `fs.readdir` ELOOP
* The removal of the cache

In the past glob was relying on `fs.readdir` to throw when handling
recursive symbolically linked directories. It is now possible that the
call to libuv can throw before. The behavior is currently different on
osx and linux causing the test suite to fail on all of the flavors of
linux we are running in CI.

This commit adds an extra check for 'ELOOP' and sets appropriately.

The commit includes an extra check to make sure that `real` is truthy
Without that extra check the test suite was reporting garbage data in the results.
This was only happening with the async implementation.

This commit has not done anything regarding the removal of the cache
As long as the cache doesn't include a value called "encoding"
everything will be fine.

There has not been any benchmarking done on this change.

ref: libuv/libuv#531
ref: nodejs/node#3594
@MylesBorins
Copy link
Copy Markdown
Contributor

I've been digging into this as part of a security audit in the node project and came across a potential edge case in freebsd.

In freebsd limits.h does not contain PATH_MAX, it is found it syslimits.h and has the value of 1024

In an issue on the freebsd tracker it seems to imply that freebsd does not support longer path's out of the box. With this being the case I am wondering if setting the default to 4096 could potentially create a problem on freebsd.

MylesBorins pushed a commit to MylesBorins/node-glob that referenced this pull request Jun 6, 2016
fs.realpath has been optimized to utilize `uv_fs_realpath()`, a new api
in libuv. The libuv api has slightly different behavior. There are two
particular issues that are causing problems for glob

* `ev_fs_realpath()` throwing before `fs.readdir` ELOOP
* The removal of the cache

In the past glob was relying on `fs.readdir` to throw when handling
recursive symbolically linked directories. It is now possible that the
call to libuv can throw before. The behavior is currently different on
osx and linux causing the test suite to fail on all of the flavors of
linux we are running in CI.

This commit adds an extra check for 'ELOOP' and sets appropriately.

The commit includes an extra check to make sure that `real` is truthy
Without that extra check the test suite was reporting garbage data in the results.
This was only happening with the async implementation.

This commit has not done anything regarding the removal of the cache
As long as the cache doesn't include a value called "encoding"
everything will be fine.

There has not been any benchmarking done on this change.

ref: libuv/libuv#531
ref: nodejs/node#3594
@Fishrock123
Copy link
Copy Markdown
Contributor

anyone ever saw @thealphanerd's comment?

@saghul
Copy link
Copy Markdown
Member

saghul commented Oct 14, 2016

@Fishrock123 yep, I believe it landed, though for some reason this issue was not referenced: f617ccc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants