@@ -104,7 +104,7 @@ func (c copier) CopyDir(source, target string, uid, gid int) error {
104104 if err := mkdirAll (target , os .ModePerm , uid , gid , false ); err != nil {
105105 return fmt .Errorf ("mkdir all %s: %s" , target , err )
106106 }
107- // Recursively copy directories and files .
107+ // Recursively copy contents of source directory .
108108 return c .copyDirContents (source , target , target , uid , gid , false )
109109}
110110
@@ -115,11 +115,26 @@ func (c copier) CopyDirPreserveOwner(source, target string) error {
115115 log .Infof ("* Ignoring copy of directory %s because it is blacklisted" , source )
116116 return nil
117117 }
118- // Make target parent directories (uid and gid will be computed from the sources one).
119- if err := mkdirAll (target , os .ModePerm , 0 , 0 , true ); err != nil {
120- return fmt .Errorf ("mkdir all %s: %s" , target , err )
118+ // Copy the parent directory of target.
119+ targetParentDir := filepath .Dir (target )
120+ if err := mkdirAll (targetParentDir , os .ModePerm , 0 , 0 , true ); err != nil {
121+ return fmt .Errorf ("mkdir parent dir %s: %s" , targetParentDir , err )
122+ }
123+ // If the source dir is a symlink, makisu would try to copy the contents rather than a link.
124+ fi , _ := os .Stat (source )
125+ sourceUid , sourceGid := fileOwners (fi )
126+ if _ , err := os .Lstat (target ); err != nil {
127+ if ! os .IsNotExist (err ) {
128+ return fmt .Errorf ("stat %s: %s" , target , err )
129+ } else if err := os .Mkdir (target , os .ModePerm ); err != nil {
130+ return fmt .Errorf ("mkdir %s: %s" , target , err )
131+ }
121132 }
122- // Recursively copy directories and files.
133+ // Preserve the source dir ownership.
134+ if err := os .Chown (target , sourceUid , sourceGid ); err != nil {
135+ return fmt .Errorf ("chown %s: %s" , target , err )
136+ }
137+ // Recursively copy contents of source directory.
123138 return c .copyDirContents (source , target , target , 0 , 0 , true )
124139}
125140
@@ -289,7 +304,7 @@ func (c copier) copyDir(src, dst string, uid, gid int, preserveOwner bool) error
289304
290305// mkdirAll performs the same operation as os.MkdirAll, but also sets the given
291306// permissions & owners on all created directories.
292- func mkdirAll (dst string , mode os.FileMode , uid , gid int , preserveOwner bool ) error {
307+ func mkdirAll (dst string , mode os.FileMode , uid , gid int , preserveParentOwner bool ) error {
293308 if dst == "" {
294309 return errors .New ("empty target directory" )
295310 }
@@ -300,7 +315,6 @@ func mkdirAll(dst string, mode os.FileMode, uid, gid int, preserveOwner bool) er
300315
301316 split := strings .Split (abs , "/" )
302317 split [0 ] = "/"
303-
304318 var prevDir string
305319 for _ , dir := range split {
306320 absDir := filepath .Join (prevDir , dir )
@@ -312,8 +326,8 @@ func mkdirAll(dst string, mode os.FileMode, uid, gid int, preserveOwner bool) er
312326 }
313327
314328 // Update file info
315- fi , _ = os .Lstat (absDir )
316- if preserveOwner {
329+ fi , _ = os .Lstat (prevDir )
330+ if preserveParentOwner {
317331 uid , gid = fileOwners (fi )
318332 }
319333 if err := os .Chown (absDir , uid , gid ); err != nil {
@@ -322,6 +336,7 @@ func mkdirAll(dst string, mode os.FileMode, uid, gid int, preserveOwner bool) er
322336 }
323337 prevDir = absDir
324338 }
339+
325340 return nil
326341}
327342
0 commit comments