#include #include #include #include #include #include #include #include #include #include #include #include #include #include "fastscp.m" #include "fastscp.h" static bool debug = false; static void n_debug (const char *ctl, ...) { if (debug){ FILE *fout = fopen ("/tmp/fastend.log","a"); if (fout != NULL){ va_list list; va_start (list,ctl); vfprintf (fout,ctl,list); va_end (list); fclose (fout); } } } #define CRBUF_SIZE 20000 static unsigned long long crbuf[CRBUF_SIZE]; static unsigned long long *ptcr = crbuf; static unsigned long long *endcr = crbuf+CRBUF_SIZE; static unsigned long long *reccr = crbuf; static bool docrypt = false; static void fastscp_crypt (const char *buf, int n, char *dest) { if (docrypt){ const unsigned long long *endbuf = (const unsigned long long*)(buf+n); unsigned long long *wdest = (unsigned long long*)dest; for (const unsigned long long *ptbuf = (const unsigned long long*)buf; ptbuf < endbuf; ptbuf++){ *wdest++ = *ptbuf ^ *ptcr++; if (ptcr == endcr) ptcr = crbuf; } }else{ memcpy (dest,buf,n); } } static void fastscp_crypt (char *buf, int n) { if (docrypt){ int modn = n%8; if (modn != 0) n += 8-modn; unsigned long long *endbuf = (unsigned long long*)(buf+n); for (unsigned long long *ptbuf = (unsigned long long*)buf; ptbuf < endbuf; ptbuf++){ *ptbuf ^= *ptcr++; if (ptcr == endcr) ptcr = crbuf; } } } static long long fastend_send (const SSTRING &fname, int fd) { long long ret = -1; FILE *fin = fopen64 (fname.get(),"r"); n_debug ("fname :%s: %p\n",fname.get(),fin); if (fin == NULL){ fprintf (stderr,MSG_R(E_CANTOPEN),fname.get(),strerror(errno)); }else{ char buf[1024*1024]; int n; ret = 0; while ((n=fread(buf,1,sizeof(buf),fin))>0){ fastscp_crypt(buf,n); n_debug ("sendto %d %d bytes\n",fd,n); write (fd,buf,n); ret += n; } n_debug ("sent %Ld\n",ret); n = sprintf (buf,"sent %Ld\n",ret); write (1,buf,n); } return ret; } int main (int argc, char *argv[]) { glocal bool silent = false; int ret = (argc,argv,"fastscp"); fprintf (stderr,"%s\n",msg); syslog (LOG_ERR,"%s",msg); int ret = -1; glocal FILE *fout = NULL; glocal long long total = 0; glocal long long fsize = 0; glocal long long lastadvise = 0; glocal SSTRING dir = "."; glocal bool is_dir = true; glocal int netfd = -1; glocal SSTRING sendfile; glocal bool odirect = false; glocal bool fadvise = false; (5000,10); n_debug ("Nouveau client %d\n",getnbclients()); if (getnbclients() > 2){ endclient = true; }else{ glocal.netfd = no; n_debug ("netfd = %d\n",no); if (glocal.sendfile.is_filled()){ fastend_send (glocal.sendfile,no); endserver = true; } if (glocal.fout == NULL) setlisten(no,false); } setrawmode (true); unlisten(info.listenhandle); if (getnbclients()==1 || glocal.fout == NULL) endserver = true; n_debug ("endclient %d nb=%d endserver %d\n",no,getnbclients(),endserver); n_debug ("receive %d len %d netfd %d\n",no,info.linelen,glocal.netfd); if (no == 0){ if (strncmp(line,"dir ",4)==0){ // This is either a directory or an output file int must_be_dir = atoi(line+4); glocal.dir = str_skip(str_skipdig(line+4)); glocal.dir.strip_end(); if (glocal.dir.is_empty()) glocal.dir = "."; int ftype = file_type(glocal.dir.c_str()); glocal.is_dir = ftype == 1; if(must_be_dir != 0){ if (ftype == -1){ if (file_mkdirp(glocal.dir.c_str(),-1,-1,-1)==-1){ fprintf (stderr,MSG_U(E_MKDIR,"Can't create directory %s (%s)\n") ,glocal.dir.c_str(),strerror(errno)); } }else if (!glocal.is_dir){ fprintf (stderr,MSG_U(E_NOTADIR,"%s is not a directory\n"),glocal.dir.c_str()); } glocal.is_dir = true; // We force this flag so even if the // front insist on copying, it will fail } n_debug ("dir :%s: %d\n",glocal.dir.c_str(),glocal.is_dir); }else if (strncmp(line,"file ",5)==0){ const char *fname = line+5; SSTRING tmp; if (glocal.is_dir){ tmp.setfromf ("%s/%s",glocal.dir.c_str(),fname); glocal.fout = fopen64 (tmp.c_str(),"w"); n_debug ("fname :%s: %p\n",tmp.c_str(),glocal.fout); }else{ tmp = glocal.dir; glocal.fout = fopen64 (glocal.dir.c_str(),"w"); n_debug ("fname :%s: %p\n",fname,glocal.fout); } if (glocal.fout == NULL){ fprintf (stderr,MSG_R(E_CANTOPEN),tmp.c_str(),strerror(errno)); endserver = true; }else{ if (glocal.odirect){ int fd = fileno(glocal.fout); int flags = fcntl (fileno(glocal.fout),F_GETFL,0); if (flags == -1){ fprintf (stderr,MSG_U(E_GETFL,"Can't get file handle flags (%s)\n"),strerror(errno)); }else{ flags |= O_DIRECT; if (fcntl (fd,F_SETFL,&flags) == -1){ fprintf (stderr,MSG_U(E_SETFL,"Can't set file handle flags (%s)\n"),strerror(errno)); } } } if (glocal.fadvise){ fprintf (stderr,"Apply fadvise DONTNEED\n"); if (posix_fadvise64(fileno(glocal.fout),0,0,POSIX_FADV_DONTNEED)==-1){ fprintf (stderr,MSG_U(E_FADVISE,"posix_fadvise failed (%s)\n"),strerror(errno)); } } if (glocal.netfd != -1){ setlisten (glocal.netfd,true); } } glocal.total = 0; glocal.fsize = 0; glocal.lastadvise = 0; }else if (strncmp(line,"get ",4)==0){ glocal.sendfile = line+4; if (glocal.netfd != -1){ fastend_send (glocal.sendfile,glocal.netfd); endserver = true; } }else if (strncmp(line,"sent ",5)==0){ sscanf (line+5,"%Ld",&glocal.fsize); n_debug ("sent %Ld\n",glocal.fsize); if (glocal.total == glocal.fsize){ if (fclose (glocal.fout)==-1){ endserver = true; } glocal.fout = NULL; if (getnbclients() == 2) setlisten (glocal.netfd,false); n_debug ("End of file %Ld\n",glocal.total); printf ("recok\n"); fflush (stdout); } }else if (strcmp(line,"debug")==0){ debug = true; }else if (strcmp(line,"odirect")==0){ glocal.odirect = true; }else if (strcmp(line,"fadvise")==0){ glocal.fadvise = true; }else if (strncmp(line,"crbuf ",6)==0){ n_debug ("crbuf: %s\n",line); docrypt = true; const char *pt = line+6; while (isxdigit(pt[0]) && isxdigit(pt[1])){ unsigned long long val; sscanf (pt,"%016Lx",&val); pt+=16; *reccr++ = val; } // We compute the length of the buffer // based on the first long long word endcr = crbuf + (CRBUF_SIZE/2 + crbuf[0]%(CRBUF_SIZE/2)); n_debug ("Crypt buf size %u\n",endcr-crbuf); }else{ tlmp_error ("Invalid request: %s",line); endserver = true; } }else if (glocal.fout != NULL){ const char *ptline = line; char obuf[info.linelen+1024*2]; char *line2 = (char*)((long)(obuf + 1023)&(~1023)); //fprintf (stderr, "Alignement obuf %p line2 %p %x\n",obuf,line2,~1023); if (docrypt || glocal.odirect){ fastscp_crypt (line,info.linelen,line2); ptline = line2; } if (fwrite (ptline,1,info.linelen,glocal.fout) != info.linelen){ fclose (glocal.fout); fprintf (stderr,"Error while writing %s\n",strerror(errno)); }else{ glocal.total += info.linelen; if (glocal.fadvise && glocal.total > glocal.lastadvise + 1024*1024*1024l){ if (glocal.lastadvise > 0){ fprintf (stderr,"Apply fadvise DONTNEED 0 -> %Ld total=%Ld\n" ,glocal.lastadvise,glocal.total); if (posix_fadvise64(fileno(glocal.fout),0,glocal.lastadvise,POSIX_FADV_DONTNEED)==-1){ fprintf (stderr,MSG_R(E_FADVISE),strerror(errno)); } } glocal.lastadvise = glocal.total; } if (glocal.total == glocal.fsize){ if (fclose (glocal.fout)==-1){ endserver = true; } glocal.fout = NULL; if (getnbclients() == 2) setlisten (no,false); n_debug ("End of file %Ld\n",glocal.total); printf ("recok\n"); fflush (stdout); } } }else{ tlmp_error ("Attempting write without opened output file\n"); endserver = true; } int port = oo.getlistenport(); printf ("VERSION%d %d\n",FASTSCP_PROTO_VERSION,port); fflush (stdout); oo.inject (0,NULL); oo.loop(); return ret; return ret; }