Downloads a file from the FTP server. This is a two-step process of firstly sending of a PASV command to open the data channel and secondly the download over the data channel. The data channel is closed after the download so this function is called for every file required.

Return TypeFunction nameArguments
hzEcodehzFtpClient::FileDownload(hzDirent&,)

Declared in file: hzFtpClient.h
Defined in file : hzFtpClient.cpp

Function Logic:

0:START 1:unknown 2:Return E_OK 3:m_LocalDir 4:tmpFile tmpFile tmpFile / m_LocalDir tgtFile 5:unknown 6:start 7:nTotal 8:unknown 9:items items rc 10:unknown 11:rc 12:unknown 13:items 14:items len 15:unknown 16:items 17:unknown 18:items 19:unknown 20:items rc 21:items 22:unknown 23:items rc 24:unknown 25:rc 26:unknown 27:items items items items 28:Goto start 29:unknown 30:nTotal items 31:unknown 32:items rc 33:items items 34:unknown 35:items 36:unknown 37:items items epoch svr_mtime svr_mtime items 38:unknown 39:items rc 40:unknown 41:items 42:unknown 43:rc 44:unknown 45:items 46:items m_nTries 47:Return rc

Function body:

hzEcode hzFtpClient::FileDownload (hzDirent& finfo)
{
   //  Downloads a file from the FTP server. This is a two-step process of firstly sending of a PASV command to open the data channel
   //  and secondly the download over the data channel. The data channel is closed after the download so this function is called for
   //  every file required.
   //  
   //  Arguments: 1) finfo The hzDirent for the server-side file. This will have been obtained by a prior directory listing.
   //  
   //  Returns: E_HOSTFAIL If there was a communication failure and reconnect failed
   //     E_NOTFOUND The file on the server does not exist.
   //     E_OPENFAIL The target file on the local machine could not be opened. Presumed fatal
   //     E_WRITEFAIL The target file on the local machine could not be written too. Presumed fatal.
   //     E_OK  If the operation successful
   _hzfunc("hzFtpClient::FileDownload") ;
   struct utimbuf  svr_mtime ;     //  Used to alter date on files to match server version
   std::ofstream   os ;            //  Target file stream
   hzTcpClient     X ;             //  Data channel
   hzString        tmpFile ;       //  Download to a temporary file first, rename upon success
   hzString        tgtFile ;       //  Download to a temporary file first, rename upon success
   uint32_t        epoch ;         //  Time in seconds since 1970
   uint32_t        nRecv ;         //  Incoming message size
   uint32_t        nTotal = 0; //  Total bytes downloaded
   uint32_t        len ;           //  Outgoing message length
   uint32_t        nTry ;          //  Local limit on reconnects
   hzEcode         rc ;            //  Return code
   //  Elimintate zero size files
   if (!finfo.Size())
       return E_OK ;
   //  X.SetDebug(_hzGlobal_Debug & HZ_DEBUG_CLIENT) ;
   tmpFile = m_LocalDir + "/" ;
   tmpFile += finfo.strName() ;
   tmpFile += ".tmp" ;
   tgtFile = m_LocalDir + "/" + finfo.strName() ;
   /*
   **  ** Loop round until success
   **      */
   for (nTry = 0; nTry < 2; nTry++)
   {
start:
       nTotal = 0;
       if (nTry == 1)
       {
           X.Close() ;
           m_ConnControl.Close() ;
           rc = _reconnect() ;
           if (rc != E_OK)
               break ;
       }
       /*
       **  ** First step is to open a data channel
       **           */
       rc = _openpasv(X) ;
       if (rc != E_OK)
       {
           threadLog("Failed PASV\n") ;
           continue ;
       }
       /*
       **  ** Send the RETR command and recv response
       **           */
       sprintf(m_c_sbuf, "RETR %s\r\n", finfo.txtName()) ;
       len = strlen(m_c_sbuf) ;
       if ((rc = m_ConnControl.Send(m_c_sbuf, len)) != E_OK)
       {
           threadLog("Could not send RETR command to get file %s\n", finfo.txtName()) ;
           continue ;
       }
       if ((rc = _ftprecv(nRecv, *_fn)) != E_OK)
       {
           threadLog("Could not get RETR respeonse (file=%s)\n", finfo.txtName()) ;
           continue ;
       }
       /*
       **  ** Check response code
       **           */
       if (m_nRescode >&eq; 400)
       {
           threadLog("Got bad response to RETR (%d)\n", m_nRescode) ;
           rc = E_PROTOCOL ;
           break ;
       }
       /*
       **  ** Then if all is well, download the file
       **           */
       os.open(*tmpFile) ;
       if (os.fail())
       {
           threadLog("Failed to open download temp file %s\n", *tmpFile) ;
           rc = E_OPENFAIL ;
           break ;
       }
       for (nTotal = 0; nTotal < finfo.Size() ;)
       {
           rc = X.Recv(m_x_rbuf, nRecv, HZ_MAXPACKET) ;
           if (rc != E_OK)
           {
               threadLog("Socket error during download of file %s\n", finfo.txtName()) ;
               X.Close() ;
               os.close() ;
               os.clear() ;
               goto start ;
           }
           if (!nRecv)
               break ;
           nTotal += nRecv ;
           os.write(m_x_rbuf, nRecv) ;
           if (os.fail())
           {
               threadLog("Failed to write data to the target file %s\n", finfo.txtName()) ;
               rc = E_WRITEFAIL ;
               break ;
           }
       }
       X.Close() ;
       os.close() ;
       if (rc == E_WRITEFAIL)
       {
           threadLog("Aborted operation to download %d of %d bytes to the target file %s - No disk space\n", nTotal, finfo.Size(), finfo.txtName()) ;
       }
       //  Initial comms phase over so exit loop
       break ;
   }
   if (rc == E_OK)
   {
       /*
       **  ** Rename the file to the target name, set mtime of the local file to match that of the server
       **           */
       rename(*tmpFile, *tgtFile) ;
       threadLog("Downloaded %d of %d bytes to the target file %s\n", nTotal, finfo.Size(), finfo.txtName()) ;
       epoch = finfo.Mtime() ;
       svr_mtime.actime = time(0);
       svr_mtime.modtime = epoch ;
       utime(finfo.txtName(), &svr_mtime) ;
       /*
       **  ** Get server progress report of download. If broken pipe reconnect but as we have the file already we don't
       **    ** have to repeat any steps.
       **           */
       if ((rc = _ftprecv(nRecv, *_fn)) != E_OK)
       {
           threadLog("Could not get response to RETR command (file=%s)\n", finfo.txtName()) ;
           rc = _reconnect() ;
       }
       else
       {
           if (m_nRescode != 226)
               threadLog("Expected code of 226 (Xfer complete), got %d\n", m_nRescode) ;
           if (m_nRescode >&eq; 400)
               rc = E_RECVFAIL ;
       }
   }
   if (rc != E_OK)
       threadLog("Could not download %s\n\n", finfo.txtName()) ;
   else
   {
       threadLog("Downloaded %s\n", finfo.txtName()) ;
       m_nTries = 0;
   }
   return rc ;
}