Oopenvela-robotfix compile error
a9d5f928创建于 4月21日历史提交
/****************************************************************************
 * fs/inode/fs_inodereserve.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 <assert.h>
#include <errno.h>

#include <nuttx/kmalloc.h>
#include <nuttx/fs/fs.h>
#include <nuttx/atomic.h>

#include "inode/inode.h"
#include "fs_heap.h"

/****************************************************************************
 * Private Data
 ****************************************************************************/

static DEFINE_PER_CPU_BSS_BMP(ino_t, g_ino);
#define g_ino this_cpu_var_bmp(g_ino)

/****************************************************************************
 * Private Functions
 ****************************************************************************/

/****************************************************************************
 * Name: inode_namelen
 ****************************************************************************/

static int inode_namelen(FAR const char *name)
{
  FAR const char *tmp = name;
  while (*tmp && *tmp != '/')
    {
      tmp++;
    }

  return tmp - name;
}

/****************************************************************************
 * Name: inode_namecpy
 ****************************************************************************/

static void inode_namecpy(FAR char *dest, FAR const char *src)
{
  while (*src && *src != '/')
    {
      *dest++ = *src++;
    }

  *dest = '\0';
}

/****************************************************************************
 * Name: inode_alloc
 ****************************************************************************/

static FAR struct inode *inode_alloc(FAR const char *name, mode_t mode)
{
  FAR struct inode *inode;
  int namelen;

  namelen = inode_namelen(name);
  inode   = fs_heap_zalloc(FSNODE_SIZE(namelen));
  if (inode)
    {
      inode->i_ino   = g_ino++;
      atomic_set(&inode->i_crefs, 1);
#ifdef CONFIG_PSEUDOFS_ATTRIBUTES
      inode->i_mode  = mode;
      clock_gettime(CLOCK_REALTIME, &inode->i_atime);
      inode->i_mtime = inode->i_atime;
      inode->i_ctime = inode->i_atime;
#endif
      inode->u.i_ops = &g_dir_fileops;
      inode_namecpy(inode->i_name, name);
    }

  return inode;
}

/****************************************************************************
 * Name: inode_insert
 ****************************************************************************/

