/** * @brief Create a new scp session. * * @param[in] session The SSH session to use. * * @param[in] mode One of SSH_SCP_WRITE or SSH_SCP_READ, depending if you * need to drop files remotely or read them. * It is not possible to combine read and write. * SSH_SCP_RECURSIVE Flag can be or'ed to this to indicate * that you're going to use recursion. Browsing through * directories is not possible without this. * * @param[in] location The directory in which write or read will be done. Any * push or pull will be relative to this place. * This can also be a pattern of files to download (read). * * @returns A ssh_scp handle, NULL if the creation was impossible. */ ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){ ssh_scp scp=malloc(sizeof(struct ssh_scp_struct)); if(scp == NULL){ ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp"); return NULL; } ZERO_STRUCTP(scp); if((mode&~SSH_SCP_RECURSIVE) != SSH_SCP_WRITE && (mode &~SSH_SCP_RECURSIVE) != SSH_SCP_READ){ ssh_set_error(session,SSH_FATAL,"Invalid mode %d for ssh_scp_new()",mode); ssh_scp_free(scp); return NULL; } scp->location=strdup(location); if (scp->location == NULL) { ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp"); ssh_scp_free(scp); return NULL; } scp->session=session; scp->mode=mode & ~SSH_SCP_RECURSIVE; scp->recursive = (mode & SSH_SCP_RECURSIVE) != 0; scp->channel=NULL; scp->state=SSH_SCP_NEW; return scp; }
static int open_location(struct location *loc, int flag){ if(loc->is_ssh && flag==WRITE){ loc->session=connect_ssh(loc->host,loc->user,verbosity); if(!loc->session){ fprintf(stderr,"Couldn't connect to %s\n",loc->host); return -1; } loc->scp=ssh_scp_new(loc->session,SSH_SCP_WRITE,loc->path); if(!loc->scp){ fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); return -1; } if(ssh_scp_init(loc->scp)==SSH_ERROR){ fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); ssh_scp_free(loc->scp); return -1; } return 0; } else if(loc->is_ssh && flag==READ){ loc->session=connect_ssh(loc->host, loc->user,verbosity); if(!loc->session){ fprintf(stderr,"Couldn't connect to %s\n",loc->host); return -1; } loc->scp=ssh_scp_new(loc->session,SSH_SCP_READ,loc->path); if(!loc->scp){ fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); return -1; } if(ssh_scp_init(loc->scp)==SSH_ERROR){ fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); ssh_scp_free(loc->scp); return -1; } return 0; } else { loc->file=fopen(loc->path,flag==READ ? "r":"w"); if(!loc->file){ if(errno==EISDIR){ if(chdir(loc->path)){ fprintf(stderr,"Error changing directory to %s: %s\n",loc->path,strerror(errno)); return -1; } return 0; } fprintf(stderr,"Error opening %s: %s\n",loc->path,strerror(errno)); return -1; } return 0; } return -1; }
int doCopy(int argc, char **argv){ struct location *dest, *src; int i; int r; if(opts(argc,argv)<0) return EXIT_FAILURE; dest=parse_location(destination); if(open_location(dest,WRITE)<0) return EXIT_FAILURE; for(i=0;i<nsources;++i){ src=parse_location(sources[i]); if(open_location(src,READ)<0){ return EXIT_FAILURE; } if(do_copy(src,dest,0) < 0){ break; } } if(dest->is_ssh){ r=ssh_scp_close(dest->scp); if(r == SSH_ERROR){ fprintf(stderr,"Error closing scp: %s\n",ssh_get_error(dest->session)); ssh_scp_free(dest->scp); dest->scp=NULL; return -1; } } else { fclose(dest->file); dest->file=NULL; } ssh_disconnect(dest->session); ssh_finalize(); return 0; }
static void close_location(struct location *loc) { int rc; if (loc) { if (loc->is_ssh) { if (loc->scp) { rc = ssh_scp_close(loc->scp); if (rc == SSH_ERROR) { fprintf(stderr, "Error closing scp: %s\n", ssh_get_error(loc->session)); } ssh_scp_free(loc->scp); loc->scp = NULL; } if (loc->session) { ssh_disconnect(loc->session); ssh_free(loc->session); loc->session = NULL; } } else { if (loc->file) { fclose(loc->file); loc->file = NULL; } } } }
static ssh_session scp_close(struct scp_ud *scpud){ if (scpud == NULL || scpud->scp == NULL)return NULL; ssh_session session= scpud->scp->session; ssh_scp_close(scpud->scp); ssh_scp_free(scpud->scp); scpud->scp=NULL; return session; }
int scp_write(ssh_session session) { ssh_scp scp; int rc; scp = ssh_scp_new(session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, "."); if(scp == NULL) { fprintf(stderr, "Error allocation scp session: %s\n", ssh_get_error(session)); return SSH_ERROR; } rc = ssh_scp_init(scp); if(rc != SSH_OK) { fprintf(stderr, "Error initializing scp session: %s\n", ssh_get_error(session)); ssh_scp_free(scp); return rc; } ssh_scp_close(scp); ssh_scp_free(scp); return SSH_OK; }
int lscp_new(lua_State *L) { ssh_session session=get_session(L); const char * location = luaL_checkstring(L, 2); int mode=get_scp_mode(L,3); ssh_scp scp=ssh_scp_new(session, mode, location); if(ssh_scp_init(scp) != SSH_OK){ ssh_scp_free(scp); luaL_error(L,ssh_get_error(session)); } struct scp_ud * scpud = lua_newuserdata(L, sizeof(*scpud)); scpud->scp =scp; if (luaL_newmetatable(L, "scpmeta")) { lua_pushcfunction(L, lscp_close); lua_setfield(L, -2, "__gc"); luaL_Reg l[] = { {"close",lscp_close}, {"write",lscp_write}, {"read",lscp_read}, {"pull_request",lscp_pull_request}, {"request_get_warning",lscp_request_get_warning}, {"request_get_size",lscp_request_get_size}, {"request_get_filename",lscp_request_get_filename}, {"request_get_permissions",lscp_request_get_permissions}, {"accept_request",lscp_accept_request}, {"leave_directory",lscp_leave_directory}, {"push_directory",lscp_push_directory}, {"push_file",lscp_push_file}, {"deny_request",lscp_deny_request}, { NULL, NULL }, }; luaL_newlib(L, l); lua_setfield(L, -2, "__index"); } lua_setmetatable(L, -2); return 1; }
int SSH::scp(const std::string& filePath, const byte* data, size_t size) { ssh_scp scp; int rc; size_t found = filePath.find_last_of("/\\"); std::string filename = filePath.substr(found+1); std::string path = filePath.substr(0, found+1); scp = ssh_scp_new(session_, SSH_SCP_WRITE, path.c_str()); if (scp == NULL) { throw Error(1, ssh_get_error(session_)); rc = SSH_ERROR; } else { rc = ssh_scp_init(scp); if (rc != SSH_OK) { throw Error(1, ssh_get_error(session_)); } else { #ifdef _MSC_VER // S_IRUSR & S_IWUSR not in MSVC (0000400 & 0000200 in /usr/include/sys/stat.h on MacOS-X 10.8) #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #endif rc = ssh_scp_push_file (scp, filename.c_str(), size, S_IRUSR | S_IWUSR); if (rc != SSH_OK) { throw Error(1, ssh_get_error(session_)); } else { rc = ssh_scp_write(scp, data, size); if (rc != SSH_OK) { throw Error(1, ssh_get_error(session_)); } } ssh_scp_close(scp); } ssh_scp_free(scp); } return rc; }
/** @brief copies files from source location to destination * @param src source location * @param dest destination location * @param recursive Copy also directories */ static int do_copy(struct location *src, struct location *dest, int recursive){ int size; socket_t fd; struct stat s; int w,r; char buffer[16384]; int total=0; int mode; char *filename; /* recursive mode doesn't work yet */ (void)recursive; /* Get the file name and size*/ if(!src->is_ssh){ fd=fileno(src->file); fstat(fd,&s); size=s.st_size; mode = s.st_mode & S_IFMT; filename=ssh_basename(src->path); } else { size=0; do { r=ssh_scp_pull_request(src->scp); if(r==SSH_SCP_REQUEST_NEWDIR){ ssh_scp_deny_request(src->scp,"Not in recursive mode"); continue; } if(r==SSH_SCP_REQUEST_NEWFILE){ size=ssh_scp_request_get_size(src->scp); filename=strdup(ssh_scp_request_get_filename(src->scp)); mode=ssh_scp_request_get_permissions(src->scp); //ssh_scp_accept_request(src->scp); break; } if(r==SSH_ERROR){ fprintf(stderr,"Error: %s\n",ssh_get_error(src->session)); return -1; } } while(r != SSH_SCP_REQUEST_NEWFILE); } if(dest->is_ssh){ r=ssh_scp_push_file(dest->scp,src->path, size, mode); // snprintf(buffer,sizeof(buffer),"C0644 %d %s\n",size,src->path); if(r==SSH_ERROR){ fprintf(stderr,"error: %s\n",ssh_get_error(dest->session)); ssh_scp_free(dest->scp); return -1; } } else { if(!dest->file){ dest->file=fopen(filename,"w"); if(!dest->file){ fprintf(stderr,"Cannot open %s for writing: %s\n",filename,strerror(errno)); if(src->is_ssh) ssh_scp_deny_request(src->scp,"Cannot open local file"); return -1; } } if(src->is_ssh){ ssh_scp_accept_request(src->scp); } } do { if(src->is_ssh){ r=ssh_scp_read(src->scp,buffer,sizeof(buffer)); if(r==SSH_ERROR){ fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(src->session)); return -1; } if(r==0) break; } else { r=fread(buffer,1,sizeof(buffer),src->file); if(r==0) break; if(r<0){ fprintf(stderr,"Error reading file: %s\n",strerror(errno)); return -1; } } if(dest->is_ssh){ w=ssh_scp_write(dest->scp,buffer,r); if(w == SSH_ERROR){ fprintf(stderr,"Error writing in scp: %s\n",ssh_get_error(dest->session)); ssh_scp_free(dest->scp); dest->scp=NULL; return -1; } } else { w=fwrite(buffer,r,1,dest->file); if(w<=0){ fprintf(stderr,"Error writing in local file: %s\n",strerror(errno)); return -1; } } total+=r; } while(total < size); printf("wrote %d bytes\n",total); return 0; }
static int do_write(const char* path, FILE* fp, ftp_transfer_func hookf, uint64_t offset) { /* try to set up a scp connection */ if (gvSSHTrySCP && !offset) { ssh_scp scp = ssh_scp_new(ftp->session, SSH_SCP_WRITE, path); if (scp != NULL) { int rc = ssh_scp_init(scp); if (rc == SSH_OK) return do_scp_write(scp, path, fp, hookf); ssh_scp_free(scp); } } time_t then = time(NULL) - 1; ftp_set_close_handler(); if (hookf) hookf(&ftp->ti); ftp->ti.begin = false; struct stat sb; errno = 0; if (fstat(fileno(fp), &sb) == -1) { ftp_err(_("Couldn't fstat local file: %s\n"), strerror(errno)); return -1; } /* open remote file */ sftp_file file = sftp_open(ftp->sftp_session, path, O_WRONLY | O_CREAT | (offset == 0u ? O_TRUNC : 0), sb.st_mode); if (!file) { ftp_err(_("Cannot open file for writing: %s\n"), ssh_get_error(ftp->session)); return -1; } /* seek to offset */ int r = sftp_seek64(file, offset); if (r != SSH_OK) { ftp_err(_("Failed to seek: %s\n"), ssh_get_error(ftp->session)); sftp_close(file); return -1; } /* read file */ char buffer[SSH_BUFSIZ]; ssize_t nbytes = 0; errno = 0; while ((nbytes = fread(buffer, sizeof(char), sizeof(buffer), fp)) > 0) { if (ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } ssize_t nwritten = sftp_write(file, buffer, nbytes); if (nwritten != nbytes) { ftp_err(_("Error while writing to file: %s\n"), ssh_get_error(ftp->session)); sftp_close(file); return -1; } ftp->ti.size += nbytes; if (hookf) { time_t now = time(NULL); if (now > then) { hookf(&ftp->ti); then = now; } } errno = 0; } if (ferror(fp)) { ftp_err(_("Failed to read from file: %s\n"), strerror(errno)); r = -1; } sftp_close(file); return r; }
static int do_scp_write(ssh_scp scp, const char* path, FILE* fp, ftp_transfer_func hookf) { time_t then = time(NULL) - 1; ftp_set_close_handler(); if (hookf) hookf(&ftp->ti); ftp->ti.begin = false; struct stat sb; errno = 0; if (fstat(fileno(fp), &sb) == -1) { ftp_err(_("Couldn't fstat local file: %s\n"), strerror(errno)); ssh_scp_free(scp); return -1; } int rc = ssh_scp_push_file(scp, path, sb.st_size, sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); if (rc != SSH_OK) { ftp_err(_("Failed to start scp upload: %s\n"), ssh_get_error(ftp->session)); ssh_scp_close(scp); ssh_scp_free(scp); return -1; } /* read file */ char buffer[SSH_BUFSIZ]; ssize_t nbytes = 0; errno = 0; while ((nbytes = fread(buffer, sizeof(char), sizeof(buffer), fp)) > 0) { if (ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } rc = ssh_scp_write(scp, buffer, nbytes); if (rc != SSH_OK) { ftp_err(_("Error while writing to file: %s\n"), ssh_get_error(ftp->session)); ssh_scp_close(scp); ssh_scp_free(scp); return -1; } ftp->ti.size += nbytes; if (hookf) { time_t now = time(NULL); if (now > then) { hookf(&ftp->ti); then = now; } } errno = 0; } if (ferror(fp)) { ftp_err(_("Failed to read from file: %s\n"), strerror(errno)); rc = -1; } ssh_scp_close(scp); ssh_scp_free(scp); return rc; }
static int do_read(const char* infile, FILE* fp, getmode_t mode, ftp_transfer_func hookf, uint64_t offset) { if (gvSSHTrySCP && !offset) { char* escaped = bash_backslash_quote(infile); /* try to set up a scp connection */ ssh_scp scp = ssh_scp_new(ftp->session, SSH_SCP_READ, escaped); free(escaped); if (scp != NULL) { int rc = ssh_scp_init(scp); if (rc == SSH_OK) return do_scp_read(scp, infile, fp, mode, hookf); ssh_scp_free(scp); } } time_t then = time(NULL) - 1; ftp_set_close_handler(); if (hookf) hookf(&ftp->ti); ftp->ti.begin = false; /* check if remote file is not a directory */ sftp_attributes attrib = sftp_stat(ftp->sftp_session, infile); if (!attrib) return -1; if (S_ISDIR(attrib->permissions)) { ftp_err(_("Cannot download a directory: %s\n"), infile); sftp_attributes_free(attrib); return -1; } sftp_attributes_free(attrib); /* open remote file */ sftp_file file = sftp_open(ftp->sftp_session, infile, O_RDONLY, 0); if (!file) { ftp_err(_("Cannot open file for reading: %s\n"), ssh_get_error(ftp->session)); return -1; } /* seek to offset */ int r = sftp_seek64(file, offset); if (r != SSH_OK) { ftp_err(_("Failed to seek: %s\n"), ssh_get_error(ftp->session)); sftp_close(file); return -1; } /* read file */ char buffer[SSH_BUFSIZ]; ssize_t nbytes = 0; while ((nbytes = sftp_read(file, buffer, sizeof(buffer))) > 0) { if (ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } errno = 0; if (fwrite(buffer, nbytes, 1, fp) != 1) { ftp_err(_("Error while writing to file: %s\n"), strerror(errno)); ftp->ti.ioerror = true; sftp_close(file); return -1; } ftp->ti.size += nbytes; if (hookf) { time_t now = time(NULL); if (now > then) { hookf(&ftp->ti); then = now; } } } if (nbytes < 0) { ftp_err(_("Error while reading from file: %s\n"), ssh_get_error(ftp->session)); r = -1; } sftp_close(file); return r; }
static int do_scp_read(ssh_scp scp, const char* infile, FILE* fp, getmode_t mode, ftp_transfer_func hookf) { time_t then = time(NULL) - 1; ftp_set_close_handler(); if (hookf) hookf(&ftp->ti); ftp->ti.begin = false; int rc = ssh_scp_pull_request(scp); if (rc != SSH_SCP_REQUEST_NEWFILE) { ftp_err(_("Failed to start scp download: %s\n"), ssh_get_error(ftp->session)); ssh_scp_close(scp); ssh_scp_free(scp); return -1; } size_t size = ssh_scp_request_get_size(scp); ssh_scp_accept_request(scp); /* read file */ char buffer[SSH_BUFSIZ]; int r = 0; while (size && (r = ssh_scp_read(scp, buffer, MIN(SSH_BUFSIZ, size))) != SSH_ERROR) { if (ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } errno = 0; if (fwrite(buffer, r, 1, fp) != 1) { ftp_err(_("Error while writing to file: %s\n"), strerror(errno)); ssh_scp_close(scp); ssh_scp_free(scp); return -1; } ftp->ti.size += r; if (hookf) { time_t now = time(NULL); if (now > then) { hookf(&ftp->ti); then = now; } } size -= r; } if (r == SSH_ERROR) { ftp_err(_("Error while reading from file: %s\n"), ssh_get_error(ftp->session)); r = -1; } else { r = ssh_scp_pull_request(scp); if (r != SSH_SCP_REQUEST_EOF) ftp_err(_("Unexpected request: %s %lu\n"), ssh_get_error(ftp->session), size); else r = 0; } ssh_scp_close(scp); ssh_scp_free(scp); return r; }