Blame src/LocalAccess.cc

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