tar_unix.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // +build !windows
  2. /*
  3. Copyright The containerd Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package archive
  15. import (
  16. "context"
  17. "os"
  18. "sync"
  19. "syscall"
  20. "github.com/containerd/continuity/sysx"
  21. "github.com/dmcgowan/go-tar"
  22. "github.com/opencontainers/runc/libcontainer/system"
  23. "github.com/pkg/errors"
  24. "golang.org/x/sys/unix"
  25. )
  26. func tarName(p string) (string, error) {
  27. return p, nil
  28. }
  29. func chmodTarEntry(perm os.FileMode) os.FileMode {
  30. return perm
  31. }
  32. func setHeaderForSpecialDevice(hdr *tar.Header, name string, fi os.FileInfo) error {
  33. s, ok := fi.Sys().(*syscall.Stat_t)
  34. if !ok {
  35. return errors.New("unsupported stat type")
  36. }
  37. // Rdev is int32 on darwin/bsd, int64 on linux/solaris
  38. rdev := uint64(s.Rdev) // nolint: unconvert
  39. // Currently go does not fill in the major/minors
  40. if s.Mode&syscall.S_IFBLK != 0 ||
  41. s.Mode&syscall.S_IFCHR != 0 {
  42. hdr.Devmajor = int64(unix.Major(rdev))
  43. hdr.Devminor = int64(unix.Minor(rdev))
  44. }
  45. return nil
  46. }
  47. func open(p string) (*os.File, error) {
  48. return os.Open(p)
  49. }
  50. func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
  51. f, err := os.OpenFile(name, flag, perm)
  52. if err != nil {
  53. return nil, err
  54. }
  55. // Call chmod to avoid permission mask
  56. if err := os.Chmod(name, perm); err != nil {
  57. return nil, err
  58. }
  59. return f, err
  60. }
  61. func mkdirAll(path string, perm os.FileMode) error {
  62. return os.MkdirAll(path, perm)
  63. }
  64. func mkdir(path string, perm os.FileMode) error {
  65. if err := os.Mkdir(path, perm); err != nil {
  66. return err
  67. }
  68. // Only final created directory gets explicit permission
  69. // call to avoid permission mask
  70. return os.Chmod(path, perm)
  71. }
  72. func skipFile(*tar.Header) bool {
  73. return false
  74. }
  75. var (
  76. inUserNS bool
  77. nsOnce sync.Once
  78. )
  79. func setInUserNS() {
  80. inUserNS = system.RunningInUserNS()
  81. }
  82. // handleTarTypeBlockCharFifo is an OS-specific helper function used by
  83. // createTarFile to handle the following types of header: Block; Char; Fifo
  84. func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
  85. nsOnce.Do(setInUserNS)
  86. if inUserNS {
  87. // cannot create a device if running in user namespace
  88. return nil
  89. }
  90. mode := uint32(hdr.Mode & 07777)
  91. switch hdr.Typeflag {
  92. case tar.TypeBlock:
  93. mode |= unix.S_IFBLK
  94. case tar.TypeChar:
  95. mode |= unix.S_IFCHR
  96. case tar.TypeFifo:
  97. mode |= unix.S_IFIFO
  98. }
  99. return unix.Mknod(path, mode, int(unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor))))
  100. }
  101. func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
  102. if hdr.Typeflag == tar.TypeLink {
  103. if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
  104. if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
  105. return err
  106. }
  107. }
  108. } else if hdr.Typeflag != tar.TypeSymlink {
  109. if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
  110. return err
  111. }
  112. }
  113. return nil
  114. }
  115. func getxattr(path, attr string) ([]byte, error) {
  116. b, err := sysx.LGetxattr(path, attr)
  117. if err == unix.ENOTSUP || err == sysx.ENODATA {
  118. return nil, nil
  119. }
  120. return b, err
  121. }
  122. func setxattr(path, key, value string) error {
  123. return sysx.LSetxattr(path, key, []byte(value), 0)
  124. }
  125. // apply applies a tar stream of an OCI style diff tar.
  126. // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
  127. func apply(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) {
  128. return applyNaive(ctx, root, tr, options)
  129. }