safedisc

Vitaliy Margolen vitaliy at kievinfo.com
Mon Nov 21 18:35:31 CST 2005


Monday, November 21, 2005, 4:54:56 PM, Ivan Leo Puoti wrote:
> Raphael Junqueira asked on bugzilla what the safedisc status is. Currently it works fine, and I
> believe what we have is more or less ready for CVS. However Vitaly
> told me Alexandre didn't like the 
> object manager Vitaly wrote, mostly he didn't like permanent
> objects, that drivers depend on. I 
> haven't talked to Alexandre about this but hopefully some reasonable solution can be found so we can
> get Vitaly's OM into wineserver (I mean my original implementation that uses pointers as handles
> also works, but things look better with a real OM). So let's try and trigger some community
> discussion, we are talking about the guts of wine after all. Vitaly, what's the OM status currently?
> Alexandre, what didn't you like about it?

Following Alexandre's suggestions I've managed to get OM working without
support for permanent objects. There will be some modification required
for ntoskrnl for that to work. I'm just about finished integrating new OM
into ntoskrnl tree and almost ready to give it a try.

As far as OM goes it's mostly finished and passes all but two of om
tests. Also it don't see any side-affects from it either. All the
programs I've tested work in the same way as they were before. All named
object moved to directories and using RootDirectory part of
OBJECT_ATTRIBUTES for create/open.

Attached is the final revision of the directory object implementation. If
it looks ok I'm ready to send some patches <g>

Vitaliy



-------------- next part --------------
/*
 * Server-side directory object management
 *
 * Copyright (C) 2005 Vitaliy Margolen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "config.h"
#include "wine/port.h"

#include <assert.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/types.h>

#include "windef.h"
#include "winternl.h"

#include "handle.h"
#include "request.h"
#include "process.h"
#include "unicode.h"
#include "wine/list.h"
#include "object.h"

#define HASH_SIZE 37

#define DIRECTORY_QUERY                 (0x0001)
#define DIRECTORY_TRAVERSE              (0x0002)
#define DIRECTORY_CREATE_OBJECT         (0x0004)
#define DIRECTORY_CREATE_SUBDIRECTORY   (0x0008)
#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF)

struct directory
{
    struct object obj;              /* object header */
    struct list entries[HASH_SIZE]; /* array of hash entry lists */
};

static void directory_dump( struct object *obj, int verbose );
static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
                                             unsigned int attr );

static const struct object_ops directory_ops =
{
    sizeof(struct directory),     /* size */
    directory_dump,               /* dump */
    no_add_queue,                 /* add_queue */
    NULL,                         /* remove_queue */
    NULL,                         /* signaled */
    NULL,                         /* satisfied */
    no_signal,                    /* signal */
    no_get_fd,                    /* get_fd */
    directory_lookup_name,        /* lookup_name */
    no_close_handle,              /* close_handle */
    no_destroy                    /* destroy */
};

static void directory_dump( struct object *obj, int verbose )
{
    struct directory *dir = (struct directory *)obj;
    assert( obj->ops == &directory_ops );

    fputs( "Directory ", stderr );
    dump_object_name( obj );
    if (verbose)
    {
        unsigned int i;

        fputs( " entries:\n", stderr );
        for (i = 0; i < HASH_SIZE; i++)
        {
            struct list *p = &dir->entries[i];
            struct object_name *ptr;

            LIST_FOR_EACH_ENTRY(ptr, p, struct object_name, entry)
            {
                fputs( " ", stderr );
                dump_object_name( ptr->obj );
                fputc( '\n', stderr );
            }
        }
    }
    else
        fputc( '\n', stderr );
}

/* find an object by its name in a given directory; the refcount is incremented
 * name - is a relative name */
