FTP Entering Extended Passive Mode

I’m trying write a program that will retrieve all files in a directory from a FTP server. The first file is downloaded successfully but on the second file c.Retr(entry) returns the error:

229 Entering Extended Passive Mode (|||44022|).

I’m obviously lacking some FTP understanding here. I don’t know what to do. I’ve tried providing ftp.DialWithDisabledEPSV(true) in ftp.Dial(...) but on the second file c.Retr(entry) returns the error:

226 Transfer complete

but no file is retrieved.

Below is the code. Please pardon it’s scripty nature. Any assistance greatly appreciated.

package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/jlaffaye/ftp"
)

const (
	monthOffset = -1
)

func main() {
	c, err := ftp.Dial(
		os.Getenv("FTP_HOST"),
		ftp.DialWithTimeout(5*time.Second),
	)
	if err != nil {
		log.Fatalln("unable to connect: ", err)
	}

	err = c.Login(
		os.Getenv("ACCOUNT"),
		os.Getenv("PASSWORD"),
	)
	if err != nil {
		log.Fatal("login failed: ", err)
	}

	t := time.Now().AddDate(0, monthOffset, 0)
	year, month, _ := t.Date()
	path := fmt.Sprintf("%d/%02d/", year, month)

	entries, err := c.NameList(path)
	if err != nil {
		log.Fatalf("unable to NLIST %s: %v\n", path, err)
	}

	for _, entry := range entries {
		fmt.Printf("retrieving %s...\n", entry)
		resp, err := c.Retr(entry)
		if err != nil {
			log.Fatalf("unable to retrieve %s: %v\n", entry, err)
		}
		defer resp.Close()

		if _, err := os.Stat(entry); os.IsNotExist(err) {
			os.MkdirAll("data/"+path, 0700)
		}
		destination, err := os.Create("data/" + entry)
		if err != nil {
			log.Fatalln("failed to create file:", err)
		}

		b, err := io.Copy(destination, resp)
		if err != nil {
			log.Fatalln("unable to copy response to dest file: ", err)
		}
		fmt.Printf("successfully copied: %s, bytes copied: %d\n", destination.Name(), b)
	}
}
1 Like

I didn’t see the func DialWithDebugOutput(w io.Writer) DialOption at first.

Using ftp.DialWithDebugOutput(os.Stdout) results are below. I don’t see the second RETR attempt in the debug output. Still a little lost honestly…

220 (vsFTPd 2.2.2)
FEAT
211-Features:
 AUTH SSL
 AUTH TLS
 EPRT
 EPSV
 MDTM
 PASV
 PBSZ
 PROT
 REST STREAM
 SIZE
 TVFS
 UTF8
211 End
USER <user>
331 Please specify the password.
PASS <password>
230 Login successful.
TYPE I
200 Switching to Binary mode.
OPTS UTF8 ON
200 Always in UTF8 mode.
EPSV
229 Entering Extended Passive Mode (|||44010|).
NLST 2019/07/
150 Here comes the directory listing.
226 Directory send OK.
retrieving 2019/07/<file>...
EPSV
229 Entering Extended Passive Mode (|||44081|).
RETR 2019/07/<file>
150 Opening BINARY mode data connection for 2019/07/<file> (290200 bytes).
successfully copied: data/2019/07/<file>, bytes copied: 290200
retrieving 2019/07/<file>...
EPSV
226 Transfer complete.
PASV
229 Entering Extended Passive Mode (|||44023|).
2019/08/04 07:07:36 unable to retrieve 2019/07/<file>: 229 Entering Extended Passive Mode (|||44023|).
exit status 1
1 Like

The issue here was I was calling defer resp.Close() within the for loop that was calling c.Retr(entry).

The solution was to call resp.Close() without defer after copy

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.