|
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 |
|
|
Packit |
8f70b4 |
#include "FileAccess.h"
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <sys/socket.h>
|
|
Packit |
8f70b4 |
#include <netinet/in.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <ctype.h>
|
|
Packit |
8f70b4 |
#include <assert.h>
|
|
Packit |
8f70b4 |
#include <stddef.h>
|
|
Packit |
8f70b4 |
#include "ascii_ctype.h"
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include "LsCache.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
#include "url.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "DummyProto.h"
|
|
Packit |
8f70b4 |
#include "netrc.h"
|
|
Packit |
8f70b4 |
#include "ArgV.h"
|
|
Packit |
8f70b4 |
#include "ConnectionSlot.h"
|
|
Packit |
8f70b4 |
#include "SignalHook.h"
|
|
Packit |
8f70b4 |
#include "FileGlob.h"
|
|
Packit |
8f70b4 |
#ifdef WITH_MODULES
|
|
Packit |
8f70b4 |
# include "module.h"
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xlist_head<FileAccess> FileAccess::all_fa;
|
|
Packit |
8f70b4 |
const FileAccessRef FileAccessRef::null;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ClassInit();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pass_open=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
default_cwd="~";
|
|
Packit |
8f70b4 |
cwd.Set(default_cwd,false,0);
|
|
Packit |
8f70b4 |
limit=FILE_END;
|
|
Packit |
8f70b4 |
real_pos=UNKNOWN_POS;
|
|
Packit |
8f70b4 |
pos=0;
|
|
Packit |
8f70b4 |
mode=CLOSED;
|
|
Packit |
8f70b4 |
retries=0;
|
|
Packit |
8f70b4 |
max_retries=0;
|
|
Packit |
8f70b4 |
opt_date=0;
|
|
Packit |
8f70b4 |
opt_size=0;
|
|
Packit |
8f70b4 |
fileset_for_info=0;
|
|
Packit |
8f70b4 |
error_code=OK;
|
|
Packit |
8f70b4 |
saved_errno=0;
|
|
Packit |
8f70b4 |
mkdir_p=false;
|
|
Packit |
8f70b4 |
rename_f=false;
|
|
Packit |
8f70b4 |
ascii=false;
|
|
Packit |
8f70b4 |
norest_manual=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
entity_size=NO_SIZE;
|
|
Packit |
8f70b4 |
entity_date=NO_DATE;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
res_prefix=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
chmod_mode=0644;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
priority=last_priority=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
all_fa.add(all_fa_node);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess::FileAccess(const FileAccess *fa)
|
|
Packit |
8f70b4 |
: all_fa_node(this)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
cwd=fa->cwd;
|
|
Packit |
8f70b4 |
home=fa->home;
|
|
Packit |
8f70b4 |
user.set(fa->user);
|
|
Packit |
8f70b4 |
pass.set(fa->pass);
|
|
Packit |
8f70b4 |
pass_open=fa->pass_open;
|
|
Packit |
8f70b4 |
hostname.set(fa->hostname);
|
|
Packit |
8f70b4 |
portname.set(fa->portname);
|
|
Packit |
8f70b4 |
vproto.set(fa->vproto);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess::~FileAccess()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
all_fa_node.remove();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Open(const char *fn,int mode,off_t offs)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef OPEN_DEBUG
|
|
Packit |
8f70b4 |
printf("%p->FA::Open(%s,%d)\n",this,fn?fn:"NULL",mode);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
if(IsOpen())
|
|
Packit |
8f70b4 |
Close();
|
|
Packit |
8f70b4 |
Resume();
|
|
Packit |
8f70b4 |
file.set(fn);
|
|
Packit |
8f70b4 |
real_pos=UNKNOWN_POS;
|
|
Packit |
8f70b4 |
pos=offs;
|
|
Packit |
8f70b4 |
this->mode=mode;
|
|
Packit |
8f70b4 |
mkdir_p=false;
|
|
Packit |
8f70b4 |
rename_f=false;
|
|
Packit |
8f70b4 |
Timeout(0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
switch((open_mode)mode)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case STORE:
|
|
Packit |
8f70b4 |
case REMOVE:
|
|
Packit |
8f70b4 |
case MAKE_DIR:
|
|
Packit |
8f70b4 |
case CHANGE_MODE:
|
|
Packit |
8f70b4 |
cache->FileChanged(this,file);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case REMOVE_DIR:
|
|
Packit |
8f70b4 |
cache->FileChanged(this,file);
|
|
Packit |
8f70b4 |
cache->TreeChanged(this,file);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
default:
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *FileAccess::StrError(int err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static xstring str;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// note to translators: several errors should not be displayed to user;
|
|
Packit |
8f70b4 |
// so no need to translate them.
|
|
Packit |
8f70b4 |
switch(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(IN_PROGRESS):
|
|
Packit |
8f70b4 |
return("Operation is in progress");
|
|
Packit |
8f70b4 |
case(OK):
|
|
Packit |
8f70b4 |
return("Error 0");
|
|
Packit |
8f70b4 |
case(SEE_ERRNO):
|
|
Packit |
8f70b4 |
if(error)
|
|
Packit |
8f70b4 |
return str.vset(error.get(),": ",strerror(saved_errno),NULL);
|
|
Packit |
8f70b4 |
return(strerror(saved_errno));
|
|
Packit |
8f70b4 |
case(LOOKUP_ERROR):
|
|
Packit |
8f70b4 |
return(error);
|
|
Packit |
8f70b4 |
case(NOT_OPEN): // Actually this means an error in application
|
|
Packit |
8f70b4 |
return("Class is not Open()ed");
|
|
Packit |
8f70b4 |
case(NO_FILE):
|
|
Packit |
8f70b4 |
if(error)
|
|
Packit |
8f70b4 |
return str.vset(_("Access failed: "),error.get(),NULL);
|
|
Packit |
8f70b4 |
return(_("File cannot be accessed"));
|
|
Packit |
8f70b4 |
case(NO_HOST):
|
|
Packit |
8f70b4 |
return(_("Not connected"));
|
|
Packit |
8f70b4 |
case(FATAL):
|
|
Packit |
8f70b4 |
if(error)
|
|
Packit |
8f70b4 |
return str.vset(_("Fatal error"),": ",error.get(),NULL);
|
|
Packit |
8f70b4 |
return(_("Fatal error"));
|
|
Packit |
8f70b4 |
case(STORE_FAILED):
|
|
Packit |
8f70b4 |
return(_("Store failed - you have to reput"));
|
|
Packit |
8f70b4 |
case(LOGIN_FAILED):
|
|
Packit |
8f70b4 |
if(error)
|
|
Packit |
8f70b4 |
return str.vset(_("Login failed"),": ",error.get(),NULL);
|
|
Packit |
8f70b4 |
return(_("Login failed"));
|
|
Packit |
8f70b4 |
case(NOT_SUPP):
|
|
Packit |
8f70b4 |
if(error)
|
|
Packit |
8f70b4 |
return str.vset(_("Operation not supported"),": ",error.get(),NULL);
|
|
Packit |
8f70b4 |
return(_("Operation not supported"));
|
|
Packit |
8f70b4 |
case(FILE_MOVED):
|
|
Packit |
8f70b4 |
if(error)
|
|
Packit |
8f70b4 |
return str.vset(_("File moved"),": ",error.get(),NULL);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
return str.vset(_("File moved to `"),location?location.get():"?","'",NULL);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return("");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Close()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file.set(0);
|
|
Packit |
8f70b4 |
file_url.set(0);
|
|
Packit |
8f70b4 |
file1.set(0);
|
|
Packit |
8f70b4 |
new_cwd=0;
|
|
Packit |
8f70b4 |
mode=CLOSED;
|
|
Packit |
8f70b4 |
opt_date=0;
|
|
Packit |
8f70b4 |
opt_size=0;
|
|
Packit |
8f70b4 |
fileset_for_info=0;
|
|
Packit |
8f70b4 |
retries=0;
|
|
Packit |
8f70b4 |
entity_size=NO_SIZE;
|
|
Packit |
8f70b4 |
entity_date=NO_DATE;
|
|
Packit |
8f70b4 |
ascii=false;
|
|
Packit |
8f70b4 |
norest_manual=false;
|
|
Packit |
8f70b4 |
location.set(0);
|
|
Packit |
8f70b4 |
entity_content_type.set(0);
|
|
Packit |
8f70b4 |
entity_charset.set(0);
|
|
Packit |
8f70b4 |
ClearError();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Open2(const char *f,const char *f1,open_mode o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Close();
|
|
Packit |
8f70b4 |
file1.set(f1);
|
|
Packit |
8f70b4 |
Open(f,o);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
cache->TreeChanged(this,file);
|
|
Packit |
8f70b4 |
cache->FileChanged(this,file);
|
|
Packit |
8f70b4 |
cache->FileChanged(this,file1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Rename(const char *rfile,const char *to,bool clobber)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Open2(rfile,to,RENAME);
|
|
Packit |
8f70b4 |
rename_f=clobber;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Mkdir(const char *fn,bool allp)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Open(fn,MAKE_DIR);
|
|
Packit |
8f70b4 |
mkdir_p=allp;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
StringSet *FileAccess::MkdirMakeSet() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
StringSet *set=new StringSet;
|
|
Packit |
8f70b4 |
const char *sl=strchr(file,'/');
|
|
Packit |
8f70b4 |
while(sl)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(sl>file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xstring& tmp=xstring::get_tmp(file,sl-file);
|
|
Packit |
8f70b4 |
if(tmp.ne(".") && tmp.ne(".."))
|
|
Packit |
8f70b4 |
set->Append(tmp);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
sl=strchr(sl+1,'/');
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return set;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool FileAccess::SameLocationAs(const FileAccess *fa) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return SameSiteAs(fa);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool FileAccess::SameSiteAs(const FileAccess *fa) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return SameProtoAs(fa);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const xstring& FileAccess::GetFileURL(const char *f,int flags) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *proto=GetVisualProto();
|
|
Packit |
8f70b4 |
if(proto[0]==0)
|
|
Packit |
8f70b4 |
return xstring::get_tmp("");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ParsedURL u;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
u.proto.set(proto);
|
|
Packit |
8f70b4 |
if(!(flags&NO_USER))
|
|
Packit |
8f70b4 |
u.user.set(user);
|
|
Packit |
8f70b4 |
if((pass_open || (flags&WITH_PASSWORD)) && !(flags&NO_PASSWORD))
|
|
Packit |
8f70b4 |
u.pass.set(pass);
|
|
Packit |
8f70b4 |
u.host.set(hostname);
|
|
Packit |
8f70b4 |
u.port.set(portname);
|
|
Packit |
8f70b4 |
if(!(flags&NO_PATH))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(cwd.url)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Path f_path(cwd);
|
|
Packit |
8f70b4 |
if(f)
|
|
Packit |
8f70b4 |
f_path.Change(f,true);
|
|
Packit |
8f70b4 |
if(f_path.url)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int f_path_index=url::path_index(f_path.url);
|
|
Packit |
8f70b4 |
return u.CombineTo(xstring::get_tmp(""),home)
|
|
Packit |
8f70b4 |
.append(f_path.url+f_path_index);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool is_dir=((!f || !*f) && !cwd.is_file);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!f || (f[0]!='/' && f[0]!='~'))
|
|
Packit |
8f70b4 |
f=dir_file(cwd.path?cwd.path.get():"~",f);
|
|
Packit |
8f70b4 |
u.path.set(f);
|
|
Packit |
8f70b4 |
if(is_dir && url::dir_needs_trailing_slash(proto) && u.path.last_char()!='/')
|
|
Packit |
8f70b4 |
u.path.append('/');
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return u.CombineTo(xstring::get_tmp(""),home);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const xstring& FileAccess::GetConnectURL(int flags) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return GetFileURL(0,flags);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Connect(const char *host1,const char *port1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Close();
|
|
Packit |
8f70b4 |
hostname.set(host1);
|
|
Packit |
8f70b4 |
portname.set(port1);
|
|
Packit |
8f70b4 |
DontSleep();
|
|
Packit |
8f70b4 |
ResetLocationData();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Login(const char *user1,const char *pass1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Close();
|
|
Packit |
8f70b4 |
user.set(user1);
|
|
Packit |
8f70b4 |
pass.set(pass1);
|
|
Packit |
8f70b4 |
pass_open=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(user && pass==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xlist_for_each(FileAccess,all_fa,node,o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pass.set(o->pass);
|
|
Packit |
8f70b4 |
if(SameSiteAs(o) && o->pass)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!o)
|
|
Packit |
8f70b4 |
pass.set(0);
|
|
Packit |
8f70b4 |
if(pass==0 && hostname) // still no pass? Try .netrc
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
NetRC::Entry *nrc=NetRC::LookupHost(hostname,user);
|
|
Packit |
8f70b4 |
if(nrc)
|
|
Packit |
8f70b4 |
pass.set(nrc->pass);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResetLocationData();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::ResetLocationData()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cwd.Set(default_cwd,false,0);
|
|
Packit |
8f70b4 |
home.Set((char*)0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::SetPasswordGlobal(const char *p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pass.set(p);
|
|
Packit |
8f70b4 |
xstring save_pass;
|
|
Packit |
8f70b4 |
xlist_for_each(FileAccess,all_fa,node,o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(o==this)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
save_pass.set(o->pass); // cheat SameSiteAs.
|
|
Packit |
8f70b4 |
o->pass.set(pass);
|
|
Packit |
8f70b4 |
if(!SameSiteAs(o))
|
|
Packit |
8f70b4 |
o->pass.set(save_pass);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::GetInfoArray(FileSet *info)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Open(0,ARRAY_INFO);
|
|
Packit |
8f70b4 |
fileset_for_info=info;
|
|
Packit |
8f70b4 |
fileset_for_info->rewind();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static void expand_tilde(xstring &path, const char *home, int i=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!(path[i]=='~' && (path[i+1]==0 || path[i+1]=='/')))
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
char prefix_len=(last_char(home)=='/' ? 2 : 1);
|
|
Packit |
8f70b4 |
if(home[0]=='/' && i>0 && path[i-1]=='/')
|
|
Packit |
8f70b4 |
home++;
|
|
Packit |
8f70b4 |
path.set_substr(i,prefix_len,home);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::ExpandTildeInCWD()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(home)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cwd.ExpandTilde(home);
|
|
Packit |
8f70b4 |
if(new_cwd)
|
|
Packit |
8f70b4 |
new_cwd->ExpandTilde(home);
|
|
Packit |
8f70b4 |
if(real_cwd)
|
|
Packit |
8f70b4 |
expand_tilde(real_cwd,home);
|
|
Packit |
8f70b4 |
if(file)
|
|
Packit |
8f70b4 |
expand_tilde(file,home);
|
|
Packit |
8f70b4 |
if(file1)
|
|
Packit |
8f70b4 |
expand_tilde(file1,home);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileAccess::set_home(const char *h)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
home.Set(h);
|
|
Packit |
8f70b4 |
ExpandTildeInCWD();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *FileAccess::ExpandTildeStatic(const char *s) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!home || !(s[0]=='~' && (s[1]=='/' || s[1]==0)))
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static xstring buf;
|
|
Packit |
8f70b4 |
buf.set(s);
|
|
Packit |
8f70b4 |
expand_tilde(buf,home);
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static inline
|
|
Packit |
8f70b4 |
bool last_element_is_doubledot(const char *path,const char *end)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return((end==path+2 && !strncmp(path,"..",2))
|
|
Packit |
8f70b4 |
|| (end>path+2 && !strncmp(end-3,"/..",3)));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileAccess::device_prefix_len(const char *path) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ResValue dp=Query("device-prefix",hostname);
|
|
Packit |
8f70b4 |
if(dp.is_nil() || !dp.to_bool())
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
int i=0;
|
|
Packit |
8f70b4 |
while(path[i] && (is_ascii_alnum(path[i]) || strchr("$_-",path[i])))
|
|
Packit |
8f70b4 |
i++;
|
|
Packit |
8f70b4 |
if(i>0 && path[i]==':')
|
|
Packit |
8f70b4 |
return i+1+(path[i+1]=='/');
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Path::Optimize(xstring& path,int device_prefix_len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int prefix_size=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(path[0]=='/' && path[1]=='~' && device_prefix_len==1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
prefix_size=2;
|
|
Packit |
8f70b4 |
while(path[prefix_size]!='/' && path[prefix_size]!='\0')
|
|
Packit |
8f70b4 |
prefix_size++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(path[0]=='/')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
prefix_size=1;
|
|
Packit |
8f70b4 |
if(path[1]=='/' && (!path[2] || path[2]!='/'))
|
|
Packit |
8f70b4 |
prefix_size=2;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(path[0]=='~')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
prefix_size=1;
|
|
Packit |
8f70b4 |
while(path[prefix_size]!='/' && path[prefix_size]!='\0')
|
|
Packit |
8f70b4 |
prefix_size++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// handle VMS and DOS devices.
|
|
Packit |
8f70b4 |
prefix_size=device_prefix_len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *in;
|
|
Packit |
8f70b4 |
char *out;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
in=out=path.get_non_const()+prefix_size;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
while((in[0]=='.' && (in[1]=='/' || in[1]==0))
|
|
Packit |
8f70b4 |
|| (in>path && in[-1]=='/' && (in[0]=='/'
|
|
Packit |
8f70b4 |
|| (in[0]=='.' && in[1]=='.' && (in[2]=='/' || in[2]==0)))))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(in[0]=='.' && in[1]=='.')
|
|
Packit |
8f70b4 |
in++;
|
|
Packit |
8f70b4 |
in++;
|
|
Packit |
8f70b4 |
if(*in=='/')
|
|
Packit |
8f70b4 |
in++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
while(*in)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(in[0]=='/')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// double slash
|
|
Packit |
8f70b4 |
if(in[1]=='/')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
in++;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(in[1]=='.')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// . - cur dir
|
|
Packit |
8f70b4 |
if(in[2]=='/' || in[2]=='\0')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
in+=2;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// .. - prev dir
|
|
Packit |
8f70b4 |
if(in[2]=='.' && (in[3]=='/' || in[3]=='\0'))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(last_element_is_doubledot(path+prefix_size,out)
|
|
Packit |
8f70b4 |
|| out==path
|
|
Packit |
8f70b4 |
|| (out==path+prefix_size && out[-1]!='/'))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(out>path && out[-1]!='/')
|
|
Packit |
8f70b4 |
*out++='/';
|
|
Packit |
8f70b4 |
*out++='.';
|
|
Packit |
8f70b4 |
*out++='.';
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
while(out>path+prefix_size && *--out!='/')
|
|
Packit |
8f70b4 |
;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
in+=3;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// don't add slash after prefix with slash
|
|
Packit |
8f70b4 |
if(out>path && out[-1]=='/')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
in++;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
*out++=*in++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
path.truncate(path.length()-(in-out));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Chdir(const char *path,bool verify)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cwd.ExpandTilde(home);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Close();
|
|
Packit |
8f70b4 |
new_cwd=new Path(&cwd;;
|
|
Packit |
8f70b4 |
new_cwd->Change(path,false);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(verify)
|
|
Packit |
8f70b4 |
Open(new_cwd->path,CHANGE_DIR);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cwd.Set(new_cwd);
|
|
Packit |
8f70b4 |
new_cwd=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::PathVerify(const Path &p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Close();
|
|
Packit |
8f70b4 |
new_cwd=new Path(p);
|
|
Packit |
8f70b4 |
Open(new_cwd->path,CHANGE_DIR);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Chmod(const char *file,int m)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
chmod_mode=m;
|
|
Packit |
8f70b4 |
Open(file,CHANGE_MODE);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::SetError(int ec,const char *e)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ec==SEE_ERRNO && !saved_errno)
|
|
Packit |
8f70b4 |
saved_errno=errno;
|
|
Packit |
8f70b4 |
if(ec==NO_FILE && file && file[0] && !strstr(e,file))
|
|
Packit |
8f70b4 |
error.vset(e," (",file.get(),")",NULL);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
error.set(e);
|
|
Packit |
8f70b4 |
error_code=ec;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::ClearError()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
saved_errno=0;
|
|
Packit |
8f70b4 |
error_code=OK;
|
|
Packit |
8f70b4 |
error.set(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Fatal(const char *e)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(FATAL,e);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::SetSuggestedFileName(const char *fn)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
suggested_filename.set(0);
|
|
Packit |
8f70b4 |
if(fn==0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// don't allow subdirectories.
|
|
Packit |
8f70b4 |
if(strchr(fn,'/') || strchr(fn,'\\') || strchr(fn,':'))
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
for(int i=0; fn[i]; i++)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// don't allow control chars.
|
|
Packit |
8f70b4 |
if(iscntrl((unsigned char)fn[i]))
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!*fn || *fn=='.')
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
suggested_filename.set(fn);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::SetFileURL(const char *u)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file_url.set(u);
|
|
Packit |
8f70b4 |
if(new_cwd && mode==CHANGE_DIR)
|
|
Packit |
8f70b4 |
new_cwd->SetURL(u);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess *SessionPool::pool[pool_size];
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void SessionPool::Reuse(FileAccess *f)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(f==0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
if(f->GetHostName()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SMTask::Delete(f);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
f->Close();
|
|
Packit |
8f70b4 |
f->SetPriority(0);
|
|
Packit |
8f70b4 |
int i;
|
|
Packit |
8f70b4 |
for(i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
assert(pool[i]!=f);
|
|
Packit |
8f70b4 |
if(pool[i]==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pool[i]=f;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
for(i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(f->IsBetterThan(pool[i]))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SMTask::Delete(pool[i]);
|
|
Packit |
8f70b4 |
pool[i]=f;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SMTask::Delete(f);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void SessionPool::Print(FILE *f)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int arr[pool_size];
|
|
Packit |
8f70b4 |
int n=0;
|
|
Packit |
8f70b4 |
int i;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(pool[i]==0)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
int j;
|
|
Packit |
8f70b4 |
for(j=0; j
|
|
Packit |
8f70b4 |
if(pool[arr[j]]->SameLocationAs(pool[i]))
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(j==n)
|
|
Packit |
8f70b4 |
arr[n++]=i;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// sort?
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(i=0; i
|
|
Packit |
8f70b4 |
fprintf(f,"%d\t%s\n",arr[i],pool[arr[i]]->GetConnectURL().get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess *SessionPool::GetSession(int n)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(n<0 || n>=pool_size)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
FileAccess *s=pool[n];
|
|
Packit |
8f70b4 |
pool[n]=0;
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess *SessionPool::Walk(int *n,const char *proto)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for( ; *n
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(pool[*n] && !strcmp(pool[*n]->GetProto(),proto))
|
|
Packit |
8f70b4 |
return pool[*n];
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void SessionPool::ClearAll()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int pass=0;
|
|
Packit |
8f70b4 |
for(;;) {
|
|
Packit |
8f70b4 |
int left=0;
|
|
Packit |
8f70b4 |
for(int n=0; n
|
|
Packit |
8f70b4 |
if(!pool[n])
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(pass==0)
|
|
Packit |
8f70b4 |
pool[n]->Disconnect();
|
|
Packit |
8f70b4 |
if(!pool[n]->IsConnected()) {
|
|
Packit |
8f70b4 |
SMTask::Delete(pool[n]);
|
|
Packit |
8f70b4 |
pool[n]=0;
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
left++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(left==0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
SMTask::Schedule();
|
|
Packit |
8f70b4 |
SMTask::Block();
|
|
Packit |
8f70b4 |
pass++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::SetTryTime(time_t t)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(t)
|
|
Packit |
8f70b4 |
reconnect_timer.Reset(Time(t));
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
reconnect_timer.Stop();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool FileAccess::IsBetterThan(const FileAccess *fa) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return(SameProtoAs(fa) && this->IsConnected() > fa->IsConnected());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::Reconfig(const char *) {}
|
|
Packit |
8f70b4 |
void FileAccess::ConnectVerify() { mode=CONNECT_VERIFY; }
|
|
Packit |
8f70b4 |
const char *FileAccess::CurrentStatus() { return ""; }
|
|
Packit |
8f70b4 |
int FileAccess::Buffered() { return 0; }
|
|
Packit |
8f70b4 |
bool FileAccess::IOReady() { return IsOpen(); }
|
|
Packit |
8f70b4 |
int FileAccess::IsConnected() const { return 0; }
|
|
Packit |
8f70b4 |
void FileAccess::UseCache(bool) {}
|
|
Packit |
8f70b4 |
bool FileAccess::NeedSizeDateBeforehand() { return false; }
|
|
Packit |
8f70b4 |
void FileAccess::Cleanup() {}
|
|
Packit |
8f70b4 |
void FileAccess::CleanupThis() {}
|
|
Packit |
8f70b4 |
ListInfo *FileAccess::MakeListInfo(const char *path) { return 0; }
|
|
Packit |
8f70b4 |
Glob *FileAccess::MakeGlob(const char *pattern) { return new NoGlob(pattern); }
|
|
Packit |
8f70b4 |
DirList *FileAccess::MakeDirList(ArgV *a) { delete a; return 0; }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileAccess::CleanupAll()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xlist_for_each(FileAccess,all_fa,node,o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Enter(o);
|
|
Packit |
8f70b4 |
o->CleanupThis();
|
|
Packit |
8f70b4 |
Leave(o);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess *FileAccess::NextSameSite(FA *scan) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(scan==0)
|
|
Packit |
8f70b4 |
scan=all_fa.first_obj();
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
scan=scan->all_fa_node.next_obj();
|
|
Packit |
8f70b4 |
for( ; scan; scan=scan->all_fa_node.next_obj())
|
|
Packit |
8f70b4 |
if(scan!=this && SameSiteAs(scan))
|
|
Packit |
8f70b4 |
return scan;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess *FileAccess::New(const char *proto,const char *host,const char *port)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ClassInit();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(proto==0)
|
|
Packit |
8f70b4 |
proto="file";
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!strcmp(proto,"slot"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const FA *session=ConnectionSlot::FindSession(host);
|
|
Packit |
8f70b4 |
return session?session->Clone():0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FA *session=Protocol::NewSession(proto);
|
|
Packit |
8f70b4 |
if(!session)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *n_proto=session->ProtocolSubstitution(host);
|
|
Packit |
8f70b4 |
if(n_proto && strcmp(n_proto,proto))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FA *n_session=Protocol::NewSession(n_proto);
|
|
Packit |
8f70b4 |
if(n_session)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Delete(session);
|
|
Packit |
8f70b4 |
session=n_session;
|
|
Packit |
8f70b4 |
session->SetVisualProto(proto);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(host)
|
|
Packit |
8f70b4 |
session->Connect(host,port);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return session;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileAccess *FileAccess::New(const ParsedURL *u,bool dummy)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *proto=u->proto?u->proto.get():"file";
|
|
Packit |
8f70b4 |
FileAccess *s=New(proto,u->host);
|
|
Packit |
8f70b4 |
if(!s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!dummy)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return new DummyNoProto(proto);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(strcmp(proto,"slot"))
|
|
Packit |
8f70b4 |
s->Connect(u->host,u->port);
|
|
Packit |
8f70b4 |
if(u->user)
|
|
Packit |
8f70b4 |
s->Login(u->user,u->pass);
|
|
Packit |
8f70b4 |
// path?
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileAccess::Protocol implementation
|
|
Packit |
8f70b4 |
xmap_p<FileAccess::Protocol> FileAccess::Protocol::proto_by_name;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess::Protocol::Protocol(const char *proto, SessionCreator *creator)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
this->proto=proto;
|
|
Packit |
8f70b4 |
this->New=creator;
|
|
Packit |
8f70b4 |
proto_by_name.add(proto,this);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess::Protocol *FileAccess::Protocol::FindProto(const char *proto)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return proto_by_name.lookup(proto);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess *FileAccess::Protocol::NewSession(const char *proto)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Protocol *p;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
p=FindProto(proto);
|
|
Packit |
8f70b4 |
if(p)
|
|
Packit |
8f70b4 |
return p->New();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifdef WITH_MODULES
|
|
Packit |
8f70b4 |
#define PROTO_PREFIX "proto-"
|
|
Packit |
8f70b4 |
const char *mod=xstring::cat(PROTO_PREFIX,proto,NULL);
|
|
Packit |
8f70b4 |
void *map=module_load(mod,0,0);
|
|
Packit |
8f70b4 |
if(map==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
fprintf(stderr,"%s\n",module_error_message());
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
p=FindProto(proto);
|
|
Packit |
8f70b4 |
if(p)
|
|
Packit |
8f70b4 |
return p->New();
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileAccessOperation implementation
|
|
Packit |
8f70b4 |
void FileAccessOperation::SetError(const char *e)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
error_text.set(e);
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileAccessOperation::SetErrorCached(const char *e)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(e);
|
|
Packit |
8f70b4 |
error_text.append(_(" [cached]"));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
DirList::DirList(FileAccess *s,ArgV *a)
|
|
Packit |
8f70b4 |
: FileAccessOperation(s), buf(new Buffer()), args(a), color(false)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
DirList::~DirList()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// ListInfo implementation
|
|
Packit |
8f70b4 |
ListInfo::ListInfo(FileAccess *s,const char *p)
|
|
Packit |
8f70b4 |
: FileAccessOperation(s), exclude_prefix(0), exclude(0), need(0),
|
|
Packit |
8f70b4 |
follow_symlinks(false), try_recursive(false), is_recursive(false)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(session && p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
saved_cwd=session->GetCwd();
|
|
Packit |
8f70b4 |
session->Chdir(p,false);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void ListInfo::PrepareToDie()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(session)
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
if(session && saved_cwd)
|
|
Packit |
8f70b4 |
session->SetCwd(saved_cwd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ListInfo::~ListInfo() {}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// Path implementation
|
|
Packit |
8f70b4 |
void FileAccess::Path::init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
device_prefix_len=0;
|
|
Packit |
8f70b4 |
is_file=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileAccess::Path::~Path()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileAccess::Path::Set(const char *new_path,bool new_is_file,const char *new_url,int new_device_prefix_len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
path.set(new_path);
|
|
Packit |
8f70b4 |
is_file=new_is_file;
|
|
Packit |
8f70b4 |
url.set(new_url);
|
|
Packit |
8f70b4 |
device_prefix_len=new_device_prefix_len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileAccess::Path::Set(const Path *o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Set(o->path,o->is_file,o->url,o->device_prefix_len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileAccess::Path::Change(const char *new_path,bool new_is_file,const char *new_path_enc,int new_device_prefix_len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!new_path && new_path_enc)
|
|
Packit |
8f70b4 |
new_path=url::decode(new_path_enc);
|
|
Packit |
8f70b4 |
if(!new_path || !*new_path)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
const char *bn=basename_ptr(new_path);
|
|
Packit |
8f70b4 |
if(!strcmp(bn,".") || !strcmp(bn,".."))
|
|
Packit |
8f70b4 |
new_is_file=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int path_index=0;
|
|
Packit |
8f70b4 |
if(url)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
path_index=url::path_index(url);
|
|
Packit |
8f70b4 |
xstring new_url_path(url+path_index);
|
|
Packit |
8f70b4 |
if(is_file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dirname_modify(new_url_path);
|
|
Packit |
8f70b4 |
if(!new_url_path[0])
|
|
Packit |
8f70b4 |
new_url_path.set("/~");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(new_url_path.last_char()!='/')
|
|
Packit |
8f70b4 |
new_url_path.append('/');
|
|
Packit |
8f70b4 |
if(new_path[0]=='/' || new_path[0]=='~' || new_device_prefix_len!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
bool have_slash=((new_path_enc?new_path_enc:new_path)[0]=='/');
|
|
Packit |
8f70b4 |
new_url_path.set(have_slash?"":"/");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(new_path_enc)
|
|
Packit |
8f70b4 |
new_url_path.append(new_path_enc);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
new_url_path.append(url::encode(new_path,URL_PATH_UNSAFE));
|
|
Packit |
8f70b4 |
if(!new_is_file && url::dir_needs_trailing_slash(url) && new_url_path.last_char()!='/')
|
|
Packit |
8f70b4 |
new_url_path.append('/');
|
|
Packit |
8f70b4 |
Optimize(new_url_path,!strncmp(new_url_path,"/~",2));
|
|
Packit |
8f70b4 |
url.truncate(path_index);
|
|
Packit |
8f70b4 |
url.append(new_url_path);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(new_path[0]!='/' && new_path[0]!='~' && new_device_prefix_len==0
|
|
Packit |
8f70b4 |
&& path && path[0])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(is_file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dirname_modify(path);
|
|
Packit |
8f70b4 |
if(!path[0])
|
|
Packit |
8f70b4 |
path.set("~");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(last_char(path)=='/')
|
|
Packit |
8f70b4 |
new_path=xstring::format("%s%s",path.get(),new_path);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
new_path=xstring::format("%s/%s",path.get(),new_path);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
path.set(new_path);
|
|
Packit |
8f70b4 |
device_prefix_len=new_device_prefix_len;
|
|
Packit |
8f70b4 |
Optimize();
|
|
Packit |
8f70b4 |
strip_trailing_slashes(path);
|
|
Packit |
8f70b4 |
is_file=new_is_file;
|
|
Packit |
8f70b4 |
if(!strcmp(path,"/") || !strcmp(path,"//"))
|
|
Packit |
8f70b4 |
is_file=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// sanity check
|
|
Packit |
8f70b4 |
if(url)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ParsedURL u(url);
|
|
Packit |
8f70b4 |
if(u.path.length()>1)
|
|
Packit |
8f70b4 |
u.path.chomp('/');
|
|
Packit |
8f70b4 |
if(!u.path.eq(path))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
LogError(0,"URL mismatch %s [%s] vs %s, dropping URL\n",url.get(),u.path.get(),path.get());
|
|
Packit |
8f70b4 |
url.set(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool FileAccess::Path::operator==(const Path &p2) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const Path &p1=*this;
|
|
Packit |
8f70b4 |
if(p1.is_file!=p2.is_file)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(xstrcmp(p1.path,p2.path))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(xstrcmp(p1.url,p2.url))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileAccess::Path::ExpandTilde(const Path &home)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!home.path)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
if(path && path[0]=='~' && (path[1]=='/' || path[1]=='\0'))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
device_prefix_len=home.device_prefix_len;
|
|
Packit |
8f70b4 |
if(path[1]=='\0')
|
|
Packit |
8f70b4 |
is_file=home.is_file;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(url)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int pi=url::path_index(url);
|
|
Packit |
8f70b4 |
if(url[pi]=='/' && url[pi+1]=='~')
|
|
Packit |
8f70b4 |
pi++;
|
|
Packit |
8f70b4 |
expand_tilde(url,home.url?home.url.get():url::encode(home.path,URL_PATH_UNSAFE).get(),pi);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
expand_tilde(path,home.path);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "DirColors.h"
|
|
Packit |
8f70b4 |
#include "LocalDir.h"
|
|
Packit |
8f70b4 |
#include "FileCopy.h"
|
|
Packit |
8f70b4 |
#include "modconfig.h"
|
|
Packit |
8f70b4 |
#ifndef MODULE_PROTO_FTP
|
|
Packit |
8f70b4 |
# include "ftpclass.h"
|
|
Packit |
8f70b4 |
# define _ftp Ftp::ClassInit()
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
# define _ftp
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifndef MODULE_PROTO_FILE
|
|
Packit |
8f70b4 |
# include "LocalAccess.h"
|
|
Packit |
8f70b4 |
# define _file LocalAccess::ClassInit()
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
# define _file
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifndef MODULE_PROTO_HTTP
|
|
Packit |
8f70b4 |
# include "Http.h"
|
|
Packit |
8f70b4 |
# define _http Http::ClassInit()
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
# define _http
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifndef MODULE_PROTO_FISH
|
|
Packit |
8f70b4 |
# include "Fish.h"
|
|
Packit |
8f70b4 |
# define _fish Fish::ClassInit()
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
# define _fish
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifndef MODULE_PROTO_SFTP
|
|
Packit |
8f70b4 |
# include "SFtp.h"
|
|
Packit |
8f70b4 |
# define _sftp SFtp::ClassInit()
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
# define _sftp
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
bool FileAccess::class_inited;
|
|
Packit |
8f70b4 |
LsCache *FileAccess::cache;
|
|
Packit |
8f70b4 |
void FileAccess::ClassInit()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(class_inited)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
class_inited=true;
|
|
Packit |
8f70b4 |
cache=new LsCache();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
SignalHook::ClassInit();
|
|
Packit |
8f70b4 |
ResMgr::ClassInit();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!Log::global)
|
|
Packit |
8f70b4 |
Log::global=new Log("debug");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
_ftp;
|
|
Packit |
8f70b4 |
_file;
|
|
Packit |
8f70b4 |
_http;
|
|
Packit |
8f70b4 |
_fish;
|
|
Packit |
8f70b4 |
_sftp;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// make it link in classes required by modules.
|
|
Packit |
8f70b4 |
LocalDirectory ld;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileAccess::ClassCleanup()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Protocol::ClassCleanup();
|
|
Packit |
8f70b4 |
call_dynamic_hook("lftp_network_cleanup");
|
|
Packit |
8f70b4 |
DirColors::DeleteInstance();
|
|
Packit |
8f70b4 |
delete cache;
|
|
Packit |
8f70b4 |
cache=0;
|
|
Packit |
8f70b4 |
FileCopy::fxp_create=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const FileAccessRef& FileAccessRef::operator=(FileAccess *p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
reuse();
|
|
Packit |
8f70b4 |
ptr=SMTask::MakeRef(p);
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// hook-up gnulib...
|
|
Packit |
8f70b4 |
CDECL_BEGIN
|
|
Packit |
8f70b4 |
#include "md5.h"
|
|
Packit |
8f70b4 |
#include "glob.h"
|
|
Packit |
8f70b4 |
CDECL_END
|
|
Packit |
8f70b4 |
void *_md5_hook=(void*)md5_init_ctx;
|
|
Packit |
8f70b4 |
void *_glob_hook=(void*)glob;
|