|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2017 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 "trio.h"
|
|
Packit |
8f70b4 |
#include "xstring.h"
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <stdlib.h>
|
|
Packit |
8f70b4 |
#include <fnmatch.h>
|
|
Packit |
8f70b4 |
#include <stddef.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "FileGlob.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "url.h"
|
|
Packit |
8f70b4 |
#include "ResMgr.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ResDecl res_nullglob("cmd:nullglob","yes",ResMgr::BoolValidate,ResMgr::NoClosure);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// Glob implementation
|
|
Packit |
8f70b4 |
Glob::Glob(FileAccess *s,const char *p)
|
|
Packit |
8f70b4 |
: FileAccessOperation(s), pattern(p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dirs_only=false;
|
|
Packit |
8f70b4 |
files_only=false;
|
|
Packit |
8f70b4 |
match_period=true;
|
|
Packit |
8f70b4 |
inhibit_tilde=true;
|
|
Packit |
8f70b4 |
casefold=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pattern[0]=='~')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *slash=strchr(pattern,'/');
|
|
Packit |
8f70b4 |
if(slash)
|
|
Packit |
8f70b4 |
inhibit_tilde=HasWildcards(xstring::get_tmp(pattern,slash-pattern));
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
inhibit_tilde=HasWildcards(pattern);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(pattern[0] && !HasWildcards(pattern))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// no need to glob, just unquote
|
|
Packit |
8f70b4 |
char *u=alloca_strdup(pattern);
|
|
Packit |
8f70b4 |
UnquoteWildcards(u);
|
|
Packit |
8f70b4 |
add(new FileInfo(u));
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
Glob::~Glob()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Glob::add_force(const FileInfo *info)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// insert new file name into list
|
|
Packit |
8f70b4 |
list.Add(new FileInfo(*info));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Glob::add(const FileInfo *info)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(info->defined&info->TYPE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(dirs_only && info->filetype==info->NORMAL)
|
|
Packit |
8f70b4 |
return; // note that symlinks can point to directories,
|
|
Packit |
8f70b4 |
// so skip normal files only.
|
|
Packit |
8f70b4 |
if(files_only && info->filetype==info->DIRECTORY)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *s=info->name;
|
|
Packit |
8f70b4 |
if(s==0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int flags=FNM_PATHNAME;
|
|
Packit |
8f70b4 |
if(match_period)
|
|
Packit |
8f70b4 |
flags|=FNM_PERIOD;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(casefold)
|
|
Packit |
8f70b4 |
flags|=FNM_CASEFOLD;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pattern[0]!=0
|
|
Packit |
8f70b4 |
&& fnmatch(pattern, s, flags)!=0)
|
|
Packit |
8f70b4 |
return; // unmatched
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(s[0]=='~' && inhibit_tilde)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *new_name=alloca_strdup2(s,2);
|
|
Packit |
8f70b4 |
strcpy(new_name,"./");
|
|
Packit |
8f70b4 |
strcat(new_name,s);
|
|
Packit |
8f70b4 |
FileInfo new_info(*info);
|
|
Packit |
8f70b4 |
new_info.SetName(new_name);
|
|
Packit |
8f70b4 |
add_force(&new_info);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
add_force(info);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool Glob::HasWildcards(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
while(*s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
switch(*s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case '\\':
|
|
Packit |
8f70b4 |
if(s[1])
|
|
Packit |
8f70b4 |
s++;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case '*':
|
|
Packit |
8f70b4 |
case '[':
|
|
Packit |
8f70b4 |
case ']':
|
|
Packit |
8f70b4 |
case '?':
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
s++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Glob::UnquoteWildcards(char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *store=s;
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(*s=='\\')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(s[1]=='*'
|
|
Packit |
8f70b4 |
|| s[1]=='['
|
|
Packit |
8f70b4 |
|| s[1]==']'
|
|
Packit |
8f70b4 |
|| s[1]=='?'
|
|
Packit |
8f70b4 |
|| s[1]=='\\')
|
|
Packit |
8f70b4 |
s++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
*store=*s;
|
|
Packit |
8f70b4 |
if(*s==0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
s++;
|
|
Packit |
8f70b4 |
store++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int NoGlob::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!done)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!HasWildcards(pattern))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *p=alloca_strdup(pattern);
|
|
Packit |
8f70b4 |
UnquoteWildcards(p);
|
|
Packit |
8f70b4 |
add(new FileInfo(p));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
NoGlob::NoGlob(const char *p) : Glob(0,p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void GlobURL::NewGlob(const char *p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
glob=0;
|
|
Packit |
8f70b4 |
session=orig_session;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
url_prefix.set(p);
|
|
Packit |
8f70b4 |
url_prefix.truncate(url::path_index(p));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ParsedURL p_url(p,true);
|
|
Packit |
8f70b4 |
if(p_url.proto && p_url.path)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
session=my_session=FA::New(&p_url);
|
|
Packit |
8f70b4 |
if(session)
|
|
Packit |
8f70b4 |
glob=session->MakeGlob(p_url.path);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
glob=session->MakeGlob(p);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!glob)
|
|
Packit |
8f70b4 |
glob=new NoGlob(p);
|
|
Packit |
8f70b4 |
if(type==FILES_ONLY)
|
|
Packit |
8f70b4 |
glob->FilesOnly();
|
|
Packit |
8f70b4 |
else if(type==DIRS_ONLY)
|
|
Packit |
8f70b4 |
glob->DirectoriesOnly();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
GlobURL::GlobURL(const FileAccessRef& s,const char *p,type_select t)
|
|
Packit |
8f70b4 |
: orig_session(s), session(orig_session), type(t)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
nullglob=ResMgr::QueryBool("cmd:nullglob",0);
|
|
Packit |
8f70b4 |
NewGlob(p);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
GlobURL::~GlobURL() {}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileSet *GlobURL::GetResult()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileSet &list=*glob->GetResult();
|
|
Packit |
8f70b4 |
if(list.count()==0 && !nullglob)
|
|
Packit |
8f70b4 |
list.Add(new FileInfo(glob->GetPattern()));
|
|
Packit |
8f70b4 |
if(session==orig_session)
|
|
Packit |
8f70b4 |
return &list;
|
|
Packit |
8f70b4 |
for(int i=0; list[i]; i++)
|
|
Packit |
8f70b4 |
list[i]->SetName(url_file(url_prefix,list[i]->name));
|
|
Packit |
8f70b4 |
return &list;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// GenericGlob implementation
|
|
Packit |
8f70b4 |
GenericGlob::GenericGlob(FileAccess *s,const char *n_pattern)
|
|
Packit |
8f70b4 |
: Glob(s,n_pattern)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dir_list=0;
|
|
Packit |
8f70b4 |
curr_dir=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *dir=alloca_strdup(pattern);
|
|
Packit |
8f70b4 |
char *slash=strrchr(dir,'/');
|
|
Packit |
8f70b4 |
if(!slash)
|
|
Packit |
8f70b4 |
dir=0;
|
|
Packit |
8f70b4 |
else if(slash>dir)
|
|
Packit |
8f70b4 |
*slash=0; // non-root directory
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
dir[1]=0; // root directory
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
updir_glob=new GenericGlob(s,dir);
|
|
Packit |
8f70b4 |
updir_glob->DirectoriesOnly();
|
|
Packit |
8f70b4 |
updir_glob->Suspend(); // don't run now, wait for options.
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int GenericGlob::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!dir_list && updir_glob)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(updir_glob->IsSuspended())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// pass the options.
|
|
Packit |
8f70b4 |
updir_glob->MatchPeriod(match_period);
|
|
Packit |
8f70b4 |
updir_glob->InhibitTilde(inhibit_tilde);
|
|
Packit |
8f70b4 |
updir_glob->CaseFold(casefold);
|
|
Packit |
8f70b4 |
updir_glob->Resume();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(updir_glob->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(updir_glob->ErrorText());
|
|
Packit |
8f70b4 |
updir_glob=0;
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!updir_glob->Done())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
dir_list=updir_glob->GetResult();
|
|
Packit |
8f70b4 |
dir_list->rewind();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
if(dir_list==0 || dir_list->curr()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
curr_dir=dir_list->curr()->name;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(li)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!li->Done() && !li->Error())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(li->Done() && !li->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileSet *set=li->GetResult();
|
|
Packit |
8f70b4 |
set->rewind();
|
|
Packit |
8f70b4 |
for(FileInfo *info=set->curr(); info!=NULL; info=set->next())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *name=info->name;
|
|
Packit |
8f70b4 |
if(name[0]=='.' && name[1]=='/')
|
|
Packit |
8f70b4 |
name+=2;
|
|
Packit |
8f70b4 |
if(curr_dir && curr_dir[0])
|
|
Packit |
8f70b4 |
name=dir_file(curr_dir,name);
|
|
Packit |
8f70b4 |
info->SetName(name);
|
|
Packit |
8f70b4 |
add(info);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
delete set;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(dir_list)
|
|
Packit |
8f70b4 |
dir_list->next();
|
|
Packit |
8f70b4 |
if(!dir_list || dir_list->curr()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(li && li->Error())
|
|
Packit |
8f70b4 |
SetError(li->ErrorText());
|
|
Packit |
8f70b4 |
li=0;
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
li=0;
|
|
Packit |
8f70b4 |
curr_dir=dir_list->curr()->name;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
li=session->MakeListInfo(curr_dir);
|
|
Packit |
8f70b4 |
if(!li)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// Cannot glob. Just unquote wildcards.
|
|
Packit |
8f70b4 |
char *p=alloca_strdup(pattern);
|
|
Packit |
8f70b4 |
UnquoteWildcards(p);
|
|
Packit |
8f70b4 |
add(new FileInfo(p));
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
li->UseCache(use_cache);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *GenericGlob::Status()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(updir_glob && !dir_list)
|
|
Packit |
8f70b4 |
return updir_glob->Status();
|
|
Packit |
8f70b4 |
if(!li)
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *st = li->Status();
|
|
Packit |
8f70b4 |
if(!*st)
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!curr_dir)
|
|
Packit |
8f70b4 |
return st;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static xstring buf;
|
|
Packit |
8f70b4 |
buf.vset(curr_dir,": ",st,NULL);
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
}
|