idtools_unix_test.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. // +build !windows
  2. package idtools
  3. import (
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "path/filepath"
  8. "syscall"
  9. "testing"
  10. )
  11. type node struct {
  12. uid int
  13. gid int
  14. }
  15. func TestMkdirAllAs(t *testing.T) {
  16. dirName, err := ioutil.TempDir("", "mkdirall")
  17. if err != nil {
  18. t.Fatalf("Couldn't create temp dir: %v", err)
  19. }
  20. defer os.RemoveAll(dirName)
  21. testTree := map[string]node{
  22. "usr": {0, 0},
  23. "usr/bin": {0, 0},
  24. "lib": {33, 33},
  25. "lib/x86_64": {45, 45},
  26. "lib/x86_64/share": {1, 1},
  27. }
  28. if err := buildTree(dirName, testTree); err != nil {
  29. t.Fatal(err)
  30. }
  31. // test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
  32. if err := MkdirAllAs(filepath.Join(dirName, "usr", "share"), 0755, 99, 99); err != nil {
  33. t.Fatal(err)
  34. }
  35. testTree["usr/share"] = node{99, 99}
  36. verifyTree, err := readTree(dirName, "")
  37. if err != nil {
  38. t.Fatal(err)
  39. }
  40. if err := compareTrees(testTree, verifyTree); err != nil {
  41. t.Fatal(err)
  42. }
  43. // test 2-deep new directories--both should be owned by the uid/gid pair
  44. if err := MkdirAllAs(filepath.Join(dirName, "lib", "some", "other"), 0755, 101, 101); err != nil {
  45. t.Fatal(err)
  46. }
  47. testTree["lib/some"] = node{101, 101}
  48. testTree["lib/some/other"] = node{101, 101}
  49. verifyTree, err = readTree(dirName, "")
  50. if err != nil {
  51. t.Fatal(err)
  52. }
  53. if err := compareTrees(testTree, verifyTree); err != nil {
  54. t.Fatal(err)
  55. }
  56. // test a directory that already exists; should be chowned, but nothing else
  57. if err := MkdirAllAs(filepath.Join(dirName, "usr"), 0755, 102, 102); err != nil {
  58. t.Fatal(err)
  59. }
  60. testTree["usr"] = node{102, 102}
  61. verifyTree, err = readTree(dirName, "")
  62. if err != nil {
  63. t.Fatal(err)
  64. }
  65. if err := compareTrees(testTree, verifyTree); err != nil {
  66. t.Fatal(err)
  67. }
  68. }
  69. func TestMkdirAllNewAs(t *testing.T) {
  70. dirName, err := ioutil.TempDir("", "mkdirnew")
  71. if err != nil {
  72. t.Fatalf("Couldn't create temp dir: %v", err)
  73. }
  74. defer os.RemoveAll(dirName)
  75. testTree := map[string]node{
  76. "usr": {0, 0},
  77. "usr/bin": {0, 0},
  78. "lib": {33, 33},
  79. "lib/x86_64": {45, 45},
  80. "lib/x86_64/share": {1, 1},
  81. }
  82. if err := buildTree(dirName, testTree); err != nil {
  83. t.Fatal(err)
  84. }
  85. // test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
  86. if err := MkdirAllNewAs(filepath.Join(dirName, "usr", "share"), 0755, 99, 99); err != nil {
  87. t.Fatal(err)
  88. }
  89. testTree["usr/share"] = node{99, 99}
  90. verifyTree, err := readTree(dirName, "")
  91. if err != nil {
  92. t.Fatal(err)
  93. }
  94. if err := compareTrees(testTree, verifyTree); err != nil {
  95. t.Fatal(err)
  96. }
  97. // test 2-deep new directories--both should be owned by the uid/gid pair
  98. if err := MkdirAllNewAs(filepath.Join(dirName, "lib", "some", "other"), 0755, 101, 101); err != nil {
  99. t.Fatal(err)
  100. }
  101. testTree["lib/some"] = node{101, 101}
  102. testTree["lib/some/other"] = node{101, 101}
  103. verifyTree, err = readTree(dirName, "")
  104. if err != nil {
  105. t.Fatal(err)
  106. }
  107. if err := compareTrees(testTree, verifyTree); err != nil {
  108. t.Fatal(err)
  109. }
  110. // test a directory that already exists; should NOT be chowned
  111. if err := MkdirAllNewAs(filepath.Join(dirName, "usr"), 0755, 102, 102); err != nil {
  112. t.Fatal(err)
  113. }
  114. verifyTree, err = readTree(dirName, "")
  115. if err != nil {
  116. t.Fatal(err)
  117. }
  118. if err := compareTrees(testTree, verifyTree); err != nil {
  119. t.Fatal(err)
  120. }
  121. }
  122. func TestMkdirAs(t *testing.T) {
  123. dirName, err := ioutil.TempDir("", "mkdir")
  124. if err != nil {
  125. t.Fatalf("Couldn't create temp dir: %v", err)
  126. }
  127. defer os.RemoveAll(dirName)
  128. testTree := map[string]node{
  129. "usr": {0, 0},
  130. }
  131. if err := buildTree(dirName, testTree); err != nil {
  132. t.Fatal(err)
  133. }
  134. // test a directory that already exists; should just chown to the requested uid/gid
  135. if err := MkdirAs(filepath.Join(dirName, "usr"), 0755, 99, 99); err != nil {
  136. t.Fatal(err)
  137. }
  138. testTree["usr"] = node{99, 99}
  139. verifyTree, err := readTree(dirName, "")
  140. if err != nil {
  141. t.Fatal(err)
  142. }
  143. if err := compareTrees(testTree, verifyTree); err != nil {
  144. t.Fatal(err)
  145. }
  146. // create a subdir under a dir which doesn't exist--should fail
  147. if err := MkdirAs(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, 102, 102); err == nil {
  148. t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed")
  149. }
  150. // create a subdir under an existing dir; should only change the ownership of the new subdir
  151. if err := MkdirAs(filepath.Join(dirName, "usr", "bin"), 0755, 102, 102); err != nil {
  152. t.Fatal(err)
  153. }
  154. testTree["usr/bin"] = node{102, 102}
  155. verifyTree, err = readTree(dirName, "")
  156. if err != nil {
  157. t.Fatal(err)
  158. }
  159. if err := compareTrees(testTree, verifyTree); err != nil {
  160. t.Fatal(err)
  161. }
  162. }
  163. func buildTree(base string, tree map[string]node) error {
  164. for path, node := range tree {
  165. fullPath := filepath.Join(base, path)
  166. if err := os.MkdirAll(fullPath, 0755); err != nil {
  167. return fmt.Errorf("Couldn't create path: %s; error: %v", fullPath, err)
  168. }
  169. if err := os.Chown(fullPath, node.uid, node.gid); err != nil {
  170. return fmt.Errorf("Couldn't chown path: %s; error: %v", fullPath, err)
  171. }
  172. }
  173. return nil
  174. }
  175. func readTree(base, root string) (map[string]node, error) {
  176. tree := make(map[string]node)
  177. dirInfos, err := ioutil.ReadDir(base)
  178. if err != nil {
  179. return nil, fmt.Errorf("Couldn't read directory entries for %q: %v", base, err)
  180. }
  181. for _, info := range dirInfos {
  182. s := &syscall.Stat_t{}
  183. if err := syscall.Stat(filepath.Join(base, info.Name()), s); err != nil {
  184. return nil, fmt.Errorf("Can't stat file %q: %v", filepath.Join(base, info.Name()), err)
  185. }
  186. tree[filepath.Join(root, info.Name())] = node{int(s.Uid), int(s.Gid)}
  187. if info.IsDir() {
  188. // read the subdirectory
  189. subtree, err := readTree(filepath.Join(base, info.Name()), filepath.Join(root, info.Name()))
  190. if err != nil {
  191. return nil, err
  192. }
  193. for path, nodeinfo := range subtree {
  194. tree[path] = nodeinfo
  195. }
  196. }
  197. }
  198. return tree, nil
  199. }
  200. func compareTrees(left, right map[string]node) error {
  201. if len(left) != len(right) {
  202. return fmt.Errorf("Trees aren't the same size")
  203. }
  204. for path, nodeLeft := range left {
  205. if nodeRight, ok := right[path]; ok {
  206. if nodeRight.uid != nodeLeft.uid || nodeRight.gid != nodeLeft.gid {
  207. // mismatch
  208. return fmt.Errorf("mismatched ownership for %q: expected: %d:%d, got: %d:%d", path,
  209. nodeLeft.uid, nodeLeft.gid, nodeRight.uid, nodeRight.gid)
  210. }
  211. continue
  212. }
  213. return fmt.Errorf("right tree didn't contain path %q", path)
  214. }
  215. return nil
  216. }
  217. func TestParseSubidFileWithNewlinesAndComments(t *testing.T) {
  218. tmpDir, err := ioutil.TempDir("", "parsesubid")
  219. if err != nil {
  220. t.Fatal(err)
  221. }
  222. fnamePath := filepath.Join(tmpDir, "testsubuid")
  223. fcontent := `tss:100000:65536
  224. # empty default subuid/subgid file
  225. dockremap:231072:65536`
  226. if err := ioutil.WriteFile(fnamePath, []byte(fcontent), 0644); err != nil {
  227. t.Fatal(err)
  228. }
  229. ranges, err := parseSubidFile(fnamePath, "dockremap")
  230. if err != nil {
  231. t.Fatal(err)
  232. }
  233. if len(ranges) != 1 {
  234. t.Fatalf("wanted 1 element in ranges, got %d instead", len(ranges))
  235. }
  236. if ranges[0].Start != 231072 {
  237. t.Fatalf("wanted 231072, got %d instead", ranges[0].Start)
  238. }
  239. if ranges[0].Length != 65536 {
  240. t.Fatalf("wanted 65536, got %d instead", ranges[0].Length)
  241. }
  242. }