From 80444dfe518aaaeb5215d0239adb4401704fbb41 Mon Sep 17 00:00:00 2001 From: Vitaliy Margolen Date: Wed, 30 Nov 2005 19:22:57 +0100 Subject: [PATCH] Implement symbolic link object in wineserver. Implement Nt[Create|Open|Query]SymbolicLinkObject. Change tests accordingly. --- dlls/ntdll/om.c | 141 ++++++++++++++++++++---- dlls/ntdll/tests/om.c | 34 +++--- include/wine/server_protocol.h | 58 +++++++++- server/Makefile.in | 1 + server/directory.c | 39 +++++-- server/object.h | 6 + server/protocol.def | 32 ++++++ server/request.h | 6 + server/symlink.c | 196 +++++++++++++++++++++++++++++++++ server/trace.c | 52 +++++++++ 10 files changed, 515 insertions(+), 50 deletions(-) create mode 100644 server/symlink.c diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c index bd314a397e..8a358eb184 100644 --- a/dlls/ntdll/om.c +++ b/dlls/ntdll/om.c @@ -2,6 +2,7 @@ * Object management functions * * Copyright 1999, 2000 Juergen Schmied + * Copyright 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 @@ -470,45 +471,137 @@ NTSTATUS WINAPI NtQueryDirectoryObject(IN HANDLE DirectoryHandle, OUT PDIRECTORY /****************************************************************************** * NtOpenSymbolicLinkObject [NTDLL.@] + * ZwOpenSymbolicLinkObject [NTDLL.@] + * + * Open a namespace symbolic link object. + * + * PARAMS + * LinkHandle [O] Destination for the new symbolic link handle + * DesiredAccess [I] Desired access to the symbolic link + * ObjectAttributes [I] Structure describing the symbolic link + * + * RETURNS + * Success: ERROR_SUCCESS. + * Failure: An NTSTATUS error code. */ -NTSTATUS WINAPI NtOpenSymbolicLinkObject( - OUT PHANDLE LinkHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) +NTSTATUS WINAPI NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) { - FIXME("(%p,0x%08lx,%p) stub\n", - LinkHandle, DesiredAccess, ObjectAttributes); - dump_ObjectAttributes(ObjectAttributes); - return STATUS_OBJECT_NAME_NOT_FOUND; + NTSTATUS ret; + TRACE("(%p,0x%08lx,%p)\n",LinkHandle, DesiredAccess, ObjectAttributes); + dump_ObjectAttributes(ObjectAttributes); + + if (!LinkHandle) return STATUS_ACCESS_VIOLATION; + if (!ObjectAttributes) return STATUS_INVALID_PARAMETER; + /* Have to test it here because server won't know difference between + * ObjectName == NULL and ObjectName == "" */ + if (!ObjectAttributes->ObjectName) + { + if (ObjectAttributes->RootDirectory) + return STATUS_OBJECT_NAME_INVALID; + else + return STATUS_OBJECT_PATH_SYNTAX_BAD; + } + + SERVER_START_REQ(open_symlink) + { + req->access = DesiredAccess; + req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0; + req->rootdir = ObjectAttributes ? ObjectAttributes->RootDirectory : 0; + if (ObjectAttributes->ObjectName) + wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer, + ObjectAttributes->ObjectName->Length); + ret = wine_server_call( req ); + *LinkHandle = reply->handle; + } + SERVER_END_REQ; + return ret; } /****************************************************************************** * NtCreateSymbolicLinkObject [NTDLL.@] + * ZwCreateSymbolicLinkObject [NTDLL.@] + * + * Open a namespace symbolic link object. + * + * PARAMS + * SymbolicLinkHandle [O] Destination for the new symbolic link handle + * DesiredAccess [I] Desired access to the symbolic link + * ObjectAttributes [I] Structure describing the symbolic link + * TargetName [I] Name of the target symbolic link points to + * + * RETURNS + * Success: ERROR_SUCCESS. + * Failure: An NTSTATUS error code. */ -NTSTATUS WINAPI NtCreateSymbolicLinkObject( - OUT PHANDLE SymbolicLinkHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN PUNICODE_STRING Name) +NTSTATUS WINAPI NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PUNICODE_STRING TargetName) { - FIXME("(%p,0x%08lx,%p, %p) stub\n", - SymbolicLinkHandle, DesiredAccess, ObjectAttributes, debugstr_us(Name)); - dump_ObjectAttributes(ObjectAttributes); - return 0; + NTSTATUS ret; + TRACE("(%p,0x%08lx,%p, -> %s)\n", SymbolicLinkHandle, DesiredAccess, ObjectAttributes, + debugstr_us(TargetName)); + dump_ObjectAttributes(ObjectAttributes); + + if (!SymbolicLinkHandle || !TargetName) return STATUS_ACCESS_VIOLATION; + if (!TargetName->Buffer) return STATUS_INVALID_PARAMETER; + + SERVER_START_REQ(create_symlink) + { + req->access = DesiredAccess; + req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0; + req->rootdir = ObjectAttributes ? ObjectAttributes->RootDirectory : 0; + if (ObjectAttributes->ObjectName) + { + req->name_len = ObjectAttributes->ObjectName->Length; + wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer, + ObjectAttributes->ObjectName->Length); + } + else + req->name_len = 0; + wine_server_add_data(req, TargetName->Buffer, TargetName->Length); + ret = wine_server_call( req ); + *SymbolicLinkHandle = reply->handle; + } + SERVER_END_REQ; + return ret; } /****************************************************************************** * NtQuerySymbolicLinkObject [NTDLL.@] + * ZwQuerySymbolicLinkObject [NTDLL.@] + * + * Query a namespace symbolic link object target name. + * + * PARAMS + * LinkHandle [I] Handle to a symbolic link object + * LinkTarget [O] Destination for the symbolic link target + * ReturnedLength [O] Size of returned data + * + * RETURNS + * Success: ERROR_SUCCESS. + * Failure: An NTSTATUS error code. */ -NTSTATUS WINAPI NtQuerySymbolicLinkObject( - IN HANDLE LinkHandle, - IN OUT PUNICODE_STRING LinkTarget, - OUT PULONG ReturnedLength OPTIONAL) +NTSTATUS WINAPI NtQuerySymbolicLinkObject(IN HANDLE LinkHandle, IN OUT PUNICODE_STRING LinkTarget, + OUT PULONG ReturnedLength OPTIONAL) { - FIXME("(%p,%p,%p) stub\n", - LinkHandle, debugstr_us(LinkTarget), ReturnedLength); + NTSTATUS ret; + TRACE("(%p,%p,%p)\n", LinkHandle, LinkTarget, ReturnedLength); - return 0; + if (!LinkTarget) return STATUS_ACCESS_VIOLATION; + + SERVER_START_REQ(query_symlink) + { + req->handle = LinkHandle; + wine_server_set_reply( req, LinkTarget->Buffer, LinkTarget->MaximumLength ); + if (!(ret = wine_server_call( req ))) + { + LinkTarget->Length = wine_server_reply_size(reply); + if (ReturnedLength) *ReturnedLength = LinkTarget->Length; + } + } + SERVER_END_REQ; + return ret; } /****************************************************************************** diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 747c477774..79bd6b66fc 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -185,9 +185,7 @@ static void test_name_collisions(void) InitializeObjectAttributes(&attr, &str, 0, 0, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "\\"); - h = 0; DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_COLLISION) - ok(h == 0, "Failed create returned valid handle! (%p)\n", h); InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, 0, NULL); DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_EXISTS) @@ -336,11 +334,11 @@ void test_directory(void) pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local"); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtOpenSymbolicLinkObject(&dir, SYMBOLIC_LINK_QUERY, &attr);\ - todo_wine ok(status == STATUS_SUCCESS, "Failed to open SymbolicLink(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to open SymbolicLink(%08lx)\n", status); pRtlFreeUnicodeString(&str); InitializeObjectAttributes(&attr, &str, 0, dir, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "one more level"); - todo_wine{ DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_TYPE_MISMATCH) } + DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_TYPE_MISMATCH) pRtlFreeUnicodeString(&str); pNtClose(h); pNtClose(dir); @@ -396,15 +394,15 @@ void test_directory(void) InitializeObjectAttributes(&attr, &str, 0, 0, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Global\\om.c-test"); - todo_wine{ DIR_TEST_CREATE_SUCCESS(&dir) } + DIR_TEST_CREATE_SUCCESS(&dir) pRtlFreeUnicodeString(&str); pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local\\om.c-test\\one more level"); - todo_wine{ DIR_TEST_CREATE_SUCCESS(&h) } + DIR_TEST_CREATE_SUCCESS(&h) pRtlFreeUnicodeString(&str); pNtClose(h); InitializeObjectAttributes(&attr, &str, 0, dir, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "one more level"); - todo_wine{ DIR_TEST_CREATE_SUCCESS(&dir) } + DIR_TEST_CREATE_SUCCESS(&dir) pRtlFreeUnicodeString(&str); pNtClose(h); @@ -476,18 +474,18 @@ void test_symboliclink(void) IO_STATUS_BLOCK iosb; /* No name and/or no attributes */ - todo_wine{ SYMLNK_TEST_CREATE_OPEN_FAILURE(NULL, "", "", STATUS_ACCESS_VIOLATION) } + SYMLNK_TEST_CREATE_OPEN_FAILURE(NULL, "", "", STATUS_ACCESS_VIOLATION) status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, NULL); - todo_wine ok(status == STATUS_ACCESS_VIOLATION, + ok(status == STATUS_ACCESS_VIOLATION, "NtCreateSymbolicLinkObject should have failed with STATUS_ACCESS_VIOLATION got(%08lx)\n", status); status = pNtOpenSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL); - todo_wine ok(status == STATUS_INVALID_PARAMETER, + ok(status == STATUS_INVALID_PARAMETER, "NtOpenSymbolicLinkObject should have failed with STATUS_INVALID_PARAMETER got(%08lx)\n", status); InitializeObjectAttributes(&attr, NULL, 0, 0, NULL); - todo_wine{ SYMLNK_TEST_CREATE_FAILURE(&link, STATUS_INVALID_PARAMETER) } - todo_wine{ SYMLNK_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) } + SYMLNK_TEST_CREATE_FAILURE(&link, STATUS_INVALID_PARAMETER) + SYMLNK_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) /* Bad name */ pRtlCreateUnicodeStringFromAsciiz(&target, "anywhere"); @@ -495,7 +493,7 @@ void test_symboliclink(void) pRtlCreateUnicodeStringFromAsciiz(&str, ""); SYMLNK_TEST_CREATE_SUCCESS(&link) - todo_wine{ SYMLNK_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) } + SYMLNK_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) pNtClose(link); pRtlFreeUnicodeString(&str); @@ -504,11 +502,11 @@ void test_symboliclink(void) pRtlFreeUnicodeString(&str); pRtlFreeUnicodeString(&target); - todo_wine{ SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects", "->Somewhere", STATUS_OBJECT_PATH_SYNTAX_BAD) } - todo_wine{ SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\", "->Somewhere", STATUS_OBJECT_NAME_INVALID) } - todo_wine{ SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects", "->Somewhere", STATUS_OBJECT_NAME_INVALID) } - todo_wine{ SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test", "->Somewhere", STATUS_OBJECT_NAME_INVALID) } - todo_wine{ SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\om.c-test\\", "->Somewhere", STATUS_OBJECT_NAME_INVALID) } + SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects", "->Somewhere", STATUS_OBJECT_PATH_SYNTAX_BAD) + SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\", "->Somewhere", STATUS_OBJECT_NAME_INVALID) + SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects", "->Somewhere", STATUS_OBJECT_NAME_INVALID) + SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test", "->Somewhere", STATUS_OBJECT_NAME_INVALID) + SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\om.c-test\\", "->Somewhere", STATUS_OBJECT_NAME_INVALID) /* Compaund test */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 213e3be55f..fcbf8b0ab3 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3609,6 +3609,53 @@ struct open_directory_reply }; + +struct create_symlink_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + size_t name_len; + /* VARARG(name,unicode_str,name_len); */ + /* VARARG(target_name,unicode_str); */ +}; +struct create_symlink_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_symlink_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(name,unicode_str); */ +}; +struct open_symlink_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct query_symlink_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct query_symlink_reply +{ + struct reply_header __header; + /* VARARG(target_name,unicode_str); */ +}; + + enum request { REQ_new_process, @@ -3818,6 +3865,9 @@ enum request REQ_set_mailslot_info, REQ_create_directory, REQ_open_directory, + REQ_create_symlink, + REQ_open_symlink, + REQ_query_symlink, REQ_NB_REQUESTS }; @@ -4032,6 +4082,9 @@ union generic_request struct set_mailslot_info_request set_mailslot_info_request; struct create_directory_request create_directory_request; struct open_directory_request open_directory_request; + struct create_symlink_request create_symlink_request; + struct open_symlink_request open_symlink_request; + struct query_symlink_request query_symlink_request; }; union generic_reply { @@ -4244,8 +4297,11 @@ union generic_reply struct set_mailslot_info_reply set_mailslot_info_reply; struct create_directory_reply create_directory_reply; struct open_directory_reply open_directory_reply; + struct create_symlink_reply create_symlink_reply; + struct open_symlink_reply open_symlink_reply; + struct query_symlink_reply query_symlink_reply; }; -#define SERVER_PROTOCOL_VERSION 200 +#define SERVER_PROTOCOL_VERSION 201 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/Makefile.in b/server/Makefile.in index 50a5049658..ee4a15a281 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -40,6 +40,7 @@ C_SRCS = \ signal.c \ snapshot.c \ sock.c \ + symlink.c \ thread.c \ timer.c \ token.c \ diff --git a/server/directory.c b/server/directory.c index 716ad66ed5..052de1065f 100644 --- a/server/directory.c +++ b/server/directory.c @@ -285,34 +285,59 @@ obj_handle_t open_object_dir( struct directory *root, const struct unicode_str * /* Global initialization */ -static struct directory *dir_global, *dir_driver, *dir_device, *dir_basenamed; +static struct directory *dir_driver, *dir_device; +static struct symlink *link_dosdev, *link_global1, *link_global2, *link_local; void init_directories(void) { /* Directories */ - static const WCHAR dir_globalW[] = {'?','?'}; + static const WCHAR dir_globalW[] = {'\\','?','?'}; static const WCHAR dir_driverW[] = {'D','r','i','v','e','r'}; static const WCHAR dir_deviceW[] = {'D','e','v','i','c','e'}; - static const WCHAR dir_basenamedW[] = {'B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s'}; + static const WCHAR dir_basenamedW[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s'}; static const struct unicode_str dir_global_str = {dir_globalW, sizeof(dir_globalW)}; static const struct unicode_str dir_driver_str = {dir_driverW, sizeof(dir_driverW)}; static const struct unicode_str dir_device_str = {dir_deviceW, sizeof(dir_deviceW)}; static const struct unicode_str dir_basenamed_str = {dir_basenamedW, sizeof(dir_basenamedW)}; + /* symlinks */ + static const WCHAR link_dosdevW[] = {'D','o','s','D','e','v','i','c','e','s'}; + static const WCHAR link_globalW[] = {'G','l','o','b','a','l'}; + static const WCHAR link_localW[] = {'L','o','c','a','l'}; + static const struct unicode_str link_dosdev_str = {link_dosdevW, sizeof(link_dosdevW)}; + static const struct unicode_str link_global_str = {link_globalW, sizeof(link_globalW)}; + static const struct unicode_str link_local_str = {link_localW, sizeof(link_localW)}; + + struct directory *dir_global, *dir_basenamed; + root_directory = create_directory( NULL, NULL, 0, HASH_SIZE ); - dir_global = create_directory( root_directory, &dir_global_str, 0, HASH_SIZE ); dir_driver = create_directory( root_directory, &dir_driver_str, 0, HASH_SIZE ); dir_device = create_directory( root_directory, &dir_device_str, 0, HASH_SIZE ); + + dir_global = create_directory( NULL, &dir_global_str, 0, HASH_SIZE ); /* use a larger hash table for this one since it can contain a lot of objects */ - dir_basenamed = create_directory( root_directory, &dir_basenamed_str, 0, 37 ); + dir_basenamed = create_directory( NULL, &dir_basenamed_str, 0, 37 ); + + /* symlinks */ + link_dosdev = create_symlink( root_directory, &link_dosdev_str, 0, &dir_global_str ); + link_global1 = create_symlink( dir_global, &link_global_str, 0, &dir_global_str ); + link_global2 = create_symlink( dir_basenamed, &link_global_str, 0, &dir_basenamed_str ); + link_local = create_symlink( dir_basenamed, &link_local_str, 0, &dir_basenamed_str ); + + /* the symlinks hold references so we can release these */ + release_object( dir_global ); + release_object( dir_basenamed ); } void close_directories(void) { - release_object( dir_global ); + release_object( link_dosdev ); + release_object( link_global1 ); + release_object( link_global2 ); + release_object( link_local ); + release_object( dir_driver ); release_object( dir_device ); - release_object( dir_basenamed ); release_object( root_directory ); } diff --git a/server/object.h b/server/object.h index 0c2ee1a6a9..c30c137864 100644 --- a/server/object.h +++ b/server/object.h @@ -193,6 +193,12 @@ extern obj_handle_t open_object_dir( struct directory *root, const struct unicod extern void init_directories(void); extern void close_directories(void); +/* symbolic link functions */ + +extern struct symlink *create_symlink( struct directory *root, const struct unicode_str *name, + unsigned int attr, const struct unicode_str *target ); + + /* global variables */ /* command-line options */ diff --git a/server/protocol.def b/server/protocol.def index 56d0bc1b70..91256e5ab0 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2527,3 +2527,35 @@ enum message_type @REPLY obj_handle_t handle; /* handle to the directory */ @END + + +/* Create a symbolic link object */ +@REQ(create_symlink) + unsigned int access; /* access flags */ + unsigned int attributes; /* object attributes */ + obj_handle_t rootdir; /* root directory */ + size_t name_len; /* length of the symlink name in bytes */ + VARARG(name,unicode_str,name_len); /* symlink name */ + VARARG(target_name,unicode_str); /* target name */ +@REPLY + obj_handle_t handle; /* handle to the symlink */ +@END + + +/* Open a symbolic link object */ +@REQ(open_symlink) + unsigned int access; /* access flags */ + unsigned int attributes; /* object attributes */ + obj_handle_t rootdir; /* root directory */ + VARARG(name,unicode_str); /* symlink name */ +@REPLY + obj_handle_t handle; /* handle to the symlink */ +@END + + +/* Query a symbolic link object */ +@REQ(query_symlink) + obj_handle_t handle; /* handle to the symlink */ +@REPLY + VARARG(target_name,unicode_str); /* target name */ +@END diff --git a/server/request.h b/server/request.h index f656372ac5..016e390c89 100644 --- a/server/request.h +++ b/server/request.h @@ -317,6 +317,9 @@ DECL_HANDLER(open_mailslot); DECL_HANDLER(set_mailslot_info); DECL_HANDLER(create_directory); DECL_HANDLER(open_directory); +DECL_HANDLER(create_symlink); +DECL_HANDLER(open_symlink); +DECL_HANDLER(query_symlink); #ifdef WANT_REQUEST_HANDLERS @@ -530,6 +533,9 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_set_mailslot_info, (req_handler)req_create_directory, (req_handler)req_open_directory, + (req_handler)req_create_symlink, + (req_handler)req_open_symlink, + (req_handler)req_query_symlink, }; #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/symlink.c b/server/symlink.c new file mode 100644 index 0000000000..7f28cc802c --- /dev/null +++ b/server/symlink.c @@ -0,0 +1,196 @@ +/* + * Server-side symbolic link 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 +#include +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winternl.h" +#include "ddk/wdm.h" + +#include "handle.h" +#include "request.h" +#include "object.h" +#include "unicode.h" + +struct symlink +{ + struct object obj; /* object header */ + WCHAR *target; /* target of the symlink */ + size_t len; /* target len in bytes */ +}; + +static void symlink_dump( struct object *obj, int verbose ); +static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ); +static void symlink_destroy( struct object *obj ); + +static const struct object_ops symlink_ops = +{ + sizeof(struct symlink), /* size */ + symlink_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + symlink_lookup_name, /* lookup_name */ + no_close_handle, /* close_handle */ + symlink_destroy /* destroy */ +}; + +static void symlink_dump( struct object *obj, int verbose ) +{ + struct symlink *symlink = (struct symlink *)obj; + assert( obj->ops == &symlink_ops ); + + fprintf( stderr, "Symlink " ); + dump_object_name( obj ); + fprintf( stderr, " -> L\"" ); + dump_strW( symlink->target, symlink->len / sizeof(WCHAR), stderr, "\"\"" ); + fprintf( stderr, "\"\n" ); +} + +static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ) +{ + struct symlink *symlink = (struct symlink *)obj; + struct unicode_str target_str, name_left; + struct object *target; + + assert( obj->ops == &symlink_ops ); + if (attr & OBJ_OPENLINK) return NULL; + + target_str.str = symlink->target; + target_str.len = symlink->len; + if ((target = find_object_dir( NULL, &target_str, attr, &name_left ))) + { + if (name_left.len) + { + release_object( target ); + target = NULL; + set_error( STATUS_OBJECT_PATH_NOT_FOUND ); + } + } + return target; +} + +static void symlink_destroy( struct object *obj ) +{ + struct symlink *symlink = (struct symlink *)obj; + assert( obj->ops == &symlink_ops ); + free( symlink->target ); +} + +struct symlink *create_symlink( struct directory *root, const struct unicode_str *name, + unsigned int attr, const struct unicode_str *target ) +{ + struct symlink *symlink; + + if (!target->len) + { + set_error( STATUS_INVALID_PARAMETER ); + return NULL; + } + if ((symlink = create_named_object_dir( root, name, attr, &symlink_ops )) && + (get_error() != STATUS_OBJECT_NAME_EXISTS)) + { + if ((symlink->target = memdup( target->str, target->len ))) + symlink->len = target->len; + else + { + release_object( symlink ); + symlink = NULL; + } + } + return symlink; +} + + +/* create a symbolic link object */ +DECL_HANDLER(create_symlink) +{ + struct symlink *symlink; + struct unicode_str name, target; + struct directory *root = NULL; + + if (req->name_len > get_req_data_size()) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + name.str = get_req_data(); + target.str = name.str + req->name_len / sizeof(WCHAR); + name.len = (target.str - name.str) * sizeof(WCHAR); + target.len = ((get_req_data_size() - name.len) / sizeof(WCHAR)) * sizeof(WCHAR); + + if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 ))) + return; + + if ((symlink = create_symlink( root, &name, req->attributes, &target ))) + { + reply->handle = alloc_handle( current->process, symlink, req->access, + req->attributes & OBJ_INHERIT ); + release_object( symlink ); + } + + if (root) release_object( root ); +} + +/* open a symbolic link object */ +DECL_HANDLER(open_symlink) +{ + struct unicode_str name; + struct directory *root = NULL; + + get_req_unicode_str( &name ); + if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 ))) + return; + + reply->handle = open_object_dir( root, &name, req->attributes | OBJ_OPENLINK, + &symlink_ops, req->access ); + + if (root) release_object( root ); +} + +/* query a symbolic link object */ +DECL_HANDLER(query_symlink) +{ + struct symlink *symlink; + + symlink = (struct symlink *)get_handle_obj( current->process, req->handle, + SYMBOLIC_LINK_QUERY, &symlink_ops ); + if (!symlink) return; + + if (get_reply_max_size() < symlink->len) + set_error( STATUS_BUFFER_TOO_SMALL ); + else + set_reply_data( symlink->target, symlink->len ); + release_object( symlink ); +} diff --git a/server/trace.c b/server/trace.c index c98633b20f..2237e7c5f0 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3121,6 +3121,49 @@ static void dump_open_directory_reply( const struct open_directory_reply *req ) fprintf( stderr, " handle=%p", req->handle ); } +static void dump_create_symlink_request( const struct create_symlink_request *req ) +{ + fprintf( stderr, " access=%08x,", req->access ); + fprintf( stderr, " attributes=%08x,", req->attributes ); + fprintf( stderr, " rootdir=%p,", req->rootdir ); + fprintf( stderr, " name_len=%d,", req->name_len ); + fprintf( stderr, " name=" ); + dump_varargs_unicode_str( min(cur_size,req->name_len) ); + fputc( ',', stderr ); + fprintf( stderr, " target_name=" ); + dump_varargs_unicode_str( cur_size ); +} + +static void dump_create_symlink_reply( const struct create_symlink_reply *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_open_symlink_request( const struct open_symlink_request *req ) +{ + fprintf( stderr, " access=%08x,", req->access ); + fprintf( stderr, " attributes=%08x,", req->attributes ); + fprintf( stderr, " rootdir=%p,", req->rootdir ); + fprintf( stderr, " name=" ); + dump_varargs_unicode_str( cur_size ); +} + +static void dump_open_symlink_reply( const struct open_symlink_reply *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_query_symlink_request( const struct query_symlink_request *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_query_symlink_reply( const struct query_symlink_reply *req ) +{ + fprintf( stderr, " target_name=" ); + dump_varargs_unicode_str( cur_size ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -3329,6 +3372,9 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_mailslot_info_request, (dump_func)dump_create_directory_request, (dump_func)dump_open_directory_request, + (dump_func)dump_create_symlink_request, + (dump_func)dump_open_symlink_request, + (dump_func)dump_query_symlink_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -3539,6 +3585,9 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_mailslot_info_reply, (dump_func)dump_create_directory_reply, (dump_func)dump_open_directory_reply, + (dump_func)dump_create_symlink_reply, + (dump_func)dump_open_symlink_reply, + (dump_func)dump_query_symlink_reply, }; static const char * const req_names[REQ_NB_REQUESTS] = { @@ -3749,6 +3798,9 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "set_mailslot_info", "create_directory", "open_directory", + "create_symlink", + "open_symlink", + "query_symlink", }; static const struct -- 2.32.0.93.g670b81a890