@@ -58,8 +58,8 @@ class _UploadEntry:
5858 guest_path : str
5959 is_dir : bool
6060 mode : int
61- uid : int
62- gid : int
61+ uid : int | None
62+ gid : int | None
6363 size : int
6464
6565
@@ -91,8 +91,8 @@ def visit(local_path: Path, remote_path: str, root: bool = False) -> None:
9191
9292 is_dir = stat .S_ISDIR (info .st_mode )
9393 entry_mode = mode if root and mode is not None else stat .S_IMODE (info .st_mode )
94- uid = int (getattr (info , "st_uid" , 0 )) if archive else 0
95- gid = int (getattr (info , "st_gid" , 0 )) if archive else 0
94+ uid = int (getattr (info , "st_uid" , 0 )) if archive else None
95+ gid = int (getattr (info , "st_gid" , 0 )) if archive else None
9696 entries .append (
9797 _UploadEntry (
9898 source = local_path ,
@@ -131,9 +131,9 @@ def _request(entry: _UploadEntry) -> str:
131131 "is_dir" : entry .is_dir ,
132132 "mode" : entry .mode ,
133133 }
134- if entry .uid :
134+ if entry .uid is not None :
135135 payload ["uid" ] = entry .uid
136- if entry .gid :
136+ if entry .gid is not None :
137137 payload ["gid" ] = entry .gid
138138 return json .dumps (payload , separators = ("," , ":" ))
139139
@@ -318,6 +318,7 @@ def __init__(self, destination: Path, archive: bool, callbacks: CopyCallbacks |
318318 self .file : BinaryIO | None = None
319319 self .temp_path : Path | None = None
320320 self .bytes_received = 0
321+ self .directories : list [_DownloadHeader ] = []
321322 self .complete = False
322323
323324 def abort (self ) -> None :
@@ -405,8 +406,7 @@ def _start(self, message: dict[str, object]) -> None:
405406 if target .is_symlink () or (target .exists () and not target .is_dir ()):
406407 raise CopyProtocolError (f"cp cannot replace local path with directory: { target } " )
407408 target .mkdir (parents = True , exist_ok = True )
408- target .chmod (header .mode )
409- self ._chown (target , header , follow_symlinks = True )
409+ self .directories .append (header )
410410 elif header .is_symlink :
411411 self ._create_symlink (header )
412412 else :
@@ -474,6 +474,11 @@ def _end(self, message: dict[str, object]) -> None:
474474 self .header = None
475475 self .bytes_received = 0
476476 if final :
477+ for directory in reversed (self .directories ):
478+ if directory .mtime :
479+ os .utime (directory .target , (directory .mtime , directory .mtime ))
480+ self ._chown (directory .target , directory , follow_symlinks = True )
481+ directory .target .chmod (directory .mode )
477482 self .complete = True
478483
479484 def _chown (self , path : Path , header : _DownloadHeader , * , follow_symlinks : bool ) -> None :
0 commit comments