Exemple #1
0
Fichier : dir.c Projet : CTU-OSP/mc
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);
            }
        }  
Exemple #4
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;
}
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;
}