Thanks

I have attached a patch of where I'm at, it seems to work for all the
cases I can think of on my machine, except that a timeout or other
connection error while testing if I can cd to a symlink will
cause it to skip over that file rather than retry. I'm not really sure 
about error handling, and what should be handled where, what is fatal, etc

Should I be calling a higher level function to CWD and PWD, in order to
handle this? 

Alternatively, how should errors be handled from within
ftp_retrieve_list() 

Thanks
Matt
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 *);

Reply via email to