Skip to content

Commit 095e14b

Browse files
author
Matt Allen
committed
Initial commit, lifted from CeePee
1 parent a0c040a commit 095e14b

8 files changed

+261
-0
lines changed

fileinfo.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package fs
2+
3+
import "fmt"
4+
5+
type FileList struct {
6+
path string
7+
files []string
8+
}
9+
10+
type FileInfo struct {
11+
FileName string `json:"file_name"`
12+
Folder string `json:"folder"`
13+
FullPath string `json:"full_path"`
14+
Size uint64 `json:"file_size"`
15+
}
16+
17+
func ScanDirectory(path string) FileList {
18+
return FileList{path, listFolder(path)}
19+
}
20+
21+
func (f *FileList) GetList() []string {
22+
return f.files
23+
}
24+
25+
func (f *FileList) Enrich(lock *FileMove) []FileInfo {
26+
enrd := []FileInfo{}
27+
for _, i := range f.files {
28+
fullPath := f.prefixPath(i)
29+
if lock.IsLocked(fullPath) {
30+
continue
31+
}
32+
size, err := fileSize(fullPath)
33+
if err != nil {
34+
size = 0
35+
}
36+
enrd = append(enrd, FileInfo{
37+
getFileNameFromPath(i),
38+
getFolderFromPath(i),
39+
fullPath,
40+
size,
41+
})
42+
}
43+
return enrd
44+
}
45+
46+
func (f *FileList) prefixPath(p string) string {
47+
return fmt.Sprintf("%s/%s", f.path, p)
48+
}

folders.go

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package fs
2+
3+
import (
4+
"io"
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
)
9+
10+
func getFolderFromPath(p string) string {
11+
split := strings.Split(p, "/")
12+
return strings.Join(split[:len(split)-1], "/")
13+
}
14+
15+
func getFileNameFromPath(p string) string {
16+
split := strings.Split(p, "/")
17+
return strings.Join(split[len(split)-1:], "/")
18+
}
19+
20+
// List folders within a given directory
21+
func listFolder(f string) []string {
22+
all := []string{}
23+
_ = filepath.Walk(f, func(path string, info os.FileInfo, err error) error {
24+
if err == nil {
25+
if !info.IsDir() {
26+
all = append(all, substring(path, len(f)+1))
27+
}
28+
}
29+
return err
30+
})
31+
return all
32+
}
33+
34+
func substring(s string, i int) string {
35+
r := []rune(s)
36+
return string(r[i:len(r)])
37+
}
38+
39+
// Move a file from one location to another
40+
func moveFile(s, d string) error {
41+
// Firstly, try renaming it. This will fail if the files are on different partitions.
42+
err := os.Rename(s, d)
43+
// If that fails then we need to make a copy of the file, then delete the existing one.
44+
if err != nil {
45+
// When copying, it could take a very long time!
46+
in, err := os.Open(s)
47+
if err != nil {
48+
return err
49+
}
50+
defer in.Close()
51+
out, err := os.Create(d)
52+
if err != nil {
53+
return err
54+
}
55+
defer func() {
56+
cerr := out.Close()
57+
if err == nil {
58+
err = cerr
59+
}
60+
}()
61+
if _, err = io.Copy(out, in); err != nil {
62+
return err
63+
}
64+
err = out.Sync()
65+
// And then delete the existing file
66+
return deleteFile(s)
67+
}
68+
return err
69+
}
70+
71+
func deleteFile(p string) error {
72+
return os.Remove(p)
73+
}
74+
75+
func fileSize(p string) (uint64, error) {
76+
in, err := os.Open(p)
77+
if err != nil {
78+
return 0, err
79+
}
80+
fi, err := in.Stat()
81+
if err != nil {
82+
return 0, err
83+
}
84+
return uint64(fi.Size()), err
85+
}

folders_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package fs
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestListDirectory(t *testing.T) {
10+
dir := listFolder("tests")
11+
assert.Equal(t, 2, len(dir))
12+
assert.Contains(t, dir, "file.txt")
13+
assert.Contains(t, dir, "subfolder/subfile.txt")
14+
}

lock.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package fs
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"github.com/minio/minio/pkg/disk"
7+
"log"
8+
)
9+
10+
type FileMove struct {
11+
locks map[string]uint64
12+
}
13+
14+
func CreateNewLock() *FileMove {
15+
return &FileMove{make(map[string]uint64)}
16+
}
17+
18+
func (f *FileMove) Move(from, to string) {
19+
size, err := fileSize(from)
20+
if err != nil {
21+
f.locks[from] = 0
22+
} else {
23+
f.locks[from] = size
24+
}
25+
_ = moveFile(from, to)
26+
delete(f.locks, from)
27+
log.Println(fmt.Sprintf("Moving of %s is complete", from))
28+
}
29+
30+
func (f *FileMove) IsLocked(p string) bool {
31+
_, exists := f.locks[p]
32+
return exists
33+
}
34+
35+
func (f *FileMove) CanMove(from, to string) error {
36+
log.Println(fmt.Sprintf("Requesting to move %s to %s", from, to))
37+
if !isValidFolderPath(from) {
38+
return errors.New("the source is not a valid file path")
39+
}
40+
if !isValidFolderPath(to) {
41+
return errors.New("the destination is not a valid file path")
42+
}
43+
if f.IsLocked(from) {
44+
return errors.New("this file is already being moved and cannot be changed")
45+
}
46+
size, sErr := fileSize(from)
47+
if sErr != nil {
48+
return sErr
49+
}
50+
log.Println("Checking remaining space at "+getFolderFromPath(to))
51+
left, lErr := remainingSpace(getFolderFromPath(to))
52+
if lErr != nil {
53+
return lErr
54+
}
55+
log.Println(fmt.Sprintf("File size: %d, remaining: %d", size, left))
56+
if size > left {
57+
return errors.New("not enough space at the destination to move this file")
58+
}
59+
// TODO Also check write permissions in destination directory
60+
return nil
61+
}
62+
63+
func (f *FileMove) CanDelete(from string) bool {
64+
return isValidFolderPath(from) && !f.IsLocked(from)
65+
}
66+
67+
func (f *FileMove) Delete(from string) error {
68+
return deleteFile(from)
69+
}
70+
71+
func remainingSpace(p string) (uint64, error) {
72+
di, err := disk.GetInfo(p)
73+
if err != nil {
74+
return 0, err
75+
}
76+
return di.Free, err
77+
}

tests/file.txt

Whitespace-only changes.

tests/subfolder/subfile.txt

Whitespace-only changes.

validate.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package fs
2+
3+
import (
4+
"os"
5+
"regexp"
6+
)
7+
8+
func isValidFileName(s string) bool {
9+
m, err := regexp.MatchString("^[^<>:;,?\"*|/]+$", s)
10+
return err == nil && m
11+
}
12+
13+
func doesFileExist(s, p string) bool {
14+
_, err := os.Stat(s)
15+
return !os.IsNotExist(err)
16+
}
17+
18+
func isValidFolderPath(s string) bool {
19+
return true
20+
}

validate_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package fs
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestValidFileName(t *testing.T) {
10+
assert.True(t, isValidFileName("filename.txt"))
11+
assert.False(t, isValidFileName("<.txt"))
12+
}
13+
14+
func TestDoesFileExist(t *testing.T) {
15+
assert.True(t, doesFileExist("lock.go", "."))
16+
assert.False(t, doesFileExist("<.txt", "."))
17+
}

0 commit comments

Comments
 (0)