|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2015 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 <errno.h>
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <sys/stat.h>
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include <dirent.h>
|
|
Packit |
8f70b4 |
#include <utime.h>
|
|
Packit |
8f70b4 |
#include <pwd.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "LocalAccess.h"
|
|
Packit |
8f70b4 |
#include "xstring.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
#include "LocalDir.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
CDECL_BEGIN
|
|
Packit |
8f70b4 |
#include <glob.h>
|
|
Packit |
8f70b4 |
CDECL_END
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define FILES_AT_ONCE_STAT 64
|
|
Packit |
8f70b4 |
#define FILES_AT_ONCE_READDIR 256
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess *LocalAccess::New() { return new LocalAccess(); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void LocalAccess::ClassInit()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// register the class
|
|
Packit |
8f70b4 |
Register("file",LocalAccess::New);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void LocalAccess::Init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
done=false;
|
|
Packit |
8f70b4 |
error_code=OK;
|
|
Packit |
8f70b4 |
home.Set(getenv("HOME"));
|
|
Packit |
8f70b4 |
hostname.set("localhost");
|
|
Packit |
8f70b4 |
struct passwd *p=getpwuid(getuid());
|
|
Packit |
8f70b4 |
if(p)
|
|
Packit |
8f70b4 |
user.set(p->pw_name);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
LocalAccess::LocalAccess() : FileAccess()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
xstring_ca c(xgetcwd());
|
|
Packit |
8f70b4 |
cwd.Set(c?c.get():".");
|
|
Packit |
8f70b4 |
LogNote(10,"local cwd is `%s'",cwd.path.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
LocalAccess::LocalAccess(const LocalAccess *o) : FileAccess(o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void LocalAccess::errno_handle()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
saved_errno=errno;
|
|
Packit |
8f70b4 |
const char *err=strerror(saved_errno);
|
|
Packit |
8f70b4 |
if(mode==RENAME)
|
|
Packit |
8f70b4 |
error.vset("rename(",file.get(),", ",file1.get(),"): ",err,NULL);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
error.vset(file.get(),": ",err,NULL);
|
|
Packit |
8f70b4 |
if(saved_errno!=EEXIST)
|
|
Packit |
8f70b4 |
LogError(0,"%s",error.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int LocalAccess::Done()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(error_code<0)
|
|
Packit |
8f70b4 |
return error_code;
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return OK;
|
|
Packit |
8f70b4 |
switch((open_mode)mode)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(CLOSED):
|
|
Packit |
8f70b4 |
case(CONNECT_VERIFY):
|
|
Packit |
8f70b4 |
return OK;
|
|
Packit |
8f70b4 |
default:
|
|
Packit |
8f70b4 |
return IN_PROGRESS;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int LocalAccess::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(Error() || done)
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
if(mode!=CLOSED)
|
|
Packit |
8f70b4 |
ExpandTildeInCWD();
|
|
Packit |
8f70b4 |
switch((open_mode)mode)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(CLOSED):
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
case(LIST):
|
|
Packit |
8f70b4 |
case(LONG_LIST):
|
|
Packit |
8f70b4 |
case(QUOTE_CMD):
|
|
Packit |
8f70b4 |
if(stream==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *cmd=0;
|
|
Packit |
8f70b4 |
// FIXME: shell-quote file name
|
|
Packit |
8f70b4 |
if(mode==LIST)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(file && file[0])
|
|
Packit |
8f70b4 |
cmd=xstring::cat("ls ",shell_encode(file).get(),NULL);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
cmd="ls";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(mode==LONG_LIST)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(file && file[0])
|
|
Packit |
8f70b4 |
cmd=xstring::cat("ls -l",shell_encode(file).get(),NULL);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
cmd="ls -la";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else// if(mode==QUOTE_CMD)
|
|
Packit |
8f70b4 |
cmd=file;
|
|
Packit |
8f70b4 |
LogNote(5,"running `%s'",cmd);
|
|
Packit |
8f70b4 |
InputFilter *f_stream=new InputFilter(cmd);
|
|
Packit |
8f70b4 |
f_stream->SetCwd(cwd);
|
|
Packit |
8f70b4 |
stream=f_stream;
|
|
Packit |
8f70b4 |
real_pos=0;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(stream->getfd()==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(stream->error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Fatal(stream->error_text);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
TimeoutS(1);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->Kill(SIGCONT);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
case(CHANGE_DIR):
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
LocalDirectory old_cwd;
|
|
Packit |
8f70b4 |
old_cwd.SetFromCWD();
|
|
Packit |
8f70b4 |
const char *err=old_cwd.Chdir();
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(NO_FILE,err);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(chdir(file)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
errno_handle();
|
|
Packit |
8f70b4 |
error_code=NO_FILE;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cwd.Set(file);
|
|
Packit |
8f70b4 |
old_cwd.Chdir();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case(REMOVE):
|
|
Packit |
8f70b4 |
case(REMOVE_DIR): {
|
|
Packit |
8f70b4 |
const char *f=dir_file(cwd,file);
|
|
Packit |
8f70b4 |
LogNote(5,"remove(%s)",f);
|
|
Packit |
8f70b4 |
if((mode==REMOVE?remove:rmdir)(f)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
errno_handle();
|
|
Packit |
8f70b4 |
error_code=NO_FILE;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case(RENAME):
|
|
Packit |
8f70b4 |
case(LINK):
|
|
Packit |
8f70b4 |
case(SYMLINK):
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *cwd_file1=dir_file(cwd,file1);
|
|
Packit |
8f70b4 |
int (*fn)(const char *f1,const char *f2)=(
|
|
Packit |
8f70b4 |
mode==RENAME ? rename :
|
|
Packit |
8f70b4 |
mode==LINK ? link :
|
|
Packit |
8f70b4 |
/*mode==SYMLINK?*/ symlink
|
|
Packit |
8f70b4 |
);
|
|
Packit |
8f70b4 |
if(fn(mode==SYMLINK?file.get():dir_file(cwd,file),cwd_file1)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
errno_handle();
|
|
Packit |
8f70b4 |
error_code=NO_FILE;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case(MAKE_DIR):
|
|
Packit |
8f70b4 |
if(mkdir_p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *sl=strchr(file,'/');
|
|
Packit |
8f70b4 |
while(sl)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(sl>file)
|
|
Packit |
8f70b4 |
mkdir(dir_file(cwd,xstring::get_tmp(file,sl-file)),0775);
|
|
Packit |
8f70b4 |
sl=strchr(sl+1,'/');
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(mkdir(dir_file(cwd,file),0775)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
errno_handle();
|
|
Packit |
8f70b4 |
error_code=NO_FILE;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
case(CHANGE_MODE):
|
|
Packit |
8f70b4 |
if(chmod(dir_file(cwd,file),chmod_mode)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
errno_handle();
|
|
Packit |
8f70b4 |
error_code=NO_FILE;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(RETRIEVE):
|
|
Packit |
8f70b4 |
case(STORE):
|
|
Packit |
8f70b4 |
if(stream==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int o_mode=O_RDONLY;
|
|
Packit |
8f70b4 |
if(mode==STORE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
o_mode=O_WRONLY|O_CREAT;
|
|
Packit |
8f70b4 |
if(pos==0)
|
|
Packit |
8f70b4 |
o_mode|=O_TRUNC;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream=new FileStream(dir_file(cwd,file),o_mode);
|
|
Packit |
8f70b4 |
real_pos=-1;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(stream->getfd()==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(stream->error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(NO_FILE,stream->error_text);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
TimeoutS(1);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->Kill(SIGCONT);
|
|
Packit |
8f70b4 |
if(opt_size || opt_date)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(fstat(stream->getfd(),&st)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(opt_size) *opt_size=NO_SIZE;
|
|
Packit |
8f70b4 |
if(opt_date) *opt_date=NO_DATE;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(opt_size)
|
|
Packit |
8f70b4 |
*opt_size=(S_ISREG(st.st_mode)?st.st_size:NO_SIZE);
|
|
Packit |
8f70b4 |
if(opt_date)
|
|
Packit |
8f70b4 |
*opt_date=st.st_mtime;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
opt_size=0;
|
|
Packit |
8f70b4 |
opt_date=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(CONNECT_VERIFY):
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(ARRAY_INFO):
|
|
Packit |
8f70b4 |
fill_array_info();
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
case MP_LIST:
|
|
Packit |
8f70b4 |
SetError(NOT_SUPP);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void LocalAccess::fill_array_info()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(FileInfo *fi=fileset_for_info->curr(); fi; fi=fileset_for_info->next())
|
|
Packit |
8f70b4 |
fi->LocalFile(fi->name,(fi->filetype!=fi->SYMLINK));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int LocalAccess::Read(Buffer *buf0,int size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(error_code<0)
|
|
Packit |
8f70b4 |
return error_code;
|
|
Packit |
8f70b4 |
if(stream==0)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
int fd=stream->getfd();
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
if(real_pos==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ascii || lseek(fd,pos,SEEK_SET)==-1)
|
|
Packit |
8f70b4 |
real_pos=0;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
real_pos=pos;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->Kill(SIGCONT);
|
|
Packit |
8f70b4 |
read_again:
|
|
Packit |
8f70b4 |
int res;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *buf=buf0->GetSpace(size);
|
|
Packit |
8f70b4 |
#ifndef NATIVE_CRLF
|
|
Packit |
8f70b4 |
if(ascii)
|
|
Packit |
8f70b4 |
res=read(fd,buf,size/2);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
res=read(fd,buf,size);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
saved_errno=errno;
|
|
Packit |
8f70b4 |
if(E_RETRY(saved_errno))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Block(stream->getfd(),POLLIN);
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(stream->NonFatalError(saved_errno))
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
return SEE_ERRNO;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->clear_status();
|
|
Packit |
8f70b4 |
if(res==0)
|
|
Packit |
8f70b4 |
return res; // eof
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifndef NATIVE_CRLF
|
|
Packit |
8f70b4 |
if(ascii)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *p=buf;
|
|
Packit |
8f70b4 |
for(int i=res; i>0; i--)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(*p=='\n')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
memmove(p+1,p,i);
|
|
Packit |
8f70b4 |
*p++='\r';
|
|
Packit |
8f70b4 |
res++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
p++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
real_pos+=res;
|
|
Packit |
8f70b4 |
if(real_pos<=pos)
|
|
Packit |
8f70b4 |
goto read_again;
|
|
Packit |
8f70b4 |
off_t shift=pos+res-real_pos;
|
|
Packit |
8f70b4 |
if(shift>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
memmove(buf,buf+shift,size-shift);
|
|
Packit |
8f70b4 |
res-=shift;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
pos+=res;
|
|
Packit |
8f70b4 |
return(res);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int LocalAccess::Write(const void *vbuf,int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *buf=(const char *)vbuf;
|
|
Packit |
8f70b4 |
if(error_code<0)
|
|
Packit |
8f70b4 |
return error_code;
|
|
Packit |
8f70b4 |
if(stream==0)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
int fd=stream->getfd();
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
if(real_pos==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ascii || lseek(fd,pos,SEEK_SET)==-1)
|
|
Packit |
8f70b4 |
real_pos=0;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
real_pos=pos;
|
|
Packit |
8f70b4 |
if(real_pos
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
error_code=STORE_FAILED;
|
|
Packit |
8f70b4 |
return error_code;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->Kill(SIGCONT);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int skip_cr=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifndef NATIVE_CRLF
|
|
Packit |
8f70b4 |
if(ascii)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// find where line ends.
|
|
Packit |
8f70b4 |
const char *cr=buf;
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cr=(const char *)memchr(cr,'\r',len-(cr-buf));
|
|
Packit |
8f70b4 |
if(!cr)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(cr-buf
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
skip_cr=1;
|
|
Packit |
8f70b4 |
len=cr-buf;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(cr-buf==len-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(len==1) // last CR in stream will be lost. (FIX?)
|
|
Packit |
8f70b4 |
skip_cr=1;
|
|
Packit |
8f70b4 |
len--;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
cr++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif // NATIVE_CRLF
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(len==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pos=(real_pos+=skip_cr);
|
|
Packit |
8f70b4 |
return skip_cr;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int res=write(fd,buf,len);
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
saved_errno=errno;
|
|
Packit |
8f70b4 |
if(E_RETRY(saved_errno))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Block(stream->getfd(),POLLOUT);
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(stream->NonFatalError(saved_errno))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// in case of full disk, check file correctness.
|
|
Packit |
8f70b4 |
if(saved_errno==ENOSPC)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(fstat(fd,&st)!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(st.st_size
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// workaround solaris nfs bug. It can lose data if disk is full.
|
|
Packit |
8f70b4 |
pos=real_pos=st.st_size;
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return SEE_ERRNO;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->clear_status();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(res==len)
|
|
Packit |
8f70b4 |
res+=skip_cr;
|
|
Packit |
8f70b4 |
pos=(real_pos+=res);
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int LocalAccess::StoreStatus()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode!=STORE)
|
|
Packit |
8f70b4 |
return OK;
|
|
Packit |
8f70b4 |
if(!stream)
|
|
Packit |
8f70b4 |
return IN_PROGRESS;
|
|
Packit |
8f70b4 |
if(stream->getfd()==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(stream->error())
|
|
Packit |
8f70b4 |
SetError(NO_FILE,stream->error_text);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream=0;
|
|
Packit |
8f70b4 |
if(error_code==OK && entity_date!=NO_DATE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static struct utimbuf ut;
|
|
Packit |
8f70b4 |
ut.actime=ut.modtime=entity_date;
|
|
Packit |
8f70b4 |
utime(dir_file(cwd,file),&ut);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(error_code<0)
|
|
Packit |
8f70b4 |
return error_code;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return OK;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void LocalAccess::Close()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
done=false;
|
|
Packit |
8f70b4 |
error_code=OK;
|
|
Packit |
8f70b4 |
stream=0;
|
|
Packit |
8f70b4 |
FileAccess::Close();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *LocalAccess::CurrentStatus()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(stream && stream->status)
|
|
Packit |
8f70b4 |
return stream->status;
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool LocalAccess::SameLocationAs(const FileAccess *fa) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!SameProtoAs(fa))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
LocalAccess *o=(LocalAccess*)fa;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(xstrcmp(home,o->home))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return !xstrcmp(cwd,o->cwd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class LocalListInfo : public ListInfo
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
DIR *dir;
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
LocalListInfo(FileAccess *s,const char *d) : ListInfo(s,d), dir(0) {}
|
|
Packit |
8f70b4 |
~LocalListInfo() { if(dir) closedir(dir); }
|
|
Packit |
8f70b4 |
const char *Status();
|
|
Packit |
8f70b4 |
int Do();
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ListInfo *LocalAccess::MakeListInfo(const char *path)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return new LocalListInfo(this,path);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int LocalListInfo::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!dir && !result)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *path=session->GetCwd();
|
|
Packit |
8f70b4 |
dir=opendir(path);
|
|
Packit |
8f70b4 |
if(!dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(xstring::format("%s: %s",path,strerror(errno)));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!result)
|
|
Packit |
8f70b4 |
result=new FileSet;
|
|
Packit |
8f70b4 |
int count=FILES_AT_ONCE_READDIR;
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct dirent *f=readdir(dir);
|
|
Packit |
8f70b4 |
if(f==0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
const char *name=f->d_name;
|
|
Packit |
8f70b4 |
if(name[0]=='~')
|
|
Packit |
8f70b4 |
name=dir_file(".",name);
|
|
Packit |
8f70b4 |
result->Add(new FileInfo(name));
|
|
Packit |
8f70b4 |
if(!--count)
|
|
Packit |
8f70b4 |
return MOVED; // let other tasks run
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
closedir(dir);
|
|
Packit |
8f70b4 |
dir=0;
|
|
Packit |
8f70b4 |
result->rewind();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!dir && result)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int count=FILES_AT_ONCE_STAT;
|
|
Packit |
8f70b4 |
const char *path=session->GetCwd();
|
|
Packit |
8f70b4 |
for(FileInfo *file=result->curr(); file!=0; file=result->next())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *name=dir_file(path,file->name);
|
|
Packit |
8f70b4 |
file->LocalFile(name, follow_symlinks);
|
|
Packit |
8f70b4 |
if(!(file->defined&file->TYPE))
|
|
Packit |
8f70b4 |
result->SubtractCurr();
|
|
Packit |
8f70b4 |
if(!--count)
|
|
Packit |
8f70b4 |
return MOVED; // let other tasks run
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
result->Exclude(exclude_prefix,exclude,excluded.get_non_const());
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *LocalListInfo::Status()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
if(dir && result)
|
|
Packit |
8f70b4 |
return xstring::format("%s (%d)",_("Getting directory contents"),result->count());
|
|
Packit |
8f70b4 |
if(result && result->count())
|
|
Packit |
8f70b4 |
return xstring::format("%s (%d%%)",_("Getting files information"),result->curr_pct());
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "FileGlob.h"
|
|
Packit |
8f70b4 |
class LocalGlob : public Glob
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *cwd;
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
LocalGlob(const char *cwd,const char *pattern);
|
|
Packit |
8f70b4 |
const char *Status() { return "Reading directory"; }
|
|
Packit |
8f70b4 |
int Do();
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
Glob *LocalAccess::MakeGlob(const char *pattern)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file.set(pattern);
|
|
Packit |
8f70b4 |
ExpandTildeInCWD();
|
|
Packit |
8f70b4 |
return new LocalGlob(cwd,file);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
LocalGlob::LocalGlob(const char *c,const char *pattern)
|
|
Packit |
8f70b4 |
: Glob(0,pattern)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cwd=c;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int LocalGlob::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
glob_t g;
|
|
Packit |
8f70b4 |
LocalDirectory oldcwd;
|
|
Packit |
8f70b4 |
oldcwd.SetFromCWD();
|
|
Packit |
8f70b4 |
// check if we can return.
|
|
Packit |
8f70b4 |
if(oldcwd.Chdir())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(_("cannot get current directory"));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(chdir(cwd)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(xstring::format("chdir(%s): %s",cwd,strerror(errno)));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
glob(pattern, 0, NULL, &g);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(unsigned i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
FileInfo info(g.gl_pathv[i]);
|
|
Packit |
8f70b4 |
if(stat(g.gl_pathv[i],&st)!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(dirs_only && !S_ISDIR(st.st_mode))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(files_only && !S_ISREG(st.st_mode))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(S_ISDIR(st.st_mode))
|
|
Packit |
8f70b4 |
info.SetType(info.DIRECTORY);
|
|
Packit |
8f70b4 |
else if(S_ISREG(st.st_mode))
|
|
Packit |
8f70b4 |
info.SetType(info.NORMAL);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
add(&info;;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
globfree(&g);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *err=oldcwd.Chdir();
|
|
Packit |
8f70b4 |
const char *name=oldcwd.GetName();
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
fprintf(stderr,"chdir(%s): %s",name?name:"?",err);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class LocalDirList : public DirList
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SMTaskRef<IOBuffer> ubuf;
|
|
Packit |
8f70b4 |
Ref<FgData> fg_data;
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
LocalDirList(ArgV *a,const char *cwd);
|
|
Packit |
8f70b4 |
const char *Status() { return ""; }
|
|
Packit |
8f70b4 |
int Do();
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
DirList *LocalAccess::MakeDirList(ArgV *a)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return new LocalDirList(a,cwd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "ArgV.h"
|
|
Packit |
8f70b4 |
LocalDirList::LocalDirList(ArgV *a,const char *cwd)
|
|
Packit |
8f70b4 |
: DirList(0,0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
a->setarg(0,"ls");
|
|
Packit |
8f70b4 |
a->insarg(1,"-l");
|
|
Packit |
8f70b4 |
InputFilter *f=new InputFilter(a); // a is consumed.
|
|
Packit |
8f70b4 |
f->SetCwd(cwd);
|
|
Packit |
8f70b4 |
ubuf=new IOBufferFDStream(f,IOBuffer::GET);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int LocalDirList::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return STALL;
|
|
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->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(ubuf->ErrorText());
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!fg_data)
|
|
Packit |
8f70b4 |
fg_data=ubuf->GetFgData(false);
|
|
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 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(len==0)
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
buf->Put(b,len);
|
|
Packit |
8f70b4 |
ubuf->Skip(len);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "modconfig.h"
|
|
Packit |
8f70b4 |
#ifdef MODULE_PROTO_FILE
|
|
Packit |
8f70b4 |
CDECL void module_init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
LocalAccess::ClassInit();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|