int SyncTransferThread::do_touch_sftp_file_with_time(QString fileName, QDateTime time) { // sftp_open, 可以得到当前的文件属性 // sftp_close, // 修改LIBSSH2_SFTP_ATTRIBUTE中的最后修改日期 // sftp_set_stat, 修改文件的最后修改日期。 LIBSSH2_SFTP_ATTRIBUTES attr; int ret; ret = libssh2_sftp_stat(this->ssh2_sftp, GlobalOption::instance()->remote_codec->fromUnicode(fileName), &attr); if (ret != 0) { //int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf char errmsg[200] = {0}; int emlen = 0; libssh2_session_last_error(this->ssh2_sess, (char **)&errmsg, &emlen, 0); q_debug()<<"sftp set stat error: "<<errmsg; } attr.flags = LIBSSH2_SFTP_ATTR_ACMODTIME; attr.mtime = time.toTime_t(); ret = libssh2_sftp_setstat(this->ssh2_sftp, GlobalOption::instance()->remote_codec->fromUnicode(fileName), &attr); if (ret != 0) { char errmsg[200] = {0}; int emlen = 0; libssh2_session_last_error(this->ssh2_sess, (char **)&errmsg, &emlen, 0); q_debug()<<"sftp set stat error: "<<errmsg; } return 0; }
// in which we fill the stat struct of sftppath using sftp int get_file_stat_struct() { int res; struct stat *buf = malloc(sizeof(struct stat)); if (buf == NULL) fprintf(stderr, "malloc'ing struct stat returned NULL\n"); LIBSSH2_SFTP_ATTRIBUTES attrs; res = libssh2_sftp_stat(sftp_session, sftppath, &attrs); do { if (res < 0 && res != LIBSSH2_ERROR_EAGAIN) { // there /is/ an errno in here and stuff fprintf(stderr, "sftp_stat failed 2\n"); exit(1); } } while (res == LIBSSH2_ERROR_EAGAIN); buf->st_nlink = 1; buf->st_uid = attrs.uid; buf->st_gid = attrs.gid; buf->st_atime = attrs.atime; buf->st_mtime = attrs.mtime; buf->st_ctime = attrs.mtime; buf->st_size = attrs.filesize; buf->st_mode = attrs.permissions; return 0; }
int FSSftp::Stat ( FSPath& path, FSStat* st, int* err, FSCInfo* info ) { MutexLock lock( &mutex ); int ret = CheckSession( err, info ); if ( ret ) { return ret; } char* fullPath = ( char* ) path.GetString( _operParam.charset, '/' ); try { SftpAttr attr; int ret; WHILE_EAGAIN_( ret, libssh2_sftp_lstat( sftpSession, fullPath, &attr.attr ) ); CheckSFTP( ret ); if ( attr.IsLink() ) { char buf[4096]; int len; WHILE_EAGAIN_( len, libssh2_sftp_readlink( sftpSession, fullPath, buf, sizeof( buf ) ) ); if ( len < 0 ) { CheckSFTP( len ); }; st->link.Set( _operParam.charset, buf ); int ret; WHILE_EAGAIN_( ret, libssh2_sftp_stat( sftpSession, fullPath, &attr.attr ) ); if ( ret ) { attr.attr.permissions = 0; } } st->mode = attr.Permissions(); st->size = attr.Size(); st->uid = attr.Uid(); st->gid = attr.Gid(); st->mtime = attr.MTime(); } catch ( int e ) { st->mode = 0; if ( err ) { *err = e; } return ( e == -2 ) ? -2 : -1; } return 0; }
int FSSftp::ReadDir ( FSList* list, FSPath& path, int* err, FSCInfo* info ) { MutexLock lock( &mutex ); int ret = CheckSession( err, info ); if ( ret ) { return ret; } if ( !list ) { return 0; } list->Clear(); try { LIBSSH2_SFTP_HANDLE* dir = 0; try { while ( true ) { dir = libssh2_sftp_opendir( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ) ); if ( dir ) { break; } CheckSFTPEagain(); WaitSocket( info ); } while ( true ) { char buf[4096]; int len = 0; SftpAttr attr; WHILE_EAGAIN_( len, libssh2_sftp_readdir( dir, buf, sizeof( buf ) - 1, &attr.attr ) ); if ( len < 0 ) { CheckSFTP( len ); } if ( len == 0 ) { break; } if ( buf[0] == '.' && ( !buf[1] || ( buf[1] == '.' && !buf[2] ) ) ) { continue; } clPtr<FSNode> pNode = new FSNode(); pNode->name.Set( _operParam.charset, buf ); if ( attr.IsLink() ) { FSPath pt = path; pt.Push( _operParam.charset, buf ); char* fullPath = ( char* )pt.GetString( _operParam.charset, '/' ); WHILE_EAGAIN_( len, libssh2_sftp_readlink( sftpSession, fullPath, buf, sizeof( buf ) - 1 ) ); if ( len < 0 ) { CheckSFTP( len ); } pNode->st.link.Set( _operParam.charset, buf ); int ret; WHILE_EAGAIN_( ret, libssh2_sftp_stat( sftpSession, fullPath, &attr.attr ) ); } pNode->st.mode = attr.Permissions(); pNode->st.size = attr.Size(); pNode->st.uid = attr.Uid(); pNode->st.gid = attr.Gid(); pNode->st.mtime = attr.MTime(); list->Append( pNode ); } } catch ( ... ) { if ( dir ) { CloseHandle( dir, info ); } throw; } if ( dir ) { CloseHandle( dir, info ); } } catch ( int e ) { if ( err ) { *err = e; } return ( e == -2 ) ? -2 : -1; } return 0; }
static int uwsgi_ssh_request_file( struct wsgi_request *wsgi_req, char* filepath, struct uwsgi_ssh_mountpoint *usm ) { int sock = -1; int return_status = 0; LIBSSH2_SESSION *session = NULL; if (uwsgi_init_ssh_session(usm, &sock, &session)) { uwsgi_log("[SSH] session initialization failed. Is the SSH server up?\n"); return_status = 500; goto shutdown; } LIBSSH2_SFTP *sftp_session = NULL; do { sftp_session = libssh2_sftp_init(session); if (!sftp_session) { if ((libssh2_session_last_errno(session)) == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto shutdown; } } else { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_init()"); return_status = 500; goto shutdown; } } } while (!sftp_session); // Request file stats via SFTP LIBSSH2_SFTP_ATTRIBUTES file_attrs; int rc; while ((rc = libssh2_sftp_stat(sftp_session, filepath, &file_attrs)) == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto shutdown; } } if (rc < 0) { // If it fails, requested file could not exist. if (rc == LIBSSH2_ERROR_SFTP_PROTOCOL && libssh2_sftp_last_error(sftp_session) == LIBSSH2_FX_NO_SUCH_FILE) { return_status = 404; } else { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_stat()"); return_status = 500; } goto sftp_shutdown; } if (wsgi_req->if_modified_since_len) { time_t ims = uwsgi_parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len); if (file_attrs.mtime <= (unsigned long)ims) { if (uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16) || uwsgi_response_write_headers_do(wsgi_req)) { uwsgi_error("uwsgi_parse_http_date()/uwsgi_response_prepare_headers(do)()"); } return_status = 500; goto sftp_shutdown; } } if (uwsgi_response_prepare_headers(wsgi_req, "200", 3)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_prepare_headers()"); return_status = 500; goto sftp_shutdown; } if (uwsgi_response_add_content_length(wsgi_req, file_attrs.filesize)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_content_length()"); return_status = 500; goto sftp_shutdown; } if (uwsgi_response_add_last_modified(wsgi_req, file_attrs.mtime)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_last_modified()"); return_status = 500; goto sftp_shutdown; } size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(filepath, strlen(filepath), &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_content_type()"); // goto sftp_shutdown; } } // Request a file via SFTP LIBSSH2_SFTP_HANDLE *sftp_handle = NULL; do { sftp_handle = libssh2_sftp_open(sftp_session, filepath, LIBSSH2_FXF_READ, 0); if (!sftp_handle) { if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_open()"); return_status = 500; goto sftp_shutdown; } else { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto sftp_shutdown; } } } } while (!sftp_handle); size_t buffer_size = uwsgi.page_size; void *buffer = alloca(buffer_size); libssh2_uint64_t read_size = 0; while (read_size < file_attrs.filesize) { rc = libssh2_sftp_read(sftp_handle, buffer, buffer_size); if (rc == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto sftp_shutdown; } } else if (rc < 0) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_read()"); break; } else { read_size += rc; if (uwsgi_response_write_body_do(wsgi_req, buffer, rc)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_write_body_do()"); break; } } } while ((rc = libssh2_sftp_close(sftp_handle)) == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto sftp_shutdown; } }; if (rc < 0) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_close()"); } sftp_shutdown: while ((rc = libssh2_sftp_shutdown(sftp_session)) == LIBSSH2_ERROR_EAGAIN) { uwsgi_ssh_waitsocket(sock, session); } if (rc < 0) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_shutdown()"); } shutdown: while (libssh2_session_disconnect(session, "Normal Shutdown, thank you!") == LIBSSH2_ERROR_EAGAIN) { uwsgi_ssh_waitsocket(sock, session); } libssh2_session_free(session); close(sock); libssh2_exit(); return return_status; }
void PJSSH::PutStream(std::istream & aStream, const char* aRemoteFileName) const { //Check if local file exists if(!aStream) { std::string error("The local file does not exist"); throw std::runtime_error(error); } LIBSSH2_SFTP* sftp = libssh2_sftp_init(mSession); if( NULL == sftp ) { throw std::runtime_error("Failed to open a sftp session."); } //Check if remote file exitst LIBSSH2_SFTP_ATTRIBUTES fileinfo; int status = libssh2_sftp_stat(sftp, aRemoteFileName , &fileinfo); if(status == 0) { //File exitsts std::string error("The file " + std::string(aRemoteFileName) + " alerady exists"); throw std::runtime_error(error); } LIBSSH2_SFTP_HANDLE* file_handle = libssh2_sftp_open(sftp,aRemoteFileName, LIBSSH2_FXF_TRUNC | LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT,0); if( NULL == file_handle ) { std::ostringstream o; o<<"Failed to write on remote file. Last error code=" <<libssh2_sftp_last_error(sftp); throw std::runtime_error(o.str()); } char buffer[1024]; do { aStream.read(buffer,1024); const std::streamsize num_of_read_characters(aStream.gcount()); if( num_of_read_characters > 0 ) { const size_t num_of_bytes_written = libssh2_sftp_write( file_handle, buffer, num_of_read_characters); if( num_of_bytes_written == ((size_t)-1) ) { throw std::runtime_error("Failed to write to the remote file."); } else if( static_cast<std::streamsize>(num_of_bytes_written) != num_of_read_characters ) { throw std::runtime_error("Failed to write all bytes to remote file."); } else if(num_of_read_characters <= 0) { throw std::runtime_error("Failed to read characters from the input " "stream to be written to the remote file."); } } } while( aStream ); // Close sftp file handle and end SFTP session. libssh2_sftp_close_handle(file_handle); libssh2_sftp_shutdown(sftp); }
CURLcode Curl_sftp_do(struct connectdata *conn, bool *done) { LIBSSH2_SFTP_ATTRIBUTES attrs; struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh; CURLcode res = CURLE_OK; struct SessionHandle *data = conn->data; curl_off_t bytecount = 0; char *buf = data->state.buffer; *done = TRUE; /* unconditionally */ if (data->set.upload) { /* * NOTE!!! libssh2 requires that the destination path is a full path * that includes the destination file and name OR ends in a "/" . * If this is not done the destination file will be named the * same name as the last directory in the path. */ sftp->sftp_handle = libssh2_sftp_open(sftp->sftp_session, sftp->path, LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT, LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR| LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH); if (!sftp->sftp_handle) return CURLE_FAILED_INIT; /* upload data */ res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); } else { if (sftp->path[strlen(sftp->path)-1] == '/') { /* * This is a directory that we are trying to get, so produce a * directory listing * * **BLOCKING behaviour** This should be made into a state machine and * get a separate function called from Curl_sftp_recv() when there is * data to read from the network, instead of "hanging" here. */ char filename[PATH_MAX+1]; int len, totalLen, currLen; char *line; sftp->sftp_handle = libssh2_sftp_opendir(sftp->sftp_session, sftp->path); if (!sftp->sftp_handle) return CURLE_SSH; while ((len = libssh2_sftp_readdir(sftp->sftp_handle, filename, PATH_MAX, &attrs)) > 0) { filename[len] = '\0'; if (data->set.ftp_list_only) { if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR)) { infof(data, "%s\n", filename); } } else { totalLen = 80 + len; line = (char *)malloc(totalLen); if (!line) return CURLE_OUT_OF_MEMORY; if (!(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID)) attrs.uid = attrs.gid =0; currLen = snprintf(line, totalLen, "---------- 1 %5d %5d", attrs.uid, attrs.gid); if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR) { line[0] = 'd'; } else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK) { line[0] = 'l'; } else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK) { line[0] = 's'; } else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR) { line[0] = 'c'; } else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK) { line[0] = 'b'; } if (attrs.permissions & LIBSSH2_SFTP_S_IRUSR) { line[1] = 'r'; } if (attrs.permissions & LIBSSH2_SFTP_S_IWUSR) { line[2] = 'w'; } if (attrs.permissions & LIBSSH2_SFTP_S_IXUSR) { line[3] = 'x'; } if (attrs.permissions & LIBSSH2_SFTP_S_IRGRP) { line[4] = 'r'; } if (attrs.permissions & LIBSSH2_SFTP_S_IWGRP) { line[5] = 'w'; } if (attrs.permissions & LIBSSH2_SFTP_S_IXGRP) { line[6] = 'x'; } if (attrs.permissions & LIBSSH2_SFTP_S_IROTH) { line[7] = 'r'; } if (attrs.permissions & LIBSSH2_SFTP_S_IWOTH) { line[8] = 'w'; } if (attrs.permissions & LIBSSH2_SFTP_S_IXOTH) { line[9] = 'x'; } } if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) { currLen += snprintf(line+currLen, totalLen-currLen, "%11lld", attrs.filesize); } if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { const char *months[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; struct tm *nowParts; time_t now, remoteTime; now = time(NULL); remoteTime = (time_t)attrs.mtime; nowParts = localtime(&remoteTime); if ((time_t)attrs.mtime > (now - (3600 * 24 * 180))) { currLen += snprintf(line+currLen, totalLen-currLen, " %s %2d %2d:%02d", months[nowParts->tm_mon], nowParts->tm_mday, nowParts->tm_hour, nowParts->tm_min); } else { currLen += snprintf(line+currLen, totalLen-currLen, " %s %2d %5d", months[nowParts->tm_mon], nowParts->tm_mday, 1900+nowParts->tm_year); } } currLen += snprintf(line+currLen, totalLen-currLen, " %s", filename); if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK)) { char linkPath[PATH_MAX + 1]; snprintf(linkPath, PATH_MAX, "%s%s", sftp->path, filename); len = libssh2_sftp_readlink(sftp->sftp_session, linkPath, filename, PATH_MAX); line = realloc(line, totalLen + 4 + len); if (!line) return CURLE_OUT_OF_MEMORY; currLen += snprintf(line+currLen, totalLen-currLen, " -> %s", filename); } currLen += snprintf(line+currLen, totalLen-currLen, "\n"); res = Curl_client_write(conn, CLIENTWRITE_BODY, line, 0); free(line); } } libssh2_sftp_closedir(sftp->sftp_handle); sftp->sftp_handle = NULL; /* no data to transfer */ res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); } else { /* * Work on getting the specified file */ sftp->sftp_handle = libssh2_sftp_open(sftp->sftp_session, sftp->path, LIBSSH2_FXF_READ, LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR| LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH); if (!sftp->sftp_handle) return CURLE_SSH; if (libssh2_sftp_stat(sftp->sftp_session, sftp->path, &attrs)) { /* * libssh2_sftp_open() didn't return an error, so maybe the server * just doesn't support stat() */ data->reqdata.size = -1; data->reqdata.maxdownload = -1; } else { data->reqdata.size = attrs.filesize; data->reqdata.maxdownload = attrs.filesize; Curl_pgrsSetDownloadSize(data, attrs.filesize); } Curl_pgrsTime(data, TIMER_STARTTRANSFER); /* Now download data. The libssh2 0.14 doesn't offer any way to do this without using this BLOCKING approach, so here's room for improvement once libssh2 can return EWOULDBLOCK to us. */ #if 0 /* code left here just because this is what this function will use the day libssh2 is improved */ res = Curl_setup_transfer(conn, FIRSTSOCKET, bytecount, FALSE, NULL, -1, NULL); #endif while (res == CURLE_OK) { size_t nread; /* NOTE: most *read() functions return ssize_t but this returns size_t which normally is unsigned! */ nread = libssh2_sftp_read(data->reqdata.proto.ssh->sftp_handle, buf, BUFSIZE-1); if (nread > 0) buf[nread] = 0; /* this check can be changed to a <= 0 when nread is changed to a signed variable type */ if ((nread == 0) || (nread == (size_t)~0)) break; bytecount += nread; res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); if(res) return res; Curl_pgrsSetDownloadCounter(data, bytecount); if(Curl_pgrsUpdate(conn)) res = CURLE_ABORTED_BY_CALLBACK; else { struct timeval now = Curl_tvnow(); res = Curl_speedcheck(data, now); } } if(Curl_pgrsUpdate(conn)) res = CURLE_ABORTED_BY_CALLBACK; /* no (more) data to transfer */ res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); } } return res; }