Loading

libssh2_sftp_rename失败问题

最近遇到一个问题,使用libssh2_sftp上传文件时,传输的文件命名文xxx.xx.temp,上传完成后需要把temp后缀去掉。
libssh2提供了一个接口libssh2_sftp_rename用于重命名远端文件。
但是在调用libssh2_sftp_rename时出现一个问题,只有第一次调用可以成功,后面在调用就会失败,返回错误码-31
libssh2.h里定义了该错误:

#define LIBSSH2_ERROR_SFTP_PROTOCOL             -31

libssh2_sftp_rename的代码实现为:

#define libssh2_sftp_rename(sftp, sourcefile, destfile) \
    libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \
                           (destfile), strlen(destfile),                \
                           LIBSSH2_SFTP_RENAME_OVERWRITE | \
                           LIBSSH2_SFTP_RENAME_ATOMIC | \
                           LIBSSH2_SFTP_RENAME_NATIVE)

libssh2_sftp_rename_ex实现为:

LIBSSH2_API int
libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename,
                       unsigned int source_filename_len,
                       const char *dest_filename,
                       unsigned int dest_filename_len, long flags)
{
    int rc;
    if(!sftp)
        return LIBSSH2_ERROR_BAD_USE;
    BLOCK_ADJUST(rc, sftp->channel->session,
                 sftp_rename(sftp, source_filename, source_filename_len,
                             dest_filename, dest_filename_len, flags));
    return rc;
}

libssh2_sftp_rename函数最终调用为sftp_rename,在sftp_rename里写明了返回LIBSSH2_ERROR_SFTP_PROTOCOL错误的几种情况:

  • 版本太低不支持
if(sftp->version < 2) {
        return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
                              "Server does not support RENAME");
    }
  • 重命名包长太小
    rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
                             sftp->rename_request_id, &data,
                             &data_len, 9);
    if(rc == LIBSSH2_ERROR_EAGAIN) {
        return rc;
    }
    else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) {
        if(data_len > 0) {
            LIBSSH2_FREE(session, data);
        }
        return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
                              "SFTP rename packet too short");
    }
  • 文件早已存在
case LIBSSH2_FX_FILE_ALREADY_EXISTS:
        retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
                                 "File already exists and "
                                 "SSH_FXP_RENAME_OVERWRITE not specified");
        break;
  • 操作不支持
case LIBSSH2_FX_OP_UNSUPPORTED:
        retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
                                 "Operation Not Supported");
        break;
  • SFTP 协议错误
default:
        retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
                                 "SFTP Protocol Error");
        break;

从上面可以看到,如果重命名的文件已经存在的话,再想调用libssh2_sftp_rename会失败,这也是为什么只有第一次重命名会成功,在以后就报错。
因此解决方法是,在重命名之前检测远端是否存在重命名后的文件,如果存在的话删除掉已有的文件,或者重新命名一个新名字。

posted @ 2022-09-02 22:56  柴承训  阅读(628)  评论(0编辑  收藏  举报