Blame src/FileCopy.h

Packit 8f70b4
/*
Packit 8f70b4
 * lftp - file transfer program
Packit 8f70b4
 *
Packit 8f70b4
 * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net)
Packit 8f70b4
 *
Packit 8f70b4
 * This program is free software; you can redistribute it and/or modify
Packit 8f70b4
 * it under the terms of the GNU General Public License as published by
Packit 8f70b4
 * the Free Software Foundation; either version 3 of the License, or
Packit 8f70b4
 * (at your option) any later version.
Packit 8f70b4
 *
Packit 8f70b4
 * This program is distributed in the hope that it will be useful,
Packit 8f70b4
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8f70b4
 * GNU General Public License for more details.
Packit 8f70b4
 *
Packit 8f70b4
 * You should have received a copy of the GNU General Public License
Packit 8f70b4
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8f70b4
 */
Packit 8f70b4
Packit 8f70b4
/*
Packit 8f70b4
  classes defined here:
Packit 8f70b4
   FileCopy
Packit 8f70b4
   FileCopyPeer
Packit 8f70b4
   +FileCopyPeerFA
Packit 8f70b4
   +FileCopyPeerFDStream
Packit 8f70b4
   \FileCopyPeerList
Packit 8f70b4
*/
Packit 8f70b4
Packit 8f70b4
#ifndef FILECOPY_H
Packit 8f70b4
#define FILECOPY_H
Packit 8f70b4
Packit 8f70b4
#include "SMTask.h"
Packit 8f70b4
#include "buffer.h"
Packit 8f70b4
#include "FileAccess.h"
Packit 8f70b4
#include "Speedometer.h"
Packit 8f70b4
#include "Timer.h"
Packit 8f70b4
#include "log.h"
Packit 8f70b4
Packit 8f70b4
class FileCopyPeer : public IOBuffer
Packit 8f70b4
{
Packit 8f70b4
protected:
Packit 8f70b4
   bool want_size;
Packit 8f70b4
   bool want_date;
Packit 8f70b4
   bool start_transfer;
Packit 8f70b4
   off_t size;
Packit 8f70b4
   off_t e_size;
Packit 8f70b4
   FileTimestamp date;
Packit 8f70b4
Packit 8f70b4
   off_t seek_pos;
Packit 8f70b4
   bool can_seek;
Packit 8f70b4
   bool can_seek0;
Packit 8f70b4
   bool date_set;
Packit 8f70b4
   bool do_set_date;
Packit 8f70b4
   bool do_verify;
Packit 8f70b4
   bool removing;
Packit 8f70b4
   bool file_removed;
Packit 8f70b4
   bool temp_file;
Packit 8f70b4
   bool do_mkdir;
Packit 8f70b4
Packit 8f70b4
   bool done;
Packit 8f70b4
Packit 8f70b4
   bool ascii;
Packit 8f70b4
   bool use_cache;
Packit 8f70b4
Packit 8f70b4
   bool write_allowed;
Packit 8f70b4
Packit 8f70b4
   xstring_c suggested_filename;
Packit 8f70b4
   bool auto_rename;
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   off_t range_start; // NOTE: ranges are implemented only partially. (FIXME)
Packit 8f70b4
   off_t range_limit;
Packit 8f70b4
Packit 8f70b4
   bool CanSeek() { return can_seek; }
Packit 8f70b4
   bool CanSeek0() { return can_seek0; }
Packit 8f70b4
   bool CanSeek(off_t p) { return p==0 ? CanSeek0() : CanSeek(); }
Packit 8f70b4
   off_t GetSeekPos() { return seek_pos; }
Packit 8f70b4
   virtual void Seek(off_t offs);
Packit 8f70b4
   virtual off_t GetRealPos() { return pos; }
Packit 8f70b4
   virtual int Buffered() { return Size(); }
Packit 8f70b4
   virtual bool IOReady() { return true; }
Packit 8f70b4
Packit 8f70b4
   virtual void WantDate() { want_date=true; date=NO_DATE_YET; }
Packit 8f70b4
   virtual void WantSize() { want_size=true; size=NO_SIZE_YET; }
Packit 8f70b4
   time_t GetDate() { return date; }
Packit 8f70b4
   off_t GetSize();
Packit 8f70b4
Packit 8f70b4
   void SetDate(time_t d,int p=0);
Packit 8f70b4
   void SetSize(off_t s);
Packit 8f70b4
   void SetEntitySize(off_t s) { if(!ascii) e_size=s; }
Packit 8f70b4
Packit 8f70b4
   void DontCopyDate() { do_set_date=false; }
Packit 8f70b4
   void DontVerify() { do_verify=false; }
Packit 8f70b4
   bool NeedDate() { return do_set_date; }
Packit 8f70b4
   void MakeTargetDir() { do_mkdir=true; }
Packit 8f70b4
Packit 8f70b4
   void SetRange(const off_t s,const off_t lim);
Packit 8f70b4
Packit 8f70b4
   FileCopyPeer(dir_t m);
Packit 8f70b4
   virtual ~FileCopyPeer() {}
Packit 8f70b4
Packit 8f70b4
   bool Done();
Packit 8f70b4
Packit 8f70b4
   void Ascii() { ascii=true; }
Packit 8f70b4
   virtual void NoCache() { use_cache=false; }
Packit 8f70b4
Packit 8f70b4
   virtual const char *GetStatus() { return 0; }
Packit 8f70b4
   virtual bool NeedSizeDateBeforehand() { return false; }
Packit 8f70b4
Packit 8f70b4
   virtual pid_t GetProcGroup() { return 0; }
Packit 8f70b4
   virtual void Kill(int sig) {}
Packit 8f70b4
Packit 8f70b4
   virtual void RemoveFile() { file_removed=true; }
Packit 8f70b4
   virtual void NeedSeek() {} // fd is shared, seek before access.
Packit 8f70b4
Packit 8f70b4
   void CannotSeek(int p)
Packit 8f70b4
      {
Packit 8f70b4
	 can_seek=false;
Packit 8f70b4
	 if(p==0)
Packit 8f70b4
	    can_seek0=false;
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
   // for fxp:
Packit 8f70b4
   virtual const FileAccessRef& GetSession() { return FileAccessRef::null; }
Packit 8f70b4
   virtual void OpenSession() {}
Packit 8f70b4
   virtual void SetFXP(bool) {}
Packit 8f70b4
Packit 8f70b4
   virtual void Fg() {}
Packit 8f70b4
   virtual void Bg() {}
Packit 8f70b4
Packit 8f70b4
   void AllowWrite(bool y=true) { write_allowed=y; }
Packit 8f70b4
   bool WriteAllowed() { return write_allowed; }
Packit 8f70b4
   bool WritePending() { return mode==PUT && Size()>0; }
Packit 8f70b4
Packit 8f70b4
   bool FileRemoved() { return file_removed; }
Packit 8f70b4
Packit 8f70b4
   void DontStartTransferYet() { start_transfer=false; }
Packit 8f70b4
   void StartTransfer() { start_transfer=true; }
Packit 8f70b4
Packit 8f70b4
   const char *GetDescriptionForLog() { return 0; }
Packit 8f70b4
   virtual const char *GetURL() { return 0; }
Packit 8f70b4
   virtual FileCopyPeer *Clone() { return 0; }
Packit 8f70b4
   virtual const Ref<FDStream>& GetLocal() const { return Ref<FDStream>::null; }
Packit 8f70b4
Packit 8f70b4
   const char *GetSuggestedFileName() { return suggested_filename; }
Packit 8f70b4
   void SetSuggestedFileName(const char *f) { if(f) suggested_filename.set(f); }
Packit 8f70b4
   void AutoRename(bool yes=true) { auto_rename=yes; }
Packit 8f70b4
   const char *UseTempFile(const char *);
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class FileCopy : public SMTask
Packit 8f70b4
{
Packit 8f70b4
public:
Packit 8f70b4
   SMTaskRef<FileCopyPeer> get;
Packit 8f70b4
   SMTaskRef<FileCopyPeer> put;
Packit 8f70b4
Packit 8f70b4
protected:
Packit 8f70b4
   enum state_t
Packit 8f70b4
      {
Packit 8f70b4
	 INITIAL,
Packit 8f70b4
	 GET_INFO_WAIT,
Packit 8f70b4
	 PUT_WAIT,
Packit 8f70b4
	 DO_COPY,
Packit 8f70b4
	 CONFIRM_WAIT,
Packit 8f70b4
	 GET_DONE_WAIT,
Packit 8f70b4
	 ALL_DONE
Packit 8f70b4
      } state;
Packit 8f70b4
Packit 8f70b4
private:
Packit 8f70b4
   bool cont;
Packit 8f70b4
Packit 8f70b4
   xstring_c error_text;
Packit 8f70b4
Packit 8f70b4
   Speedometer rate;
Packit 8f70b4
   Speedometer rate_for_eta;
Packit 8f70b4
   int put_buf;
Packit 8f70b4
   off_t put_eof_pos;
Packit 8f70b4
Packit 8f70b4
   off_t high_watermark;
Packit 8f70b4
   Timer high_watermark_timeout;
Packit 8f70b4
Packit 8f70b4
   Time start_time;
Packit 8f70b4
   Time end_time;
Packit 8f70b4
Packit 8f70b4
   bool fail_if_cannot_seek;
Packit 8f70b4
   bool fail_if_broken;
Packit 8f70b4
   bool remove_source_later;
Packit 8f70b4
   bool remove_target_first;
Packit 8f70b4
Packit 8f70b4
   Ref<Buffer> line_buffer;
Packit 8f70b4
   int  line_buffer_max;
Packit 8f70b4
Packit 8f70b4
   bool CheckFileSizeAtEOF() const;
Packit 8f70b4
Packit 8f70b4
protected:
Packit 8f70b4
   void RateAdd(int a);
Packit 8f70b4
   void RateReset();
Packit 8f70b4
   off_t bytes_count;
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   off_t GetPos() const;
Packit 8f70b4
   off_t GetSize() const;
Packit 8f70b4
   int  GetPercentDone() const;
Packit 8f70b4
   const char *GetPercentDoneStr() const;
Packit 8f70b4
   float GetRate();
Packit 8f70b4
   const char *GetRateStr();
Packit 8f70b4
   off_t GetBytesRemaining();
Packit 8f70b4
   long GetETA() { return GetETA(GetBytesRemaining()); }
Packit 8f70b4
   long GetETA(off_t b);
Packit 8f70b4
   const char *GetETAStr();
Packit 8f70b4
   const char *GetETAStrSFromTime(time_t t) { return rate_for_eta.GetETAStrSFromTime(t); }
Packit 8f70b4
   const char *GetStatus();
Packit 8f70b4
   FgData *GetFgData(bool fg);
Packit 8f70b4
   pid_t GetProcGroup();
Packit 8f70b4
   void Kill(int sig);
Packit 8f70b4
   off_t GetBytesCount() { return bytes_count; }
Packit 8f70b4
   double GetTimeSpent();
Packit 8f70b4
   double GetTransferRate() { return rate.Get(); }
Packit 8f70b4
Packit 8f70b4
   void SetDate(time_t t,int p=0) { get->SetDate(t,p); }
Packit 8f70b4
   void SetDate(const FileTimestamp &t) { SetDate(t.ts,t.ts_prec); }
Packit 8f70b4
   void SetSize(off_t s) { get->SetSize(s); }
Packit 8f70b4
Packit 8f70b4
   bool SetContinue(bool new_cont) { return replace_value(cont,new_cont); }
Packit 8f70b4
Packit 8f70b4
   bool Done() { return state==ALL_DONE; }
Packit 8f70b4
   bool Error() { return error_text!=0; }
Packit 8f70b4
   const char *ErrorText() { return error_text; }
Packit 8f70b4
   void SetError(const char *str);
Packit 8f70b4
Packit 8f70b4
   void DontCopyDate() { put->DontCopyDate(); }
Packit 8f70b4
   void DontVerify() { put->DontVerify(); }
Packit 8f70b4
   void Ascii() { get->Ascii(); put->Ascii(); }
Packit 8f70b4
   void DontFailIfBroken() { fail_if_broken=false; }
Packit 8f70b4
   void FailIfCannotSeek() { fail_if_cannot_seek=true; }
Packit 8f70b4
   void SetRange(off_t s,off_t lim);
Packit 8f70b4
   void SetRangeLimit(off_t lim) { get->range_limit=lim; }
Packit 8f70b4
   off_t GetRangeStart() const { return get->range_start; }
Packit 8f70b4
   off_t GetRangeLimit() const { return get->range_limit; }
Packit 8f70b4
   void RemoveSourceLater() { remove_source_later=true; }
Packit 8f70b4
   void RemoveTargetFirst() { remove_target_first=true; put->Resume(); put->RemoveFile(); }
Packit 8f70b4
   void LineBuffered(int size=0x1000);
Packit 8f70b4
   bool IsLineBuffered() const { return line_buffer; }
Packit 8f70b4
Packit 8f70b4
   FileCopy(FileCopyPeer *src,FileCopyPeer *dst,bool cont);
Packit 8f70b4
   ~FileCopy();
Packit 8f70b4
Packit 8f70b4
   int Do();
Packit 8f70b4
   void SuspendInternal();
Packit 8f70b4
   void ResumeInternal();
Packit 8f70b4
   void Fg();
Packit 8f70b4
   void Bg();
Packit 8f70b4
Packit 8f70b4
   static FileCopy *New(FileCopyPeer *src,FileCopyPeer *dst,bool cont);
Packit 8f70b4
   static FileCopy *(*fxp_create)(FileCopyPeer *src,FileCopyPeer *dst,bool cont);
Packit 8f70b4
Packit 8f70b4
   void AllowWrite(bool y=true) { if(put) put->AllowWrite(y); }
Packit 8f70b4
   bool WriteAllowed() { return !put || put->WriteAllowed(); }
Packit 8f70b4
   bool WritePending() { return put && put->WritePending(); }
Packit 8f70b4
Packit 8f70b4
   void LogTransfer();
Packit 8f70b4
   static Ref<Log> transfer_log;
Packit 8f70b4
Packit 8f70b4
   static const char *TempFileName(const char *file);
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class FileVerificator : public SMTask
Packit 8f70b4
{
Packit 8f70b4
   bool done;
Packit 8f70b4
   xstring error_text;
Packit 8f70b4
   SMTaskRef<IOBufferFDStream> verify_buffer;
Packit 8f70b4
   Ref<InputFilter> verify_process;
Packit 8f70b4
   void Init0();
Packit 8f70b4
   void InitVerify(const char *f);
Packit 8f70b4
public:
Packit 8f70b4
   FileVerificator(const char *f);
Packit 8f70b4
   FileVerificator(const FDStream *);
Packit 8f70b4
   FileVerificator(const FileAccess *,const char *f);
Packit 8f70b4
   ~FileVerificator();
Packit 8f70b4
   int Do();
Packit 8f70b4
   bool Done() { return done; }
Packit 8f70b4
   bool Error() { return error_text!=0; }
Packit 8f70b4
   const char *ErrorText() { return error_text; }
Packit 8f70b4
   const char *Status() { return _("Verifying..."); };
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class FileCopyPeerFA : public FileCopyPeer
Packit 8f70b4
{
Packit 8f70b4
   xstring_c file;
Packit 8f70b4
   xstring orig_url;
Packit 8f70b4
   FileAccessRef my_session;
Packit 8f70b4
   FileAccessRefC session;
Packit 8f70b4
   int FAmode;
Packit 8f70b4
Packit 8f70b4
   int Get_LL(int size);
Packit 8f70b4
   int Put_LL(const char *buf,int size);
Packit 8f70b4
   int PutEOF_LL();
Packit 8f70b4
Packit 8f70b4
   // to read data in larger quantities, delay the read op
Packit 8f70b4
   Timer get_ll_timer;
Packit 8f70b4
   int get_delay;
Packit 8f70b4
Packit 8f70b4
   FileSet info;
Packit 8f70b4
Packit 8f70b4
   bool fxp;   // FXP (ftp<=>ftp copy) active
Packit 8f70b4
Packit 8f70b4
   UploadState upload_state;
Packit 8f70b4
   int redirections;
Packit 8f70b4
Packit 8f70b4
   SMTaskRef<FileVerificator> verify;
Packit 8f70b4
Packit 8f70b4
protected:
Packit 8f70b4
   void PrepareToDie();
Packit 8f70b4
   ~FileCopyPeerFA();
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   void Init();
Packit 8f70b4
   FileCopyPeerFA(FileAccess *s,const char *f,int m);
Packit 8f70b4
   FileCopyPeerFA(const FileAccessRef& s,const char *f,int m);
Packit 8f70b4
   FileCopyPeerFA(const class ParsedURL *u,int m);
Packit 8f70b4
   int Do();
Packit 8f70b4
   bool IOReady();
Packit 8f70b4
   off_t GetRealPos();
Packit 8f70b4
   void Seek(off_t new_pos);
Packit 8f70b4
Packit 8f70b4
   int Buffered() { return Size()+session->Buffered(); }
Packit 8f70b4
Packit 8f70b4
   void SuspendInternal();
Packit 8f70b4
   void ResumeInternal();
Packit 8f70b4
Packit 8f70b4
   const char *GetStatus();
Packit 8f70b4
   const char *GetProto() const { return session->GetProto(); }
Packit 8f70b4
Packit 8f70b4
   bool NeedSizeDateBeforehand() { return session->NeedSizeDateBeforehand(); }
Packit 8f70b4
   void WantSize();
Packit 8f70b4
   void RemoveFile();
Packit 8f70b4
Packit 8f70b4
   static FileCopyPeerFA *New(FA *s,const char *url,int m);
Packit 8f70b4
   static FileCopyPeerFA *New(const FileAccessRef& s,const char *url,int m);
Packit 8f70b4
Packit 8f70b4
   void OpenSession();
Packit 8f70b4
   const FileAccessRef& GetSession() { return session; }
Packit 8f70b4
   void Fg() { session->SetPriority(1); }
Packit 8f70b4
   void Bg() { session->SetPriority(0); }
Packit 8f70b4
   void SetFXP(bool on) { fxp=on; }
Packit 8f70b4
Packit 8f70b4
   const char *GetDescriptionForLog()
Packit 8f70b4
      {
Packit 8f70b4
	 return orig_url ? orig_url : session->GetFileURL(file);
Packit 8f70b4
      }
Packit 8f70b4
   const char *GetURL() { return GetDescriptionForLog(); }
Packit 8f70b4
   FileCopyPeer *Clone();
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class FileCopyPeerFDStream : public FileCopyPeer
Packit 8f70b4
{
Packit 8f70b4
   Ref<FDStream> my_stream;
Packit 8f70b4
   const Ref<FDStream>& stream;
Packit 8f70b4
   off_t seek_base;
Packit 8f70b4
   Ref<Timer> put_ll_timer;
Packit 8f70b4
Packit 8f70b4
   int Get_LL(int size);
Packit 8f70b4
   int Put_LL(const char *buf,int size);
Packit 8f70b4
   void Seek_LL();
Packit 8f70b4
Packit 8f70b4
   int getfd();
Packit 8f70b4
Packit 8f70b4
   bool create_fg_data;
Packit 8f70b4
   bool need_seek;
Packit 8f70b4
   bool close_when_done;
Packit 8f70b4
Packit 8f70b4
   SMTaskRef<FileVerificator> verify;
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   void Init();
Packit 8f70b4
   FileCopyPeerFDStream(const Ref<FDStream>& o,dir_t m);
Packit 8f70b4
   FileCopyPeerFDStream(FDStream *o,dir_t m);
Packit 8f70b4
   int Do();
Packit 8f70b4
   bool IOReady();
Packit 8f70b4
   void Seek(off_t new_pos);
Packit 8f70b4
   FgData *GetFgData(bool fg);
Packit 8f70b4
   pid_t GetProcGroup() { return stream->GetProcGroup(); }
Packit 8f70b4
   void Kill(int sig);
Packit 8f70b4
Packit 8f70b4
   void DontCreateFgData() { create_fg_data=false; }
Packit 8f70b4
   void NeedSeek() { need_seek=true; }
Packit 8f70b4
   void CloseWhenDone() { close_when_done=true; }
Packit 8f70b4
   void WantSize();
Packit 8f70b4
   void RemoveFile();
Packit 8f70b4
   void SetBase(off_t b) { seek_base=b; }
Packit 8f70b4
Packit 8f70b4
   const char *GetStatus();
Packit 8f70b4
Packit 8f70b4
   static FileCopyPeerFDStream *NewPut(const char *file,bool cont=false);
Packit 8f70b4
   static FileCopyPeerFDStream *NewGet(const char *file);
Packit 8f70b4
Packit 8f70b4
   const char *GetDescriptionForLog()
Packit 8f70b4
      {
Packit 8f70b4
	 return stream->name;
Packit 8f70b4
      }
Packit 8f70b4
   const char *GetURL()
Packit 8f70b4
      {
Packit 8f70b4
	 return stream->full_name;
Packit 8f70b4
      }
Packit 8f70b4
   const Ref<FDStream>& GetLocal() const { return stream; }
Packit 8f70b4
   FileCopyPeer *Clone();
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class FileCopyPeerDirList : public FileCopyPeer
Packit 8f70b4
{
Packit 8f70b4
private:
Packit 8f70b4
   FileAccessRef session;
Packit 8f70b4
   SMTaskRef<DirList> dl;
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   FileCopyPeerDirList(FA *s,ArgV *v); // consumes s and v.
Packit 8f70b4
Packit 8f70b4
   int Do();
Packit 8f70b4
   void NoCache() { use_cache=false; if(dl) dl->UseCache(false); }
Packit 8f70b4
   void Fg() { session->SetPriority(1); }
Packit 8f70b4
   void Bg() { session->SetPriority(0); }
Packit 8f70b4
   const char *GetStatus() { return session->CurrentStatus(); }
Packit 8f70b4
   void UseColor(bool c=true) { if(dl) dl->UseColor(c); }
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class FileCopyPeerMemory : public FileCopyPeer
Packit 8f70b4
{
Packit 8f70b4
private:
Packit 8f70b4
   int max_size;
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   FileCopyPeerMemory(int m) : FileCopyPeer(PUT), max_size(m) {}
Packit 8f70b4
   FileCopyPeerMemory(const xstring& s) : FileCopyPeer(GET), max_size(0) {
Packit 8f70b4
      Put(s);
Packit 8f70b4
      PutEOF();
Packit 8f70b4
      size=s.length();
Packit 8f70b4
      pos=0;
Packit 8f70b4
   }
Packit 8f70b4
   int Do();
Packit 8f70b4
   bool Done() { return true; }
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
#endif