connection_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. // Copyright (C) 2019-2022 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package common
  15. import (
  16. "errors"
  17. "os"
  18. "path"
  19. "path/filepath"
  20. "runtime"
  21. "testing"
  22. "time"
  23. "github.com/pkg/sftp"
  24. "github.com/rs/xid"
  25. "github.com/sftpgo/sdk"
  26. "github.com/stretchr/testify/assert"
  27. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  28. "github.com/drakkan/sftpgo/v2/internal/kms"
  29. "github.com/drakkan/sftpgo/v2/internal/util"
  30. "github.com/drakkan/sftpgo/v2/internal/vfs"
  31. )
  32. var (
  33. errWalkDir = errors.New("err walk dir")
  34. errWalkFile = errors.New("err walk file")
  35. )
  36. // MockOsFs mockable OsFs
  37. type MockOsFs struct {
  38. vfs.Fs
  39. hasVirtualFolders bool
  40. name string
  41. err error
  42. }
  43. // Name returns the name for the Fs implementation
  44. func (fs *MockOsFs) Name() string {
  45. if fs.name != "" {
  46. return fs.name
  47. }
  48. return "mockOsFs"
  49. }
  50. // HasVirtualFolders returns true if folders are emulated
  51. func (fs *MockOsFs) HasVirtualFolders() bool {
  52. return fs.hasVirtualFolders
  53. }
  54. func (fs *MockOsFs) IsUploadResumeSupported() bool {
  55. return !fs.hasVirtualFolders
  56. }
  57. func (fs *MockOsFs) Chtimes(name string, atime, mtime time.Time, isUploading bool) error {
  58. return vfs.ErrVfsUnsupported
  59. }
  60. // Walk returns a duplicate path for testing
  61. func (fs *MockOsFs) Walk(root string, walkFn filepath.WalkFunc) error {
  62. if fs.err == errWalkDir {
  63. walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
  64. return walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
  65. }
  66. walkFn("fsfpath", vfs.NewFileInfo("fpath", false, 0, time.Now(), false), nil) //nolint:errcheck
  67. return fs.err
  68. }
  69. func newMockOsFs(hasVirtualFolders bool, connectionID, rootDir, name string, err error) vfs.Fs {
  70. return &MockOsFs{
  71. Fs: vfs.NewOsFs(connectionID, rootDir, ""),
  72. name: name,
  73. hasVirtualFolders: hasVirtualFolders,
  74. err: err,
  75. }
  76. }
  77. func TestRemoveErrors(t *testing.T) {
  78. mappedPath := filepath.Join(os.TempDir(), "map")
  79. homePath := filepath.Join(os.TempDir(), "home")
  80. user := dataprovider.User{
  81. BaseUser: sdk.BaseUser{
  82. Username: "remove_errors_user",
  83. HomeDir: homePath,
  84. },
  85. VirtualFolders: []vfs.VirtualFolder{
  86. {
  87. BaseVirtualFolder: vfs.BaseVirtualFolder{
  88. Name: filepath.Base(mappedPath),
  89. MappedPath: mappedPath,
  90. },
  91. VirtualPath: "/virtualpath",
  92. },
  93. },
  94. }
  95. user.Permissions = make(map[string][]string)
  96. user.Permissions["/"] = []string{dataprovider.PermAny}
  97. fs := vfs.NewOsFs("", os.TempDir(), "")
  98. conn := NewBaseConnection("", ProtocolFTP, "", "", user)
  99. err := conn.IsRemoveDirAllowed(fs, mappedPath, "/virtualpath1")
  100. if assert.Error(t, err) {
  101. assert.Contains(t, err.Error(), "permission denied")
  102. }
  103. err = conn.RemoveFile(fs, filepath.Join(homePath, "missing_file"), "/missing_file",
  104. vfs.NewFileInfo("info", false, 100, time.Now(), false))
  105. assert.Error(t, err)
  106. }
  107. func TestSetStatMode(t *testing.T) {
  108. oldSetStatMode := Config.SetstatMode
  109. Config.SetstatMode = 1
  110. fakePath := "fake path"
  111. user := dataprovider.User{
  112. BaseUser: sdk.BaseUser{
  113. HomeDir: os.TempDir(),
  114. },
  115. }
  116. user.Permissions = make(map[string][]string)
  117. user.Permissions["/"] = []string{dataprovider.PermAny}
  118. fs := newMockOsFs(true, "", user.GetHomeDir(), "", nil)
  119. conn := NewBaseConnection("", ProtocolWebDAV, "", "", user)
  120. err := conn.handleChmod(fs, fakePath, fakePath, nil)
  121. assert.NoError(t, err)
  122. err = conn.handleChown(fs, fakePath, fakePath, nil)
  123. assert.NoError(t, err)
  124. err = conn.handleChtimes(fs, fakePath, fakePath, nil)
  125. assert.NoError(t, err)
  126. Config.SetstatMode = 2
  127. err = conn.handleChmod(fs, fakePath, fakePath, nil)
  128. assert.NoError(t, err)
  129. err = conn.handleChtimes(fs, fakePath, fakePath, &StatAttributes{
  130. Atime: time.Now(),
  131. Mtime: time.Now(),
  132. })
  133. assert.NoError(t, err)
  134. Config.SetstatMode = oldSetStatMode
  135. }
  136. func TestRecursiveRenameWalkError(t *testing.T) {
  137. fs := vfs.NewOsFs("", filepath.Clean(os.TempDir()), "")
  138. conn := NewBaseConnection("", ProtocolWebDAV, "", "", dataprovider.User{
  139. BaseUser: sdk.BaseUser{
  140. Permissions: map[string][]string{
  141. "/": {dataprovider.PermListItems, dataprovider.PermUpload,
  142. dataprovider.PermDownload, dataprovider.PermRenameDirs},
  143. },
  144. },
  145. })
  146. err := conn.checkRecursiveRenameDirPermissions(fs, fs, filepath.Join(os.TempDir(), "/source"),
  147. filepath.Join(os.TempDir(), "/target"), "/source", "/target",
  148. vfs.NewFileInfo("source", true, 0, time.Now(), false))
  149. assert.ErrorIs(t, err, os.ErrNotExist)
  150. fs = newMockOsFs(false, "mockID", filepath.Clean(os.TempDir()), "S3Fs", errWalkDir)
  151. err = conn.checkRecursiveRenameDirPermissions(fs, fs, filepath.Join(os.TempDir(), "/source"),
  152. filepath.Join(os.TempDir(), "/target"), "/source", "/target",
  153. vfs.NewFileInfo("source", true, 0, time.Now(), false))
  154. if assert.Error(t, err) {
  155. assert.Equal(t, err.Error(), conn.GetOpUnsupportedError().Error())
  156. }
  157. conn.User.Permissions["/"] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  158. dataprovider.PermDownload, dataprovider.PermRenameFiles}
  159. // no dir rename permission, the quick check path returns permission error without walking
  160. err = conn.checkRecursiveRenameDirPermissions(fs, fs, filepath.Join(os.TempDir(), "/source"),
  161. filepath.Join(os.TempDir(), "/target"), "/source", "/target",
  162. vfs.NewFileInfo("source", true, 0, time.Now(), false))
  163. if assert.Error(t, err) {
  164. assert.EqualError(t, err, conn.GetPermissionDeniedError().Error())
  165. }
  166. }
  167. func TestCrossRenameFsErrors(t *testing.T) {
  168. fs := vfs.NewOsFs("", os.TempDir(), "")
  169. conn := NewBaseConnection("", ProtocolWebDAV, "", "", dataprovider.User{})
  170. res := conn.hasSpaceForCrossRename(fs, vfs.QuotaCheckResult{}, 1, "missingsource")
  171. assert.False(t, res)
  172. if runtime.GOOS != osWindows {
  173. dirPath := filepath.Join(os.TempDir(), "d")
  174. err := os.Mkdir(dirPath, os.ModePerm)
  175. assert.NoError(t, err)
  176. err = os.Chmod(dirPath, 0001)
  177. assert.NoError(t, err)
  178. res = conn.hasSpaceForCrossRename(fs, vfs.QuotaCheckResult{}, 1, dirPath)
  179. assert.False(t, res)
  180. err = os.Chmod(dirPath, os.ModePerm)
  181. assert.NoError(t, err)
  182. err = os.Remove(dirPath)
  183. assert.NoError(t, err)
  184. }
  185. }
  186. func TestRenameVirtualFolders(t *testing.T) {
  187. vdir := "/avdir"
  188. u := dataprovider.User{}
  189. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  190. BaseVirtualFolder: vfs.BaseVirtualFolder{
  191. Name: "name",
  192. MappedPath: "mappedPath",
  193. },
  194. VirtualPath: vdir,
  195. })
  196. fs := vfs.NewOsFs("", os.TempDir(), "")
  197. conn := NewBaseConnection("", ProtocolFTP, "", "", u)
  198. res := conn.isRenamePermitted(fs, fs, "source", "target", vdir, "vdirtarget", nil)
  199. assert.False(t, res)
  200. }
  201. func TestRenamePerms(t *testing.T) {
  202. src := "source"
  203. target := "target"
  204. sub := "/sub"
  205. subTarget := sub + "/target"
  206. u := dataprovider.User{}
  207. u.Permissions = map[string][]string{}
  208. u.Permissions["/"] = []string{dataprovider.PermCreateDirs, dataprovider.PermUpload, dataprovider.PermCreateSymlinks,
  209. dataprovider.PermDeleteFiles}
  210. conn := NewBaseConnection("", ProtocolSFTP, "", "", u)
  211. assert.False(t, conn.hasRenamePerms(src, target, nil))
  212. u.Permissions["/"] = []string{dataprovider.PermRename}
  213. assert.True(t, conn.hasRenamePerms(src, target, nil))
  214. u.Permissions["/"] = []string{dataprovider.PermCreateDirs, dataprovider.PermUpload, dataprovider.PermDeleteFiles,
  215. dataprovider.PermDeleteDirs}
  216. assert.False(t, conn.hasRenamePerms(src, target, nil))
  217. info := vfs.NewFileInfo(src, true, 0, time.Now(), false)
  218. u.Permissions["/"] = []string{dataprovider.PermRenameFiles}
  219. assert.False(t, conn.hasRenamePerms(src, target, info))
  220. u.Permissions["/"] = []string{dataprovider.PermRenameDirs}
  221. assert.True(t, conn.hasRenamePerms(src, target, info))
  222. u.Permissions["/"] = []string{dataprovider.PermRename}
  223. assert.True(t, conn.hasRenamePerms(src, target, info))
  224. u.Permissions["/"] = []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDeleteDirs}
  225. assert.False(t, conn.hasRenamePerms(src, target, info))
  226. // test with different permissions between source and target
  227. u.Permissions["/"] = []string{dataprovider.PermRename}
  228. u.Permissions[sub] = []string{dataprovider.PermRenameFiles}
  229. assert.False(t, conn.hasRenamePerms(src, subTarget, info))
  230. u.Permissions[sub] = []string{dataprovider.PermRenameDirs}
  231. assert.True(t, conn.hasRenamePerms(src, subTarget, info))
  232. // test files
  233. info = vfs.NewFileInfo(src, false, 0, time.Now(), false)
  234. u.Permissions["/"] = []string{dataprovider.PermRenameDirs}
  235. assert.False(t, conn.hasRenamePerms(src, target, info))
  236. u.Permissions["/"] = []string{dataprovider.PermRenameFiles}
  237. assert.True(t, conn.hasRenamePerms(src, target, info))
  238. u.Permissions["/"] = []string{dataprovider.PermRename}
  239. assert.True(t, conn.hasRenamePerms(src, target, info))
  240. // test with different permissions between source and target
  241. u.Permissions["/"] = []string{dataprovider.PermRename}
  242. u.Permissions[sub] = []string{dataprovider.PermRenameDirs}
  243. assert.False(t, conn.hasRenamePerms(src, subTarget, info))
  244. u.Permissions[sub] = []string{dataprovider.PermRenameFiles}
  245. assert.True(t, conn.hasRenamePerms(src, subTarget, info))
  246. }
  247. func TestUpdateQuotaAfterRename(t *testing.T) {
  248. user := dataprovider.User{
  249. BaseUser: sdk.BaseUser{
  250. Username: userTestUsername,
  251. HomeDir: filepath.Join(os.TempDir(), "home"),
  252. },
  253. }
  254. mappedPath := filepath.Join(os.TempDir(), "vdir")
  255. user.Permissions = make(map[string][]string)
  256. user.Permissions["/"] = []string{dataprovider.PermAny}
  257. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  258. BaseVirtualFolder: vfs.BaseVirtualFolder{
  259. MappedPath: mappedPath,
  260. },
  261. VirtualPath: "/vdir",
  262. QuotaFiles: -1,
  263. QuotaSize: -1,
  264. })
  265. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  266. BaseVirtualFolder: vfs.BaseVirtualFolder{
  267. MappedPath: mappedPath,
  268. },
  269. VirtualPath: "/vdir1",
  270. QuotaFiles: -1,
  271. QuotaSize: -1,
  272. })
  273. err := os.MkdirAll(user.GetHomeDir(), os.ModePerm)
  274. assert.NoError(t, err)
  275. err = os.MkdirAll(mappedPath, os.ModePerm)
  276. assert.NoError(t, err)
  277. fs, err := user.GetFilesystem("id")
  278. assert.NoError(t, err)
  279. c := NewBaseConnection("", ProtocolSFTP, "", "", user)
  280. request := sftp.NewRequest("Rename", "/testfile")
  281. if runtime.GOOS != osWindows {
  282. request.Filepath = "/dir"
  283. request.Target = path.Join("/vdir", "dir")
  284. testDirPath := filepath.Join(mappedPath, "dir")
  285. err := os.MkdirAll(testDirPath, os.ModePerm)
  286. assert.NoError(t, err)
  287. err = os.Chmod(testDirPath, 0001)
  288. assert.NoError(t, err)
  289. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, testDirPath, 0)
  290. assert.Error(t, err)
  291. err = os.Chmod(testDirPath, os.ModePerm)
  292. assert.NoError(t, err)
  293. }
  294. testFile1 := "/testfile1"
  295. request.Target = testFile1
  296. request.Filepath = path.Join("/vdir", "file")
  297. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 0)
  298. assert.Error(t, err)
  299. err = os.WriteFile(filepath.Join(mappedPath, "file"), []byte("test content"), os.ModePerm)
  300. assert.NoError(t, err)
  301. request.Filepath = testFile1
  302. request.Target = path.Join("/vdir", "file")
  303. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 12)
  304. assert.NoError(t, err)
  305. err = os.WriteFile(filepath.Join(user.GetHomeDir(), "testfile1"), []byte("test content"), os.ModePerm)
  306. assert.NoError(t, err)
  307. request.Target = testFile1
  308. request.Filepath = path.Join("/vdir", "file")
  309. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 12)
  310. assert.NoError(t, err)
  311. request.Target = path.Join("/vdir1", "file")
  312. request.Filepath = path.Join("/vdir", "file")
  313. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 12)
  314. assert.NoError(t, err)
  315. err = os.RemoveAll(mappedPath)
  316. assert.NoError(t, err)
  317. err = os.RemoveAll(user.GetHomeDir())
  318. assert.NoError(t, err)
  319. }
  320. func TestErrorsMapping(t *testing.T) {
  321. fs := vfs.NewOsFs("", os.TempDir(), "")
  322. conn := NewBaseConnection("", ProtocolSFTP, "", "", dataprovider.User{BaseUser: sdk.BaseUser{HomeDir: os.TempDir()}})
  323. osErrorsProtocols := []string{ProtocolWebDAV, ProtocolFTP, ProtocolHTTP, ProtocolHTTPShare,
  324. ProtocolDataRetention, ProtocolOIDC, protocolEventAction}
  325. for _, protocol := range supportedProtocols {
  326. conn.SetProtocol(protocol)
  327. err := conn.GetFsError(fs, os.ErrNotExist)
  328. if protocol == ProtocolSFTP {
  329. assert.ErrorIs(t, err, sftp.ErrSSHFxNoSuchFile)
  330. } else if util.Contains(osErrorsProtocols, protocol) {
  331. assert.EqualError(t, err, os.ErrNotExist.Error())
  332. } else {
  333. assert.EqualError(t, err, ErrNotExist.Error())
  334. }
  335. err = conn.GetFsError(fs, os.ErrPermission)
  336. if protocol == ProtocolSFTP {
  337. assert.EqualError(t, err, sftp.ErrSSHFxPermissionDenied.Error())
  338. } else {
  339. assert.EqualError(t, err, ErrPermissionDenied.Error())
  340. }
  341. err = conn.GetFsError(fs, os.ErrClosed)
  342. if protocol == ProtocolSFTP {
  343. assert.ErrorIs(t, err, sftp.ErrSSHFxFailure)
  344. } else {
  345. assert.EqualError(t, err, ErrGenericFailure.Error())
  346. }
  347. err = conn.GetFsError(fs, ErrPermissionDenied)
  348. if protocol == ProtocolSFTP {
  349. assert.ErrorIs(t, err, sftp.ErrSSHFxFailure)
  350. } else {
  351. assert.EqualError(t, err, ErrPermissionDenied.Error())
  352. }
  353. err = conn.GetFsError(fs, vfs.ErrVfsUnsupported)
  354. if protocol == ProtocolSFTP {
  355. assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
  356. } else {
  357. assert.EqualError(t, err, ErrOpUnsupported.Error())
  358. }
  359. err = conn.GetFsError(fs, vfs.ErrStorageSizeUnavailable)
  360. if protocol == ProtocolSFTP {
  361. assert.ErrorIs(t, err, sftp.ErrSSHFxOpUnsupported)
  362. assert.Contains(t, err.Error(), vfs.ErrStorageSizeUnavailable.Error())
  363. } else {
  364. assert.EqualError(t, err, vfs.ErrStorageSizeUnavailable.Error())
  365. }
  366. err = conn.GetQuotaExceededError()
  367. assert.True(t, conn.IsQuotaExceededError(err))
  368. err = conn.GetReadQuotaExceededError()
  369. if protocol == ProtocolSFTP {
  370. assert.ErrorIs(t, err, sftp.ErrSSHFxFailure)
  371. assert.Contains(t, err.Error(), ErrReadQuotaExceeded.Error())
  372. } else {
  373. assert.ErrorIs(t, err, ErrReadQuotaExceeded)
  374. }
  375. err = conn.GetNotExistError()
  376. assert.True(t, conn.IsNotExistError(err))
  377. err = conn.GetFsError(fs, nil)
  378. assert.NoError(t, err)
  379. err = conn.GetOpUnsupportedError()
  380. if protocol == ProtocolSFTP {
  381. assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
  382. } else {
  383. assert.EqualError(t, err, ErrOpUnsupported.Error())
  384. }
  385. err = conn.GetFsError(fs, ErrShuttingDown)
  386. if protocol == ProtocolSFTP {
  387. assert.ErrorIs(t, err, sftp.ErrSSHFxFailure)
  388. assert.Contains(t, err.Error(), ErrShuttingDown.Error())
  389. } else {
  390. assert.EqualError(t, err, ErrShuttingDown.Error())
  391. }
  392. }
  393. }
  394. func TestMaxWriteSize(t *testing.T) {
  395. permissions := make(map[string][]string)
  396. permissions["/"] = []string{dataprovider.PermAny}
  397. user := dataprovider.User{
  398. BaseUser: sdk.BaseUser{
  399. Username: userTestUsername,
  400. Permissions: permissions,
  401. HomeDir: filepath.Clean(os.TempDir()),
  402. },
  403. }
  404. fs, err := user.GetFilesystem("123")
  405. assert.NoError(t, err)
  406. conn := NewBaseConnection("", ProtocolFTP, "", "", user)
  407. quotaResult := vfs.QuotaCheckResult{
  408. HasSpace: true,
  409. }
  410. size, err := conn.GetMaxWriteSize(quotaResult, false, 0, fs.IsUploadResumeSupported())
  411. assert.NoError(t, err)
  412. assert.Equal(t, int64(0), size)
  413. conn.User.Filters.MaxUploadFileSize = 100
  414. size, err = conn.GetMaxWriteSize(quotaResult, false, 0, fs.IsUploadResumeSupported())
  415. assert.NoError(t, err)
  416. assert.Equal(t, int64(100), size)
  417. quotaResult.QuotaSize = 1000
  418. size, err = conn.GetMaxWriteSize(quotaResult, false, 50, fs.IsUploadResumeSupported())
  419. assert.NoError(t, err)
  420. assert.Equal(t, int64(100), size)
  421. quotaResult.QuotaSize = 1000
  422. quotaResult.UsedSize = 990
  423. size, err = conn.GetMaxWriteSize(quotaResult, false, 50, fs.IsUploadResumeSupported())
  424. assert.NoError(t, err)
  425. assert.Equal(t, int64(60), size)
  426. quotaResult.QuotaSize = 0
  427. quotaResult.UsedSize = 0
  428. size, err = conn.GetMaxWriteSize(quotaResult, true, 100, fs.IsUploadResumeSupported())
  429. assert.True(t, conn.IsQuotaExceededError(err))
  430. assert.Equal(t, int64(0), size)
  431. size, err = conn.GetMaxWriteSize(quotaResult, true, 10, fs.IsUploadResumeSupported())
  432. assert.NoError(t, err)
  433. assert.Equal(t, int64(90), size)
  434. fs = newMockOsFs(true, fs.ConnectionID(), user.GetHomeDir(), "", nil)
  435. size, err = conn.GetMaxWriteSize(quotaResult, true, 100, fs.IsUploadResumeSupported())
  436. assert.EqualError(t, err, ErrOpUnsupported.Error())
  437. assert.Equal(t, int64(0), size)
  438. }
  439. func TestCheckParentDirsErrors(t *testing.T) {
  440. permissions := make(map[string][]string)
  441. permissions["/"] = []string{dataprovider.PermAny}
  442. user := dataprovider.User{
  443. BaseUser: sdk.BaseUser{
  444. Username: userTestUsername,
  445. Permissions: permissions,
  446. HomeDir: filepath.Clean(os.TempDir()),
  447. },
  448. FsConfig: vfs.Filesystem{
  449. Provider: sdk.CryptedFilesystemProvider,
  450. },
  451. }
  452. c := NewBaseConnection(xid.New().String(), ProtocolSFTP, "", "", user)
  453. err := c.CheckParentDirs("/a/dir")
  454. assert.Error(t, err)
  455. user.FsConfig.Provider = sdk.LocalFilesystemProvider
  456. user.VirtualFolders = nil
  457. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  458. BaseVirtualFolder: vfs.BaseVirtualFolder{
  459. FsConfig: vfs.Filesystem{
  460. Provider: sdk.CryptedFilesystemProvider,
  461. },
  462. },
  463. VirtualPath: "/vdir",
  464. })
  465. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  466. BaseVirtualFolder: vfs.BaseVirtualFolder{
  467. MappedPath: filepath.Clean(os.TempDir()),
  468. },
  469. VirtualPath: "/vdir/sub",
  470. })
  471. c = NewBaseConnection(xid.New().String(), ProtocolSFTP, "", "", user)
  472. err = c.CheckParentDirs("/vdir/sub/dir")
  473. assert.Error(t, err)
  474. user = dataprovider.User{
  475. BaseUser: sdk.BaseUser{
  476. Username: userTestUsername,
  477. Permissions: permissions,
  478. HomeDir: filepath.Clean(os.TempDir()),
  479. },
  480. FsConfig: vfs.Filesystem{
  481. Provider: sdk.S3FilesystemProvider,
  482. S3Config: vfs.S3FsConfig{
  483. BaseS3FsConfig: sdk.BaseS3FsConfig{
  484. Bucket: "buck",
  485. Region: "us-east-1",
  486. AccessKey: "key",
  487. },
  488. AccessSecret: kms.NewPlainSecret("s3secret"),
  489. },
  490. },
  491. }
  492. c = NewBaseConnection(xid.New().String(), ProtocolSFTP, "", "", user)
  493. err = c.CheckParentDirs("/a/dir")
  494. assert.NoError(t, err)
  495. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  496. BaseVirtualFolder: vfs.BaseVirtualFolder{
  497. MappedPath: filepath.Clean(os.TempDir()),
  498. },
  499. VirtualPath: "/local/dir",
  500. })
  501. c = NewBaseConnection(xid.New().String(), ProtocolSFTP, "", "", user)
  502. err = c.CheckParentDirs("/local/dir/sub-dir")
  503. assert.NoError(t, err)
  504. err = os.RemoveAll(filepath.Join(os.TempDir(), "sub-dir"))
  505. assert.NoError(t, err)
  506. }
  507. func TestRemoveDirTree(t *testing.T) {
  508. user := dataprovider.User{
  509. BaseUser: sdk.BaseUser{
  510. HomeDir: filepath.Clean(os.TempDir()),
  511. },
  512. }
  513. user.Permissions = make(map[string][]string)
  514. user.Permissions["/"] = []string{dataprovider.PermAny}
  515. fs := vfs.NewOsFs("connID", user.HomeDir, "")
  516. connection := NewBaseConnection(fs.ConnectionID(), ProtocolWebDAV, "", "", user)
  517. vpath := path.Join("adir", "missing")
  518. p := filepath.Join(user.HomeDir, "adir", "missing")
  519. err := connection.removeDirTree(fs, p, vpath)
  520. if assert.Error(t, err) {
  521. assert.True(t, fs.IsNotExist(err))
  522. }
  523. fs = newMockOsFs(false, "mockID", user.HomeDir, "", nil)
  524. err = connection.removeDirTree(fs, p, vpath)
  525. if assert.Error(t, err) {
  526. assert.True(t, fs.IsNotExist(err), "unexpected error: %v", err)
  527. }
  528. errFake := errors.New("fake err")
  529. fs = newMockOsFs(false, "mockID", user.HomeDir, "", errFake)
  530. err = connection.removeDirTree(fs, p, vpath)
  531. if assert.Error(t, err) {
  532. assert.EqualError(t, err, ErrGenericFailure.Error())
  533. }
  534. fs = newMockOsFs(true, "mockID", user.HomeDir, "", errWalkDir)
  535. err = connection.removeDirTree(fs, p, vpath)
  536. if assert.Error(t, err) {
  537. assert.True(t, fs.IsPermission(err), "unexpected error: %v", err)
  538. }
  539. fs = newMockOsFs(false, "mockID", user.HomeDir, "", errWalkFile)
  540. err = connection.removeDirTree(fs, p, vpath)
  541. if assert.Error(t, err) {
  542. assert.EqualError(t, err, ErrGenericFailure.Error())
  543. }
  544. connection.User.Permissions["/"] = []string{dataprovider.PermListItems}
  545. fs = newMockOsFs(false, "mockID", user.HomeDir, "", nil)
  546. err = connection.removeDirTree(fs, p, vpath)
  547. if assert.Error(t, err) {
  548. assert.EqualError(t, err, ErrPermissionDenied.Error())
  549. }
  550. }
  551. func TestOrderDirsToRemove(t *testing.T) {
  552. fs := vfs.NewOsFs("id", os.TempDir(), "")
  553. dirsToRemove := []objectToRemoveMapping{}
  554. orderedDirs := orderDirsToRemove(fs, dirsToRemove)
  555. assert.Equal(t, len(dirsToRemove), len(orderedDirs))
  556. dirsToRemove = []objectToRemoveMapping{
  557. {
  558. fsPath: "dir1",
  559. virtualPath: "",
  560. },
  561. }
  562. orderedDirs = orderDirsToRemove(fs, dirsToRemove)
  563. assert.Equal(t, len(dirsToRemove), len(orderedDirs))
  564. dirsToRemove = []objectToRemoveMapping{
  565. {
  566. fsPath: "dir1",
  567. virtualPath: "",
  568. },
  569. {
  570. fsPath: "dir12",
  571. virtualPath: "",
  572. },
  573. {
  574. fsPath: filepath.Join("dir1", "a", "b"),
  575. virtualPath: "",
  576. },
  577. {
  578. fsPath: filepath.Join("dir1", "a"),
  579. virtualPath: "",
  580. },
  581. }
  582. orderedDirs = orderDirsToRemove(fs, dirsToRemove)
  583. if assert.Equal(t, len(dirsToRemove), len(orderedDirs)) {
  584. assert.Equal(t, "dir12", orderedDirs[0].fsPath)
  585. assert.Equal(t, filepath.Join("dir1", "a", "b"), orderedDirs[1].fsPath)
  586. assert.Equal(t, filepath.Join("dir1", "a"), orderedDirs[2].fsPath)
  587. assert.Equal(t, "dir1", orderedDirs[3].fsPath)
  588. }
  589. }