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