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