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