void SFtpFileEngine::readDir(const QString &dir) { QString cacheDir(getCachePath(dir, true)); _fileInfoCache->removeDirInfo(cacheDir); // add an empty entry to distinguish a empty directory from // a non-existent directory _fileInfoCache->addFileInfo(cacheDir, QUrlInfo()); LIBSSH2_SFTP_HANDLE* dir_handle; dir_handle = libssh2_sftp_opendir(_sftp_session, _textCodec->fromUnicode(dir).data()); if (dir_handle) { QByteArray entry(512, 0); QByteArray longEntry(512, 0); LIBSSH2_SFTP_ATTRIBUTES attr; while (libssh2_sftp_readdir_ex(dir_handle, entry.data(), entry.capacity(), longEntry.data(), longEntry.capacity(), &attr) > 0) { QString entryUni(_textCodec->toUnicode(entry.data())); QUrlInfo urlInfo; attr2urlinfo(&urlInfo, entryUni, &attr); _fileInfoCache->addFileInfo(cacheDir, urlInfo); } libssh2_sftp_closedir(dir_handle); } }
/** * @function SFTP.readDir * * ### Synopsis * * var files = SFTP.readDir(handle, path); * * Read a directory from remote server, return an array of objects of the form: * * + name: name of file. * + longentry: a string? * + size: size of file in bytes. * + permissions: file permissions. * + uid: uid of owner of file. * + gid: gid of owner of file. * + mtime: modification time (timestamp) of file. * + atime: access time (timestamp) of file * * The above values may be undefined (except for name), if the SSH2 library and remote server don't allow extended information. * * @param {object} handle - opaque handle to existing SFTP connection (already connected). * @param {string} path - path on remote server to directory to get listing of. * @return {array} files - array of objects as specifed above, or string containing error message. */ JSVAL sftp_readdir (JSARGS args) { HandleScope scope; SFTP *handle = HANDLE(args[0]); String::Utf8Value path(args[1]); LIBSSH2_SFTP_HANDLE *sftp_handle = libssh2_sftp_opendir(handle->sftp_session, *path); if (!sftp_handle) { return scope.Close(String::New("Could not open remote directory")); } char mem[512], longentry[512]; LIBSSH2_SFTP_ATTRIBUTES attrs; Handle<String> _name = String::New("name"); Handle<String> _longentry = String::New("longentry"); Handle<String> _permissions = String::New("permissions"); Handle<String> _uid = String::New("uid"); Handle<String> _gid = String::New("gid"); Handle<String> _size = String::New("size"); Handle<String> _mtime = String::New("mtime"); Handle<String> _atime = String::New("atime"); Handle<Array>a = Array::New(); int aIndex = 0; while (1) { if (libssh2_sftp_readdir_ex(sftp_handle, mem, sizeof (mem), longentry, sizeof (longentry), &attrs) <= 0) { break; } JSOBJ o = Object::New(); o->Set(_name, String::New(mem)); o->Set(_longentry, String::New(longentry)); if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) { o->Set(_size, Integer::New(attrs.filesize)); } if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { o->Set(_permissions, Integer::New(attrs.permissions)); } if (attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) { o->Set(_uid, Integer::New(attrs.uid)); o->Set(_gid, Integer::New(attrs.gid)); } if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { o->Set(_mtime, Integer::New(attrs.mtime)); o->Set(_atime, Integer::New(attrs.atime)); } a->Set(aIndex++, o); } libssh2_sftp_closedir(sftp_handle); return scope.Close(a); }
/* sftp打开文件夹 */ static int sftp_open_dir(protocol_data_t *protocol, char *dirpath) { if (protocol == NULL || protocol->protocol_data || dirpath == NULL) { return; } sftp_data_t *data = (sftp_data_t *)protocol->protocol_data; data->dir_handle = libssh2_sftp_opendir(data->sftp_session, dirpath); if (!data->dir_handle) { return -1; } return 0; }
/* sftp删除文件夹 */ static int sftp_rm_dir(protocol_data_t *protocol, char *dirname) { int rc; LIBSSH2_SFTP_ATTRIBUTES attrs; LIBSSH2_SFTP_HANDLE *dir_handle; char source[MAX_PATH_LEN] = {0}; if (protocol == NULL || protocol->protocol_data == NULL || dirname == NULL) { return -1; } sftp_data_t *data = (sftp_data_t *)protocol->protocol_data; strcpy(source, dirname); dir_handle = libssh2_sftp_opendir(data->sftp_session, source); if (!dir_handle) { return -1; } do { char filename[MAX_FILENAME_LEN] = {0}; /*255是文件名最大长度*/ rc = libssh2_sftp_readdir_ex(dir_handle, filename, sizeof(filename), NULL, 0, &attrs); if(rc > 0) { if (filename[0] != '\0' && filename[0] != '.') {/*略去隐藏文件*/ if (LIBSSH2_SFTP_S_ISREG(attrs.permissions)) { add_lastfilename(source, filename); libssh2_sftp_unlink(data->sftp_session, source); del_lastfilename(source); } if(LIBSSH2_SFTP_S_ISDIR(attrs.permissions)){ add_lastdirname(source, filename); sftp_rm_dir(protocol, source); del_lastdirname(source); } } } else if (rc == 0) { break; } else { continue; } } while (1); libssh2_sftp_closedir(dir_handle); libssh2_sftp_rmdir(data->sftp_session, source); return 0; }
void * sftpfs_opendir (const vfs_path_t * vpath, GError ** error) { sftpfs_dir_data_t *sftpfs_dir; struct vfs_s_super *super; sftpfs_super_data_t *super_data; const vfs_path_element_t *path_element; LIBSSH2_SFTP_HANDLE *handle; path_element = vfs_path_get_by_index (vpath, -1); if (vfs_s_get_path (vpath, &super, 0) == NULL) return NULL; super_data = (sftpfs_super_data_t *) super->data; while (TRUE) { int libssh_errno; handle = libssh2_sftp_opendir (super_data->sftp_session, sftpfs_fix_filename (path_element->path)); if (handle != NULL) break; libssh_errno = libssh2_session_last_errno (super_data->session); if (libssh_errno != LIBSSH2_ERROR_EAGAIN) { sftpfs_ssherror_to_gliberror (super_data, libssh_errno, error); return NULL; } sftpfs_waitsocket (super_data, error); if (error != NULL && *error != NULL) return NULL; } sftpfs_dir = g_new0 (sftpfs_dir_data_t, 1); sftpfs_dir->handle = handle; sftpfs_dir->super_data = super_data; return (void *) sftpfs_dir; }
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; }
int SSHDirRetriver::retrive_dir() { int exec_ret = -1; NetDirNode *parent_item, *new_item, *tmp_item; void *parent_persistent_index; QString tmp; QVector<NetDirNode*> deltaItems; QVector<QMap<char, QString> > fileinfos; char file_name[PATH_MAX+1]; int fxp_ls_ret = 0; while (this->dir_node_process_queue.size() > 0) { std::map<NetDirNode*,void * >::iterator mit; mit = this->dir_node_process_queue.begin(); parent_item = mit->first; parent_persistent_index = mit->second; fileinfos.clear(); LIBSSH2_SFTP_ATTRIBUTES ssh2_sftp_attrib; LIBSSH2_SFTP_HANDLE *ssh2_sftp_handle = 0; ssh2_sftp_handle = libssh2_sftp_opendir(this->ssh2_sftp, GlobalOption::instance()->remote_codec ->fromUnicode(parent_item->fullPath + ("/")).data()); // ssh2_sftp_handle == 0 是怎么回事呢? 返回值 应该是 // 1 . 这个file_name 是一个链接,但这个链接指向的是一个普通文件而不是目录时libssh2_sftp_opendir返回0 , 而 libssh2_sftp_last_error 返回值为 2 == SSH2_FX_NO_SUCH_FILE if (ssh2_sftp_handle == 0) { qDebug()<<" sftp last error: "<< libssh2_sftp_last_error(this->ssh2_sftp) << libssh2_session_last_errno(this->ssh2_sess) <<(parent_item->fullPath+ ( "/" )) <<GlobalOption::instance()->remote_codec ->fromUnicode(parent_item->fullPath + ( "/" )).data(); } fxp_ls_ret = 0; while (ssh2_sftp_handle != 0 && libssh2_sftp_readdir(ssh2_sftp_handle, file_name, PATH_MAX, &ssh2_sftp_attrib ) > 0) { if (strlen(file_name) == 1 && file_name[0] == '.') continue; if (strlen(file_name) == 2 && file_name[0] == '.' && file_name[1] == '.') continue; //不处理隐藏文件? 处理隐藏文件,在这要提供隐藏文件,上层使用过滤代理模型提供显示隐藏文件的功能。 tmp = QString(GlobalOption::instance()->remote_codec->toUnicode(file_name)); tmp_item = parent_item->findChindByName(tmp); tmp_item = 0; // if (parent_item->setDeleteFlag(tmp, 0)) { if (tmp_item != NULL && tmp_item->matchChecksum(&ssh2_sftp_attrib)) { tmp_item->setDeleteFlag(false); if (fxp_ls_ret++ == 0) printf("Already in list, omited %d", fxp_ls_ret), fxp_ls_ret = fxp_ls_ret | 1<<16; else printf(" %d", fxp_ls_ret<<16>>16); } else { new_item = new NetDirNode(); new_item->pNode = parent_item; new_item->fullPath = parent_item->fullPath + QString("/") + tmp ; // this is unicode new_item->_fileName = tmp; new_item->attrib = ssh2_sftp_attrib; new_item->retrFlag = (new_item->isDir() || new_item->isSymLink()) ? POP_NO_NEED_NO_DATA : POP_NEWEST; deltaItems.append(new_item); } }
bool SFTPChannel::updateLs() { int rc; if (mRequestState == Beginning) { mOperationHandle = libssh2_sftp_opendir(mHandle, mCurrentRequest->getPath().toUtf8()); if (mOperationHandle) mRequestState = Reading; else if ((rc = libssh2_session_last_errno(mSession->sessionHandle())) == LIBSSH2_ERROR_EAGAIN) return true; // try again else { criticalError(tr("Failed to open remote directory for reading: %1").arg(rc)); return false; } mResult.clear(); } if (mRequestState == Reading) { char buffer[1024]; LIBSSH2_SFTP_ATTRIBUTES attrs; rc = libssh2_sftp_readdir(mOperationHandle, buffer, sizeof(buffer), &attrs); if (rc == LIBSSH2_ERROR_EAGAIN) return true; // Try again else if (rc == 0) mRequestState = Finishing; else if (rc < 0) { criticalError(tr("Error while reading remote directory: %1").arg(rc)); return false; } else // Got a directory entry { // Skip hidden entries iff request says to if (mCurrentRequest->getIncludeHidden() || buffer[0] != '.') { // Can't determine if remote file is readable/writable, so report all as so. QString flags = "rw"; if (LIBSSH2_SFTP_S_ISDIR(attrs.permissions)) flags += 'd'; QVariantMap details; details.insert("f", flags); details.insert("s", attrs.filesize); details.insert("m", (qulonglong)attrs.mtime); mResult.insert(buffer, details); } } } if (mRequestState == Finishing) { rc = libssh2_sftp_closedir(mOperationHandle); if (rc == LIBSSH2_ERROR_EAGAIN) return true; else if (rc < 0) { criticalError(tr("Failed to cleanly close SFTP directory: %1").arg(rc)); return false; } // Success! Send a response and finish up. QVariantMap finalResult; finalResult.insert("entries", mResult); mCurrentRequest->triggerSuccess(finalResult); return false; } return true; }
int main(int argc, char *argv[]) { unsigned long hostaddr; int sock, i, auth_pw = 1; struct sockaddr_in sin; const char *fingerprint; LIBSSH2_SESSION *session; const char *username="******"; const char *password="******"; const char *sftppath="/tmp/secretdir"; int rc; LIBSSH2_SFTP *sftp_session; LIBSSH2_SFTP_HANDLE *sftp_handle; #ifdef WIN32 WSADATA wsadata; WSAStartup(MAKEWORD(2,0), &wsadata); #endif if (argc > 1) { hostaddr = inet_addr(argv[1]); } else { hostaddr = htonl(0x7F000001); } if(argc > 2) { username = argv[2]; } if(argc > 3) { password = argv[3]; } if(argc > 4) { sftppath = argv[4]; } /* * The application code is responsible for creating the socket * and establishing the connection */ sock = socket(AF_INET, SOCK_STREAM, 0); sin.sin_family = AF_INET; sin.sin_port = htons(22); sin.sin_addr.s_addr = hostaddr; if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) { fprintf(stderr, "failed to connect!\n"); return -1; } /* Create a session instance */ session = libssh2_session_init(); if(!session) return -1; /* ... start it up. This will trade welcome banners, exchange keys, * and setup crypto, compression, and MAC layers */ rc = libssh2_session_startup(session, sock); if(rc) { fprintf(stderr, "Failure establishing SSH session: %d\n", rc); return -1; } /* At this point we havn't yet authenticated. The first thing to do * is check the hostkey's fingerprint against our known hosts Your app * may have it hard coded, may go to a file, may present it to the * user, that's your call */ fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); printf("Fingerprint: "); for(i = 0; i < 16; i++) { printf("%02X ", (unsigned char)fingerprint[i]); } printf("\n"); if (auth_pw) { /* We could authenticate via password */ if ((i = libssh2_userauth_password(session, username, password))) { printf("Authentication by password failed.\n"); goto shutdown; } } else { /* Or by public key */ if (libssh2_userauth_publickey_fromfile(session, username, "/home/username/.ssh/id_rsa.pub", "/home/username/.ssh/id_rsa", password)) { printf("\tAuthentication by public key failed\n"); goto shutdown; } } fprintf(stderr, "libssh2_sftp_init()!\n"); sftp_session = libssh2_sftp_init(session); if (!sftp_session) { fprintf(stderr, "Unable to init SFTP session\n"); goto shutdown; } /* Since we have not set non-blocking, tell libssh2 we are blocking */ libssh2_session_set_blocking(session, 1); fprintf(stderr, "libssh2_sftp_opendir()!\n"); /* Request a dir listing via SFTP */ sftp_handle = libssh2_sftp_opendir(sftp_session, sftppath); if (!sftp_handle) { fprintf(stderr, "Unable to open dir with SFTP\n"); goto shutdown; } fprintf(stderr, "libssh2_sftp_opendir() is done, now receive listing!\n"); do { char mem[512]; char longentry[512]; LIBSSH2_SFTP_ATTRIBUTES attrs; /* loop until we fail */ rc = libssh2_sftp_readdir_ex(sftp_handle, mem, sizeof(mem), longentry, sizeof(longentry), &attrs); if(rc > 0) { /* rc is the length of the file name in the mem buffer */ if (longentry[0] != '\0') { printf("%s\n", longentry); } else { if(attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { /* this should check what permissions it is and print the output accordingly */ printf("--fix----- "); } else { printf("---------- "); } if(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) { printf("%4ld %4ld ", attrs.uid, attrs.gid); } else { printf(" - - "); } if(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) { /* attrs.filesize is an uint64_t according to the docs but there is no really good and portable 64bit type for C before C99, and correspondingly there was no good printf() option for it... */ printf("%8lld ", attrs.filesize); } printf("%s\n", mem); } } else break; } while (1); libssh2_sftp_closedir(sftp_handle); libssh2_sftp_shutdown(sftp_session); shutdown: libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing"); libssh2_session_free(session); #ifdef WIN32 Sleep(1000); closesocket(sock); #else sleep(1); close(sock); #endif printf("all done\n"); return 0; }
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; }