Repository: borgbackup/borg

Issue:
export/import-tar roundtrip test crashing in focal64 vagrant vm
```
    focal64:         os.unlink('input/flagfile')                                                                                                                                       [97/15946]
    focal64:         self.cmd('init', '--encryption=none', self.repository_location)                                                                                                             
    focal64:         self.cmd('create', self.repository_location + '::src', 'input')                                                                                                             
    focal64:         self.cmd('export-tar', self.repository_location + '::src', 'simple.tgz')                                                                                                    
    focal64:         self.cmd('import-tar', self.repository_location + '::dst', 'simple.tgz')                                                                                                    
    focal64:         with changedir(self.output_path):                                                                                                                                           
    focal64: >           self.cmd('extract', self.repository_location + '::dst')                                                                                                                 
    focal64:                                                                                                                                                                                     
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/testsuite/archiver.py:3438:                                                                                                        
    focal64: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _                                                                                                     
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/testsuite/archiver.py:288: in cmd                                                                                                  
    focal64:     ret, output = exec_cmd(*args, fork=fork, exe=self.EXE, archiver=self.archiver, **kw)                                                                                            
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/testsuite/archiver.py:108: in exec_cmd                                                                                             
    focal64:     ret = archiver.run(args)                                                                                                                                                        
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/archiver.py:4892: in run                                                                                                           
    focal64:     return set_ec(func(args))                                                      
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/archiver.py:183: in wrapper                                                                                                        
    focal64:     return method(self, args, repository=repository, **kwargs)                                                                                                                      
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/archiver.py:198: in wrapper                                                                                                        
    focal64:     return method(self, args, repository=repository, manifest=manifest, key=key, archive=archive, **kwargs)  
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/archiver.py:907: in do_extract                                                                                                     
    focal64:     archive.extract_item(item, stdout=stdout, sparse=sparse, hardlink_masters=hardlink_masters,              
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/archive.py:781: in extract_item                                                                                                    
    focal64:     self.restore_attrs(path, item, fd=fd.fileno())                                                                                                                                  
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/archive.py:832: in restore_attrs                                                                                                   
    focal64:     uid, gid = get_item_uid_gid(item, numeric=self.numeric_ids)                                                                                                                     
    focal64: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _                                                                                                     
    focal64:                                                                                                                                                                                         focal64: item = Item(internal_dict={'chunks': [ChunkListEntry(id=b'\xb2\x91^\xb6\x9f&\r\x8d<%$\x91\x95\xf2\xc8\xf4\xf7\x16\xea\x82\xec...': 35309, 'mtime': 1623859428000000000, 'path': b'in
put/file1', 'size': 81920, 'uid': 100, 'user': b'systemd-network'})                                                                                                                              
    focal64:                                                                                                                                                                                     
    focal64:     def get_item_uid_gid(item, *, numeric, uid_forced=None, gid_forced=None, uid_default=0, gid_default=0):  
    focal64:         if uid_forced is not None:                                                                                                                                                  
    focal64:             uid = uid_forced                                                                                                                                                        
    focal64:         else:                                                                                                                                                                       
    focal64:             uid = None if numeric else user2uid(item.user)                                                                                                                          
    focal64:             uid = item.uid if uid is None else uid                                                                                                                                  
    focal64:             if uid < 0:                                                                                                                                                             
    focal64:                 uid = uid_default                                                                                                                                                   
    focal64:         if gid_forced is not None:                                                                                                                                                  
    focal64:             gid = gid_forced                                                                                                                                                        
    focal64:         else:                                                                                                                                                                       
    focal64:             gid = None if numeric else group2gid(item.group)                                                                                                                        
    focal64:             gid = item.gid if gid is None else gid                                                                                                                                  
    focal64: >           if gid < 0:                                                                                                                                                             
    focal64: E           TypeError: '<' not supported between instances of 'str' and 'int'                                                                                                       
    focal64:                                                                                                                                                                                     
    focal64: .tox/py38-fuse3/lib/python3.8/site-packages/borg/archive.py:384: TypeError           
```


Discussion:
`gid == ''` when that crash happens.

this is because `item.group == ''`.
export-tar sets tarinfo.uname/gname to the empty string (which is also the default of a fresh `TarInfo` instance) and means "not known".

but our Item instances have `None` meaning "not known" and every str should really be a user/group name.

```
diff --git a/src/borg/archive.py b/src/borg/archive.py
index 2de2e90e..aca04c0b 100644
--- a/src/borg/archive.py
+++ b/src/borg/archive.py
@@ -1410,7 +1410,7 @@ def __init__(self, *, cache, key,
     @contextmanager
     def create_helper(self, tarinfo, status=None, type=None):
         item = Item(path=make_path_safe(tarinfo.name), mode=tarinfo.mode | type,
-                    uid=tarinfo.uid, gid=tarinfo.gid, user=tarinfo.uname, group=tarinfo.gname,
+                    uid=tarinfo.uid, gid=tarinfo.gid, user=tarinfo.uname or None, group=tarinfo.gname or None,
                     mtime=tarinfo.mtime * 1000**3)
         yield item, status
         # if we get here, "with"-block worked ok without error/exception, the item was processed ok...
```

Resolving patch:
diff --git a/src/borg/archive.py b/src/borg/archive.py
--- a/src/borg/archive.py
+++ b/src/borg/archive.py
@@ -1410,7 +1410,7 @@ def __init__(self, *, cache, key,
     @contextmanager
     def create_helper(self, tarinfo, status=None, type=None):
         item = Item(path=make_path_safe(tarinfo.name), mode=tarinfo.mode | type,
-                    uid=tarinfo.uid, gid=tarinfo.gid, user=tarinfo.uname, group=tarinfo.gname,
+                    uid=tarinfo.uid, gid=tarinfo.gid, user=tarinfo.uname or None, group=tarinfo.gname or None,
                     mtime=tarinfo.mtime * 1000**3)
         yield item, status
         # if we get here, "with"-block worked ok without error/exception, the item was processed ok...


Test patch: