Skip to content

Commit 8228ee4

Browse files
author
John Howard
committed
Windows: Archive package changes for Windows daemon
Signed-off-by: John Howard <[email protected]>
1 parent c696993 commit 8228ee4

11 files changed

Lines changed: 166 additions & 56 deletions

pkg/archive/archive.go

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212
"io/ioutil"
1313
"os"
1414
"os/exec"
15-
"path"
1615
"path/filepath"
16+
"runtime"
1717
"strings"
1818
"syscall"
1919

@@ -291,17 +291,8 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
291291
file.Close()
292292

293293
case tar.TypeBlock, tar.TypeChar, tar.TypeFifo:
294-
mode := uint32(hdr.Mode & 07777)
295-
switch hdr.Typeflag {
296-
case tar.TypeBlock:
297-
mode |= syscall.S_IFBLK
298-
case tar.TypeChar:
299-
mode |= syscall.S_IFCHR
300-
case tar.TypeFifo:
301-
mode |= syscall.S_IFIFO
302-
}
303-
304-
if err := system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor))); err != nil {
294+
// Handle this is an OS-specific way
295+
if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
305296
return err
306297
}
307298

@@ -337,8 +328,11 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
337328
return fmt.Errorf("Unhandled tar header type %d\n", hdr.Typeflag)
338329
}
339330

340-
if err := os.Lchown(path, hdr.Uid, hdr.Gid); err != nil && Lchown {
341-
return err
331+
// Lchown is not supported on Windows
332+
if runtime.GOOS != "windows" {
333+
if err := os.Lchown(path, hdr.Uid, hdr.Gid); err != nil && Lchown {
334+
return err
335+
}
342336
}
343337

344338
for key, value := range hdr.Xattrs {
@@ -349,20 +343,12 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
349343

350344
// There is no LChmod, so ignore mode for symlink. Also, this
351345
// must happen after chown, as that can modify the file mode
352-
if hdr.Typeflag == tar.TypeLink {
353-
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
354-
if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
355-
return err
356-
}
357-
}
358-
} else if hdr.Typeflag != tar.TypeSymlink {
359-
if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
360-
return err
361-
}
346+
if err := handleLChmod(hdr, path, hdrInfo); err != nil {
347+
return err
362348
}
363349

364350
ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
365-
// syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and
351+
// syscall.UtimesNano doesn't support a NOFOLLOW flag atm
366352
if hdr.Typeflag == tar.TypeLink {
367353
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
368354
if err := system.UtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
@@ -531,7 +517,7 @@ loop:
531517
parent := filepath.Dir(hdr.Name)
532518
parentPath := filepath.Join(dest, parent)
533519
if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
534-
err = os.MkdirAll(parentPath, 0777)
520+
err = system.MkdirAll(parentPath, 0777)
535521
if err != nil {
536522
return err
537523
}
@@ -651,7 +637,7 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
651637
}
652638
// Create dst, copy src's content into it
653639
logrus.Debugf("Creating dest directory: %s", dst)
654-
if err := os.MkdirAll(dst, 0755); err != nil && !os.IsExist(err) {
640+
if err := system.MkdirAll(dst, 0755); err != nil && !os.IsExist(err) {
655641
return err
656642
}
657643
logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
@@ -675,12 +661,12 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
675661
if srcSt.IsDir() {
676662
return fmt.Errorf("Can't copy a directory")
677663
}
678-
// Clean up the trailing /
679-
if dst[len(dst)-1] == '/' {
680-
dst = path.Join(dst, filepath.Base(src))
664+
// Clean up the trailing slash
665+
if dst[len(dst)-1] == os.PathSeparator {
666+
dst = filepath.Join(dst, filepath.Base(src))
681667
}
682668
// Create the holding directory if necessary
683-
if err := os.MkdirAll(filepath.Dir(dst), 0700); err != nil && !os.IsExist(err) {
669+
if err := system.MkdirAll(filepath.Dir(dst), 0700); err != nil && !os.IsExist(err) {
684670
return err
685671
}
686672

pkg/archive/archive_unix.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"errors"
88
"os"
99
"syscall"
10+
11+
"github.com/docker/docker/pkg/system"
1012
)
1113

1214
// canonicalTarNameForPath returns platform-specific filepath
@@ -51,3 +53,37 @@ func major(device uint64) uint64 {
5153
func minor(device uint64) uint64 {
5254
return (device & 0xff) | ((device >> 12) & 0xfff00)
5355
}
56+
57+
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
58+
// createTarFile to handle the following types of header: Block; Char; Fifo
59+
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
60+
mode := uint32(hdr.Mode & 07777)
61+
switch hdr.Typeflag {
62+
case tar.TypeBlock:
63+
mode |= syscall.S_IFBLK
64+
case tar.TypeChar:
65+
mode |= syscall.S_IFCHR
66+
case tar.TypeFifo:
67+
mode |= syscall.S_IFIFO
68+
}
69+
70+
if err := system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor))); err != nil {
71+
return err
72+
}
73+
return nil
74+
}
75+
76+
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
77+
if hdr.Typeflag == tar.TypeLink {
78+
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
79+
if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
80+
return err
81+
}
82+
}
83+
} else if hdr.Typeflag != tar.TypeSymlink {
84+
if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
85+
return err
86+
}
87+
}
88+
return nil
89+
}

pkg/archive/archive_windows.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ import (
1414
// path.
1515
func CanonicalTarNameForPath(p string) (string, error) {
1616
// windows: convert windows style relative path with backslashes
17-
// into forward slashes. since windows does not allow '/' or '\'
17+
// into forward slashes. Since windows does not allow '/' or '\'
1818
// in file names, it is mostly safe to replace however we must
1919
// check just in case
2020
if strings.Contains(p, "/") {
21-
return "", fmt.Errorf("windows path contains forward slash: %s", p)
21+
return "", fmt.Errorf("Windows path contains forward slash: %s", p)
2222
}
2323
return strings.Replace(p, string(os.PathSeparator), "/", -1), nil
2424

@@ -38,3 +38,13 @@ func setHeaderForSpecialDevice(hdr *tar.Header, ta *tarAppender, name string, st
3838
// do nothing. no notion of Rdev, Inode, Nlink in stat on Windows
3939
return
4040
}
41+
42+
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
43+
// createTarFile to handle the following types of header: Block; Char; Fifo
44+
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
45+
return nil
46+
}
47+
48+
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
49+
return nil
50+
}

pkg/archive/changes.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,6 @@ func (info *FileInfo) path() string {
174174
return filepath.Join(info.parent.path(), info.name)
175175
}
176176

177-
func (info *FileInfo) isDir() bool {
178-
return info.parent == nil || info.stat.Mode()&syscall.S_IFDIR != 0
179-
}
180-
181177
func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
182178

183179
sizeAtEntry := len(*changes)
@@ -214,13 +210,7 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
214210
// be visible when actually comparing the stat fields. The only time this
215211
// breaks down is if some code intentionally hides a change by setting
216212
// back mtime
217-
if oldStat.Mode() != newStat.Mode() ||
218-
oldStat.Uid() != newStat.Uid() ||
219-
oldStat.Gid() != newStat.Gid() ||
220-
oldStat.Rdev() != newStat.Rdev() ||
221-
// Don't look at size for dirs, its not a good measure of change
222-
(oldStat.Mode()&syscall.S_IFDIR != syscall.S_IFDIR &&
223-
(!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) ||
213+
if statDifferent(oldStat, newStat) ||
224214
bytes.Compare(oldChild.capability, newChild.capability) != 0 {
225215
change := Change{
226216
Path: newChild.path(),

pkg/archive/changes_unix.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// +build !windows
2+
3+
package archive
4+
5+
import (
6+
"syscall"
7+
8+
"github.com/docker/docker/pkg/system"
9+
)
10+
11+
func statDifferent(oldStat *system.Stat_t, newStat *system.Stat_t) bool {
12+
// Don't look at size for dirs, its not a good measure of change
13+
if oldStat.Mode() != newStat.Mode() ||
14+
oldStat.Uid() != newStat.Uid() ||
15+
oldStat.Gid() != newStat.Gid() ||
16+
oldStat.Rdev() != newStat.Rdev() ||
17+
// Don't look at size for dirs, its not a good measure of change
18+
(oldStat.Mode()&syscall.S_IFDIR != syscall.S_IFDIR &&
19+
(!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) {
20+
return true
21+
}
22+
return false
23+
}
24+
25+
func (info *FileInfo) isDir() bool {
26+
return info.parent == nil || info.stat.Mode()&syscall.S_IFDIR != 0
27+
}

pkg/archive/changes_windows.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package archive
2+
3+
import (
4+
"github.com/docker/docker/pkg/system"
5+
)
6+
7+
func statDifferent(oldStat *system.Stat_t, newStat *system.Stat_t) bool {
8+
9+
// Don't look at size for dirs, its not a good measure of change
10+
if oldStat.ModTime() != newStat.ModTime() ||
11+
oldStat.Mode() != newStat.Mode() ||
12+
oldStat.Size() != newStat.Size() && !oldStat.IsDir() {
13+
return true
14+
}
15+
return false
16+
}
17+
18+
func (info *FileInfo) isDir() bool {
19+
return info.parent == nil || info.stat.IsDir()
20+
}

pkg/archive/diff.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func UnpackLayer(dest string, layer ArchiveReader) (size int64, err error) {
4747
parent := filepath.Dir(hdr.Name)
4848
parentPath := filepath.Join(dest, parent)
4949
if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
50-
err = os.MkdirAll(parentPath, 0600)
50+
err = system.MkdirAll(parentPath, 0600)
5151
if err != nil {
5252
return 0, err
5353
}

pkg/system/lstat_windows.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,28 @@
22

33
package system
44

5+
import (
6+
"os"
7+
)
8+
9+
// Some explanation for my own sanity, and hopefully maintainers in the
10+
// future.
11+
//
12+
// Lstat calls os.Lstat to get a fileinfo interface back.
13+
// This is then copied into our own locally defined structure.
14+
// Note the Linux version uses fromStatT to do the copy back,
15+
// but that not strictly necessary when already in an OS specific module.
16+
517
func Lstat(path string) (*Stat_t, error) {
6-
// should not be called on cli code path
7-
return nil, ErrNotSupportedPlatform
18+
fi, err := os.Lstat(path)
19+
if err != nil {
20+
return nil, err
21+
}
22+
23+
return &Stat_t{
24+
name: fi.Name(),
25+
size: fi.Size(),
26+
mode: fi.Mode(),
27+
modTime: fi.ModTime(),
28+
isDir: fi.IsDir()}, nil
829
}

pkg/system/mknod_windows.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
package system
44

55
func Mknod(path string, mode uint32, dev int) error {
6-
// should not be called on cli code path
76
return ErrNotSupportedPlatform
87
}
98

109
func Mkdev(major int64, minor int64) uint32 {
11-
panic("Mkdev not implemented on windows, should not be called on cli code")
10+
panic("Mkdev not implemented on Windows.")
1211
}

pkg/system/stat.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// +build !windows
2+
13
package system
24

35
import (

0 commit comments

Comments
 (0)