• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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