Blame src/FtpDirList.cc

Packit Service a2489d
/*
Packit Service a2489d
 * lftp - file transfer program
Packit Service a2489d
 *
Packit Service a2489d
 * Copyright (c) 1996-2013 by Alexander V. Lukyanov (lav@yars.free.net)
Packit Service a2489d
 *
Packit Service a2489d
 * This program is free software; you can redistribute it and/or modify
Packit Service a2489d
 * it under the terms of the GNU General Public License as published by
Packit Service a2489d
 * the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
 * (at your option) any later version.
Packit Service a2489d
 *
Packit Service a2489d
 * This program is distributed in the hope that it will be useful,
Packit Service a2489d
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
 * GNU General Public License for more details.
Packit Service a2489d
 *
Packit Service a2489d
 * You should have received a copy of the GNU General Public License
Packit Service a2489d
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service a2489d
 */
Packit Service a2489d
Packit Service a2489d
#include <config.h>
Packit Service a2489d
Packit Service a2489d
#include "FileAccess.h"
Packit Service a2489d
#include "FtpDirList.h"
Packit Service a2489d
#include "LsCache.h"
Packit Service a2489d
#include "ArgV.h"
Packit Service a2489d
#include "misc.h"
Packit Service a2489d
#include "DirColors.h"
Packit Service a2489d
#include "ftpclass.h"
Packit Service a2489d
Packit Service a2489d
#include <sys/types.h>
Packit Service a2489d
#include <time.h>
Packit Service a2489d
#ifdef TM_IN_SYS_TIME
Packit Service a2489d
# include <sys/time.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#define super DirList
Packit Service a2489d
Packit Service a2489d
int FtpDirList::Do()
Packit Service a2489d
{
Packit Service a2489d
   int m=STALL;
Packit Service a2489d
Packit Service a2489d
   if(done)
Packit Service a2489d
      return m;
Packit Service a2489d
Packit Service a2489d
   if(buf->Eof())
Packit Service a2489d
   {
Packit Service a2489d
      done=true;
Packit Service a2489d
      return MOVED;
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   if(!ubuf)
Packit Service a2489d
   {
Packit Service a2489d
      const char *cache_buffer=0;
Packit Service a2489d
      int cache_buffer_size=0;
Packit Service a2489d
      int err;
Packit Service a2489d
      if(use_cache && FileAccess::cache->Find(session,pattern,FA::LONG_LIST,&err,
Packit Service a2489d
				    &cache_buffer,&cache_buffer_size))
Packit Service a2489d
      {
Packit Service a2489d
	 if(err)
Packit Service a2489d
	 {
Packit Service a2489d
	    SetErrorCached(cache_buffer);
Packit Service a2489d
	    return MOVED;
Packit Service a2489d
	 }
Packit Service a2489d
	 ubuf=new IOBuffer(IOBuffer::GET);
Packit Service a2489d
	 ubuf->Put(cache_buffer,cache_buffer_size);
Packit Service a2489d
	 ubuf->PutEOF();
Packit Service a2489d
      }
Packit Service a2489d
      else
Packit Service a2489d
      {
Packit Service a2489d
	 session->Open(pattern,FA::LONG_LIST);
Packit Service a2489d
	 ubuf=new IOBufferFileAccess(session);
Packit Service a2489d
	 if(FileAccess::cache->IsEnabled(session->GetHostName()))
Packit Service a2489d
	    ubuf->Save(FileAccess::cache->SizeLimit());
Packit Service a2489d
      }
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   const char *b;
Packit Service a2489d
   int len;
Packit Service a2489d
   ubuf->Get(&b,&len;;
Packit Service a2489d
   if(b==0) // eof
Packit Service a2489d
   {
Packit Service a2489d
      buf->PutEOF();
Packit Service a2489d
      FileAccess::cache->Add(session,pattern,FA::LONG_LIST,FA::OK,ubuf);
Packit Service a2489d
      return MOVED;
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   while(len>0)
Packit Service a2489d
   {
Packit Service a2489d
      const char *eol=find_char(b,len,'\n');
Packit Service a2489d
      if(!eol && !ubuf->Eof() && len<0x1000)
Packit Service a2489d
	 break;
Packit Service a2489d
      if(eol)
Packit Service a2489d
      {
Packit Service a2489d
	 int line_len=eol+1-b;
Packit Service a2489d
	 if(!TryEPLF(b, eol-b)
Packit Service a2489d
	 && !TryMLSD(b, eol-b)
Packit Service a2489d
	 && !TryColor(b, eol-b))
Packit Service a2489d
	    buf->Put(b,line_len);
Packit Service a2489d
	 ubuf->Skip(line_len);
Packit Service a2489d
      }
Packit Service a2489d
      else
Packit Service a2489d
      {
Packit Service a2489d
	 // too long line of missing \n on last line.
Packit Service a2489d
	 buf->Put(b,len);
Packit Service a2489d
	 ubuf->Skip(len);
Packit Service a2489d
      }
Packit Service a2489d
      ubuf->Get(&b,&len;;
Packit Service a2489d
      m=MOVED;
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   if(ubuf->Error())
Packit Service a2489d
   {
Packit Service a2489d
      SetError(ubuf->ErrorText());
Packit Service a2489d
      m=MOVED;
Packit Service a2489d
   }
Packit Service a2489d
   return m;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *FtpDirList::Status()
Packit Service a2489d
{
Packit Service a2489d
   if(ubuf && !ubuf->Eof() && session->IsOpen())
Packit Service a2489d
   {
Packit Service a2489d
      return xstring::format(_("Getting file list (%lld) [%s]"),
Packit Service a2489d
		     (long long)session->GetPos(),session->CurrentStatus());
Packit Service a2489d
   }
Packit Service a2489d
   return "";
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void FtpDirList::SuspendInternal()
Packit Service a2489d
{
Packit Service a2489d
   super::SuspendInternal();
Packit Service a2489d
   if(ubuf)
Packit Service a2489d
      ubuf->SuspendSlave();
Packit Service a2489d
}
Packit Service a2489d
void FtpDirList::ResumeInternal()
Packit Service a2489d
{
Packit Service a2489d
   if(ubuf)
Packit Service a2489d
      ubuf->ResumeSlave();
Packit Service a2489d
   super::ResumeInternal();
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void FtpDirList::FormatGeneric(FileInfo *fi)
Packit Service a2489d
{
Packit Service a2489d
   bool dir=(fi->defined&fi->TYPE) && fi->filetype==fi->DIRECTORY;
Packit Service a2489d
   if(!(fi->defined&fi->MODE))
Packit Service a2489d
      fi->mode=(dir?0755:0644);
Packit Service a2489d
   char size_str[32];
Packit Service a2489d
   if(fi->defined&fi->SIZE)
Packit Service a2489d
      snprintf(size_str,sizeof(size_str),"%lld",(long long)fi->size);
Packit Service a2489d
   else
Packit Service a2489d
      strcpy(size_str,"-");
Packit Service a2489d
   const char *date_str="-";
Packit Service a2489d
   if(fi->defined&fi->DATE)
Packit Service a2489d
      date_str=TimeDate(fi->date).IsoDateTime();
Packit Service a2489d
Packit Service a2489d
   buf->Format("%c%s  %10s  %16s  ",
Packit Service a2489d
	 dir ? 'd':'-', format_perms(fi->mode), size_str, date_str);
Packit Service a2489d
Packit Service a2489d
   if(color)
Packit Service a2489d
      DirColors::GetInstance()->
Packit Service a2489d
	 PutColored(buf,fi->name,fi->filetype);
Packit Service a2489d
   else
Packit Service a2489d
      buf->Put(fi->name);
Packit Service a2489d
Packit Service a2489d
   buf->Put("\r\n");
Packit Service a2489d
   delete fi;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
FileInfo *ParseFtpLongList_EPLF(char *line,int *err,const char *);
Packit Service a2489d
Packit Service a2489d
bool FtpDirList::TryEPLF(const char *line_c, int len)
Packit Service a2489d
{
Packit Service a2489d
   // check for EPLF listing
Packit Service a2489d
   if(len<2)
Packit Service a2489d
      return false;
Packit Service a2489d
   if(line_c[0]!='+')
Packit Service a2489d
      return false;
Packit Service a2489d
Packit Service a2489d
   char *line=string_alloca(len+1);
Packit Service a2489d
   strncpy(line,line_c,len);
Packit Service a2489d
   line[len]=0;
Packit Service a2489d
Packit Service a2489d
   int err=0;
Packit Service a2489d
   FileInfo *fi=ParseFtpLongList_EPLF(line,&err,0);
Packit Service a2489d
   if(!fi)
Packit Service a2489d
      return false;
Packit Service a2489d
Packit Service a2489d
   // ok, this is EPLF. Format new string.
Packit Service a2489d
   FormatGeneric(fi);
Packit Service a2489d
   return true;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
bool FtpDirList::TryColor(const char *line_c,int len)
Packit Service a2489d
{
Packit Service a2489d
   if(!color)
Packit Service a2489d
      return false;
Packit Service a2489d
Packit Service a2489d
   char *line=string_alloca(len+1);
Packit Service a2489d
   strncpy(line,line_c,len);
Packit Service a2489d
   line[len]=0;
Packit Service a2489d
   if(len>0 && line[len-1]=='\r')
Packit Service a2489d
      line[len-1]=0;
Packit Service a2489d
Packit Service a2489d
   char year_or_time[6];
Packit Service a2489d
   char perms[12],user[32],group[32],month_name[4];
Packit Service a2489d
   int nlink,day,year,hour,minute;
Packit Service a2489d
   long long size;
Packit Service a2489d
   int consumed=0;
Packit Service a2489d
Packit Service a2489d
   int n=sscanf(line,"%11s %d %31s %31s %lld %3s %2d %5s%n",perms,&nlink,
Packit Service a2489d
	       user,group,&size,month_name,&day,year_or_time,&consumed);
Packit Service a2489d
   if(n==4) // bsd-like listing without group?
Packit Service a2489d
   {
Packit Service a2489d
      group[0]=0;
Packit Service a2489d
      n=sscanf(line,"%11s %d %31s %lld %3s %2d %5s%n",perms,&nlink,
Packit Service a2489d
	    user,&size,month_name,&day,year_or_time,&consumed);
Packit Service a2489d
      if(n!=7)
Packit Service a2489d
	 return false;
Packit Service a2489d
   }
Packit Service a2489d
   else if(n!=8)
Packit Service a2489d
      return false;
Packit Service a2489d
   if(consumed>0 && -1!=(parse_perms(perms+1))
Packit Service a2489d
   && -1!=(parse_month(month_name))
Packit Service a2489d
   && -1!=parse_year_or_time(year_or_time,&year,&hour,&minute)
Packit Service a2489d
   && strlen(line+consumed)>1)
Packit Service a2489d
   {
Packit Service a2489d
      // good.
Packit Service a2489d
      int type=-1;
Packit Service a2489d
      int name_start=consumed+1;
Packit Service a2489d
      int name_len=strlen(line+name_start);
Packit Service a2489d
      if(perms[0]=='d')
Packit Service a2489d
	 type=FileInfo::DIRECTORY;
Packit Service a2489d
      else if(perms[0]=='l')
Packit Service a2489d
      {
Packit Service a2489d
	 type=FileInfo::SYMLINK;
Packit Service a2489d
	 const char *str=strstr(line+name_start+1," -> ");
Packit Service a2489d
	 if(str)
Packit Service a2489d
	    name_len=str-(line+name_start);
Packit Service a2489d
      }
Packit Service a2489d
      else if(perms[0]=='-')
Packit Service a2489d
	 type=FileInfo::NORMAL;
Packit Service a2489d
      buf->Put(line,consumed+1);
Packit Service a2489d
      char *name=string_alloca(name_len+1);
Packit Service a2489d
      strncpy(name,line+name_start,name_len);
Packit Service a2489d
      name[name_len]=0;
Packit Service a2489d
      DirColors::GetInstance()->PutColored(buf,name,type);
Packit Service a2489d
      buf->Put(line+name_start+name_len);
Packit Service a2489d
      buf->Put("\r\n");
Packit Service a2489d
      return true;
Packit Service a2489d
   }
Packit Service a2489d
   return false;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
FileInfo *ParseFtpLongList_MLSD(char *line,int *err,const char *);
Packit Service a2489d
Packit Service a2489d
bool FtpDirList::TryMLSD(const char *line_c,int len)
Packit Service a2489d
{
Packit Service a2489d
   char *line=string_alloca(len+1);
Packit Service a2489d
   strncpy(line,line_c,len);
Packit Service a2489d
   line[len]=0;
Packit Service a2489d
Packit Service a2489d
   int err=0;
Packit Service a2489d
   FileInfo *fi=ParseFtpLongList_MLSD(line,&err,0);
Packit Service a2489d
   if(!fi)
Packit Service a2489d
      return false;
Packit Service a2489d
Packit Service a2489d
   FormatGeneric(fi);
Packit Service a2489d
   return true;
Packit Service a2489d
}