1cc290419Sopenharmony_ci/*
2cc290419Sopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd.
3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License.
5cc290419Sopenharmony_ci * You may obtain a copy of the License at
6cc290419Sopenharmony_ci *
7cc290419Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8cc290419Sopenharmony_ci *
9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and
13cc290419Sopenharmony_ci * limitations under the License.
14cc290419Sopenharmony_ci */
15cc290419Sopenharmony_ci#include "host_app.h"
16cc290419Sopenharmony_ci#include "compress.h"
17cc290419Sopenharmony_ci
18cc290419Sopenharmony_cinamespace Hdc {
19cc290419Sopenharmony_ciHdcHostApp::HdcHostApp(HTaskInfo hTaskInfo)
20cc290419Sopenharmony_ci    : HdcTransferBase(hTaskInfo)
21cc290419Sopenharmony_ci{
22cc290419Sopenharmony_ci    commandBegin = CMD_APP_BEGIN;
23cc290419Sopenharmony_ci    commandData = CMD_APP_DATA;
24cc290419Sopenharmony_ci    originLocalDir = "";
25cc290419Sopenharmony_ci    isStableBuf = hTaskInfo->isStableBuf;
26cc290419Sopenharmony_ci}
27cc290419Sopenharmony_ci
28cc290419Sopenharmony_ciHdcHostApp::~HdcHostApp()
29cc290419Sopenharmony_ci{
30cc290419Sopenharmony_ci}
31cc290419Sopenharmony_ci
32cc290419Sopenharmony_cistring HdcHostApp::Dir2Tar(const char *dir)
33cc290419Sopenharmony_ci{
34cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "dir:%s", dir);
35cc290419Sopenharmony_ci    string tarpath;
36cc290419Sopenharmony_ci    uv_fs_t req;
37cc290419Sopenharmony_ci    int r = uv_fs_lstat(nullptr, &req, dir, nullptr);
38cc290419Sopenharmony_ci    uv_fs_req_cleanup(&req);
39cc290419Sopenharmony_ci    if (r == 0 && (req.statbuf.st_mode & S_IFDIR)) {  // is dir
40cc290419Sopenharmony_ci        string sdir = dir;
41cc290419Sopenharmony_ci        string tarname = Base::GetRandomString(EXPECTED_LEN) + ".tar";
42cc290419Sopenharmony_ci        tarpath = Base::GetTmpDir() + tarname;
43cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "tarpath:%s", tarpath.c_str());
44cc290419Sopenharmony_ci        Compress c;
45cc290419Sopenharmony_ci        c.UpdataPrefix(sdir);
46cc290419Sopenharmony_ci        c.AddPath(sdir);
47cc290419Sopenharmony_ci        c.SaveToFile(tarpath);
48cc290419Sopenharmony_ci    }
49cc290419Sopenharmony_ci    return tarpath;
50cc290419Sopenharmony_ci}
51cc290419Sopenharmony_ci
52cc290419Sopenharmony_cibool HdcHostApp::BeginInstall(CtxFile *context, const char *command)
53cc290419Sopenharmony_ci{
54cc290419Sopenharmony_ci    int argc = 0;
55cc290419Sopenharmony_ci    bool ret = false;
56cc290419Sopenharmony_ci    string options;
57cc290419Sopenharmony_ci    char **argv = Base::SplitCommandToArgs(command, &argc);
58cc290419Sopenharmony_ci    if (argc < 1) {
59cc290419Sopenharmony_ci        goto Finish;
60cc290419Sopenharmony_ci    }
61cc290419Sopenharmony_ci
62cc290419Sopenharmony_ci    for (int i = 0; i < argc; ++i) {
63cc290419Sopenharmony_ci        if (!strcmp(argv[i], CMD_OPTION_CLIENTCWD.c_str())) {
64cc290419Sopenharmony_ci            if (i + 1 < argc) {
65cc290419Sopenharmony_ci                context->transferConfig.clientCwd = argv[i + 1];
66cc290419Sopenharmony_ci                i += 1;  // add content index
67cc290419Sopenharmony_ci            }
68cc290419Sopenharmony_ci        } else if (!strncmp(argv[i], "-", 1)) {
69cc290419Sopenharmony_ci            if (options.size()) {
70cc290419Sopenharmony_ci                options += " ";
71cc290419Sopenharmony_ci            }
72cc290419Sopenharmony_ci            options += argv[i];
73cc290419Sopenharmony_ci        } else {
74cc290419Sopenharmony_ci            string path = argv[i];
75cc290419Sopenharmony_ci            ExtractRelativePath(context->transferConfig.clientCwd, path);
76cc290419Sopenharmony_ci            if (MatchPackageExtendName(path, ".hap") || MatchPackageExtendName(path, ".hsp")) {
77cc290419Sopenharmony_ci                context->taskQueue.push_back(path);
78cc290419Sopenharmony_ci            } else {
79cc290419Sopenharmony_ci                string tarpath = Dir2Tar(path.c_str());
80cc290419Sopenharmony_ci                if (!tarpath.empty()) {
81cc290419Sopenharmony_ci                    context->taskQueue.push_back(tarpath);
82cc290419Sopenharmony_ci                    originLocalDir = path;
83cc290419Sopenharmony_ci                }
84cc290419Sopenharmony_ci            }
85cc290419Sopenharmony_ci        }
86cc290419Sopenharmony_ci    }
87cc290419Sopenharmony_ci    if (!context->taskQueue.size()) {
88cc290419Sopenharmony_ci        LogMsg(MSG_FAIL, "Not any installation package was found");
89cc290419Sopenharmony_ci        goto Finish;
90cc290419Sopenharmony_ci    }
91cc290419Sopenharmony_ci    // remove repeate
92cc290419Sopenharmony_ci    sort(context->taskQueue.begin(), context->taskQueue.end());
93cc290419Sopenharmony_ci    context->taskQueue.erase(unique(context->taskQueue.begin(), context->taskQueue.end()), context->taskQueue.end());
94cc290419Sopenharmony_ci
95cc290419Sopenharmony_ci    context->transferConfig.options = options;
96cc290419Sopenharmony_ci    context->transferConfig.functionName = CMDSTR_APP_INSTALL;
97cc290419Sopenharmony_ci    ret = RunQueue(context);
98cc290419Sopenharmony_ciFinish:
99cc290419Sopenharmony_ci    if (argv) {
100cc290419Sopenharmony_ci        delete[](reinterpret_cast<char *>(argv));
101cc290419Sopenharmony_ci    }
102cc290419Sopenharmony_ci    return ret;
103cc290419Sopenharmony_ci}
104cc290419Sopenharmony_ci
105cc290419Sopenharmony_cibool HdcHostApp::BeginSideload(CtxFile *context, const char *localPath)
106cc290419Sopenharmony_ci{
107cc290419Sopenharmony_ci    bool ret = false;
108cc290419Sopenharmony_ci    context->transferConfig.functionName = CMDSTR_APP_SIDELOAD;
109cc290419Sopenharmony_ci    context->taskQueue.push_back(localPath);
110cc290419Sopenharmony_ci    ret = RunQueue(context);
111cc290419Sopenharmony_ci    return ret;
112cc290419Sopenharmony_ci}
113cc290419Sopenharmony_ci
114cc290419Sopenharmony_cibool HdcHostApp::RunQueue(CtxFile *context)
115cc290419Sopenharmony_ci{
116cc290419Sopenharmony_ci    context->localPath = context->taskQueue.back();
117cc290419Sopenharmony_ci    uv_fs_t *openReq = new uv_fs_t;
118cc290419Sopenharmony_ci    if (openReq == nullptr) {
119cc290419Sopenharmony_ci        LogMsg(MSG_FAIL, "HdcHostApp::RunQueue new uv_fs_t failed");
120cc290419Sopenharmony_ci        OnFileOpenFailed(context);
121cc290419Sopenharmony_ci        return false;
122cc290419Sopenharmony_ci    }
123cc290419Sopenharmony_ci    memset_s(openReq, sizeof(uv_fs_t), 0, sizeof(uv_fs_t));
124cc290419Sopenharmony_ci    openReq->data = context;
125cc290419Sopenharmony_ci    ++refCount;
126cc290419Sopenharmony_ci    uv_fs_open(loopTask, openReq, context->localPath.c_str(), O_RDONLY, 0, OnFileOpen);
127cc290419Sopenharmony_ci    context->master = true;
128cc290419Sopenharmony_ci    return true;
129cc290419Sopenharmony_ci}
130cc290419Sopenharmony_ci
131cc290419Sopenharmony_civoid HdcHostApp::CheckMaster(CtxFile *context)
132cc290419Sopenharmony_ci{
133cc290419Sopenharmony_ci    uv_fs_t fs = {};
134cc290419Sopenharmony_ci    uv_fs_fstat(nullptr, &fs, context->openFd, nullptr);
135cc290419Sopenharmony_ci    context->transferConfig.fileSize = fs.statbuf.st_size;
136cc290419Sopenharmony_ci    uv_fs_req_cleanup(&fs);
137cc290419Sopenharmony_ci
138cc290419Sopenharmony_ci    context->transferConfig.optionalName
139cc290419Sopenharmony_ci        = Base::GetRandomString(EXPECTED_LEN);  // Prevent the name of illegal APP leads to pm unable to install
140cc290419Sopenharmony_ci    if (context->localPath.find(".hap") != static_cast<size_t>(-1)) {
141cc290419Sopenharmony_ci        context->transferConfig.optionalName += ".hap";
142cc290419Sopenharmony_ci    } else if (context->localPath.find(".hsp") != static_cast<size_t>(-1)) {
143cc290419Sopenharmony_ci        context->transferConfig.optionalName += ".hsp";
144cc290419Sopenharmony_ci    } else if (context->localPath.find(".tar") != static_cast<size_t>(-1)) {
145cc290419Sopenharmony_ci        context->transferConfig.optionalName += ".tar";
146cc290419Sopenharmony_ci    } else {
147cc290419Sopenharmony_ci        context->transferConfig.optionalName += ".bundle";
148cc290419Sopenharmony_ci    }
149cc290419Sopenharmony_ci    string bufString = SerialStruct::SerializeToString(context->transferConfig);
150cc290419Sopenharmony_ci    SendToAnother(CMD_APP_CHECK, const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(bufString.c_str())),
151cc290419Sopenharmony_ci                  bufString.size());
152cc290419Sopenharmony_ci}
153cc290419Sopenharmony_ci
154cc290419Sopenharmony_cibool HdcHostApp::CheckInstallContinue(AppModType mode, bool lastResult, const char *msg)
155cc290419Sopenharmony_ci{
156cc290419Sopenharmony_ci    string modeDesc;
157cc290419Sopenharmony_ci    switch (mode) {
158cc290419Sopenharmony_ci        case APPMOD_INSTALL:
159cc290419Sopenharmony_ci            modeDesc = "App install";
160cc290419Sopenharmony_ci            break;
161cc290419Sopenharmony_ci        case APPMOD_UNINSTALL:
162cc290419Sopenharmony_ci            modeDesc = "App uninstall";
163cc290419Sopenharmony_ci            break;
164cc290419Sopenharmony_ci        case APPMOD_SIDELOAD:
165cc290419Sopenharmony_ci            modeDesc = "Side load";
166cc290419Sopenharmony_ci            break;
167cc290419Sopenharmony_ci        default:
168cc290419Sopenharmony_ci            modeDesc = "Unknown";
169cc290419Sopenharmony_ci            break;
170cc290419Sopenharmony_ci    }
171cc290419Sopenharmony_ci    if (ctxNow.taskQueue.size() > 0) {
172cc290419Sopenharmony_ci        string path = ctxNow.taskQueue.back();
173cc290419Sopenharmony_ci        ctxNow.taskQueue.pop_back();
174cc290419Sopenharmony_ci        string::size_type pos = path.rfind(".tar");
175cc290419Sopenharmony_ci        if (mode == APPMOD_INSTALL && pos != string::npos) {
176cc290419Sopenharmony_ci            unlink(path.c_str());
177cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "unlink path:%s", path.c_str());
178cc290419Sopenharmony_ci        }
179cc290419Sopenharmony_ci    }
180cc290419Sopenharmony_ci    string path = ctxNow.localPath;
181cc290419Sopenharmony_ci    if (!originLocalDir.empty()) {
182cc290419Sopenharmony_ci        path = originLocalDir;
183cc290419Sopenharmony_ci    }
184cc290419Sopenharmony_ci    LogMsg(MSG_INFO, "%s path:%s msg:%s", modeDesc.c_str(), path.c_str(), msg + printedMsgLen);
185cc290419Sopenharmony_ci    printedMsgLen = strlen(msg);
186cc290419Sopenharmony_ci    if (singalStop || !ctxNow.taskQueue.size()) {
187cc290419Sopenharmony_ci        LogMsg(MSG_OK, "AppMod finish");
188cc290419Sopenharmony_ci        return false;
189cc290419Sopenharmony_ci    }
190cc290419Sopenharmony_ci    return RunQueue(&ctxNow);
191cc290419Sopenharmony_ci}
192cc290419Sopenharmony_ci
193cc290419Sopenharmony_cibool HdcHostApp::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
194cc290419Sopenharmony_ci{
195cc290419Sopenharmony_ci    if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) {
196cc290419Sopenharmony_ci        return false;
197cc290419Sopenharmony_ci    }
198cc290419Sopenharmony_ci    bool ret = true;
199cc290419Sopenharmony_ci    constexpr int cmdOffset = 2;
200cc290419Sopenharmony_ci    switch (command) {
201cc290419Sopenharmony_ci        case CMD_APP_INIT: {
202cc290419Sopenharmony_ci            ret = BeginInstall(&ctxNow, (const char *)payload);
203cc290419Sopenharmony_ci            break;
204cc290419Sopenharmony_ci        }
205cc290419Sopenharmony_ci        case CMD_APP_FINISH: {
206cc290419Sopenharmony_ci            AppModType mode = static_cast<AppModType>(payload[0]);
207cc290419Sopenharmony_ci            bool result = static_cast<bool>(payload[1]);
208cc290419Sopenharmony_ci            string s(reinterpret_cast<char *>(payload + cmdOffset), payloadSize - cmdOffset);
209cc290419Sopenharmony_ci            ret = CheckInstallContinue(mode, result, s.c_str());
210cc290419Sopenharmony_ci            break;
211cc290419Sopenharmony_ci        }
212cc290419Sopenharmony_ci        case CMD_APP_UNINSTALL: {
213cc290419Sopenharmony_ci            SendToAnother(CMD_APP_UNINSTALL, payload, payloadSize);
214cc290419Sopenharmony_ci            ctxNow.taskQueue.push_back(reinterpret_cast<char *>(payload));  // just compatible
215cc290419Sopenharmony_ci            break;
216cc290419Sopenharmony_ci        }
217cc290419Sopenharmony_ci        case CMD_APP_SIDELOAD: {
218cc290419Sopenharmony_ci            BeginSideload(&ctxNow, (const char *)payload);
219cc290419Sopenharmony_ci            break;
220cc290419Sopenharmony_ci        }
221cc290419Sopenharmony_ci        default:
222cc290419Sopenharmony_ci            break;
223cc290419Sopenharmony_ci    }
224cc290419Sopenharmony_ci    return ret;
225cc290419Sopenharmony_ci};
226cc290419Sopenharmony_ci}
227