add Realpath client public fn and fix server impl
diff --git a/client.go b/client.go
index f0d67e8..4aee6dd 100644
--- a/client.go
+++ b/client.go
@@ -611,6 +611,11 @@
 	}
 }
 
+// Realpath requests the canonical name (absolute path, symlinks resolved) of a requested path
+func (c *Client) Realpath(path string) (string, error) {
+	return c.realpath(path)
+}
+
 func (c *Client) realpath(path string) (string, error) {
 	id := c.nextID()
 	typ, data, err := c.sendRequest(sshFxpRealpathPacket{
diff --git a/client_integration_test.go b/client_integration_test.go
index 8fa7f95..6f3f537 100644
--- a/client_integration_test.go
+++ b/client_integration_test.go
@@ -578,6 +578,47 @@
 	}
 }
 
+func TestClientRealpath(t *testing.T) {
+	sftp, cmd := testClient(t, READONLY, NO_DELAY)
+	defer cmd.Wait()
+	defer sftp.Close()
+
+	f, err := ioutil.TempFile("", "sftptest")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(f.Name())
+
+	realName, err := filepath.EvalSymlinks(f.Name())
+	if err != nil {
+		t.Fatal(err)
+	}
+	realName, err = filepath.Abs(realName)
+	if err != nil {
+		t.Fatal(err)
+	}
+	realName = filepath.Clean(realName)
+	linkName := realName + ".softlink"
+
+	// create a symlink that points at sftptest
+	if err := os.Symlink(realName, linkName); err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(linkName)
+
+	// compare names
+	want := realName
+	got, err := sftp.Realpath(linkName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// check that realpath is valid
+	if want != got {
+		t.Fatalf("Realpath(%q): got %v", want, got)
+	}
+}
+
 func TestClientSymlink(t *testing.T) {
 	sftp, cmd := testClient(t, READWRITE, NO_DELAY)
 	defer cmd.Wait()
diff --git a/server.go b/server.go
index 81b1659..1c6f0ae 100644
--- a/server.go
+++ b/server.go
@@ -361,7 +361,12 @@
 func (p sshFxpRealpathPacket) readonly() bool { return true }
 
 func (p sshFxpRealpathPacket) respond(svr *Server) error {
-	f, err := filepath.Abs(p.Path)
+	f, err := filepath.EvalSymlinks(p.Path)
+	if err != nil {
+		return svr.sendPacket(statusFromError(p.ID, err))
+	}
+
+	f, err = filepath.Abs(f)
 	if err != nil {
 		return svr.sendPacket(statusFromError(p.ID, err))
 	}
diff --git a/server_integration_test.go b/server_integration_test.go
index 4d70829..7772ac1 100644
--- a/server_integration_test.go
+++ b/server_integration_test.go
@@ -503,6 +503,63 @@
 	}
 }
 
+func TestServerRealpath(t *testing.T) {
+	// create servers of each variant
+	listenerGo, hostGo, portGo := testServer(t, GOLANG_SFTP, READONLY)
+	listenerOp, hostOp, portOp := testServer(t, OPENSSH_SFTP, READONLY)
+	defer listenerGo.Close()
+	defer listenerOp.Close()
+
+	// create clients for each server
+	clientConfig := ssh.ClientConfig{
+		Config: ssh.Config{		},
+		User: "test",
+		Auth: []ssh.AuthMethod{ssh.Password("")},
+	}
+	clientConfigGo := clientConfig
+	clientConfigOp := clientConfig
+	sshClientGo, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", hostGo, portGo), &clientConfigGo)
+	if err != nil {
+		t.Fatal(err)
+	}
+	sshClientOp, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", hostOp, portOp), &clientConfigOp)
+	if err != nil {
+		t.Fatal(err)
+	}
+	sftpClientGo, err := NewClient(sshClientGo)
+	if err != nil {
+		t.Fatal(err)
+	}
+	sftpClientOp, err := NewClient(sshClientOp)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// create a file, and a convoluted path under it
+	dir, err := ioutil.TempDir("", "sftptestServerRealpath")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(dir)
+	f1 := path.Join(dir, "a", "b", "b.txt")
+	f1strange := strings.Join([]string{dir, "a", "b", "c", "d", "e", "..", "..", "..", "b.txt"}, string(os.PathSeparator))
+	if err := os.MkdirAll(path.Join(dir, "a", "b", "c", "d", "e"), 0755); err != nil {
+		t.Fatal(err)
+	}
+	if err := ioutil.WriteFile(f1, []byte("hello"), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	// compare output from go and openssh
+	if outputGo, err := sftpClientGo.Realpath(f1strange); err != nil {
+		t.Fatalf("failed: %v %v", err, string(outputGo))
+	} else if outputOp, err := sftpClientOp.Realpath(f1strange); err != nil {
+		t.Fatalf("failed: %v %v", err, string(outputOp))
+	} else if outputGo != outputOp {
+		t.Fatalf("output differs:\ngo: '%v'\nop: '%v'\n", outputGo, outputOp)
+	}
+}
+
 func TestServerPut(t *testing.T) {
 	listenerGo, hostGo, portGo := testServer(t, GOLANG_SFTP, READONLY)
 	defer listenerGo.Close()