static struct object *find_object_in_dir( struct directory *dir, const WCHAR *name,
                                          size_t len, unsigned int attr )
{
    const struct list *list, *p;

    if (!name || !len) return NULL;

    list = &dir->entries[ get_name_hash( name, len ) % HASH_SIZE ];
    LIST_FOR_EACH( p, list )
    {
        const struct object_name *ptr = LIST_ENTRY( p, const struct object_name, entry );
        if (!ptr || ptr->len != len) continue;
        if (attr & OBJ_CASE_INSENSITIVE)
        {
            if (!strncmpiW( ptr->name, name, len/sizeof(WCHAR) )) return grab_object( ptr->obj );
        }
        else
        {
            if (!memcmp( ptr->name, name, len )) return grab_object( ptr->obj );
        }
    }
    return NULL;
}

static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
                                             unsigned int attr )
{
    struct object *found;
    WCHAR *p;
    size_t sz;
    assert( obj->ops == &directory_ops );

    if (!(p = memchrW( name->str, '\\', name->len / sizeof(WCHAR) )))
        /* Last element in the path name */
        sz = name->len;
    else
        sz = (p - name->str) * sizeof(WCHAR);

    if ((found = find_object_in_dir( (struct directory *)obj, name->str, sz, attr )))
    {
        /* Skip trailing \\ */
        if (p)
        {
            p++;
            sz += sizeof(WCHAR);
        }
        /* Move to the next element*/
        name->str = p;
        name->len -= sz;
        return found;
    }

    if (name->str)
    {
        if (sz == 0) /* Double backslash */
            set_error( STATUS_OBJECT_NAME_INVALID );
        else if (p)  /* Path still has backslashes */
            set_error( STATUS_OBJECT_PATH_NOT_FOUND );
    }
    return NULL;
}

/******************************************************************************/

/* Create root directory - it's a special case when no namespace exists yet.*/
struct directory *create_root( void )
{
    static const WCHAR rootW[]={'\\'};
    static const struct unicode_str root = {rootW, sizeof(rootW)};
    struct directory *dir;
    struct object_name *name_ptr;

    if (!(name_ptr = alloc_name( &root ))) return NULL;
    if ((dir = alloc_object( &directory_ops )))
    {
        unsigned int i;
        /* root has no parents */
        list_init( &name_ptr->entry );
        name_ptr->obj = &dir->obj;
        dir->obj.name = name_ptr;
        for (i = 0; i < HASH_SIZE; i++)
            list_init( &dir->entries[i] );
    }
    else free( name_ptr );
    return dir;
}

struct directory *create_directory( const struct object_attr *attr )
{
    struct directory *dir;

    if ((dir = create_named_object( attr, &directory_ops )))
    {
        if (get_error() != STATUS_OBJECT_NAME_EXISTS)
        {
            unsigned int i;
            for (i = 0; i < HASH_SIZE; i++)
                list_init( &dir->entries[i] );
        }
    }
    return dir;
}

static void insert_into_dir( struct directory* dir, struct object *obj )
{
    int hash = get_name_hash( obj->name->name, obj->name->len) % HASH_SIZE;

    grab_object( dir );
    obj->name->parent = &dir->obj;
    list_add_head( &dir->entries[hash], &obj->name->entry );
}

/******************************************************************************/

/*
 * Find an object by it's name in a given root object
 *
 * PARAMS
 *  attr      [I] rootdir, name and attributes
 *  name_left [O] [optional] leftover name if object is not found
 *
 * RETURNS
 *  NULL:      If params are invalid
 *  Found:     If object with exact name is found returns that object. (name_left->len == 0)
 *             Object's refcount is incremented
 *  Not found: The last matched parent. (name_left->len > 0)
 *             Parent's refcount is incremented.
 */
struct object *find_object( const struct object_attr *attr, struct unicode_str *name_left )
{
    struct object *obj, *parent;
    struct unicode_str name_l = *attr->name;

    /* Arguments check:
     * - Either name or root have to be specified
     * - If root is specified path shouldn't start with backslash */
    if (!attr ||
        (!attr->rootdir && (!name_l.str || !name_l.len)) ||
        (name_l.len && ((*name_l.str == '\\' && attr->rootdir) ||
                        (*name_l.str != '\\' && !attr->rootdir))))
    {
        set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
        return NULL;
    }

