void * sftpfs_readdir (void *data, GError ** error) { char mem[BUF_MEDIUM]; LIBSSH2_SFTP_ATTRIBUTES attrs; sftpfs_dir_data_t *sftpfs_dir = (sftpfs_dir_data_t *) data; static union vfs_dirent sftpfs_dirent; int rc; do { rc = libssh2_sftp_readdir (sftpfs_dir->handle, mem, sizeof (mem), &attrs); if (rc >= 0) break; if (rc != LIBSSH2_ERROR_EAGAIN) { sftpfs_ssherror_to_gliberror (sftpfs_dir->super_data, rc, error); return NULL; } sftpfs_waitsocket (sftpfs_dir->super_data, error); if (error != NULL && *error != NULL) return NULL; } while (rc == LIBSSH2_ERROR_EAGAIN); if (rc == 0) return NULL; g_strlcpy (sftpfs_dirent.dent.d_name, mem, BUF_MEDIUM); compute_namelen (&sftpfs_dirent.dent); return &sftpfs_dirent; }
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; }
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; }