diff options
author | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-06-23 08:32:49 +0000 |
---|---|---|
committer | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-06-23 08:32:49 +0000 |
commit | c339f208c4b304199ebed24cf9963e8d13eefa1f (patch) | |
tree | d91946e1927ef4615cde44e7472fda698fa8bc6b /process.c | |
parent | 0fcc2cdb99264e196846155617f14e503ac951fc (diff) |
merge revision(s) 45287:45290: [Backport #9600]
* process.c (obj2uid, obj2gid): now getpwnam_r() and getgrnam_r()
may need larger buffers than sysconf values, so retry with
expanding the buffer when ERANGE is returned.
[ruby-core:61325] [Bug #9600]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_0_0@46511 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'process.c')
-rw-r--r-- | process.c | 54 |
1 files changed, 50 insertions, 4 deletions
@@ -147,6 +147,9 @@ static void check_gid_switch(void); #if defined(HAVE_PWD_H) # if defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX) # define USE_GETPWNAM_R 1 +# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX) +# define GETPW_R_SIZE_DEFAULT 0x1000 +# define GETPW_R_SIZE_LIMIT 0x10000 # endif # ifdef USE_GETPWNAM_R # define PREPARE_GETPWNAM \ @@ -171,6 +174,9 @@ static rb_uid_t obj2uid(VALUE id); #if defined(HAVE_GRP_H) # if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX) # define USE_GETGRNAM_R +# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX) +# define GETGR_R_SIZE_DEFAULT 0x1000 +# define GETGR_R_SIZE_LIMIT 0x10000 # endif # ifdef USE_GETGRNAM_R # define PREPARE_GETGRNAM \ @@ -4744,8 +4750,28 @@ obj2uid(VALUE id struct passwd *pwptr; #ifdef USE_GETPWNAM_R struct passwd pwbuf; - if (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) - rb_sys_fail("getpwnam_r"); + char *getpw_buf; + long getpw_buf_len; + if (!*getpw_tmp) { + getpw_buf_len = GETPW_R_SIZE_INIT; + if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT; + getpw_buf = rb_alloc_tmp_buffer(getpw_tmp, getpw_buf_len); + } + else { + getpw_buf = RSTRING_PTR(*getpw_tmp); + getpw_buf_len = rb_str_capacity(*getpw_tmp); + } + errno = ERANGE; + /* gepwnam_r() on MacOS X doesn't set errno if buffer size is insufficient */ + while (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) { + if (errno != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) { + rb_free_tmp_buffer(getpw_tmp); + rb_sys_fail("getpwnam_r"); + } + rb_str_modify_expand(*getpw_tmp, getpw_buf_len); + getpw_buf = RSTRING_PTR(*getpw_tmp); + getpw_buf_len = rb_str_capacity(*getpw_tmp); + } #else pwptr = getpwnam(usrname); #endif @@ -4792,8 +4818,28 @@ obj2gid(VALUE id struct group *grptr; #ifdef USE_GETGRNAM_R struct group grbuf; - if (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) - rb_sys_fail("getgrnam_r"); + char *getgr_buf; + long getgr_buf_len; + if (!*getgr_tmp) { + getgr_buf_len = GETGR_R_SIZE_INIT; + if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT; + getgr_buf = rb_alloc_tmp_buffer(getgr_tmp, getgr_buf_len); + } + else { + getgr_buf = RSTRING_PTR(*getgr_tmp); + getgr_buf_len = rb_str_capacity(*getgr_tmp); + } + errno = ERANGE; + /* gegrnam_r() on MacOS X doesn't set errno if buffer size is insufficient */ + while (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) { + if (errno != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) { + rb_free_tmp_buffer(getgr_tmp); + rb_sys_fail("getgrnam_r"); + } + rb_str_modify_expand(*getgr_tmp, getgr_buf_len); + getgr_buf = RSTRING_PTR(*getgr_tmp); + getgr_buf_len = rb_str_capacity(*getgr_tmp); + } #else grptr = getgrnam(grpname); #endif |