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_config.h"
33
34#include "los_task.h"
35#include "shell.h"
36#include "sys/stat.h"
37#include "stdlib.h"
38#include "unistd.h"
39#include "fcntl.h"
40#include "stdio.h"
41#include "pthread.h"
42
43#include "shcmd.h"
44#include "securec.h"
45#include "show.h"
46
47#include <dirent.h>
48#include <ctype.h>
49
50#define VFS_ERROR OS_ERROR
51#define SHOW_MAX_LEN CMD_MAX_LEN
52#define TEMP_PATH_MAX (PATH_MAX + SHOW_MAX_LEN)
53
54typedef enum {
55    RM_RECURSIVER,
56    RM_FILE,
57    RM_DIR,
58    CP_FILE,
59    CP_COUNT
60} wildcard_type;
61
62#define ERROR_OUT_IF(condition, message_function, handler) \
63    do { \
64        if (condition) { \
65            message_function; \
66            handler; \
67        } \
68    } while (0)
69
70INT32 OsShellCmdDoChdir(const CHAR *path)
71{
72    CHAR *fullpath = NULL;
73    CHAR *fullpathBak = NULL;
74    DIR *dirent = NULL;
75    INT32 ret;
76    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
77    if (shellWorkingDirectory == NULL) {
78        return -1;
79    }
80
81    if (path == NULL) {
82        LOS_TaskLock();
83        PRINTK("%s\n", shellWorkingDirectory);
84        LOS_TaskUnlock();
85        return 0;
86    }
87
88    ERROR_OUT_IF(strlen(path) > PATH_MAX, SetErr(ENOTDIR, "cd error"), return -1);
89
90    ret = VfsNormalizePath(shellWorkingDirectory, path, &fullpath);
91    ERROR_OUT_IF(ret < 0, SetErr(-ret, "cd error"), return -1);
92
93    fullpathBak = fullpath;
94    dirent = opendir(fullpath);
95    if (dirent == NULL) {
96        free(fullpathBak);
97        /* this is a not exist directory */
98        PRINTK("no such file or directory\n");
99        return -1;
100    }
101
102    /* close directory stream */
103    (VOID)closedir(dirent);
104
105    /* copy full path to working directory */
106    LOS_TaskLock();
107    ret = strncpy_s(shellWorkingDirectory, PATH_MAX, fullpath, strlen(fullpath));
108    if (ret != EOK) {
109        free(fullpathBak);
110        LOS_TaskUnlock();
111        return -1;
112    }
113    LOS_TaskUnlock();
114    /* release normalize directory path name */
115
116    free(fullpathBak);
117    return 0;
118}
119
120STATIC CHAR *OsLsGetFullpath(const CHAR *path, struct dirent *pdirent)
121{
122    CHAR *fullpath = NULL;
123    INT32 ret;
124    size_t pathLen;
125
126    if (path[1] != '\0') {
127        pathLen = strlen(path) + strlen(pdirent->d_name) + 2; /* 2, path + '/' + d_name + '\0' */
128        fullpath = (CHAR *)malloc(pathLen);
129        if (fullpath == NULL) {
130            goto exit_with_nomem;
131        }
132
133        ret = snprintf_s(fullpath, pathLen, pathLen - 1, "%s/%s", path, pdirent->d_name);
134        if (ret < 0) {
135            free(fullpath);
136            return NULL;
137        }
138    } else {
139        pathLen = strlen(pdirent->d_name) + 2; /* 2, '/' + d_name + '\0' */
140        fullpath = (CHAR *)malloc(pathLen);
141        if (fullpath == NULL) {
142            goto exit_with_nomem;
143        }
144
145        ret = snprintf_s(fullpath, pathLen, pathLen, "/%s", pdirent->d_name);
146        if (ret < 0) {
147            free(fullpath);
148            return NULL;
149        }
150    }
151
152    return fullpath;
153exit_with_nomem:
154    return (CHAR *)NULL;
155}
156
157VOID OsLs(const CHAR *pathname)
158{
159    struct dirent *pdirent = NULL;
160    CHAR *path = NULL;
161    CHAR *fullpath = NULL;
162    CHAR *fullpathBak = NULL;
163    INT32 ret;
164    struct stat statInfo = { 0 };
165    DIR *d = NULL;
166
167    /* list all directory and file */
168    if (pathname == NULL) {
169        path = strdup("/");
170        if (path == NULL) {
171            return;
172        }
173    } else {
174        ret = VfsNormalizePath(NULL, pathname, &path);
175        if (ret < 0) {
176            SetErrno(-ret);
177            return;
178        }
179    }
180
181    d = opendir(path);
182    if (d == NULL) {
183        PRINT_ERR("No such directory = %s\n", path);
184        free(path);
185    } else {
186        PRINTK("Directory %s:\n", path);
187        do {
188            pdirent = readdir(d);
189            if (pdirent != NULL) {
190                (VOID)memset_s(&statInfo, sizeof(struct stat), 0, sizeof(struct stat));
191                fullpath = OsLsGetFullpath(path, pdirent);
192                if (fullpath == NULL) {
193                    free(path);
194                    (VOID)closedir(d);
195                    return;
196                }
197
198                fullpathBak = fullpath;
199                if (stat(fullpath, &statInfo) == 0) {
200                    PRINTK("%-20s", pdirent->d_name);
201                    if (S_ISDIR(statInfo.st_mode)) {
202                        PRINTK(" %-25s\n", "<DIR>");
203                    } else {
204                        PRINTK(" %-25lu\n", statInfo.st_size);
205                    }
206                } else {
207                    PRINTK("BAD file: %s\n", pdirent->d_name);
208                }
209                free(fullpathBak);
210            }
211        } while (pdirent != NULL);
212
213        free(path);
214        (VOID)closedir(d);
215    }
216}
217
218INT32 OsShellCmdLs(INT32 argc, const CHAR **argv)
219{
220    CHAR *fullpath = NULL;
221    const CHAR *filename = NULL;
222    INT32 ret;
223    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
224    if (shellWorkingDirectory == NULL) {
225        return -1;
226    }
227
228    ERROR_OUT_IF(argc > 1, PRINTK("ls or ls [DIRECTORY]\n"), return -1);
229
230    if (argc == 0) {
231        OsLs(shellWorkingDirectory);
232        return 0;
233    }
234
235    filename = argv[0];
236    ret = VfsNormalizePath(shellWorkingDirectory, filename, &fullpath);
237    ERROR_OUT_IF(ret < 0, SetErr(-ret, "ls error"), return -1);
238
239    OsLs(fullpath);
240    free(fullpath);
241
242    return 0;
243}
244
245INT32 OsShellCmdCd(INT32 argc, const CHAR **argv)
246{
247    if (argc == 0) {
248        (VOID)OsShellCmdDoChdir("/");
249        return 0;
250    }
251
252    OsShellCmdDoChdir(argv[0]);
253    return 0;
254}
255
256#define CAT_BUF_SIZE  512
257#define CAT_TASK_PRIORITY  10
258#define CAT_TASK_STACK_SIZE  0x3000
259pthread_mutex_t g_mutex_cat = PTHREAD_MUTEX_INITIALIZER;
260
261INT32 OsShellCmdCat(INT32 argc, const CHAR **argv)
262{
263    CHAR *fullpath = NULL;
264    INT32 ret;
265    CHAR buf[CAT_BUF_SIZE];
266    size_t size;
267
268    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
269
270    if (shellWorkingDirectory == NULL) {
271        return -1;
272    }
273
274    ERROR_OUT_IF(argc != 1, PRINTK("cat [FILE]\n"), return -1);
275
276    ret = VfsNormalizePath(shellWorkingDirectory, argv[0], &fullpath);
277    ERROR_OUT_IF(ret < 0, SetErr(-ret, "cat error"), return -1);
278
279    INT32 fd = open(fullpath, O_RDONLY, 0666);
280
281    if (fd == -1) {
282        ret = -1;
283        free(fullpath);
284        return ret;
285    }
286
287    do {
288        (VOID)memset_s(buf, sizeof(buf), 0, CAT_BUF_SIZE);
289        size = read(fd, buf, CAT_BUF_SIZE - 1);
290        if ((INT32)size < 0) {
291            free(fullpath);
292            close(fd);
293            return -1;
294        }
295        PRINTK("%s", buf);
296        (VOID)LOS_TaskDelay(1);
297    } while (size == CAT_BUF_SIZE - 1);
298
299    free(fullpath);
300    close(fd);
301
302    return ret;
303}
304
305INT32 OsShellCmdMkdir(INT32 argc, const CHAR **argv)
306{
307    INT32 ret;
308    CHAR *fullpath = NULL;
309    const CHAR *filename = NULL;
310    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
311    if (shellWorkingDirectory == NULL) {
312        return -1;
313    }
314
315    ERROR_OUT_IF(argc != 1, PRINTK("mkdir [DIRECTORY]\n"), return 0);
316
317    filename = argv[0];
318    ret = VfsNormalizePath(shellWorkingDirectory, filename, &fullpath);
319    ERROR_OUT_IF(ret < 0, SetErr(-ret, "mkdir error"), return -1);
320
321    ret = mkdir(fullpath, S_IRWXU | S_IRWXG | S_IRWXO);
322    if (ret == -1) {
323        perror("mkdir error");
324    }
325    free(fullpath);
326    return 0;
327}
328
329INT32 OsShellCmdPwd(INT32 argc, const CHAR **argv)
330{
331    CHAR buf[SHOW_MAX_LEN] = {0};
332    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
333    if (shellWorkingDirectory == NULL) {
334        return -1;
335    }
336
337    ERROR_OUT_IF(argc > 0, PRINTK("\nUsage: pwd\n"), return -1);
338
339    LOS_TaskLock();
340    if (strncpy_s(buf, SHOW_MAX_LEN, shellWorkingDirectory, SHOW_MAX_LEN - 1) != EOK) {
341        LOS_TaskUnlock();
342        PRINTK("pwd error: strncpy_s error!\n");
343        return -1;
344    }
345    LOS_TaskUnlock();
346
347    PRINTK("%s\n", buf);
348    return 0;
349}
350
351INT32 OsShellCmdTouch(INT32 argc, const CHAR **argv)
352{
353    INT32 ret;
354    INT32 fd = -1;
355    CHAR *fullpath = NULL;
356    const CHAR *filename = NULL;
357    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
358    if (shellWorkingDirectory == NULL) {
359        return -1;
360    }
361
362    ERROR_OUT_IF(argc != 1, PRINTK("touch [FILE]\n"), return -1);
363
364    filename = argv[0];
365    ret = VfsNormalizePath(shellWorkingDirectory, filename, &fullpath);
366    ERROR_OUT_IF(ret < 0, SetErr(-ret, "touch error"), return -1);
367
368    fd = open(fullpath, O_RDWR | O_CREAT, 0777);
369    free(fullpath);
370    if (fd == -1) {
371        perror("touch error");
372        return -1;
373    }
374
375    (VOID)close(fd);
376    return 0;
377}
378
379#define CP_BUF_SIZE 4096
380pthread_mutex_t g_mutexCp = PTHREAD_MUTEX_INITIALIZER;
381
382STATIC INT32 OsShellCmdDoCp(const CHAR *srcFilePath, const CHAR *dstFileName)
383{
384    INT32  ret;
385    CHAR *srcFullPath = NULL;
386    CHAR *drcFullPath = NULL;
387    const CHAR *srcFileName = NULL;
388    CHAR *dstFilePath = NULL;
389    CHAR *buf = NULL;
390    const CHAR *filename = NULL;
391    ssize_t rdSize, wrSize;
392    INT32 srcFd = -1;
393    INT32 dstFd = -1;
394    struct stat statBuf;
395    mode_t srcMode;
396    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
397    if (shellWorkingDirectory == NULL) {
398        return -1;
399    }
400
401    buf = (CHAR *)malloc(CP_BUF_SIZE);
402    if (buf == NULL) {
403        PRINTK("cp error: Out of memory!\n");
404        return -1;
405    }
406
407    /* Get source fullpath. */
408    ret = VfsNormalizePath(shellWorkingDirectory, srcFilePath, &srcFullPath);
409    if (ret < 0) {
410        SetErrno(-ret);
411        PRINTK("cp error: %s\n", strerror(errno));
412        free(buf);
413        return -1;
414    }
415
416    /* Is source path exist? */
417    ret = stat(srcFullPath, &statBuf);
418    if (ret == -1) {
419        PRINTK("cp %s error: %s\n", srcFullPath, strerror(errno));
420        goto errout_with_srcpath;
421    }
422    srcMode = statBuf.st_mode;
423    /* Is source path a directory? */
424    if (S_ISDIR(statBuf.st_mode)) {
425        PRINTK("cp %s error: Source file can't be a directory.\n", srcFullPath);
426        goto errout_with_srcpath;
427    }
428
429    /* Get dest fullpath. */
430    drcFullPath = strdup(dstFileName);
431    if (drcFullPath == NULL) {
432        PRINTK("cp error: Out of memory.\n");
433        goto errout_with_srcpath;
434    }
435    /* Is dest path exist? */
436    ret = stat(drcFullPath, &statBuf);
437    if (ret == 0) {
438        /* Is dest path a directory? */
439        if (S_ISDIR(statBuf.st_mode)) {
440            /* Get source file name without '/'. */
441            srcFileName = srcFilePath;
442            while (1) {
443                filename = strchr(srcFileName, '/');
444                if (filename == NULL) {
445                    break;
446                }
447                srcFileName = filename + 1;
448            }
449            /* Add the source file after dest path. */
450            ret = VfsNormalizePath(drcFullPath, srcFileName, &dstFilePath);
451            if (ret < 0) {
452                SetErrno(-ret);
453                PRINTK("cp error. %s.\n", strerror(errno));
454                goto errout_with_path;
455            }
456            free(drcFullPath);
457            drcFullPath = dstFilePath;
458        }
459    }
460
461    /* Is dest file same as source file? */
462    if (strcmp(srcFullPath, drcFullPath) == 0) {
463        PRINTK("cp error: '%s' and '%s' are the same file\n", srcFullPath, drcFullPath);
464        goto errout_with_path;
465    }
466
467    /* Copy begins. */
468    (VOID)pthread_mutex_lock(&g_mutexCp);
469    srcFd = open(srcFullPath, O_RDONLY);
470    if (srcFd < 0) {
471        PRINTK("cp error: can't open %s. %s.\n", srcFullPath, strerror(errno));
472        goto errout_with_mutex;
473    }
474
475    dstFd = open(drcFullPath, O_CREAT | O_WRONLY | O_TRUNC, srcMode);
476    if (dstFd < 0) {
477        PRINTK("cp error: can't create %s. %s.\n", drcFullPath, strerror(errno));
478        goto errout_with_srcfd;
479    }
480
481    do {
482        (VOID)memset_s(buf, CP_BUF_SIZE, 0, CP_BUF_SIZE);
483        rdSize = read(srcFd, buf, CP_BUF_SIZE);
484        if (rdSize < 0) {
485            PRINTK("cp %s %s failed. %s.\n", srcFullPath, drcFullPath, strerror(errno));
486            goto errout_with_fd;
487        }
488        wrSize = write(dstFd, buf, rdSize);
489        if (wrSize != rdSize) {
490            PRINTK("cp %s %s failed. %s.\n", srcFullPath, drcFullPath, strerror(errno));
491            goto errout_with_fd;
492        }
493    } while (rdSize == CP_BUF_SIZE);
494
495    /* Release resource. */
496    free(buf);
497    free(srcFullPath);
498    free(drcFullPath);
499    (VOID)close(srcFd);
500    (VOID)close(dstFd);
501    (VOID)pthread_mutex_unlock(&g_mutexCp);
502    return LOS_OK;
503
504errout_with_fd:
505    (VOID)close(dstFd);
506errout_with_srcfd:
507    (VOID)close(srcFd);
508errout_with_mutex:
509    (VOID)pthread_mutex_unlock(&g_mutexCp);
510errout_with_path:
511    free(drcFullPath);
512errout_with_srcpath:
513    free(srcFullPath);
514    free(buf);
515    return -1;
516}
517
518/* The separator and EOF for a directory fullpath: '/'and '\0' */
519#define SEPARATOR_EOF_LEN 2
520
521STATIC INT32 OsShellCmdDoRmdir(const CHAR *pathname)
522{
523    struct dirent *dirent = NULL;
524    struct stat statInfo;
525    DIR *d = NULL;
526    CHAR *fullpath = NULL;
527    INT32 ret;
528
529    (VOID)memset_s(&statInfo, sizeof(statInfo), 0, sizeof(struct stat));
530    if (stat(pathname, &statInfo) != 0) {
531        return -1;
532    }
533
534    if (S_ISREG(statInfo.st_mode) || S_ISLNK(statInfo.st_mode)) {
535        return remove(pathname);
536    }
537    d = opendir(pathname);
538    if (d == NULL) {
539        return -1;
540    }
541    while (1) {
542        dirent = readdir(d);
543        if (dirent == NULL) {
544            break;
545        }
546        if (strcmp(dirent->d_name, "..") && strcmp(dirent->d_name, ".")) {
547            size_t fullPathBufSize = strlen(pathname) + strlen(dirent->d_name) + SEPARATOR_EOF_LEN;
548            fullpath = (CHAR *)malloc(fullPathBufSize);
549            if (fullpath == NULL) {
550                PRINTK("malloc failure!\n");
551                (VOID)closedir(d);
552                return -1;
553            }
554            ret = snprintf_s(fullpath, fullPathBufSize, fullPathBufSize - 1, "%s/%s", pathname, dirent->d_name);
555            if (ret < 0) {
556                PRINTK("name is too long!\n");
557                free(fullpath);
558                (VOID)closedir(d);
559                return -1;
560            }
561            (VOID)OsShellCmdDoRmdir(fullpath);
562            free(fullpath);
563        }
564    }
565    (VOID)closedir(d);
566    return rmdir(pathname);
567}
568
569/*  Wildcard matching operations  */
570STATIC INT32 OsWildcardMatch(const CHAR *src, const CHAR *filename)
571{
572    INT32 ret;
573
574    if (*src != '\0') {
575        if (*filename == '*') {
576            while ((*filename == '*') || (*filename == '?')) {
577                filename++;
578            }
579
580            if (*filename == '\0') {
581                return 0;
582            }
583
584            while (*src != '\0' && !(*src == *filename)) {
585                src++;
586            }
587
588            if (*src == '\0') {
589                return -1;
590            }
591
592            ret = OsWildcardMatch(src, filename);
593
594            while ((ret != 0) && (*(++src) != '\0')) {
595                if (*src == *filename) {
596                    ret = OsWildcardMatch(src, filename);
597                }
598            }
599            return ret;
600        } else {
601            if ((*src == *filename) || (*filename == '?')) {
602                return OsWildcardMatch(++src, ++filename);
603            }
604            return -1;
605        }
606    }
607
608    while (*filename != '\0') {
609        if (*filename != '*') {
610            return -1;
611        }
612        filename++;
613    }
614    return 0;
615}
616
617/*   To determine whether a wildcard character exists in a path   */
618STATIC INT32 OsIsContainersWildcard(const CHAR *filename)
619{
620    while (*filename != '\0') {
621        if ((*filename == '*') || (*filename == '?')) {
622            return 1;
623        }
624        filename++;
625    }
626    return 0;
627}
628
629/*  Delete a non directory file  */
630STATIC INT32 OsRmFileOnly(const CHAR *fullpath)
631{
632    struct stat statInfo = {0};
633    INT32 ret = stat(fullpath, &statInfo);
634    if (ret == 0) {
635        if (!S_ISDIR(statInfo.st_mode)) {
636            ret = unlink(fullpath);
637        } else {
638            ret = 0;
639            PRINTK("rm: cannot remove '%s': Is a directory\n", fullpath);
640        }
641    } else {
642        PRINTK("stat: get '%s' statInfo fail!\n", fullpath);
643    }
644    return ret;
645}
646
647/*  Delete a matching file or directory  */
648
649STATIC INT32 OsWildcardDeleteFileOrDir(const CHAR *fullpath, wildcard_type mark)
650{
651    INT32 ret;
652
653    switch (mark) {
654        case RM_RECURSIVER:
655            ret = OsShellCmdDoRmdir(fullpath);
656            break;
657        case RM_FILE:
658            ret = OsRmFileOnly(fullpath);
659            break;
660        case RM_DIR:
661            ret = rmdir(fullpath);
662            break;
663        default:
664            return (INT32)VFS_ERROR;
665    }
666    if (ret == -1) {
667        PRINTK("%s  ", fullpath);
668        perror("rm/rmdir error!");
669        return ret;
670    }
671    return 0;
672}
673
674/*  Split the path with wildcard characters  */
675
676STATIC CHAR *OsWildcardSplitPath(CHAR *fullpath, CHAR **handle, CHAR **wait)
677{
678    INT32 n;
679    INT32 a = 0;
680    INT32 b = 0;
681    INT32 len  = strlen(fullpath);
682
683    for (n = 0; n < len; n++) {
684        if (fullpath[n] == '/') {
685            if (b != 0) {
686                fullpath[n] = '\0';
687                *wait = fullpath + n + 1;
688                break;
689            }
690            a = n;
691        } else if (fullpath[n] == '*' || fullpath[n] == '?') {
692            b = n;
693            fullpath[a] = '\0';
694            if (a == 0) {
695                *handle = fullpath + a + 1;
696                continue;
697            }
698            *handle = fullpath + a + 1;
699        }
700    }
701    return fullpath;
702}
703
704/*  Handling entry of the path with wildcard characters  */
705
706STATIC INT32 OsWildcardExtractDirectory(CHAR *fullpath, VOID *dst, wildcard_type mark)
707{
708    CHAR separator[] = "/";
709    CHAR src[PATH_MAX] = {0};
710    struct dirent *dirent = NULL;
711    CHAR *f = NULL;
712    CHAR *s = NULL;
713    CHAR *t = NULL;
714    INT32 ret = 0;
715    DIR *d = NULL;
716    struct stat statBuf;
717    INT32 deleteFlag = 0;
718
719    f = OsWildcardSplitPath(fullpath, &s, &t);
720
721    if (s == NULL) {
722        if (mark == CP_FILE) {
723            ret = OsShellCmdDoCp(fullpath, dst);
724        } else if (mark == CP_COUNT) {
725            ret = stat(fullpath, &statBuf);
726            if (ret == 0 && (S_ISREG(statBuf.st_mode) || S_ISLNK(statBuf.st_mode))) {
727                (*(INT32 *)dst)++;
728            }
729        } else {
730            ret = OsWildcardDeleteFileOrDir(fullpath, mark);
731        }
732        return ret;
733    }
734
735    d = (*f == '\0') ? opendir("/") : opendir(f);
736
737    if (d == NULL) {
738        perror("opendir error");
739        return (INT32)VFS_ERROR;
740    }
741
742    while (1) {
743        dirent = readdir(d);
744        if (dirent == NULL) {
745            break;
746        }
747
748        if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) {
749            continue;
750        }
751
752        ret = strcpy_s(src, PATH_MAX, f);
753        if (ret != EOK) {
754            goto closedir_out;
755        }
756
757        ret = OsWildcardMatch(dirent->d_name, s);
758        if (ret == 0) {
759            ret = strcat_s(src, sizeof(src), separator);
760            if (ret != EOK) {
761                goto closedir_out;
762            }
763            ret = strcat_s(src, sizeof(src), dirent->d_name);
764            if (ret != EOK) {
765                goto closedir_out;
766            }
767            if (t == NULL) {
768                if (mark == CP_FILE) {
769                    ret = OsShellCmdDoCp(src, dst);
770                } else if (mark == CP_COUNT) {
771                    ret = stat(src, &statBuf);
772                    if (ret == 0 && (S_ISREG(statBuf.st_mode) || S_ISLNK(statBuf.st_mode))) {
773                        (*(INT32 *)dst)++;
774                        if ((*(INT32 *)dst) > 1) {
775                            break;
776                        }
777                    }
778                } else {
779                    ret = OsWildcardDeleteFileOrDir(src, mark);
780                    if (ret == 0) {
781                        deleteFlag = 1;
782                    }
783                }
784            } else {
785                ret = strcat_s(src, sizeof(src), separator);
786                if (ret != EOK) {
787                    goto closedir_out;
788                }
789                ret = strcat_s(src, sizeof(src), t);
790                if (ret != EOK) {
791                    goto closedir_out;
792                }
793                ret = OsWildcardExtractDirectory(src, dst, mark);
794                if (mark == CP_COUNT && (*(INT32 *)dst) > 1) {
795                    break;
796                }
797            }
798        }
799    }
800    (VOID)closedir(d);
801    if (deleteFlag == 1) {
802        ret = 0;
803    }
804    return ret;
805closedir_out:
806    (VOID)closedir(d);
807    return (INT32)VFS_ERROR;
808}
809
810INT32 OsShellCmdCp(INT32 argc, const CHAR **argv)
811{
812    INT32  ret;
813    const CHAR *src = NULL;
814    const CHAR *dst = NULL;
815    CHAR *srcFullPath = NULL;
816    CHAR *drcFullPath = NULL;
817    struct stat statBuf;
818    INT32 count = 0;
819    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
820    if (shellWorkingDirectory == NULL) {
821        return -1;
822    }
823
824    ERROR_OUT_IF(argc < 2, PRINTK("cp [SOURCEFILE] [DESTFILE]\n"), return -1);
825
826    src = argv[0];
827    dst = argv[1];
828
829    /* Get source fullpath. */
830
831    ret = VfsNormalizePath(shellWorkingDirectory, src, &srcFullPath);
832    if (ret < 0) {
833        SetErrno(-ret);
834        PRINTK("cp error:%s\n", strerror(errno));
835        return -1;
836    }
837
838    if (src[strlen(src) - 1] == '/') {
839        PRINTK("cp %s error: Source file can't be a directory.\n", src);
840        goto errout_with_srcpath;
841    }
842
843    /* Get dest fullpath. */
844    ret = VfsNormalizePath(shellWorkingDirectory, dst, &drcFullPath);
845    if (ret < 0) {
846        SetErrno(-ret);
847        PRINTK("cp error: can't open %s. %s\n", dst, strerror(errno));
848        goto errout_with_srcpath;
849    }
850
851    /* Is dest path exist? */
852
853    ret = stat(drcFullPath, &statBuf);
854    if (ret < 0) {
855        /* Is dest path a directory? */
856        if (dst[strlen(dst) - 1] == '/') {
857            PRINTK("cp error: %s, %s.\n", drcFullPath, strerror(errno));
858            goto errout_with_path;
859        }
860    } else {
861        if ((S_ISREG(statBuf.st_mode) || S_ISLNK(statBuf.st_mode)) && dst[strlen(dst) - 1] == '/') {
862            PRINTK("cp error: %s is not a directory.\n", drcFullPath);
863            goto errout_with_path;
864        }
865    }
866
867    if (OsIsContainersWildcard(srcFullPath)) {
868        if (ret < 0 || S_ISREG(statBuf.st_mode) || S_ISLNK(statBuf.st_mode)) {
869            CHAR *srcCopy = strdup(srcFullPath);
870            if (srcCopy == NULL) {
871                PRINTK("cp error : Out of memory.\n");
872                goto errout_with_path;
873            }
874            (VOID)OsWildcardExtractDirectory(srcCopy, &count, CP_COUNT);
875            free(srcCopy);
876            if (count > 1) {
877                PRINTK("cp error : Can not copy two or more files.\n");
878                goto errout_with_path;
879            }
880        }
881        ret = OsWildcardExtractDirectory(srcFullPath, drcFullPath, CP_FILE);
882    } else {
883        ret = OsShellCmdDoCp(srcFullPath, drcFullPath);
884    }
885    free(drcFullPath);
886    free(srcFullPath);
887    return ret;
888
889errout_with_path:
890    free(drcFullPath);
891errout_with_srcpath:
892    free(srcFullPath);
893    return (INT32)VFS_ERROR;
894}
895
896STATIC INLINE VOID PrintRmUsage(VOID)
897{
898    PRINTK("rm [FILE] or rm [-r/-R] [FILE]\n");
899}
900
901INT32 OsShellCmdRm(INT32 argc, const CHAR **argv)
902{
903    INT32  ret;
904    CHAR *fullpath = NULL;
905    const CHAR *filename = NULL;
906    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
907
908    if (shellWorkingDirectory == NULL) {
909        return -1;
910    }
911
912    ERROR_OUT_IF(argc != 1 && argc != 2, PrintRmUsage(), return -1);
913
914    if (argc == 2) {
915        ERROR_OUT_IF(strcmp(argv[0], "-r") != 0 && strcmp(argv[0], "-R") != 0, PrintRmUsage(), return -1);
916
917        filename = argv[1];
918        ret = VfsNormalizePath(shellWorkingDirectory, filename, &fullpath);
919        ERROR_OUT_IF(ret < 0, SetErr(-ret, "rm error"), return -1);
920
921        if (OsIsContainersWildcard(fullpath)) {
922            ret = OsWildcardExtractDirectory(fullpath, NULL, RM_RECURSIVER);
923        } else {
924            ret = OsShellCmdDoRmdir(fullpath);
925        }
926    } else {
927        filename = argv[0];
928        ret = VfsNormalizePath(shellWorkingDirectory, filename, &fullpath);
929        ERROR_OUT_IF(ret < 0, SetErr(-ret, "rm error"), return -1);
930
931        if (OsIsContainersWildcard(fullpath)) {
932            ret = OsWildcardExtractDirectory(fullpath, NULL, RM_FILE);
933        } else {
934            ret = OsRmFileOnly(fullpath);
935        }
936    }
937    if (ret == -1) {
938        perror("rm error");
939    }
940    free(fullpath);
941    return 0;
942}
943
944INT32 OsShellCmdRmdir(INT32 argc, const CHAR **argv)
945{
946    INT32  ret;
947    CHAR *fullpath = NULL;
948    const CHAR *filename = NULL;
949    CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory();
950    if (shellWorkingDirectory == NULL) {
951        return -1;
952    }
953
954    ERROR_OUT_IF(argc == 0, PRINTK("rmdir [DIRECTORY]\n"), return -1);
955
956    filename = argv[0];
957    ret = VfsNormalizePath(shellWorkingDirectory, filename, &fullpath);
958    ERROR_OUT_IF(ret < 0, SetErr(-ret, "rmdir error"), return -1);
959
960    if (OsIsContainersWildcard(fullpath)) {
961        ret = OsWildcardExtractDirectory(fullpath, NULL, RM_DIR);
962    } else {
963        ret = rmdir(fullpath);
964    }
965    if (ret == -1) {
966        PRINTK("rmdir %s failed. Error: %s.\n", fullpath, strerror(errno));
967    }
968    free(fullpath);
969
970    return 0;
971}
972
973