2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <assert.h>
2N/A#include <sys/avl.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <libuvfs_impl.h>
2N/A
2N/Astatic umem_cache_t *libuvfs_fid_info_cache;
2N/Astatic umem_cache_t *libuvfs_name_dirent_cache;
2N/A
2N/Astatic libuvfs_name_dirent_t *
2N/Alibuvfs_name_dirent_alloc(libuvfs_fid_info_t *dir, libuvfs_fid_info_t *child,
2N/A const char *name, const libuvfs_fid_t *dirfid,
2N/A const libuvfs_fid_t *childfid)
2N/A{
2N/A libuvfs_name_dirent_t *rc;
2N/A
2N/A rc = umem_cache_alloc(libuvfs_name_dirent_cache, UMEM_NOFAIL);
2N/A
2N/A rc->de_name = libuvfs_strdup(name);
2N/A rc->de_dirfid = *dirfid;
2N/A rc->de_fid = *childfid;
2N/A rc->de_dir = dir;
2N/A rc->de_myinfo = child;
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Astatic void
2N/Alibuvfs_name_dirent_free(libuvfs_name_dirent_t *dirent)
2N/A{
2N/A libuvfs_fid_info_t *myinfo = dirent->de_myinfo;
2N/A
2N/A if (list_link_active(&dirent->de_allnames))
2N/A list_remove(&myinfo->nm_allnames, dirent);
2N/A libuvfs_strfree(dirent->de_name);
2N/A
2N/A umem_cache_free(libuvfs_name_dirent_cache, dirent);
2N/A}
2N/A
2N/Astatic libuvfs_fid_info_t *
2N/Alibuvfs_fid_info_alloc(const libuvfs_fid_t *fid)
2N/A{
2N/A libuvfs_fid_info_t *rc;
2N/A
2N/A rc = umem_cache_alloc(libuvfs_fid_info_cache, UMEM_NOFAIL);
2N/A
2N/A rc->nm_fid = *fid;
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Astatic void
2N/Alibuvfs_fid_info_free(libuvfs_fid_info_t *info)
2N/A{
2N/A libuvfs_name_dirent_t *de;
2N/A void *cookie;
2N/A
2N/A cookie = NULL;
2N/A while ((de = avl_destroy_nodes(&info->nm_dir, &cookie)) != NULL)
2N/A libuvfs_name_dirent_free(de);
2N/A while ((de = list_head(&info->nm_allnames)) != NULL) {
2N/A /*
2N/A * If we get here, we're freeing info when it still has
2N/A * libuvfs_name_dirent_t objects pointing to it; i.e.,
2N/A * it's like freeing a file before all of its names are
2N/A * gone. This can happen via libuvfs_destroy_fs, when
2N/A * all libuvfs_fid_info_t objects are destroyed in
2N/A * fid order.
2N/A */
2N/A list_remove(&info->nm_allnames, de);
2N/A de->de_myinfo = NULL;
2N/A }
2N/A
2N/A umem_cache_free(libuvfs_fid_info_cache, info);
2N/A}
2N/A
2N/Astatic libuvfs_fid_info_t *
2N/Alibuvfs_fid_info_find(libuvfs_fs_t *fs, const libuvfs_fid_t *dirfid,
2N/A avl_index_t *where)
2N/A{
2N/A libuvfs_fid_info_t *rc, key;
2N/A
2N/A key.nm_fid = *dirfid;
2N/A
2N/A rc = avl_find(&fs->fs_name_info_tree, &key, where);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Astatic libuvfs_name_dirent_t *
2N/Alibuvfs_name_dirent_find(libuvfs_fid_info_t *dir, const char *name,
2N/A avl_index_t *where)
2N/A{
2N/A libuvfs_name_dirent_t *rc, key;
2N/A
2N/A key.de_name = libuvfs_strdup(name);
2N/A
2N/A rc = avl_find(&dir->nm_dir, &key, where);
2N/A
2N/A libuvfs_strfree(key.de_name);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Avoid
2N/Alibuvfs_name_fs_rdlock(libuvfs_fs_t *fs)
2N/A{
2N/A (void) rw_rdlock(&fs->fs_name_user_lock);
2N/A}
2N/A
2N/Avoid
2N/Alibuvfs_name_fs_wrlock(libuvfs_fs_t *fs)
2N/A{
2N/A (void) rw_wrlock(&fs->fs_name_user_lock);
2N/A}
2N/A
2N/Avoid
2N/Alibuvfs_name_fs_unlock(libuvfs_fs_t *fs)
2N/A{
2N/A (void) rw_unlock(&fs->fs_name_user_lock);
2N/A}
2N/A
2N/Aint
2N/Alibuvfs_name_fid_rdlock(libuvfs_fs_t *fs, const libuvfs_fid_t *fid)
2N/A{
2N/A libuvfs_fid_info_t *info;
2N/A
2N/A /*
2N/A * We drop fs_name_lock before we enter nm_user_lock. We do
2N/A * this to avoid lock order problems. It should be safe, since
2N/A * at present, libuvfs_fid_info_t structures are never freed.
2N/A * If that ever changes, we will need to be sure that info does
2N/A * not disappear before we dereference it.
2N/A */
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A info = libuvfs_fid_info_find(fs, fid, NULL);
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A if (info == NULL)
2N/A return (-1);
2N/A
2N/A (void) rw_rdlock(&info->nm_user_lock);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Alibuvfs_name_fid_wrlock(libuvfs_fs_t *fs, const libuvfs_fid_t *fid)
2N/A{
2N/A libuvfs_fid_info_t *info;
2N/A
2N/A /* See comment in libuvfs_name_fid_rdlock() about the locking below */
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A info = libuvfs_fid_info_find(fs, fid, NULL);
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A if (info == NULL)
2N/A return (-1);
2N/A
2N/A (void) rw_wrlock(&info->nm_user_lock);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Alibuvfs_name_fid_unlock(libuvfs_fs_t *fs, const libuvfs_fid_t *fid)
2N/A{
2N/A libuvfs_fid_info_t *info;
2N/A
2N/A /*
2N/A * We hold fs_name_lock across the dropping of nm_user_lock. This
2N/A * is different than the two functions above, where we acquire
2N/A * nm_user_lock. This is because there is no risk of getting
2N/A * stuck before dropping fs_name_lock.
2N/A */
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A info = libuvfs_fid_info_find(fs, fid, NULL);
2N/A if (info == NULL) {
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A return (-1);
2N/A }
2N/A
2N/A (void) rw_unlock(&info->nm_user_lock);
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/Alibuvfs_name_root_create(libuvfs_fs_t *fs, const libuvfs_fid_t *rootfid)
2N/A{
2N/A libuvfs_fid_info_t *root;
2N/A avl_index_t where;
2N/A
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A
2N/A root = libuvfs_fid_info_find(fs, rootfid, &where);
2N/A if (root != NULL) {
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A return;
2N/A }
2N/A
2N/A root = libuvfs_fid_info_alloc(rootfid);
2N/A avl_insert(&fs->fs_name_info_tree, root, where);
2N/A
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A}
2N/A
2N/A/*
2N/A * Store childfid in the directory specified by dirfid under the given
2N/A * name. If overwrite is nonzero, the previous fid (if any) is overwritten.
2N/A * If oldfid is not NULL, return the previous fid; the uvfid_len is set
2N/A * to NULL if there is no previous fid.
2N/A *
2N/A * If childfid is NULL, and overwrite is true, then this function will
2N/A * delete (although you could also call libuvfs_name_delete).
2N/A */
2N/A
2N/Avoid
2N/Alibuvfs_name_store(libuvfs_fs_t *fs, const libuvfs_fid_t *dirfid,
2N/A const char *name, const libuvfs_fid_t *childfid, int overwrite,
2N/A libuvfs_fid_t *oldfid)
2N/A{
2N/A libuvfs_fid_info_t *dir;
2N/A libuvfs_name_dirent_t *dirent;
2N/A libuvfs_fid_info_t *child;
2N/A avl_index_t where;
2N/A
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A
2N/A dir = libuvfs_fid_info_find(fs, dirfid, &where);
2N/A if (dir == NULL) {
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A return;
2N/A }
2N/A if (childfid != NULL) {
2N/A child = libuvfs_fid_info_find(fs, childfid, &where);
2N/A if (child == NULL) {
2N/A child = libuvfs_fid_info_alloc(childfid);
2N/A avl_insert(&fs->fs_name_info_tree, child, where);
2N/A }
2N/A } else {
2N/A child = NULL;
2N/A }
2N/A
2N/A dirent = libuvfs_name_dirent_find(dir, name, &where);
2N/A if (oldfid != NULL) {
2N/A if (dirent != NULL)
2N/A *oldfid = dirent->de_fid;
2N/A else
2N/A oldfid->uvfid_len = 0;
2N/A }
2N/A
2N/A if (dirent == NULL) {
2N/A if (childfid != NULL) {
2N/A dirent = libuvfs_name_dirent_alloc(dir, child, name,
2N/A dirfid, childfid);
2N/A avl_insert(&dir->nm_dir, dirent, where);
2N/A list_insert_head(&child->nm_allnames, dirent);
2N/A }
2N/A } else if (overwrite) {
2N/A libuvfs_fid_info_t *oldinfo = dirent->de_myinfo;
2N/A list_remove(&oldinfo->nm_allnames, dirent);
2N/A
2N/A if (childfid != NULL) {
2N/A dirent->de_fid = *childfid;
2N/A list_insert_head(&child->nm_allnames, dirent);
2N/A dirent->de_myinfo = child;
2N/A } else {
2N/A avl_remove(&dir->nm_dir, dirent);
2N/A libuvfs_name_dirent_free(dirent);
2N/A }
2N/A }
2N/A
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A}
2N/A
2N/A/*
2N/A * Delete the fid in the given dirfid for the given name. If oldfid is
2N/A * not NULL, then the previous fid (if any) is put there.
2N/A */
2N/A
2N/Avoid
2N/Alibuvfs_name_delete(libuvfs_fs_t *fs, const libuvfs_fid_t *dirfid,
2N/A const char *name, libuvfs_fid_t *oldfid)
2N/A{
2N/A libuvfs_name_store(fs, dirfid, name, NULL, B_TRUE, oldfid);
2N/A}
2N/A
2N/A/*
2N/A * Retrieve the fid for the given dirfid and the given name.
2N/A */
2N/A
2N/Avoid
2N/Alibuvfs_name_lookup(libuvfs_fs_t *fs, const libuvfs_fid_t *dirfid,
2N/A const char *name, libuvfs_fid_t *found)
2N/A{
2N/A libuvfs_fid_info_t *dir;
2N/A libuvfs_name_dirent_t *dirent;
2N/A
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A
2N/A found->uvfid_len = 0;
2N/A dir = libuvfs_fid_info_find(fs, dirfid, NULL);
2N/A if (dir && (dirent = libuvfs_name_dirent_find(dir, name, NULL)))
2N/A *found = dirent->de_fid;
2N/A
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A}
2N/A
2N/A/*
2N/A * Return the parent fid for the given directory fid. The index parameter
2N/A * indicates which hard link to follow; normally, index is zero.
2N/A */
2N/A
2N/Aint
2N/Alibuvfs_name_parent(libuvfs_fs_t *fs, const libuvfs_fid_t *fid, int index,
2N/A libuvfs_fid_t *parent)
2N/A{
2N/A libuvfs_fid_info_t *me;
2N/A libuvfs_name_dirent_t *de;
2N/A int found = B_TRUE;
2N/A
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A
2N/A me = libuvfs_fid_info_find(fs, fid, NULL);
2N/A if (me == NULL) {
2N/A found = B_FALSE;
2N/A goto out;
2N/A }
2N/A
2N/A for (de = list_head(&me->nm_allnames); de != NULL;
2N/A de = list_next(&me->nm_allnames, de))
2N/A if (index-- <= 0)
2N/A break;
2N/A if (de == NULL) {
2N/A found = B_FALSE;
2N/A goto out;
2N/A }
2N/A
2N/Aout:
2N/A if (found)
2N/A *parent = de->de_dirfid;
2N/A else
2N/A parent->uvfid_len = 0;
2N/A
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A
2N/A return (found);
2N/A}
2N/A
2N/A/*
2N/A * Retrieve the fid and name for the "index"th entry in the given directory.
2N/A */
2N/A
2N/Auint32_t
2N/Alibuvfs_name_dirent(libuvfs_fs_t *fs, const libuvfs_fid_t *dirfid, int index,
2N/A libuvfs_fid_t *fid, char *name, uint32_t namesize)
2N/A{
2N/A libuvfs_fid_info_t *dir;
2N/A libuvfs_name_dirent_t *de;
2N/A uint32_t namelen = 0;
2N/A
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A dir = libuvfs_fid_info_find(fs, dirfid, NULL);
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A if (dir == NULL)
2N/A goto out;
2N/A
2N/A for (de = avl_first(&dir->nm_dir); de != NULL;
2N/A de = AVL_NEXT(&dir->nm_dir, de))
2N/A if (--index < 0)
2N/A break;
2N/A if (de == NULL)
2N/A goto out;
2N/A
2N/A *fid = de->de_fid;
2N/A namelen = strlcpy(name, de->de_name, namesize);
2N/A
2N/Aout:
2N/A
2N/A return (namelen);
2N/A}
2N/A
2N/A/*
2N/A * Given a directory and an existing name, retrieve the next name and fid
2N/A * from that directory. Note that directories are sorted by name.
2N/A */
2N/A
2N/Auint32_t
2N/Alibuvfs_name_dirent_next(libuvfs_fs_t *fs, const libuvfs_fid_t *dirfid,
2N/A libuvfs_fid_t *fid, char *name, uint32_t namesize)
2N/A{
2N/A libuvfs_fid_info_t *dir;
2N/A libuvfs_name_dirent_t *de;
2N/A uint32_t namelen = 0;
2N/A
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A dir = libuvfs_fid_info_find(fs, dirfid, NULL);
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A if (dir == NULL)
2N/A goto out;
2N/A de = libuvfs_name_dirent_find(dir, name, NULL);
2N/A if (de == NULL)
2N/A goto out;
2N/A de = AVL_NEXT(&dir->nm_dir, de);
2N/A if (de == NULL)
2N/A goto out;
2N/A
2N/A *fid = de->de_fid;
2N/A namelen = strlcpy(name, de->de_name, namesize);
2N/A
2N/Aout:
2N/A
2N/A return (namelen);
2N/A}
2N/A
2N/A/*
2N/A * Count the number of names a fid appears in, i.e. the number of known
2N/A * hard links.
2N/A */
2N/A
2N/Auint32_t
2N/Alibuvfs_name_count(libuvfs_fs_t *fs, const libuvfs_fid_t *fid)
2N/A{
2N/A libuvfs_fid_info_t *child;
2N/A uint32_t count = 0;
2N/A
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A
2N/A child = libuvfs_fid_info_find(fs, fid, NULL);
2N/A if (child != NULL) {
2N/A libuvfs_name_dirent_t *de;
2N/A
2N/A for (de = list_head(&child->nm_allnames); de != NULL;
2N/A de = list_next(&child->nm_allnames, de))
2N/A ++count;
2N/A }
2N/A
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A
2N/A return (count);
2N/A}
2N/A
2N/Astatic uint32_t
2N/Alibuvfs_name_dirent_path(libuvfs_name_dirent_t *de, char *buffer,
2N/A uint32_t size)
2N/A{
2N/A uint32_t need = 0;
2N/A
2N/A if (de->de_dir != NULL) {
2N/A libuvfs_name_dirent_t *first =
2N/A list_head(&de->de_dir->nm_allnames);
2N/A if (first != NULL)
2N/A need = libuvfs_name_dirent_path(first, buffer, size);
2N/A }
2N/A
2N/A if (need < size)
2N/A need = strlcat(buffer, "/", size);
2N/A
2N/A if (need < size)
2N/A need = strlcat(buffer, de->de_name, size);
2N/A
2N/Aout:
2N/A return (need);
2N/A}
2N/A
2N/A/*
2N/A * Determine a path for a given fid. The index parameter specifies which
2N/A * hard link to find the path for; it is normally zero.
2N/A */
2N/A
2N/Auint32_t
2N/Alibuvfs_name_path(libuvfs_fs_t *fs, const libuvfs_fid_t *fid,
2N/A uint32_t index, const char *prefix, char *buffer, uint32_t size)
2N/A{
2N/A libuvfs_fid_info_t *fnode;
2N/A libuvfs_name_dirent_t *de;
2N/A uint32_t need = 0;
2N/A
2N/A (void) mutex_lock(&fs->fs_name_lock);
2N/A
2N/A fnode = libuvfs_fid_info_find(fs, fid, NULL);
2N/A if (fnode == NULL)
2N/A goto out;
2N/A de = list_head(&fnode->nm_allnames);
2N/A if (de != NULL)
2N/A while (index-- > 0)
2N/A if ((de = list_next(&fnode->nm_allnames, de)) == NULL)
2N/A goto out;
2N/A
2N/A if (prefix == NULL)
2N/A prefix = (de != NULL) ? "" : "/";
2N/A need = strlcpy(buffer, prefix, size);
2N/A if (need >= size)
2N/A goto out;
2N/A
2N/A if (de != NULL)
2N/A need = libuvfs_name_dirent_path(de, buffer, size);
2N/A
2N/Aout:
2N/A (void) mutex_unlock(&fs->fs_name_lock);
2N/A
2N/A return (need);
2N/A}
2N/A
2N/Astatic int
2N/Alibuvfs_name_dirent_compare(const void *va, const void *vb)
2N/A{
2N/A const libuvfs_name_dirent_t *a = va;
2N/A const libuvfs_name_dirent_t *b = vb;
2N/A int rc;
2N/A
2N/A rc = strcmp(a->de_name, b->de_name);
2N/A if (rc < 0)
2N/A return (-1);
2N/A if (rc > 0)
2N/A return (1);
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Alibuvfs_fid_info_construct(void *vdir, void *foo, int bar)
2N/A{
2N/A libuvfs_fid_info_t *dir = vdir;
2N/A
2N/A (void) rwlock_init(&dir->nm_user_lock, USYNC_THREAD, NULL);
2N/A list_create(&dir->nm_allnames, sizeof (libuvfs_name_dirent_t),
2N/A offsetof(libuvfs_name_dirent_t, de_allnames));
2N/A avl_create(&dir->nm_dir, libuvfs_name_dirent_compare,
2N/A sizeof (libuvfs_name_dirent_t), offsetof(libuvfs_name_dirent_t,
2N/A de_dirnode));
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic void
2N/Alibuvfs_fid_info_destroy(void *vdir, void *foo)
2N/A{
2N/A libuvfs_fid_info_t *dir = vdir;
2N/A
2N/A avl_destroy(&dir->nm_dir);
2N/A list_destroy(&dir->nm_allnames);
2N/A (void) rwlock_destroy(&dir->nm_user_lock);
2N/A}
2N/A
2N/Astatic int
2N/Alibuvfs_fid_info_compare(const void *va, const void *vb)
2N/A{
2N/A const libuvfs_fid_info_t *a = va;
2N/A const libuvfs_fid_info_t *b = vb;
2N/A
2N/A return (libuvfs_fid_compare(&a->nm_fid, &b->nm_fid));
2N/A}
2N/A
2N/Avoid
2N/Alibuvfs_name_fs_construct(libuvfs_fs_t *fs)
2N/A{
2N/A (void) rwlock_init(&fs->fs_name_user_lock, USYNC_THREAD, NULL);
2N/A avl_create(&fs->fs_name_info_tree, libuvfs_fid_info_compare,
2N/A sizeof (libuvfs_fid_info_t), offsetof(libuvfs_fid_info_t,
2N/A nm_fs_avl));
2N/A}
2N/A
2N/Avoid
2N/Alibuvfs_name_fs_destroy(libuvfs_fs_t *fs)
2N/A{
2N/A avl_destroy(&fs->fs_name_info_tree);
2N/A (void) rwlock_destroy(&fs->fs_name_user_lock);
2N/A}
2N/A
2N/Avoid
2N/Alibuvfs_name_fs_free(libuvfs_fs_t *fs)
2N/A{
2N/A libuvfs_fid_info_t *dir;
2N/A void *cookie;
2N/A
2N/A cookie = NULL;
2N/A while ((dir = avl_destroy_nodes(&fs->fs_name_info_tree, &cookie))
2N/A != NULL)
2N/A libuvfs_fid_info_free(dir);
2N/A}
2N/A
2N/A#pragma init(libuvfs_name_init)
2N/Astatic void
2N/Alibuvfs_name_init(void)
2N/A{
2N/A libuvfs_fid_info_cache = umem_cache_create("libuvfs_fid_info_cache",
2N/A sizeof (libuvfs_fid_info_t), 0,
2N/A libuvfs_fid_info_construct, libuvfs_fid_info_destroy, NULL,
2N/A NULL, NULL, 0);
2N/A libuvfs_name_dirent_cache =
2N/A umem_cache_create("libuvfs_name_dirent_cache",
2N/A sizeof (libuvfs_name_dirent_t), 0,
2N/A NULL, NULL, NULL,
2N/A NULL, NULL, 0);
2N/A}
2N/A
2N/A#pragma fini(libuvfs_name_fini)
2N/Astatic void
2N/Alibuvfs_name_fini(void)
2N/A{
2N/A umem_cache_destroy(libuvfs_fid_info_cache);
2N/A umem_cache_destroy(libuvfs_name_dirent_cache);
2N/A}