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