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