xref: /ide/tools/previewer/test/mock/MockFile.cpp (revision 7c804472)
1/*
2 * Copyright (c) 2024 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
16#include "MockFile.h"
17#include <filesystem>
18#include <cstdio>
19#include <iostream>
20#include <fstream>
21#include <fcntl.h>
22#include <unistd.h>
23#include <sys/file.h>
24#include "zlib.h"
25#include "contrib/minizip/zip.h"
26using namespace testmock;
27namespace fs = std::filesystem;
28
29bool MockFile::SimulateFileLock(const std::string& filePath)
30{
31    int fd = open(filePath.c_str(), O_RDWR | O_CREAT);
32    if (fd == -1) {
33        // Handle error
34        return false;
35    }
36
37    // Attempt to acquire an exclusive lock
38    struct flock fl;
39    fl.l_type = F_WRLCK;    // Exclusive write lock
40    fl.l_whence = SEEK_SET; // Starting from beginning of file
41    fl.l_start = 0;         // Starting from offset 0
42    fl.l_len = 0;           // Lock whole file
43    fl.l_pid = getpid();    // PID of process holding the lock
44
45    if (fcntl(fd, F_SETLK, &fl) == -1) {
46        // Lock failed (file is already locked)
47        close(fd);
48        return true; // Simulate that file is locked
49    }
50
51    // Lock acquired, simulate that file is not locked
52    close(fd);
53    return false;
54}
55
56bool MockFile::ReleaseFileLock(const std::string& filePath)
57{
58    int fd = open(filePath.c_str(), O_RDWR | O_CREAT);
59    if (fd == -1) {
60        // Handle error
61        return false;
62    }
63
64    struct flock fl;
65    fl.l_type = F_UNLCK;    // Unlock the file
66    fl.l_whence = SEEK_SET; // Starting from beginning of file
67    fl.l_start = 0;         // Starting from offset 0
68    fl.l_len = 0;           // Unlock whole file
69
70    if (fcntl(fd, F_SETLK, &fl) == -1) {
71        // Failed to unlock
72        close(fd);
73        return false;
74    }
75
76    // Successfully unlocked
77    close(fd);
78    return true;
79}
80
81// Function to add a file to zip
82bool MockFile::AddFileToZip(zipFile zip, const std::string& filePath, const std::string& entryName)
83{
84    if (zipOpenNewFileInZip(zip, entryName.c_str(), NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,
85        Z_DEFAULT_COMPRESSION) != ZIP_OK) {
86        std::cerr << "Failed to create entry in zip file for " << filePath << std::endl;
87        return false;
88    }
89
90    FILE* file = fopen(filePath.c_str(), "rb");
91    if (!file) {
92        std::cerr << "Failed to open file " << filePath << std::endl;
93        zipCloseFileInZip(zip);
94        return false;
95    }
96
97    const int bufferSize = 1024;
98    void* buffer = malloc(bufferSize);
99    int size;
100    while ((size = fread(buffer, 1, bufferSize, file)) > 0) {
101        if (zipWriteInFileInZip(zip, buffer, size) < 0) {
102            std::cerr << "Failed to write to zip for " << filePath << std::endl;
103            free(buffer);
104            if (fclose(file) == EOF) {
105                std::cerr << "Failed to close file" << std::endl;
106                return false;
107            }
108            zipCloseFileInZip(zip);
109            return false;
110        }
111    }
112
113    free(buffer);
114    if (fclose(file) == EOF) {
115        std::cerr << "Failed to close file" << std::endl;
116        return false;
117    }
118    zipCloseFileInZip(zip);
119
120    return true;
121}
122
123// Function to add a folder and its contents recursively to zip
124bool MockFile::AddFolderToZip(zipFile zip, const std::string& folderPath, const std::string& entryName)
125{
126    for (const auto& entry : fs::recursive_directory_iterator(folderPath)) {
127        std::string relativePath = entry.path().string().substr(folderPath.length() + 1); // Relative path
128
129        if (fs::is_directory(entry)) {
130            // Create directory entry
131            if (zipOpenNewFileInZip(zip, (entryName + "/" + relativePath + "/").c_str(), NULL, NULL, 0,
132                NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != ZIP_OK) {
133                std::cerr << "Failed to create entry in zip file for " << entry.path() << std::endl;
134                return false;
135            }
136            zipCloseFileInZip(zip);
137        } else {
138            // Add file
139            if (!AddFileToZip(zip, entry.path().string(), entryName + "/" + relativePath)) {
140                return false;
141            }
142        }
143    }
144
145    return true;
146}
147
148// Main compression function
149bool MockFile::CompressFiles(const std::vector<std::string>& files, const std::string& zipFilename)
150{
151    zipFile zip = zipOpen(zipFilename.c_str(), APPEND_STATUS_CREATE);
152    if (!zip) {
153        std::cerr << "Could not create zip file " << zipFilename << std::endl;
154        return false;
155    }
156
157    for (const auto& file : files) {
158        if (fs::is_directory(file)) {
159            // Add directory and its contents
160            if (!AddFolderToZip(zip, file, fs::path(file).filename())) {
161                zipClose(zip, NULL);
162                return false;
163            }
164        } else {
165            // Add individual file
166            if (!AddFileToZip(zip, file, fs::path(file).filename())) {
167                zipClose(zip, NULL);
168                return false;
169            }
170        }
171    }
172
173    if (zipClose(zip, NULL) != ZIP_OK) {
174        std::cerr << "Failed to close zip file " << zipFilename << std::endl;
175        return false;
176    }
177
178    return true;
179}
180
181namespace {
182// 将内容写入 module.json 文件
183void WriteToFile(const std::string& filePath, const std::string& content)
184{
185    std::ofstream file(filePath);
186    if (!file) {
187        std::cerr << "Error creating file: " << filePath << std::endl;
188        return;
189    }
190    file << content;
191    file.close();
192}
193
194void CreateFiles(const std::string hspAbcContent)
195{
196    std::filesystem::path dir("ets");
197
198    // 检查文件夹是否存在
199    if (std::filesystem::exists(dir)) {
200        std::cout << "Folder already exists." << std::endl;
201    } else {
202        // 创建文件夹
203        std::filesystem::create_directory(dir);
204        std::cout << "Folder created successfully." << std::endl;
205    }
206    // 生成hsp文件
207    // 在ets下写入文件modules.abc
208    WriteToFile("ets/modules.abc", hspAbcContent);
209    // 在当前目录下写入文件module.json
210    WriteToFile("module.json", hspAbcContent);
211}
212}
213
214std::string MockFile::CreateHspFile(const std::string hspFileName, const std::string hspAbcContent)
215{
216    CreateFiles(hspAbcContent);
217    std::vector<std::string> filesToCompress = { "ets", "module.json" };
218    std::string zipFilename = hspFileName + ".zip";
219    std::string newFileName = hspFileName + ".hsp";
220    if (CompressFiles(filesToCompress, zipFilename)) {
221        std::cout << "Compression successful. File created: " << zipFilename << std::endl;
222        if (std::rename(zipFilename.c_str(), newFileName.c_str()) != 0) {
223            std::cout << newFileName << " 创建hsp文件失败" << std::endl;
224            return "";
225        }
226    } else {
227        std::cerr << "Compression failed." << std::endl;
228        return "";
229    }
230    return newFileName;
231}
232