• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this list of
8  *    conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11  *    of conditions and the following disclaimer in the documentation and/or other materials
12  *    provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15  *    to endorse or promote products derived from this software without specific prior written
16  *    permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "unistd.h"
32 #include "errno.h"
33 #include "vnode.h"
34 #include "path_cache.h"
35 
follow_symlink(int dirfd,const char * path,struct Vnode ** vnode,char ** fullpath)36 int follow_symlink(int dirfd, const char *path, struct Vnode **vnode, char **fullpath)
37 {
38   int ret;
39   struct Vnode *newvnode = NULL;
40   char pathname[PATH_MAX] = {0};
41 
42   (void)strcpy_s(pathname, PATH_MAX, path);
43 
44   for (int i = 0; i < CONFIG_FS_MAX_LNK_CNT; i++)
45     {
46       if (*fullpath)
47         {
48           free(*fullpath);
49           *fullpath = NULL;
50         }
51 
52       ret = vfs_normalize_pathat(dirfd, pathname, fullpath);
53       if (ret < 0)
54         {
55           return ret;
56         }
57 
58       ret = VnodeLookup(*fullpath, &newvnode, 0);
59       if (ret != OK)
60         {
61           /* The object of fullpath is not exist. Return its parent's vnode. */
62           *vnode = newvnode;
63           return ret;
64         }
65       if (newvnode->type != VNODE_TYPE_LNK)
66         {
67           /* The object of fullpath is exist, and is not a symbol link. Return its vnode. */
68           *vnode = newvnode;
69           return ret;
70         }
71       if (newvnode->vop->Readlink == NULL)
72         {
73           ret = -ENOSYS;
74           return ret;
75         }
76 
77       /* The object of fullpath is a symbol link. Read its target and find the source file successively. */
78       (void)memset_s(pathname, PATH_MAX, 0, PATH_MAX);
79       ret = newvnode->vop->Readlink(newvnode, pathname, PATH_MAX);
80       if (ret < 0)
81         {
82           return ret;
83         }
84     }
85 
86   /* Failed to find the source file in CONFIG_FS_MAX_LNK_CNT times. */
87   return -ELOOP;
88 }
89 
do_symlink(const char * target,int newfd,const char * path)90 int do_symlink(const char *target, int newfd, const char *path)
91 {
92   struct Vnode *parent_vnode = NULL;
93   struct Vnode *new_vnode = NULL;
94   char *fullpath = NULL;
95   char *newname = NULL;
96   struct Mount *mount = NULL;
97   int ret;
98 
99   if (!path)
100     {
101       ret = -EFAULT;
102       goto errout;
103     }
104 
105   if (*path == '\0')
106     {
107       ret = -EINVAL;
108       goto errout;
109     }
110 
111   if (strlen(target) >= PATH_MAX)
112     {
113       ret = -ENAMETOOLONG;
114       goto errout;
115     }
116 
117   ret = vfs_normalize_pathat(newfd, path, &fullpath);
118   if (ret < 0)
119     {
120       goto errout;
121     }
122 
123   newname = strrchr(fullpath, '/') + 1;
124 
125   VnodeHold();
126   ret = VnodeLookup(fullpath, &parent_vnode, 0);
127   if (ret == 0)
128     {
129       ret = -EEXIST;
130       goto errout_with_vnode;
131     }
132 
133   if (!parent_vnode->vop || !parent_vnode->vop->Symlink)
134     {
135       ret = -ENOSYS;
136       goto errout_with_vnode;
137     }
138   mount = parent_vnode->originMount;
139   if ((mount != NULL) && (mount->mountFlags & MS_RDONLY))
140     {
141       ret = -EROFS;
142       goto errout_with_vnode;
143     }
144 
145   parent_vnode->useCount++;
146   ret = parent_vnode->vop->Symlink(parent_vnode, &new_vnode, (const char *)newname, (const char *)target);
147   parent_vnode->useCount--;
148   if (ret < 0)
149     {
150       goto errout_with_vnode;
151     }
152 
153   PathCacheAlloc(parent_vnode, new_vnode, newname, strlen(newname));
154   VnodeDrop();
155 
156   free(fullpath);
157 
158   return OK;
159 
160 errout_with_vnode:
161   VnodeDrop();
162   free(fullpath);
163 errout:
164   set_errno(-ret);
165   return VFS_ERROR;
166 }
167 
symlink(const char * target,const char * path)168 int symlink(const char *target, const char *path)
169 {
170   return do_symlink(target, AT_FDCWD, path);
171 }
172 
symlinkat(const char * target,int newdirfd,const char * path)173 int symlinkat(const char *target, int newdirfd, const char *path)
174 {
175   return do_symlink(target, newdirfd, path);
176 }
177