1 /****************************************************************************
2 * fs/vfs/fs_mkdir.c
3 *
4 * Copyright (C) 2007, 2008, 2014, 2017 Gregory Nutt. All rights reserved.
5 * Author: Gregory Nutt <gnutt@nuttx.org>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name NuttX nor the names of its contributors may be
18 * used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 ****************************************************************************/
35
36 /****************************************************************************
37 * Included Files
38 ****************************************************************************/
39
40 #include "vfs_config.h"
41 #include "errno.h"
42 #include "sys/types.h"
43 #include "sys/stat.h"
44 #include "stdlib.h"
45 #include "vnode.h"
46 #include "string.h"
47 #include "capability_api.h"
48 #include "path_cache.h"
49
50 /****************************************************************************
51 * Private Functions
52 ****************************************************************************/
do_mkdir(int dirfd,const char * pathname,mode_t mode)53 int do_mkdir(int dirfd, const char *pathname, mode_t mode)
54 {
55 struct Vnode *parentVnode = NULL;
56 struct Vnode *vnode = NULL;
57 struct Mount *mount = NULL;
58 int ret;
59 char *fullpath = NULL;
60 char *relativepath = NULL;
61 char *dirname = NULL;
62
63 mode &= ~GetUmask();
64 mode &= (S_IRWXU|S_IRWXG|S_IRWXO);
65
66 /* Get absolute path by dirfd*/
67 ret = get_path_from_fd(dirfd, &relativepath);
68 if (ret < 0)
69 {
70 goto errout;
71 }
72
73 ret = vfs_normalize_path((const char *)relativepath, pathname, &fullpath);
74 if (relativepath)
75 {
76 free(relativepath);
77 }
78
79 if (ret < 0)
80 {
81 goto errout;
82 }
83 if (!strncmp(fullpath, "/dev", 4) || !strncmp(fullpath, "/proc", 5))
84 {
85 // virtual root create virtual dir
86 VnodeHold();
87 ret = VnodeLookup(fullpath, &vnode, V_DUMMY|V_CREATE);
88 if (ret != OK)
89 {
90 goto errout_with_lock;
91 }
92 vnode->mode = mode | S_IFDIR;
93 vnode->type = VNODE_TYPE_DIR;
94 VnodeDrop();
95 goto out;
96 }
97
98 dirname = strrchr(fullpath, '/') + 1;
99
100 VnodeHold();
101 ret = VnodeLookup(fullpath, &parentVnode, 0);
102 if (ret == OK)
103 {
104 ret = -EEXIST;
105 goto errout_with_lock;
106 }
107
108 if (parentVnode == NULL)
109 {
110 ret = -ENOENT;
111 goto errout_with_lock;
112 }
113 mount = parentVnode->originMount;
114 if ((mount != NULL) && (mount->mountFlags & MS_RDONLY))
115 {
116 ret = -EROFS;
117 goto errout_with_lock;
118 }
119
120 parentVnode->useCount++;
121
122 if (VfsVnodePermissionCheck(parentVnode, (WRITE_OP | EXEC_OP)))
123 {
124 ret = -EACCES;
125 goto errout_with_count;
126 }
127
128 if ((parentVnode->vop != NULL) && (parentVnode->vop->Mkdir != NULL))
129 {
130 ret = parentVnode->vop->Mkdir(parentVnode, dirname, mode, &vnode);
131 }
132 else
133 {
134 ret = -ENOSYS;
135 }
136
137 if (ret < 0)
138 {
139 goto errout_with_count;
140 }
141
142 struct PathCache *dt = PathCacheAlloc(parentVnode, vnode, dirname, strlen(dirname));
143 if (dt == NULL) {
144 // alloc name cache failed is not a critical problem, let it go.
145 PRINT_ERR("alloc path cache %s failed\n", dirname);
146 }
147 vnode->filePath = strdup(fullpath);
148 parentVnode->useCount--;
149 VnodeDrop();
150 out:
151 /* Directory successfully created */
152 free(fullpath);
153
154 return OK;
155 errout_with_count:
156 parentVnode->useCount--;
157 errout_with_lock:
158 VnodeDrop();
159 errout:
160 set_errno(-ret);
161 if (fullpath)
162 {
163 free(fullpath);
164 }
165 return VFS_ERROR;
166 }
167
168 /****************************************************************************
169 * Public Functions
170 ****************************************************************************/
171
172 /****************************************************************************
173 * Name: mkdir
174 *
175 * Description: Create a directory
176 *
177 ****************************************************************************/
178
mkdir(const char * pathname,mode_t mode)179 int mkdir(const char *pathname, mode_t mode)
180 {
181 return do_mkdir(AT_FDCWD, pathname, mode);
182 }
183
184 /****************************************************************************
185 * Name: mkdirat
186 *
187 * Description: Create a directory by dirfd
188 *
189 ****************************************************************************/
190
mkdirat(int dirfd,const char * pathname,mode_t mode)191 int mkdirat(int dirfd, const char *pathname, mode_t mode)
192 {
193 return do_mkdir(dirfd, pathname, mode);
194 }
195