ntdll: Store the base directory for an assembly (based on a patch by Eric Pouech).

This commit is contained in:
Alexandre Julliard 2007-07-25 17:02:11 +02:00
parent 4156a716b0
commit ad0d2b90ee
1 changed files with 73 additions and 25 deletions

View File

@ -158,6 +158,7 @@ struct assembly
enum assembly_type type; enum assembly_type type;
struct assembly_identity id; struct assembly_identity id;
struct file_info manifest; struct file_info manifest;
WCHAR *directory;
BOOL no_inherit; BOOL no_inherit;
struct dll_redirect *dlls; struct dll_redirect *dlls;
unsigned int num_dlls; unsigned int num_dlls;
@ -234,7 +235,6 @@ static WCHAR *strdupW(const WCHAR* str)
{ {
WCHAR* ptr; WCHAR* ptr;
if (!str) return NULL;
if (!(ptr = RtlAllocateHeap(GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR)))) if (!(ptr = RtlAllocateHeap(GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR))))
return NULL; return NULL;
return strcpyW(ptr, str); return strcpyW(ptr, str);
@ -480,6 +480,36 @@ static void free_depend_manifests(struct actctx_loader* acl)
RtlFreeHeap(GetProcessHeap(), 0, acl->dependencies); RtlFreeHeap(GetProcessHeap(), 0, acl->dependencies);
} }
static WCHAR *build_assembly_dir(struct assembly_identity* ai)
{
static const WCHAR undW[] = {'_',0};
static const WCHAR noneW[] = {'n','o','n','e',0};
static const WCHAR mskeyW[] = {'d','e','a','d','b','e','e','f',0};
static const WCHAR versionW[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
const WCHAR *key = ai->public_key ? ai->public_key : noneW;
const WCHAR *lang = ai->language ? ai->language : noneW;
SIZE_T size = (strlenW(ai->arch) + 1 + strlenW(ai->name) + 1 + strlenW(key) + 24 + 1 +
strlenW(lang) + 1) * sizeof(WCHAR) + sizeof(mskeyW);
WCHAR *ret;
if (!(ret = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return NULL;
strcpyW( ret, ai->arch );
strcatW( ret, undW );
strcatW( ret, ai->name );
strcatW( ret, undW );
strcatW( ret, key );
strcatW( ret, undW );
sprintfW( ret + strlenW(ret), versionW,
ai->version.major, ai->version.minor, ai->version.build, ai->version.revision );
strcatW( ret, undW );
strcatW( ret, lang );
strcatW( ret, undW );
strcatW( ret, mskeyW );
return ret;
}
static ACTIVATION_CONTEXT *check_actctx( HANDLE h ) static ACTIVATION_CONTEXT *check_actctx( HANDLE h )
{ {
ACTIVATION_CONTEXT *actctx = h; ACTIVATION_CONTEXT *actctx = h;
@ -517,6 +547,7 @@ static void actctx_release( ACTIVATION_CONTEXT *actctx )
} }
RtlFreeHeap( GetProcessHeap(), 0, assembly->dlls ); RtlFreeHeap( GetProcessHeap(), 0, assembly->dlls );
RtlFreeHeap( GetProcessHeap(), 0, assembly->manifest.info ); RtlFreeHeap( GetProcessHeap(), 0, assembly->manifest.info );
RtlFreeHeap( GetProcessHeap(), 0, assembly->directory );
free_entity_array( &assembly->entities ); free_entity_array( &assembly->entities );
free_assembly_identity(&assembly->id); free_assembly_identity(&assembly->id);
} }
@ -1336,16 +1367,19 @@ static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl,
} }
static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_identity* ai, static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
LPCWSTR filename, xmlbuf_t* xmlbuf ) LPCWSTR filename, LPCWSTR directory, xmlbuf_t* xmlbuf )
{ {
xmlstr_t elem; xmlstr_t elem;
struct assembly* assembly; struct assembly* assembly;
TRACE( "parsing manifest loaded from %s\n", debugstr_w(filename) ); TRACE( "parsing manifest loaded from %s base dir %s\n", debugstr_w(filename), debugstr_w(directory) );
if (!(assembly = add_assembly(acl->actctx, ASSEMBLY_MANIFEST))) if (!(assembly = add_assembly(acl->actctx, ASSEMBLY_MANIFEST)))
return STATUS_SXS_CANT_GEN_ACTCTX; return STATUS_SXS_CANT_GEN_ACTCTX;
if (directory && !(assembly->directory = strdupW(directory)))
return STATUS_NO_MEMORY;
if (filename) assembly->manifest.info = strdupW( filename + 4 /* skip \??\ prefix */ ); if (filename) assembly->manifest.info = strdupW( filename + 4 /* skip \??\ prefix */ );
assembly->manifest.type = assembly->manifest.info ? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE assembly->manifest.type = assembly->manifest.info ? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
: ACTIVATION_CONTEXT_PATH_TYPE_NONE; : ACTIVATION_CONTEXT_PATH_TYPE_NONE;
@ -1420,7 +1454,8 @@ static NTSTATUS get_module_filename( HMODULE module, UNICODE_STRING *str, unsign
} }
static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai, static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai,
LPCWSTR filename, HANDLE hModule, LPCWSTR resname, ULONG lang ) LPCWSTR filename, LPCWSTR directory, HANDLE hModule,
LPCWSTR resname, ULONG lang )
{ {
NTSTATUS status; NTSTATUS status;
UNICODE_STRING nameW; UNICODE_STRING nameW;
@ -1463,13 +1498,14 @@ static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assemb
xmlbuf_t buf; xmlbuf_t buf;
buf.ptr = ptr; buf.ptr = ptr;
buf.end = buf.ptr + entry->Size; buf.end = buf.ptr + entry->Size;
status = parse_manifest(acl, ai, filename, &buf); status = parse_manifest(acl, ai, filename, directory, &buf);
} }
return status; return status;
} }
static NTSTATUS get_manifest_in_pe_file( struct actctx_loader* acl, struct assembly_identity* ai, static NTSTATUS get_manifest_in_pe_file( struct actctx_loader* acl, struct assembly_identity* ai,
LPCWSTR filename, HANDLE file, LPCWSTR resname, ULONG lang ) LPCWSTR filename, LPCWSTR directory, HANDLE file,
LPCWSTR resname, ULONG lang )
{ {
HANDLE mapping; HANDLE mapping;
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
@ -1504,7 +1540,7 @@ static NTSTATUS get_manifest_in_pe_file( struct actctx_loader* acl, struct assem
if (RtlImageNtHeader(base)) /* we got a PE file */ if (RtlImageNtHeader(base)) /* we got a PE file */
{ {
HANDLE module = (HMODULE)((ULONG_PTR)base | 1); /* make it a LOAD_LIBRARY_AS_DATAFILE handle */ HANDLE module = (HMODULE)((ULONG_PTR)base | 1); /* make it a LOAD_LIBRARY_AS_DATAFILE handle */
status = get_manifest_in_module( acl, ai, filename, module, resname, lang ); status = get_manifest_in_module( acl, ai, filename, directory, module, resname, lang );
} }
else status = STATUS_INVALID_IMAGE_FORMAT; else status = STATUS_INVALID_IMAGE_FORMAT;
@ -1513,7 +1549,7 @@ static NTSTATUS get_manifest_in_pe_file( struct actctx_loader* acl, struct assem
} }
static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct assembly_identity* ai, static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct assembly_identity* ai,
LPCWSTR filename, HANDLE file ) LPCWSTR filename, LPCWSTR directory, HANDLE file )
{ {
HANDLE mapping; HANDLE mapping;
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
@ -1548,7 +1584,7 @@ static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct
buf.ptr = base; buf.ptr = base;
buf.end = buf.ptr + count; buf.end = buf.ptr + count;
status = parse_manifest(acl, ai, filename, &buf); status = parse_manifest(acl, ai, filename, directory, &buf);
NtUnmapViewOfSection( GetCurrentProcess(), base ); NtUnmapViewOfSection( GetCurrentProcess(), base );
return status; return status;
@ -1556,7 +1592,7 @@ static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct
/* try to load the .manifest file associated to the file */ /* try to load the .manifest file associated to the file */
static NTSTATUS get_manifest_in_associated_manifest( struct actctx_loader* acl, struct assembly_identity* ai, static NTSTATUS get_manifest_in_associated_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
LPCWSTR filename, HMODULE module, LPCWSTR resname ) LPCWSTR filename, LPCWSTR directory, HMODULE module, LPCWSTR resname )
{ {
static const WCHAR fmtW[] = { '.','%','l','u',0 }; static const WCHAR fmtW[] = { '.','%','l','u',0 };
WCHAR *buffer; WCHAR *buffer;
@ -1597,7 +1633,7 @@ static NTSTATUS get_manifest_in_associated_manifest( struct actctx_loader* acl,
status = open_nt_file( &file, &nameW ); status = open_nt_file( &file, &nameW );
if (status == STATUS_SUCCESS) if (status == STATUS_SUCCESS)
{ {
status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, file ); status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, file );
NtClose( file ); NtClose( file );
} }
RtlFreeUnicodeString( &nameW ); RtlFreeUnicodeString( &nameW );
@ -1731,16 +1767,17 @@ static NTSTATUS lookup_winsxs(struct actctx_loader* acl, struct assembly_identit
path[path_us.Length/sizeof(WCHAR)] = '\\'; path[path_us.Length/sizeof(WCHAR)] = '\\';
strcpyW( path + path_us.Length/sizeof(WCHAR) + 1, file ); strcpyW( path + path_us.Length/sizeof(WCHAR) + 1, file );
RtlFreeHeap( GetProcessHeap(), 0, file );
RtlInitUnicodeString( &path_us, path ); RtlInitUnicodeString( &path_us, path );
*strrchrW(file, '.') = 0; /* remove .manifest extension */
if (!open_nt_file( &handle, &path_us )) if (!open_nt_file( &handle, &path_us ))
{ {
io.u.Status = get_manifest_in_manifest_file(acl, &sxs_ai, path_us.Buffer, handle); io.u.Status = get_manifest_in_manifest_file(acl, &sxs_ai, path_us.Buffer, file, handle);
NtClose( handle ); NtClose( handle );
} }
else io.u.Status = STATUS_NO_SUCH_FILE; else io.u.Status = STATUS_NO_SUCH_FILE;
RtlFreeHeap( GetProcessHeap(), 0, file );
RtlFreeUnicodeString( &path_us ); RtlFreeUnicodeString( &path_us );
return io.u.Status; return io.u.Status;
} }
@ -1750,7 +1787,7 @@ static NTSTATUS lookup_assembly(struct actctx_loader* acl,
{ {
static const WCHAR dotDllW[] = {'.','d','l','l',0}; static const WCHAR dotDllW[] = {'.','d','l','l',0};
unsigned int i; unsigned int i;
WCHAR *buffer, *p; WCHAR *buffer, *p, *directory;
NTSTATUS status; NTSTATUS status;
UNICODE_STRING nameW; UNICODE_STRING nameW;
HANDLE file; HANDLE file;
@ -1764,6 +1801,12 @@ static NTSTATUS lookup_assembly(struct actctx_loader* acl,
(strlenW(acl->actctx->appdir.info) + 2 * strlenW(ai->name) + 2) * sizeof(WCHAR) + sizeof(dotManifestW) ))) (strlenW(acl->actctx->appdir.info) + 2 * strlenW(ai->name) + 2) * sizeof(WCHAR) + sizeof(dotManifestW) )))
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
if (!(directory = build_assembly_dir( ai )))
{
RtlFreeHeap( GetProcessHeap(), 0, buffer );
return STATUS_NO_MEMORY;
}
/* lookup in appdir\name.dll /* lookup in appdir\name.dll
* appdir\name.manifest * appdir\name.manifest
* appdir\name\name.dll * appdir\name\name.dll
@ -1783,7 +1826,7 @@ static NTSTATUS lookup_assembly(struct actctx_loader* acl,
status = open_nt_file( &file, &nameW ); status = open_nt_file( &file, &nameW );
if (!status) if (!status)
{ {
status = get_manifest_in_pe_file( acl, ai, nameW.Buffer, file, status = get_manifest_in_pe_file( acl, ai, nameW.Buffer, directory, file,
(LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID, 0 ); (LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID, 0 );
NtClose( file ); NtClose( file );
break; break;
@ -1797,15 +1840,18 @@ static NTSTATUS lookup_assembly(struct actctx_loader* acl,
status = open_nt_file( &file, &nameW ); status = open_nt_file( &file, &nameW );
if (!status) if (!status)
{ {
status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, file ); status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, file );
NtClose( file ); NtClose( file );
break; break;
} }
RtlFreeUnicodeString( &nameW ); RtlFreeUnicodeString( &nameW );
} }
status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
} }
RtlFreeUnicodeString( &nameW ); RtlFreeUnicodeString( &nameW );
return STATUS_SXS_ASSEMBLY_NOT_FOUND; RtlFreeHeap( GetProcessHeap(), 0, directory );
RtlFreeHeap( GetProcessHeap(), 0, buffer );
return status;
} }
static NTSTATUS parse_depend_manifests(struct actctx_loader* acl) static NTSTATUS parse_depend_manifests(struct actctx_loader* acl)
@ -1855,6 +1901,7 @@ void actctx_init(void)
NTSTATUS WINAPI RtlCreateActivationContext( HANDLE *handle, const void *ptr ) NTSTATUS WINAPI RtlCreateActivationContext( HANDLE *handle, const void *ptr )
{ {
const ACTCTXW *pActCtx = ptr; /* FIXME: not the right structure */ const ACTCTXW *pActCtx = ptr; /* FIXME: not the right structure */
const WCHAR *directory = NULL;
ACTIVATION_CONTEXT *actctx; ACTIVATION_CONTEXT *actctx;
UNICODE_STRING nameW; UNICODE_STRING nameW;
ULONG lang = 0; ULONG lang = 0;
@ -1913,32 +1960,33 @@ NTSTATUS WINAPI RtlCreateActivationContext( HANDLE *handle, const void *ptr )
acl.allocated_dependencies = 0; acl.allocated_dependencies = 0;
if (pActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID) lang = pActCtx->wLangId; if (pActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID) lang = pActCtx->wLangId;
if (pActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) directory = pActCtx->lpAssemblyDirectory;
if (pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) if (pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID)
{ {
/* if we have a resource it's a PE file */ /* if we have a resource it's a PE file */
if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID) if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)
{ {
status = get_manifest_in_module( &acl, NULL, NULL, pActCtx->hModule, status = get_manifest_in_module( &acl, NULL, NULL, directory, pActCtx->hModule,
pActCtx->lpResourceName, lang ); pActCtx->lpResourceName, lang );
if (status) if (status)
/* FIXME: what to do if pActCtx->lpSource is set */ /* FIXME: what to do if pActCtx->lpSource is set */
status = get_manifest_in_associated_manifest( &acl, NULL, NULL, pActCtx->hModule, status = get_manifest_in_associated_manifest( &acl, NULL, NULL, directory,
pActCtx->lpResourceName ); pActCtx->hModule, pActCtx->lpResourceName );
} }
else if (pActCtx->lpSource) else if (pActCtx->lpSource)
{ {
status = get_manifest_in_pe_file( &acl, NULL, nameW.Buffer, file, status = get_manifest_in_pe_file( &acl, NULL, nameW.Buffer, directory,
pActCtx->lpResourceName, lang ); file, pActCtx->lpResourceName, lang );
if (status) if (status)
status = get_manifest_in_associated_manifest( &acl, NULL, nameW.Buffer, NULL, status = get_manifest_in_associated_manifest( &acl, NULL, nameW.Buffer, directory,
pActCtx->lpResourceName ); NULL, pActCtx->lpResourceName );
} }
else status = STATUS_INVALID_PARAMETER; else status = STATUS_INVALID_PARAMETER;
} }
else else
{ {
status = get_manifest_in_manifest_file( &acl, NULL, nameW.Buffer, file ); status = get_manifest_in_manifest_file( &acl, NULL, nameW.Buffer, directory, file );
} }
if (file) NtClose( file ); if (file) NtClose( file );