Blame src/FtpDirList.cc

Packit 8f70b4
/*
Packit 8f70b4
 * lftp - file transfer program
Packit 8f70b4
 *
Packit 8f70b4
 * Copyright (c) 1996-2013 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
Packit 8f70b4
#include "FileAccess.h"
Packit 8f70b4
#include "FtpDirList.h"
Packit 8f70b4
#include "LsCache.h"
Packit 8f70b4
#include "ArgV.h"
Packit 8f70b4
#include "misc.h"
Packit 8f70b4
#include "DirColors.h"
Packit 8f70b4
#include "ftpclass.h"
Packit 8f70b4
Packit 8f70b4
#include <sys/types.h>
Packit 8f70b4
#include <time.h>
Packit 8f70b4
#ifdef TM_IN_SYS_TIME
Packit 8f70b4
# include <sys/time.h>
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#define super DirList
Packit 8f70b4
Packit 8f70b4
int FtpDirList::Do()
Packit 8f70b4
{
Packit 8f70b4
   int m=STALL;
Packit 8f70b4
Packit 8f70b4
   if(done)
Packit 8f70b4
      return m;
Packit 8f70b4
Packit 8f70b4
   if(buf->Eof())
Packit 8f70b4
   {
Packit 8f70b4
      done=true;
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(!ubuf)
Packit 8f70b4
   {
Packit 8f70b4
      const char *cache_buffer=0;
Packit 8f70b4
      int cache_buffer_size=0;
Packit 8f70b4
      int err;
Packit 8f70b4
      if(use_cache && FileAccess::cache->Find(session,pattern,FA::LONG_LIST,&err,
Packit 8f70b4
				    &cache_buffer,&cache_buffer_size))
Packit 8f70b4
      {
Packit 8f70b4
	 if(err)
Packit 8f70b4
	 {
Packit 8f70b4
	    SetErrorCached(cache_buffer);
Packit 8f70b4
	    return MOVED;
Packit 8f70b4
	 }
Packit 8f70b4
	 ubuf=new IOBuffer(IOBuffer::GET);
Packit 8f70b4
	 ubuf->Put(cache_buffer,cache_buffer_size);
Packit 8f70b4
	 ubuf->PutEOF();
Packit 8f70b4
      }
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 session->Open(pattern,FA::LONG_LIST);
Packit 8f70b4
	 ubuf=new IOBufferFileAccess(session);
Packit 8f70b4
	 if(FileAccess::cache->IsEnabled(session->GetHostName()))
Packit 8f70b4
	    ubuf->Save(FileAccess::cache->SizeLimit());
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   const char *b;
Packit 8f70b4
   int len;
Packit 8f70b4
   ubuf->Get(&b,&len;;
Packit 8f70b4
   if(b==0) // eof
Packit 8f70b4
   {
Packit 8f70b4
      buf->PutEOF();
Packit 8f70b4
      FileAccess::cache->Add(session,pattern,FA::LONG_LIST,FA::OK,ubuf);
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   while(len>0)
Packit 8f70b4
   {
Packit 8f70b4
      const char *eol=find_char(b,len,'\n');
Packit 8f70b4
      if(!eol && !ubuf->Eof() && len<0x1000)
Packit 8f70b4
	 break;
Packit 8f70b4
      if(eol)
Packit 8f70b4
      {
Packit 8f70b4
	 int line_len=eol+1-b;
Packit 8f70b4
	 if(!TryEPLF(b, eol-b)
Packit 8f70b4
	 && !TryMLSD(b, eol-b)
Packit 8f70b4
	 && !TryColor(b, eol-b))
Packit 8f70b4
	    buf->Put(b,line_len);
Packit 8f70b4
	 ubuf->Skip(line_len);
Packit 8f70b4
      }
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 // too long line of missing \n on last line.
Packit 8f70b4
	 buf->Put(b,len);
Packit 8f70b4
	 ubuf->Skip(len);
Packit 8f70b4
      }
Packit 8f70b4
      ubuf->Get(&b,&len;;
Packit 8f70b4
      m=MOVED;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(ubuf->Error())
Packit 8f70b4
   {
Packit 8f70b4
      SetError(ubuf->ErrorText());
Packit 8f70b4
      m=MOVED;
Packit 8f70b4
   }
Packit 8f70b4
   return m;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
const char *FtpDirList::Status()
Packit 8f70b4
{
Packit 8f70b4
   if(ubuf && !ubuf->Eof() && session->IsOpen())
Packit 8f70b4
   {
Packit 8f70b4
      return xstring::format(_("Getting file list (%lld) [%s]"),
Packit 8f70b4
		     (long long)session->GetPos(),session->CurrentStatus());
Packit 8f70b4
   }
Packit 8f70b4
   return "";
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void FtpDirList::SuspendInternal()
Packit 8f70b4
{
Packit 8f70b4
   super::SuspendInternal();
Packit 8f70b4
   if(ubuf)
Packit 8f70b4
      ubuf->SuspendSlave();
Packit 8f70b4
}
Packit 8f70b4
void FtpDirList::ResumeInternal()
Packit 8f70b4
{
Packit 8f70b4
   if(ubuf)
Packit 8f70b4
      ubuf->ResumeSlave();
Packit 8f70b4
   super::ResumeInternal();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void FtpDirList::FormatGeneric(FileInfo *fi)
Packit 8f70b4
{
Packit 8f70b4
   bool dir=(fi->defined&fi->TYPE) && fi->filetype==fi->DIRECTORY;
Packit 8f70b4
   if(!(fi->defined&fi->MODE))
Packit 8f70b4
      fi->mode=(dir?0755:0644);
Packit 8f70b4
   char size_str[32];
Packit 8f70b4
   if(fi->defined&fi->SIZE)
Packit 8f70b4
      snprintf(size_str,sizeof(size_str),"%lld",(long long)fi->size);
Packit 8f70b4
   else
Packit 8f70b4
      strcpy(size_str,"-");
Packit 8f70b4
   const char *date_str="-";
Packit 8f70b4
   if(fi->defined&fi->DATE)
Packit 8f70b4
      date_str=TimeDate(fi->date).IsoDateTime();
Packit 8f70b4
Packit 8f70b4
   buf->Format("%c%s  %10s  %16s  ",
Packit 8f70b4
	 dir ? 'd':'-', format_perms(fi->mode), size_str, date_str);
Packit 8f70b4
Packit 8f70b4
   if(color)
Packit 8f70b4
      DirColors::GetInstance()->
Packit 8f70b4
	 PutColored(buf,fi->name,fi->filetype);
Packit 8f70b4
   else
Packit 8f70b4
      buf->Put(fi->name);
Packit 8f70b4
Packit 8f70b4
   buf->Put("\r\n");
Packit 8f70b4
   delete fi;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
FileInfo *ParseFtpLongList_EPLF(char *line,int *err,const char *);
Packit 8f70b4
Packit 8f70b4
bool FtpDirList::TryEPLF(const char *line_c, int len)
Packit 8f70b4
{
Packit 8f70b4
   // check for EPLF listing
Packit 8f70b4
   if(len<2)
Packit 8f70b4
      return false;
Packit 8f70b4
   if(line_c[0]!='+')
Packit 8f70b4
      return false;
Packit 8f70b4
Packit 8f70b4
   char *line=string_alloca(len+1);
Packit 8f70b4
   strncpy(line,line_c,len);
Packit 8f70b4
   line[len]=0;
Packit 8f70b4
Packit 8f70b4
   int err=0;
Packit 8f70b4
   FileInfo *fi=ParseFtpLongList_EPLF(line,&err,0);
Packit 8f70b4
   if(!fi)
Packit 8f70b4
      return false;
Packit 8f70b4
Packit 8f70b4
   // ok, this is EPLF. Format new string.
Packit 8f70b4
   FormatGeneric(fi);
Packit 8f70b4
   return true;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
bool FtpDirList::TryColor(const char *line_c,int len)
Packit 8f70b4
{
Packit 8f70b4
   if(!color)
Packit 8f70b4
      return false;
Packit 8f70b4
Packit 8f70b4
   char *line=string_alloca(len+1);
Packit 8f70b4
   strncpy(line,line_c,len);
Packit 8f70b4
   line[len]=0;
Packit 8f70b4
   if(len>0 && line[len-1]=='\r')
Packit 8f70b4
      line[len-1]=0;
Packit 8f70b4
Packit 8f70b4
   char year_or_time[6];
Packit 8f70b4
   char perms[12],user[32],group[32],month_name[4];
Packit 8f70b4
   int nlink,day,year,hour,minute;
Packit 8f70b4
   long long size;
Packit 8f70b4
   int consumed=0;
Packit 8f70b4
Packit 8f70b4
   int n=sscanf(line,"%11s %d %31s %31s %lld %3s %2d %5s%n",perms,&nlink,
Packit 8f70b4
	       user,group,&size,month_name,&day,year_or_time,&consumed);
Packit 8f70b4
   if(n==4) // bsd-like listing without group?
Packit 8f70b4
   {
Packit 8f70b4
      group[0]=0;
Packit 8f70b4
      n=sscanf(line,"%11s %d %31s %lld %3s %2d %5s%n",perms,&nlink,
Packit 8f70b4
	    user,&size,month_name,&day,year_or_time,&consumed);
Packit 8f70b4
      if(n!=7)
Packit 8f70b4
	 return false;
Packit 8f70b4
   }
Packit 8f70b4
   else if(n!=8)
Packit 8f70b4
      return false;
Packit 8f70b4
   if(consumed>0 && -1!=(parse_perms(perms+1))
Packit 8f70b4
   && -1!=(parse_month(month_name))
Packit 8f70b4
   && -1!=parse_year_or_time(year_or_time,&year,&hour,&minute)
Packit 8f70b4
   && strlen(line+consumed)>1)
Packit 8f70b4
   {
Packit 8f70b4
      // good.
Packit 8f70b4
      int type=-1;
Packit 8f70b4
      int name_start=consumed+1;
Packit 8f70b4
      int name_len=strlen(line+name_start);
Packit 8f70b4
      if(perms[0]=='d')
Packit 8f70b4
	 type=FileInfo::DIRECTORY;
Packit 8f70b4
      else if(perms[0]=='l')
Packit 8f70b4
      {
Packit 8f70b4
	 type=FileInfo::SYMLINK;
Packit 8f70b4
	 const char *str=strstr(line+name_start+1," -> ");
Packit 8f70b4
	 if(str)
Packit 8f70b4
	    name_len=str-(line+name_start);
Packit 8f70b4
      }
Packit 8f70b4
      else if(perms[0]=='-')
Packit 8f70b4
	 type=FileInfo::NORMAL;
Packit 8f70b4
      buf->Put(line,consumed+1);
Packit 8f70b4
      char *name=string_alloca(name_len+1);
Packit 8f70b4
      strncpy(name,line+name_start,name_len);
Packit 8f70b4
      name[name_len]=0;
Packit 8f70b4
      DirColors::GetInstance()->PutColored(buf,name,type);
Packit 8f70b4
      buf->Put(line+name_start+name_len);
Packit 8f70b4
      buf->Put("\r\n");
Packit 8f70b4
      return true;
Packit 8f70b4
   }
Packit 8f70b4
   return false;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
FileInfo *ParseFtpLongList_MLSD(char *line,int *err,const char *);
Packit 8f70b4
Packit 8f70b4
bool FtpDirList::TryMLSD(const char *line_c,int len)
Packit 8f70b4
{
Packit 8f70b4
   char *line=string_alloca(len+1);
Packit 8f70b4
   strncpy(line,line_c,len);
Packit 8f70b4
   line[len]=0;
Packit 8f70b4
Packit 8f70b4
   int err=0;
Packit 8f70b4
   FileInfo *fi=ParseFtpLongList_MLSD(line,&err,0);
Packit 8f70b4
   if(!fi)
Packit 8f70b4
      return false;
Packit 8f70b4
Packit 8f70b4
   FormatGeneric(fi);
Packit 8f70b4
   return true;
Packit 8f70b4
}