1 /****************************************************************************
2 * fs/vfs/fs_mkdir.c
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership. The
7 * ASF licenses this file to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance with the
9 * License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 * License for the specific language governing permissions and limitations
17 * under the License.
18 *
19 ****************************************************************************/
20
21 /****************************************************************************
22 * Included Files
23 ****************************************************************************/
24
25 #include "vfs_config.h"
26 #include "errno.h"
27 #include "sys/types.h"
28 #include "sys/stat.h"
29 #include "stdlib.h"
30 #include "vnode.h"
31 #include "string.h"
32 #include "capability_api.h"
33 #include "path_cache.h"
34
35 /****************************************************************************
36 * Private Functions
37 ****************************************************************************/
do_mkdir(int dirfd,const char * pathname,mode_t mode)38 int do_mkdir(int dirfd, const char *pathname, mode_t mode)
39 {
40 struct Vnode *parentVnode = NULL;
41 struct Vnode *vnode = NULL;
42 struct Mount *mount = NULL;
43 int ret;
44 char *fullpath = NULL;
45 char *relativepath = NULL;
46 char *dirname = NULL;
47
48 mode &= ~GetUmask();
49 mode &= (S_IRWXU|S_IRWXG|S_IRWXO);
50
51 /* Get absolute path by dirfd*/
52 ret = get_path_from_fd(dirfd, &relativepath);
53 if (ret < 0)
54 {
55 goto errout;
56 }
57
58 ret = vfs_normalize_path((const char *)relativepath, pathname, &fullpath);
59 if (relativepath)
60 {
61 free(relativepath);
62 }
63
64 if (ret < 0)
65 {
66 goto errout;
67 }
68 #ifdef LOSCFG_KERNEL_PLIMITS
69 if (!strncmp(fullpath, "/dev", 4) || !strcmp(fullpath, "/proc"))
70 #else
71 if (!strncmp(fullpath, "/dev", 4) || !strncmp(fullpath, "/proc", 5))
72 #endif
73 {
74 // virtual root create virtual dir
75 VnodeHold();
76 ret = VnodeLookup(fullpath, &vnode, V_DUMMY|V_CREATE);
77 if (ret != OK)
78 {
79 goto errout_with_lock;
80 }
81 vnode->mode = mode | S_IFDIR;
82 vnode->type = VNODE_TYPE_DIR;
83 VnodeDrop();
84 goto out;
85 }
86
87 dirname = strrchr(fullpath, '/') + 1;
88
89 VnodeHold();
90 ret = VnodeLookup(fullpath, &parentVnode, 0);
91 if (ret == OK)
92 {
93 ret = -EEXIST;
94 goto errout_with_lock;
95 }
96
97 if (parentVnode == NULL)
98 {
99 ret = -ENOENT;
100 goto errout_with_lock;
101 }
102 mount = parentVnode->originMount;
103 if ((mount != NULL) && (mount->mountFlags & MS_RDONLY))
104 {
105 ret = -EROFS;
106 goto errout_with_lock;
107 }
108
109 parentVnode->useCount++;
110
111 if (VfsVnodePermissionCheck(parentVnode, (WRITE_OP | EXEC_OP)))
112 {
113 ret = -EACCES;
114 goto errout_with_count;
115 }
116
117 if ((parentVnode->vop != NULL) && (parentVnode->vop->Mkdir != NULL))
118 {
119 ret = parentVnode->vop->Mkdir(parentVnode, dirname, mode, &vnode);
120 }
121 else
122 {
123 ret = -ENOSYS;
124 }
125
126 if (ret < 0)
127 {
128 goto errout_with_count;
129 }
130
131 struct PathCache *dt = PathCacheAlloc(parentVnode, vnode, dirname, strlen(dirname));
132 if (dt == NULL) {
133 // alloc name cache failed is not a critical problem, let it go.
134 PRINT_ERR("alloc path cache %s failed\n", dirname);
135 }
136 vnode->filePath = strdup(fullpath);
137 parentVnode->useCount--;
138 VnodeDrop();
139 out:
140 /* Directory successfully created */
141 free(fullpath);
142
143 return OK;
144 errout_with_count:
145 parentVnode->useCount--;
146 errout_with_lock:
147 VnodeDrop();
148 errout:
149 set_errno(-ret);
150 if (fullpath)
151 {
152 free(fullpath);
153 }
154 return VFS_ERROR;
155 }
156
157 /****************************************************************************
158 * Public Functions
159 ****************************************************************************/
160
161 /****************************************************************************
162 * Name: mkdir
163 *
164 * Description: Create a directory
165 *
166 ****************************************************************************/
167
mkdir(const char * pathname,mode_t mode)168 int mkdir(const char *pathname, mode_t mode)
169 {
170 return do_mkdir(AT_FDCWD, pathname, mode);
171 }
172
173 /****************************************************************************
174 * Name: mkdirat
175 *
176 * Description: Create a directory by dirfd
177 *
178 ****************************************************************************/
179
mkdirat(int dirfd,const char * pathname,mode_t mode)180 int mkdirat(int dirfd, const char *pathname, mode_t mode)
181 {
182 return do_mkdir(dirfd, pathname, mode);
183 }
184