platform_linux.pyx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import os
  2. from attic.helpers import acl_use_local_uid_gid, acl_use_stored_uid_gid, user2uid, group2gid
  3. API_VERSION = 1
  4. cdef extern from "sys/types.h":
  5. int ACL_TYPE_ACCESS
  6. int ACL_TYPE_DEFAULT
  7. cdef extern from "sys/acl.h":
  8. ctypedef struct _acl_t:
  9. pass
  10. ctypedef _acl_t *acl_t
  11. int acl_free(void *obj)
  12. acl_t acl_get_file(const char *path, int type)
  13. acl_t acl_set_file(const char *path, int type, acl_t acl)
  14. acl_t acl_from_text(const char *buf)
  15. char *acl_to_text(acl_t acl, ssize_t *len)
  16. cdef extern from "acl/libacl.h":
  17. int acl_extended_file_nofollow(const char *path)
  18. def acl_append_numeric_ids(acl):
  19. """Extend the "POSIX 1003.1e draft standard 17" format with an additional uid/gid field
  20. """
  21. entries = []
  22. for entry in acl.decode('ascii').split('\n'):
  23. if entry:
  24. type, name, permission = entry.split(':')
  25. if name and type == 'user':
  26. entries.append(':'.join([type, name, permission, str(user2uid(name, name))]))
  27. elif name and type == 'group':
  28. entries.append(':'.join([type, name, permission, str(group2gid(name, name))]))
  29. else:
  30. entries.append(entry)
  31. return ('\n'.join(entries)).encode('ascii')
  32. def acl_numeric_ids(acl):
  33. """Replace the "POSIX 1003.1e draft standard 17" user/group field with uid/gid
  34. """
  35. entries = []
  36. for entry in acl.decode('ascii').split('\n'):
  37. if entry:
  38. type, name, permission = entry.split(':')
  39. if name and type == 'user':
  40. entries.append(':'.join([type, str(user2uid(name, name)), permission]))
  41. elif name and type == 'group':
  42. entries.append(':'.join([type, str(group2gid(name, name)), permission]))
  43. else:
  44. entries.append(entry)
  45. return ('\n'.join(entries)).encode('ascii')
  46. def acl_get(path, item, numeric_owner=False):
  47. """Saves ACL Entries
  48. If `numeric_owner` is True the user/group field is not preserved only uid/gid
  49. """
  50. cdef acl_t default_acl = NULL
  51. cdef acl_t access_acl = NULL
  52. cdef char *default_text = NULL
  53. cdef char *access_text = NULL
  54. if acl_extended_file_nofollow(<bytes>os.fsencode(path)) <= 0:
  55. return
  56. if numeric_owner:
  57. converter = acl_numeric_ids
  58. else:
  59. converter = acl_append_numeric_ids
  60. try:
  61. access_acl = acl_get_file(<bytes>os.fsencode(path), ACL_TYPE_ACCESS)
  62. if access_acl:
  63. access_text = acl_to_text(access_acl, NULL)
  64. if access_text:
  65. item[b'acl_access'] = acl_append_numeric_ids(access_text)
  66. default_acl = acl_get_file(<bytes>os.fsencode(path), ACL_TYPE_DEFAULT)
  67. if default_acl:
  68. default_text = acl_to_text(default_acl, NULL)
  69. if default_text:
  70. item[b'acl_default'] = acl_append_numeric_ids(default_text)
  71. finally:
  72. acl_free(default_text)
  73. acl_free(default_acl)
  74. acl_free(access_text)
  75. acl_free(access_acl)
  76. def acl_set(path, item, numeric_owner=False):
  77. """Restore ACL Entries
  78. If `numeric_owner` is True the stored uid/gid is used instead
  79. of the user/group names
  80. """
  81. cdef acl_t access_acl = NULL
  82. cdef acl_t default_acl = NULL
  83. if numeric_owner:
  84. converter = acl_use_stored_uid_gid
  85. else:
  86. converter = acl_use_local_uid_gid
  87. access_text = item.get(b'acl_access')
  88. default_text = item.get(b'acl_default')
  89. if access_text:
  90. try:
  91. access_acl = acl_from_text(<bytes>converter(access_text))
  92. if access_acl:
  93. acl_set_file(<bytes>os.fsencode(path), ACL_TYPE_ACCESS, access_acl)
  94. finally:
  95. acl_free(access_acl)
  96. if default_text:
  97. try:
  98. default_acl = acl_from_text(<bytes>converter(default_text))
  99. if default_acl:
  100. acl_set_file(<bytes>os.fsencode(path), ACL_TYPE_DEFAULT, default_acl)
  101. finally:
  102. acl_free(default_acl)