1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "file.h"
16 #include "serial_struct.h"
17
18 namespace Hdc {
HdcFile(HTaskInfo hTaskInfo)19 HdcFile::HdcFile(HTaskInfo hTaskInfo)
20 : HdcTransferBase(hTaskInfo)
21 {
22 commandBegin = CMD_FILE_BEGIN;
23 commandData = CMD_FILE_DATA;
24 }
25
~HdcFile()26 HdcFile::~HdcFile()
27 {
28 WRITE_LOG(LOG_DEBUG, "~HdcFile");
29 };
30
StopTask()31 void HdcFile::StopTask()
32 {
33 WRITE_LOG(LOG_DEBUG, "HdcFile StopTask");
34 singalStop = true;
35 };
36
BeginTransfer(CtxFile * context,const string & command)37 bool HdcFile::BeginTransfer(CtxFile *context, const string &command)
38 {
39 int argc = 0;
40 bool ret = false;
41 char **argv = Base::SplitCommandToArgs(command.c_str(), &argc);
42 if (argc < CMD_ARG1_COUNT || argv == nullptr) {
43 LogMsg(MSG_FAIL, "Transfer path split failed");
44 if (argv) {
45 delete[]((char *)argv);
46 }
47 return false;
48 }
49 if (!SetMasterParameters(context, command.c_str(), argc, argv)) {
50 delete[]((char *)argv);
51 return false;
52 }
53 do {
54 ++refCount;
55 uv_fs_open(loopTask, &context->fsOpenReq, context->localPath.c_str(), O_RDONLY, S_IWUSR | S_IRUSR, OnFileOpen);
56 context->master = true;
57 ret = true;
58 } while (false);
59 if (!ret) {
60 LogMsg(MSG_FAIL, "Transfer path failed, Master:%s Slave:%s", context->localPath.c_str(),
61 context->remotePath.c_str());
62 }
63 delete[]((char *)argv);
64 return ret;
65 }
66
SetMasterParameters(CtxFile * context,const char * command,int argc,char ** argv)67 bool HdcFile::SetMasterParameters(CtxFile *context, const char *command, int argc, char **argv)
68 {
69 int srcArgvIndex = 0;
70 string errStr;
71 const string CMD_OPTION_TSTMP = "-a";
72 const string CMD_OPTION_SYNC = "-sync";
73 const string CMD_OPTION_ZIP = "-z";
74
75 for (int i = 0; i < argc - CMD_ARG1_COUNT; i++) {
76 if (argv[i] == CMD_OPTION_ZIP) {
77 context->transferConfig.compressType = COMPRESS_LZ4;
78 ++srcArgvIndex;
79 } else if (argv[i] == CMD_OPTION_SYNC) {
80 context->transferConfig.updateIfNew = true;
81 ++srcArgvIndex;
82 } else if (argv[i] == CMD_OPTION_TSTMP) {
83 // The time zone difference may cause the display time on the PC and the
84 // device to differ by several hours
85 //
86 // ls -al --full-time
87 context->transferConfig.holdTimestamp = true;
88 ++srcArgvIndex;
89 } else if (argv[i] == CMD_OPTION_CLIENTCWD) {
90 context->transferConfig.clientCwd = argv[i + 1];
91 srcArgvIndex += CMD_ARG1_COUNT; // skip 2args
92 } else if (argv[i][0] == '-') {
93 LogMsg(MSG_FAIL, "Unknow file option: %s", argv[i]);
94 return false;
95 }
96 }
97 context->remotePath = argv[argc - 1];
98 context->localPath = argv[argc - 2];
99 if (taskInfo->serverOrDaemon) {
100 // master and server
101 ExtractRelativePath(context->transferConfig.clientCwd, context->localPath);
102 }
103 if (!Base::CheckDirectoryOrPath(context->localPath.c_str(), true, true, errStr)) {
104 LogMsg(MSG_FAIL, "%s", errStr.c_str());
105 return false;
106 }
107 context->localName = Base::GetFullFilePath(context->localPath);
108 return true;
109 }
110
CheckMaster(CtxFile * context)111 void HdcFile::CheckMaster(CtxFile *context)
112 {
113 string s = SerialStruct::SerializeToString(context->transferConfig);
114 SendToAnother(CMD_FILE_CHECK, (uint8_t *)s.c_str(), s.size());
115 }
116
WhenTransferFinish(CtxFile * context)117 void HdcFile::WhenTransferFinish(CtxFile *context)
118 {
119 WRITE_LOG(LOG_DEBUG, "HdcTransferBase OnFileClose");
120 uint8_t flag = 1;
121 SendToAnother(CMD_FILE_FINISH, &flag, 1);
122 }
123
TransferSummary(CtxFile * context)124 void HdcFile::TransferSummary(CtxFile *context)
125 {
126 uint64_t nMSec = Base::GetRuntimeMSec() - context->transferBegin;
127 double fRate = static_cast<double>(context->indexIO) / nMSec; // / /1000 * 1000 = 0
128 if (context->indexIO >= context->fileSize) {
129 LogMsg(MSG_OK, "FileTransfer finish, Size:%lld time:%lldms rate:%.2lfkB/s", context->indexIO, nMSec, fRate);
130 } else {
131 constexpr int bufSize = 1024;
132 char buf[bufSize] = { 0 };
133 uv_strerror_r((int)(-context->lastErrno), buf, bufSize);
134 LogMsg(MSG_FAIL, "Transfer Stop at:%lld/%lld(Bytes), Reason: %s", context->indexIO, context->fileSize,
135 buf);
136 }
137 }
138
SlaveCheck(uint8_t * payload,const int payloadSize)139 bool HdcFile::SlaveCheck(uint8_t *payload, const int payloadSize)
140 {
141 bool ret = true;
142 bool childRet = false;
143 // parse option
144 string serialStrring((char *)payload, payloadSize);
145 TransferConfig &stat = ctxNow.transferConfig;
146 SerialStruct::ParseFromString(stat, serialStrring);
147 ctxNow.fileSize = stat.fileSize;
148 ctxNow.localPath = stat.path;
149 ctxNow.master = false;
150 ctxNow.fsOpenReq.data = &ctxNow;
151 #ifdef HDC_DEBUG
152 WRITE_LOG(LOG_DEBUG, "HdcFile fileSize got %" PRIu64 "", ctxNow.fileSize);
153 #endif
154 // check path
155 childRet = SmartSlavePath(stat.clientCwd, ctxNow.localPath, stat.optionalName.c_str());
156 if (childRet && ctxNow.transferConfig.updateIfNew) { // file exist and option need update
157 // if is newer
158 uv_fs_t fs = {};
159 uv_fs_stat(nullptr, &fs, ctxNow.localPath.c_str(), nullptr);
160 uv_fs_req_cleanup(&fs);
161 if ((uint64_t)fs.statbuf.st_mtim.tv_sec >= ctxNow.transferConfig.mtime) {
162 LogMsg(MSG_FAIL, "Target file is the same date or newer,path: %s", ctxNow.localPath.c_str());
163 return false;
164 }
165 }
166 // begin work
167 ++refCount;
168 uv_fs_open(loopTask, &ctxNow.fsOpenReq, ctxNow.localPath.c_str(), UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY,
169 S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, OnFileOpen);
170 ctxNow.transferBegin = Base::GetRuntimeMSec();
171 return ret;
172 }
173
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)174 bool HdcFile::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
175 {
176 HdcTransferBase::CommandDispatch(command, payload, payloadSize);
177 bool ret = true;
178 switch (command) {
179 case CMD_FILE_INIT: { // initial
180 string s = string((char *)payload, payloadSize);
181 ret = BeginTransfer(&ctxNow, s);
182 ctxNow.transferBegin = Base::GetRuntimeMSec();
183 break;
184 }
185 case CMD_FILE_CHECK: {
186 ret = SlaveCheck(payload, payloadSize);
187 break;
188 }
189 case CMD_FILE_FINISH: {
190 if (*payload) { // close-step3
191 ctxNow.ioFinish = true;
192 --(*payload);
193 SendToAnother(CMD_FILE_FINISH, payload, 1);
194 } else { // close-step3
195 TransferSummary(&ctxNow);
196 TaskFinish();
197 }
198 break;
199 }
200 default:
201 break;
202 }
203 return ret;
204 }
205 } // namespace Hdc
206