1 /*
2  * Copyright (c) 2022-2023 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_utils.h"
16 
17 #include <cerrno>
18 #include <cinttypes>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 
22 #include "securec.h"
23 #include "sensors_errors.h"
24 
25 #undef LOG_TAG
26 #define LOG_TAG "MiscdeviceFileUtils"
27 
28 namespace OHOS {
29 namespace Sensors {
30 namespace {
31 const std::string CONFIG_DIR = "/vendor/etc/vibrator/";
32 constexpr int32_t FILE_SIZE_MAX = 0x5000;
33 constexpr int64_t READ_DATA_BUFF_SIZE = 256;
34 constexpr int32_t INVALID_FILE_SIZE = -1;
35 constexpr int32_t FILE_PATH_MAX = 1024;
36 } // namespace
37 
ReadJsonFile(const std::string & filePath)38 std::string ReadJsonFile(const std::string &filePath)
39 {
40     if (filePath.empty()) {
41         MISC_HILOGE("Path is empty");
42         return {};
43     }
44     char realPath[PATH_MAX] = {};
45     if (realpath(filePath.c_str(), realPath) == nullptr) {
46         MISC_HILOGE("Path is error, %{public}d", errno);
47         return {};
48     }
49     if (!CheckFileDir(realPath, CONFIG_DIR)) {
50         MISC_HILOGE("File dir is invalid");
51         return {};
52     }
53     if (!CheckFileExtendName(realPath, "json")) {
54         MISC_HILOGE("Unable to parse files other than json format");
55         return {};
56     }
57     if (!IsFileExists(realPath)) {
58         MISC_HILOGE("File not exist");
59         return {};
60     }
61     if (!CheckFileSize(realPath)) {
62         MISC_HILOGE("File size out of read range");
63         return {};
64     }
65     FILE *fp = fopen(realPath, "r");
66     CHKPS(fp);
67     std::string dataStr;
68     char buf[READ_DATA_BUFF_SIZE] = { '\0' };
69     while (fgets(buf, sizeof(buf), fp) != nullptr) {
70         dataStr += buf;
71     }
72     if (fclose(fp) != 0) {
73         MISC_HILOGW("Close file failed, errno:%{public}d", errno);
74     }
75     return dataStr;
76 }
77 
GetFileSize(const std::string & filePath)78 int32_t GetFileSize(const std::string &filePath)
79 {
80     struct stat statbuf = { 0 };
81     if (stat(filePath.c_str(), &statbuf) != 0) {
82         MISC_HILOGE("Get file size error");
83         return INVALID_FILE_SIZE;
84     }
85     return statbuf.st_size;
86 }
87 
GetFileSize(int32_t fd)88 int64_t GetFileSize(int32_t fd)
89 {
90     if (fd < 0) {
91         MISC_HILOGE("fd is invalid, fd:%{public}d", fd);
92         return INVALID_FILE_SIZE;
93     }
94     struct stat64 statbuf = { 0 };
95     if (fstat64(fd, &statbuf) != 0) {
96         MISC_HILOGE("fstat error, errno:%{public}d", errno);
97         return INVALID_FILE_SIZE;
98     }
99     return statbuf.st_size;
100 }
101 
GetFileName(const int32_t & fd,std::string & fileName)102 int32_t GetFileName(const int32_t &fd, std::string &fileName)
103 {
104     if (fd < 0) {
105         MISC_HILOGE("fd is invalid, fd:%{public}d", fd);
106         return ERROR;
107     }
108     char buf[FILE_PATH_MAX] = {'\0'};
109     char filePath[FILE_PATH_MAX] = {'\0'};
110 
111     int ret = snprintf_s(buf, sizeof(buf), (sizeof(buf) - 1), "/proc/self/fd/%d", fd);
112     if (ret < 0) {
113         MISC_HILOGE("snprintf failed with %{public}d", errno);
114         return ERROR;
115     }
116 
117     ret = readlink(buf, filePath, FILE_PATH_MAX - 1);
118     if (ret < 0 || ret >= FILE_PATH_MAX) {
119         MISC_HILOGE("readlink failed with %{public}d", errno);
120         return ERROR;
121     }
122 
123     fileName = filePath;
124     std::size_t firstSlash = fileName.rfind("/");
125     if (firstSlash == fileName.npos) {
126         MISC_HILOGE("Get error path");
127         return ERROR;
128     }
129     fileName = fileName.substr(firstSlash + 1, fileName.size() - firstSlash);
130     return SUCCESS;
131 }
132 
GetFileExtName(const int32_t & fd,std::string & extName)133 int32_t GetFileExtName(const int32_t &fd, std::string &extName)
134 {
135     if (fd < 0) {
136         MISC_HILOGE("fd is invalid, fd:%{public}d", fd);
137         return ERROR;
138     }
139     std::string fileName = "";
140     if (GetFileName(fd, fileName) == ERROR) {
141         MISC_HILOGE("GetFileName failed");
142         return ERROR;
143     }
144     extName = fileName.substr(fileName.find_last_of(".") + 1);
145     return SUCCESS;
146 }
147 
CheckFileDir(const std::string & filePath,const std::string & dir)148 bool CheckFileDir(const std::string &filePath, const std::string &dir)
149 {
150     if (filePath.compare(0, CONFIG_DIR.size(), CONFIG_DIR) != 0) {
151         MISC_HILOGE("filePath dir is invalid");
152         return false;
153     }
154     return true;
155 }
156 
CheckFileSize(const std::string & filePath)157 bool CheckFileSize(const std::string &filePath)
158 {
159     int32_t fileSize = GetFileSize(filePath);
160     if ((fileSize <= 0) || (fileSize > FILE_SIZE_MAX)) {
161         MISC_HILOGE("File size out of read range");
162         return false;
163     }
164     return true;
165 }
166 
CheckFileExtendName(const std::string & filePath,const std::string & checkExtension)167 bool CheckFileExtendName(const std::string &filePath, const std::string &checkExtension)
168 {
169     std::string::size_type pos = filePath.find_last_of('.');
170     if (pos == std::string::npos) {
171         MISC_HILOGE("File is not find extension");
172         return false;
173     }
174     return (filePath.substr(pos + 1, filePath.npos) == checkExtension);
175 }
176 
IsFileExists(const std::string & fileName)177 bool IsFileExists(const std::string &fileName)
178 {
179     return (access(fileName.c_str(), F_OK) == 0);
180 }
181 
ReadFd(const RawFileDescriptor & rawFd)182 std::string ReadFd(const RawFileDescriptor &rawFd)
183 {
184     if (rawFd.fd < 0) {
185         MISC_HILOGE("fd is invalid, fd:%{public}d", rawFd.fd);
186         return {};
187     }
188     int64_t fdSize = GetFileSize(rawFd.fd);
189     if ((rawFd.offset < 0) || (rawFd.offset > fdSize)) {
190         MISC_HILOGE("offset is invalid, offset:%{public}" PRId64, rawFd.offset);
191         return {};
192     }
193     if ((rawFd.length <= 0) || (rawFd.length > fdSize - rawFd.offset)) {
194         MISC_HILOGE("length is invalid, length:%{public}" PRId64, rawFd.length);
195         return {};
196     }
197     FILE *fp = fdopen(rawFd.fd, "r");
198     CHKPS(fp);
199     if (fseek(fp, rawFd.offset, SEEK_SET) != 0) {
200         MISC_HILOGE("fseek failed, errno:%{public}d", errno);
201         if (fclose(fp) != 0) {
202             MISC_HILOGW("Close file failed, errno:%{public}d", errno);
203         }
204         return {};
205     }
206     std::string dataStr;
207     char buf[READ_DATA_BUFF_SIZE] = { '\0' };
208     int64_t alreadyRead = 0;
209     while (alreadyRead < rawFd.length) {
210         int64_t onceRead = std::min(rawFd.length - alreadyRead, READ_DATA_BUFF_SIZE - 1);
211         fgets(buf, onceRead + 1, fp);
212         dataStr += buf;
213         alreadyRead = ftell(fp) - rawFd.offset;
214     }
215     if (fclose(fp) != 0) {
216         MISC_HILOGW("Close file failed, errno:%{public}d", errno);
217     }
218     return dataStr;
219 }
220 
GetFileSuffix(int32_t fd)221 std::string GetFileSuffix(int32_t fd)
222 {
223     std::string fdPath = "/proc/self/fd/" + std::to_string(fd);
224     char filePath[FILE_PATH_MAX + 1] = { '\0' };
225     ssize_t ret = readlink(fdPath.c_str(), filePath, FILE_PATH_MAX);
226     if (ret < 0 || ret > FILE_PATH_MAX) {
227         MISC_HILOGE("Readlink failed, errno:%{public}d", errno);
228         return {};
229     }
230     std::string fileAbsolutePath(filePath);
231     size_t pos = fileAbsolutePath.find_last_of('.');
232     if (pos == std::string::npos) {
233         MISC_HILOGE("File suffix is invalid, fileAbsolutePath:%{public}s", fileAbsolutePath.c_str());
234         return {};
235     }
236     return fileAbsolutePath.substr(pos + 1);
237 }
238 } // namespace Sensors
239 } // namespace OHOS
240