Blame src/buffer.cc

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
#include <config.h>
Packit 8f70b4
#include <errno.h>
Packit 8f70b4
#include "buffer.h"
Packit 8f70b4
#include "FileAccess.h"
Packit 8f70b4
#include "misc.h"
Packit 8f70b4
#include "trio.h"
Packit 8f70b4
#include "Speedometer.h"
Packit 8f70b4
#include "log.h"
Packit 8f70b4
Packit 8f70b4
#define BUFFER_INC	   (8*1024) // should be power of 2
Packit 8f70b4
Packit 8f70b4
const char *Buffer::Get() const
Packit 8f70b4
{
Packit 8f70b4
   if(Size()==0)
Packit 8f70b4
      return eof?0:"";
Packit 8f70b4
   return buffer+buffer_ptr;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::Get(const char **buf,int *size) const
Packit 8f70b4
{
Packit 8f70b4
   *size=Size();
Packit 8f70b4
   *buf=Get();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::GetSaved(const char **buf,int *size) const
Packit 8f70b4
{
Packit 8f70b4
   if(!save)
Packit 8f70b4
   {
Packit 8f70b4
      *size=0;
Packit 8f70b4
      *buf=0;
Packit 8f70b4
      return;
Packit 8f70b4
   }
Packit 8f70b4
   *buf=buffer;
Packit 8f70b4
   *size=buffer.length();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::SaveRollback(off_t p)
Packit 8f70b4
{
Packit 8f70b4
   pos=p;
Packit 8f70b4
   if(buffer_ptr
Packit 8f70b4
      save=false;
Packit 8f70b4
   if(!save)
Packit 8f70b4
      p=0;
Packit 8f70b4
   buffer.truncate(buffer_ptr=p);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::Allocate(int size)
Packit 8f70b4
{
Packit 8f70b4
   if(buffer_ptr>0 && Size()==0 && !save)
Packit 8f70b4
   {
Packit 8f70b4
      buffer.truncate(0);
Packit 8f70b4
      buffer_ptr=0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   size_t in_buffer_real=Size();
Packit 8f70b4
   /* disable data movement to beginning of the buffer, if:
Packit 8f70b4
      1. we save the data explicitly;
Packit 8f70b4
      2. we add more data than there is space in the beginning of the buffer
Packit 8f70b4
	 (because the probability of realloc is high anyway);
Packit 8f70b4
      3. the gap at beginning is smaller than the amount of data in the buffer
Packit 8f70b4
	 (because the penalty of data movement is high). */
Packit 8f70b4
   if(save || buffer_ptr
Packit 8f70b4
      in_buffer_real+=buffer_ptr;
Packit 8f70b4
Packit 8f70b4
   // could be round-robin, but this is easier
Packit 8f70b4
   if(buffer.length()>in_buffer_real)
Packit 8f70b4
   {
Packit 8f70b4
      buffer.nset(buffer+buffer_ptr,Size());
Packit 8f70b4
      buffer_ptr=0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   buffer.get_space2(in_buffer_real+size,BUFFER_INC);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::SaveMaxCheck(int size)
Packit 8f70b4
{
Packit 8f70b4
   if(save && buffer_ptr+size>save_max)
Packit 8f70b4
      save=false;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::Append(const char *buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   if(size==0)
Packit 8f70b4
      return;
Packit 8f70b4
Packit 8f70b4
   SaveMaxCheck(size);
Packit 8f70b4
   if(Size()==0 && buffer_ptr>0 && !save)
Packit 8f70b4
   {
Packit 8f70b4
      buffer.truncate(0);
Packit 8f70b4
      buffer_ptr=0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   memmove(GetSpace(size),buf,size);
Packit 8f70b4
   SpaceAdd(size);
Packit 8f70b4
}
Packit 8f70b4
void Buffer::Put(const char *buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   Append(buf,size);
Packit 8f70b4
   pos+=size;
Packit 8f70b4
}
Packit 8f70b4
void Buffer::Prepend(const char *buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   if(size==0)
Packit 8f70b4
      return;
Packit 8f70b4
   save=false;
Packit 8f70b4
   if(Size()==0)
Packit 8f70b4
   {
Packit 8f70b4
      memmove(GetSpace(size),buf,size);
Packit 8f70b4
      SpaceAdd(size);
Packit 8f70b4
      return;
Packit 8f70b4
   }
Packit 8f70b4
   if(buffer_ptr
Packit 8f70b4
   {
Packit 8f70b4
      Allocate(size-buffer_ptr);
Packit 8f70b4
      memmove(buffer.get_non_const()+size,buffer+buffer_ptr,Size());
Packit 8f70b4
      SpaceAdd(size-buffer_ptr);
Packit 8f70b4
      buffer_ptr=size;
Packit 8f70b4
   }
Packit 8f70b4
   memmove(buffer.get_non_const()+buffer_ptr-size,buf,size);
Packit 8f70b4
   buffer_ptr-=size;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::Format(const char *f,...)
Packit 8f70b4
{
Packit 8f70b4
   va_list v;
Packit 8f70b4
   va_start(v,f);
Packit 8f70b4
   vFormat(f, v);
Packit 8f70b4
   va_end(v);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::vFormat(const char *f, va_list v)
Packit 8f70b4
{
Packit 8f70b4
   int size=64;
Packit 8f70b4
   for(;;)
Packit 8f70b4
   {
Packit 8f70b4
      va_list tmp;
Packit 8f70b4
      VA_COPY(tmp,v);
Packit 8f70b4
      int res=vsnprintf(GetSpace(size), size, f, tmp);
Packit 8f70b4
      va_end(tmp);
Packit 8f70b4
      if(res>=0 && res
Packit 8f70b4
      {
Packit 8f70b4
	 SpaceAdd(res);
Packit 8f70b4
	 return;
Packit 8f70b4
      }
Packit 8f70b4
      if(res>size)   // some vsnprintf's return desired buffer size.
Packit 8f70b4
	 size=res+1;
Packit 8f70b4
      else
Packit 8f70b4
	 size*=2;
Packit 8f70b4
   }
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::Skip(int len)
Packit 8f70b4
{
Packit 8f70b4
   if(len>Size())
Packit 8f70b4
      len=Size();
Packit 8f70b4
   buffer_ptr+=len;
Packit 8f70b4
   pos+=len;
Packit 8f70b4
}
Packit 8f70b4
void Buffer::UnSkip(int len)
Packit 8f70b4
{
Packit 8f70b4
   if(len>buffer_ptr)
Packit 8f70b4
      len=buffer_ptr;
Packit 8f70b4
   buffer_ptr-=len;
Packit 8f70b4
   pos-=len;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::Empty()
Packit 8f70b4
{
Packit 8f70b4
   buffer.truncate(0);
Packit 8f70b4
   buffer_ptr=0;
Packit 8f70b4
   if(save_max>0)
Packit 8f70b4
      save=true;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
// move data from other buffer, prepare for SpaceAdd.
Packit 8f70b4
int Buffer::MoveDataHere(Buffer *o,int max_len)
Packit 8f70b4
{
Packit 8f70b4
   const char *b;
Packit 8f70b4
   int size;
Packit 8f70b4
   o->Get(&b,&size);
Packit 8f70b4
   if(size>max_len)
Packit 8f70b4
      size=max_len;
Packit 8f70b4
   if(size>0) {
Packit 8f70b4
      if(size>=64 && Size()==0 && o->Size()==size && !save && !o->save) {
Packit 8f70b4
	 // optimization by swapping buffers
Packit 8f70b4
	 buffer.swap(o->buffer);
Packit 8f70b4
	 buffer_ptr=replace_value(o->buffer_ptr,buffer_ptr);
Packit 8f70b4
	 buffer.set_length_no_z(buffer_ptr);
Packit 8f70b4
	 o->pos+=size;
Packit 8f70b4
      } else {
Packit 8f70b4
	 memcpy(GetSpace(size),b,size);
Packit 8f70b4
	 o->Skip(size);
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   return size;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Buffer::Buffer()
Packit 8f70b4
{
Packit 8f70b4
   saved_errno=0;
Packit 8f70b4
   error_fatal=false;
Packit 8f70b4
   buffer_ptr=0;
Packit 8f70b4
   eof=false;
Packit 8f70b4
   broken=false;
Packit 8f70b4
   save=false;
Packit 8f70b4
   save_max=0;
Packit 8f70b4
   pos=0;
Packit 8f70b4
}
Packit 8f70b4
Buffer::~Buffer()
Packit 8f70b4
{
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
const char *Buffer::GetRateStrS()
Packit 8f70b4
{
Packit 8f70b4
   if(!rate || !rate->Valid())
Packit 8f70b4
      return "";
Packit 8f70b4
   return rate->GetStrS();
Packit 8f70b4
}
Packit 8f70b4
void Buffer::RateAdd(int n)
Packit 8f70b4
{
Packit 8f70b4
   if(!rate)
Packit 8f70b4
      return;
Packit 8f70b4
   rate->Add(n);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Buffer::SetError(const char *e,bool fatal)
Packit 8f70b4
{
Packit 8f70b4
   error_text.set(e);
Packit 8f70b4
   error_fatal=fatal;
Packit 8f70b4
}
Packit 8f70b4
void Buffer::SetErrorCached(const char *e)
Packit 8f70b4
{
Packit 8f70b4
   SetError(e,false);
Packit 8f70b4
   error_text.append(_(" [cached]"));
Packit 8f70b4
}
Packit 8f70b4
const char *Buffer::Dump() const
Packit 8f70b4
{
Packit 8f70b4
   if(buffer_ptr==0)
Packit 8f70b4
      return buffer.dump();
Packit 8f70b4
   return xstring::get_tmp(Get(),Size()).dump();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void DataTranslator::AppendTranslated(Buffer *target,const char *put_buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   off_t old_pos=target->GetPos();
Packit 8f70b4
   PutTranslated(target,put_buf,size);
Packit 8f70b4
   target->SetPos(old_pos);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void DirectedBuffer::SetTranslator(DataTranslator *t)
Packit 8f70b4
{
Packit 8f70b4
   if(mode==GET && !translator && Size()>0) {
Packit 8f70b4
      // translate unread data
Packit 8f70b4
      const char *data;
Packit 8f70b4
      int len;
Packit 8f70b4
      Get(&data,&len;;
Packit 8f70b4
      t->Put(data,len);
Packit 8f70b4
      buffer.truncate(buffer_ptr);
Packit 8f70b4
      t->AppendTranslated(this,0,0);
Packit 8f70b4
   }
Packit 8f70b4
   translator=t;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#ifdef HAVE_ICONV
Packit 8f70b4
void DataRecoder::PutTranslated(Buffer *target,const char *put_buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   bool from_untranslated=false;
Packit 8f70b4
   if(Size()>0)
Packit 8f70b4
   {
Packit 8f70b4
      Put(put_buf,size);
Packit 8f70b4
      Get(&put_buf,&size);
Packit 8f70b4
      from_untranslated=true;
Packit 8f70b4
   }
Packit 8f70b4
   if(size<=0)
Packit 8f70b4
      return;
Packit 8f70b4
   if(!backend_translate)
Packit 8f70b4
   {
Packit 8f70b4
      target->Put(put_buf,size);
Packit 8f70b4
      if(from_untranslated)
Packit 8f70b4
	 Skip(size);
Packit 8f70b4
      return;
Packit 8f70b4
   }
Packit 8f70b4
   size_t put_size=size;
Packit 8f70b4
Packit 8f70b4
   int size_coeff=6;
Packit 8f70b4
try_again:
Packit 8f70b4
   if(put_size==0)
Packit 8f70b4
      return;
Packit 8f70b4
   size_t store_size=size_coeff*put_size;
Packit 8f70b4
   char *store_space=target->GetSpace(store_size);
Packit 8f70b4
   char *store_buf=store_space;
Packit 8f70b4
   const char *base_buf=put_buf;
Packit 8f70b4
   // do the translation
Packit 8f70b4
   ICONV_CONST char **put_buf_ptr=const_cast<ICONV_CONST char**>(&put_buf);
Packit 8f70b4
   size_t res=iconv(backend_translate,put_buf_ptr,&put_size,&store_buf,&store_size);
Packit 8f70b4
   target->SpaceAdd(store_buf-store_space);
Packit 8f70b4
   if(from_untranslated)
Packit 8f70b4
      Skip(put_buf-base_buf);
Packit 8f70b4
   if(res==(size_t)-1)
Packit 8f70b4
   {
Packit 8f70b4
      switch(errno)
Packit 8f70b4
      {
Packit 8f70b4
      case EINVAL: // incomplete character
Packit 8f70b4
	 if(!from_untranslated)
Packit 8f70b4
	    Put(put_buf,put_size);
Packit 8f70b4
	 break;
Packit 8f70b4
      case EILSEQ: // invalid character
Packit 8f70b4
	 target->Put("?");
Packit 8f70b4
	 put_buf++;
Packit 8f70b4
	 put_size--;
Packit 8f70b4
	 goto try_again;
Packit 8f70b4
      case E2BIG:  // no room to store result, allocate more.
Packit 8f70b4
	 size_coeff*=2;
Packit 8f70b4
	 goto try_again;
Packit 8f70b4
      default:
Packit 8f70b4
	 break;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   return;
Packit 8f70b4
}
Packit 8f70b4
void DataRecoder::ResetTranslation()
Packit 8f70b4
{
Packit 8f70b4
   Empty();
Packit 8f70b4
   if(!backend_translate)
Packit 8f70b4
      return;
Packit 8f70b4
   iconv(backend_translate,0,0,0,0);
Packit 8f70b4
}
Packit 8f70b4
DataRecoder::~DataRecoder()
Packit 8f70b4
{
Packit 8f70b4
   if(backend_translate)
Packit 8f70b4
      iconv_close(backend_translate);
Packit 8f70b4
}
Packit 8f70b4
DataRecoder::DataRecoder(const char *from_code,const char *to_code,bool translit)
Packit 8f70b4
{
Packit 8f70b4
   backend_translate=0;
Packit 8f70b4
Packit 8f70b4
   if(translit) {
Packit 8f70b4
      const char *to_code_translit=xstring::cat(to_code,"//TRANSLIT",NULL);
Packit 8f70b4
      backend_translate=iconv_open(to_code_translit,from_code);
Packit 8f70b4
      if(backend_translate!=(iconv_t)-1) {
Packit 8f70b4
	 Log::global->Format(9,"initialized translation from %s to %s\n",from_code,to_code_translit);
Packit 8f70b4
	 return;
Packit 8f70b4
      }
Packit 8f70b4
      backend_translate=0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   backend_translate=iconv_open(to_code,from_code);
Packit 8f70b4
   if(backend_translate!=(iconv_t)-1) {
Packit 8f70b4
      Log::global->Format(9,"initialized translation from %s to %s\n",from_code,to_code);
Packit 8f70b4
      return;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   Log::global->Format(0,"iconv_open(%s,%s) failed: %s\n",
Packit 8f70b4
			      to_code,from_code,strerror(errno));
Packit 8f70b4
   backend_translate=0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void DirectedBuffer::SetTranslation(const char *enc,bool translit)
Packit 8f70b4
{
Packit 8f70b4
   if(!enc || !*enc)
Packit 8f70b4
      return;
Packit 8f70b4
   const char *local_code=ResMgr::Query("file:charset",0);
Packit 8f70b4
   if(!local_code || !*local_code)
Packit 8f70b4
      return;
Packit 8f70b4
   const char *from_code=(mode==GET?enc:local_code);
Packit 8f70b4
   const char *to_code  =(mode==GET?local_code:enc);
Packit 8f70b4
   if(!strcasecmp(from_code,to_code))
Packit 8f70b4
      return;
Packit 8f70b4
   SetTranslator(new DataRecoder(from_code,to_code,translit));
Packit 8f70b4
}
Packit 8f70b4
#endif //HAVE_ICONV
Packit 8f70b4
Packit 8f70b4
void DirectedBuffer::ResetTranslation()
Packit 8f70b4
{
Packit 8f70b4
   if(translator)
Packit 8f70b4
      translator->ResetTranslation();
Packit 8f70b4
}
Packit 8f70b4
void DirectedBuffer::Put(const char *buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   if(mode==PUT && translator)
Packit 8f70b4
      translator->PutTranslated(this,buf,size);
Packit 8f70b4
   else
Packit 8f70b4
      Buffer::Put(buf,size);
Packit 8f70b4
}
Packit 8f70b4
void DirectedBuffer::PutTranslated(const char *buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   if(translator)
Packit 8f70b4
      translator->PutTranslated(this,buf,size);
Packit 8f70b4
   else
Packit 8f70b4
      Buffer::Put(buf,size);
Packit 8f70b4
}
Packit 8f70b4
int DirectedBuffer::MoveDataHere(Buffer *buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   if(size>buf->Size())
Packit 8f70b4
      size=buf->Size();
Packit 8f70b4
   if(mode==PUT && translator)
Packit 8f70b4
      translator->PutTranslated(this,buf->Get(),size);
Packit 8f70b4
   else
Packit 8f70b4
      return Buffer::MoveDataHere(buf,size);
Packit 8f70b4
   return size;
Packit 8f70b4
}
Packit 8f70b4
void DirectedBuffer::PutEOF()
Packit 8f70b4
{
Packit 8f70b4
   if(mode==PUT && translator)
Packit 8f70b4
      translator->PutTranslated(this,0,0);
Packit 8f70b4
   Buffer::PutEOF();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void DirectedBuffer::EmbraceNewData(int len)
Packit 8f70b4
{
Packit 8f70b4
   if(len<=0)
Packit 8f70b4
      return;
Packit 8f70b4
   RateAdd(len);
Packit 8f70b4
   if(translator)
Packit 8f70b4
   {
Packit 8f70b4
      // copy the data to free room for translated data
Packit 8f70b4
      translator->Put(buffer+buffer.length(),len);
Packit 8f70b4
      translator->AppendTranslated(this,0,0);
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
      SpaceAdd(len);
Packit 8f70b4
   SaveMaxCheck(0);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
IOBuffer::IOBuffer(dir_t m)
Packit 8f70b4
   : DirectedBuffer(m), event_time(now),
Packit 8f70b4
     max_buf(0), get_size(GET_BUFSIZE)
Packit 8f70b4
{
Packit 8f70b4
}
Packit 8f70b4
IOBuffer::~IOBuffer()
Packit 8f70b4
{
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void IOBuffer::Put(const char *buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   if(size>=PUT_LL_MIN && Size()==0 && mode==PUT && !save && !translator)
Packit 8f70b4
   {
Packit 8f70b4
      int res=Put_LL(buf,size);
Packit 8f70b4
      if(res>=0)
Packit 8f70b4
      {
Packit 8f70b4
	 buf+=res;
Packit 8f70b4
	 size-=res;
Packit 8f70b4
	 pos+=res;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   if(size<=0)
Packit 8f70b4
      return;
Packit 8f70b4
   if(Size()==0)
Packit 8f70b4
      current->Timeout(0);
Packit 8f70b4
   DirectedBuffer::Put(buf,size);
Packit 8f70b4
}
Packit 8f70b4
void IOBuffer::Put(const char *buf)
Packit 8f70b4
{
Packit 8f70b4
   Put(buf,strlen(buf));
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int IOBuffer::TuneGetSize(int res)
Packit 8f70b4
{
Packit 8f70b4
   if(res>0)
Packit 8f70b4
   {
Packit 8f70b4
      // buffer size tuning depending on data rate
Packit 8f70b4
      const int max_get_size=(max_buf?max_buf:0x100000);
Packit 8f70b4
      if(res>get_size/2 && Size()+get_size*2<=max_get_size)
Packit 8f70b4
	 get_size*=2;
Packit 8f70b4
   }
Packit 8f70b4
   return res;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int IOBuffer::Do()
Packit 8f70b4
{
Packit 8f70b4
   if(Done() || Error())
Packit 8f70b4
      return STALL;
Packit 8f70b4
   int res=0;
Packit 8f70b4
   switch(mode)
Packit 8f70b4
   {
Packit 8f70b4
   case PUT:
Packit 8f70b4
      if(Size()==0)
Packit 8f70b4
	 return STALL;
Packit 8f70b4
      res=Put_LL(buffer+buffer_ptr,Size());
Packit 8f70b4
      if(res>0)
Packit 8f70b4
      {
Packit 8f70b4
	 RateAdd(res);
Packit 8f70b4
	 buffer_ptr+=res;
Packit 8f70b4
	 event_time=now;
Packit 8f70b4
	 if(eof)
Packit 8f70b4
	    PutEOF_LL();
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      break;
Packit 8f70b4
Packit 8f70b4
   case GET:
Packit 8f70b4
      if(eof)
Packit 8f70b4
	 return STALL;
Packit 8f70b4
      res=TuneGetSize(Get_LL(get_size));
Packit 8f70b4
      if(res>0)
Packit 8f70b4
      {
Packit 8f70b4
	 EmbraceNewData(res);
Packit 8f70b4
	 event_time=now;
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      if(eof)
Packit 8f70b4
      {
Packit 8f70b4
	 event_time=now;
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      break;
Packit 8f70b4
   }
Packit 8f70b4
   if(res<0)
Packit 8f70b4
   {
Packit 8f70b4
      event_time=now;
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
   return STALL;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
// IOBufferStacked implementation
Packit 8f70b4
#undef super
Packit 8f70b4
#define super IOBuffer
Packit 8f70b4
int IOBufferStacked::Do()
Packit 8f70b4
{
Packit 8f70b4
   int m=STALL;
Packit 8f70b4
   if(Done() || Error())
Packit 8f70b4
      return m;
Packit 8f70b4
   int res=0;
Packit 8f70b4
   switch(mode)
Packit 8f70b4
   {
Packit 8f70b4
   case PUT:
Packit 8f70b4
      if(down->Broken() && !broken)
Packit 8f70b4
      {
Packit 8f70b4
	 broken=true;
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      if(down->Error())
Packit 8f70b4
      {
Packit 8f70b4
	 SetError(down->ErrorText(),down->ErrorFatal());
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      if(Size()==0)
Packit 8f70b4
	 return m;
Packit 8f70b4
      res=Put_LL(buffer+buffer_ptr,Size());
Packit 8f70b4
      if(res>0)
Packit 8f70b4
      {
Packit 8f70b4
	 buffer_ptr+=res;
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      break;
Packit 8f70b4
Packit 8f70b4
   case GET:
Packit 8f70b4
      if(eof)
Packit 8f70b4
	 return m;
Packit 8f70b4
      res=Get_LL(/*unused*/0);
Packit 8f70b4
      if(res>0)
Packit 8f70b4
      {
Packit 8f70b4
	 EmbraceNewData(res);
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      if(eof)
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
      if(down->Error())
Packit 8f70b4
      {
Packit 8f70b4
	 SetError(down->ErrorText(),down->ErrorFatal());
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      break;
Packit 8f70b4
   }
Packit 8f70b4
   if(res<0)
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   return m;
Packit 8f70b4
}
Packit 8f70b4
int IOBufferStacked::Put_LL(const char *buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   if(down->Broken())
Packit 8f70b4
   {
Packit 8f70b4
      broken=true;
Packit 8f70b4
      return -1;
Packit 8f70b4
   }
Packit 8f70b4
   down->Put(buf,size);
Packit 8f70b4
   return size;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int IOBufferStacked::Get_LL(int)
Packit 8f70b4
{
Packit 8f70b4
   if(max_buf && Size()>=max_buf) {
Packit 8f70b4
      down->SuspendSlave();
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   down->ResumeSlave();
Packit 8f70b4
   int size=MoveDataHere(down,down->Size());
Packit 8f70b4
   if(down->Size()==0 && down->Eof())
Packit 8f70b4
      PutEOF();
Packit 8f70b4
   return size;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
bool IOBufferStacked::Done()
Packit 8f70b4
{
Packit 8f70b4
   if(super::Done())
Packit 8f70b4
      return down->Done();
Packit 8f70b4
   return false;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void IOBufferStacked::SuspendInternal()
Packit 8f70b4
{
Packit 8f70b4
   super::SuspendInternal();
Packit 8f70b4
   down->SuspendSlave();
Packit 8f70b4
}
Packit 8f70b4
void IOBufferStacked::ResumeInternal()
Packit 8f70b4
{
Packit 8f70b4
   if(!max_buf || Size()
Packit 8f70b4
      down->ResumeSlave();
Packit 8f70b4
   super::ResumeInternal();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
// IOBufferFDStream implementation
Packit 8f70b4
#include <fcntl.h>
Packit 8f70b4
#include <unistd.h>
Packit 8f70b4
#undef super
Packit 8f70b4
#define super IOBuffer
Packit 8f70b4
int IOBufferFDStream::Put_LL(const char *buf,int size)
Packit 8f70b4
{
Packit 8f70b4
   if(put_ll_timer && !eof && Size()
Packit 8f70b4
   && !put_ll_timer->Stopped())
Packit 8f70b4
      return 0;
Packit 8f70b4
   if(stream->broken())
Packit 8f70b4
   {
Packit 8f70b4
      broken=true;
Packit 8f70b4
      return -1;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   int res=0;
Packit 8f70b4
Packit 8f70b4
   int fd=stream->getfd();
Packit 8f70b4
   if(fd==-1)
Packit 8f70b4
   {
Packit 8f70b4
      if(stream->error())
Packit 8f70b4
	 goto stream_err;
Packit 8f70b4
      TimeoutS(1);
Packit 8f70b4
      event_time=now;
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   res=write(fd,buf,size);
Packit 8f70b4
   if(res==-1)
Packit 8f70b4
   {
Packit 8f70b4
      saved_errno=errno;
Packit 8f70b4
      if(E_RETRY(saved_errno))
Packit 8f70b4
      {
Packit 8f70b4
	 Block(fd,POLLOUT);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      if(NonFatalError(saved_errno))
Packit 8f70b4
	 return 0;
Packit 8f70b4
      if(errno==EPIPE)
Packit 8f70b4
      {
Packit 8f70b4
	 broken=true;
Packit 8f70b4
	 return -1;
Packit 8f70b4
      }
Packit 8f70b4
      stream->MakeErrorText(saved_errno);
Packit 8f70b4
      goto stream_err;
Packit 8f70b4
   }
Packit 8f70b4
   if(put_ll_timer)
Packit 8f70b4
      put_ll_timer->Reset();
Packit 8f70b4
   return res;
Packit 8f70b4
Packit 8f70b4
stream_err:
Packit 8f70b4
   SetError(stream->error_text,!TemporaryNetworkError(saved_errno));
Packit 8f70b4
   return -1;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int IOBufferFDStream::Get_LL(int size)
Packit 8f70b4
{
Packit 8f70b4
   if(max_buf && Size()>=max_buf)
Packit 8f70b4
      return 0;
Packit 8f70b4
Packit 8f70b4
   int res=0;
Packit 8f70b4
Packit 8f70b4
   int fd=stream->getfd();
Packit 8f70b4
   if(fd==-1)
Packit 8f70b4
   {
Packit 8f70b4
      if(stream->error())
Packit 8f70b4
	 goto stream_err;
Packit 8f70b4
      TimeoutS(1);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(!Ready(fd,POLLIN))
Packit 8f70b4
   {
Packit 8f70b4
      Block(fd,POLLIN);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   res=read(fd,GetSpace(size),size);
Packit 8f70b4
   if(res==-1)
Packit 8f70b4
   {
Packit 8f70b4
      saved_errno=errno;
Packit 8f70b4
      if(E_RETRY(saved_errno))
Packit 8f70b4
      {
Packit 8f70b4
	 SetNotReady(fd,POLLIN);
Packit 8f70b4
	 Block(fd,POLLIN);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      if(NonFatalError(saved_errno))
Packit 8f70b4
	 return 0;
Packit 8f70b4
      stream->MakeErrorText(saved_errno);
Packit 8f70b4
      goto stream_err;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(res==0) {
Packit 8f70b4
      Log::global->Format(10,"buffer: EOF on FD %d\n",fd);
Packit 8f70b4
      eof=true;
Packit 8f70b4
   }
Packit 8f70b4
   return res;
Packit 8f70b4
Packit 8f70b4
stream_err:
Packit 8f70b4
   SetError(stream->error_text,!TemporaryNetworkError(saved_errno));
Packit 8f70b4
   return -1;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
FgData *IOBufferFDStream::GetFgData(bool fg)
Packit 8f70b4
{
Packit 8f70b4
   if(stream->getfd()!=-1)
Packit 8f70b4
      return new FgData(stream->GetProcGroup(),fg);
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
bool IOBufferFDStream::Done()
Packit 8f70b4
{
Packit 8f70b4
   if(put_ll_timer)
Packit 8f70b4
      put_ll_timer->Stop();
Packit 8f70b4
   if(super::Done())
Packit 8f70b4
      return stream->Done(); // stream->Done indicates if sub-process finished
Packit 8f70b4
   return false;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
IOBufferFDStream::~IOBufferFDStream() {}
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
// IOBufferFileAccess implementation
Packit 8f70b4
#undef super
Packit 8f70b4
#define super IOBuffer
Packit 8f70b4
int IOBufferFileAccess::Get_LL(int size)
Packit 8f70b4
{
Packit 8f70b4
   if(max_buf && Size()>=max_buf) {
Packit 8f70b4
      session->SuspendSlave();
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   session->ResumeSlave();
Packit 8f70b4
Packit 8f70b4
   int res=0;
Packit 8f70b4
Packit 8f70b4
   res=session->Read(this,size);
Packit 8f70b4
   if(res<0)
Packit 8f70b4
   {
Packit 8f70b4
      if(res==FA::DO_AGAIN)
Packit 8f70b4
	 return 0;
Packit 8f70b4
      SetError(session->StrError(res));
Packit 8f70b4
      return -1;
Packit 8f70b4
   }
Packit 8f70b4
   if(res==0)
Packit 8f70b4
      eof=true;
Packit 8f70b4
   return res;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void IOBufferFileAccess::SuspendInternal()
Packit 8f70b4
{
Packit 8f70b4
   super::SuspendInternal();
Packit 8f70b4
   session->SuspendSlave();
Packit 8f70b4
}
Packit 8f70b4
void IOBufferFileAccess::ResumeInternal()
Packit 8f70b4
{
Packit 8f70b4
   if(!max_buf || Size()
Packit 8f70b4
      session->ResumeSlave();
Packit 8f70b4
   super::ResumeInternal();
Packit 8f70b4
}
Packit 8f70b4
const char *IOBufferFileAccess::Status()
Packit 8f70b4
{
Packit 8f70b4
   return session->CurrentStatus();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
unsigned long long Buffer::UnpackUINT64BE(int offset) const
Packit 8f70b4
{
Packit 8f70b4
   if(Size()-offset<8)
Packit 8f70b4
      return 0;
Packit 8f70b4
   unsigned long long res=UnpackUINT32BE(offset);
Packit 8f70b4
   res=(res<<32)|UnpackUINT32BE(offset+4);
Packit 8f70b4
   return res;
Packit 8f70b4
}
Packit 8f70b4
long long Buffer::UnpackINT64BE(int offset) const
Packit 8f70b4
{
Packit 8f70b4
   unsigned long long n=UnpackUINT64BE(offset);
Packit 8f70b4
   if(n&0x8000000000000000ULL)
Packit 8f70b4
      return -(long long)(n^0xFFFFFFFFFFFFFFFFULL)-1;
Packit 8f70b4
   return (long long)n;
Packit 8f70b4
}
Packit 8f70b4
unsigned Buffer::UnpackUINT32BE(int offset) const
Packit 8f70b4
{
Packit 8f70b4
   if(Size()-offset<4)
Packit 8f70b4
      return 0;
Packit 8f70b4
   unsigned char *b=(unsigned char*)buffer.get()+buffer_ptr+offset;
Packit 8f70b4
   return (b[0]<<24)|(b[1]<<16)|(b[2]<<8)|b[3];
Packit 8f70b4
}
Packit 8f70b4
int Buffer::UnpackINT32BE(int offset) const
Packit 8f70b4
{
Packit 8f70b4
   unsigned n=UnpackUINT32BE(offset);
Packit 8f70b4
   if(n&0x80000000U)
Packit 8f70b4
      return -(int)(n^0xFFFFFFFFU)-1;
Packit 8f70b4
   return (int)n;
Packit 8f70b4
}
Packit 8f70b4
unsigned Buffer::UnpackUINT16BE(int offset) const
Packit 8f70b4
{
Packit 8f70b4
   if(Size()-offset<2)
Packit 8f70b4
      return 0;
Packit 8f70b4
   unsigned char *b=(unsigned char*)buffer.get()+buffer_ptr+offset;
Packit 8f70b4
   return (b[0]<<8)|b[1];
Packit 8f70b4
}
Packit 8f70b4
unsigned Buffer::UnpackUINT8(int offset) const
Packit 8f70b4
{
Packit 8f70b4
   if(Size()-offset<1)
Packit 8f70b4
      return 0;
Packit 8f70b4
   unsigned char *b=(unsigned char*)buffer.get()+buffer_ptr+offset;
Packit 8f70b4
   return b[0];
Packit 8f70b4
}
Packit 8f70b4
void Buffer::PackUINT64BE(unsigned long long data)
Packit 8f70b4
{
Packit 8f70b4
#ifndef NDEBUG
Packit 8f70b4
   Log::global->Format(11,"PackUINT64BE(0x%016llX)\n",data);
Packit 8f70b4
#endif
Packit 8f70b4
   Allocate(8);
Packit 8f70b4
   PackUINT32BE((unsigned)(data>>32));
Packit 8f70b4
   PackUINT32BE((unsigned)(data&0xFFFFFFFFU));
Packit 8f70b4
}
Packit 8f70b4
void Buffer::PackINT64BE(long long data)
Packit 8f70b4
{
Packit 8f70b4
   unsigned long long n;
Packit 8f70b4
   if(data<0)
Packit 8f70b4
      n=((unsigned long long)(-data)^0xFFFFFFFFFFFFFFFFULL)+1;
Packit 8f70b4
   else
Packit 8f70b4
      n=(unsigned long long)data;
Packit 8f70b4
   PackUINT64BE(n);
Packit 8f70b4
}
Packit 8f70b4
void Buffer::PackUINT32BE(unsigned data)
Packit 8f70b4
{
Packit 8f70b4
#ifndef NDEBUG
Packit 8f70b4
   Log::global->Format(11,"PackUINT32BE(0x%08X)\n",data);
Packit 8f70b4
#endif
Packit 8f70b4
   char *b=GetSpace(4);
Packit 8f70b4
   b[0]=(data>>24)&255;
Packit 8f70b4
   b[1]=(data>>16)&255;
Packit 8f70b4
   b[2]=(data>>8)&255;
Packit 8f70b4
   b[3]=(data)&255;
Packit 8f70b4
   SpaceAdd(4);
Packit 8f70b4
}
Packit 8f70b4
void Buffer::PackINT32BE(int data)
Packit 8f70b4
{
Packit 8f70b4
   unsigned n;
Packit 8f70b4
   if(data<0)
Packit 8f70b4
      n=((unsigned)(-data)^0xFFFFFFFFU)+1;
Packit 8f70b4
   else
Packit 8f70b4
      n=(unsigned)data;
Packit 8f70b4
   PackUINT32BE(n);
Packit 8f70b4
}
Packit 8f70b4
void Buffer::PackUINT16BE(unsigned data)
Packit 8f70b4
{
Packit 8f70b4
   char *b=GetSpace(2);
Packit 8f70b4
   b[0]=(data>>8)&255;
Packit 8f70b4
   b[1]=(data)&255;
Packit 8f70b4
   SpaceAdd(2);
Packit 8f70b4
}
Packit 8f70b4
void Buffer::PackUINT8(unsigned data)
Packit 8f70b4
{
Packit 8f70b4
#ifndef NDEBUG
Packit 8f70b4
   Log::global->Format(11,"PackUINT8(0x%02X)\n",data);
Packit 8f70b4
#endif
Packit 8f70b4
   char *b=GetSpace(1);
Packit 8f70b4
   b[0]=(data)&255;
Packit 8f70b4
   SpaceAdd(1);
Packit 8f70b4
}