filesystem_test.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Copyright (C) 2017 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package fs
  7. import (
  8. "path/filepath"
  9. "testing"
  10. "github.com/syncthing/syncthing/lib/build"
  11. )
  12. func TestIsInternal(t *testing.T) {
  13. cases := []struct {
  14. file string
  15. internal bool
  16. }{
  17. {".stfolder", true},
  18. {".stignore", true},
  19. {".stversions", true},
  20. {".stfolder/foo", true},
  21. {".stignore/foo", true},
  22. {".stversions/foo", true},
  23. {".stfolderfoo", false},
  24. {".stignorefoo", false},
  25. {".stversionsfoo", false},
  26. {"foo.stfolder", false},
  27. {"foo.stignore", false},
  28. {"foo.stversions", false},
  29. {"foo/.stfolder", false},
  30. {"foo/.stignore", false},
  31. {"foo/.stversions", false},
  32. }
  33. for _, tc := range cases {
  34. res := IsInternal(filepath.FromSlash(tc.file))
  35. if res != tc.internal {
  36. t.Errorf("Unexpected result: IsInteral(%q): %v should be %v", tc.file, res, tc.internal)
  37. }
  38. }
  39. }
  40. func TestCanonicalize(t *testing.T) {
  41. type testcase struct {
  42. path string
  43. expected string
  44. ok bool
  45. }
  46. cases := []testcase{
  47. // Valid cases
  48. {"/bar", "bar", true},
  49. {"/bar/baz", "bar/baz", true},
  50. {"bar", "bar", true},
  51. {"bar/baz", "bar/baz", true},
  52. // Not escape attempts, but oddly formatted relative paths
  53. {"", ".", true},
  54. {"/", ".", true},
  55. {"/..", ".", true},
  56. {"./bar", "bar", true},
  57. {"./bar/baz", "bar/baz", true},
  58. {"bar/../baz", "baz", true},
  59. {"/bar/../baz", "baz", true},
  60. {"./bar/../baz", "baz", true},
  61. // Results in an allowed path, but does it by probing. Disallowed.
  62. {"../foo", "", false},
  63. {"../foo/bar", "", false},
  64. {"../foo/bar", "", false},
  65. {"../../baz/foo/bar", "", false},
  66. {"bar/../../foo/bar", "", false},
  67. {"bar/../../../baz/foo/bar", "", false},
  68. // Escape attempts.
  69. {"..", "", false},
  70. {"../", "", false},
  71. {"../bar", "", false},
  72. {"../foobar", "", false},
  73. {"bar/../../quux/baz", "", false},
  74. }
  75. for _, tc := range cases {
  76. res, err := Canonicalize(tc.path)
  77. if tc.ok {
  78. if err != nil {
  79. t.Errorf("Unexpected error for Canonicalize(%q): %v", tc.path, err)
  80. continue
  81. }
  82. exp := filepath.FromSlash(tc.expected)
  83. if res != exp {
  84. t.Errorf("Unexpected result for Canonicalize(%q): %q != expected %q", tc.path, res, exp)
  85. }
  86. } else if err == nil {
  87. t.Errorf("Unexpected pass for Canonicalize(%q) => %q", tc.path, res)
  88. continue
  89. }
  90. }
  91. }
  92. func TestFileModeString(t *testing.T) {
  93. var fm FileMode = 0777
  94. exp := "-rwxrwxrwx"
  95. if fm.String() != exp {
  96. t.Fatalf("Got %v, expected %v", fm.String(), exp)
  97. }
  98. }
  99. func TestIsParent(t *testing.T) {
  100. test := func(path, parent string, expected bool) {
  101. t.Helper()
  102. path = filepath.FromSlash(path)
  103. parent = filepath.FromSlash(parent)
  104. if res := IsParent(path, parent); res != expected {
  105. t.Errorf(`Unexpected result: IsParent("%v", "%v"): %v should be %v`, path, parent, res, expected)
  106. }
  107. }
  108. testBoth := func(path, parent string, expected bool) {
  109. t.Helper()
  110. test(path, parent, expected)
  111. if build.IsWindows {
  112. test("C:/"+path, "C:/"+parent, expected)
  113. } else {
  114. test("/"+path, "/"+parent, expected)
  115. }
  116. }
  117. // rel - abs
  118. for _, parent := range []string{"/", "/foo", "/foo/bar"} {
  119. for _, path := range []string{"", ".", "foo", "foo/bar", "bas", "bas/baz"} {
  120. if build.IsWindows {
  121. parent = "C:/" + parent
  122. }
  123. test(parent, path, false)
  124. test(path, parent, false)
  125. }
  126. }
  127. // equal
  128. for i, path := range []string{"/", "/foo", "/foo/bar", "", ".", "foo", "foo/bar"} {
  129. if i < 3 && build.IsWindows {
  130. path = "C:" + path
  131. }
  132. test(path, path, false)
  133. }
  134. test("", ".", false)
  135. test(".", "", false)
  136. for _, parent := range []string{"", "."} {
  137. for _, path := range []string{"foo", "foo/bar"} {
  138. test(path, parent, true)
  139. test(parent, path, false)
  140. }
  141. }
  142. for _, parent := range []string{"foo", "foo/bar"} {
  143. for _, path := range []string{"bar", "bar/foo"} {
  144. testBoth(path, parent, false)
  145. testBoth(parent, path, false)
  146. }
  147. }
  148. for _, parent := range []string{"foo", "foo/bar"} {
  149. for _, path := range []string{"foo/bar/baz", "foo/bar/baz/bas"} {
  150. testBoth(path, parent, true)
  151. testBoth(parent, path, false)
  152. if build.IsWindows {
  153. test("C:/"+path, "D:/"+parent, false)
  154. }
  155. }
  156. }
  157. }