1 /****************************************************************************
2 * fs/vfs/fs_open.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
27 #include "errno.h"
28 #include "sys/types.h"
29 #include "fcntl.h"
30 #include "sched.h"
31 #include "assert.h"
32 #ifdef LOSCFG_FILE_MODE
33 #include "stdarg.h"
34 #endif
35 #include "stdlib.h"
36 #include "vnode.h"
37 #include "blockproxy.h"
38 #include "path_cache.h"
39 #include "unistd.h"
40
41 /****************************************************************************
42 * Public Functions
43 ****************************************************************************/
44
oflag_convert_mode(int oflags)45 static int oflag_convert_mode(int oflags)
46 {
47 /* regular file operations */
48
49 int acc_mode = 0;
50 if ((oflags & O_ACCMODE) == O_RDONLY)
51 acc_mode |= READ_OP;
52 if (oflags & O_WRONLY)
53 acc_mode |= WRITE_OP;
54 if (oflags & O_RDWR)
55 acc_mode |= READ_OP | WRITE_OP;
56
57 /* Opens the file, if it is existing. If not, a new file is created. */
58
59 if (oflags & O_CREAT)
60 acc_mode |= WRITE_OP;
61
62 /* Creates a new file. If the file is existing, it is truncated and overwritten. */
63
64 if (oflags & O_TRUNC)
65 acc_mode |= WRITE_OP;
66
67 /* Creates a new file. The function fails if the file is already existing. */
68
69 if (oflags & O_EXCL)
70 acc_mode |= WRITE_OP;
71 if (oflags & O_APPEND)
72 acc_mode |= WRITE_OP;
73
74 /* mark for executing operation */
75
76 if (oflags & O_EXECVE)
77 acc_mode |= EXEC_OP;
78 return acc_mode;
79 }
80
get_path_from_fd(int fd,char ** path)81 int get_path_from_fd(int fd, char **path)
82 {
83 struct file *file = NULL;
84 char *copypath = NULL;
85
86 if (fd == AT_FDCWD)
87 {
88 return OK;
89 }
90
91 int ret = fs_getfilep(fd, &file);
92 if (ret < 0)
93 {
94 return -ENOENT;
95 }
96
97 if ((file == NULL) || (file->f_vnode == NULL) || (file->f_path == NULL))
98 {
99 return -EBADF;
100 }
101
102 copypath = strdup((const char*)file->f_path);
103 if (copypath == NULL)
104 {
105 return VFS_ERROR;
106 }
107
108 *path = copypath;
109 return OK;
110 }
111
do_creat(struct Vnode * parentNode,char * fullpath,mode_t mode,struct Vnode ** node)112 static int do_creat(struct Vnode *parentNode, char *fullpath, mode_t mode, struct Vnode **node)
113 {
114 int ret;
115 char *name = strrchr(fullpath, '/') + 1;
116 parentNode->useCount++;
117
118 if (parentNode->vop != NULL && parentNode->vop->Create != NULL)
119 {
120 ret = parentNode->vop->Create(parentNode, name, mode, node);
121 }
122 else
123 {
124 ret = -ENOSYS;
125 }
126
127 parentNode->useCount--;
128 if (ret < 0)
129 {
130 return ret;
131 }
132
133 struct PathCache *dt = PathCacheAlloc(parentNode, *node, name, strlen(name));
134 if (dt == NULL)
135 {
136 // alloc name cache failed is not a critical problem, let it go.
137 PRINT_ERR("alloc path cache %s failed\n", name);
138 }
139 return OK;
140 }
141
fp_open(int dirfd,const char * path,int oflags,mode_t mode)142 int fp_open(int dirfd, const char *path, int oflags, mode_t mode)
143 {
144 int ret;
145 int accmode;
146 struct file *filep = NULL;
147 struct Vnode *vnode = NULL;
148 struct Vnode *parentVnode = NULL;
149 char *fullpath = NULL;
150
151 VnodeHold();
152 ret = follow_symlink(dirfd, path, &vnode, &fullpath);
153 if (ret == OK)
154 {
155 /* if file exist */
156 if (vnode->type == VNODE_TYPE_BCHR)
157 {
158 ret = -EINVAL;
159 VnodeDrop();
160 goto errout;
161 }
162 #ifdef LOSCFG_FS_VFS_BLOCK_DEVICE
163 if (vnode->type == VNODE_TYPE_BLK)
164 {
165 VnodeDrop();
166 int fd = block_proxy(fullpath, oflags);
167 if (fd < 0)
168 {
169 ret = fd;
170 goto errout;
171 }
172 return fd;
173 }
174 #endif
175 if ((vnode->originMount) && (vnode->originMount->mountFlags & MS_RDONLY) &&
176 (((oflags & O_ACCMODE) != O_RDONLY) || (oflags & O_TRUNC)))
177 {
178 ret = -EROFS;
179 VnodeDrop();
180 goto errout;
181 }
182 if ((oflags & O_CREAT) && (oflags & O_EXCL))
183 {
184 ret = -EEXIST;
185 VnodeDrop();
186 goto errout;
187 }
188 if (vnode->type == VNODE_TYPE_DIR)
189 {
190 ret = -EISDIR;
191 VnodeDrop();
192 goto errout;
193 }
194 accmode = oflag_convert_mode(oflags);
195 if (VfsVnodePermissionCheck(vnode, accmode))
196 {
197 ret = -EACCES;
198 VnodeDrop();
199 goto errout;
200 }
201 }
202
203 if ((ret != OK) && (oflags & O_CREAT) && vnode)
204 {
205 /* if file not exist, but parent dir of the file is exist */
206 if ((vnode->originMount) && (vnode->originMount->mountFlags & MS_RDONLY))
207 {
208 ret = -EROFS;
209 VnodeDrop();
210 goto errout;
211 }
212 if (VfsVnodePermissionCheck(vnode, (WRITE_OP | EXEC_OP)))
213 {
214 ret = -EACCES;
215 VnodeDrop();
216 goto errout;
217 }
218 parentVnode = vnode;
219 ret = do_creat(parentVnode, fullpath, mode, &vnode);
220 if (ret != OK)
221 {
222 VnodeDrop();
223 goto errout;
224 }
225 vnode->filePath = strdup(fullpath);
226 }
227
228 if (ret != OK)
229 {
230 /* found nothing */
231 VnodeDrop();
232 goto errout;
233 }
234 vnode->useCount++;
235 VnodeDrop();
236
237 if (oflags & O_TRUNC)
238 {
239 if (vnode->useCount > 1)
240 {
241 ret = -EBUSY;
242 goto errout_with_count;
243 }
244
245 if (vnode->vop->Truncate)
246 {
247 ret = vnode->vop->Truncate(vnode, 0);
248 if (ret != OK)
249 {
250 goto errout_with_count;
251 }
252 }
253 else
254 {
255 ret = -ENOSYS;
256 goto errout_with_count;
257 }
258 }
259
260 filep = files_allocate(vnode, oflags, 0, NULL, FILE_START_FD);
261 if (filep == NULL)
262 {
263 ret = -EMFILE;
264 goto errout_with_count;
265 }
266
267 if (filep->ops && filep->ops->open)
268 {
269 ret = filep->ops->open(filep);
270 }
271
272 if (ret < 0)
273 {
274 files_release(filep->fd);
275 goto errout_with_count;
276 }
277
278 if (fullpath)
279 {
280 free(fullpath);
281 }
282 return filep->fd;
283
284 errout_with_count:
285 VnodeHold();
286 vnode->useCount--;
287 VnodeDrop();
288 errout:
289 if (fullpath)
290 {
291 free(fullpath);
292 }
293 set_errno(-ret);
294 return VFS_ERROR;
295 }
296
do_open(int dirfd,const char * path,int oflags,mode_t mode)297 int do_open(int dirfd, const char *path, int oflags, mode_t mode)
298 {
299 int ret;
300 int fd;
301
302 if ((oflags & (O_WRONLY | O_CREAT)) != 0)
303 {
304 mode &= ~GetUmask();
305 mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
306 }
307
308 fd = fp_open(dirfd, path, oflags, mode);
309 if (fd < 0)
310 {
311 ret = -get_errno();
312 goto errout;
313 }
314
315 return fd;
316
317 errout:
318 set_errno(-ret);
319 return VFS_ERROR;
320 }
321
322 /****************************************************************************
323 * Name: open
324 *
325 * Description: Standard 'open' interface
326 *
327 ****************************************************************************/
328
open(const char * path,int oflags,...)329 int open(const char *path, int oflags, ...)
330 {
331 mode_t mode = DEFAULT_FILE_MODE; /* File read-write properties. */
332 #ifdef LOSCFG_FILE_MODE
333 va_list ap;
334 va_start(ap, oflags);
335 mode = va_arg(ap, int);
336 va_end(ap);
337 #endif
338
339 return do_open(AT_FDCWD, path, oflags, mode);
340 }
341
open64(const char * __path,int __oflag,...)342 int open64 (const char *__path, int __oflag, ...)
343 {
344 mode_t mode = DEFAULT_FILE_MODE; /* File read-write properties. */
345 #ifdef LOSCFG_FILE_MODE
346 va_list ap;
347 va_start(ap, __oflag);
348 mode = va_arg(ap, int);
349 va_end(ap);
350 if ((__oflag & (O_WRONLY | O_CREAT)) != 0)
351 {
352 mode &= ~GetUmask();
353 mode &= (S_IRWXU|S_IRWXG|S_IRWXO);
354 }
355 #endif
356 return open (__path, ((unsigned int)__oflag) | O_LARGEFILE, mode);
357 }
358