|
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 |
}
|