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 "los_fs.h"
33 #include "los_config.h"
34 #include "fs_operations.h"
35 #if (LOSCFG_SUPPORT_FATFS == 1)
36 #include "fatfs.h"
37 #endif
38 #include "dirent.h"
39 #include "errno.h"
40 #include "fcntl.h"
41 #include "securec.h"
42 #include "stdio.h"
43 #include "stdlib.h"
44 #include "string.h"
45 #include "sys/mount.h"
46 #include "sys/statfs.h"
47 #include "sys/stat.h"
48 #include "unistd.h"
49
50 #ifdef LOSCFG_NET_LWIP_SACK
51 #define _BSD_SOURCE
52 #include "lwip/sockets.h"
53 #endif
54
55 #include "vfs_config.h"
56
57 #ifdef LOSCFG_RANDOM_DEV
58 #include "hks_client.h"
59 #define RANDOM_DEV_FD CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS
60 #define RANDOM_DEV_PATH "/dev/random"
61 #endif
62
63 #if (LOSCFG_POSIX_PIPE_API == 1)
64 #include "pipe_impl.h"
65 #ifdef LOSCFG_RANDOM_DEV
66 #define PIPE_DEV_FD (RANDOM_DEV_FD + 1)
67 #else
68 #define PIPE_DEV_FD (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)
69 #endif
70
PollQueryFd(int fd,struct PollTable * table)71 int PollQueryFd(int fd, struct PollTable *table)
72 {
73 if (fd >= PIPE_DEV_FD) {
74 return PipePoll(fd, table);
75 }
76
77 return -ENODEV;
78 }
79 #endif
80
81 #define FREE_AND_SET_NULL(ptr) do { \
82 free(ptr); \
83 ptr = NULL; \
84 } while (0)
85
86 #ifdef LOSCFG_RANDOM_DEV
87 /**
88 * @brief Get canonical form of a given path based on cwd(Current working directory).
89 *
90 * @param cwd Indicates the current working directory.
91 * @param path Indicates the path to be canonicalization.
92 * @param buf Indicates the pointer to the buffer where the result will be return.
93 * @param bufSize Indicates the size of the buffer.
94 * @return Returns the length of the canonical path.
95 *
96 * @attention if path is an absolute path, cwd is ignored. if cwd if not specified, it is assumed to be root('/').
97 * if the buffer is not big enough the result will be truncated, but the return value will always be the
98 * length of the canonical path.
99 */
GetCanonicalPath(const char * cwd,const char * path,char * buf,size_t bufSize)100 static size_t GetCanonicalPath(const char *cwd, const char *path, char *buf, size_t bufSize)
101 {
102 size_t offset;
103 if (!path) {
104 path = "";
105 }
106
107 if (!cwd || path[0] == '/') {
108 cwd = "";
109 }
110
111 offset = strlen("///") + 1; // three '/' and one '\0'
112 size_t tmpLen = strlen(cwd) + strlen(path) + offset;
113 char *tmpBuf = (char *)malloc(tmpLen);
114 if (tmpBuf == NULL) {
115 return FS_SUCCESS;
116 }
117
118 if (-1 == sprintf_s(tmpBuf, tmpLen, "/%s/%s/", cwd, path)) {
119 free(tmpBuf);
120 return FS_SUCCESS;
121 }
122
123 char *p;
124 /* replace /./ to / */
125 offset = strlen("/./") - 1;
126 while ((p = strstr(tmpBuf, "/./")) != NULL) {
127 if (EOK != memmove_s(p, tmpLen - (p - tmpBuf), p + offset, tmpLen - (p - tmpBuf) - offset)) {
128 free(tmpBuf);
129 return FS_SUCCESS;
130 }
131 }
132
133 /* replace // to / */
134 while ((p = strstr(tmpBuf, "//")) != NULL) {
135 if (EOK != memmove_s(p, tmpLen - (p - tmpBuf), p + 1, tmpLen - (p - tmpBuf) - 1)) {
136 free(tmpBuf);
137 return FS_SUCCESS;
138 }
139 }
140
141 /* handle /../ (e.g., replace /aa/bb/../ to /aa/) */
142 offset = strlen("/../") - 1;
143 while ((p = strstr(tmpBuf, "/../")) != NULL) {
144 char *start = p;
145 while (start > tmpBuf && *(start - 1) != '/') {
146 --start;
147 }
148 if (EOK != memmove_s(start, tmpLen - (start - tmpBuf), p + offset, tmpLen - (p - tmpBuf) - offset)) {
149 free(tmpBuf);
150 return FS_SUCCESS;
151 }
152 }
153
154 size_t totalLen = strlen(tmpBuf);
155 /* strip the last / */
156 if (totalLen > 1 && tmpBuf[totalLen - 1] == '/') {
157 tmpBuf[--totalLen] = 0;
158 }
159
160 if (!buf || bufSize == 0) {
161 free(tmpBuf);
162 return totalLen;
163 }
164
165 if (EOK != memcpy_s(buf, bufSize, tmpBuf, (((totalLen + 1) > bufSize) ? bufSize : (totalLen + 1)))) {
166 free(tmpBuf);
167 return FS_SUCCESS;
168 }
169
170 buf[bufSize - 1] = 0;
171 free(tmpBuf);
172 return totalLen;
173 }
174 #endif
175
176 static struct FsMap g_fsmap[MAX_FILESYSTEM_LEN] = {0};
177 static struct FsMap *g_fs = NULL;
178
InitMountInfo(void)179 static void InitMountInfo(void)
180 {
181 #if (LOSCFG_SUPPORT_FATFS == 1)
182 extern struct MountOps g_fatfsMnt;
183 extern struct FileOps g_fatfsFops;
184 g_fsmap[0].fileSystemtype = strdup("fat");
185 g_fsmap[0].fsMops = &g_fatfsMnt;
186 g_fsmap[0].fsFops = &g_fatfsFops;
187 #endif
188 #if (LOSCFG_SUPPORT_LITTLEFS == 1)
189 extern struct MountOps g_lfsMnt;
190 extern struct FileOps g_lfsFops;
191 g_fsmap[1].fileSystemtype = strdup("littlefs");
192 g_fsmap[1].fsMops = &g_lfsMnt;
193 g_fsmap[1].fsFops = &g_lfsFops;
194 #endif
195 }
196
MountFindfs(const char * fileSystemtype)197 static struct FsMap *MountFindfs(const char *fileSystemtype)
198 {
199 struct FsMap *m = NULL;
200
201 for (int i = 0; i < MAX_FILESYSTEM_LEN; i++) {
202 m = &(g_fsmap[i]);
203 if (m->fileSystemtype && strcmp(fileSystemtype, m->fileSystemtype) == 0) {
204 return m;
205 }
206 }
207
208 return NULL;
209 }
210
LOS_FsMount(const char * source,const char * target,const char * filesystemtype,unsigned long mountflags,const void * data)211 int LOS_FsMount(const char *source, const char *target,
212 const char *filesystemtype, unsigned long mountflags,
213 const void *data)
214 {
215 static int initFlag = 0;
216
217 if (initFlag == 0) {
218 InitMountInfo();
219 initFlag = 1;
220 }
221
222 g_fs = MountFindfs(filesystemtype);
223 if (g_fs == NULL) {
224 errno = ENODEV;
225 return FS_FAILURE;
226 }
227
228 if (g_fs->fsMops == NULL || g_fs->fsMops->Mount == NULL) {
229 errno = ENOSYS;
230 return FS_FAILURE;
231 }
232
233 return g_fs->fsMops->Mount(source, target, filesystemtype, mountflags, data);
234 }
235
LOS_FsUmount(const char * target)236 int LOS_FsUmount(const char *target)
237 {
238 if (g_fs == NULL) {
239 errno = ENODEV;
240 return FS_FAILURE;
241 }
242 if (g_fs->fsMops == NULL || g_fs->fsMops->Umount == NULL) {
243 errno = ENOSYS;
244 return FS_FAILURE;
245 }
246 return g_fs->fsMops->Umount(target);
247 }
248
LOS_FsUmount2(const char * target,int flag)249 int LOS_FsUmount2(const char *target, int flag)
250 {
251 if (g_fs == NULL) {
252 errno = ENODEV;
253 return FS_FAILURE;
254 }
255 if (g_fs->fsMops == NULL || g_fs->fsMops->Umount2 == NULL) {
256 errno = ENOSYS;
257 return FS_FAILURE;
258 }
259 return g_fs->fsMops->Umount2(target, flag);
260 }
261
LOS_Open(const char * path,int oflag,...)262 int LOS_Open(const char *path, int oflag, ...)
263 {
264 #ifdef LOSCFG_RANDOM_DEV
265 unsigned flags = O_RDONLY | O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_LARGEFILE | O_TRUNC | O_EXCL | O_DIRECTORY;
266 if ((unsigned)oflag & ~flags) {
267 errno = EINVAL;
268 return FS_FAILURE;
269 }
270
271 size_t pathLen = strlen(path) + 1;
272 if ((unsigned)pathLen > PATH_MAX) {
273 errno = EINVAL;
274 return FS_FAILURE;
275 }
276 char *canonicalPath = (char *)malloc(pathLen);
277 if (!canonicalPath) {
278 errno = ENOMEM;
279 return FS_FAILURE;
280 }
281 if (GetCanonicalPath(NULL, path, canonicalPath, pathLen) == 0) {
282 FREE_AND_SET_NULL(canonicalPath);
283 errno = ENOMEM;
284 return FS_FAILURE;
285 }
286
287 if (strcmp(canonicalPath, RANDOM_DEV_PATH) == 0) {
288 FREE_AND_SET_NULL(canonicalPath);
289 if ((O_ACCMODE & (unsigned)oflag) != O_RDONLY) {
290 errno = EPERM;
291 return FS_FAILURE;
292 }
293 if ((unsigned)oflag & O_DIRECTORY) {
294 errno = ENOTDIR;
295 return FS_FAILURE;
296 }
297 return RANDOM_DEV_FD;
298 }
299 if (strcmp(canonicalPath, "/") == 0 || strcmp(canonicalPath, "/dev") == 0) {
300 FREE_AND_SET_NULL(canonicalPath);
301 if ((unsigned)oflag & O_DIRECTORY) {
302 errno = EPERM;
303 return FS_FAILURE;
304 }
305 errno = EISDIR;
306 return FS_FAILURE;
307 }
308 FREE_AND_SET_NULL(canonicalPath);
309 #endif
310
311 #if (LOSCFG_POSIX_PIPE_API == 1)
312 if ((path != NULL) && !strncmp(path, PIPE_DEV_PATH, strlen(PIPE_DEV_PATH))) {
313 return PipeOpen(path, oflag, PIPE_DEV_FD);
314 }
315 #endif
316
317 if (g_fs == NULL) {
318 errno = ENODEV;
319 return FS_FAILURE;
320 }
321 if (g_fs->fsFops == NULL || g_fs->fsFops->Open == NULL) {
322 errno = ENOSYS;
323 return FS_FAILURE;
324 }
325 return g_fs->fsFops->Open(path, oflag);
326 }
327
LOS_Close(int fd)328 int LOS_Close(int fd)
329 {
330 #ifdef LOSCFG_RANDOM_DEV
331 if (fd == RANDOM_DEV_FD) {
332 return FS_SUCCESS;
333 }
334 #endif
335 #ifdef LOSCFG_NET_LWIP_SACK
336 if (fd >= CONFIG_NFILE_DESCRIPTORS && fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
337 return closesocket(fd);
338 }
339 #endif
340
341 #if (LOSCFG_POSIX_PIPE_API == 1)
342 if (fd >= PIPE_DEV_FD) {
343 return PipeClose(fd);
344 }
345 #endif
346
347 if (g_fs == NULL) {
348 errno = ENODEV;
349 return FS_FAILURE;
350 }
351 if (g_fs->fsFops == NULL || g_fs->fsFops->Close == NULL) {
352 errno = ENOSYS;
353 return FS_FAILURE;
354 }
355 return g_fs->fsFops->Close(fd);
356 }
357
LOS_Read(int fd,void * buf,size_t nbyte)358 ssize_t LOS_Read(int fd, void *buf, size_t nbyte)
359 {
360 #ifdef LOSCFG_RANDOM_DEV
361 if (fd == RANDOM_DEV_FD) {
362 if (nbyte == 0) {
363 return FS_SUCCESS;
364 }
365 if (buf == NULL) {
366 errno = EINVAL;
367 return FS_FAILURE;
368 }
369 if (nbyte > 1024) { /* 1024, max random_size */
370 nbyte = 1024; /* hks_generate_random: random_size must <= 1024 */
371 }
372 struct hks_blob key = {HKS_BLOB_TYPE_RAW, (uint8_t *)buf, nbyte};
373 if (hks_generate_random(&key) != 0) {
374 errno = EIO;
375 return FS_FAILURE;
376 }
377 return (ssize_t)nbyte;
378 }
379 #endif
380 #ifdef LOSCFG_NET_LWIP_SACK
381 if (fd >= CONFIG_NFILE_DESCRIPTORS && fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
382 return recv(fd, buf, nbyte, 0);
383 }
384 #endif
385
386 #if (LOSCFG_POSIX_PIPE_API == 1)
387 if (fd >= PIPE_DEV_FD) {
388 return PipeRead(fd, buf, nbyte);
389 }
390 #endif
391
392 if (g_fs == NULL) {
393 errno = ENODEV;
394 return FS_FAILURE;
395 }
396 if (g_fs->fsFops == NULL || g_fs->fsFops->Read == NULL) {
397 errno = ENOSYS;
398 return FS_FAILURE;
399 }
400 return g_fs->fsFops->Read(fd, buf, nbyte);
401 }
402
LOS_Write(int fd,const void * buf,size_t nbyte)403 ssize_t LOS_Write(int fd, const void *buf, size_t nbyte)
404 {
405 #ifdef LOSCFG_RANDOM_DEV
406 if (fd == RANDOM_DEV_FD) {
407 errno = EBADF; /* "/dev/random" is readonly */
408 return FS_FAILURE;
409 }
410 #endif
411 #ifdef LOSCFG_NET_LWIP_SACK
412 if (fd >= CONFIG_NFILE_DESCRIPTORS && fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
413 return send(fd, buf, nbyte, 0);
414 }
415 #endif
416
417 #if (LOSCFG_POSIX_PIPE_API == 1)
418 if (fd >= PIPE_DEV_FD) {
419 return PipeWrite(fd, buf, nbyte);
420 }
421 #endif
422
423 if (g_fs == NULL) {
424 errno = ENODEV;
425 return FS_FAILURE;
426 }
427 if (g_fs->fsFops == NULL || g_fs->fsFops->Write == NULL) {
428 errno = ENOSYS;
429 return FS_FAILURE;
430 }
431 return g_fs->fsFops->Write(fd, buf, nbyte);
432 }
433
LOS_Lseek(int fd,off_t offset,int whence)434 off_t LOS_Lseek(int fd, off_t offset, int whence)
435 {
436 if (g_fs == NULL) {
437 errno = ENODEV;
438 return FS_FAILURE;
439 }
440 if (g_fs->fsFops == NULL || g_fs->fsFops->Seek == NULL) {
441 errno = ENOSYS;
442 return FS_FAILURE;
443 }
444 return g_fs->fsFops->Seek(fd, offset, whence);
445 }
446
LOS_Unlink(const char * path)447 int LOS_Unlink(const char *path)
448 {
449 if (g_fs == NULL) {
450 errno = ENODEV;
451 return FS_FAILURE;
452 }
453 if (g_fs->fsFops == NULL || g_fs->fsFops->Unlink == NULL) {
454 errno = ENOSYS;
455 return FS_FAILURE;
456 }
457 return g_fs->fsFops->Unlink(path);
458 }
459
LOS_Fstat(int fd,struct stat * buf)460 int LOS_Fstat(int fd, struct stat *buf)
461 {
462 if (g_fs == NULL) {
463 errno = ENODEV;
464 return FS_FAILURE;
465 }
466 if (g_fs->fsFops == NULL || g_fs->fsFops->Fstat == NULL) {
467 errno = ENOSYS;
468 return FS_FAILURE;
469 }
470 return g_fs->fsFops->Fstat(fd, buf);
471 }
472
LOS_Stat(const char * path,struct stat * buf)473 int LOS_Stat(const char *path, struct stat *buf)
474 {
475 if (g_fs == NULL) {
476 errno = ENODEV;
477 return FS_FAILURE;
478 }
479 if (g_fs->fsFops == NULL || g_fs->fsFops->Getattr == NULL) {
480 errno = ENOSYS;
481 return FS_FAILURE;
482 }
483 return g_fs->fsFops->Getattr(path, buf);
484 }
485
LOS_Fsync(int fd)486 int LOS_Fsync(int fd)
487 {
488 if (g_fs == NULL) {
489 errno = ENODEV;
490 return FS_FAILURE;
491 }
492 if (g_fs->fsFops == NULL || g_fs->fsFops->Fsync == NULL) {
493 errno = ENOSYS;
494 return FS_FAILURE;
495 }
496 return g_fs->fsFops->Fsync(fd);
497 }
498
LOS_Mkdir(const char * path,mode_t mode)499 int LOS_Mkdir(const char *path, mode_t mode)
500 {
501 if (g_fs == NULL) {
502 errno = ENODEV;
503 return FS_FAILURE;
504 }
505 if (g_fs->fsFops == NULL || g_fs->fsFops->Mkdir == NULL) {
506 errno = ENOSYS;
507 return FS_FAILURE;
508 }
509 return g_fs->fsFops->Mkdir(path, mode);
510 }
511
LOS_Opendir(const char * dirName)512 DIR *LOS_Opendir(const char *dirName)
513 {
514 if (g_fs == NULL) {
515 errno = ENODEV;
516 return NULL;
517 }
518 if (g_fs->fsFops == NULL || g_fs->fsFops->Opendir == NULL) {
519 errno = ENOSYS;
520 return NULL;
521 }
522 return g_fs->fsFops->Opendir(dirName);
523 }
524
LOS_Readdir(DIR * dir)525 struct dirent *LOS_Readdir(DIR *dir)
526 {
527 if (g_fs == NULL) {
528 errno = ENODEV;
529 return NULL;
530 }
531 if (g_fs->fsFops == NULL || g_fs->fsFops->Readdir == NULL) {
532 errno = ENOSYS;
533 return NULL;
534 }
535 return g_fs->fsFops->Readdir(dir);
536 }
537
LOS_Closedir(DIR * dir)538 int LOS_Closedir(DIR *dir)
539 {
540 if (g_fs == NULL) {
541 errno = ENODEV;
542 return FS_FAILURE;
543 }
544 if (g_fs->fsFops == NULL || g_fs->fsFops->Closedir == NULL) {
545 errno = ENOSYS;
546 return FS_FAILURE;
547 }
548 return g_fs->fsFops->Closedir(dir);
549 }
550
LOS_Rmdir(const char * path)551 int LOS_Rmdir(const char *path)
552 {
553 if (g_fs == NULL) {
554 errno = ENODEV;
555 return FS_FAILURE;
556 }
557 if (g_fs->fsFops == NULL || g_fs->fsFops->Rmdir == NULL) {
558 errno = ENOSYS;
559 return FS_FAILURE;
560 }
561 return g_fs->fsFops->Rmdir(path);
562 }
563
LOS_Rename(const char * oldName,const char * newName)564 int LOS_Rename(const char *oldName, const char *newName)
565 {
566 if (g_fs == NULL) {
567 errno = ENODEV;
568 return FS_FAILURE;
569 }
570 if (g_fs->fsFops == NULL || g_fs->fsFops->Rename == NULL) {
571 errno = ENOSYS;
572 return FS_FAILURE;
573 }
574 return g_fs->fsFops->Rename(oldName, newName);
575 }
576
LOS_Statfs(const char * path,struct statfs * buf)577 int LOS_Statfs(const char *path, struct statfs *buf)
578 {
579 if (g_fs == NULL) {
580 errno = ENODEV;
581 return FS_FAILURE;
582 }
583 if (g_fs->fsMops == NULL || g_fs->fsMops->Statfs == NULL) {
584 errno = ENOSYS;
585 return FS_FAILURE;
586 }
587 return g_fs->fsMops->Statfs(path, buf);
588 }
589
LOS_Ftruncate(int fd,off_t length)590 int LOS_Ftruncate(int fd, off_t length)
591 {
592 if (g_fs == NULL) {
593 errno = ENODEV;
594 return FS_FAILURE;
595 }
596 if (g_fs->fsFops == NULL || g_fs->fsFops->Ftruncate == NULL) {
597 errno = ENOSYS;
598 return FS_FAILURE;
599 }
600 return g_fs->fsFops->Ftruncate(fd, length);
601 }
602
LOS_Pread(int fd,void * buf,size_t nbyte,off_t offset)603 ssize_t LOS_Pread(int fd, void *buf, size_t nbyte, off_t offset)
604 {
605 #ifdef LOSCFG_RANDOM_DEV
606 if (fd == RANDOM_DEV_FD) {
607 if (nbyte == 0) {
608 return FS_SUCCESS;
609 }
610 if (buf == NULL) {
611 errno = EINVAL;
612 return FS_FAILURE;
613 }
614 if (nbyte > 1024) { /* 1024, max random_size */
615 nbyte = 1024; /* hks_generate_random: random_size must <= 1024 */
616 }
617 struct hks_blob key = {HKS_BLOB_TYPE_RAW, (uint8_t *)buf, nbyte};
618 if (hks_generate_random(&key) != 0) {
619 errno = EIO;
620 return FS_FAILURE;
621 }
622 return (ssize_t)nbyte;
623 }
624 #endif
625 if (g_fs == NULL) {
626 errno = ENODEV;
627 return FS_FAILURE;
628 }
629 if (g_fs->fsFops == NULL || g_fs->fsFops->Pread == NULL) {
630 errno = ENOSYS;
631 return FS_FAILURE;
632 }
633 return g_fs->fsFops->Pread(fd, buf, nbyte, offset);
634 }
635
LOS_Pwrite(int fd,const void * buf,size_t nbyte,off_t offset)636 ssize_t LOS_Pwrite(int fd, const void *buf, size_t nbyte, off_t offset)
637 {
638 #ifdef LOSCFG_RANDOM_DEV
639 if (fd == RANDOM_DEV_FD) {
640 errno = EBADF; /* "/dev/random" is readonly */
641 return FS_FAILURE;
642 }
643 #endif
644 if (g_fs == NULL) {
645 errno = ENODEV;
646 return FS_FAILURE;
647 }
648 if (g_fs->fsFops == NULL || g_fs->fsFops->Pwrite == NULL) {
649 errno = ENOSYS;
650 return FS_FAILURE;
651 }
652 return g_fs->fsFops->Pwrite(fd, buf, nbyte, offset);
653 }
654