• 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 = (char *)path;
41   char buffer[PATH_MAX] = {0};
42 
43   if (path == NULL) {
44       return -EINVAL;
45   }
46 
47   for (int i = 0; i < CONFIG_FS_MAX_LNK_CNT; i++)
48     {
49       if (*fullpath)
50         {
51           free(*fullpath);
52           *fullpath = NULL;
53         }
54 
55       ret = vfs_normalize_pathat(dirfd, pathname, fullpath);
56       if (ret < 0)
57         {
58           return ret;
59         }
60 
61       ret = VnodeLookupFullpath(*fullpath, &newvnode, 0);
62       if (ret != OK)
63         {
64           /* The object of fullpath is not exist. Return its parent's vnode. */
65           *vnode = newvnode;
66           return ret;
67         }
68       if (newvnode->type != VNODE_TYPE_LNK)
69         {
70           /* The object of fullpath is exist, and is not a symbol link. Return its vnode. */
71           *vnode = newvnode;
72           return ret;
73         }
74       if (newvnode->vop->Readlink == NULL)
75         {
76           ret = -ENOSYS;
77           return ret;
78         }
79 
80       /* The object of fullpath is a symbol link. Read its target and find the source file successively. */
81       pathname = buffer;
82       ret = newvnode->vop->Readlink(newvnode, pathname, PATH_MAX);
83       if (ret < 0)
84         {
85           return ret;
86         }
87     }
88 
89   /* Failed to find the source file in CONFIG_FS_MAX_LNK_CNT times. */
90   return -ELOOP;
91 }
92 
do_symlink(const char * target,int newfd,const char * path)93 int do_symlink(const char *target, int newfd, const char *path)
94 {
95   struct Vnode *parent_vnode = NULL;
96   struct Vnode *new_vnode = NULL;
97   char *fullpath = NULL;
98   char *newname = NULL;
99   struct Mount *mount = NULL;
100   int ret;
101 
102   if (!path)
103     {
104       ret = -EFAULT;
105       goto errout;
106     }
107 
108   if (*path == '\0')
109     {
110       ret = -EINVAL;
111       goto errout;
112     }
113 
114   if (strlen(target) >= PATH_MAX)
115     {
116       ret = -ENAMETOOLONG;
117       goto errout;
118     }
119 
120   ret = vfs_normalize_pathat(newfd, path, &fullpath);
121   if (ret < 0)
122     {
123       goto errout;
124     }
125 
126   newname = strrchr(fullpath, '/') + 1;
127 
128   VnodeHold();
129   ret = VnodeLookup(fullpath, &parent_vnode, 0);
130   if (ret == 0)
131     {
132       ret = -EEXIST;
133       goto errout_with_vnode;
134     }
135 
136   if (!parent_vnode->vop || !parent_vnode->vop->Symlink)
137     {
138       ret = -ENOSYS;
139       goto errout_with_vnode;
140     }
141   mount = parent_vnode->originMount;
142   if ((mount != NULL) && (mount->mountFlags & MS_RDONLY))
143     {
144       ret = -EROFS;
145       goto errout_with_vnode;
146     }
147 
148   parent_vnode->useCount++;
149   ret = parent_vnode->vop->Symlink(parent_vnode, &new_vnode, (const char *)newname, (const char *)target);
150   parent_vnode->useCount--;
151   if (ret < 0)
152     {
153       goto errout_with_vnode;
154     }
155 
156   PathCacheAlloc(parent_vnode, new_vnode, newname, strlen(newname));
157   VnodeDrop();
158 
159   free(fullpath);
160 
161   return OK;
162 
163 errout_with_vnode:
164   VnodeDrop();
165   free(fullpath);
166 errout:
167   set_errno(-ret);
168   return VFS_ERROR;
169 }
170 
symlink(const char * target,const char * path)171 int symlink(const char *target, const char *path)
172 {
173   return do_symlink(target, AT_FDCWD, path);
174 }
175 
symlinkat(const char * target,int newdirfd,const char * path)176 int symlinkat(const char *target, int newdirfd, const char *path)
177 {
178   return do_symlink(target, newdirfd, path);
179 }
180