static void inode_insert(FAR struct inode *inode,
                         FAR struct inode *peer,
                         FAR struct inode *parent)
{
  /* If peer is non-null, then new node simply goes to the right
   * of that peer node.
   */

  if (peer)
    {
      inode->i_peer   = peer->i_peer;
      inode->i_parent = parent;
      peer->i_peer    = inode;
    }

  /* Then it must go at the head of parent's list of children. */

  else
    {
      DEBUGASSERT(parent != NULL);
      inode->i_peer   = parent->i_child;
      inode->i_parent = parent;
      parent->i_child = inode;
    }
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: inode_root_reserve
 *
 * Description:
 *   Reserve the root inode for the pseudo file system.
 *
 ****************************************************************************/

void inode_root_reserve(void)
{
  g_root_inode = inode_alloc("", 0777);
}

/****************************************************************************
 * Name: inode_reserve
 *
 * Description:
 *   Reserve an (initialized) inode the pseudo file system.  The initial
 *   reference count on the new inode is zero.
 *
 * Input Parameters:
 *   path - The path to the inode to create
 *   mode - inmode privileges
 *   inode - The location to return the inode pointer
 *
 * Returned Value:
 *   Zero on success (with the inode point in 'inode'); A negated errno
 *   value is returned on failure:
 *
 *   EINVAL - 'path' is invalid for this operation
 *   EEXIST - An inode already exists at 'path'
 *   ENOMEM - Failed to allocate in-memory resources for the operation
 *
 * Assumptions:
 *   Caller must hold the inode semaphore
 *
 ****************************************************************************/

int inode_reserve(FAR const char *path,
                  mode_t mode, FAR struct inode **inode)
{
  struct inode_search_s desc;
  FAR struct inode *node;
  FAR struct inode *left;
  FAR struct inode *parent;
  FAR const char *name;
  FAR const char *nextname;
  int ret;

  /* Assume failure */

  DEBUGASSERT(path != NULL && inode != NULL);

  /* Check if path is empty before inode_search.
   * Otherwise inode_search will return -ENOENT for any path whose inode
   * doesn't exist, including empty path. In that case, we cannot distinguish
   * between empty path and non-empty path whose inode doesn't exist.
   */

  if (path[0] == '\0')
    {
      return -ENOENT;
    }

  *inode = NULL;

  /* Find the location to insert the new subtree */

  SETUP_SEARCH(&desc, path, false);

  ret = inode_search(&desc);
  if (ret >= 0)
    {
      /* It is an error if the node already exists in the tree (or if it
       * lies within a mountpoint, we don't distinguish here).
       */

      ret = -EEXIST;
      goto errout_with_search;
    }

  if (ret != -ENOENT)
    {
      /* Some other error occurred during the search */

      goto errout_with_search;
    }

  /* Now we now where to insert the subtree */

  name   = desc.path;
  left   = desc.peer;
  parent = desc.parent;

  /* Create a new node -- we need to know if this is the
   * the leaf node or some intermediary.  We can find this
   * by looking at the next name.
   */

  nextname = inode_nextname(name);
  if (*nextname != '\0')
    {
      /* It's an error if the intermediate path doesn't exist */

      ret = -ENOENT;
      goto errout_with_search;
    }
  else
    {
      node = inode_alloc(name, mode);
      if (node != NULL)
        {
          inode_insert(node, left, parent);
#ifdef CONFIG_PSEUDOFS_ATTRIBUTES
          /* Touch parent directory timestamps on successful insert */

          if (parent != NULL)
            {
              nxclock_gettime(CLOCK_REALTIME, &parent->i_ctime);
              parent->i_mtime = parent->i_ctime;
            }
#endif

          *inode = node;
          ret = OK;
        }
      else
        {
          /* We get here on failures to allocate node memory */

          ret = -ENOMEM;
        }
    }

errout_with_search:
  RELEASE_SEARCH(&desc);
  return ret;
}

/****************************************************************************
 * Name: inode_reserve_path
 *
 * Description:
 *   Reserve an (initialized) inode the pseudo file system.
 *   If the intermediate nodes do not exist, then create their inodes.
 *   The initial reference count on the new inode is zero.
 *
 * Input Parameters:
 *   path - The path to the inode to create
 *   mode - inmode privileges
 *   inode - The location to return the inode pointer
 *
 * Returned Value:
 *   Zero on success (with the inode point in 'inode'); A negated errno
 *   value is returned on failure:
 *
 *   EINVAL - 'path' is invalid for this operation
 *   EEXIST - An inode already exists at 'path'
 *   ENOMEM - Failed to allocate in-memory resources for the operation
 *
 * Assumptions:
 *   Caller must hold the inode semaphore
 *
 ****************************************************************************/

int inode_reserve_path(FAR const char *path,
                       mode_t mode, FAR struct inode **inode)
{
  struct inode_search_s desc;
  FAR struct inode *left;
  FAR struct inode *parent;
  FAR const char *name;
  int ret;

  /* Assume failure */

  DEBUGASSERT(path != NULL && inode != NULL);

  /* Check if path is empty before inode_search.
   * Otherwise inode_search will return -ENOENT for any path whose inode
   * doesn't exist, including empty path. In that case, we cannot distinguish
   * between empty path and non-empty path whose inode doesn't exist.
   */

  if (path[0] == '\0')
    {
      return -ENOENT;
    }

  *inode = NULL;

  /* Find the location to insert the new subtree */

  SETUP_SEARCH(&desc, path, false);

  ret = inode_search(&desc);
  if (ret >= 0)
    {
      /* It is an error if the node already exists in the tree (or if it
       * lies within a mountpoint, we don't distinguish here).
       */

      ret = -EEXIST;
      goto errout_with_search;
    }

  if (ret != -ENOENT)
    {
      /* Some other error occurred during the search */

      goto errout_with_search;
    }

  /* Now we now where to insert the subtree */

  name   = desc.path;
  left   = desc.peer;
  parent = desc.parent;

  for (; ; )
    {
      FAR struct inode *node;

      /* Create a new node -- we need to know if this is the
       * the leaf node or some intermediary.  We can find this
       * by looking at the next name.
       */

      FAR const char *nextname = inode_nextname(name);
      if (*nextname != '\0')
        {
          /* Insert an operationless node */

          node = inode_alloc(name, 0777);
          if (node != NULL)
            {
              inode_insert(node, left, parent);

              /* Set up for the next time through the loop */

              name   = nextname;
              left   = NULL;
              parent = node;
              continue;
            }
        }
      else
        {
          node = inode_alloc(name, mode);
          if (node != NULL)
            {
              inode_insert(node, left, parent);
              *inode = node;
              ret = OK;
              break;
            }
        }

      /* We get here on failures to allocate node memory */

      ret = -ENOMEM;
      break;
    }

errout_with_search:
  RELEASE_SEARCH(&desc);
  return ret;
}