|
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 |
|
|
Packit |
8f70b4 |
#include "trio.h"
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <stdlib.h>
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include <utime.h>
|
|
Packit |
8f70b4 |
#include <sys/stat.h>
|
|
Packit |
8f70b4 |
#include <sys/wait.h>
|
|
Packit |
8f70b4 |
#include <stddef.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "Filter.h"
|
|
Packit |
8f70b4 |
#include "SignalHook.h"
|
|
Packit |
8f70b4 |
#include "ArgV.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "FileSet.h"
|
|
Packit |
8f70b4 |
#include "ResMgr.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifndef O_BINARY
|
|
Packit |
8f70b4 |
# define O_BINARY 0
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FDStream::FDStream(int new_fd,const char *new_name)
|
|
Packit |
8f70b4 |
: close_when_done(false), closed(false), fd(new_fd), name(new_name?expand_home_relative(new_name):0), status(0) {}
|
|
Packit |
8f70b4 |
FDStream::FDStream()
|
|
Packit |
8f70b4 |
: close_when_done(false), closed(false), fd(-1), status(0) {}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FDStream::MakeErrorText(int e)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!e)
|
|
Packit |
8f70b4 |
e=errno;
|
|
Packit |
8f70b4 |
if(NonFatalError(e))
|
|
Packit |
8f70b4 |
return; // not a serious error - can be retried
|
|
Packit |
8f70b4 |
error_text.vset(name.get(),": ",strerror(e),NULL);
|
|
Packit |
8f70b4 |
revert_backup();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FDStream::SetCwd(const char *new_cwd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cwd.set(new_cwd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FDStream::DoCloseFD()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(fd!=-1) {
|
|
Packit |
8f70b4 |
if(close_when_done) {
|
|
Packit |
8f70b4 |
close(fd);
|
|
Packit |
8f70b4 |
Log::global->Format(11,"closed FD %d\n",fd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
fd=-1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FDStream::SetFD(int new_fd,bool c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
DoCloseFD();
|
|
Packit |
8f70b4 |
fd=new_fd;
|
|
Packit |
8f70b4 |
close_when_done=c;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool FDStream::Done()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(closed)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
DoCloseFD();
|
|
Packit |
8f70b4 |
closed=true;
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FDStream::~FDStream()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
DoCloseFD();
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void OutputFilter::Parent(int *p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
close(p[0]);
|
|
Packit |
8f70b4 |
SetFD(p[1],true);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void InputFilter::Parent(int *p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
close(p[1]);
|
|
Packit |
8f70b4 |
SetFD(p[0],true);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void OutputFilter::Child(int *p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
close(p[1]);
|
|
Packit |
8f70b4 |
if(p[0]!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dup2(p[0],0);
|
|
Packit |
8f70b4 |
close(p[0]);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(second_fd!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(second_fd!=1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dup2(second_fd,1);
|
|
Packit |
8f70b4 |
close(second_fd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int fl=fcntl(1,F_GETFL);
|
|
Packit |
8f70b4 |
fcntl(1,F_SETFL,fl&~O_NONBLOCK);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void InputFilter::Child(int *p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
close(p[0]);
|
|
Packit |
8f70b4 |
if(p[1]!=1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dup2(p[1],1);
|
|
Packit |
8f70b4 |
close(p[1]);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(second_fd!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(second_fd!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dup2(second_fd,0);
|
|
Packit |
8f70b4 |
close(second_fd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int fl=fcntl(0,F_GETFL);
|
|
Packit |
8f70b4 |
fcntl(0,F_SETFL,fl&~O_NONBLOCK);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int OutputFilter::getfd()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(fd!=-1 || error() || closed)
|
|
Packit |
8f70b4 |
return fd;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(second && second_fd==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
second_fd=second->getfd();
|
|
Packit |
8f70b4 |
if(second_fd==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(second->error())
|
|
Packit |
8f70b4 |
error_text.set(second->error_text);
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(pg==0)
|
|
Packit |
8f70b4 |
pg=second->GetProcGroup();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int p[2];
|
|
Packit |
8f70b4 |
pid_t pid;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pipe(p)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(NonFatalError(errno))
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
error_text.vset(_("pipe() failed: "),strerror(errno),NULL);
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ProcWait::Signal(false);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool had_pg=(pg!=0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
fflush(stdout);
|
|
Packit |
8f70b4 |
fflush(stderr);
|
|
Packit |
8f70b4 |
switch(pid=fork())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(0): /* child */
|
|
Packit |
8f70b4 |
setpgid(0,pg);
|
|
Packit |
8f70b4 |
kill(getpid(),SIGSTOP);
|
|
Packit |
8f70b4 |
SignalHook::RestoreAll();
|
|
Packit |
8f70b4 |
Child(p);
|
|
Packit |
8f70b4 |
if(stderr_to_stdout)
|
|
Packit |
8f70b4 |
dup2(1,2);
|
|
Packit |
8f70b4 |
if(stdout_to_null)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
close(1);
|
|
Packit |
8f70b4 |
int null=open("/dev/null",O_RDWR);
|
|
Packit |
8f70b4 |
if(null==-1)
|
|
Packit |
8f70b4 |
perror("open(\"/dev/null\")");
|
|
Packit |
8f70b4 |
else if(null==0) {
|
|
Packit |
8f70b4 |
if(dup(0)==-1)
|
|
Packit |
8f70b4 |
perror("dup");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(cwd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(chdir(cwd)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
fprintf(stderr,_("chdir(%s) failed: %s\n"),cwd.get(),strerror(errno));
|
|
Packit |
8f70b4 |
fflush(stderr);
|
|
Packit |
8f70b4 |
_exit(1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(a)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
execvp(a->a0(),a->GetVNonConst());
|
|
Packit |
8f70b4 |
fprintf(stderr,_("execvp(%s) failed: %s\n"),a->a0(),strerror(errno));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
execl("/bin/sh","sh","-c",name.get(),NULL);
|
|
Packit |
8f70b4 |
fprintf(stderr,_("execl(/bin/sh) failed: %s\n"),strerror(errno));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
fflush(stderr);
|
|
Packit |
8f70b4 |
_exit(1);
|
|
Packit |
8f70b4 |
case(-1): /* error */
|
|
Packit |
8f70b4 |
close(p[0]);
|
|
Packit |
8f70b4 |
close(p[1]);
|
|
Packit |
8f70b4 |
goto out;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pg==0)
|
|
Packit |
8f70b4 |
pg=pid;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* parent */
|
|
Packit |
8f70b4 |
Parent(p);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
fcntl(fd,F_SETFD,FD_CLOEXEC);
|
|
Packit |
8f70b4 |
fcntl(fd,F_SETFL,O_NONBLOCK);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// wait until the child stops.
|
|
Packit |
8f70b4 |
int info;
|
|
Packit |
8f70b4 |
waitpid(pid,&info,WUNTRACED);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
w=new ProcWait(pid);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(had_pg)
|
|
Packit |
8f70b4 |
kill(pid,SIGCONT);
|
|
Packit |
8f70b4 |
out:
|
|
Packit |
8f70b4 |
ProcWait::Signal(true);
|
|
Packit |
8f70b4 |
return fd;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void OutputFilter::Init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
w=0;
|
|
Packit |
8f70b4 |
second_fd=-1;
|
|
Packit |
8f70b4 |
xgetcwd_to(cwd);
|
|
Packit |
8f70b4 |
pg=0;
|
|
Packit |
8f70b4 |
stderr_to_stdout=false;
|
|
Packit |
8f70b4 |
stdout_to_null=false;
|
|
Packit |
8f70b4 |
if(a)
|
|
Packit |
8f70b4 |
a->CombineTo(name);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
OutputFilter::OutputFilter(const char *filter,int new_second_fd)
|
|
Packit |
8f70b4 |
: FDStream(-1,filter), second(my_second), second_fd(new_second_fd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
OutputFilter::OutputFilter(const char *filter,FDStream *new_second)
|
|
Packit |
8f70b4 |
: FDStream(-1,filter), my_second(new_second), second(my_second)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
OutputFilter::OutputFilter(const char *filter,const Ref<FDStream>& new_second)
|
|
Packit |
8f70b4 |
: FDStream(-1,filter), second(new_second)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
OutputFilter::OutputFilter(ArgV *a1,int new_second_fd)
|
|
Packit |
8f70b4 |
: FDStream(-1,0), a(a1), second(my_second), second_fd(new_second_fd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
OutputFilter::OutputFilter(ArgV *a1,FDStream *new_second)
|
|
Packit |
8f70b4 |
: FDStream(-1,0), a(a1), my_second(new_second), second(my_second)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
OutputFilter::OutputFilter(ArgV *a1,const Ref<FDStream>& new_second)
|
|
Packit |
8f70b4 |
: FDStream(-1,0), a(a1), second(new_second)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
OutputFilter::~OutputFilter()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(w)
|
|
Packit |
8f70b4 |
w->Auto();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool OutputFilter::Done()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!FDStream::Done())
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(w==0)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(w->GetState()!=w->RUNNING)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(my_second)
|
|
Packit |
8f70b4 |
return my_second->Done();
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool OutputFilter::broken()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(w==0)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(w->GetState()!=w->RUNNING)
|
|
Packit |
8f70b4 |
return true; // filter process terminated - pipe is broken
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void OutputFilter::Kill(int sig)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(w)
|
|
Packit |
8f70b4 |
w->Kill(sig);
|
|
Packit |
8f70b4 |
if(second)
|
|
Packit |
8f70b4 |
second->Kill(sig);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool OutputFilter::usesfd(int n_fd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(FDStream::usesfd(n_fd))
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(second_fd!=-1 && n_fd==second_fd)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(second)
|
|
Packit |
8f70b4 |
return second->usesfd(n_fd);
|
|
Packit |
8f70b4 |
return n_fd<=2;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define NO_MODE ((mode_t)-1)
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileStream::setmtime(const FileTimestamp &ts)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
getfd(); // this might create the file... But can fail retriably. FIXME.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// skip the time update if the timestamp is already accurate enough.
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(fstat(fd,&st)!=-1 && labs(st.st_mtime-ts)<=ts.ts_prec)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
struct utimbuf ut;
|
|
Packit |
8f70b4 |
ut.actime=ut.modtime=ts;
|
|
Packit |
8f70b4 |
utime(full_name,&ut);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileStream::FileStream(const char *fname,int new_mode)
|
|
Packit |
8f70b4 |
: FDStream(-1,fname), mode(new_mode), create_mode(0664),
|
|
Packit |
8f70b4 |
do_lock(ResMgr::QueryBool("file:use-lock",0)),
|
|
Packit |
8f70b4 |
no_keep_backup(false),
|
|
Packit |
8f70b4 |
old_file_mode(NO_MODE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(name[0]=='/')
|
|
Packit |
8f70b4 |
full_name.set(name);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xgetcwd_to(cwd);
|
|
Packit |
8f70b4 |
full_name.set(dir_file(cwd,name));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileStream::~FileStream()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileStream::remove()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
::remove(full_name);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileStream::remove_if_empty()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!full_name)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
int res=stat(full_name,&st);
|
|
Packit |
8f70b4 |
if(res!=-1 && st.st_size==0)
|
|
Packit |
8f70b4 |
remove();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileStream::revert_backup()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(backup_file) {
|
|
Packit |
8f70b4 |
rename(backup_file,full_name);
|
|
Packit |
8f70b4 |
backup_file.unset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileStream::remove_backup()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(backup_file && (no_keep_backup || !ResMgr::QueryBool("xfer:keep-backup",0))) {
|
|
Packit |
8f70b4 |
::remove(backup_file);
|
|
Packit |
8f70b4 |
backup_file.unset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(old_file_mode!=NO_MODE)
|
|
Packit |
8f70b4 |
chmod(full_name,old_file_mode);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileStream::getfd()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(fd!=-1 || error() || closed)
|
|
Packit |
8f70b4 |
return fd;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool clobber=!(mode&O_EXCL);
|
|
Packit |
8f70b4 |
bool truncate=(mode&O_TRUNC);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if((!clobber || truncate) && stat(full_name,&st)!=-1 && st.st_size>0 && S_ISREG(st.st_mode))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!clobber)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
error_text.vset(name.get(),": ",_("file already exists and xfer:clobber is unset"),NULL);
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(truncate && ResMgr::QueryBool("xfer:make-backup",0))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
/* rename old file if exists and size>0 */
|
|
Packit |
8f70b4 |
xstring_ca suffix(xstrftime(ResMgr::Query("xfer:backup-suffix",0),SMTask::now));
|
|
Packit |
8f70b4 |
backup_file.vset(full_name.get(),suffix.get(),NULL);
|
|
Packit |
8f70b4 |
if(rename(full_name,backup_file)!=0)
|
|
Packit |
8f70b4 |
backup_file.set(0);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
create_mode=old_file_mode=st.st_mode;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int new_fd=open(full_name,mode|O_NONBLOCK|O_BINARY,create_mode);
|
|
Packit |
8f70b4 |
if(new_fd==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
MakeErrorText();
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
Log::global->Format(11,"opened FD %d (%s)\n",new_fd,full_name.get());
|
|
Packit |
8f70b4 |
SetFD(new_fd,true);
|
|
Packit |
8f70b4 |
fcntl(fd,F_SETFD,FD_CLOEXEC);
|
|
Packit |
8f70b4 |
if(do_lock && !(mode&O_APPEND)) {
|
|
Packit |
8f70b4 |
struct flock lk;
|
|
Packit |
8f70b4 |
lk.l_type=((mode&3)==0)?F_RDLCK:F_WRLCK;
|
|
Packit |
8f70b4 |
lk.l_whence=SEEK_SET;
|
|
Packit |
8f70b4 |
lk.l_start=0;
|
|
Packit |
8f70b4 |
lk.l_len=0;
|
|
Packit |
8f70b4 |
if(fcntl(fd,F_SETLKW,&lk)==-1) {
|
|
Packit |
8f70b4 |
MakeErrorText();
|
|
Packit |
8f70b4 |
DoCloseFD();
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return fd;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool FileStream::can_seek()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode&O_APPEND)
|
|
Packit |
8f70b4 |
return false; // whatever we seek, the writes will go to end of file.
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t FileStream::get_size()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(-1==(fd==-1?stat(full_name,&st):fstat(fd,&st)))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(errno==ENOENT)
|
|
Packit |
8f70b4 |
return 0; // assume non-existent files to be empty.
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return st.st_size;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "SMTask.h"
|
|
Packit |
8f70b4 |
bool FDStream::NonFatalError(int err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(err==EDQUOT || err==ENOSPC)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(fd>=0 && fstat(fd,&st)!=-1 && st.st_nlink==0)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool non_fatal=SMTask::NonFatalError(err);
|
|
Packit |
8f70b4 |
if(non_fatal)
|
|
Packit |
8f70b4 |
set_status(strerror(err));
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
clear_status();
|
|
Packit |
8f70b4 |
return non_fatal;
|
|
Packit |
8f70b4 |
}
|