]> granicus.if.org Git - python/commitdiff
Merged revisions 83124 via svnmerge from
authorRonald Oussoren <ronaldoussoren@mac.com>
Sat, 24 Jul 2010 10:05:19 +0000 (10:05 +0000)
committerRonald Oussoren <ronaldoussoren@mac.com>
Sat, 24 Jul 2010 10:05:19 +0000 (10:05 +0000)
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.
  ........
................

Lib/test/test_posix.py
Misc/NEWS
Modules/posixmodule.c

index a2eba89cf3c3a358c12d4eaf4a9cca3b4cae14c2..4416f68a451b7302134f3d694976174dc9aebc0e 100644 (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()
index 4856c79549059856dd26b82c710462ebe7129c44..d9cb0eeb538aa1d260affb1dc2c797cad64d3490 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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
index a7f738256774e0b7e76975ec96d6640ff3cea3bd..822bc110fd477a2e31ba63113b059cf04052fbc6 100644 (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;