@@ -452,6 +452,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
452452 }
453453 seen [relFilePath ] = true
454454
455+ // TODO Windows: Verify if this needs to be os.Pathseparator
455456 // Rename the base resource
456457 if options .Name != "" && filePath == srcPath + "/" + filepath .Base (relFilePath ) {
457458 renamedRelFilePath = relFilePath
@@ -503,7 +504,8 @@ loop:
503504 }
504505
505506 // Normalize name, for safety and for a simple is-root check
506- // This keeps "../" as-is, but normalizes "/../" to "/"
507+ // This keeps "../" as-is, but normalizes "/../" to "/". Or Windows:
508+ // This keeps "..\" as-is, but normalizes "\..\" to "\".
507509 hdr .Name = filepath .Clean (hdr .Name )
508510
509511 for _ , exclude := range options .ExcludePatterns {
@@ -512,7 +514,10 @@ loop:
512514 }
513515 }
514516
515- if ! strings .HasSuffix (hdr .Name , "/" ) {
517+ // After calling filepath.Clean(hdr.Name) above, hdr.Name will now be in
518+ // the filepath format for the OS on which the daemon is running. Hence
519+ // the check for a slash-suffix MUST be done in an OS-agnostic way.
520+ if ! strings .HasSuffix (hdr .Name , string (os .PathSeparator )) {
516521 // Not the root directory, ensure that the parent directory exists
517522 parent := filepath .Dir (hdr .Name )
518523 parentPath := filepath .Join (dest , parent )
@@ -529,7 +534,7 @@ loop:
529534 if err != nil {
530535 return err
531536 }
532- if strings .HasPrefix (rel , "../" ) {
537+ if strings .HasPrefix (rel , ".." + string ( os . PathSeparator ) ) {
533538 return breakoutError (fmt .Errorf ("%q is outside of %q" , hdr .Name , dest ))
534539 }
535540
@@ -658,10 +663,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
658663 if err != nil {
659664 return err
660665 }
666+
661667 if srcSt .IsDir () {
662668 return fmt .Errorf ("Can't copy a directory" )
663669 }
664- // Clean up the trailing slash
670+
671+ // Clean up the trailing slash. This must be done in an operating
672+ // system specific manner.
665673 if dst [len (dst )- 1 ] == os .PathSeparator {
666674 dst = filepath .Join (dst , filepath .Base (src ))
667675 }
@@ -709,8 +717,10 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
709717// for a single file. It copies a regular file from path `src` to
710718// path `dst`, and preserves all its metadata.
711719//
712- // If `dst` ends with a trailing slash '/', the final destination path
713- // will be `dst/base(src)`.
720+ // Destination handling is in an operating specific manner depending
721+ // where the daemon is running. If `dst` ends with a trailing slash
722+ // the final destination path will be `dst/base(src)` (Linux) or
723+ // `dst\base(src)` (Windows).
714724func CopyFileWithTar (src , dst string ) (err error ) {
715725 return defaultArchiver .CopyFileWithTar (src , dst )
716726}
0 commit comments