@@ -3,7 +3,7 @@ import re
33import stat
44
55from .posix import posix_acl_use_stored_uid_gid
6- from .posix import user2uid, group2gid
6+ from . import posix_ug
77from ..helpers import workarounds
88from ..helpers import safe_decode, safe_encode
99from .base import SyncFile as BaseSyncFile
@@ -47,11 +47,12 @@ cdef extern from "sys/acl.h":
4747 int acl_set_file(const char * path, int type , acl_t acl)
4848 int acl_set_fd(int fd, acl_t acl)
4949 acl_t acl_from_text(const char * buf)
50- char * acl_to_text(acl_t acl, ssize_t * len )
5150
5251cdef extern from " acl/libacl.h" :
5352 int acl_extended_file_nofollow(const char * path)
5453 int acl_extended_fd(int fd)
54+ char * acl_to_any_text(acl_t acl, const char * prefix, char separator, int options)
55+ int TEXT_NUMERIC_IDS
5556
5657cdef extern from " linux/fs.h" :
5758 # ioctls
@@ -203,46 +204,66 @@ def acl_use_local_uid_gid(acl):
203204 if entry:
204205 fields = entry.split(' :' )
205206 if fields[0 ] == ' user' and fields[1 ]:
206- fields[1 ] = str (user2uid (fields[1 ], fields[3 ]))
207+ fields[1 ] = str (posix_ug._user2uid (fields[1 ], fields[3 ]))
207208 elif fields[0 ] == ' group' and fields[1 ]:
208- fields[1 ] = str (group2gid (fields[1 ], fields[3 ]))
209+ fields[1 ] = str (posix_ug._group2gid (fields[1 ], fields[3 ]))
209210 entries.append(' :' .join(fields[:3 ]))
210211 return safe_encode(' \n ' .join(entries))
211212
212213
213- cdef acl_append_numeric_ids(acl):
214- """ Extend the "POSIX 1003.1e draft standard 17" format with an additional uid/gid field
214+ def _acl_from_numeric_to_named_with_id (acl ):
215+ """ Convert numeric-id ACL entries to name entries and append numeric id as 4th field.
216+
217+ Input format (Linux libacl): lines like 'user:1000:rwx' or 'group:100:r-x' or 'user::rwx'.
218+ Output format: for entries with a name/id field, become 'user:uname:rwx:uid' or 'group:gname:r-x:gid'.
215219 """
216220 assert isinstance (acl, bytes)
217221 entries = []
218222 for entry in _comment_re.sub(' ' , safe_decode(acl)).split(' \n ' ):
219- if entry:
220- type , name, permission = entry.split(' :' )
221- if name and type == ' user' :
222- entries.append(' :' .join([type , name, permission, str (user2uid(name, name))]))
223- elif name and type == ' group' :
224- entries.append(' :' .join([type , name, permission, str (group2gid(name, name))]))
223+ if not entry:
224+ continue
225+ fields = entry.split(' :' )
226+ # Expected 3 fields: type, ugid_or_empty, perms
227+ if len (fields) >= 3 :
228+ typ, ugid_str, perm = fields[0 ], fields[1 ], fields[2 ]
229+ if ugid_str and typ == ' user' :
230+ try :
231+ uid = int (ugid_str)
232+ except ValueError :
233+ uid = None
234+ uname = posix_ug._uid2user(uid, ugid_str) if uid is not None else ugid_str
235+ entries.append(' :' .join([typ, uname, perm, str (uid if uid is not None else ugid_str)]))
236+ elif ugid_str and typ == ' group' :
237+ try :
238+ gid = int (ugid_str)
239+ except ValueError :
240+ gid = None
241+ gname = posix_ug._gid2group(gid, ugid_str) if gid is not None else ugid_str
242+ entries.append(' :' .join([typ, gname, perm, str (gid if gid is not None else ugid_str)]))
225243 else :
226- entries.append(entry)
244+ # owner, group_obj, mask, other (empty ugid_str field) stay as-is
245+ entries.append(' :' .join([typ, ' ' , perm]))
246+ else :
247+ entries.append(entry)
227248 return safe_encode(' \n ' .join(entries))
228249
229250
230- cdef acl_numeric_ids(acl):
231- """ Replace the "POSIX 1003.1e draft standard 17" user/group field with uid/gid
232- """
251+ def _acl_from_numeric_to_numeric_with_id (acl ):
252+ """ Keep numeric ids in name field and append the same id as 4th field where applicable."""
233253 assert isinstance (acl, bytes)
234254 entries = []
235255 for entry in _comment_re.sub(' ' , safe_decode(acl)).split(' \n ' ):
236- if entry:
237- type , name, permission = entry.split(' :' )
238- if name and type == ' user' :
239- uid = str (user2uid(name, name))
240- entries.append(' :' .join([type , uid, permission, uid]))
241- elif name and type == ' group' :
242- gid = str (group2gid(name, name))
243- entries.append(' :' .join([type , gid, permission, gid]))
256+ if not entry:
257+ continue
258+ fields = entry.split(' :' )
259+ if len (fields) >= 3 :
260+ typ, ugid, perm = fields[0 ], fields[1 ], fields[2 ]
261+ if ugid and (typ == ' user' or typ == ' group' ):
262+ entries.append(' :' .join([typ, ugid, perm, ugid]))
244263 else :
245- entries.append(entry)
264+ entries.append(' :' .join([typ, ' ' , perm]))
265+ else :
266+ entries.append(entry)
246267 return safe_encode(' \n ' .join(entries))
247268
248269
@@ -266,17 +287,17 @@ def acl_get(path, item, st, numeric_ids=False, fd=None):
266287 # note: this should also be the case for symlink fs objects, as they can not have ACLs.
267288 return
268289 if numeric_ids:
269- converter = acl_numeric_ids
290+ converter = _acl_from_numeric_to_numeric_with_id
270291 else :
271- converter = acl_append_numeric_ids
292+ converter = _acl_from_numeric_to_named_with_id
272293 try :
273294 if fd is not None :
274295 access_acl = acl_get_fd(fd)
275296 else :
276297 access_acl = acl_get_file(path, ACL_TYPE_ACCESS)
277298 if access_acl == NULL :
278299 raise OSError (errno.errno, os.strerror(errno.errno), os.fsdecode(path))
279- access_text = acl_to_text (access_acl, NULL )
300+ access_text = acl_to_any_text (access_acl, NULL , ' \n ' , TEXT_NUMERIC_IDS )
280301 if access_text == NULL :
281302 raise OSError (errno.errno, os.strerror(errno.errno), os.fsdecode(path))
282303 item[' acl_access' ] = converter(access_text)
@@ -289,7 +310,7 @@ def acl_get(path, item, st, numeric_ids=False, fd=None):
289310 default_acl = acl_get_file(path, ACL_TYPE_DEFAULT)
290311 if default_acl == NULL :
291312 raise OSError (errno.errno, os.strerror(errno.errno), os.fsdecode(path))
292- default_text = acl_to_text (default_acl, NULL )
313+ default_text = acl_to_any_text (default_acl, NULL , ' \n ' , TEXT_NUMERIC_IDS )
293314 if default_text == NULL :
294315 raise OSError (errno.errno, os.strerror(errno.errno), os.fsdecode(path))
295316 item[' acl_default' ] = converter(default_text)
0 commit comments