    if (attr->rootdir)
        parent = get_handle_obj( current->process, attr->rootdir, 0, &directory_ops );
    else
        parent = grab_object( root_directory );
    if (!parent) return NULL;

    /* Skip leading backslash */
    if (name_l.len && *name_l.str == '\\')
    {
        name_l.str++;
        name_l.len -= sizeof(WCHAR);
    }

    /* Special case for opening RootDirectory */
    if (!name_l.len) goto done;

    while ((obj = parent->ops->lookup_name( parent, &name_l, attr->attributes )))
    {
        /* move to the next element */
        release_object ( parent );
        parent = obj;
    }
    if (get_error())
    {
        release_object ( parent );
        return NULL;
    }

    done:
    if (name_left) dup_unicode_str(&name_l, name_left);
    return parent;
}

void *create_named_object( const struct object_attr *attr, const struct object_ops *ops )
{
    struct object *obj, *new_obj = NULL;
    struct unicode_str new_name;
    struct object_name *name_ptr;

    if (!attr || !attr->name || !attr->name->len)
    {
        if((new_obj = alloc_object( ops ))) return new_obj;
    }

    if (!(obj = find_object( attr, &new_name ))) return NULL;
    if (!new_name.len)
    {
        if (attr->attributes & OBJ_OPENIF && obj->ops == ops)
            set_error( STATUS_OBJECT_NAME_EXISTS );
        else
        {
            release_object( obj );
            obj = NULL;
            if (attr->attributes & OBJ_OPENIF)
                set_error( STATUS_OBJECT_TYPE_MISMATCH );
            else
                set_error( STATUS_OBJECT_NAME_COLLISION );
        }
        return obj;
    }

    /* We can't insert objects into anything else but directories */
    if (obj->ops != &directory_ops)
    {
        release_object( obj );
        set_error( STATUS_OBJECT_TYPE_MISMATCH );
        return NULL;
    }

    if (!(name_ptr = alloc_name( &new_name ))) goto done;
    if ((new_obj = alloc_object( ops )))
    {
        name_ptr->obj = new_obj;
        new_obj->name = name_ptr;
        insert_into_dir( (struct directory *)obj, new_obj );

        clear_error();
    }
    else free( name_ptr );

done:
    release_object( obj );
    free_unicode_str( &new_name );
if (new_obj){fprintf(stderr, "create_named_object:%d: mew_obj: ", __LINE__);dump_object_name( new_obj );fprintf(stderr, " in: ");
dump_object_name( obj ); fprintf(stderr, " refcount=%d \n", obj->refcount);}
    return new_obj;
}

/* open a new handle to an existing object */
obj_handle_t open_object( const struct object_attr *attr, const struct object_ops *ops,
                          unsigned int access )
{
    obj_handle_t handle = 0;
    struct unicode_str name_left;
    struct object *obj;

    if ((obj = find_object( attr, &name_left )))
    {
        if (name_left.len) /* not fully parsed */
            set_error( STATUS_OBJECT_PATH_NOT_FOUND );
        else if (ops && obj->ops != ops)
            set_error( STATUS_OBJECT_TYPE_MISMATCH );
        else
            handle = alloc_handle( current->process, obj, access, attr->attributes & OBJ_INHERIT );

        release_object( obj );
        free_unicode_str( &name_left );
    }
    return handle;
}

/******************************************************************************/

DECL_HANDLER(create_directory)
{
    struct directory *dir;
    struct object_attr attr;
    struct unicode_str name;
    reply->handle = 0;

    GET_OBJECT_ATTR(&attr, req, &name)
    if ((dir = create_directory( &attr )))
    {
        reply->handle = alloc_handle( current->process, dir, req->access,
                                      attr.attributes & OBJ_INHERIT );
        release_object( dir );
    }
}

DECL_HANDLER(open_directory)
{
    struct object_attr attr;
    struct unicode_str name;

    GET_OBJECT_ATTR(&attr, req, &name)
    reply->handle = open_object( &attr, &directory_ops, req->access );
}


More information about the wine-devel mailing list