From 143430ff5f20bd8cc130b76a57f841c77fc8dc65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Nu=C8=9Biu?= Date: Sun, 29 Oct 2017 18:59:03 +0200 Subject: [PATCH] Implementing the Path --- server/server/commands.go | 8 +--- server/server/errors.go | 7 +++ server/server/path.go | 85 ++++++++++++++++++++++++++++++++++ server/server/path_test.go | 94 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 server/server/path.go create mode 100644 server/server/path_test.go diff --git a/server/server/commands.go b/server/server/commands.go index dd1b963..003cc15 100644 --- a/server/server/commands.go +++ b/server/server/commands.go @@ -10,15 +10,11 @@ import ( "strings" ) -// PATH is the constant which should contain the fixed path where the simpleFTP server will run -// This will act like a root cage. -const PATH = "/Users/denis/GoglandProjects/golangBook/GoRoutines/" - // GetFile sends the file to the client and returns true if it succeeds and false otherwise. func GetFile(c net.Conn, path string) (int, error) { fileName := sanitizeFilePath(path) - file, err := os.Open(PATH + fileName) + file, err := os.Open(BasePath + fileName) if err != nil { log.Println(err) return 0, err @@ -66,7 +62,7 @@ func sanitizeFilePath(path string) string { // ListFiles list the files from path and sends them to the connection func ListFiles(c net.Conn) error { - files, err := ioutil.ReadDir(PATH) + files, err := ioutil.ReadDir(BasePath) if err != nil { return err } diff --git a/server/server/errors.go b/server/server/errors.go index 3144b40..dd8443b 100644 --- a/server/server/errors.go +++ b/server/server/errors.go @@ -37,3 +37,10 @@ var ( StackOverflowError = StackError{"StackOverflowError", errors.New("stack capacity exceeded")} StackUnderflowError = StackError{"StackUnderflowError", errors.New("stack is empty")} ) + +// PathErrors +var ( + ErrInvalidDirectoryName = errors.New("names should not contain / character") + ErrNotADirectory = errors.New("file name is not a valid directory") + ErrAlreadyAtBaseDirectory = errors.New("can't go past beyond root directory") +) diff --git a/server/server/path.go b/server/server/path.go new file mode 100644 index 0000000..d0ba0f2 --- /dev/null +++ b/server/server/path.go @@ -0,0 +1,85 @@ +package server + +// The Path module should work with the stack by providing functions that update the stack +// with information that helps keeping track of the directories that the clients use. + +import ( + "bytes" + "os" +) + +func containsSlash(dir string) bool { + for _, c := range dir { + if c == '/' { + return true + } + } + return false +} + +// PATH is the constant which should contain the fixed path where the simpleFTP server will run +// This will act like a root cage. +var BasePath = "/Users/denis/GoglandProjects/golangBook/" + +// GetPath will return the complete path +func GetPath(stack *StringStack) string { + if stack.IsEmpty() { + return BasePath + } + + return BasePath +} + +// MakePathFromStringStack gets a StringStack and makes a path. +func MakePathFromStringStack(stack *StringStack) string { + var buffer bytes.Buffer + + buffer.WriteString(BasePath) + if BasePath[len(BasePath)-1] != '/' { + buffer.WriteString("/") + } + + for i := 0; i < stack.Size(); i++ { + buffer.WriteString(stack.Items()[i] + "/") + } + + return buffer.String() +} + +// ChangeDirectory changes the current working directory with respect to BasePath +func ChangeDirectory(stack *StringStack, directory string) error { + if containsSlash(directory) == true { + return ErrInvalidDirectoryName + } + stack.Push(directory) + + path := MakePathFromStringStack(stack) + fileInfo, err := os.Stat(path) + if err != nil { + return err + } + + if fileInfo.IsDir() == false { + return ErrNotADirectory + } + + // The last 9 bits represent the Unix perms format rwxrwxrwx + perms := fileInfo.Mode().Perm() + + // The user has permission to view the directory + if (perms&1 != 0) && (perms&(1<<2) != 0) || (perms&(1<<6) != 0) && (perms&(1<<8) != 0) { + return nil + } + stack.Pop() + return os.ErrPermission +} + +// ChangeDirectoryToPrevious changes the current working directory to the previous one, +// doesn't go past the BasePath +func ChangeDirectoryToPrevious(stack *StringStack) error { + if stack.IsEmpty() { + return ErrAlreadyAtBaseDirectory + } + stack.Pop() + return nil +} diff --git a/server/server/path_test.go b/server/server/path_test.go new file mode 100644 index 0000000..efa4244 --- /dev/null +++ b/server/server/path_test.go @@ -0,0 +1,94 @@ +package server + +import ( + "fmt" + "math/rand" + "os" + "testing" +) + +func TestGetPath_StackIsEmpty(t *testing.T) { + st := MakeStringStack(1) + + path := GetPath(st) + + if path != BasePath { + t.Errorf("TestGetPath: Base path is not returned when stack is empty.") + } +} + +func TestMakePathFromStringStack(t *testing.T) { + st := MakeStringStack(5) + + st.Push("first") + st.Push("folder two") + st.Push("trinity") + + path := MakePathFromStringStack(st) + expected := fmt.Sprintf("%s/%s/%s/%s/", BasePath, "first", "folder two", "trinity") + + if path != expected { + t.Errorf("TestMakePathFromStringStack: Returned an invalid path! Want %s Got %s", expected, path) + } + +} + +func TestMakePathFromStringStack_StackIsEmpty(t *testing.T) { + st := MakeStringStack(1) + path := MakePathFromStringStack(st) + + expected := BasePath + if BasePath[len(BasePath)-1] != '/' { + expected += "/" + } + + if path != expected { + t.Errorf("TestMakePathFromStringStack: Returned an invalid path!") + } +} + +func TestChangeDirectory(t *testing.T) { + st := MakeStringStack(1) + err := os.Chdir(BasePath) + if err != nil { + t.Errorf("TestChangeDirectory: Step1: %s", err.Error()) + } + + dirName := string(rand.Intn(10000)) + + err = os.Mkdir(dirName, os.FileMode(0522)) + if err != nil { + t.Errorf("TestChangeDirectory: Step2: %s", err.Error()) + } + + err = ChangeDirectory(st, dirName) + if err != nil { + t.Errorf("TestChangeDirectory: Step3: %s", err.Error()) + } + + err = os.Chdir(BasePath) + if err != nil { + t.Errorf("TestChangeDirectory: Step4: %s", err.Error()) + } + + err = os.Remove(dirName) + if err != nil { + t.Errorf("TestChangeDirectory: Step5: %s", err.Error()) + } +} + +func TestChangeDirectory_InvalidDirectoryName(t *testing.T) { + st := MakeStringStack(1) + err := ChangeDirectory(st, "some/not/cool/directory/") + if err != ErrInvalidDirectoryName { + t.Error("TestChangeDirectory: Changed directory to something containing the '/' character!") + } +} + +func TestChangeDirectoryToPrevious_StackIsEmpty(t *testing.T) { + st := MakeStringStack(1) + err := ChangeDirectoryToPrevious(st) + if err != ErrAlreadyAtBaseDirectory { + t.Error("TestChangeDirectoryToPrevious: Stack is empty and no error occured!") + } +}