* fs/shm/shm_open.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include "inode/inode.h"
#include "vfs/vfs.h"
#include "shm/shmfs.h"
* Private Functions
****************************************************************************/
static int file_shm_open(FAR struct file *shm, FAR const char *name,
int oflags, mode_t mode)
{
FAR struct inode *inode;
struct inode_search_s desc;
char fullpath[sizeof(CONFIG_FS_SHMFS_VFS_PATH) + CONFIG_NAME_MAX + 2];
int ret;
if (!shm || !name)
{
return -EINVAL;
}
while (*name == '/')
{
name++;
}
if (*name == '\0')
{
return -EINVAL;
}
if (strnlen(name, CONFIG_NAME_MAX + 1) > CONFIG_NAME_MAX)
{
return -ENAMETOOLONG;
}
snprintf(fullpath, sizeof(fullpath),
CONFIG_FS_SHMFS_VFS_PATH "/%s", name);
SETUP_SEARCH(&desc, fullpath, false);
inode_lock();
ret = inode_find(&desc);
if (ret >= 0)
{
inode = desc.node;
if (!INODE_IS_SHM(inode))
{
ret = -EINVAL;
inode_release(inode);
goto errout_with_sem;
}
* create a new object with this name.
*/
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
{
ret = -EEXIST;
inode_release(inode);
goto errout_with_sem;
}
#ifdef CONFIG_PSEUDOFS_ATTRIBUTES
if (((oflags & O_WRONLY) && !(inode->i_mode & S_IWUSR)) ||
((oflags & O_RDONLY) && !(inode->i_mode & S_IRUSR)))
{
ret = -EACCES;
inode_release(inode);
goto errout_with_sem;
}
#endif
* zero bytes.
*/
if ((oflags & O_TRUNC) == O_TRUNC && inode->i_private != NULL)
{
shmfs_free_object(inode->i_private);
inode->i_private = NULL;
inode->i_size = 0;
}
}
else
{
if ((oflags & O_CREAT) == 0)
{
ret = -ENOENT;
goto errout_with_sem;
}
ret = inode_reserve_path(fullpath, mode, &inode);
if (ret < 0)
{
goto errout_with_sem;
}
INODE_SET_SHM(inode);
inode->u.i_ops = &g_shmfs_operations;
inode->i_private = NULL;
inode_addref(inode);
}
shm->f_oflags = oflags | O_NOFOLLOW;
shm->f_inode = inode;
errout_with_sem:
inode_unlock();
RELEASE_SEARCH(&desc);
#ifdef CONFIG_FS_NOTIFY
if (ret >= 0)
{
notify_open(fullpath, oflags);
}
#endif
return ret;
}
* Public Functions
****************************************************************************/
int shm_open(FAR const char *name, int oflag, mode_t mode)
{
FAR struct file *shm;
int ret;
int fd;
shm = file_allocate();
if (shm == NULL)
{
set_errno(ENOMEM);
return ERROR;
}
ret = file_shm_open(shm, name, oflag, mode);
if (ret < 0)
{
file_deallocate(shm);
set_errno(-ret);
return ERROR;
}
fd = file_dup(shm, 0, oflag | O_CLOEXEC);
if (fd < 0)
{
file_close(shm);
file_deallocate(shm);
set_errno(-fd);
return ERROR;
}
return fd;
}