Blame src/LocalAccess.cc

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