platform_darwin.pyx 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import os
  2. from .helpers import user2uid, group2gid
  3. API_VERSION = 2
  4. cdef extern from "sys/acl.h":
  5. ctypedef struct _acl_t:
  6. pass
  7. ctypedef _acl_t *acl_t
  8. int acl_free(void *obj)
  9. acl_t acl_get_link_np(const char *path, int type)
  10. acl_t acl_set_link_np(const char *path, int type, acl_t acl)
  11. acl_t acl_from_text(const char *buf)
  12. char *acl_to_text(acl_t acl, ssize_t *len_p)
  13. int ACL_TYPE_EXTENDED
  14. def _remove_numeric_id_if_possible(acl):
  15. """Replace the user/group field with the local uid/gid if possible
  16. """
  17. entries = []
  18. for entry in acl.decode('ascii').split('\n'):
  19. if entry:
  20. fields = entry.split(':')
  21. if fields[0] == 'user':
  22. if user2uid(fields[2]) is not None:
  23. fields[1] = fields[3] = ''
  24. elif fields[0] == 'group':
  25. if group2gid(fields[2]) is not None:
  26. fields[1] = fields[3] = ''
  27. entries.append(':'.join(fields))
  28. return ('\n'.join(entries)).encode('ascii')
  29. def _remove_non_numeric_identifier(acl):
  30. """Remove user and group names from the acl
  31. """
  32. entries = []
  33. for entry in acl.split(b'\n'):
  34. if entry:
  35. fields = entry.split(b':')
  36. if fields[0] in (b'user', b'group'):
  37. fields[2] = b''
  38. entries.append(b':'.join(fields))
  39. else:
  40. entries.append(entry)
  41. return b'\n'.join(entries)
  42. def acl_get(path, item, st, numeric_owner=False):
  43. cdef acl_t acl = NULL
  44. cdef char *text = NULL
  45. try:
  46. acl = acl_get_link_np(<bytes>os.fsencode(path), ACL_TYPE_EXTENDED)
  47. if acl == NULL:
  48. return
  49. text = acl_to_text(acl, NULL)
  50. if text == NULL:
  51. return
  52. if numeric_owner:
  53. item[b'acl_extended'] = _remove_non_numeric_identifier(text)
  54. else:
  55. item[b'acl_extended'] = text
  56. finally:
  57. acl_free(text)
  58. acl_free(acl)
  59. def acl_set(path, item, numeric_owner=False):
  60. cdef acl_t acl = NULL
  61. try:
  62. try:
  63. if numeric_owner:
  64. acl = acl_from_text(item[b'acl_extended'])
  65. else:
  66. acl = acl_from_text(<bytes>_remove_numeric_id_if_possible(item[b'acl_extended']))
  67. except KeyError:
  68. return
  69. if acl == NULL:
  70. return
  71. if acl_set_link_np(<bytes>os.fsencode(path), ACL_TYPE_EXTENDED, acl):
  72. return
  73. finally:
  74. acl_free(acl)