* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <ftw.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <dirent.h>
#include "securec.h"
#include "hdc_cmn.h"
#include "hdc_file_common.h"
unsigned long long g_recv_bytes = 0;
void set_flag(struct filehdr *hdr, enum FILE_HDR_FLAGS flag)
{
hdr->flags = flag;
}
struct fileopt *get_specific_option(char *rcvbuf, uint16_t option_type)
{
struct filehdr *fh = (struct filehdr *)rcvbuf;
size_t offset = sizeof(struct filehdr);
struct fileopt *fopt = NULL;
while (offset < ntohs(fh->hdrlen)) {
fopt = (struct fileopt *)((char *)fh + offset);
if (ntohs(fopt->kind) == option_type) {
break;
}
offset += sizeof(struct fileopt);
offset += ntohs(fopt->opt_len);
}
if (offset < ntohs(fh->hdrlen)) {
return fopt;
} else {
return NULL;
}
}
bool validate_recv_segment(char *p_rcvbuf, signed int buf_len)
{
struct filehdr *fh = (struct filehdr *)p_rcvbuf;
uint32_t offset = sizeof(struct filehdr);
struct fileopt *fopt = NULL;
if ((uint32_t)buf_len < offset || ntohl(fh->len) != (uint32_t)buf_len || ntohl(fh->len) < ntohs(fh->hdrlen)) {
HDC_LOG_ERR("Input parameter is error. (buf_len=%d; file_len=%d; header_len=%d)\n", buf_len, ntohl(fh->len),
(signed int)ntohs(fh->hdrlen));
return false;
}
while (offset < ntohs(fh->hdrlen)) {
if ((offset + sizeof(struct fileopt)) > ntohs(fh->hdrlen)) {
HDC_LOG_ERR("Input parameter is error. (offset=%d; fileopt_len=%d; header_len=%d)\n", offset,
(signed int)sizeof(struct fileopt),
(signed int)ntohs(fh->hdrlen));
return false;
}
fopt = (struct fileopt *)((char *)fh + offset);
offset += (uint32_t)sizeof(struct fileopt);
offset += ntohs(fopt->opt_len);
}
if (offset != ntohs(fh->hdrlen)) {
HDC_LOG_ERR("Parameter offset is error. (offset=%d; header_len=%d)\n", offset, (signed int)ntohs(fh->hdrlen));
return false;
}
return true;
}
hdcError_t recv_reply(HDC_SESSION session, uint16_t *res)
{
struct drvHdcMsg *p_rcvmsg = NULL;
signed int rcvbuf_count;
char *p_rcvbuf = NULL;
signed int buf_len = 0;
struct filehdr *fh = NULL;
hdcError_t ret;
int retry_cnt = 0;
recv_flag_again:
ret = drvHdcAllocMsg(session, &p_rcvmsg, 1);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcAllocMsg error. (hdcError_t=%d)\n", ret);
return ret;
}
ret = halHdcRecv(session, p_rcvmsg, FILE_SEG_MAX_SIZE, 0, &rcvbuf_count, 0);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling halHdcRecv error. (hdcError_t=%d)\n", ret);
(void)drvHdcFreeMsg(p_rcvmsg);
return ret;
}
ret = drvHdcGetMsgBuffer(p_rcvmsg, 0, &p_rcvbuf, &buf_len);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcGetMsgBuffer error. (hdcError_t=%d)\n", ret);
(void)drvHdcFreeMsg(p_rcvmsg);
return ret;
}
g_recv_bytes += (unsigned long long)buf_len;
if (!validate_recv_segment(p_rcvbuf, buf_len)) {
HDC_LOG_ERR("Calling validate_recv_segment error. (buffer=\"%s\"; buffer_len=%d)\n", p_rcvbuf, buf_len);
(void)drvHdcFreeMsg(p_rcvmsg);
return DRV_ERROR_INVALID_VALUE;
}
fh = (struct filehdr *)p_rcvbuf;
if (fh->flags != FILE_FLAGS_RPLY) {
(void)drvHdcFreeMsg(p_rcvmsg);
if ((fh->flags == FILE_FLAGS_ACK) && (retry_cnt == 0)) {
retry_cnt++;
HDC_LOG_WARN("Receive ack flag, rply may in next time, retry recv.\n");
goto recv_flag_again;
}
HDC_LOG_ERR("Receive packet isn't reply after retry. (flags=%d, retry_time=%d)\n", fh->flags, retry_cnt);
return DRV_ERROR_INVALID_VALUE;
}
if (get_specific_option(p_rcvbuf, FILE_OPT_RCVOK) != NULL) {
*res = FILE_OPT_RCVOK;
} else if (get_specific_option(p_rcvbuf, FILE_OPT_NOSPC) != NULL) {
*res = FILE_OPT_NOSPC;
} else if (get_specific_option(p_rcvbuf, FILE_OPT_WRPTH) != NULL) {
*res = FILE_OPT_WRPTH;
} else {
*res = FILE_OPT_NOOP;
}
(void)drvHdcFreeMsg(p_rcvmsg);
p_rcvmsg = NULL;
return ret;
}
#ifndef DRV_UT
hdcError_t hdc_session_send(HDC_SESSION session, char *sndbuf, signed int bufsize)
{
hdcError_t ret;
struct drvHdcMsg *p_sndmsg = NULL;
ret = drvHdcAllocMsg(session, &p_sndmsg, 1);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcAllocMsg error. (hdcError_t=%d)\n", ret);
return ret;
}
ret = drvHdcAddMsgBuffer(p_sndmsg, sndbuf, bufsize);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcAddMsgBuffer error. (hdcError_t=%d)\n", ret);
(void)drvHdcFreeMsg(p_sndmsg);
return ret;
}
ret = halHdcSend(session, p_sndmsg, HDC_FLAG_WAIT_TIMEOUT, HDC_SEND_FILE_WAIT_TIME);
if (ret != DRV_ERROR_NONE) {
if (ret == DRV_ERROR_WAIT_TIMEOUT) {
HDC_LOG_ERR("Calling halHdcSend timeout, peer oom or peer receive packet blocking.\n");
} else {
HDC_LOG_ERR("Calling halHdcSend error. (hdcError_t=%d)\n", ret);
}
(void)drvHdcFreeMsg(p_sndmsg);
return ret;
}
(void)drvHdcFreeMsg(p_sndmsg);
return DRV_ERROR_NONE;
}
#endif
STATIC hdcError_t send_fin(struct filesock *fs, char *sndbuf, signed int bufsize)
{
struct filehdr *fh = (struct filehdr *)sndbuf;
uint32_t len;
uint16_t hdrlen;
hdcError_t ret;
(void)bufsize;
set_flag(fh, FILE_FLAGS_FIN);
hdrlen = sizeof(struct filehdr);
len = hdrlen;
fh->len = htonl(len);
fh->seq = htonl(fs->seq);
fh->hdrlen = htons(hdrlen);
ret = hdc_session_send(fs->session, sndbuf, (int)len);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling hdc_session_send error. (hdcError_t=%d)\n", ret);
}
return ret;
}
STATIC void send_data_fill_fh(struct filehdr *fh, struct filesock *fs)
{
uint16_t hdrlen;
set_flag(fh, FILE_FLAGS_DATA);
fh->seq = htonl(fs->seq++);
hdrlen = sizeof(struct filehdr);
fh->hdrlen = htons(hdrlen);
}
STATIC hdcError_t send_data_handle(struct filesock *fs, struct drvHdcMsg *p_sndmsg, char *sndbuf, signed int bufsize)
{
signed int fd = -1;
struct filehdr *fh = (struct filehdr *)sndbuf;
signed long long len, rdlen;
uint16_t hdrlen = sizeof(struct filehdr);
hdcError_t ret = 0;
send_data_fill_fh(fh, fs);
len = hdrlen;
fd = open(fs->file, O_RDONLY);
if (fd < 0) {
HDC_LOG_ERR("Open file error. (file=\"%s\"; strerror=\"%s\")\n", fs->file, strerror(errno));
return DRV_ERROR_FILE_OPS;
}
while ((rdlen = read(fd, &(sndbuf[hdrlen]), (size_t)(bufsize - hdrlen))) != 0) {
if (rdlen == -1) {
if (errno == EINTR) {
continue;
} else {
HDC_LOG_ERR("Read file error. (file=\"%s\"; strerror=\"%s\")\n", fs->file, strerror(errno));
ret = DRV_ERROR_FILE_OPS;
goto other_error;
}
}
len += rdlen;
fh->len = htonl((uint32_t)len);
if ((ret = drvHdcAddMsgBuffer(p_sndmsg, sndbuf, (int)len)) != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcAddMsgBuffer error. (hdcError_t=%d)\n", ret);
goto other_error;
}
if ((ret = halHdcSend(fs->session, p_sndmsg, HDC_FLAG_WAIT_TIMEOUT,
HDC_SEND_FILE_WAIT_TIME)) != DRV_ERROR_NONE) {
if (ret == DRV_ERROR_WAIT_TIMEOUT) {
HDC_LOG_ERR("Calling halHdcSend timeout, peer oom or peer receive packet blocking.\n");
} else {
HDC_LOG_ERR("Calling halHdcSend error. (hdcError_t=%d)\n", ret);
}
goto other_error;
}
(void)drvHdcReuseMsg(p_sndmsg);
send_data_fill_fh(fh, fs);
len = hdrlen;
if ((fs->hdc_errno != DRV_ERROR_NONE) || fs->exit) {
HDC_LOG_WARN("Other thread something wrong, quit.\n");
if (fs->hdc_errno != DRV_ERROR_NONE) {
ret = DRV_ERROR_INVALID_VALUE;
}
goto other_error;
}
}
other_error:
(void)close(fd);
fd = -1;
return ret;
}
STATIC hdcError_t send_data(struct filesock *fs, char *sndbuf, signed int bufsize)
{
struct drvHdcMsg *p_sndmsg = NULL;
uint16_t hdrlen = sizeof(struct filehdr);
hdcError_t ret;
struct drvHdcCapacity capacity = {0};
if (bufsize <= hdrlen) {
HDC_LOG_ERR("Input parameter is error. (bufsize=%d; hdrlen=%d)\n", bufsize, hdrlen);
return DRV_ERROR_INVALID_VALUE;
}
ret = drvHdcGetCapacity(&capacity);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcGetCapacity error. (hdcError_t=%d)\n", ret);
return ret;
}
HDC_LOG_INFO("Get capacity_maxSegment value. (maxSegment=%d; bufsize=%d)\n", capacity.maxSegment, bufsize);
ret = drvHdcAllocMsg(fs->session, &p_sndmsg, 1);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcAllocMsg error. (hdcError_t=%d)\n", ret);
return ret;
}
ret = (hdcError_t)clock_gettime(CLOCK_MONOTONIC, &fs->start_time);
hdc_file_check("clock_gettime", ret, DRV_ERROR_NONE);
if ((ret = send_data_handle(fs, p_sndmsg, sndbuf, bufsize)) != DRV_ERROR_NONE) {
HDC_LOG_WARN("Send data not success. (ret=%d)\n", ret);
}
(void)drvHdcFreeMsg(p_sndmsg);
p_sndmsg = NULL;
return ret;
}
STATIC uint64_t get_send_rate(const struct filesock *fs)
{
struct timespec now;
uint64_t rate, time;
signed int ret;
ret = (hdcError_t)clock_gettime(CLOCK_MONOTONIC, &now);
hdc_file_check("clock_gettime", (hdcError_t)ret, DRV_ERROR_NONE);
time = (uint64_t)(now.tv_sec - fs->start_time.tv_sec) * SECONDS_TO_MICORSECONDS +
(uint64_t)(now.tv_nsec - fs->start_time.tv_nsec) / CONVERT_NS_TO_US;
if (time != 0) {
rate = (uint64_t)(fs->prog_info.send_bytes) * SECONDS_TO_MICORSECONDS / time;
} else {
rate = 0;
}
return rate;
}
void call_progress_notifier(struct filesock *fs, bool is_fin)
{
if (fs->progress_notifier != NULL) {
if (is_fin) {
fs->prog_info.send_bytes = (long long int)fs->file_size;
fs->prog_info.progress = HDC_SEND_FILE_PROGRESS;
fs->prog_info.rate = (long long int)get_send_rate(fs);
fs->prog_info.remain_time = 0;
fs->progress_notifier(&fs->prog_info);
} else {
if (fs->file_size == 0) {
fs->prog_info.progress = HDC_SEND_FILE_PROGRESS;
} else {
fs->prog_info.progress = (int)(((uint64_t)(fs->prog_info.send_bytes) * HDC_SEND_FILE_PROGRESS) /
fs->file_size);
}
fs->prog_info.rate = (long long int)get_send_rate(fs);
if (fs->prog_info.rate != 0) {
fs->prog_info.remain_time = (int)((fs->file_size - (uint64_t)(fs->prog_info.send_bytes)) /
(uint64_t)fs->prog_info.rate);
} else {
fs->prog_info.remain_time = 0x7FFFFFFF;
}
if (fs->prog_info.progress != HDC_SEND_FILE_PROGRESS) {
fs->progress_notifier(&fs->prog_info);
}
}
}
}
STATIC void process_ack(char *p_rcvbuf, struct filesock *fs)
{
struct fileopt *fopt = NULL;
fopt = get_specific_option(p_rcvbuf, FILE_OPT_RCVSZ);
if (fopt == NULL) {
HDC_LOG_WARN("ACK packet doesn't have recv size, go on.\n");
return;
}
if (ntohs(fopt->opt_len) > 0) {
if (memcpy_s(&(fs->prog_info.send_bytes), sizeof(fs->prog_info.send_bytes), fopt->info,
sizeof(fs->prog_info.send_bytes)) != 0) {
return;
}
call_progress_notifier(fs, 0);
}
}
STATIC void process_reply(char *p_rcvbuf, struct filesock *fs)
{
if (get_specific_option(p_rcvbuf, FILE_OPT_RCVOK) != NULL) {
call_progress_notifier(fs, 1);
} else if (get_specific_option(p_rcvbuf, FILE_OPT_NOSPC) != NULL) {
HDC_LOG_ERR("There is no space on the destination side, exit.\n");
fs->hdc_errno = DRV_ERROR_NO_FREE_SPACE;
} else if (get_specific_option(p_rcvbuf, FILE_OPT_WRPTH) != NULL) {
HDC_LOG_ERR("The destination path is illegal, exit. (dstpth=\"%s\")\n", fs->dstpth);
fs->hdc_errno = DRV_ERROR_DST_PATH_ILLEGAL;
} else if (get_specific_option(p_rcvbuf, FILE_OPT_PERDE) != NULL) {
HDC_LOG_ERR("No permission for the destination path, exit. (dstpth=\"%s\")\n", fs->dstpth);
fs->hdc_errno = DRV_ERROR_DST_PERMISSION_DENIED;
} else if (get_specific_option(p_rcvbuf, FILE_OPT_WRING) != NULL) {
HDC_LOG_WARN("The destination file is being written, exit. (dstpth=\"%s\")\n", fs->dstpth);
fs->hdc_errno = DRV_ERROR_DST_FILE_IS_BEING_WRITTEN;
} else if (get_specific_option(p_rcvbuf, FILE_OPT_SIZE) != NULL) {
HDC_LOG_ERR("Remote whitelist verify failed, check the remote logs, exit.(dstpth=\"%s\")\n", fs->dstpth);
fs->hdc_errno = DRV_ERROR_INVALID_VALUE;
} else {
HDC_LOG_ERR("Receive an unexpected reply packet, quit.\n");
fs->exit = 1;
fs->hdc_errno = DRV_ERROR_INVALID_VALUE;
}
}
STATIC bool process_exit_check(const struct filesock *fs, signed int *cnt)
{
if (fs->exit) {
if ((*cnt)-- <= 0) {
HDC_LOG_WARN("Exit for timeout without reply packet.\n");
return true;
}
}
return false;
}
STATIC void *process_recv_thread(void *arg)
{
struct filesock *fs = (struct filesock *)arg;
struct drvHdcMsg *p_rcvmsg = NULL;
signed int rcvbuf_count;
char *p_rcvbuf = NULL;
signed int buf_len = 0;
signed int timeout_recv_cnt = RECV_TIME_OUT_COUNT;
signed int timeout_exit_cnt = RECV_TIME_OUT_COUNT;
struct filehdr *fh = NULL;
hdcError_t ret;
struct timespec now_time;
ret = (hdcError_t)clock_gettime(CLOCK_MONOTONIC, &fs->session_start_time);
hdc_file_check("clock_gettime", ret, DRV_ERROR_NONE);
ret = drvHdcAllocMsg(fs->session, &p_rcvmsg, 1);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Call drvHdcAllocMsg error. (hdcError_t=%d)\n", ret);
return NULL;
}
fs->is_close = 0;
while (1) {
ret = (hdcError_t)clock_gettime(CLOCK_MONOTONIC, &now_time);
if ((ret != DRV_ERROR_NONE) || (now_time.tv_sec - fs->session_start_time.tv_sec >= SESSION_TIME_OUT)) {
(void)drvHdcSessionClose(fs->session);
fs->is_close = 1;
HDC_LOG_ERR("Session time out. (ret=%d)\n", ret);
break;
}
(void)drvHdcReuseMsg(p_rcvmsg);
ret = halHdcRecv(fs->session, p_rcvmsg, FILE_SEG_MAX_SIZE, HDC_FLAG_WAIT_TIMEOUT,
&rcvbuf_count, HDC_RECV_WAIT_TIME);
if (ret == DRV_ERROR_WAIT_TIMEOUT) {
if (fs->exit) {
HDC_LOG_WARN("Calling halHdcRecv time out. (recv_cnt=%d; fs->exit=%d)\n", timeout_recv_cnt, fs->exit);
break;
}
if (timeout_recv_cnt-- <= 0) {
fs->hdc_errno = ret;
HDC_LOG_ERR("halHdcRecv time out 5 times. (fs_exit=%d)\n", fs->exit);
break;
}
continue;
}
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling halHdcRecv error. (hdcError_t=%d)\n", ret);
fs->hdc_errno = ret;
break;
}
if (process_exit_check(fs, &timeout_exit_cnt)) {
HDC_LOG_WARN("Exit for timeout without reply packet.\n");
break;
}
timeout_recv_cnt = RECV_TIME_OUT_COUNT;
ret = drvHdcGetMsgBuffer(p_rcvmsg, 0, &p_rcvbuf, &buf_len);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcGetMsgBuffer error. (hdcError_t=%d)\n", ret);
fs->hdc_errno = ret;
break;
}
g_recv_bytes += (unsigned long long)buf_len;
if (!validate_recv_segment(p_rcvbuf, buf_len)) {
HDC_LOG_WARN("Calling validate_recv_segment not success. (buffer=\"%s\"; buffer_len=%d)\n",
p_rcvbuf, buf_len);
continue;
}
fh = (struct filehdr *)p_rcvbuf;
if (fh->flags == FILE_FLAGS_RPLY) {
process_reply(p_rcvbuf, fs);
break;
} else if (fh->flags == FILE_FLAGS_ACK) {
process_ack(p_rcvbuf, fs);
} else {
HDC_LOG_WARN("Receive an unexpected packet, go on. (flags=%d)\n", fh->flags);
continue;
}
}
(void)drvHdcFreeMsg(p_rcvmsg);
p_rcvmsg = NULL;
return NULL;
}
STATIC hdcError_t send_data_and_fin(struct filesock *fs, char *sndbuf, signed int bufsize)
{
hdcError_t ret;
ret = send_data(fs, sndbuf, bufsize);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_WARN("Send data has problem.\n");
return ret;
}
ret = send_fin(fs, sndbuf, bufsize);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Send fin error.\n");
return ret;
}
return DRV_ERROR_NONE;
}
hdcError_t send_end(HDC_SESSION session, char *sndbuf, signed int bufsize)
{
struct filehdr *fh = (struct filehdr *)sndbuf;
uint32_t len;
uint16_t hdrlen;
hdcError_t ret;
(void)bufsize;
set_flag(fh, FILE_FLAGS_END);
hdrlen = sizeof(struct filehdr);
len = hdrlen;
fh->len = htonl(len);
fh->seq = htonl(0);
fh->hdrlen = htons(hdrlen);
ret = hdc_session_send(session, sndbuf, (int)len);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling hdc_session_send error. (hdcError_t=%d)\n", ret);
}
return ret;
}
STATIC hdcError_t is_recv_side_ready(struct filesock *fs)
{
hdcError_t ret;
uint16_t is_rcvok;
ret = recv_reply(fs->session, &is_rcvok);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling recv_reply error.\n");
return ret;
}
if (is_rcvok == FILE_OPT_NOSPC) {
HDC_LOG_ERR("There is no space on the destination side,exit.\n");
ret = DRV_ERROR_NO_FREE_SPACE;
} else if (is_rcvok == FILE_OPT_WRPTH) {
HDC_LOG_ERR("The destination path is illegal, exit. (dstpth=\"%s\")\n", fs->dstpth);
ret = DRV_ERROR_DST_PATH_ILLEGAL;
} else if (is_rcvok != FILE_OPT_RCVOK) {
HDC_LOG_WARN("Receive an unexpected reply packet. (kinds=%d)\n", is_rcvok);
}
return ret;
}
uint16_t set_option_mode(char *sndbuf, signed int bufsize, uint32_t offset, uint32_t mode)
{
struct fileopt *fopt = NULL;
uint16_t len = sizeof(struct fileopt);
uint16_t mode_len = sizeof(mode);
uint32_t resspace;
char *pinfo = NULL;
if ((sndbuf == NULL) || (bufsize < 0) || ((uint32_t)bufsize < offset) || ((uint32_t)bufsize - offset < len) ||
(uint32_t)bufsize - offset - len < sizeof(mode)) {
return 0;
}
fopt = (struct fileopt *)(sndbuf + offset);
fopt->kind = htons(FILE_OPT_MODE);
fopt->opt_len = htons(mode_len);
pinfo = fopt->info;
resspace = (uint32_t)bufsize - offset - len;
if (memcpy_s(pinfo, resspace, &mode, sizeof(mode)) != 0) {
return 0;
}
len = (uint16_t)(len + mode_len);
return len;
}
STATIC uint16_t set_option_size(char *sndbuf, signed int bufsize, uint32_t offset, uint64_t size)
{
struct fileopt *fopt = NULL;
uint16_t len = sizeof(struct fileopt);
uint16_t size_len = sizeof(size);
uint32_t resspace;
char *pinfo = NULL;
if ((sndbuf == NULL) || (bufsize < 0) || ((uint32_t)bufsize < offset) || ((uint32_t)bufsize - offset < len) ||
(uint32_t)bufsize - offset - len < sizeof(size)) {
return 0;
}
fopt = (struct fileopt *)(sndbuf + offset);
fopt->kind = htons(FILE_OPT_SIZE);
fopt->opt_len = htons(size_len);
pinfo = fopt->info;
resspace = (uint32_t)bufsize - offset - len;
if (memcpy_s(pinfo, resspace, &size, sizeof(size)) != 0) {
return 0;
}
len = (uint16_t)(len + size_len);
return len;
}
uint16_t set_option_dstpth(char *sndbuf, signed int bufsize, uint32_t offset, const char *dstpth)
{
struct fileopt *fopt = NULL;
uint16_t len = sizeof(struct fileopt);
uint16_t dstpth_len = (uint16_t)(strlen(dstpth) + 1);
uint32_t resspace;
char *pinfo = NULL;
if ((sndbuf == NULL) || (bufsize < 0) || ((uint32_t)bufsize < offset) || ((uint32_t)bufsize - offset < len) ||
((uint32_t)bufsize - offset - len < dstpth_len)) {
return 0;
}
fopt = (struct fileopt *)(sndbuf + offset);
fopt->kind = htons(FILE_OPT_DSTPTH);
fopt->opt_len = htons(dstpth_len);
pinfo = fopt->info;
resspace = (uint32_t)bufsize - offset - len;
if (strcpy_s(pinfo, resspace, dstpth) != 0) {
return 0;
}
len = (uint16_t)(len + dstpth_len);
return len;
}
uint16_t set_option_name(char *sndbuf, signed int bufsize, uint32_t offset, const char *file)
{
struct fileopt *fopt = NULL;
uint16_t len = sizeof(struct fileopt);
uint16_t name_len = (uint16_t)(strlen(file) + 1);
uint32_t resspace;
char *pinfo = NULL;
if ((sndbuf == NULL) || (bufsize < 0) || ((uint32_t)bufsize < offset) || ((uint32_t)bufsize - offset < len) ||
((uint32_t)bufsize - offset - len < name_len)) {
return 0;
}
fopt = (struct fileopt *)(sndbuf + offset);
fopt->kind = htons(FILE_OPT_NAME);
fopt->opt_len = htons(name_len);
pinfo = fopt->info;
resspace = (uint32_t)bufsize - offset - len;
if (strcpy_s(pinfo, resspace, file) != 0) {
return 0;
}
len = (uint16_t)(len + name_len);
return len;
}
STATIC hdcError_t get_file_name(const struct filesock *fs, char *name, signed int len)
{
uint32_t i = 0;
uint32_t sppos = 0;
(void)len;
while (*(fs->file + i) != '\0') {
if (*(fs->file + i) == '/') {
sppos = i + 1;
}
i++;
}
if (strcpy_s(name, HDC_NAME_MAX, fs->file + sppos) != 0) {
HDC_LOG_ERR("Calling strcpy_s error. (strerror=\"%s\")\n", strerror(errno));
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
STATIC hdcError_t send_request(struct filesock *fs, char *sndbuf, signed int bufsize)
{
struct filehdr *fh = (struct filehdr *)sndbuf;
uint32_t len;
uint16_t hdrlen;
uint16_t offset;
hdcError_t ret;
char name[HDC_NAME_MAX];
set_flag(fh, FILE_FLAGS_REQ);
hdrlen = sizeof(struct filehdr);
if ((ret = get_file_name(fs, name, HDC_NAME_MAX)) != DRV_ERROR_NONE) {
return DRV_ERROR_INVALID_VALUE;
}
offset = set_option_name(sndbuf, bufsize, hdrlen, name);
if (offset == 0) {
HDC_LOG_ERR("Calling set_option_name error. (file_name=\"%s\")\n", name);
return DRV_ERROR_INVALID_VALUE;
}
hdrlen = (uint16_t)(hdrlen + offset);
offset = set_option_dstpth(sndbuf, bufsize, hdrlen, fs->dstpth);
if (offset == 0) {
HDC_LOG_ERR("Calling set_option_dstpth error. (destination_path=\"%s\")\n", fs->dstpth);
return DRV_ERROR_INVALID_VALUE;
}
hdrlen = (uint16_t)(hdrlen + offset);
offset = set_option_size(sndbuf, bufsize, hdrlen, fs->file_size);
if (offset == 0) {
HDC_LOG_ERR("Calling set_option_size error. (file_size=%llu)\n", fs->file_size);
return DRV_ERROR_INVALID_VALUE;
}
hdrlen = (uint16_t)(hdrlen + offset);
offset = set_option_mode(sndbuf, bufsize, hdrlen, fs->file_mode);
if (offset == 0) {
HDC_LOG_ERR("Calling set_option_mode error. (file_mode=%d)\n", fs->file_mode);
return DRV_ERROR_INVALID_VALUE;
}
hdrlen = (uint16_t)(hdrlen + offset);
len = hdrlen;
fh->len = htonl(len);
fh->seq = htonl(fs->seq);
fh->hdrlen = htons(hdrlen);
fh->user_mode = fs->user_mode;
ret = hdc_session_send(fs->session, sndbuf, (int)len);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling hdc_session_send error. (hdcError_t=%d)\n", ret);
return ret;
}
return ret;
}
STATIC hdcError_t validate_file(struct filesock *fs)
{
struct stat s_buf;
signed int fd = -1;
uint32_t mask = 0xfff;
uint32_t sppos = 0;
uint32_t i = 0;
fd = open(fs->file, O_RDONLY);
if (fd < 0) {
HDC_LOG_ERR("Open file error. (file=\"%s\"; strerror=\"%s\")\n", fs->file, strerror(errno));
return DRV_ERROR_OPEN_FAILED;
}
if (fstat(fd, &s_buf) < 0) {
HDC_LOG_ERR("Calling fstat error. (file=\"%s\"; strerror=\"%s\")\n", fs->file, strerror(errno));
(void)close(fd);
fd = -1;
return DRV_ERROR_LOCAL_ABNORMAL_FILE;
}
if (!S_ISREG(s_buf.st_mode)) {
HDC_LOG_ERR("Calling S_ISREG error, please check input. (file=\"%s\")\n", fs->file);
(void)close(fd);
fd = -1;
return DRV_ERROR_LOCAL_ABNORMAL_FILE;
}
(void)close(fd);
fd = -1;
fs->file_size = (uint64_t)s_buf.st_size;
fs->file_mode = s_buf.st_mode & mask;
while (*(fs->file + i) != '\0') {
if (*(fs->file + i) == '/') {
sppos = i + 1;
}
i++;
}
if (strcpy_s(fs->prog_info.name, HDC_NAME_MAX, fs->file + sppos) != 0) {
HDC_LOG_ERR("Calling strcpy_s error. (strerror=\"%s\")\n", strerror(errno));
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
hdcError_t get_hdc_capacity(struct drvHdcCapacity *capacity)
{
hdcError_t ret;
ret = drvHdcGetCapacity(capacity);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcGetCapacity error. (hdcError_t=%d)\n", ret);
return ret;
}
if (capacity->maxSegment <= 0) {
HDC_LOG_ERR("Parameter capacity_maxSegment is invalid. (maxSegment=%d)\n", capacity->maxSegment);
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
hdcError_t send_file_in_session(signed int user_mode, HDC_SESSION session, const char *file, const char *dst_path,
void (*progress_notifier)(struct drvHdcProgInfo *))
{
struct filesock *fs = NULL;
hdcError_t ret;
pthread_t recv_thread = 0;
struct drvHdcCapacity capacity = {0};
char *p_sndbuf = NULL;
pthread_attr_t attr;
char *file_path = NULL;
(void)pthread_attr_init(&attr);
if ((ret = get_hdc_capacity(&capacity)) != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling get_hdc_capacity error. (hdcError_t=%d)\n", ret);
goto error0;
}
p_sndbuf = (char *)malloc((uint32_t)capacity.maxSegment);
if (p_sndbuf == NULL) {
HDC_LOG_ERR("Calling malloc p_sndbuf failed.\n");
ret = DRV_ERROR_MALLOC_FAIL;
goto error0;
}
fs = (struct filesock *)malloc(sizeof(struct filesock));
if (fs == NULL) {
HDC_LOG_ERR("Calling malloc fs failed.\n");
ret = DRV_ERROR_MALLOC_FAIL;
goto error1;
}
file_path = realpath((const char *)file, NULL);
if (file_path == NULL) {
HDC_LOG_ERR("Got realpath failed. (file_path=\"%s\")\n", file);
ret = DRV_ERROR_INVALID_VALUE;
goto error2;
}
if ((memset_s(fs, sizeof(struct filesock), 0, sizeof(struct filesock)) != 0) ||
(strcpy_s(fs->file, PATH_MAX, file_path) != 0) || (strcpy_s(fs->dstpth, PATH_MAX, dst_path) != 0)) {
HDC_LOG_ERR("Calling memset_s or strcpy_s error. (strerror=\"%s\")\n", strerror(errno));
ret = DRV_ERROR_INVALID_VALUE;
goto error3;
}
fs->session = session;
fs->progress_notifier = progress_notifier;
fs->user_mode = (uint8_t)user_mode;
ret = validate_file(fs);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling validate_file error.\n");
goto error3;
}
ret = send_request(fs, p_sndbuf, (int)capacity.maxSegment);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling send_request error.\n");
goto error3;
}
ret = is_recv_side_ready(fs);
if (ret != DRV_ERROR_NONE) {
goto error3;
}
if (pthread_create(&recv_thread, &attr, process_recv_thread, (void *)fs) != 0) {
HDC_LOG_ERR("Create recv_thread error. (strerror=\"%s\")\n", strerror(errno));
ret = DRV_ERROR_INVALID_VALUE;
goto error3;
}
ret = send_data_and_fin(fs, p_sndbuf, (int)capacity.maxSegment);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_WARN("Calling send_data_and_fin not success.\n");
}
fs->exit = 1;
if (pthread_join(recv_thread, NULL) != 0) {
HDC_LOG_ERR("Calling pthread_join recv_thread error. (strerror=\"%s\")\n", strerror(errno));
ret = DRV_ERROR_INVALID_VALUE;
}
if (fs->hdc_errno != DRV_ERROR_NONE) {
ret = fs->hdc_errno;
}
error3:
free(file_path);
file_path = NULL;
error2:
free(fs);
fs = NULL;
error1:
free(p_sndbuf);
p_sndbuf = NULL;
error0:
(void)pthread_attr_destroy(&attr);
return ret;
}
hdcError_t drvHdcGetTrustedBasePathEx(signed int user_mode, signed int peer_node, signed int peer_devid,
char *base_path, unsigned int path_len)
{
hdcError_t ret;
signed int s_ret;
signed int id = 0;
char path[HDC_NAME_MAX] = {0};
if ((peer_node != 0) && (peer_node != 0xffff)) {
HDC_LOG_ERR("Input parameter peer_node is error. (peer_node=%d)\n", peer_node);
return DRV_ERROR_INVALID_VALUE;
}
if (base_path == NULL) {
HDC_LOG_ERR("Input parameter base_path is error.\n");
return DRV_ERROR_INVALID_VALUE;
}
if (peer_node == 0xffff) {
s_ret = get_local_trusted_base_path(user_mode, path, peer_devid);
} else {
ret = drv_hdc_get_peer_dev_id(peer_devid, &id);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drv_hdc_get_peer_dev_id failed. (dev_id=%d; ret=%d)\n", peer_devid, ret);
return ret;
}
s_ret = get_peer_trusted_base_path(user_mode, path, id);
}
if (s_ret < 0) {
HDC_LOG_ERR("Calling sprintf_s failed.\n");
return DRV_ERROR_INNER_ERR;
}
if (path_len <= (unsigned int)strlen(path)) {
HDC_LOG_ERR("Parameter path_len is invalid. (id=%d; path_len=%d; len=%d)\n", id, path_len, strlen(path));
return DRV_ERROR_INVALID_VALUE;
}
if (strcpy_s(base_path, path_len, path) != 0) {
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
STATIC hdcError_t drv_hdc_send_file_para_check(signed int user_mode, signed int peer_node, signed int peer_devid,
const char *file, const char *dst_path)
{
#ifndef CFG_SOC_PLATFORM_RC
hdcError_t ret;
#endif
char base_path[HDC_NAME_MAX] = {0};
int file_len, dstpth_len;
if ((file == NULL) || (dst_path == NULL)) {
HDC_LOG_ERR("Input parameter is error. (file or dst_path)\n");
return DRV_ERROR_INVALID_VALUE;
}
file_len = (int)strnlen(file, PATH_MAX);
dstpth_len = (int)strnlen(dst_path, PATH_MAX);
if ((file_len == 0) || (file_len >= PATH_MAX) || (dstpth_len >= PATH_MAX) || (dstpth_len == 0)) {
HDC_LOG_ERR("Input parameter is error. (file or dst_path is too long)\n");
return DRV_ERROR_INVALID_VALUE;
}
#ifndef CFG_SOC_PLATFORM_RC
ret = drvHdcGetTrustedBasePathEx(user_mode, peer_node, peer_devid, base_path, HDC_NAME_MAX);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcGetTrustedBasePath error. (hdcError_t=%d)\n", ret);
return ret;
}
#endif
if (strstr(dst_path, (const char *)base_path) != dst_path) {
HDC_LOG_ERR("Calling strstr failed. (dev_id=%d; file=\"%s\"; dst_path=\"%s\"; base_path=\"%s\")\n",
peer_devid, file, dst_path, base_path);
return DRV_ERROR_DST_PATH_ILLEGAL;
}
return DRV_ERROR_NONE;
}
hdcError_t drvHdcSendFileEx(signed int user_mode, signed int peer_node, signed int peer_devid, const char *file,
const char *dst_path, void (*progress_notifier)(struct drvHdcProgInfo *))
{
HDC_CLIENT client = NULL;
HDC_SESSION session = NULL;
hdcError_t ret;
struct drvHdcCapacity capacity = {0};
char *p_sndbuf = NULL;
signed int type;
if ((ret = drv_hdc_send_file_para_check(user_mode, peer_node, peer_devid, file, dst_path)) != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drv_hdc_send_file_para_check error. (hdcError_t=%d)\n", ret);
return ret;
}
#ifdef HDC_UT_TEST
type = HDC_SERVICE_TYPE_FILE_TRANS;
#else
if ((user_mode == 0) || (user_mode == HDC_FILE_TRANS_MODE_CANN)) {
type = HDC_SERVICE_TYPE_FILE_TRANS;
} else {
type = HDC_SERVICE_TYPE_UPGRADE;
}
#endif
if ((ret = drvHdcClientCreate(&client, 1, type, 0)) != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcClientCreate error. (hdcError_t=%d)\n", ret);
return ret;
}
ret = drvHdcSessionConnect(peer_node, peer_devid, client, &session);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_WARN("Calling drvHdcSessionConnect not success. (hdcError_t=%d)\n", ret);
(void)drvHdcClientDestroy(client);
return ret;
}
(void)drvHdcSetSessionReference(session);
ret = send_file_in_session(user_mode, session, file, dst_path, progress_notifier);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_WARN("Calling send_file_in_session not success. (ret=%d)\n", ret);
goto out;
}
if ((ret = get_hdc_capacity(&capacity)) != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling get_hdc_capacity error. (hdcError_t=%d)\n", ret);
goto out;
}
p_sndbuf = malloc((uint32_t)capacity.maxSegment);
if (p_sndbuf == NULL) {
HDC_LOG_ERR("Calling malloc error. (strerror=\"%s\")\n", strerror(errno));
ret = DRV_ERROR_MALLOC_FAIL;
goto out;
}
ret = send_end(session, p_sndbuf, (int)capacity.maxSegment);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling send_end error.\n");
}
free(p_sndbuf);
p_sndbuf = NULL;
out:
(void)drvHdcSessionClose(session);
(void)drvHdcClientDestroy(client);
return ret;
}
bool is_dir(const char *name, size_t len)
{
struct stat s_buf;
(void)len;
if (name == NULL) {
HDC_LOG_ERR("Input parameter is error.\n");
return false;
}
if (access(name, F_OK) != 0) {
return false;
}
if (stat(name, &s_buf) < 0) {
return false;
}
if (S_ISDIR(s_buf.st_mode)) {
return true;
} else {
return false;
}
}
STATIC uint16_t set_option_mkdir(char *sndbuf, signed int bufsize, uint32_t offset, const char *dir)
{
struct fileopt *fopt = NULL;
uint16_t len = sizeof(struct fileopt);
char name[HDC_NAME_MAX];
uint16_t name_len;
uint32_t sppos = 0;
uint32_t i = 0;
uint32_t resspace;
char *pinfo = NULL;
while (*(dir + i) != '\0') {
if (*(dir + i) == '/') {
sppos = i + 1;
}
i++;
}
if (strcpy_s(name, HDC_NAME_MAX, dir + sppos) != 0) {
return 0;
}
name_len = (uint16_t)(strlen(name) + 1);
if ((sndbuf == NULL) || (bufsize < 0) || ((uint32_t)bufsize < offset) || ((uint32_t)bufsize - offset < len) ||
((uint32_t)bufsize - offset - len < name_len)) {
return 0;
}
fopt = (struct fileopt *)(sndbuf + offset);
fopt->kind = htons(FILE_OPT_MKDIR);
fopt->opt_len = htons(name_len);
pinfo = fopt->info;
resspace = (uint32_t)bufsize - offset - len;
if (strcpy_s(pinfo, resspace, name) != 0) {
return 0;
}
len = (uint16_t)(len + name_len);
return len;
}
STATIC hdcError_t send_cmd(HDC_SESSION session, char *sndbuf, signed int bufsize, const char *local_dir,
const char *dst_path)
{
struct filehdr *fh = (struct filehdr *)sndbuf;
uint32_t len;
uint16_t hdrlen;
uint16_t offset;
hdcError_t ret;
struct stat s_buf;
if (stat(local_dir, &s_buf) < 0) {
HDC_LOG_ERR("Calling stat error. (local_dir=\"%s\"; strerror=\"%s\")\n", local_dir, strerror(errno));
return DRV_ERROR_INVALID_VALUE;
}
set_flag(fh, FILE_FLAGS_CMD);
hdrlen = sizeof(struct filehdr);
offset = set_option_mkdir(sndbuf, bufsize, hdrlen, local_dir);
if (offset == 0) {
HDC_LOG_ERR("Calling set_option_mkdir error. (local_dir=\"%s\")\n", local_dir);
return DRV_ERROR_INVALID_VALUE;
}
hdrlen = (uint16_t)(hdrlen + offset);
offset = set_option_dstpth(sndbuf, bufsize, hdrlen, dst_path);
if (offset == 0) {
HDC_LOG_ERR("Calling set_option_dstpth error. (destination_path=\"%s\")\n", dst_path);
return DRV_ERROR_INVALID_VALUE;
}
hdrlen = (uint16_t)(hdrlen + offset);
offset = set_option_mode(sndbuf, bufsize, hdrlen, s_buf.st_mode & 0xfff);
if (offset == 0) {
HDC_LOG_ERR("Calling set_option_mode error. (dir_mode=%d)\n", s_buf.st_mode & 0xfff);
return DRV_ERROR_INVALID_VALUE;
}
hdrlen = (uint16_t)(hdrlen + offset);
len = hdrlen;
fh->len = htonl(len);
fh->seq = htonl(0);
fh->hdrlen = htons(hdrlen);
ret = hdc_session_send(session, sndbuf, (int)len);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling hdc_session_send error. (hdcError_t=%d)\n", ret);
}
return ret;
}
hdcError_t get_new_dir_name(char *dst_path, int dst_len, const char *src_path, const char *d_name)
{
if ((strcpy_s(dst_path, (size_t)dst_len, src_path) != EOK) ||
(*(dst_path + strlen(dst_path) - 1) != '/' &&
(strcat_s(dst_path, (size_t)dst_len, "/") != EOK)) ||
(strcat_s(dst_path, (size_t)dst_len, d_name) != EOK)) {
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
STATIC hdcError_t __send_current_dir(HDC_SESSION session, const char *local_dir, size_t local_dir_len,
char *new_local_dir, size_t new_local_len, char *new_dst_path, size_t new_dst_len,
signed int count, void (*progress_notifier)(struct drvHdcProgInfo *))
{
DIR *dir = NULL;
struct dirent *ptr = NULL;
hdcError_t ret = DRV_ERROR_NONE;
(void)local_dir_len;
(void)new_dst_len;
if ((dir = opendir(local_dir)) == NULL) {
HDC_LOG_ERR("Calling opendir error. (strerror=\"%s\")\n", strerror(errno));
ret = DRV_ERROR_FILE_OPS;
return ret;
}
while ((ptr = readdir(dir)) != NULL) {
if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) {
continue;
}
ret = get_new_dir_name(new_local_dir, (int)new_local_len, local_dir, ptr->d_name);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling strcpy_s or strcat_s error. (strerror=\"%s\")\n", strerror(errno));
break;
}
if (is_dir(new_local_dir, new_local_len)) {
ret = send_dir_in_session(session, new_local_dir, new_dst_path, count, progress_notifier);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling send_dir_in_session error. (local_dir=\"%s\"; dst_path=\"%s\")\n",
new_local_dir, new_dst_path);
break;
}
} else {
ret = send_file_in_session(0, session, new_local_dir, new_dst_path, progress_notifier);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling send_file_in_session error. (file_name=\"%s\"; dst_path=\"%s\")\n",
new_local_dir, new_dst_path);
break;
}
}
}
(void)closedir(dir);
dir = NULL;
ptr = NULL;
return ret;
}
STATIC hdcError_t send_current_dir(HDC_SESSION session, const char *local_dir, size_t local_len,
const char *dst_path, size_t dst_len, signed int count,
void (*progress_notifier)(struct drvHdcProgInfo *))
{
char *new_dst_path = NULL;
char *new_local_dir = NULL;
uint32_t sppos = 0;
uint32_t i = 0;
hdcError_t ret;
(void)local_len;
(void)dst_len;
new_dst_path = (char *)malloc(PATH_MAX);
if (new_dst_path == NULL) {
HDC_LOG_ERR("Calling malloc new_dst_path error.\n");
ret = DRV_ERROR_MALLOC_FAIL;
goto error2;
}
new_local_dir = (char *)malloc(PATH_MAX);
if (new_local_dir == NULL) {
HDC_LOG_ERR("Calling malloc new_local_dir error.\n");
ret = DRV_ERROR_MALLOC_FAIL;
goto error1;
}
while (*(local_dir + i) != '\0') {
if (*(local_dir + i) == '/') {
sppos = i + 1;
}
i++;
}
if ((strcpy_s(new_dst_path, PATH_MAX, dst_path) != 0) ||
(*(new_dst_path + strlen(new_dst_path) - 1) != '/' && (strcat_s(new_dst_path, PATH_MAX, "/") != 0)) ||
(strcpy_s(new_dst_path + strlen(new_dst_path), PATH_MAX - strlen(new_dst_path), local_dir + sppos) != 0)) {
HDC_LOG_ERR("Calling strcpy_s or strcat_s error. (strerror=\"%s\")\n", strerror(errno));
ret = DRV_ERROR_INVALID_VALUE;
goto error0;
}
ret = __send_current_dir(session, local_dir, PATH_MAX, new_local_dir, PATH_MAX, new_dst_path, PATH_MAX, count,
progress_notifier);
error0:
free(new_local_dir);
new_local_dir = NULL;
error1:
free(new_dst_path);
new_dst_path = NULL;
error2:
return ret;
}
hdcError_t send_dir_in_session(HDC_SESSION session, const char *plocal_dir, const char *pdst_path, signed int count,
void (*progress_notifier)(struct drvHdcProgInfo *))
{
hdcError_t ret;
struct drvHdcCapacity capacity = {0};
char *p_sndbuf = NULL;
uint16_t is_rcvok;
char *local_dir = NULL;
signed int is_null;
signed int is_count = count;
if (is_count-- <= 0) {
HDC_LOG_ERR("Only support direction maxdepth. (maxdepth=%d)\n", DIR_SEND_MAX_DEPTH);
return DRV_ERROR_INVALID_VALUE;
}
is_null = (plocal_dir == NULL) || (pdst_path == NULL);
if (is_null != 0) {
HDC_LOG_ERR("Input parameter plocal_dir or pdst_path is NULL.\n");
return DRV_ERROR_INVALID_VALUE;
}
if (!is_dir(plocal_dir, PATH_MAX)) {
HDC_LOG_ERR("Input path isn't dir, please check. (path=\"%s\")\n", plocal_dir);
return DRV_ERROR_INVALID_VALUE;
}
if ((ret = get_hdc_capacity(&capacity)) != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling get_hdc_capacity error. (hdcError_t=%d)\n", ret);
goto error0;
}
p_sndbuf = malloc((uint32_t)capacity.maxSegment);
if (p_sndbuf == NULL) {
HDC_LOG_ERR("Calling malloc p_sndbuf failed.\n");
ret = DRV_ERROR_MALLOC_FAIL;
goto error0;
}
local_dir = (char *)malloc(PATH_MAX);
if (local_dir == NULL) {
HDC_LOG_ERR("Calling malloc local_dir failed.\n");
ret = DRV_ERROR_MALLOC_FAIL;
goto error1;
}
if (strcpy_s(local_dir, PATH_MAX, plocal_dir) != 0) {
HDC_LOG_ERR("Calling strcpy_s error. (strerror=\"%s\")\n", strerror(errno));
ret = DRV_ERROR_INVALID_VALUE;
goto error2;
}
if (*(local_dir + strlen(local_dir) - 1) == '/') {
*(local_dir + strlen(local_dir) - 1) = '\0';
}
ret = send_cmd(session, p_sndbuf, (int)capacity.maxSegment, local_dir, pdst_path);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling send_cmd error. (local_dir=\"%s\"; dst_path=\"%s\")\n", local_dir, pdst_path);
goto error2;
}
ret = recv_reply(session, &is_rcvok);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling recv_reply error.\n");
goto error2;
}
if (is_rcvok == FILE_OPT_WRPTH) {
HDC_LOG_ERR("Create destination path error. (local_dir=\"%s\"; dst_path=\"%s\")\n", local_dir, pdst_path);
ret = DRV_ERROR_INVALID_VALUE;
goto error2;
}
ret = send_current_dir(session, local_dir, PATH_MAX, pdst_path, PATH_MAX, is_count,
progress_notifier);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling send_current_dir error. (local_dir=\"%s\"; dst_path=\"%s\")\n", local_dir, pdst_path);
}
error2:
free(local_dir);
local_dir = NULL;
error1:
free(p_sndbuf);
p_sndbuf = NULL;
error0:
return ret;
}
hdcError_t drvHdcSendDir(signed int peer_node, signed int peer_devid, const char *plocal_dir, const char *pdst_path,
void (*progress_notifier)(struct drvHdcProgInfo *))
{
HDC_CLIENT client = NULL;
HDC_SESSION session = NULL;
hdcError_t ret;
struct drvHdcCapacity capacity = {0};
char *p_sndbuf = NULL;
signed int is_null;
is_null = (plocal_dir == NULL) || (pdst_path == NULL);
if (is_null != 0) {
HDC_LOG_ERR("Input parameter is error.\n");
return DRV_ERROR_INVALID_VALUE;
}
if ((ret = drvHdcClientCreate(&client, 1, HDC_SERVICE_TYPE_FILE_TRANS, 0)) != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcClientCreate error. (hdcError_t=%d)\n", ret);
return ret;
}
if ((ret = drvHdcSessionConnect(peer_node, peer_devid, client, &session)) != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling drvHdcSessionConnect error. (hdcError_t=%d)\n", ret);
(void)drvHdcClientDestroy(client);
return ret;
}
(void)drvHdcSetSessionReference(session);
ret = send_dir_in_session(session, plocal_dir, pdst_path, DIR_SEND_MAX_DEPTH, progress_notifier);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling send_dir_in_session error.\n");
goto out;
}
if ((ret = get_hdc_capacity(&capacity)) != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling get_hdc_capacity error. (hdcError_t=%d)\n", ret);
goto out;
}
p_sndbuf = malloc((uint32_t)capacity.maxSegment);
if (p_sndbuf == NULL) {
HDC_LOG_ERR("Calling malloc error. (strerror=\"%s\")\n", strerror(errno));
ret = DRV_ERROR_MALLOC_FAIL;
goto out;
}
ret = send_end(session, p_sndbuf, (int)capacity.maxSegment);
if (ret != DRV_ERROR_NONE) {
HDC_LOG_ERR("Calling send_end error.\n");
}
free(p_sndbuf);
p_sndbuf = NULL;
out:
(void)drvHdcSessionClose(session);
(void)drvHdcClientDestroy(client);
return ret;
}