• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "file.h"
16 #include "serial_struct.h"
17 
18 namespace Hdc {
HdcFile(HTaskInfo hTaskInfo)19 HdcFile::HdcFile(HTaskInfo hTaskInfo)
20     : HdcTransferBase(hTaskInfo)
21 {
22     commandBegin = CMD_FILE_BEGIN;
23     commandData = CMD_FILE_DATA;
24 }
25 
~HdcFile()26 HdcFile::~HdcFile()
27 {
28     WRITE_LOG(LOG_DEBUG, "~HdcFile");
29 };
30 
StopTask()31 void HdcFile::StopTask()
32 {
33     WRITE_LOG(LOG_DEBUG, "HdcFile StopTask");
34     singalStop = true;
35 };
36 
BeginTransfer(CtxFile * context,const string & command)37 bool HdcFile::BeginTransfer(CtxFile *context, const string &command)
38 {
39     int argc = 0;
40     bool ret = false;
41     char **argv = Base::SplitCommandToArgs(command.c_str(), &argc);
42     if (argc < CMD_ARG1_COUNT || argv == nullptr) {
43         LogMsg(MSG_FAIL, "Transfer path split failed");
44         if (argv) {
45             delete[]((char *)argv);
46         }
47         return false;
48     }
49     if (!SetMasterParameters(context, command.c_str(), argc, argv)) {
50         delete[]((char *)argv);
51         return false;
52     }
53     do {
54         ++refCount;
55         uv_fs_open(loopTask, &context->fsOpenReq, context->localPath.c_str(), O_RDONLY, S_IWUSR | S_IRUSR, OnFileOpen);
56         context->master = true;
57         ret = true;
58     } while (false);
59     if (!ret) {
60         LogMsg(MSG_FAIL, "Transfer path failed, Master:%s Slave:%s", context->localPath.c_str(),
61                context->remotePath.c_str());
62     }
63     delete[]((char *)argv);
64     return ret;
65 }
66 
SetMasterParameters(CtxFile * context,const char * command,int argc,char ** argv)67 bool HdcFile::SetMasterParameters(CtxFile *context, const char *command, int argc, char **argv)
68 {
69     int srcArgvIndex = 0;
70     string errStr;
71     const string CMD_OPTION_TSTMP = "-a";
72     const string CMD_OPTION_SYNC = "-sync";
73     const string CMD_OPTION_ZIP = "-z";
74 
75     for (int i = 0; i < argc - CMD_ARG1_COUNT; i++) {
76         if (argv[i] == CMD_OPTION_ZIP) {
77             context->transferConfig.compressType = COMPRESS_LZ4;
78             ++srcArgvIndex;
79         } else if (argv[i] == CMD_OPTION_SYNC) {
80             context->transferConfig.updateIfNew = true;
81             ++srcArgvIndex;
82         } else if (argv[i] == CMD_OPTION_TSTMP) {
83             // The time zone difference may cause the display time on the PC and the
84             // device to differ by several hours
85             //
86             // ls -al --full-time
87             context->transferConfig.holdTimestamp = true;
88             ++srcArgvIndex;
89         } else if (argv[i] == CMD_OPTION_CLIENTCWD) {
90             context->transferConfig.clientCwd = argv[i + 1];
91             srcArgvIndex += CMD_ARG1_COUNT;  // skip 2args
92         } else if (argv[i][0] == '-') {
93             LogMsg(MSG_FAIL, "Unknow file option: %s", argv[i]);
94             return false;
95         }
96     }
97     context->remotePath = argv[argc - 1];
98     context->localPath = argv[argc - 2];
99     if (taskInfo->serverOrDaemon) {
100         // master and server
101         ExtractRelativePath(context->transferConfig.clientCwd, context->localPath);
102     }
103     if (!Base::CheckDirectoryOrPath(context->localPath.c_str(), true, true, errStr)) {
104         LogMsg(MSG_FAIL, "%s", errStr.c_str());
105         return false;
106     }
107     context->localName = Base::GetFullFilePath(context->localPath);
108     return true;
109 }
110 
CheckMaster(CtxFile * context)111 void HdcFile::CheckMaster(CtxFile *context)
112 {
113     string s = SerialStruct::SerializeToString(context->transferConfig);
114     SendToAnother(CMD_FILE_CHECK, (uint8_t *)s.c_str(), s.size());
115 }
116 
WhenTransferFinish(CtxFile * context)117 void HdcFile::WhenTransferFinish(CtxFile *context)
118 {
119     WRITE_LOG(LOG_DEBUG, "HdcTransferBase OnFileClose");
120     uint8_t flag = 1;
121     SendToAnother(CMD_FILE_FINISH, &flag, 1);
122 }
123 
TransferSummary(CtxFile * context)124 void HdcFile::TransferSummary(CtxFile *context)
125 {
126     uint64_t nMSec = Base::GetRuntimeMSec() - context->transferBegin;
127     double fRate = static_cast<double>(context->indexIO) / nMSec;  // / /1000 * 1000 = 0
128     if (context->indexIO >= context->fileSize) {
129         LogMsg(MSG_OK, "FileTransfer finish, Size:%lld time:%lldms rate:%.2lfkB/s", context->indexIO, nMSec, fRate);
130     } else {
131         constexpr int bufSize = 1024;
132         char buf[bufSize] = { 0 };
133         uv_strerror_r((int)(-context->lastErrno), buf, bufSize);
134         LogMsg(MSG_FAIL, "Transfer Stop at:%lld/%lld(Bytes), Reason: %s", context->indexIO, context->fileSize,
135                buf);
136     }
137 }
138 
SlaveCheck(uint8_t * payload,const int payloadSize)139 bool HdcFile::SlaveCheck(uint8_t *payload, const int payloadSize)
140 {
141     bool ret = true;
142     bool childRet = false;
143     // parse option
144     string serialStrring((char *)payload, payloadSize);
145     TransferConfig &stat = ctxNow.transferConfig;
146     SerialStruct::ParseFromString(stat, serialStrring);
147     ctxNow.fileSize = stat.fileSize;
148     ctxNow.localPath = stat.path;
149     ctxNow.master = false;
150     ctxNow.fsOpenReq.data = &ctxNow;
151 #ifdef HDC_DEBUG
152     WRITE_LOG(LOG_DEBUG, "HdcFile fileSize got %" PRIu64 "", ctxNow.fileSize);
153 #endif
154     // check path
155     childRet = SmartSlavePath(stat.clientCwd, ctxNow.localPath, stat.optionalName.c_str());
156     if (childRet && ctxNow.transferConfig.updateIfNew) {  // file exist and option need update
157         // if is newer
158         uv_fs_t fs = {};
159         uv_fs_stat(nullptr, &fs, ctxNow.localPath.c_str(), nullptr);
160         uv_fs_req_cleanup(&fs);
161         if ((uint64_t)fs.statbuf.st_mtim.tv_sec >= ctxNow.transferConfig.mtime) {
162             LogMsg(MSG_FAIL, "Target file is the same date or newer,path: %s", ctxNow.localPath.c_str());
163             return false;
164         }
165     }
166     // begin work
167     ++refCount;
168     uv_fs_open(loopTask, &ctxNow.fsOpenReq, ctxNow.localPath.c_str(), UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY,
169                S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, OnFileOpen);
170     ctxNow.transferBegin = Base::GetRuntimeMSec();
171     return ret;
172 }
173 
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)174 bool HdcFile::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
175 {
176     HdcTransferBase::CommandDispatch(command, payload, payloadSize);
177     bool ret = true;
178     switch (command) {
179         case CMD_FILE_INIT: {  // initial
180             string s = string((char *)payload, payloadSize);
181             ret = BeginTransfer(&ctxNow, s);
182             ctxNow.transferBegin = Base::GetRuntimeMSec();
183             break;
184         }
185         case CMD_FILE_CHECK: {
186             ret = SlaveCheck(payload, payloadSize);
187             break;
188         }
189         case CMD_FILE_FINISH: {
190             if (*payload) {  // close-step3
191                 ctxNow.ioFinish = true;
192                 --(*payload);
193                 SendToAnother(CMD_FILE_FINISH, payload, 1);
194             } else {  // close-step3
195                 TransferSummary(&ctxNow);
196                 TaskFinish();
197             }
198             break;
199         }
200         default:
201             break;
202     }
203     return ret;
204 }
205 }  // namespace Hdc
206