Implementing change directory command
This commit is contained in:
parent
8158edf88c
commit
da7f4cbfd0
5 changed files with 88 additions and 30 deletions
|
@ -11,7 +11,10 @@ import (
|
||||||
|
|
||||||
// GetFile sends the file to the client and returns true if it succeeds and false otherwise.
|
// GetFile sends the file to the client and returns true if it succeeds and false otherwise.
|
||||||
func GetFile(c Client, path string) (int, error) {
|
func GetFile(c Client, path string) (int, error) {
|
||||||
fileName := sanitizeFilePath(path)
|
fileName, sanitized := sanitizeFilePath(path)
|
||||||
|
if sanitized {
|
||||||
|
return 0, ErrSlashNotAllowed
|
||||||
|
}
|
||||||
|
|
||||||
stack, ok := c.Stack().(*StringStack)
|
stack, ok := c.Stack().(*StringStack)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -51,17 +54,20 @@ func readFileData(file *os.File) ([]byte, error) {
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sanitizeFilePath(path string) string {
|
func sanitizeFilePath(path string) (string, bool) {
|
||||||
var fileName string
|
var fileName string
|
||||||
|
var sanitized bool
|
||||||
// Make sure the user can't request any files on the system.
|
// Make sure the user can't request any files on the system.
|
||||||
lastForwardSlash := strings.LastIndex(path, "/")
|
lastForwardSlash := strings.LastIndex(path, "/")
|
||||||
if lastForwardSlash != -1 {
|
if lastForwardSlash != -1 {
|
||||||
// Eliminate the last forward slash i.e ../../asdas will become asdas
|
// Eliminate the last forward slash i.e ../../asdas will become asdas
|
||||||
fileName = path[lastForwardSlash+1:]
|
fileName = path[lastForwardSlash+1:]
|
||||||
|
sanitized = true
|
||||||
} else {
|
} else {
|
||||||
fileName = path
|
fileName = path
|
||||||
|
sanitized = false
|
||||||
}
|
}
|
||||||
return fileName
|
return fileName, sanitized
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListFiles list the files from path and sends them to the connection
|
// ListFiles list the files from path and sends them to the connection
|
||||||
|
@ -90,13 +96,46 @@ func ListFiles(c Client) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearScreen cleans the client's screen by sending clear to the terminal.
|
||||||
|
func ClearScreen(c Client) error {
|
||||||
|
// Ansi clear: 1b 5b 48 1b 5b 4a
|
||||||
|
// clear | hexdump -C
|
||||||
|
var b = []byte{0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x4a}
|
||||||
|
_, err := c.Connection().Write(b)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeDirectoryCommand changes the directory to the given directory
|
||||||
|
func ChangeDirectoryCommand(c Client, directory string) error {
|
||||||
|
var err error
|
||||||
|
path, sanitized := sanitizeFilePath(directory)
|
||||||
|
if sanitized {
|
||||||
|
return ErrSlashNotAllowed
|
||||||
|
}
|
||||||
|
|
||||||
|
stack, ok := c.Stack().(*StringStack)
|
||||||
|
if !ok {
|
||||||
|
return ErrStackCast
|
||||||
|
}
|
||||||
|
|
||||||
|
if path == ".." {
|
||||||
|
err = ChangeDirectoryToPrevious(stack)
|
||||||
|
} else {
|
||||||
|
err = ChangeDirectory(stack, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func ShowHelp(c Client) error {
|
func ShowHelp(c Client) error {
|
||||||
var helpText = `
|
var helpText = `
|
||||||
The available commands are:
|
The available commands are:
|
||||||
get <filename> - Download the requested filename.
|
get <filename> - Download the requested filename.
|
||||||
ls - List the files in the current directory.
|
ls - List the files in the current directory.
|
||||||
|
cd - Changes the directory.
|
||||||
clear - Clear the screen.
|
clear - Clear the screen.
|
||||||
exit - Close the connection with the server.
|
exit - Close the connection with the server.c
|
||||||
`
|
`
|
||||||
_, err := c.Connection().Write([]byte(helpText))
|
_, err := c.Connection().Write([]byte(helpText))
|
||||||
|
|
||||||
|
|
|
@ -44,4 +44,5 @@ var (
|
||||||
ErrInvalidDirectoryName = errors.New("names should not contain / character")
|
ErrInvalidDirectoryName = errors.New("names should not contain / character")
|
||||||
ErrNotADirectory = errors.New("file name is not a valid directory")
|
ErrNotADirectory = errors.New("file name is not a valid directory")
|
||||||
ErrAlreadyAtBaseDirectory = errors.New("can't go past beyond root directory")
|
ErrAlreadyAtBaseDirectory = errors.New("can't go past beyond root directory")
|
||||||
|
ErrSlashNotAllowed = errors.New("slash is not allowed in file names")
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,6 +25,16 @@ func ProcessInput(c Client, text string) error {
|
||||||
thisCommand := commands[0]
|
thisCommand := commands[0]
|
||||||
|
|
||||||
switch thisCommand {
|
switch thisCommand {
|
||||||
|
case "cd":
|
||||||
|
err := checkArgumentsLength(commandsLen, 2)
|
||||||
|
if err != nil {
|
||||||
|
return &InputError{thisCommand, err}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ChangeDirectoryCommand(c, commands[1])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case "get":
|
case "get":
|
||||||
err := checkArgumentsLength(commandsLen, 2)
|
err := checkArgumentsLength(commandsLen, 2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -52,11 +62,10 @@ func ProcessInput(c Client, text string) error {
|
||||||
return &InputError{thisCommand, err}
|
return &InputError{thisCommand, err}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ansi clear: 1b 5b 48 1b 5b 4a
|
err = ClearScreen(c)
|
||||||
// clear | hexdump -C
|
if err != nil {
|
||||||
var b = []byte{0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x4a}
|
return err
|
||||||
|
}
|
||||||
c.Connection().Write(b)
|
|
||||||
case "help":
|
case "help":
|
||||||
// Check arguments
|
// Check arguments
|
||||||
err := checkArgumentsLength(commandsLen, 1)
|
err := checkArgumentsLength(commandsLen, 1)
|
||||||
|
|
|
@ -18,17 +18,17 @@ func containsSlash(dir string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PATH is the constant which should contain the fixed path where the simpleFTP server will run
|
// PATH is the constant which should contain the fixed path where the simpleFTP server will run
|
||||||
// This will act like a root cage.
|
// This will act like a root cage. It must end with a forward slash!
|
||||||
var BasePath = "/Users/denis/GoglandProjects/golangBook/"
|
var BasePath = "/Users/denis/GoglandProjects/golangBook/"
|
||||||
|
|
||||||
// GetPath will return the complete path
|
// GetPath will return the complete path
|
||||||
func GetPath(stack *StringStack) string {
|
//func GetPath(stack *StringStack) string {
|
||||||
if stack.IsEmpty() {
|
// if stack.IsEmpty() {
|
||||||
return BasePath
|
// return BasePath
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return BasePath
|
// return BasePath
|
||||||
}
|
//}
|
||||||
|
|
||||||
// MakePathFromStringStack gets a StringStack and makes a path.
|
// MakePathFromStringStack gets a StringStack and makes a path.
|
||||||
func MakePathFromStringStack(stack *StringStack) string {
|
func MakePathFromStringStack(stack *StringStack) string {
|
||||||
|
@ -56,10 +56,12 @@ func ChangeDirectory(stack *StringStack, directory string) error {
|
||||||
path := MakePathFromStringStack(stack)
|
path := MakePathFromStringStack(stack)
|
||||||
fileInfo, err := os.Stat(path)
|
fileInfo, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
stack.Pop()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if fileInfo.IsDir() == false {
|
if fileInfo.IsDir() == false {
|
||||||
|
stack.Pop()
|
||||||
return ErrNotADirectory
|
return ErrNotADirectory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,6 @@ import (
|
||||||
"testing"
|
"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) {
|
func TestMakePathFromStringStack(t *testing.T) {
|
||||||
st := MakeStringStack(5)
|
st := MakeStringStack(5)
|
||||||
|
|
||||||
|
@ -25,7 +15,7 @@ func TestMakePathFromStringStack(t *testing.T) {
|
||||||
st.Push("trinity")
|
st.Push("trinity")
|
||||||
|
|
||||||
path := MakePathFromStringStack(st)
|
path := MakePathFromStringStack(st)
|
||||||
expected := fmt.Sprintf("%s/%s/%s/%s/", BasePath, "first", "folder two", "trinity")
|
expected := fmt.Sprintf("%s%s/%s/%s/", BasePath, "first", "folder two", "trinity")
|
||||||
|
|
||||||
if path != expected {
|
if path != expected {
|
||||||
t.Errorf("TestMakePathFromStringStack: Returned an invalid path! Want %s Got %s", expected, path)
|
t.Errorf("TestMakePathFromStringStack: Returned an invalid path! Want %s Got %s", expected, path)
|
||||||
|
@ -77,6 +67,23 @@ func TestChangeDirectory(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestChangeDirectory_InvalidDirectoryIsNotInStack(t *testing.T) {
|
||||||
|
st := MakeStringStack(1)
|
||||||
|
err := os.Chdir(BasePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("TestChangeDirectory_InvalidDirectoryIsNotInStack: Step1: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
dirName := string(rand.Intn(10000))
|
||||||
|
|
||||||
|
// ignore no such directory error
|
||||||
|
ChangeDirectory(st, dirName)
|
||||||
|
if !st.IsEmpty() && st.Top() == dirName {
|
||||||
|
t.Errorf("TestChangeDirectory: Stack is corrupted because invalid directory remained in stack")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestChangeDirectory_InvalidDirectoryName(t *testing.T) {
|
func TestChangeDirectory_InvalidDirectoryName(t *testing.T) {
|
||||||
st := MakeStringStack(1)
|
st := MakeStringStack(1)
|
||||||
err := ChangeDirectory(st, "some/not/cool/directory/")
|
err := ChangeDirectory(st, "some/not/cool/directory/")
|
||||||
|
|
Loading…
Reference in a new issue