text: /****************************************************************************
   *
   * Copyright 2016 Samsung Electronics All Rights Reserved.
   *
   * Licensed 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.
   *
   ****************************************************************************/
  /****************************************************************************
   * fs/inode/fs_registerreserve.c
   *
   *   Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
   *   Author: Gregory Nutt <gnutt@nuttx.org>
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   * 3. Neither the name NuttX nor the names of its contributors may be
   *    used to endorse or promote products derived from this software
   *    without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   *
   ****************************************************************************/
  
  /****************************************************************************
   * Included Files
   ****************************************************************************/
  
  #include <tinyara/config.h>
  
  #include <assert.h>
  #include <errno.h>
  
  #include <tinyara/kmalloc.h>
  #include <tinyara/fs/fs.h>
  
  #include "inode/inode.h"
  
  /****************************************************************************
   * Pre-processor Definitions
   ****************************************************************************/
  
  /****************************************************************************
   * Private Variables
   ****************************************************************************/
  
  /****************************************************************************
   * Public Variables
   ****************************************************************************/
  
  /****************************************************************************
   * Private Functions
   ****************************************************************************/
  
  /****************************************************************************
   * Name: inode_namelen
   ****************************************************************************/
  
  static int inode_namelen(FAR const char *name)
  {
  	const char *tmp = name;
  	while (*tmp && *tmp != '/') {
  		tmp++;
  	}
  	return tmp - name;
  }
  
  /****************************************************************************
   * Name: inode_namecpy
   ****************************************************************************/
  
  static void inode_namecpy(char *dest, const char *src)
  {
  	while (*src && *src != '/') {
  		*dest++ = *src++;
  	}
  	*dest = '\0';
  }
  
  /****************************************************************************
   * Name: inode_alloc
   ****************************************************************************/
  
  static FAR struct inode *inode_alloc(FAR const char *name)
  {
  	int namelen = inode_namelen(name);
  	FAR struct inode *node = (FAR struct inode *)kmm_zalloc(FSNODE_SIZE(namelen));
  	if (node) {
  		inode_namecpy(node->i_name, name);
  	}
  
  	return node;
  }
  
  /****************************************************************************
   * Name: inode_insert
   ****************************************************************************/
  
  static void inode_insert(FAR struct inode *node, 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) {
  		node->i_peer = peer->i_peer;
  		peer->i_peer = node;
  	}
  
  	/* If parent is non-null, then it must go at the head of its
  	 * list of children.
  	 */
  
  	else if (parent) {
  		node->i_peer = parent->i_child;
  		parent->i_child = node;
  	}
  
  	/* Otherwise, this must be the new root_inode */
  
  	else {
  		node->i_peer = root_inode;
  		root_inode = node;
  	}
  }
  
  /****************************************************************************
   * Public Functions
   ****************************************************************************/
  
  /****************************************************************************
   * Name: inode_reserve
   *
   * Description:
   *   Reserve an (initialized) inode the pseudo file system.
   *
   *   NOTE: Caller must hold the inode semaphore
   *
   * Input parameters:
   *   path - The path to the inode to create
   *   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
   *
   ****************************************************************************/
  
  int inode_reserve(FAR const char *path, FAR struct inode **inode)
  {
  	FAR const char *name = path;
  	FAR struct inode *left;
  	FAR struct inode *parent;
  
  	/* Assume failure */
  
  	DEBUGASSERT(path && inode);
  	*inode = NULL;
  
  	/* Handle paths that are interpreted as the root directory */
  
  	if (!*path || path[0] != '/') {
  		return -EINVAL;
  	}
  
  	/* Find the location to insert the new subtree */
  
  	if (inode_search(&name, &left, &parent, (FAR const char **)NULL) != NULL) {
  		/* It is an error if the node already exists in the tree */
  
  		return -EEXIST;
  	}
  
  	/* Now we now where to insert the subtree */
  
  	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 *next_name = inode_nextname(name);
  		if (*next_name) {
  			/* Insert an operationless node */
  
  			node = inode_alloc(name);
  			if (node) {
  				inode_insert(node, left, parent);
  
  				/* Set up for the next time through the loop */
  
  				name = next_name;
  				left = NULL;
  				parent = node;
  				continue;
  			}
  		} else {
  			node = inode_alloc(name);
  			if (node) {
  				inode_insert(node, left, parent);
  				*inode = node;
  				return OK;
  			}
  		}
  
  		/* We get here on failures to allocate node memory */
  
  		return -ENOMEM;
  	}
  }
  