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

RFC: Rewrite homedir based on uv_os_homedir #19636

Merged
merged 1 commit into from
Dec 18, 2016

Conversation

ararslan
Copy link
Member

Fixes #11331

Rather than relying on environment variables to determine the user's home directory, this calls uv_os_homedir from libuv, per @stevengj's suggestion.

The "magic number" of 1024 in there is what we're setting as the PATH_MAX if none is found in the system (see src/support/dirpath.h), so it seemed to me like a decent choice for the number of bytes to allocate for the output path. Let me know if that isn't reasonable or if there's a better choice.

For reference, here is the upstream libuv documentation on uv_os_homedir: http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_homedir

Copy link
Contributor

@yuyichao yuyichao left a comment

Choose a reason for hiding this comment

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

And a better implementation is

julia> function homedir2()
           sz = Ref{Csize_t}(1024 + 1)
           buf = Vector{UInt8}(sz[] - 1)
           while true
               rc = ccall(:uv_os_homedir, Cint, (Ptr{UInt8}, Ptr{Csize_t}), buf, sz)
               if rc == 0
                   resize!(buf, sz[])
                   return String(buf)
               elseif rc == Base.UV_ENOBUFS # No Base. in base
                   resize!(buf, sz[] - 1)
               else
                   error("Unable to retrieve home directory.")
               end
           end
       end

buf = Vector{Cchar}(1024)
sz = Ref{Csize_t}(sizeof(buf))
rc = ccall(:uv_os_homedir, Cint, (Ptr{Cchar}, Ptr{Csize_t}), buf, sz)
rc == 0 || error("unable to retrieve home directory")
Copy link
Contributor

Choose a reason for hiding this comment

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

Hard to imagine it will happen but the correct way is to use sz[] - 1 to resize the array.

homedir()
function homedir()
buf = Vector{Cchar}(1024)
sz = Ref{Csize_t}(sizeof(buf))
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be sizeof(buf) + 1

rc = ccall(:uv_os_homedir, Cint, (Ptr{Cchar}, Ptr{Csize_t}), buf, sz)
rc == 0 || error("unable to retrieve home directory")
nbytes = Int(sz[])
return unsafe_string(pointer(buf[1:nbytes]))
Copy link
Contributor

Choose a reason for hiding this comment

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

This is wrong and inefficient.

@ararslan
Copy link
Member Author

Thanks for the feedback, @yuyichao!

String(buf) causes an error because Cchar is Int8, not UInt8, so String can't convert the array. That's why I had initially used unsafe_string with pointer. Would it be better to convert to UInt8, then call the String constructor?

@yuyichao
Copy link
Contributor

That s why I used UInt8

@ararslan
Copy link
Member Author

Oh sorry! Missed that part.

@ararslan
Copy link
Member Author

Looking better, @yuyichao?

@stevengj stevengj merged commit 1d561e8 into JuliaLang:master Dec 18, 2016
@ararslan ararslan deleted the aa/homedir branch December 18, 2016 20:55
@tkelman tkelman added the needs news A NEWS entry is required for this change label Feb 1, 2017
@asampal
Copy link

asampal commented Mar 13, 2017

With this change, is there any way to override the home directory Julia uses? I'd like my Julia homedir to be the home directory under my MSYS2/MinGW installation instead of the standard user dir Windows defines.

@stevengj
Copy link
Member

stevengj commented Mar 13, 2017

@asampal, yes. From the libuv documentation:

Gets the current user’s home directory. On Windows, uv_os_homedir() first checks the USERPROFILE environment variable using GetEnvironmentVariableW(). If USERPROFILE is not set, GetUserProfileDirectoryW() is called. On all other operating systems, uv_os_homedir() first checks the HOME environment variable using getenv(3). If HOME is not set, getpwuid_r(3) is called. The user’s home directory is stored in buffer. When uv_os_homedir() is called, size indicates the maximum size of buffer. On success size is set to the string length of buffer. On UV_ENOBUFS failure size is set to the required length for buffer, including the null byte.

So, setting USERPROFILE seems like it should do it, which according to Microsoft refers to:

The user's profile folder. A typical path is C:\Documents and Settings\username. Applications should not create files or folders at this level; they should put their data under the locations referred to by CSIDL_APPDATA or CSIDL_LOCAL_APPDATA.

@asampal
Copy link

asampal commented Mar 13, 2017

@stevengj if I redefine USERPROFILE in juliarc.jl I can get homedir() as I need it, but this will be overwritten by a new install. I can't use .juliarc.jl, to set the home dir, obviously, and this isn't an env variable that should be changed globally (actually marked as read-only). So without running Julia using a batch file, there's no other option?

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.

6 participants