Merged revisions 83124 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/branches/release27-maint

................
  r83124 | ronald.oussoren | 2010-07-24 10:46:41 +0100 (Sat, 24 Jul 2010) | 15 lines

  Merged revisions 83088 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/branches/py3k

  ........
    r83088 | ronald.oussoren | 2010-07-23 14:53:51 +0100 (Fri, 23 Jul 2010) | 8 lines

    This fixes issue7900 by adding code that deals
    with the fact that getgroups(2) might return
    more that MAX_GROUPS on OSX.

    See the issue (and python-dev archives) for the
    gory details. Summarized: OSX behaves rather oddly
    and Apple says this is intentional.
  ........
................
This commit is contained in:
Ronald Oussoren 2010-07-24 10:05:19 +00:00
parent a417db544e
commit ac08e302de
3 changed files with 94 additions and 8 deletions

View File

@ -8,6 +8,7 @@ except ImportError:
raise test_support.TestSkipped, "posix is not available"
import errno
import sys
import time
import os
import pwd
@ -306,9 +307,52 @@ class PosixTester(unittest.TestCase):
os.chdir(curdir)
shutil.rmtree(base_path)
def test_getgroups(self):
with os.popen('id -G') as idg:
groups = idg.read().strip()
if not groups:
raise unittest.SkipTest("need working 'id -G'")
self.assertEqual([int(x) for x in groups.split()], posix.getgroups())
class PosixGroupsTester(unittest.TestCase):
if posix.getuid() == 0 and hasattr(posix, 'getgroups') and sys.platform != 'darwin':
def setUp(self):
self.saved_groups = posix.getgroups()
def tearDown(self):
if hasattr(posix, 'setgroups'):
posix.setgroups(self.saved_groups)
elif hasattr(posix, 'initgroups'):
name = pwd.getpwuid(posix.getuid()).pw_name
posix.initgroups(name, self.saved_groups[0])
if hasattr(posix, 'initgroups'):
def test_initgroups(self):
# find missing group
groups = sorted(self.saved_groups)
for g1,g2 in zip(groups[:-1], groups[1:]):
g = g1 + 1
if g < g2:
break
else:
g = g2 + 1
name = pwd.getpwuid(posix.getuid()).pw_name
posix.initgroups(name, g)
self.assertIn(g, posix.getgroups())
if hasattr(posix, 'setgroups'):
def test_setgroups(self):
for groups in [[0], range(16)]:
posix.setgroups(groups)
self.assertListEqual(groups, posix.getgroups())
def test_main():
test_support.run_unittest(PosixTester)
test_support.run_unittest(PosixTester, PosixGroupsTester)
if __name__ == '__main__':
test_main()

View File

@ -312,6 +312,13 @@ Library
Extension Modules
-----------------
- Issue #7900: The getgroups(2) system call on MacOSX behaves rather oddly
compared to other unix systems. In particular, os.getgroups() does
not reflect any changes made using os.setgroups() but basicly always
returns the same information as the id command.
os.getgroups() can now return more than 16 groups on MacOSX.
- Issue #9277: Fix bug in struct.pack for bools in standard mode
(e.g., struct.pack('>?')): if conversion to bool raised an exception
then that exception wasn't properly propagated on machines where

View File

@ -3895,17 +3895,49 @@ posix_getgroups(PyObject *self, PyObject *noargs)
#define MAX_GROUPS 64
#endif
gid_t grouplist[MAX_GROUPS];
/* On MacOSX getgroups(2) can return more than MAX_GROUPS results
* This is a helper variable to store the intermediate result when
* that happens.
*
* To keep the code readable the OSX behaviour is unconditional,
* according to the POSIX spec this should be safe on all unix-y
* systems.
*/
gid_t* alt_grouplist = grouplist;
int n;
n = getgroups(MAX_GROUPS, grouplist);
if (n < 0)
posix_error();
else {
result = PyList_New(n);
if (result != NULL) {
if (n < 0) {
if (errno == EINVAL) {
n = getgroups(0, NULL);
if (n == -1) {
return posix_error();
}
if (n == 0) {
/* Avoid malloc(0) */
alt_grouplist = grouplist;
} else {
alt_grouplist = PyMem_Malloc(n * sizeof(gid_t));
if (alt_grouplist == NULL) {
errno = EINVAL;
return posix_error();
}
n = getgroups(n, alt_grouplist);
if (n == -1) {
PyMem_Free(alt_grouplist);
return posix_error();
}
}
} else {
return posix_error();
}
}
result = PyList_New(n);
if (result != NULL) {
int i;
for (i = 0; i < n; ++i) {
PyObject *o = PyInt_FromLong((long)grouplist[i]);
PyObject *o = PyInt_FromLong((long)alt_grouplist[i]);
if (o == NULL) {
Py_DECREF(result);
result = NULL;
@ -3913,7 +3945,10 @@ posix_getgroups(PyObject *self, PyObject *noargs)
}
PyList_SET_ITEM(result, i, o);
}
}
}
if (alt_grouplist != grouplist) {
PyMem_Free(alt_grouplist);
}
return result;