Пример #1
0
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);
    }
}
Пример #2
0
/**
 * @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);
}
Пример #3
0
/* 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;
}
Пример #4
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;
}
Пример #5
0
Файл: dir.c Проект: CTU-OSP/mc
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;
}
Пример #6
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;
}
Пример #7
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);
            }
        }  
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
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;
}