17c804472Sopenharmony_ci/*
27c804472Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
37c804472Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
47c804472Sopenharmony_ci * you may not use this file except in compliance with the License.
57c804472Sopenharmony_ci * You may obtain a copy of the License at
67c804472Sopenharmony_ci *
77c804472Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
87c804472Sopenharmony_ci *
97c804472Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
107c804472Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
117c804472Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
127c804472Sopenharmony_ci * See the License for the specific language governing permissions and
137c804472Sopenharmony_ci * limitations under the License.
147c804472Sopenharmony_ci */
157c804472Sopenharmony_ci
167c804472Sopenharmony_ci#include "MockFile.h"
177c804472Sopenharmony_ci#include <filesystem>
187c804472Sopenharmony_ci#include <cstdio>
197c804472Sopenharmony_ci#include <iostream>
207c804472Sopenharmony_ci#include <fstream>
217c804472Sopenharmony_ci#include <fcntl.h>
227c804472Sopenharmony_ci#include <unistd.h>
237c804472Sopenharmony_ci#include <sys/file.h>
247c804472Sopenharmony_ci#include "zlib.h"
257c804472Sopenharmony_ci#include "contrib/minizip/zip.h"
267c804472Sopenharmony_ciusing namespace testmock;
277c804472Sopenharmony_cinamespace fs = std::filesystem;
287c804472Sopenharmony_ci
297c804472Sopenharmony_cibool MockFile::SimulateFileLock(const std::string& filePath)
307c804472Sopenharmony_ci{
317c804472Sopenharmony_ci    int fd = open(filePath.c_str(), O_RDWR | O_CREAT);
327c804472Sopenharmony_ci    if (fd == -1) {
337c804472Sopenharmony_ci        // Handle error
347c804472Sopenharmony_ci        return false;
357c804472Sopenharmony_ci    }
367c804472Sopenharmony_ci
377c804472Sopenharmony_ci    // Attempt to acquire an exclusive lock
387c804472Sopenharmony_ci    struct flock fl;
397c804472Sopenharmony_ci    fl.l_type = F_WRLCK;    // Exclusive write lock
407c804472Sopenharmony_ci    fl.l_whence = SEEK_SET; // Starting from beginning of file
417c804472Sopenharmony_ci    fl.l_start = 0;         // Starting from offset 0
427c804472Sopenharmony_ci    fl.l_len = 0;           // Lock whole file
437c804472Sopenharmony_ci    fl.l_pid = getpid();    // PID of process holding the lock
447c804472Sopenharmony_ci
457c804472Sopenharmony_ci    if (fcntl(fd, F_SETLK, &fl) == -1) {
467c804472Sopenharmony_ci        // Lock failed (file is already locked)
477c804472Sopenharmony_ci        close(fd);
487c804472Sopenharmony_ci        return true; // Simulate that file is locked
497c804472Sopenharmony_ci    }
507c804472Sopenharmony_ci
517c804472Sopenharmony_ci    // Lock acquired, simulate that file is not locked
527c804472Sopenharmony_ci    close(fd);
537c804472Sopenharmony_ci    return false;
547c804472Sopenharmony_ci}
557c804472Sopenharmony_ci
567c804472Sopenharmony_cibool MockFile::ReleaseFileLock(const std::string& filePath)
577c804472Sopenharmony_ci{
587c804472Sopenharmony_ci    int fd = open(filePath.c_str(), O_RDWR | O_CREAT);
597c804472Sopenharmony_ci    if (fd == -1) {
607c804472Sopenharmony_ci        // Handle error
617c804472Sopenharmony_ci        return false;
627c804472Sopenharmony_ci    }
637c804472Sopenharmony_ci
647c804472Sopenharmony_ci    struct flock fl;
657c804472Sopenharmony_ci    fl.l_type = F_UNLCK;    // Unlock the file
667c804472Sopenharmony_ci    fl.l_whence = SEEK_SET; // Starting from beginning of file
677c804472Sopenharmony_ci    fl.l_start = 0;         // Starting from offset 0
687c804472Sopenharmony_ci    fl.l_len = 0;           // Unlock whole file
697c804472Sopenharmony_ci
707c804472Sopenharmony_ci    if (fcntl(fd, F_SETLK, &fl) == -1) {
717c804472Sopenharmony_ci        // Failed to unlock
727c804472Sopenharmony_ci        close(fd);
737c804472Sopenharmony_ci        return false;
747c804472Sopenharmony_ci    }
757c804472Sopenharmony_ci
767c804472Sopenharmony_ci    // Successfully unlocked
777c804472Sopenharmony_ci    close(fd);
787c804472Sopenharmony_ci    return true;
797c804472Sopenharmony_ci}
807c804472Sopenharmony_ci
817c804472Sopenharmony_ci// Function to add a file to zip
827c804472Sopenharmony_cibool MockFile::AddFileToZip(zipFile zip, const std::string& filePath, const std::string& entryName)
837c804472Sopenharmony_ci{
847c804472Sopenharmony_ci    if (zipOpenNewFileInZip(zip, entryName.c_str(), NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,
857c804472Sopenharmony_ci        Z_DEFAULT_COMPRESSION) != ZIP_OK) {
867c804472Sopenharmony_ci        std::cerr << "Failed to create entry in zip file for " << filePath << std::endl;
877c804472Sopenharmony_ci        return false;
887c804472Sopenharmony_ci    }
897c804472Sopenharmony_ci
907c804472Sopenharmony_ci    FILE* file = fopen(filePath.c_str(), "rb");
917c804472Sopenharmony_ci    if (!file) {
927c804472Sopenharmony_ci        std::cerr << "Failed to open file " << filePath << std::endl;
937c804472Sopenharmony_ci        zipCloseFileInZip(zip);
947c804472Sopenharmony_ci        return false;
957c804472Sopenharmony_ci    }
967c804472Sopenharmony_ci
977c804472Sopenharmony_ci    const int bufferSize = 1024;
987c804472Sopenharmony_ci    void* buffer = malloc(bufferSize);
997c804472Sopenharmony_ci    int size;
1007c804472Sopenharmony_ci    while ((size = fread(buffer, 1, bufferSize, file)) > 0) {
1017c804472Sopenharmony_ci        if (zipWriteInFileInZip(zip, buffer, size) < 0) {
1027c804472Sopenharmony_ci            std::cerr << "Failed to write to zip for " << filePath << std::endl;
1037c804472Sopenharmony_ci            free(buffer);
1047c804472Sopenharmony_ci            if (fclose(file) == EOF) {
1057c804472Sopenharmony_ci                std::cerr << "Failed to close file" << std::endl;
1067c804472Sopenharmony_ci                return false;
1077c804472Sopenharmony_ci            }
1087c804472Sopenharmony_ci            zipCloseFileInZip(zip);
1097c804472Sopenharmony_ci            return false;
1107c804472Sopenharmony_ci        }
1117c804472Sopenharmony_ci    }
1127c804472Sopenharmony_ci
1137c804472Sopenharmony_ci    free(buffer);
1147c804472Sopenharmony_ci    if (fclose(file) == EOF) {
1157c804472Sopenharmony_ci        std::cerr << "Failed to close file" << std::endl;
1167c804472Sopenharmony_ci        return false;
1177c804472Sopenharmony_ci    }
1187c804472Sopenharmony_ci    zipCloseFileInZip(zip);
1197c804472Sopenharmony_ci
1207c804472Sopenharmony_ci    return true;
1217c804472Sopenharmony_ci}
1227c804472Sopenharmony_ci
1237c804472Sopenharmony_ci// Function to add a folder and its contents recursively to zip
1247c804472Sopenharmony_cibool MockFile::AddFolderToZip(zipFile zip, const std::string& folderPath, const std::string& entryName)
1257c804472Sopenharmony_ci{
1267c804472Sopenharmony_ci    for (const auto& entry : fs::recursive_directory_iterator(folderPath)) {
1277c804472Sopenharmony_ci        std::string relativePath = entry.path().string().substr(folderPath.length() + 1); // Relative path
1287c804472Sopenharmony_ci
1297c804472Sopenharmony_ci        if (fs::is_directory(entry)) {
1307c804472Sopenharmony_ci            // Create directory entry
1317c804472Sopenharmony_ci            if (zipOpenNewFileInZip(zip, (entryName + "/" + relativePath + "/").c_str(), NULL, NULL, 0,
1327c804472Sopenharmony_ci                NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != ZIP_OK) {
1337c804472Sopenharmony_ci                std::cerr << "Failed to create entry in zip file for " << entry.path() << std::endl;
1347c804472Sopenharmony_ci                return false;
1357c804472Sopenharmony_ci            }
1367c804472Sopenharmony_ci            zipCloseFileInZip(zip);
1377c804472Sopenharmony_ci        } else {
1387c804472Sopenharmony_ci            // Add file
1397c804472Sopenharmony_ci            if (!AddFileToZip(zip, entry.path().string(), entryName + "/" + relativePath)) {
1407c804472Sopenharmony_ci                return false;
1417c804472Sopenharmony_ci            }
1427c804472Sopenharmony_ci        }
1437c804472Sopenharmony_ci    }
1447c804472Sopenharmony_ci
1457c804472Sopenharmony_ci    return true;
1467c804472Sopenharmony_ci}
1477c804472Sopenharmony_ci
1487c804472Sopenharmony_ci// Main compression function
1497c804472Sopenharmony_cibool MockFile::CompressFiles(const std::vector<std::string>& files, const std::string& zipFilename)
1507c804472Sopenharmony_ci{
1517c804472Sopenharmony_ci    zipFile zip = zipOpen(zipFilename.c_str(), APPEND_STATUS_CREATE);
1527c804472Sopenharmony_ci    if (!zip) {
1537c804472Sopenharmony_ci        std::cerr << "Could not create zip file " << zipFilename << std::endl;
1547c804472Sopenharmony_ci        return false;
1557c804472Sopenharmony_ci    }
1567c804472Sopenharmony_ci
1577c804472Sopenharmony_ci    for (const auto& file : files) {
1587c804472Sopenharmony_ci        if (fs::is_directory(file)) {
1597c804472Sopenharmony_ci            // Add directory and its contents
1607c804472Sopenharmony_ci            if (!AddFolderToZip(zip, file, fs::path(file).filename())) {
1617c804472Sopenharmony_ci                zipClose(zip, NULL);
1627c804472Sopenharmony_ci                return false;
1637c804472Sopenharmony_ci            }
1647c804472Sopenharmony_ci        } else {
1657c804472Sopenharmony_ci            // Add individual file
1667c804472Sopenharmony_ci            if (!AddFileToZip(zip, file, fs::path(file).filename())) {
1677c804472Sopenharmony_ci                zipClose(zip, NULL);
1687c804472Sopenharmony_ci                return false;
1697c804472Sopenharmony_ci            }
1707c804472Sopenharmony_ci        }
1717c804472Sopenharmony_ci    }
1727c804472Sopenharmony_ci
1737c804472Sopenharmony_ci    if (zipClose(zip, NULL) != ZIP_OK) {
1747c804472Sopenharmony_ci        std::cerr << "Failed to close zip file " << zipFilename << std::endl;
1757c804472Sopenharmony_ci        return false;
1767c804472Sopenharmony_ci    }
1777c804472Sopenharmony_ci
1787c804472Sopenharmony_ci    return true;
1797c804472Sopenharmony_ci}
1807c804472Sopenharmony_ci
1817c804472Sopenharmony_cinamespace {
1827c804472Sopenharmony_ci// 将内容写入 module.json 文件
1837c804472Sopenharmony_civoid WriteToFile(const std::string& filePath, const std::string& content)
1847c804472Sopenharmony_ci{
1857c804472Sopenharmony_ci    std::ofstream file(filePath);
1867c804472Sopenharmony_ci    if (!file) {
1877c804472Sopenharmony_ci        std::cerr << "Error creating file: " << filePath << std::endl;
1887c804472Sopenharmony_ci        return;
1897c804472Sopenharmony_ci    }
1907c804472Sopenharmony_ci    file << content;
1917c804472Sopenharmony_ci    file.close();
1927c804472Sopenharmony_ci}
1937c804472Sopenharmony_ci
1947c804472Sopenharmony_civoid CreateFiles(const std::string hspAbcContent)
1957c804472Sopenharmony_ci{
1967c804472Sopenharmony_ci    std::filesystem::path dir("ets");
1977c804472Sopenharmony_ci
1987c804472Sopenharmony_ci    // 检查文件夹是否存在
1997c804472Sopenharmony_ci    if (std::filesystem::exists(dir)) {
2007c804472Sopenharmony_ci        std::cout << "Folder already exists." << std::endl;
2017c804472Sopenharmony_ci    } else {
2027c804472Sopenharmony_ci        // 创建文件夹
2037c804472Sopenharmony_ci        std::filesystem::create_directory(dir);
2047c804472Sopenharmony_ci        std::cout << "Folder created successfully." << std::endl;
2057c804472Sopenharmony_ci    }
2067c804472Sopenharmony_ci    // 生成hsp文件
2077c804472Sopenharmony_ci    // 在ets下写入文件modules.abc
2087c804472Sopenharmony_ci    WriteToFile("ets/modules.abc", hspAbcContent);
2097c804472Sopenharmony_ci    // 在当前目录下写入文件module.json
2107c804472Sopenharmony_ci    WriteToFile("module.json", hspAbcContent);
2117c804472Sopenharmony_ci}
2127c804472Sopenharmony_ci}
2137c804472Sopenharmony_ci
2147c804472Sopenharmony_cistd::string MockFile::CreateHspFile(const std::string hspFileName, const std::string hspAbcContent)
2157c804472Sopenharmony_ci{
2167c804472Sopenharmony_ci    CreateFiles(hspAbcContent);
2177c804472Sopenharmony_ci    std::vector<std::string> filesToCompress = { "ets", "module.json" };
2187c804472Sopenharmony_ci    std::string zipFilename = hspFileName + ".zip";
2197c804472Sopenharmony_ci    std::string newFileName = hspFileName + ".hsp";
2207c804472Sopenharmony_ci    if (CompressFiles(filesToCompress, zipFilename)) {
2217c804472Sopenharmony_ci        std::cout << "Compression successful. File created: " << zipFilename << std::endl;
2227c804472Sopenharmony_ci        if (std::rename(zipFilename.c_str(), newFileName.c_str()) != 0) {
2237c804472Sopenharmony_ci            std::cout << newFileName << " 创建hsp文件失败" << std::endl;
2247c804472Sopenharmony_ci            return "";
2257c804472Sopenharmony_ci        }
2267c804472Sopenharmony_ci    } else {
2277c804472Sopenharmony_ci        std::cerr << "Compression failed." << std::endl;
2287c804472Sopenharmony_ci        return "";
2297c804472Sopenharmony_ci    }
2307c804472Sopenharmony_ci    return newFileName;
2317c804472Sopenharmony_ci}
232