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