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