• 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 "transfer.h"
16 #include "serial_struct.h"
17 #include <sys/stat.h>
18 #ifdef HARMONY_PROJECT
19 #include <lz4.h>
20 #endif
21 #if (!(defined(HOST_MINGW)||defined(HOST_MAC))) && defined(SURPPORT_SELINUX)
22 #include <selinux/selinux.h>
23 #endif
24 namespace Hdc {
25 constexpr uint64_t HDC_TIME_CONVERT_BASE = 1000000000;
26 
27 
HdcTransferBase(HTaskInfo hTaskInfo)28 HdcTransferBase::HdcTransferBase(HTaskInfo hTaskInfo)
29     : HdcTaskBase(hTaskInfo)
30 {
31     ResetCtx(&ctxNow, true);
32     commandBegin = 0;
33     commandData = 0;
34 }
35 
~HdcTransferBase()36 HdcTransferBase::~HdcTransferBase()
37 {
38     WRITE_LOG(LOG_DEBUG, "~HdcTransferBase channelId:%u lastErrno:%u result:%d ioFinish:%d",
39         taskInfo->channelId, ctxNow.lastErrno, ctxNow.fsOpenReq.result, ctxNow.ioFinish);
40     if (ctxNow.lastErrno != 0 || (ctxNow.fsOpenReq.result > 0 && !ctxNow.ioFinish)) {
41         uv_fs_close(nullptr, &ctxNow.fsCloseReq, ctxNow.fsOpenReq.result, nullptr);
42     }
43 };
44 
ResetCtx(CtxFile * context,bool full)45 bool HdcTransferBase::ResetCtx(CtxFile *context, bool full)
46 {
47     if (full) {
48         *context = {};
49         context->fsOpenReq.data = context;
50         context->fsCloseReq.data = context;
51         context->thisClass = this;
52         context->loop = loopTask;
53         context->cb = OnFileIO;
54     }
55     context->closeNotify = false;
56     context->indexIO = 0;
57     context->lastErrno = 0;
58     context->ioFinish = false;
59     context->closeReqSubmitted = false;
60     return true;
61 }
62 
SimpleFileIO(CtxFile * context,uint64_t index,uint8_t * sendBuf,int bytes)63 int HdcTransferBase::SimpleFileIO(CtxFile *context, uint64_t index, uint8_t *sendBuf, int bytes)
64 {
65     StartTraceScope("HdcTransferBase::SimpleFileIO");
66     // The first 8 bytes file offset
67     uint8_t *buf = cirbuf.Malloc();
68     if (buf == nullptr) {
69         WRITE_LOG(LOG_FATAL, "SimpleFileIO buf nullptr");
70         return -1;
71     }
72     CtxFileIO *ioContext = new(std::nothrow) CtxFileIO();
73     if (ioContext == nullptr) {
74         cirbuf.Free(buf);
75         WRITE_LOG(LOG_FATAL, "SimpleFileIO ioContext nullptr");
76         return -1;
77     }
78     bool ret = false;
79     while (true) {
80         size_t bufMaxSize = static_cast<size_t>(Base::GetUsbffsBulkSize() - payloadPrefixReserve);
81         if (bytes < 0 || static_cast<size_t>(bytes) > bufMaxSize) {
82             WRITE_LOG(LOG_DEBUG, "SimpleFileIO param check failed");
83             break;
84         }
85         if (context->ioFinish) {
86             WRITE_LOG(LOG_DEBUG, "SimpleFileIO to closed IOStream");
87             break;
88         }
89         uv_fs_t *req = &ioContext->fs;
90         ioContext->bufIO = buf + payloadPrefixReserve;
91         ioContext->context = context;
92         req->data = ioContext;
93         ++refCount;
94         if (context->master) {  // master just read, and slave just write.when master/read, sendBuf can be nullptr
95             uv_buf_t iov = uv_buf_init(reinterpret_cast<char *>(ioContext->bufIO), bytes);
96             uv_fs_read(context->loop, req, context->fsOpenReq.result, &iov, 1, index, context->cb);
97         } else {
98             // The US_FS_WRITE here must be brought into the actual file offset, which cannot be incorporated with local
99             // accumulated index because UV_FS_WRITE will be executed multiple times and then trigger a callback.
100             if (bytes > 0 && memcpy_s(ioContext->bufIO, bufMaxSize, sendBuf, bytes) != EOK) {
101                 WRITE_LOG(LOG_WARN, "SimpleFileIO memcpy error");
102                 break;
103             }
104             uv_buf_t iov = uv_buf_init(reinterpret_cast<char *>(ioContext->bufIO), bytes);
105             uv_fs_write(context->loop, req, context->fsOpenReq.result, &iov, 1, index, context->cb);
106         }
107         ret = true;
108         break;
109     }
110     if (!ret) {
111         if (ioContext != nullptr) {
112             delete ioContext;
113             ioContext = nullptr;
114         }
115         cirbuf.Free(buf);
116         return -1;
117     }
118     return bytes;
119 }
120 
OnFileClose(uv_fs_t * req)121 void HdcTransferBase::OnFileClose(uv_fs_t *req)
122 {
123     StartTraceScope("HdcTransferBase::OnFileClose");
124     uv_fs_req_cleanup(req);
125     CtxFile *context = (CtxFile *)req->data;
126     context->closeReqSubmitted = false;
127     HdcTransferBase *thisClass = (HdcTransferBase *)context->thisClass;
128     if (context->closeNotify) {
129         // close-step2
130         // maybe successful finish or failed finish
131         thisClass->WhenTransferFinish(context);
132     }
133     --thisClass->refCount;
134     return;
135 }
136 
SetFileTime(CtxFile * context)137 void HdcTransferBase::SetFileTime(CtxFile *context)
138 {
139     if (!context->transferConfig.holdTimestamp) {
140         return;
141     }
142     if (!context->transferConfig.mtime) {
143         return;
144     }
145     uv_fs_t fs;
146     double aTimeSec = static_cast<long double>(context->transferConfig.atime) / HDC_TIME_CONVERT_BASE;
147     double mTimeSec = static_cast<long double>(context->transferConfig.mtime) / HDC_TIME_CONVERT_BASE;
148     uv_fs_futime(nullptr, &fs, context->fsOpenReq.result, aTimeSec, mTimeSec, nullptr);
149     uv_fs_req_cleanup(&fs);
150 }
151 
SendIOPayload(CtxFile * context,uint64_t index,uint8_t * data,int dataSize)152 bool HdcTransferBase::SendIOPayload(CtxFile *context, uint64_t index, uint8_t *data, int dataSize)
153 {
154     TransferPayload payloadHead;
155     string head;
156     int compressSize = 0;
157     int sendBufSize = payloadPrefixReserve + dataSize;
158     uint8_t *sendBuf = data - payloadPrefixReserve;
159     bool ret = false;
160 
161     StartTraceScope("HdcTransferBase::SendIOPayload");
162     payloadHead.compressType = context->transferConfig.compressType;
163     payloadHead.uncompressSize = dataSize;
164     payloadHead.index = index;
165     if (dataSize > 0) {
166         switch (payloadHead.compressType) {
167 #ifdef HARMONY_PROJECT
168             case COMPRESS_LZ4: {
169                 sendBuf = new uint8_t[sendBufSize]();
170                 if (!sendBuf) {
171                     WRITE_LOG(LOG_FATAL, "alloc LZ4 buffer failed");
172                     return false;
173                 }
174                 compressSize = LZ4_compress_default((const char *)data, (char *)sendBuf + payloadPrefixReserve,
175                                                     dataSize, dataSize);
176                 break;
177             }
178 #endif
179             default: {  // COMPRESS_NONE
180                 compressSize = dataSize;
181                 break;
182             }
183         }
184     }
185     payloadHead.compressSize = compressSize;
186     head = SerialStruct::SerializeToString(payloadHead);
187     if (head.size() + 1 > payloadPrefixReserve) {
188         goto out;
189     }
190     if (EOK != memcpy_s(sendBuf, sendBufSize, head.c_str(), head.size() + 1)) {
191         goto out;
192     }
193     ret = SendToAnother(commandData, sendBuf, payloadPrefixReserve + compressSize) > 0;
194 
195 out:
196     if (dataSize > 0 && payloadHead.compressType == COMPRESS_LZ4) {
197         delete[] sendBuf;
198     }
199     return ret;
200 }
201 
OnFileIO(uv_fs_t * req)202 void HdcTransferBase::OnFileIO(uv_fs_t *req)
203 {
204     CtxFileIO *contextIO = reinterpret_cast<CtxFileIO *>(req->data);
205     CtxFile *context = reinterpret_cast<CtxFile *>(contextIO->context);
206     HdcTransferBase *thisClass = (HdcTransferBase *)context->thisClass;
207     uint8_t *bufIO = contextIO->bufIO;
208     StartTraceScope("HdcTransferBase::OnFileIO");
209     uv_fs_req_cleanup(req);
210     while (true) {
211         if (context->ioFinish) {
212             break;
213         }
214         if (req->result < 0) {
215             constexpr int bufSize = 1024;
216             char buf[bufSize] = { 0 };
217             uv_strerror_r((int)req->result, buf, bufSize);
218             WRITE_LOG(LOG_DEBUG, "OnFileIO error: %s", buf);
219             context->closeNotify = true;
220             context->lastErrno = abs(req->result);
221             context->ioFinish = true;
222             break;
223         }
224         context->indexIO += req->result;
225         if (req->fs_type == UV_FS_READ) {
226 #ifdef HDC_DEBUG
227             WRITE_LOG(LOG_DEBUG, "read file data %" PRIu64 "/%" PRIu64 "", context->indexIO,
228                       context->fileSize);
229 #endif // HDC_DEBUG
230             if (!thisClass->SendIOPayload(context, context->indexIO - req->result, bufIO, req->result)) {
231                 context->ioFinish = true;
232                 break;
233             }
234             if (context->indexIO < context->fileSize) {
235                 thisClass->SimpleFileIO(context, context->indexIO, nullptr,
236                                         Base::GetMaxBufSize() * thisClass->maxTransferBufFactor);
237             } else {
238                 context->ioFinish = true;
239             }
240         } else if (req->fs_type == UV_FS_WRITE) {  // write
241 #ifdef HDC_DEBUG
242             WRITE_LOG(LOG_DEBUG, "write file data %" PRIu64 "/%" PRIu64 "", context->indexIO,
243                       context->fileSize);
244 #endif // HDC_DEBUG
245             if (context->indexIO >= context->fileSize) {
246                 // The active end must first read it first, but you can't make Finish first, because Slave may not
247                 // end.Only slave receives complete talents Finish
248                 context->closeNotify = true;
249                 context->ioFinish = true;
250                 thisClass->SetFileTime(context);
251             }
252         } else {
253             context->ioFinish = true;
254         }
255         break;
256     }
257     if (context->ioFinish) {
258         // close-step1
259         ++thisClass->refCount;
260         if (req->fs_type == UV_FS_WRITE) {
261             uv_fs_fsync(thisClass->loopTask, &context->fsCloseReq, context->fsOpenReq.result, nullptr);
262         }
263         WRITE_LOG(LOG_DEBUG, "channelId:%u result:%d, closeReqSubmitted:%d",
264                   thisClass->taskInfo->channelId, context->fsOpenReq.result, context->closeReqSubmitted);
265         if (context->lastErrno == 0 && !context->closeReqSubmitted) {
266             context->closeReqSubmitted = true;
267             WRITE_LOG(LOG_DEBUG, "OnFileIO fs_close, channelId:%u", thisClass->taskInfo->channelId);
268             uv_fs_close(thisClass->loopTask, &context->fsCloseReq, context->fsOpenReq.result, OnFileClose);
269         } else {
270             thisClass->WhenTransferFinish(context);
271             --thisClass->refCount;
272         }
273     }
274     thisClass->cirbuf.Free(bufIO - payloadPrefixReserve);
275     --thisClass->refCount;
276     delete contextIO;  // Req is part of the Contextio structure, no free release
277 }
278 
OnFileOpen(uv_fs_t * req)279 void HdcTransferBase::OnFileOpen(uv_fs_t *req)
280 {
281     CtxFile *context = (CtxFile *)req->data;
282     HdcTransferBase *thisClass = (HdcTransferBase *)context->thisClass;
283     StartTraceScope("HdcTransferBase::OnFileOpen");
284     uv_fs_req_cleanup(req);
285     WRITE_LOG(LOG_DEBUG, "Filemod openfile:%s channelId:%u result:%d",
286         context->localPath.c_str(), thisClass->taskInfo->channelId, context->fsOpenReq.result);
287     --thisClass->refCount;
288     if (req->result <= 0) {
289         constexpr int bufSize = 1024;
290         char buf[bufSize] = { 0 };
291         uv_strerror_r((int)req->result, buf, bufSize);
292         thisClass->LogMsg(MSG_FAIL, "Error opening file: %s, path:%s", buf,
293                           context->localPath.c_str());
294         WRITE_LOG(LOG_FATAL, "open path:%s error:%s", context->localPath.c_str(), buf);
295         if (context->isDir) {
296             uint8_t payload = 1;
297             thisClass->CommandDispatch(CMD_FILE_FINISH, &payload, 1);
298         } else {
299             thisClass->TaskFinish();
300         }
301         return;
302     }
303     thisClass->ResetCtx(context);
304     if (context->master) {
305         // init master
306         uv_fs_t fs = {};
307         uv_fs_fstat(nullptr, &fs, context->fsOpenReq.result, nullptr);
308         WRITE_LOG(LOG_DEBUG, "uv_fs_fstat result:%d fileSize:%llu",
309             context->fsOpenReq.result, fs.statbuf.st_size);
310         TransferConfig &st = context->transferConfig;
311         st.fileSize = fs.statbuf.st_size;
312         st.optionalName = context->localName;
313         if (st.holdTimestamp) {
314             st.atime = fs.statbuf.st_atim.tv_sec * HDC_TIME_CONVERT_BASE + fs.statbuf.st_atim.tv_nsec;
315             st.mtime = fs.statbuf.st_mtim.tv_sec * HDC_TIME_CONVERT_BASE + fs.statbuf.st_mtim.tv_nsec;
316         }
317         st.path = context->remotePath;
318         // update ctxNow=context child value
319         context->fileSize = st.fileSize;
320         context->fileMode.perm = fs.statbuf.st_mode;
321         context->fileMode.uId = fs.statbuf.st_uid;
322         context->fileMode.gId = fs.statbuf.st_gid;
323 
324 #if (!(defined(HOST_MINGW)||defined(HOST_MAC))) && defined(SURPPORT_SELINUX)
325         char *con = nullptr;
326         getfilecon(context->localPath.c_str(), &con);
327         if (con != nullptr) {
328             context->fileMode.context = con;
329             freecon(con);
330         }
331 #endif
332         uv_fs_req_cleanup(&fs);
333         thisClass->CheckMaster(context);
334     } else {  // write
335         if (context->fileModeSync) {
336             FileMode &mode = context->fileMode;
337             uv_fs_t fs = {};
338             uv_fs_chmod(nullptr, &fs, context->localPath.c_str(), mode.perm, nullptr);
339             uv_fs_chown(nullptr, &fs, context->localPath.c_str(), mode.uId, mode.gId, nullptr);
340             uv_fs_req_cleanup(&fs);
341 
342 #if (!(defined(HOST_MINGW)||defined(HOST_MAC))) && defined(SURPPORT_SELINUX)
343             if (!mode.context.empty()) {
344                 WRITE_LOG(LOG_DEBUG, "setfilecon from master = %s", mode.context.c_str());
345                 setfilecon(context->localPath.c_str(), mode.context.c_str());
346             }
347 #endif
348         }
349         thisClass->SendToAnother(thisClass->commandBegin, nullptr, 0);
350     }
351 }
352 
MatchPackageExtendName(string fileName,string extName)353 bool HdcTransferBase::MatchPackageExtendName(string fileName, string extName)
354 {
355     bool match = false;
356     int subfixIndex = fileName.rfind(extName);
357     if ((fileName.size() - subfixIndex) != extName.size()) {
358         return false;
359     }
360     match = true;
361     return match;
362 }
363 
364 // filter can be empty
GetSubFiles(const char * path,string filter,vector<string> * out)365 int HdcTransferBase::GetSubFiles(const char *path, string filter, vector<string> *out)
366 {
367     int retNum = 0;
368     uv_fs_t req = {};
369     uv_dirent_t dent;
370     vector<string> filterStrings;
371     if (!strlen(path)) {
372         return retNum;
373     }
374     if (filter.size()) {
375         Base::SplitString(filter, ";", filterStrings);
376     }
377 
378     if (uv_fs_scandir(nullptr, &req, path, 0, nullptr) < 0) {
379         uv_fs_req_cleanup(&req);
380         return retNum;
381     }
382     while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
383         // Skip. File
384         if (strcmp(dent.name, ".") == 0 || strcmp(dent.name, "..") == 0) {
385             continue;
386         }
387         if (!(static_cast<uint32_t>(dent.type) & UV_DIRENT_FILE)) {
388             continue;
389         }
390         string fileName = dent.name;
391         for (auto &&s : filterStrings) {
392             int subfixIndex = fileName.rfind(s);
393             if ((fileName.size() - subfixIndex) != s.size())
394                 continue;
395             string fullPath = string(path) + "/";
396             fullPath += fileName;
397             out->push_back(fullPath);
398             ++retNum;
399         }
400     }
401     uv_fs_req_cleanup(&req);
402     return retNum;
403 }
404 
405 
GetSubFilesRecursively(string path,string currentDirname,vector<string> * out)406 int HdcTransferBase::GetSubFilesRecursively(string path, string currentDirname, vector<string> *out)
407 {
408     int retNum = 0;
409     uv_fs_t req = {};
410     uv_dirent_t dent;
411 
412     WRITE_LOG(LOG_DEBUG, "GetSubFiles path = %s currentDirname = %s", path.c_str(), currentDirname.c_str());
413 
414     if (!path.size()) {
415         return retNum;
416     }
417 
418     if (uv_fs_scandir(nullptr, &req, path.c_str(), 0, nullptr) < 0) {
419         uv_fs_req_cleanup(&req);
420         return retNum;
421     }
422 
423     uv_fs_t fs = {};
424     int ret = uv_fs_stat(nullptr, &fs, path.c_str(), nullptr);
425     if (ret == 0) {
426         FileMode mode;
427         mode.fullName = currentDirname;
428         mode.perm = fs.statbuf.st_mode;
429         mode.uId = fs.statbuf.st_uid;
430         mode.gId = fs.statbuf.st_gid;
431 
432 #if (!(defined(HOST_MINGW)||defined(HOST_MAC))) && defined(SURPPORT_SELINUX)
433         char *con = nullptr;
434         getfilecon(path.c_str(), &con);
435         if (con != nullptr) {
436             mode.context = con;
437             freecon(con);
438         }
439 #endif
440         ctxNow.dirMode.push_back(mode);
441     }
442     while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
443         // Skip. File
444         if (strcmp(dent.name, ".") == 0 || strcmp(dent.name, "..") == 0) {
445             continue;
446         }
447         if (!(static_cast<uint32_t>(dent.type) & UV_DIRENT_FILE)) {
448             WRITE_LOG(LOG_DEBUG, "subdir dent.name fileName = %s", dent.name);
449             GetSubFilesRecursively(path + Base::GetPathSep() + dent.name,
450                 currentDirname + Base::GetPathSep() + dent.name, out);
451             continue;
452         }
453         string fileName = dent.name;
454         WRITE_LOG(LOG_DEBUG, "GetSubFiles fileName = %s", fileName.c_str());
455 
456         out->push_back(currentDirname + Base::GetPathSep() + fileName);
457     }
458     uv_fs_req_cleanup(&req);
459     return retNum;
460 }
461 
462 
CheckLocalPath(string & localPath,string & optName,string & errStr)463 bool HdcTransferBase::CheckLocalPath(string &localPath, string &optName, string &errStr)
464 {
465     // If optName show this is directory mode, check localPath and try create each layer
466     WRITE_LOG(LOG_DEBUG, "CheckDirectory localPath = %s optName = %s", localPath.c_str(), optName.c_str());
467     if ((optName.find('/') == string::npos) && (optName.find('\\') == string::npos)) {
468         WRITE_LOG(LOG_DEBUG, "Not directory mode optName = %s,  return", optName.c_str());
469         return true;
470     }
471     ctxNow.isDir = true;
472     uv_fs_t req;
473     int r = uv_fs_lstat(nullptr, &req, localPath.c_str(), nullptr);
474     mode_t mode = req.statbuf.st_mode;
475     uv_fs_req_cleanup(&req);
476 
477     if (r) {
478         vector<string> dirsOflocalPath;
479         string split(1, Base::GetPathSep());
480         Base::SplitString(localPath, split, dirsOflocalPath);
481 
482         WRITE_LOG(LOG_DEBUG, "localPath = %s dir layers = %zu", localPath.c_str(), dirsOflocalPath.size());
483         string makedirPath;
484 
485         if (!Base::IsAbsolutePath(localPath)) {
486             makedirPath = ".";
487         }
488 
489         for (auto dir : dirsOflocalPath) {
490             WRITE_LOG(LOG_DEBUG, "CheckLocalPath create dir = %s", dir.c_str());
491 
492             if (dir == ".") {
493                 continue;
494             } else {
495 #ifdef _WIN32
496                 if (dir.find(":") == 1) {
497                     makedirPath = dir;
498                     continue;
499                 }
500 #endif
501                 makedirPath = makedirPath + Base::GetPathSep() + dir;
502                 if (!Base::TryCreateDirectory(makedirPath, errStr)) {
503                     return false;
504                 }
505             }
506         }
507         // set flag to remove first layer directory of filename from master
508         ctxNow.targetDirNotExist = true;
509     } else if (!(mode & S_IFDIR)) {
510         WRITE_LOG(LOG_WARN, "Not a directory, path:%s", localPath.c_str());
511         errStr = "Not a directory, path:";
512         errStr += localPath.c_str();
513         return false;
514     }
515     return true;
516 }
517 
CheckFilename(string & localPath,string & optName,string & errStr)518 bool HdcTransferBase::CheckFilename(string &localPath, string &optName, string &errStr)
519 {
520     string localPathBackup = localPath;
521     if (ctxNow.targetDirNotExist) {
522         // If target directory not exist, the first layer directory from master should remove
523         if (optName.find('/') != string::npos) {
524             optName = optName.substr(optName.find('/') + 1);
525         } else if (optName.find('\\') != string::npos) {
526             optName = optName.substr(optName.find('\\') + 1);
527         }
528     }
529     vector<string> dirsOfOptName;
530 
531     if (optName.find('/') != string::npos) {
532         Base::SplitString(optName, "/", dirsOfOptName);
533     } else if (optName.find('\\') != string::npos) {
534         Base::SplitString(optName, "\\", dirsOfOptName);
535     } else {
536         WRITE_LOG(LOG_DEBUG, "No need create dir for file = %s", optName.c_str());
537         return true;
538     }
539 
540     // If filename still include dir, try create each layer
541     optName = dirsOfOptName.back();
542     dirsOfOptName.pop_back();
543 
544     for (auto s : dirsOfOptName) {
545         // Add each layer directory to localPath
546         localPath = localPath + Base::GetPathSep() + s;
547         if (!Base::TryCreateDirectory(localPath, errStr)) {
548             return false;
549         }
550         if (ctxNow.fileModeSync) {
551             string resolvedPath = Base::CanonicalizeSpecPath(localPath);
552             auto pos = resolvedPath.find(localPathBackup);
553             if (pos == 0) {
554                 string shortPath = resolvedPath.substr(localPathBackup.size());
555                 if (shortPath.at(0) == Base::GetPathSep()) {
556                     shortPath = shortPath.substr(1);
557                 }
558                 WRITE_LOG(LOG_DEBUG, "pos = %zu, shortPath = %s", pos, shortPath.c_str());
559 
560                 // set mode
561                 auto it = ctxNow.dirModeMap.find(shortPath);
562                 if (it != ctxNow.dirModeMap.end()) {
563                     auto mode = it->second;
564                     uv_fs_t fs = {};
565                     uv_fs_chmod(nullptr, &fs, localPath.c_str(), mode.perm, nullptr);
566                     uv_fs_chown(nullptr, &fs, localPath.c_str(), mode.uId, mode.gId, nullptr);
567                     uv_fs_req_cleanup(&fs);
568 #if (!(defined(HOST_MINGW) || defined(HOST_MAC))) && defined(SURPPORT_SELINUX)
569                     if (!mode.context.empty()) {
570                         WRITE_LOG(LOG_DEBUG, "setfilecon from master = %s", mode.context.c_str());
571                         setfilecon(localPath.c_str(), mode.context.c_str());
572                     }
573 #endif
574                 }
575             }
576         }
577     }
578 
579     WRITE_LOG(LOG_DEBUG, "CheckFilename finish localPath:%s optName:%s", localPath.c_str(), optName.c_str());
580     return true;
581 }
582 
583 // https://en.cppreference.com/w/cpp/filesystem/is_directory
584 // return true if file exist, false if file not exist
SmartSlavePath(string & cwd,string & localPath,const char * optName)585 bool HdcTransferBase::SmartSlavePath(string &cwd, string &localPath, const char *optName)
586 {
587     string errStr;
588     if (taskInfo->serverOrDaemon) {
589         // slave and server
590         ExtractRelativePath(cwd, localPath);
591     }
592     mode_t mode = mode_t(~S_IFMT);
593     if (Base::CheckDirectoryOrPath(localPath.c_str(), true, false, errStr, mode)) {
594         WRITE_LOG(LOG_DEBUG, "%s", errStr.c_str());
595         return true;
596     }
597 
598     uv_fs_t req;
599     int r = uv_fs_lstat(nullptr, &req, localPath.c_str(), nullptr);
600     uv_fs_req_cleanup(&req);
601     if (r == 0 && (req.statbuf.st_mode & S_IFDIR)) {  // is dir
602         localPath = Base::StringFormat("%s%c%s", localPath.c_str(), Base::GetPathSep(), optName);
603     }
604     return false;
605 }
606 
RecvIOPayload(CtxFile * context,uint8_t * data,int dataSize)607 bool HdcTransferBase::RecvIOPayload(CtxFile *context, uint8_t *data, int dataSize)
608 {
609     if (dataSize < static_cast<int>(payloadPrefixReserve)) {
610         WRITE_LOG(LOG_WARN, "unable to parse TransferPayload: invalid dataSize %d", dataSize);
611         return false;
612     }
613     uint8_t *clearBuf = nullptr;
614     string serialString(reinterpret_cast<char *>(data), payloadPrefixReserve);
615     TransferPayload pld;
616     Base::ZeroStruct(pld);
617     bool ret = false;
618     SerialStruct::ParseFromString(pld, serialString);
619     int clearSize = 0;
620     StartTraceScope("HdcTransferBase::RecvIOPayload");
621     if (pld.compressSize > 0) {
622         switch (pld.compressType) {
623 #ifdef HARMONY_PROJECT
624             case COMPRESS_LZ4: {
625                 clearBuf = new uint8_t[pld.uncompressSize]();
626                 if (!clearBuf) {
627                     WRITE_LOG(LOG_FATAL, "alloc LZ4 buffer failed");
628                     return false;
629                 }
630                 clearSize = LZ4_decompress_safe((const char *)data + payloadPrefixReserve, (char *)clearBuf,
631                                                 pld.compressSize, pld.uncompressSize);
632                 break;
633             }
634 #endif
635             default: {  // COMPRESS_NONE
636                 clearBuf = data + payloadPrefixReserve;
637                 clearSize = pld.compressSize;
638                 break;
639             }
640         }
641     }
642     while (true) {
643         if (static_cast<uint32_t>(clearSize) != pld.uncompressSize || dataSize - payloadPrefixReserve < clearSize) {
644             WRITE_LOG(LOG_WARN, "invalid data size for fileIO: %d", clearSize);
645             break;
646         }
647         if (SimpleFileIO(context, pld.index, clearBuf, clearSize) < 0) {
648             break;
649         }
650         ret = true;
651         break;
652     }
653     if (pld.compressSize > 0 && pld.compressType != COMPRESS_NONE) {
654         delete[] clearBuf;
655     }
656     return ret;
657 }
658 
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)659 bool HdcTransferBase::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
660 {
661     StartTraceScope("HdcTransferBase::CommandDispatch");
662     bool ret = true;
663     while (true) {
664         if (command == commandBegin) {
665             CtxFile *context = &ctxNow;
666             int ioRet = SimpleFileIO(context, context->indexIO, nullptr, Base::GetMaxBufSize() * maxTransferBufFactor);
667             if (ioRet < 0) {
668                 WRITE_LOG(LOG_FATAL, "CommandDispatch SimpleFileIO ioRet:%d", ioRet);
669                 ret = false;
670                 break;
671             }
672             context->transferBegin = Base::GetRuntimeMSec();
673         } else if (command == commandData) {
674             if (static_cast<uint32_t>(payloadSize) > HDC_BUF_MAX_BYTES || payloadSize < 0) {
675                 WRITE_LOG(LOG_FATAL, "CommandDispatch payloadSize:%d", payloadSize);
676                 ret = false;
677                 break;
678             }
679             // Note, I will trigger FileIO after multiple times.
680             CtxFile *context = &ctxNow;
681             if (!RecvIOPayload(context, payload, payloadSize)) {
682                 WRITE_LOG(LOG_FATAL, "CommandDispatch RecvIOPayload command:%u", command);
683                 ret = false;
684                 break;
685             }
686         } else {
687             // Other subclass commands
688         }
689         break;
690     }
691     return ret;
692 }
693 
ExtractRelativePath(string & cwd,string & path)694 void HdcTransferBase::ExtractRelativePath(string &cwd, string &path)
695 {
696     bool absPath = Base::IsAbsolutePath(path);
697     if (!absPath) {
698         path = cwd + path;
699     }
700 }
701 }  // namespace Hdc
702