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