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 isStableBuf = hTaskInfo->isStableBuf;
25 }
26
~HdcFile()27 HdcFile::~HdcFile()
28 {
29 WRITE_LOG(LOG_DEBUG, "~HdcFile channelId:%u", taskInfo->channelId);
30 };
31
StopTask()32 void HdcFile::StopTask()
33 {
34 WRITE_LOG(LOG_DEBUG, "StopTask channelId:%u", taskInfo->channelId);
35 singalStop = true;
36 };
37
BeginTransfer(CtxFile * context,const string & command)38 bool HdcFile::BeginTransfer(CtxFile *context, const string &command)
39 {
40 int argc = 0;
41 bool ret = false;
42 StartTraceScope("HdcFile::BeginTransfer");
43 char **argv = Base::SplitCommandToArgs(command.c_str(), &argc);
44 if (argc < CMD_ARG1_COUNT || argv == nullptr) {
45 LogMsg(MSG_FAIL, "Transfer path split failed");
46 if (argv) {
47 delete[](reinterpret_cast<char *>(argv));
48 }
49 return false;
50 }
51 if (!SetMasterParameters(context, command.c_str(), argc, argv)) {
52 delete[](reinterpret_cast<char *>(argv));
53 return false;
54 }
55 if (!CheckBlacklistPath(context)) {
56 WRITE_LOG(LOG_INFO, "Operation not allowed");
57 delete[](reinterpret_cast<char *>(argv));
58 return false;
59 }
60 uv_fs_t *openReq = new uv_fs_t;
61 if (openReq == nullptr) {
62 delete[](reinterpret_cast<char *>(argv));
63 LogMsg(MSG_FAIL, "HdcFile::BeginTransfer new openReq failed");
64 return false;
65 }
66 memset_s(openReq, sizeof(uv_fs_t), 0, sizeof(uv_fs_t));
67 openReq->data = context;
68 do {
69 ++refCount;
70 uv_fs_open(loopTask, openReq, context->localPath.c_str(), O_RDONLY, S_IWUSR | S_IRUSR, OnFileOpen);
71 context->master = true;
72 ret = true;
73 } while (false);
74 if (!ret) {
75 LogMsg(MSG_FAIL, "Transfer path failed, Master:%s Slave:%s", context->localPath.c_str(),
76 context->remotePath.c_str());
77 }
78 delete[](reinterpret_cast<char *>(argv));
79 return ret;
80 }
81
containsBlacklistedSubstring(const std::string & input,const std::unordered_set<std::string> & blacklistFiles)82 bool HdcFile::containsBlacklistedSubstring(const std::string& input,
83 const std::unordered_set<std::string>& blacklistFiles)
84 {
85 for (const auto& blacklisted : blacklistFiles) {
86 if (input.find(blacklisted) != std::string::npos) {
87 return true;
88 }
89 }
90 return false;
91 }
92
CheckBlacklistPath(CtxFile * context)93 bool HdcFile::CheckBlacklistPath(CtxFile *context)
94 {
95 // Initialize blacklistFiles,
96 // if you need to add blacklistFiles content, you can use blacklistFiles.insert("");
97 std::unordered_set<std::string> blacklistFiles = {"/data/service/el1/public/hdc"};
98 if (containsBlacklistedSubstring(context->localPath, blacklistFiles)) {
99 LogMsg(MSG_FAIL, "[E005008] Operation not allowed");
100 return false;
101 }
102 return true;
103 }
104
ParseMasterParameters(CtxFile * context,int argc,char ** argv,int & srcArgvIndex)105 bool HdcFile::ParseMasterParameters(CtxFile *context, int argc, char **argv, int &srcArgvIndex)
106 {
107 for (int i = 0; i < argc; i++) {
108 if (argv[i] == cmdOptionZip) {
109 context->transferConfig.compressType = COMPRESS_LZ4;
110 ++srcArgvIndex;
111 } else if (argv[i] == cmdOptionSync) {
112 context->transferConfig.updateIfNew = true;
113 ++srcArgvIndex;
114 } else if (argv[i] == cmdOptionTstmp) {
115 // The time zone difference may cause the display time on the PC and the
116 // device to differ by several hours
117 //
118 // ls -al --full-time
119 context->transferConfig.holdTimestamp = true;
120 ++srcArgvIndex;
121 } else if (argv[i] == CMD_OPTION_CLIENTCWD) {
122 context->transferConfig.clientCwd = argv[i + 1];
123 srcArgvIndex += CMD_ARG1_COUNT; // skip 2args
124 } else if (argv[i] == cmdOptionModeSync) {
125 context->fileModeSync = true;
126 ++srcArgvIndex;
127 } else if (argv[i] == CMDSTR_REMOTE_PARAMETER) {
128 ++srcArgvIndex;
129 } else if (argv[i] == cmdBundleName) {
130 context->sandboxMode = true;
131 if (argc == srcArgvIndex + 1) {
132 LogMsg(MSG_FAIL, "[E005003] The parameter is missing, correct your input by referring below:\n%s",
133 taskInfo->serverOrDaemon ? "Usage: hdc file send [-b bundlename] local remote" :
134 "Usage: hdc file recv [-b bundlename] remote local");
135 WRITE_LOG(LOG_DEBUG, "There is no bundle name.");
136 return false;
137 }
138 context->transferConfig.reserve1 = argv[i + 1];
139 context->bundleName = argv[i + 1];
140 srcArgvIndex += CMD_ARG1_COUNT; // skip 2args
141 } else if (argv[i][0] == '-') {
142 LogMsg(MSG_FAIL, "Unknown file option: %s", argv[i]);
143 return false;
144 }
145 }
146
147 return ValidateAndSetPaths(context, argc, argv, srcArgvIndex);
148 }
149
ValidateAndSetPaths(CtxFile * context,int argc,char ** argv,int & srcArgvIndex)150 bool HdcFile::ValidateAndSetPaths(CtxFile *context, int argc, char **argv, int &srcArgvIndex)
151 {
152 if (argc == srcArgvIndex) {
153 LogMsg(MSG_FAIL, "There is no local and remote path");
154 return false;
155 }
156
157 if (context->sandboxMode) {
158 if ((srcArgvIndex + 1) == argc) {
159 context->remotePath = ".";
160 context->localPath = argv[argc - 1];
161 context->inputLocalPath = context->localPath;
162 } else if ((srcArgvIndex + CMD_FILE_PENULT_PARAM) == argc) {
163 context->remotePath = argv[argc - 1];
164 context->localPath = argv[argc - CMD_FILE_PENULT_PARAM];
165 context->inputLocalPath = context->localPath;
166 } else {
167 context->remotePath = argv[argc - 1];
168 context->localPath = argv[argc - CMD_FILE_PENULT_PARAM];
169 context->inputLocalPath = context->localPath;
170 }
171 } else {
172 context->remotePath = argv[argc - 1];
173 context->localPath = argv[argc - CMD_FILE_PENULT_PARAM];
174 context->inputLocalPath = context->localPath;
175 }
176 return true;
177 }
178
CheckSandboxSubPath(CtxFile * context,string & resolvedPath)179 bool HdcFile::CheckSandboxSubPath(CtxFile *context, string &resolvedPath)
180 {
181 string fullPath = SANDBOX_ROOT_DIR + context->bundleName;
182 string appDir(fullPath);
183 appDir = Base::CanonicalizeSpecPath(appDir);
184 fullPath = fullPath + Base::GetPathSep() + context->inputLocalPath;
185 // remove the postfix char '/', make sure that the method Base::GetPathWithoutFilename
186 // returns a path without the last dir node name.
187 // if input local path ends with "../" likes "data/storage/el1/base/../../../../", the final value
188 // of fullpath will be the parent dir of the expected path. it won't be unexcepted, so correct it.
189 const int lastTwoIndex = 2;
190 while (fullPath.back() == Base::GetPathSep() && fullPath[fullPath.size() - lastTwoIndex] != '.') {
191 fullPath.pop_back();
192 }
193 resolvedPath = PathSimplify(fullPath);
194 if (resolvedPath.size() > appDir.size() + 1) {
195 resolvedPath = Base::GetPathWithoutFilename(resolvedPath);
196 }
197 if (!IsPathInsideSandbox(resolvedPath, appDir)) {
198 LogMsg(MSG_FAIL, "[E005102] Remote path: %s is invalid, no such file/directory or it's out of "
199 "the application directory.", context->inputLocalPath.c_str());
200 WRITE_LOG(LOG_DEBUG, "Invalid path:%s, fullpath:%s, resolvedPath:%s, errno:%d",
201 context->inputLocalPath.c_str(), fullPath.c_str(), resolvedPath.c_str(), errno);
202 return false;
203 }
204 return true;
205 }
206
IsPathInsideSandbox(const string & path,const string & appDir)207 bool HdcFile::IsPathInsideSandbox(const string &path, const string &appDir)
208 {
209 if (path.size() < appDir.size()) {
210 return false;
211 }
212 string resolvedPath = path + Base::GetPathSep();
213 string appDirPath = appDir + Base::GetPathSep();
214 return (strncmp(resolvedPath.c_str(), appDirPath.c_str(), appDirPath.size()) == 0);
215 }
216
PathSimplify(const string & path)217 string HdcFile::PathSimplify(const string &path)
218 {
219 string outPath;
220 string group;
221 vector<string> nameVec;
222 std::stringstream oss(path);
223 while (getline(oss, group, Base::GetPathSep())) {
224 if (group == "" || group == ".") {
225 continue;
226 }
227 if (group == ".." && (nameVec.size() != 0)) {
228 nameVec.pop_back();
229 } else if (group != "..") {
230 nameVec.push_back(group);
231 }
232 }
233
234 for (string& name : nameVec) {
235 outPath += Base::GetPathSep() + name;
236 }
237 return (outPath.size() != 0) ? outPath : string(1, Base::GetPathSep());
238 }
239
SetMasterParameters(CtxFile * context,const char * command,int argc,char ** argv)240 bool HdcFile::SetMasterParameters(CtxFile *context, const char *command, int argc, char **argv)
241 {
242 int srcArgvIndex = 0;
243 string errStr;
244 if (!ParseMasterParameters(context, argc, argv, srcArgvIndex)) {
245 return false;
246 }
247
248 if (taskInfo->serverOrDaemon) {
249 // master and server
250 if ((srcArgvIndex + 1) == argc) {
251 LogMsg(MSG_FAIL, "There is no remote path");
252 return false;
253 }
254 ExtractRelativePath(context->transferConfig.clientCwd, context->localPath);
255 } else if (!SetMasterParametersOnDaemon(context, argc, argv, srcArgvIndex)) {
256 return false;
257 }
258 context->localName = Base::GetFullFilePath(context->localPath);
259 mode_t mode = mode_t(~S_IFMT);
260 if (!Base::CheckDirectoryOrPath(context->localPath.c_str(), true, true, errStr, mode) && (mode & S_IFDIR)) {
261 context->isDir = true;
262 GetSubFilesRecursively(context->localPath, context->localName, &context->taskQueue);
263 if (context->taskQueue.size() == 0) {
264 LogMsg(MSG_FAIL, "Operation failed, because the source folder is empty.");
265 return false;
266 }
267 context->fileCnt = 0;
268 context->dirSize = 0;
269 context->localDirName = Base::GetPathWithoutFilename(context->localPath);
270
271 context->localName = context->taskQueue.back();
272 context->localPath = context->localDirName + context->localName;
273
274 context->taskQueue.pop_back();
275 }
276 return true;
277 }
278
SetMasterParametersOnDaemon(CtxFile * context,int argc,char ** argv,int srcArgvIndex)279 bool HdcFile::SetMasterParametersOnDaemon(CtxFile *context, int argc, char **argv, int srcArgvIndex)
280 {
281 if (context->sandboxMode &&
282 context->transferConfig.reserve1.size() > 0 &&
283 !IsValidBundlePath(context->transferConfig.reserve1)) {
284 LogMsg(MSG_FAIL, "[E005101] Invalid bundle name: %s",
285 context->transferConfig.reserve1.c_str());
286 WRITE_LOG(LOG_DEBUG, "SetMasterParameters invalid bundleName:%s",
287 context->transferConfig.reserve1.c_str());
288 return false;
289 }
290 if ((srcArgvIndex + 1) == argc) {
291 context->remotePath = ".";
292 context->localPath = argv[argc - 1];
293 }
294 context->localName = Base::GetFullFilePath(context->localPath);
295
296 if (context->sandboxMode && IsValidBundlePath(context->transferConfig.reserve1)) {
297 string resolvedPath;
298 if (CheckSandboxSubPath(context, resolvedPath)) {
299 context->localPath = resolvedPath + Base::GetPathSep() + context->localName;
300 } else {
301 WRITE_LOG(LOG_WARN, "SetMasterParameters, CheckSandboxSubPath false.");
302 return false;
303 }
304 }
305 return true;
306 }
307
CheckMaster(CtxFile * context)308 void HdcFile::CheckMaster(CtxFile *context)
309 {
310 StartTraceScope("HdcFile::CheckMaster");
311 if (context->fileModeSync) {
312 string s = SerialStruct::SerializeToString(context->fileMode);
313 SendToAnother(CMD_FILE_MODE, reinterpret_cast<uint8_t *>(const_cast<char *>(s.c_str())), s.size());
314 } else {
315 string s = SerialStruct::SerializeToString(context->transferConfig);
316 SendToAnother(CMD_FILE_CHECK, reinterpret_cast<uint8_t *>(const_cast<char *>(s.c_str())), s.size());
317 }
318 }
319
WhenTransferFinish(CtxFile * context)320 void HdcFile::WhenTransferFinish(CtxFile *context)
321 {
322 WRITE_LOG(LOG_DEBUG, "WhenTransferFinish fileCnt:%d", context->fileCnt);
323 uint8_t flag = 1;
324 context->fileCnt++;
325 context->dirSize += context->indexIO;
326 SendToAnother(CMD_FILE_FINISH, &flag, 1);
327 }
328
TransferSummary(CtxFile * context)329 void HdcFile::TransferSummary(CtxFile *context)
330 {
331 uint64_t nMSec = Base::GetRuntimeMSec() -
332 (context->fileCnt > 1 ? context->transferDirBegin : context->transferBegin);
333 uint64_t fSize = context->fileCnt > 1 ? context->dirSize : context->indexIO;
334 double fRate = static_cast<double>(fSize) / nMSec; // / /1000 * 1000 = 0
335 if (context->indexIO >= context->fileSize || context->lastErrno == 0) {
336 LogMsg(MSG_OK, "FileTransfer finish, Size:%lld, File count = %d, time:%lldms rate:%.2lfkB/s",
337 fSize, context->fileCnt, nMSec, fRate);
338 } else {
339 constexpr int bufSize = 1024;
340 char buf[bufSize] = { 0 };
341 uv_strerror_r(static_cast<int>(-context->lastErrno), buf, bufSize);
342 LogMsg(MSG_FAIL, "Transfer Stop at:%lld/%lld(Bytes), Reason: %s", context->indexIO, context->fileSize,
343 buf);
344 }
345 }
346
FileModeSync(const uint16_t cmd,uint8_t * payload,const int payloadSize)347 bool HdcFile::FileModeSync(const uint16_t cmd, uint8_t *payload, const int payloadSize)
348 {
349 StartTraceScope("HdcFile::FileModeSync");
350 if (ctxNow.master) {
351 WRITE_LOG(LOG_DEBUG, "FileModeSync master ctxNow.fileModeSync = %d size = %zu", ctxNow.fileModeSync,
352 ctxNow.dirMode.size());
353 if (ctxNow.dirMode.size() > 0) {
354 auto mode = ctxNow.dirMode.back();
355 WRITE_LOG(LOG_DEBUG, "file = %s permissions: %o uId = %u, gId = %u conext = %s",
356 mode.fullName.c_str(), mode.perm, mode.uId, mode.gId, mode.context.c_str());
357 string s = SerialStruct::SerializeToString(mode);
358 ctxNow.dirMode.pop_back();
359 SendToAnother(CMD_DIR_MODE, reinterpret_cast<uint8_t *>(const_cast<char *>(s.c_str())), s.size());
360 } else {
361 string s = SerialStruct::SerializeToString(ctxNow.transferConfig);
362 SendToAnother(CMD_FILE_CHECK, reinterpret_cast<uint8_t *>(const_cast<char *>(s.c_str())), s.size());
363 }
364 } else {
365 ctxNow.fileModeSync = true;
366 string serialString(reinterpret_cast<char *>(payload), payloadSize);
367 if (cmd == CMD_FILE_MODE) {
368 SerialStruct::ParseFromString(ctxNow.fileMode, serialString);
369 } else {
370 FileMode dirMode;
371 SerialStruct::ParseFromString(dirMode, serialString);
372
373 WRITE_LOG(LOG_DEBUG, "file = %s permissions: %o uId = %u, gId = %u context = %s",
374 dirMode.fullName.c_str(), dirMode.perm, dirMode.uId, dirMode.gId, dirMode.context.c_str());
375
376 vector<string> dirsOfOptName;
377 if (dirMode.fullName.find('/') != string::npos) {
378 WRITE_LOG(LOG_DEBUG, "dir mode create parent dir from linux system");
379 Base::SplitString(dirMode.fullName, "/", dirsOfOptName);
380 } else if (dirMode.fullName.find('\\') != string::npos) {
381 WRITE_LOG(LOG_DEBUG, "dir mode create parent dir from windows system");
382 Base::SplitString(dirMode.fullName, "\\", dirsOfOptName);
383 } else {
384 dirsOfOptName.emplace_back(dirMode.fullName);
385 }
386
387 dirMode.fullName = "";
388 for (auto s : dirsOfOptName) {
389 if (dirMode.fullName.empty()) {
390 dirMode.fullName = s;
391 } else {
392 dirMode.fullName = dirMode.fullName + Base::GetPathSep() + s;
393 }
394 }
395 WRITE_LOG(LOG_DEBUG, "dir = %s permissions: %o uId = %u, gId = %u context = %s",
396 dirMode.fullName.c_str(), dirMode.perm, dirMode.uId, dirMode.gId, dirMode.context.c_str());
397 ctxNow.dirModeMap.insert(std::make_pair(dirMode.fullName, dirMode));
398 }
399 SendToAnother(CMD_FILE_MODE, nullptr, 0);
400 }
401 return true;
402 }
403
SlaveCheck(uint8_t * payload,const int payloadSize)404 bool HdcFile::SlaveCheck(uint8_t *payload, const int payloadSize)
405 {
406 if (!ParseAndValidateOptions(payload, payloadSize)) {
407 return false;
408 }
409
410 if (!CheckBundleAndPath()) {
411 return false;
412 }
413
414 if (!CheckLocalPathAndFilename()) {
415 return false;
416 }
417
418 if (!HandleFileExistenceAndNewness()) {
419 return false;
420 }
421
422 return BeginFileOperations();
423 }
424
ParseAndValidateOptions(uint8_t * payload,const int payloadSize)425 bool HdcFile::ParseAndValidateOptions(uint8_t *payload, const int payloadSize)
426 {
427 string serialString(reinterpret_cast<char *>(payload), payloadSize);
428 TransferConfig &stat = ctxNow.transferConfig;
429 if (!SerialStruct::ParseFromString(stat, serialString)) {
430 WRITE_LOG(LOG_DEBUG, "ParseFromString failed, serialString: %s", serialString.c_str());
431 return false;
432 }
433 ctxNow.fileSize = stat.fileSize;
434 ctxNow.localPath = stat.path;
435 ctxNow.inputLocalPath = ctxNow.localPath;
436 ctxNow.master = false;
437 ctxNow.bundleName = stat.reserve1;
438
439 #ifdef HDC_DEBUG
440 WRITE_LOG(LOG_DEBUG, "HdcFile fileSize got %" PRIu64 "", ctxNow.fileSize);
441 #endif
442
443 return true;
444 }
445
CheckBundleAndPath()446 bool HdcFile::CheckBundleAndPath()
447 {
448 if (!taskInfo->serverOrDaemon && IsValidBundlePath(ctxNow.bundleName)) {
449 string fullPath = SANDBOX_ROOT_DIR + ctxNow.bundleName + Base::GetPathSep();
450 fullPath.append(ctxNow.inputLocalPath);
451 ctxNow.localPath = fullPath;
452
453 string resolvedPath;
454 if (!CheckSandboxSubPath(&ctxNow, resolvedPath)) {
455 WRITE_LOG(LOG_DEBUG, "SlaveCheck CheckSandboxSubPath false.");
456 return false;
457 }
458 } else if (!taskInfo->serverOrDaemon && ctxNow.bundleName.size() > 0) {
459 LogMsg(MSG_FAIL, "[E005101] Invalid bundle name: %s",
460 ctxNow.bundleName.c_str());
461 WRITE_LOG(LOG_DEBUG, "Invalid bundle name: %s", ctxNow.bundleName.c_str());
462 return false;
463 }
464 return true;
465 }
466
CheckLocalPathAndFilename()467 bool HdcFile::CheckLocalPathAndFilename()
468 {
469 if (!CheckBlacklistPath(&ctxNow)) {
470 WRITE_LOG(LOG_DEBUG, "Operation not allowed");
471 return false;
472 }
473
474 string errStr;
475 if (!CheckLocalPath(ctxNow.localPath, ctxNow.transferConfig.optionalName, errStr)) {
476 RemoveSandboxRootPath(errStr, ctxNow.transferConfig.reserve1);
477 LogMsg(MSG_FAIL, "%s", errStr.c_str());
478 WRITE_LOG(LOG_DEBUG, "SlaveCheck CheckLocalPath error:%s", errStr.c_str());
479 return false;
480 }
481
482 if (!CheckFilename(ctxNow.localPath, ctxNow.transferConfig.optionalName, errStr)) {
483 RemoveSandboxRootPath(errStr, ctxNow.transferConfig.reserve1);
484 LogMsg(MSG_FAIL, "%s", errStr.c_str());
485 WRITE_LOG(LOG_DEBUG, "SlaveCheck CheckFilename error:%s", errStr.c_str());
486 return false;
487 }
488 return true;
489 }
490
HandleFileExistenceAndNewness()491 bool HdcFile::HandleFileExistenceAndNewness()
492 {
493 bool childRet = SmartSlavePath(ctxNow.transferConfig.clientCwd, ctxNow.localPath,
494 ctxNow.transferConfig.optionalName.c_str());
495 if (childRet && ctxNow.transferConfig.updateIfNew) { // file exist and option need update
496 uv_fs_t fs = {};
497 uv_fs_stat(nullptr, &fs, ctxNow.localPath.c_str(), nullptr);
498 uv_fs_req_cleanup(&fs);
499 if ((uint64_t)fs.statbuf.st_mtim.tv_sec >= ctxNow.transferConfig.mtime) {
500 LogMsg(MSG_FAIL, "Target file is the same date or newer,path: %s", ctxNow.localPath.c_str());
501 return false;
502 }
503 }
504 return true;
505 }
506
BeginFileOperations()507 bool HdcFile::BeginFileOperations()
508 {
509 uv_fs_t *openReq = new uv_fs_t;
510 if (openReq == nullptr) {
511 LogMsg(MSG_FAIL, "HdcFile::SlaveCheck new openReq failed");
512 return false;
513 }
514 memset_s(openReq, sizeof(uv_fs_t), 0, sizeof(uv_fs_t));
515 openReq->data = &ctxNow;
516 ++refCount;
517 uv_fs_open(loopTask, openReq, ctxNow.localPath.c_str(), UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY,
518 S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, OnFileOpen);
519 if (ctxNow.transferDirBegin == 0) {
520 ctxNow.transferDirBegin = Base::GetRuntimeMSec();
521 }
522 ctxNow.transferBegin = Base::GetRuntimeMSec();
523 return true;
524 }
525
TransferNext(CtxFile * context)526 void HdcFile::TransferNext(CtxFile *context)
527 {
528 context->localName = context->taskQueue.back();
529 context->localPath = context->localDirName + context->localName;
530 context->taskQueue.pop_back();
531 WRITE_LOG(LOG_DEBUG, "TransferNext localPath = %s queuesize:%d",
532 context->localPath.c_str(), ctxNow.taskQueue.size());
533 uv_fs_t *openReq = new uv_fs_t;
534 if (openReq == nullptr) {
535 WRITE_LOG(LOG_FATAL, "HdcFile::TransferNext new openReq failed for file %s", context->localPath.c_str());
536 OnFileOpenFailed(context);
537 return;
538 }
539 memset_s(openReq, sizeof(uv_fs_t), 0, sizeof(uv_fs_t));
540 openReq->data = context;
541 do {
542 ++refCount;
543 uv_fs_open(loopTask, openReq, context->localPath.c_str(), O_RDONLY, S_IWUSR | S_IRUSR, OnFileOpen);
544 } while (false);
545
546 return;
547 }
548
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)549 bool HdcFile::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
550 {
551 HdcTransferBase::CommandDispatch(command, payload, payloadSize);
552 bool ret = true;
553 StartTraceScope("HdcFile::CommandDispatch");
554 switch (command) {
555 case CMD_FILE_INIT: { // initial
556 string s = string(reinterpret_cast<char *>(payload), payloadSize);
557 ret = BeginTransfer(&ctxNow, s);
558 ctxNow.transferBegin = Base::GetRuntimeMSec();
559 break;
560 }
561 case CMD_FILE_CHECK: {
562 ret = SlaveCheck(payload, payloadSize);
563 break;
564 }
565 case CMD_FILE_MODE:
566 case CMD_DIR_MODE: {
567 ret = FileModeSync(command, payload, payloadSize);
568 break;
569 }
570 case CMD_FILE_FINISH: {
571 if (*payload) { // close-step3
572 CloseCtxFd(&ctxNow);
573 WRITE_LOG(LOG_DEBUG, "Dir = %d taskQueue size = %d", ctxNow.isDir, ctxNow.taskQueue.size());
574 if (ctxNow.isDir && (ctxNow.taskQueue.size() > 0)) {
575 TransferNext(&ctxNow);
576 } else {
577 ctxNow.ioFinish = true;
578 ctxNow.transferDirBegin = 0;
579 --(*payload);
580 SendToAnother(CMD_FILE_FINISH, payload, 1);
581 }
582 } else { // close-step3
583 TransferSummary(&ctxNow);
584 TaskFinish();
585 }
586 break;
587 }
588 default:
589 break;
590 }
591 return ret;
592 }
593 } // namespace Hdc
594