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 "stdlib.h"
34 #include "string.h"
35 #include "dirent.h"
36 #include "unistd.h"
37 #include "sys/select.h"
38 #include "sys/mount.h"
39 #include "sys/stat.h"
40 #include "sys/statfs.h"
41 #include "sys/prctl.h"
42 #include "fs/fd_table.h"
43 #include "fs/file.h"
44 #include "linux/spinlock.h"
45 #include "los_process_pri.h"
46 #include "los_task_pri.h"
47 #include "capability_api.h"
48 #include "vnode.h"
49
50 #define MAX_DIR_ENT 1024
fstat(int fd,struct stat * buf)51 int fstat(int fd, struct stat *buf)
52 {
53 struct file *filep = NULL;
54
55 int ret = fs_getfilep(fd, &filep);
56 if (ret < 0) {
57 return VFS_ERROR;
58 }
59
60 return stat(filep->f_path, buf);
61 }
62
fstat64(int fd,struct stat64 * buf)63 int fstat64(int fd, struct stat64 *buf)
64 {
65 struct file *filep = NULL;
66
67 int ret = fs_getfilep(fd, &filep);
68 if (ret < 0) {
69 return VFS_ERROR;
70 }
71
72 return stat64(filep->f_path, buf);
73 }
74
lstat(const char * path,struct stat * buffer)75 int lstat(const char *path, struct stat *buffer)
76 {
77 return stat(path, buffer);
78 }
79
VfsVnodePermissionCheck(const struct Vnode * node,int accMode)80 int VfsVnodePermissionCheck(const struct Vnode *node, int accMode)
81 {
82 uint fuid = node->uid;
83 uint fgid = node->gid;
84 uint fileMode = node->mode;
85 return VfsPermissionCheck(fuid, fgid, fileMode, accMode);
86 }
87
VfsPermissionCheck(uint fuid,uint fgid,uint fileMode,int accMode)88 int VfsPermissionCheck(uint fuid, uint fgid, uint fileMode, int accMode)
89 {
90 uint uid = OsCurrUserGet()->effUserID;
91 mode_t tmpMode = fileMode;
92
93 if (uid == fuid) {
94 tmpMode >>= USER_MODE_SHIFT;
95 } else if (LOS_CheckInGroups(fgid)) {
96 tmpMode >>= GROUP_MODE_SHIFT;
97 }
98
99 tmpMode &= (READ_OP | WRITE_OP | EXEC_OP);
100
101 if (((uint)accMode & tmpMode) == accMode) {
102 return 0;
103 }
104
105 tmpMode = 0;
106 if (S_ISDIR(fileMode)) {
107 if (IsCapPermit(CAP_DAC_EXECUTE)
108 || (!((uint)accMode & WRITE_OP) && IsCapPermit(CAP_DAC_READ_SEARCH))) {
109 tmpMode |= EXEC_OP;
110 }
111 } else {
112 if (IsCapPermit(CAP_DAC_EXECUTE) && (fileMode & MODE_IXUGO)) {
113 tmpMode |= EXEC_OP;
114 }
115 }
116
117 if (IsCapPermit(CAP_DAC_WRITE)) {
118 tmpMode |= WRITE_OP;
119 }
120
121 if (IsCapPermit(CAP_DAC_READ_SEARCH)) {
122 tmpMode |= READ_OP;
123 }
124
125 if (((uint)accMode & tmpMode) == accMode) {
126 return 0;
127 }
128
129 return 1;
130 }
131
132 #ifdef VFS_USING_WORKDIR
SetWorkDir(const char * dir,size_t len)133 static int SetWorkDir(const char *dir, size_t len)
134 {
135 errno_t ret;
136 uint lock_flags;
137 LosProcessCB *curr = OsCurrProcessGet();
138
139 spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
140 ret = strncpy_s(curr->files->workdir, PATH_MAX, dir, len);
141 curr->files->workdir[PATH_MAX - 1] = '\0';
142 spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
143 if (ret != EOK) {
144 return -1;
145 }
146
147 return 0;
148 }
149 #endif
150
chdir(const char * path)151 int chdir(const char *path)
152 {
153 int ret;
154 char *fullpath = NULL;
155 char *fullpath_bak = NULL;
156 struct stat statBuff;
157
158
159 if (!path) {
160 set_errno(EFAULT);
161 return -1;
162 }
163
164 if (!strlen(path)) {
165 set_errno(ENOENT);
166 return -1;
167 }
168
169 if (strlen(path) > PATH_MAX) {
170 set_errno(ENAMETOOLONG);
171 return -1;
172 }
173
174 ret = vfs_normalize_path((const char *)NULL, path, &fullpath);
175 if (ret < 0) {
176 set_errno(-ret);
177 return -1; /* build path failed */
178 }
179 fullpath_bak = fullpath;
180 ret = stat(fullpath, &statBuff);
181 if (ret < 0) {
182 free(fullpath_bak);
183 return -1;
184 }
185
186 if (!S_ISDIR(statBuff.st_mode)) {
187 set_errno(ENOTDIR);
188 free(fullpath_bak);
189 return -1;
190 }
191
192 if (VfsPermissionCheck(statBuff.st_uid, statBuff.st_gid, statBuff.st_mode, EXEC_OP)) {
193 set_errno(EACCES);
194 free(fullpath_bak);
195 return -1;
196 }
197
198 #ifdef VFS_USING_WORKDIR
199 ret = SetWorkDir(fullpath, strlen(fullpath));
200 if (ret != 0) {
201 PRINT_ERR("chdir path error!\n");
202 ret = -1;
203 }
204 #endif
205
206 /* release normalize directory path name */
207
208 free(fullpath_bak);
209
210 return ret;
211 }
212
213 /**
214 * this function is a POSIX compliant version, which will return current
215 * working directory.
216 *
217 * @param buf the returned current directory.
218 * @param size the buffer size.
219 *
220 * @return the returned current directory.
221 */
222
getcwd(char * buf,size_t n)223 char *getcwd(char *buf, size_t n)
224 {
225 #ifdef VFS_USING_WORKDIR
226 int ret;
227 unsigned int len;
228 UINTPTR lock_flags;
229 LosProcessCB *curr = OsCurrProcessGet();
230 #endif
231 if (buf == NULL) {
232 set_errno(EINVAL);
233 return buf;
234 }
235 #ifdef VFS_USING_WORKDIR
236 spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
237 len = strlen(curr->files->workdir);
238 if (n <= len) {
239 set_errno(ERANGE);
240 spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
241 return NULL;
242 }
243 ret = memcpy_s(buf, n, curr->files->workdir, len + 1);
244 if (ret != EOK) {
245 set_errno(ENAMETOOLONG);
246 spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
247 return NULL;
248 }
249 spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
250 #else
251 PRINT_ERR("NO_WORKING_DIR\n");
252 #endif
253
254 return buf;
255 }
256
chmod(const char * path,mode_t mode)257 int chmod(const char *path, mode_t mode)
258 {
259 struct IATTR attr = {0};
260 attr.attr_chg_mode = mode;
261 attr.attr_chg_valid = CHG_MODE; /* change mode */
262 int ret;
263
264 ret = chattr(path, &attr);
265 if (ret < 0) {
266 return VFS_ERROR;
267 }
268
269 return OK;
270 }
271
chown(const char * pathname,uid_t owner,gid_t group)272 int chown(const char *pathname, uid_t owner, gid_t group)
273 {
274 struct IATTR attr = {0};
275 attr.attr_chg_valid = 0;
276 int ret;
277
278 if (owner != (uid_t)-1) {
279 attr.attr_chg_uid = owner;
280 attr.attr_chg_valid |= CHG_UID;
281 }
282 if (group != (gid_t)-1) {
283 attr.attr_chg_gid = group;
284 attr.attr_chg_valid |= CHG_GID;
285 }
286 ret = chattr(pathname, &attr);
287 if (ret < 0) {
288 return VFS_ERROR;
289 }
290
291 return OK;
292 }
293
access(const char * path,int amode)294 int access(const char *path, int amode)
295 {
296 int ret;
297 struct stat buf;
298 struct statfs fsBuf;
299
300 ret = statfs(path, &fsBuf);
301 if (ret != 0) {
302 if (get_errno() != ENOSYS) {
303 return VFS_ERROR;
304 }
305 /* dev has no statfs ops, need devfs to handle this in feature */
306 }
307
308 if ((fsBuf.f_flags & MS_RDONLY) && ((unsigned int)amode & W_OK)) {
309 set_errno(EROFS);
310 return VFS_ERROR;
311 }
312
313 ret = stat(path, &buf);
314 if (ret != 0) {
315 return VFS_ERROR;
316 }
317
318 if (VfsPermissionCheck(buf.st_uid, buf.st_gid, buf.st_mode, amode)) {
319 set_errno(EACCES);
320 return VFS_ERROR;
321 }
322
323 return OK;
324 }
325
scandir_get_file_list(const char * dir,int * num,int (* filter)(const struct dirent *))326 static struct dirent **scandir_get_file_list(const char *dir, int *num, int(*filter)(const struct dirent *))
327 {
328 DIR *od = NULL;
329 int listSize = MAX_DIR_ENT;
330 int n = 0;
331 struct dirent **list = NULL;
332 struct dirent **newList = NULL;
333 struct dirent *ent = NULL;
334 struct dirent *p = NULL;
335 int err;
336
337 od = opendir(dir);
338 if (od == NULL) {
339 return NULL;
340 }
341
342 list = (struct dirent **)malloc(listSize * sizeof(struct dirent *));
343 if (list == NULL) {
344 (void)closedir(od);
345 return NULL;
346 }
347
348 for (ent = readdir(od); ent != NULL; ent = readdir(od)) {
349 if (filter && !filter(ent)) {
350 continue;
351 }
352
353 if (n == listSize) {
354 listSize += MAX_DIR_ENT;
355 newList = (struct dirent **)malloc(listSize * sizeof(struct dirent *));
356 if (newList == NULL) {
357 break;
358 }
359
360 err = memcpy_s(newList, listSize * sizeof(struct dirent *), list, n * sizeof(struct dirent *));
361 if (err != EOK) {
362 free(newList);
363 break;
364 }
365 free(list);
366 list = newList;
367 }
368
369 p = (struct dirent *)malloc(sizeof(struct dirent));
370 if (p == NULL) {
371 break;
372 }
373
374 (void)memcpy_s((void *)p, sizeof(struct dirent), (void *)ent, sizeof(struct dirent));
375 list[n] = p;
376
377 n++;
378 }
379
380 if (closedir(od) < 0) {
381 while (n--) {
382 free(list[n]);
383 }
384 free(list);
385 return NULL;
386 }
387
388 *num = n;
389 return list;
390 }
391
scandir(const char * dir,struct dirent *** namelist,int (* filter)(const struct dirent *),int (* compar)(const struct dirent **,const struct dirent **))392 int scandir(const char *dir, struct dirent ***namelist,
393 int(*filter)(const struct dirent *),
394 int(*compar)(const struct dirent **, const struct dirent **))
395 {
396 int n = 0;
397 struct dirent **list = NULL;
398
399 if ((dir == NULL) || (namelist == NULL)) {
400 return -1;
401 }
402
403 list = scandir_get_file_list(dir, &n, filter);
404 if (list == NULL) {
405 return -1;
406 }
407
408 /* Change to return to the array size */
409 *namelist = (struct dirent **)malloc(n * sizeof(struct dirent *));
410 if (*namelist == NULL && n > 0) {
411 *namelist = list;
412 } else if (*namelist != NULL) {
413 (void)memcpy_s(*namelist, n * sizeof(struct dirent *), list, n * sizeof(struct dirent *));
414 free(list);
415 } else {
416 free(list);
417 }
418
419 /* Sort array */
420
421 if (compar && *namelist) {
422 qsort((void *)*namelist, (size_t)n, sizeof(struct dirent *), (int (*)(const void *, const void *))*compar);
423 }
424
425 return n;
426 }
427
alphasort(const struct dirent ** a,const struct dirent ** b)428 int alphasort(const struct dirent **a, const struct dirent **b)
429 {
430 return strcoll((*a)->d_name, (*b)->d_name);
431 }
432
rindex(const char * s,int c)433 char *rindex(const char *s, int c)
434 {
435 if (s == NULL) {
436 return NULL;
437 }
438
439 /* Don't bother tracing - strrchr can do that */
440 return (char *)strrchr(s, c);
441 }
442
ls_get_fullpath(const char * path,struct dirent * pdirent)443 static char *ls_get_fullpath(const char *path, struct dirent *pdirent)
444 {
445 char *fullpath = NULL;
446 int ret;
447
448 if (path[1] != '\0') {
449 /* 2, The position of the path character: / and the end character '/0' */
450 fullpath = (char *)malloc(strlen(path) + strlen(pdirent->d_name) + 2);
451 if (fullpath == NULL) {
452 goto exit_with_nomem;
453 }
454
455 /* 2, The position of the path character: / and the end character '/0' */
456 ret = snprintf_s(fullpath, strlen(path) + strlen(pdirent->d_name) + 2,
457 strlen(path) + strlen(pdirent->d_name) + 1, "%s/%s", path, pdirent->d_name);
458 if (ret < 0) {
459 free(fullpath);
460 set_errno(ENAMETOOLONG);
461 return NULL;
462 }
463 } else {
464 /* 2, The position of the path character: / and the end character '/0' */
465 fullpath = (char *)malloc(strlen(pdirent->d_name) + 2);
466 if (fullpath == NULL) {
467 goto exit_with_nomem;
468 }
469
470 /* 2, The position of the path character: / and the end character '/0' */
471 ret = snprintf_s(fullpath, strlen(pdirent->d_name) + 2, strlen(pdirent->d_name) + 1,
472 "/%s", pdirent->d_name);
473 if (ret < 0) {
474 free(fullpath);
475 set_errno(ENAMETOOLONG);
476 return NULL;
477 }
478 }
479 return fullpath;
480
481 exit_with_nomem:
482 set_errno(ENOSPC);
483 return (char *)NULL;
484 }
485
PrintFileInfo64(const struct stat64 * stat64Info,const char * name)486 static void PrintFileInfo64(const struct stat64 *stat64Info, const char *name)
487 {
488 mode_t mode;
489 char str[UGO_NUMS][UGO_NUMS + 1] = {0};
490 char dirFlag;
491 int i;
492
493 for (i = 0; i < UGO_NUMS; i++) {
494 mode = stat64Info->st_mode >> (uint)(USER_MODE_SHIFT - i * UGO_NUMS);
495 str[i][0] = (mode & READ_OP) ? 'r' : '-';
496 str[i][1] = (mode & WRITE_OP) ? 'w' : '-';
497 str[i][UGO_NUMS - 1] = (mode & EXEC_OP) ? 'x' : '-';
498 }
499
500 if (S_ISDIR(stat64Info->st_mode)) {
501 dirFlag = 'd';
502 } else if (S_ISLNK(stat64Info->st_mode)) {
503 dirFlag = 'l';
504 } else {
505 dirFlag = '-';
506 }
507
508 PRINTK("%c%s%s%s %-8lld u:%-5d g:%-5d %-10s\n", dirFlag,
509 str[0], str[1], str[UGO_NUMS - 1], stat64Info->st_size, stat64Info->st_uid, stat64Info->st_gid, name);
510 }
511
PrintFileInfo(const struct stat * statInfo,const char * name)512 static void PrintFileInfo(const struct stat *statInfo, const char *name)
513 {
514 mode_t mode;
515 char str[UGO_NUMS][UGO_NUMS + 1] = {0};
516 char dirFlag;
517 int i;
518
519 for (i = 0; i < UGO_NUMS; i++) {
520 mode = statInfo->st_mode >> (uint)(USER_MODE_SHIFT - i * UGO_NUMS);
521 str[i][0] = (mode & READ_OP) ? 'r' : '-';
522 str[i][1] = (mode & WRITE_OP) ? 'w' : '-';
523 str[i][UGO_NUMS - 1] = (mode & EXEC_OP) ? 'x' : '-';
524 }
525
526 if (S_ISDIR(statInfo->st_mode)) {
527 dirFlag = 'd';
528 } else if (S_ISLNK(statInfo->st_mode)) {
529 dirFlag = 'l';
530 } else {
531 dirFlag = '-';
532 }
533
534 PRINTK("%c%s%s%s %-8lld u:%-5d g:%-5d %-10s\n", dirFlag,
535 str[0], str[1], str[UGO_NUMS - 1], statInfo->st_size, statInfo->st_uid, statInfo->st_gid, name);
536 }
537
LsFile(const char * path)538 int LsFile(const char *path)
539 {
540 struct stat64 stat64Info;
541 struct stat statInfo;
542
543 if (stat64(path, &stat64Info) == 0) {
544 PrintFileInfo64(&stat64Info, path);
545 } else if (stat(path, &statInfo) == 0) {
546 PrintFileInfo(&statInfo, path);
547 } else {
548 return -1;
549 }
550
551 return 0;
552 }
553
LsDir(const char * path)554 int LsDir(const char *path)
555 {
556 struct stat statInfo = { 0 };
557 struct stat64 stat64Info = { 0 };
558 DIR *d = NULL;
559 char *fullpath = NULL;
560 char *fullpath_bak = NULL;
561 struct dirent *pdirent = NULL;
562
563 d = opendir(path);
564 if (d == NULL) {
565 return -1;
566 }
567
568 PRINTK("Directory %s:\n", path);
569 do {
570 pdirent = readdir(d);
571 if (pdirent == NULL) {
572 break;
573 } else {
574 if (!strcmp(pdirent->d_name, ".") || !strcmp(pdirent->d_name, "..")) {
575 continue;
576 }
577 (void)memset_s(&statInfo, sizeof(struct stat), 0, sizeof(struct stat));
578 (void)memset_s(&stat64Info, sizeof(struct stat), 0, sizeof(struct stat));
579 fullpath = ls_get_fullpath(path, pdirent);
580 if (fullpath == NULL) {
581 (void)closedir(d);
582 return -1;
583 }
584
585 fullpath_bak = fullpath;
586 if (stat64(fullpath, &stat64Info) == 0) {
587 PrintFileInfo64(&stat64Info, pdirent->d_name);
588 } else if (stat(fullpath, &statInfo) == 0) {
589 PrintFileInfo(&statInfo, pdirent->d_name);
590 } else {
591 PRINTK("BAD file: %s\n", pdirent->d_name);
592 }
593 free(fullpath_bak);
594 }
595 } while (1);
596 (void)closedir(d);
597
598 return 0;
599 }
600
ls(const char * pathname)601 void ls(const char *pathname)
602 {
603 struct stat statInfo = { 0 };
604 char *path = NULL;
605 int ret;
606
607 if (pathname == NULL) {
608 #ifdef VFS_USING_WORKDIR
609 UINTPTR lock_flags;
610 LosProcessCB *curr = OsCurrProcessGet();
611
612 /* open current working directory */
613
614 spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
615 path = strdup(curr->files->workdir);
616 spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
617 #else
618 path = strdup("/");
619 #endif
620 if (path == NULL) {
621 return;
622 }
623 } else {
624 ret = vfs_normalize_path(NULL, pathname, &path);
625 if (ret < 0) {
626 set_errno(-ret);
627 return;
628 }
629 }
630
631 ret = stat(path, &statInfo);
632 if (ret < 0) {
633 perror("ls error");
634 free(path);
635 return;
636 }
637
638 if (statInfo.st_mode & S_IFDIR) { /* list all directory and file */
639 ret = LsDir((pathname == NULL) ? path : pathname);
640 } else { /* show the file information */
641 ret = LsFile(path);
642 }
643 if (ret < 0) {
644 perror("ls error");
645 }
646
647 free(path);
648 return;
649 }
650
651
realpath(const char * path,char * resolved_path)652 char *realpath(const char *path, char *resolved_path)
653 {
654 int ret, result;
655 char *new_path = NULL;
656 struct stat buf;
657
658 ret = vfs_normalize_path(NULL, path, &new_path);
659 if (ret < 0) {
660 ret = -ret;
661 set_errno(ret);
662 return NULL;
663 }
664
665 result = stat(new_path, &buf);
666
667 if (resolved_path == NULL) {
668 if (result != ENOERR) {
669 free(new_path);
670 return NULL;
671 }
672 return new_path;
673 }
674
675 ret = strcpy_s(resolved_path, PATH_MAX, new_path);
676 if (ret != EOK) {
677 ret = -ret;
678 set_errno(ret);
679 free(new_path);
680 return NULL;
681 }
682
683 free(new_path);
684 if (result != ENOERR) {
685 return NULL;
686 }
687 return resolved_path;
688 }
689
lsfd(void)690 void lsfd(void)
691 {
692 struct filelist *f_list = NULL;
693 unsigned int i = 3; /* file start fd */
694 int ret;
695 struct Vnode *node = NULL;
696
697 f_list = &tg_filelist;
698
699 PRINTK(" fd filename\n");
700 ret = sem_wait(&f_list->fl_sem);
701 if (ret < 0) {
702 PRINTK("sem_wait error, ret=%d\n", ret);
703 return;
704 }
705
706 while (i < CONFIG_NFILE_DESCRIPTORS) {
707 node = files_get_openfile(i);
708 if (node) {
709 PRINTK("%5d %s\n", i, f_list->fl_files[i].f_path);
710 }
711 i++;
712 }
713 (void)sem_post(&f_list->fl_sem);
714 }
715
GetUmask(void)716 mode_t GetUmask(void)
717 {
718 return OsCurrProcessGet()->umask;
719 }
720
SysUmask(mode_t mask)721 mode_t SysUmask(mode_t mask)
722 {
723 UINT32 intSave;
724 mode_t umask;
725 mode_t oldUmask;
726 umask = mask & UMASK_FULL;
727 SCHEDULER_LOCK(intSave);
728 oldUmask = OsCurrProcessGet()->umask;
729 OsCurrProcessGet()->umask = umask;
730 SCHEDULER_UNLOCK(intSave);
731 return oldUmask;
732 }
733
734