Skip to content

Commit

Permalink
Implement User/Group from_name?/from_id? like Ruby (#10182)
Browse files Browse the repository at this point in the history
* Implement User/Group from_name?/from_id? like Ruby

* Implement User/Group from_name?/from_id? using retry_with_buffer
  • Loading branch information
wonderix authored Jan 11, 2021
1 parent 4522952 commit a9832d7
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 37 deletions.
19 changes: 19 additions & 0 deletions src/crystal/system/unix.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# :nodoc:
module Crystal::System
def self.retry_with_buffer(function_name, max_buffer)
initial_buf = uninitialized UInt8[1024]
buf = initial_buf

while (ret = yield buf.to_slice) != 0
case ret
when LibC::ENOENT, LibC::ESRCH, LibC::EBADF, LibC::EPERM
return nil
when LibC::ERANGE
raise RuntimeError.from_errno(function_name) if buf.size >= max_buffer
buf = Bytes.new(buf.size * 2)
else
raise RuntimeError.from_errno(function_name)
end
end
end
end
24 changes: 5 additions & 19 deletions src/crystal/system/unix/group.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "c/grp"
require "../unix"

module Crystal::System::Group
private GETGR_R_SIZE_MAX = 1024 * 16
Expand All @@ -12,17 +13,10 @@ module Crystal::System::Group

grp = uninitialized LibC::Group
grp_pointer = pointerof(grp)
initial_buf = uninitialized UInt8[1024]
buf = initial_buf.to_slice

ret = LibC.getgrnam_r(groupname, grp_pointer, buf, buf.size, pointerof(grp_pointer))
while ret == LibC::ERANGE && buf.size < GETGR_R_SIZE_MAX
buf = Bytes.new(buf.size * 2)
ret = LibC.getgrnam_r(groupname, grp_pointer, buf, buf.size, pointerof(grp_pointer))
System.retry_with_buffer("getgrnam_r", GETGR_R_SIZE_MAX) do |buf|
LibC.getgrnam_r(groupname, grp_pointer, buf, buf.size, pointerof(grp_pointer))
end

raise RuntimeError.from_errno("getgrnam_r") if ret != 0

from_struct(grp) if grp_pointer
end

Expand All @@ -32,17 +26,9 @@ module Crystal::System::Group

grp = uninitialized LibC::Group
grp_pointer = pointerof(grp)
initial_buf = uninitialized UInt8[1024]
buf = initial_buf.to_slice

ret = LibC.getgrgid_r(groupid, grp_pointer, buf, buf.size, pointerof(grp_pointer))
while ret == LibC::ERANGE && buf.size < GETGR_R_SIZE_MAX
buf = Bytes.new(buf.size * 2)
ret = LibC.getgrgid_r(groupid, grp_pointer, buf, buf.size, pointerof(grp_pointer))
System.retry_with_buffer("getgrgid_r", GETGR_R_SIZE_MAX) do |buf|
LibC.getgrgid_r(groupid, grp_pointer, buf, buf.size, pointerof(grp_pointer))
end

raise RuntimeError.from_errno("getgrgid_r") if ret != 0

from_struct(grp) if grp_pointer
end
end
23 changes: 5 additions & 18 deletions src/crystal/system/unix/user.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "c/pwd"
require "../unix"

module Crystal::System::User
private GETPW_R_SIZE_MAX = 1024 * 16
Expand All @@ -13,17 +14,10 @@ module Crystal::System::User

pwd = uninitialized LibC::Passwd
pwd_pointer = pointerof(pwd)
initial_buf = uninitialized UInt8[1024]
buf = initial_buf.to_slice

ret = LibC.getpwnam_r(username, pwd_pointer, buf, buf.size, pointerof(pwd_pointer))
while ret == LibC::ERANGE && buf.size < GETPW_R_SIZE_MAX
buf = Bytes.new(buf.size * 2)
ret = LibC.getpwnam_r(username, pwd_pointer, buf, buf.size, pointerof(pwd_pointer))
System.retry_with_buffer("getpwnam_r", GETPW_R_SIZE_MAX) do |buf|
LibC.getpwnam_r(username, pwd_pointer, buf, buf.size, pointerof(pwd_pointer))
end

raise RuntimeError.from_errno("getpwnam_r") if ret != 0

from_struct(pwd) if pwd_pointer
end

Expand All @@ -33,17 +27,10 @@ module Crystal::System::User

pwd = uninitialized LibC::Passwd
pwd_pointer = pointerof(pwd)
initial_buf = uninitialized UInt8[1024]
buf = initial_buf.to_slice

ret = LibC.getpwuid_r(id, pwd_pointer, buf, buf.size, pointerof(pwd_pointer))
while ret == LibC::ERANGE && buf.size < GETPW_R_SIZE_MAX
buf = Bytes.new(buf.size * 2)
ret = LibC.getpwuid_r(id, pwd_pointer, buf, buf.size, pointerof(pwd_pointer))
System.retry_with_buffer("getpwuid_r", GETPW_R_SIZE_MAX) do |buf|
LibC.getpwuid_r(id, pwd_pointer, buf, buf.size, pointerof(pwd_pointer))
end

raise RuntimeError.from_errno("getpwuid_r") if ret != 0

from_struct(pwd) if pwd_pointer
end
end

0 comments on commit a9832d7

Please sign in to comment.