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 "ecmascript/platform/filesystem.h"
17
18#include <dirent.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <unistd.h>
22
23#include "ecmascript/platform/file.h"
24
25#include "os/filesystem.h"
26
27namespace panda::ecmascript::filesystem {
28bool CreateDirectory(const std::string& path)
29{
30    if (path.empty()) {
31        return true;
32    }
33    auto pos = path.find_last_of('/');
34    if (pos != std::string::npos) {
35        if (!CreateDirectory(path.substr(0, pos))) {
36            return false;
37        }
38    }
39    panda::os::CreateDirectories(path);
40    if (!Exists(path)) {
41        return false;
42    }
43    return true;
44}
45
46bool Exists(const std::string& path)
47{
48    return panda::ecmascript::FileExist(path.c_str());
49}
50
51std::string TempDirectoryPath()
52{
53    const char* temp = getenv("TMPDIR");
54    if (temp) {
55        return std::string(temp);
56    }
57    return "/tmp";
58}
59
60std::size_t FileSize(const std::string& path)
61{
62    struct stat info;
63    stat(path.c_str(), &info);
64    return info.st_size;
65}
66
67bool RemoveAll(const std::string& path)
68{
69    struct stat info;
70    if (stat(path.c_str(), &info) != 0) {
71        return false;
72    }
73
74    if (S_ISDIR(info.st_mode)) {
75        DIR* dir = opendir(path.c_str());
76        if (!dir) {
77            return false;
78        }
79
80        struct dirent* entry;
81        while ((entry = readdir(dir)) != nullptr) {
82            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
83                continue;
84            }
85            std::string entryPath = path + "/" + entry->d_name;
86            if (!RemoveAll(entryPath)) {
87                closedir(dir);
88                return false;
89            }
90        }
91        closedir(dir);
92        return rmdir(path.c_str()) == 0;
93    } else {
94        return unlink(path.c_str()) == 0;
95    }
96}
97
98void CreateEmptyFile(const std::string& fileName)
99{
100    std::string realPath;
101    if (!panda::ecmascript::RealPath(fileName, realPath, false)) {
102        LOG_FULL(ERROR) << "failed to create empty file: " << fileName << ", error: " << std::strerror(errno);
103        return;
104    }
105    if (Exists(realPath)) {
106        LOG_FULL(INFO) << realPath << " exists, skip creation";
107        return;
108    }
109
110    auto index = realPath.find_last_of('/');
111    if (index != std::string::npos) {
112        std::string dir = realPath.substr(0, index);
113        if (Exists(dir)) {
114            LOG_FULL(INFO) << dir << " exists, skip creation";
115        } else {
116            LOG_FULL(INFO) << "creating folder " << dir;
117            if (!CreateDirectory(dir)) {
118                LOG_FULL(ERROR) << "failed to create folder " << dir << ", error: " << std::strerror(errno);
119                return;
120            }
121        }
122    }
123
124    std::ofstream file(realPath);
125    if (!file.good()) {
126        LOG_FULL(ERROR) << "failed to create empty file: " << realPath << ", error: " << std::strerror(errno);
127    } else {
128        LOG_FULL(INFO) << "created empty file: " << realPath;
129    }
130    file.close();
131}
132} // namespace panda::ecmascript::kungfu::filesystem