diff --git a/src/ftp-basic.c b/src/ftp-basic.c index b6e67e2..152e399 100644 --- a/src/ftp-basic.c +++ b/src/ftp-basic.c @@ -1213,3 +1213,26 @@ ftp_process_type (const char *params) else return 'I'; } + +/* Get current working diectory, CWD to dir, and CWD back */ +uerr_t +try_cwd (int csock, char *dir) +{ + char *pwd = NULL; + uerr_t err; + err = ftp_pwd (csock, &pwd); + if (err != FTPOK) + return err; + err = ftp_cwd (csock, dir); + if (err != FTPOK) + return err; + err = ftp_cwd (csock, pwd); + if (err != FTPOK) + { + /* What if any cleanup is necessary here, or just return err rather than + * abort? */ + fd_close (csock); + abort (); + } + return err; +} diff --git a/src/ftp.c b/src/ftp.c index 2d54333..c369809 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -2046,7 +2046,30 @@ Already have correct symlink %s -> %s\n\n"), else /* opt.retr_symlinks */ { if (dlthis) - err = ftp_loop_internal (u, f, con, NULL); + { + err = ftp_loop_internal (u, f, con, NULL); + if (err == FTPNSFOD) + { + err = try_cwd (con->csock, f->name); + /* CWD to a non directory will return FTPNSFOD + * eg if the symlink points to a non readable file + * Should we do this on (err != FTPOK || err != FTPNSFOD?) + */ + if (err == FTPRERR || err == FTPSRVERR) + { + logputs (LOG_VERBOSE, "\n"); + logputs (LOG_NOTQUIET, _("\ +Error in server response, closing control connection.\n")); + fd_close (con->csock); + con->csock = -1; + } + if (err == FTPOK) + /* Does anything else afterwards depend on this being + * FT_SYMLINK? */ + f->type = FT_DIRECTORY; + } + } + } /* opt.retr_symlinks */ break; case FT_DIRECTORY: diff --git a/src/ftp.h b/src/ftp.h index 78b5270..50d4b65 100644 --- a/src/ftp.h +++ b/src/ftp.h @@ -73,6 +73,7 @@ uerr_t ftp_list (int, const char *, bool, bool, bool *); uerr_t ftp_syst (int, enum stype *, enum ustype *); uerr_t ftp_pwd (int, char **); uerr_t ftp_size (int, const char *, wgint *); +uerr_t try_cwd (int, char *); #ifdef ENABLE_OPIE const char *skey_response (int, const char *, const char *);