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
do_link(int oldfd,const char * oldpath,int newfd,const char * newpath,int flag)36 int do_link(int oldfd, const char *oldpath, int newfd, const char *newpath, int flag)
37 {
38 struct Vnode *new_parent_vnode = NULL;
39 struct Vnode *new_vnode = NULL;
40 struct Vnode *old_vnode = NULL;
41 struct Mount *mount = NULL;
42 char *fulloldpath = NULL;
43 char *fullnewpath = NULL;
44 char *newname = NULL;
45 int ret;
46
47 if (!oldpath || !newpath)
48 {
49 ret = -EFAULT;
50 goto errout;
51 }
52
53 if (*oldpath == '\0' || *newpath == '\0' || flag & ~AT_SYMLINK_FOLLOW)
54 {
55 ret = -EINVAL;
56 goto errout;
57 }
58
59 ret = vfs_normalize_pathat(newfd, newpath, &fullnewpath);
60 if (ret < 0)
61 {
62 goto errout;
63 }
64
65 if (!(flag & AT_SYMLINK_FOLLOW))
66 {
67 ret = vfs_normalize_pathat(oldfd, oldpath, &fulloldpath);
68 if (ret < 0)
69 {
70 goto errout_with_newpath;
71 }
72 }
73
74 newname = strrchr(fullnewpath, '/') + 1;
75
76 VnodeHold();
77
78 if (flag & AT_SYMLINK_FOLLOW)
79 {
80 ret = follow_symlink(oldfd, oldpath, &old_vnode, &fulloldpath);
81 if (ret < 0)
82 {
83 goto errout_with_vnode;
84 }
85 }
86 else
87 {
88 ret = VnodeLookup(fulloldpath, &old_vnode, 0);
89 if (ret < 0)
90 {
91 goto errout_with_vnode;
92 }
93 }
94
95 mount = old_vnode->originMount;
96 if ((mount != NULL) && (mount->mountFlags & MS_RDONLY))
97 {
98 ret = -EROFS;
99 goto errout_with_vnode;
100 }
101
102 if (old_vnode->type != VNODE_TYPE_REG && old_vnode->type != VNODE_TYPE_LNK)
103 {
104 ret = -EPERM;
105 goto errout_with_vnode;
106 }
107
108 ret = VnodeLookup(fullnewpath, &new_parent_vnode, 0);
109 if (ret == OK)
110 {
111 ret = -EEXIST;
112 goto errout_with_vnode;
113 }
114
115 if (old_vnode->originMount != new_parent_vnode->originMount)
116 {
117 ret = -EXDEV;
118 goto errout_with_vnode;
119 }
120
121 if (!old_vnode->vop || !old_vnode->vop->Link)
122 {
123 ret = -ENOSYS;
124 goto errout_with_vnode;
125 }
126 new_parent_vnode->useCount++;
127 ret = old_vnode->vop->Link(old_vnode, new_parent_vnode, &new_vnode, newname);
128 new_parent_vnode->useCount--;
129 if (ret < 0)
130 {
131 goto errout_with_vnode;
132 }
133 PathCacheAlloc(new_parent_vnode, new_vnode, newname, strlen(newname));
134 VnodeDrop();
135
136 free(fulloldpath);
137 free(fullnewpath);
138
139 return OK;
140
141 errout_with_vnode:
142 VnodeDrop();
143 free(fulloldpath);
144 errout_with_newpath:
145 free(fullnewpath);
146 errout:
147 set_errno(-ret);
148 return VFS_ERROR;
149 }
150
link(const char * oldpath,const char * newpath)151 int link(const char *oldpath, const char *newpath)
152 {
153 return do_link(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
154 }
155
linkat(int olddirfd,const char * oldpath,int newdirfd,const char * newpath,int flags)156 int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags)
157 {
158 return do_link(olddirfd, oldpath, newdirfd, newpath, flags);
159 }
160