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