From 99be0634ab9a1a9a61630647096d3e63b6a4873e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Heddeland=20Instefjord?= Date: Sun, 4 Sep 2022 20:43:06 +0200 Subject: [PATCH] Add forceListHidden dial option to force the use of 'LIST -a' command (#271) This is useful for servers that do not offer up hidden folders/files by default when using LIST/MLSD commands. Setting forceListHidden to true will force the use of the 'LIST -a' command even when MLST support has been detected. --- client_test.go | 14 ++++++++++++++ ftp.go | 40 +++++++++++++++++++++++++++------------- walker.go | 2 +- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/client_test.go b/client_test.go index b4faae5..75be766 100644 --- a/client_test.go +++ b/client_test.go @@ -295,6 +295,20 @@ func TestListCurrentDir(t *testing.T) { mock.Wait() } +func TestListCurrentDirWithForceListHidden(t *testing.T) { + mock, c := openConnExt(t, "127.0.0.1", "no-time", DialWithDisabledMLSD(true), DialWithForceListHidden(true)) + + assert.True(t, c.options.forceListHidden) + _, err := c.List("") + assert.NoError(t, err) + assert.Equal(t, "LIST -a", mock.lastFull, "LIST -a must not have a trailing whitespace") + + err = c.Quit() + assert.NoError(t, err) + + mock.Wait() +} + func TestTimeUnsupported(t *testing.T) { mock, c := openConnExt(t, "127.0.0.1", "no-time") diff --git a/ftp.go b/ftp.go index 7b13628..7059630 100644 --- a/ftp.go +++ b/ftp.go @@ -72,18 +72,19 @@ type DialOption struct { // dialOptions contains all the options set by DialOption.setup type dialOptions struct { - context context.Context - dialer net.Dialer - tlsConfig *tls.Config - explicitTLS bool - disableEPSV bool - disableUTF8 bool - disableMLSD bool - writingMDTM bool - location *time.Location - debugOutput io.Writer - dialFunc func(network, address string) (net.Conn, error) - shutTimeout time.Duration // time to wait for data connection closing status + context context.Context + dialer net.Dialer + tlsConfig *tls.Config + explicitTLS bool + disableEPSV bool + disableUTF8 bool + disableMLSD bool + writingMDTM bool + forceListHidden bool + location *time.Location + debugOutput io.Writer + dialFunc func(network, address string) (net.Conn, error) + shutTimeout time.Duration // time to wait for data connection closing status } // Entry describes a file and is returned by List(). @@ -247,6 +248,16 @@ func DialWithWritingMDTM(enabled bool) DialOption { }} } +// DialWithForceListHidden returns a DialOption making ServerConn use LIST -a to include hidden files and folders in directory listings +// +// This is useful for servers that do not do this by default, but it forces the use of the LIST command +// even if the server supports MLST. +func DialWithForceListHidden(enabled bool) DialOption { + return DialOption{func(do *dialOptions) { + do.forceListHidden = enabled + }} +} + // DialWithLocation returns a DialOption that configures the ServerConn with specified time.Location // The location is used to parse the dates sent by the server which are in server's timezone func DialWithLocation(location *time.Location) DialOption { @@ -650,11 +661,14 @@ func (c *ServerConn) List(path string) (entries []*Entry, err error) { var cmd string var parser parseFunc - if c.mlstSupported { + if c.mlstSupported && !c.options.forceListHidden { cmd = "MLSD" parser = parseRFC3659ListLine } else { cmd = "LIST" + if c.options.forceListHidden { + cmd += " -a" + } parser = parseListLine } diff --git a/walker.go b/walker.go index 3e0acc3..81735f1 100644 --- a/walker.go +++ b/walker.go @@ -4,7 +4,7 @@ import ( "path" ) -//Walker traverses the directory tree of a remote FTP server +// Walker traverses the directory tree of a remote FTP server type Walker struct { serverConn *ServerConn root string