1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 *    conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 *    of conditions and the following disclaimer in the documentation and/or other materials
13 *    provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 *    to endorse or promote products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <errno.h>
33#include <fcntl.h>
34#include <unistd.h>
35#include <string.h>
36#include <stdlib.h>
37#include <securec.h>
38
39#include "lwip/sockets.h"
40#include "hks_client.h"
41#include "hi_fs.h"
42
43#define RANDOM_DEV_FD  (LWIP_SOCKET_OFFSET + LWIP_CONFIG_NUM_SOCKETS)
44#define RANDOM_DEV_PATH  "/dev/random"
45
46#define IS_SOCKET_FD(fd) ((fd) >= LWIP_SOCKET_OFFSET && (fd) < (LWIP_SOCKET_OFFSET + LWIP_CONFIG_NUM_SOCKETS))
47
48#define HI_FS_MAX_OPEN_FILES (32+1)
49#define HI_FS_FD_OFFSET RANDOM_DEV_FD
50
51#define IS_HI_FS_FD(fd) ((fd) >= HI_FS_FD_OFFSET && (fd) < (HI_FS_FD_OFFSET + HI_FS_MAX_OPEN_FILES))
52#define HI_FS_FD(fd) ((fd) - HI_FS_FD_OFFSET)
53
54#define FREE_AND_SET_NULL(ptr) do { \
55    free(ptr);                      \
56    ptr = NULL;                     \
57} while (0)
58
59/**
60 * @brief Get canonical form of a given path based on cwd(Current working directory).
61 *
62 * @param cwd Indicates the current working directory.
63 * @param path Indicates the path to be canonicalization.
64 * @param buf Indicates the pointer to the buffer where the result will be return.
65 * @param bufSize Indicates the size of the buffer.
66 * @return Returns the length of the canonical path.
67 *
68 * @attention if path is an absolute path, cwd is ignored. if cwd if not specified, it is assumed to be root('/').
69 *            if the buffer is not big enough the result will be truncated, but the return value will always be the
70 *            length of the canonical path.
71 */
72static size_t GetCanonicalPath(const char *cwd, const char *path, char *buf, size_t bufSize)
73{
74    if (!path) {
75        path = "";
76    }
77
78    if (!cwd || path[0] == '/') {
79        cwd = "";
80    }
81
82    size_t tmpLen = strlen(cwd) + strlen(path) + 4; // three '/' and one '\0'
83    if (tmpLen <= 0) {
84        return 0;
85    }
86    char *tmpBuf = (char *)malloc(tmpLen);
87    if (tmpBuf == NULL) {
88        return 0;
89    }
90
91    if (-1 == sprintf_s(tmpBuf, tmpLen, "/%s/%s/", cwd, path)) {
92        free(tmpBuf);
93        return 0;
94    }
95
96    char *p;
97    /* replace /./ to / */
98    while ((p = strstr(tmpBuf, "/./")) != NULL) {
99        if (EOK != memmove_s(p, tmpLen - (p - tmpBuf), p + 2, tmpLen - (p - tmpBuf) - 2)) {
100            free(tmpBuf);
101            return 0;
102        }
103    }
104
105    /* replace // to / */
106    while ((p = strstr(tmpBuf, "//")) != NULL) {
107        if (EOK != memmove_s(p, tmpLen - (p - tmpBuf), p + 1, tmpLen - (p - tmpBuf) - 1)) {
108            free(tmpBuf);
109            return 0;
110        }
111    }
112
113    /* handle /../ (e.g., replace /aa/bb/../ to /aa/) */
114    while ((p = strstr(tmpBuf, "/../")) != NULL) {
115        char *start = p;
116        while (start > tmpBuf && *--start != '/') {
117        }
118        if (EOK != memmove_s(start, tmpLen - (start - tmpBuf), p + 3, tmpLen - (p - tmpBuf) - 3)) {
119            free(tmpBuf);
120            return 0;
121        }
122    }
123
124    size_t totalLen = strlen(tmpBuf);
125
126    /* strip the last / */
127    if (totalLen > 1 && tmpBuf[totalLen - 1] == '/') {
128        tmpBuf[--totalLen] = 0;
129    }
130
131    if (!buf || bufSize == 0) {
132        free(tmpBuf);
133        return totalLen;
134    }
135
136    if (EOK != memcpy_s(buf, bufSize, tmpBuf, (totalLen + 1 > bufSize) ? bufSize : totalLen + 1)) {
137        free(tmpBuf);
138        return 0;
139    }
140
141    buf[bufSize - 1] = 0;
142    free(tmpBuf);
143    return totalLen;
144}
145
146int open(const char *file, int oflag, ...)
147{
148    int fd = -1;
149    unsigned flags = O_RDONLY | O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_LARGEFILE | O_TRUNC | O_EXCL | O_DIRECTORY;
150    if (((unsigned)oflag & ~flags) || (file == NULL)) {
151        errno = EINVAL;
152        return -1;
153    }
154    size_t pathLen = strlen(file) + 1;
155    if (pathLen <= 0) {
156        errno = EINVAL;
157        return -1;
158    }
159    char *canonicalPath = (char *)malloc(pathLen);
160    if (!canonicalPath) {
161        errno = ENOMEM;
162        return -1;
163    }
164    if (GetCanonicalPath(NULL, file, canonicalPath, pathLen) == 0) {
165        FREE_AND_SET_NULL(canonicalPath);
166        errno = ENOMEM;
167        return -1;
168    }
169    if (strcmp(canonicalPath, RANDOM_DEV_PATH) == 0) {
170        FREE_AND_SET_NULL(canonicalPath);
171        if ((O_ACCMODE & (unsigned)oflag) != O_RDONLY) {
172            errno = EPERM;
173            return -1;
174        }
175        if ((unsigned)oflag & O_DIRECTORY) {
176            errno = ENOTDIR;
177            return -1;
178        }
179        return RANDOM_DEV_FD;
180    }
181    if (strcmp(canonicalPath, "/") == 0 || strcmp(canonicalPath, "/dev") == 0) {
182        FREE_AND_SET_NULL(canonicalPath);
183        if ((unsigned)oflag & O_DIRECTORY) {
184            errno = EPERM;
185            return -1;
186        }
187        errno = EISDIR;
188        return -1;
189    }
190    FREE_AND_SET_NULL(canonicalPath);
191    fd = hi_open(file, (uint32_t)oflag);
192    if (fd < 0) {
193	return -1;
194    }
195    return fd + HI_FS_FD_OFFSET;
196}
197
198int close(int fd)
199{
200    if (fd == RANDOM_DEV_FD) {
201        return 0;
202    }
203    if (IS_SOCKET_FD(fd)) {
204        return closesocket(fd);
205    }
206    if (IS_HI_FS_FD(fd)) {
207        return hi_close(HI_FS_FD(fd));
208    }
209    errno = EBADF;
210    return -1;
211}
212
213ssize_t read(int fd, void *buf, size_t nbytes)
214{
215    if (fd == RANDOM_DEV_FD) {
216        if (nbytes == 0) {
217            return 0;
218        }
219        if (buf == NULL) {
220            errno = EINVAL;
221            return -1;
222        }
223        if (nbytes > 1024) {
224            nbytes = 1024; /* hks_generate_random: random_size must <= 1024 */
225        }
226        struct hks_blob key = {HKS_BLOB_TYPE_RAW, (uint8_t *)buf, nbytes};
227        if (hks_generate_random(&key) != 0) {
228            errno = EIO;
229            return -1;
230        }
231        return (ssize_t)nbytes;
232    }
233    if (IS_SOCKET_FD(fd)) {
234        return recv(fd, buf, nbytes, 0);
235    }
236    if (IS_HI_FS_FD(fd)) {
237        return hi_read(HI_FS_FD(fd), buf, nbytes);
238    }
239    errno = EBADF;
240    return -1;
241}
242
243ssize_t write(int fd, const void *buf, size_t nbytes)
244{
245    if (fd == RANDOM_DEV_FD) {
246        errno = EBADF; /* "/dev/random" is readonly */
247        return -1;
248    }
249    if (IS_SOCKET_FD(fd)) {
250        return send(fd, buf, nbytes, 0);
251    }
252    if (IS_HI_FS_FD(fd)) {
253        return hi_write(HI_FS_FD(fd), (const char*)buf, nbytes);
254    }
255    errno = EBADF;
256    return -1;
257}
258
259off_t lseek(int fd, off_t offset, int whence)
260{
261    if (fd == RANDOM_DEV_FD) {
262        errno = ENOTSUP;
263        return (off_t)-1;
264    }
265    if (IS_SOCKET_FD(fd)) {
266        errno = ESPIPE;
267        return (off_t)-1;
268    }
269    if (IS_HI_FS_FD(fd)) {
270        return hi_lseek(HI_FS_FD(fd), offset, whence);
271    }
272    errno = EBADF;
273    return (off_t)-1;
274}
275
276int unlink(const char *path)
277{
278    return hi_unlink(path);
279}
280
281int fsync(int fd)
282{
283    (void)fd;
284    return 0;
285}
286