Add support for installing drivers 0.3
authorJ. Ali Harlow <ali@juiblex.co.uk>
Mon Feb 08 22:07:17 2010 +0000 (2010-02-08)
changeset 109ae1a7880142
parent 9 5fc4375cdfb5
child 11 1b33b0db2236
child 12 76758820d807
Add support for installing drivers
configure.ac
whelk/Makefile.am
whelk/_whelk.h
whelk/catalog.c
whelk/reg_keys.c
whelk/setup.c
whelk/whelk.c
     1.1 --- a/configure.ac	Fri Oct 16 15:24:19 2009 +0100
     1.2 +++ b/configure.ac	Mon Feb 08 22:07:17 2010 +0000
     1.3 @@ -45,6 +45,7 @@
     1.4  # Checks for header files.
     1.5  ##################################################
     1.6  AC_HEADER_STDC
     1.7 +AC_CHECK_HEADERS_ONCE([softpub.h mscat.h])
     1.8  
     1.9  ##################################################
    1.10  # Checks for typedefs, structures, and compiler characteristics.
    1.11 @@ -55,7 +56,7 @@
    1.12  ##################################################
    1.13  case $host_os in
    1.14      mingw*)
    1.15 -	EXTRA_LIBS="-lole32"
    1.16 +	EXTRA_LIBS="-lole32 -lsetupapi"
    1.17  	EXTRA_BUILD_LIBS="-Wl,-luuid"
    1.18  	EXTRA_PRIVATE_LIBS="-luuid"
    1.19          ;;
    1.20 @@ -75,6 +76,14 @@
    1.21  ##################################################
    1.22  # Checks for library functions.
    1.23  ##################################################
    1.24 +case $host_os in
    1.25 +    mingw*)
    1.26 +	save_libs="$LIBS"
    1.27 +	LIBS="-lsetupapi $LIBS"
    1.28 +	AC_CHECK_FUNCS_ONCE([SetupUninstallOEMInfW])
    1.29 +	LIBS="$save_libs"
    1.30 +	;;
    1.31 +esac
    1.32  
    1.33  ##################################################
    1.34  # Checks for processor independent files.
     2.1 --- a/whelk/Makefile.am	Fri Oct 16 15:24:19 2009 +0100
     2.2 +++ b/whelk/Makefile.am	Mon Feb 08 22:07:17 2010 +0000
     2.3 @@ -9,7 +9,7 @@
     2.4  libwhelk_la_SOURCES=whelk.c whelk.h _whelk.h string.c
     2.5  if WHELK_MINGW
     2.6  libwhelk_la_SOURCES+=unicode.c get_folder_path.c registry.c reg_keys.c \
     2.7 -	shelllink.c spawn.c wait.c
     2.8 +	shelllink.c spawn.c wait.c catalog.c setup.c
     2.9  endif
    2.10  libwhelk_la_LDFLAGS=-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
    2.11  
     3.1 --- a/whelk/_whelk.h	Fri Oct 16 15:24:19 2009 +0100
     3.2 +++ b/whelk/_whelk.h	Mon Feb 08 22:07:17 2010 +0000
     3.3 @@ -53,4 +53,10 @@
     3.4  void whelk_wait_remove_object(struct whelk_wait *wait,HANDLE object);
     3.5  HANDLE whelk_wait_poll(struct whelk_wait *wait);
     3.6  void whelk_wait_free(struct whelk_wait *wait);
     3.7 +
     3.8 +int whelk_crypt_cat_admin_new(lua_State *L);
     3.9 +
    3.10 +int whelk_setup_copy_oem_inf(lua_State *L);
    3.11 +int whelk_setup_uninstall_oem_inf(lua_State *L);
    3.12 +void whelk_open_setup(lua_State *L);
    3.13  #endif
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/whelk/catalog.c	Mon Feb 08 22:07:17 2010 +0000
     4.3 @@ -0,0 +1,191 @@
     4.4 +#include "config.h"
     4.5 +#include <stdlib.h>
     4.6 +#include <errno.h>
     4.7 +#include <windows.h>
     4.8 +#if HAVE_MSCAT_H
     4.9 +#include <mscat.h>
    4.10 +#else
    4.11 +typedef HANDLE HCATADMIN;
    4.12 +typedef HANDLE HCATINFO;
    4.13 +#endif
    4.14 +#if HAVE_SOFTPUB_H
    4.15 +#include <Softpub.h>
    4.16 +#endif
    4.17 +#include <lua.h>
    4.18 +#include <lualib.h>
    4.19 +#include <lauxlib.h>
    4.20 +#include "_whelk.h"
    4.21 +
    4.22 +#ifndef DRIVER_ACTION_VERIFY
    4.23 +#define DRIVER_ACTION_VERIFY \
    4.24 +     { 0xf750e6c3, 0x38ee, 0x11d1, { 0x85,0xe5,0x00,0xc0,0x4f,0xc2,0x95,0xee }}
    4.25 +#endif
    4.26 +
    4.27 +#define WHELK_TYPE_CAT_ADMIN	"whelk-cat-admin"
    4.28 +#define WHELK_CAT_ADMIN(L,n)	\
    4.29 +    ((struct whelk_cat_admin *)luaL_checkudata(L,n,WHELK_TYPE_CAT_ADMIN))
    4.30 +
    4.31 +struct whelk_cat_admin_class {
    4.32 +    HMODULE wintrust;
    4.33 +    BOOL (WINAPI *acquire_context)(HCATADMIN *ca,const GUID *subsystem,
    4.34 +      DWORD flags);
    4.35 +    HCATINFO (WINAPI *add_catalog)(HCATADMIN ca,WCHAR *catalog_file,
    4.36 +      WCHAR *select_base_name,DWORD flags);
    4.37 +    BOOL (WINAPI *remove_catalog)(HCATADMIN ca,WCHAR *catalog_file,DWORD flags);
    4.38 +    BOOL (WINAPI *release_catalog_context)(HCATADMIN ca,HCATINFO ci,
    4.39 +      DWORD flags);
    4.40 +    BOOL (WINAPI *release_context)(HCATADMIN ca,DWORD flags);
    4.41 +};
    4.42 +
    4.43 +struct whelk_cat_admin {
    4.44 +    struct whelk_cat_admin_class *klass;
    4.45 +    HCATADMIN handle;
    4.46 +};
    4.47 +
    4.48 +/*
    4.49 + * AddCatalog(catalog_file,select_base_name)
    4.50 + *
    4.51 + * select_base_name can be nil.
    4.52 + *
    4.53 + * Returns nil and an error message on error and something other than nil
    4.54 + * on success.
    4.55 + *
    4.56 + * Note that add_catalog should return a CryptCatInfo if we were
    4.57 + * to follow the native API. We don't at present since there's
    4.58 + * nothing the caller could do with it yet. Callers should check
    4.59 + * for failure by comparing the result with nil.
    4.60 + */
    4.61 +
    4.62 +static int add_catalog(lua_State *L)
    4.63 +{
    4.64 +    int retval;
    4.65 +    HCATINFO result;
    4.66 +    size_t n;
    4.67 +    const char *s;
    4.68 +    struct whelk_cat_admin *this=WHELK_CAT_ADMIN(L,1);
    4.69 +    WCHAR *catalog_file=whelk_utf8_to_utf16(luaL_checkstring(L,2),-1);
    4.70 +    WCHAR *select_base_name;
    4.71 +    s=luaL_checklstring(L,3,&n);
    4.72 +    select_base_name=s?whelk_utf8_to_utf16(s,n):NULL;
    4.73 +    result=this->klass->add_catalog(this->handle,catalog_file,select_base_name,
    4.74 +      0);
    4.75 +    if (result)
    4.76 +    {
    4.77 +	this->klass->release_catalog_context(this->handle,result,0);
    4.78 +	lua_pushinteger(L,1);	/* Something other than nil */
    4.79 +	retval=1;
    4.80 +    }
    4.81 +    else
    4.82 +    {
    4.83 +	lua_pushnil(L);
    4.84 +	lua_pushfstring(L,"%s: Failed to add catalog",catalog_file);
    4.85 +	lua_pushinteger(L,-1);
    4.86 +	retval=3;
    4.87 +    }
    4.88 +    free(catalog_file);
    4.89 +    free(select_base_name);
    4.90 +    return retval;
    4.91 +}
    4.92 +
    4.93 +/*
    4.94 + * RemoveCatalog(catalog_file)
    4.95 + *
    4.96 + * Returns nil and an error message on error and something other than nil
    4.97 + * on success.
    4.98 + */
    4.99 +
   4.100 +static int remove_catalog(lua_State *L)
   4.101 +{
   4.102 +    int retval;
   4.103 +    BOOL result;
   4.104 +    struct whelk_cat_admin *this=WHELK_CAT_ADMIN(L,1);
   4.105 +    WCHAR *catalog_file=whelk_utf8_to_utf16(luaL_checkstring(L,2),-1);
   4.106 +    result=this->klass->remove_catalog(this->handle,catalog_file,0);
   4.107 +    if (result)
   4.108 +    {
   4.109 +	lua_pushinteger(L,1);	/* Something other than nil */
   4.110 +	retval=1;
   4.111 +    }
   4.112 +    else
   4.113 +    {
   4.114 +	lua_pushnil(L);
   4.115 +	lua_pushfstring(L,"%s: Failed to remove catalog",catalog_file);
   4.116 +	lua_pushinteger(L,-1);
   4.117 +	retval=3;
   4.118 +    }
   4.119 +    free(catalog_file);
   4.120 +    return retval;
   4.121 +}
   4.122 +
   4.123 +static int whelk_cat_admin_gc(lua_State *L)
   4.124 +{
   4.125 +    struct whelk_cat_admin *this=WHELK_CAT_ADMIN(L,1);
   4.126 +    this->klass->release_context(this->handle,0);
   4.127 +    this->handle=INVALID_HANDLE_VALUE;
   4.128 +    return 0;
   4.129 +}
   4.130 +
   4.131 +static const luaL_Reg whelk_cat_admin_methods[]={
   4.132 +    { "AddCatalog",add_catalog },
   4.133 +    { "RemoveCatalog",remove_catalog },
   4.134 +    { "__gc",whelk_cat_admin_gc },
   4.135 +    { NULL }
   4.136 +};
   4.137 +
   4.138 +static struct whelk_cat_admin_class *whelk_cat_admin_class_new(lua_State *L)
   4.139 +{
   4.140 +    struct whelk_cat_admin_class *klass;
   4.141 +    klass=calloc(sizeof(struct whelk_cat_admin_class),1);
   4.142 +    klass->wintrust=LoadLibrary("wintrust.dll");
   4.143 +    if (!klass->wintrust)
   4.144 +    {
   4.145 +	free(klass);
   4.146 +	return NULL;
   4.147 +    }
   4.148 +    klass->acquire_context=
   4.149 +      GetProcAddress(klass->wintrust,"CryptCATAdminAcquireContext");
   4.150 +    klass->add_catalog=(HCATINFO (WINAPI *)())
   4.151 +      GetProcAddress(klass->wintrust,"CryptCATAdminAddCatalog");
   4.152 +    klass->remove_catalog=
   4.153 +      GetProcAddress(klass->wintrust,"CryptCATAdminRemoveCatalog");
   4.154 +    klass->release_catalog_context=
   4.155 +      GetProcAddress(klass->wintrust,"CryptCATAdminReleaseCatalogContext");
   4.156 +    klass->release_context=
   4.157 +      GetProcAddress(klass->wintrust,"CryptCATAdminReleaseContext");
   4.158 +    if (!klass->acquire_context || !klass->add_catalog ||
   4.159 +      !klass->release_catalog_context || !klass->release_context)
   4.160 +    {
   4.161 +	FreeLibrary(klass->wintrust);
   4.162 +	free(klass);
   4.163 +	return NULL;
   4.164 +    }
   4.165 +    luaL_newmetatable(L,WHELK_TYPE_CAT_ADMIN);
   4.166 +    lua_pushvalue(L,-1);
   4.167 +    lua_setfield(L,-2,"__index");
   4.168 +    luaL_register(L,NULL,whelk_cat_admin_methods);
   4.169 +    return klass;
   4.170 +}
   4.171 +
   4.172 +static struct whelk_cat_admin *newcatadmin(lua_State *L)
   4.173 +{
   4.174 +    struct whelk_cat_admin *ca;
   4.175 +    static struct whelk_cat_admin_class *klass=NULL;
   4.176 +    if (!klass)
   4.177 +	klass=whelk_cat_admin_class_new(L);
   4.178 +    ca=lua_newuserdata(L,sizeof(struct whelk_cat_admin));
   4.179 +    ca->klass=klass;
   4.180 +    ca->handle=INVALID_HANDLE_VALUE;
   4.181 +    luaL_getmetatable(L,WHELK_TYPE_CAT_ADMIN);
   4.182 +    lua_setmetatable(L,-2);
   4.183 +    return ca;
   4.184 +}
   4.185 +
   4.186 +int whelk_crypt_cat_admin_new(lua_State *L)
   4.187 +{
   4.188 +    struct whelk_cat_admin *ca;
   4.189 +    static GUID subsystem=DRIVER_ACTION_VERIFY;
   4.190 +    ca=newcatadmin(L);
   4.191 +    if (!ca->klass->acquire_context(&ca->handle,&subsystem,0))
   4.192 +	lua_pushnil(L);
   4.193 +    return 1;
   4.194 +}
     5.1 --- a/whelk/reg_keys.c	Fri Oct 16 15:24:19 2009 +0100
     5.2 +++ b/whelk/reg_keys.c	Mon Feb 08 22:07:17 2010 +0000
     5.3 @@ -165,4 +165,5 @@
     5.4      create_predefined_key(L,HKEY_CURRENT_USER,"KEY_CURRENT_USER");
     5.5      create_predefined_key(L,HKEY_LOCAL_MACHINE,"KEY_LOCAL_MACHINE");
     5.6      create_predefined_key(L,HKEY_USERS,"KEY_USERS");
     5.7 +    lua_pop(L,1);
     5.8  }
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/whelk/setup.c	Mon Feb 08 22:07:17 2010 +0000
     6.3 @@ -0,0 +1,165 @@
     6.4 +#include <stdlib.h>
     6.5 +#include <errno.h>
     6.6 +#include <windows.h>
     6.7 +#include <setupapi.h>
     6.8 +#include <lua.h>
     6.9 +#include <lualib.h>
    6.10 +#include <lauxlib.h>
    6.11 +#include "_whelk.h"
    6.12 +
    6.13 +#ifndef SUOI_FORCEDELETE
    6.14 +#define SUOI_FORCEDELETE	1
    6.15 +#endif
    6.16 +
    6.17 +int whelk_win32_error(lua_State *L,DWORD err)
    6.18 +{
    6.19 +    DWORD n;
    6.20 +    WCHAR *buf;
    6.21 +    char *utf8;
    6.22 +    lua_pushnil(L);
    6.23 +    buf=NULL;
    6.24 +    n=FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|\
    6.25 +      FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,0,err,0,
    6.26 +      (LPWSTR)&buf,0,NULL);
    6.27 +    if (n)
    6.28 +    {
    6.29 +	if (n>2 && buf[n-2]=='\r' && buf[n-1]=='\n')
    6.30 +	    n-=2;
    6.31 +	utf8=whelk_utf16_to_utf8(buf,n);
    6.32 +	LocalFree(buf);
    6.33 +	lua_pushstring(L,utf8);
    6.34 +	free(utf8);
    6.35 +    }
    6.36 +    else
    6.37 +	lua_pushstring(L,"Unknown error");
    6.38 +    lua_pushinteger(L,err);
    6.39 +    return 3;
    6.40 +}
    6.41 +
    6.42 +/*
    6.43 + * SetupCopyOEMInf(source_inf_file_name,oem_source_media_location,
    6.44 + * 	oem_source_media_type,copy_style)
    6.45 + *
    6.46 + * oem_source_media_type is one of:
    6.47 + * 	SPOST_NONE
    6.48 + * 		No source media information is stored.
    6.49 + *
    6.50 + * 	SPOST_PATH
    6.51 + * 		oem_source_media_location contains a path to the source media
    6.52 + * 		(eg., "A:\").
    6.53 + *
    6.54 + *	SPOST_URL
    6.55 + *		oem_source_media_locationcontains a universal resource locator.
    6.56 + *
    6.57 + * copy_style is one of:
    6.58 + * 	SP_COPY_DELETESOURCE
    6.59 + * 		Delete source file on successful copy.
    6.60 + * 	SP_COPY_REPLACEONLY
    6.61 + * 		Copy only if this file already exists in the Inf directory.
    6.62 + *	SP_COPY_NOOVERWRITE
    6.63 + * 		Copy only if this file does not already exist in the Inf
    6.64 + * 		directory.
    6.65 + *	SP_COPY_OEMINF_CATALOG_ONLY
    6.66 + *		The specified .inf file's corresponding catalog files is
    6.67 + *		copied to %windir%\Inf.
    6.68 + *
    6.69 + * Returns two strings: the destination .inf file path (including file name)
    6.70 + * and just the file name component.
    6.71 + */
    6.72 +
    6.73 +int whelk_setup_copy_oem_inf(lua_State *L)
    6.74 +{
    6.75 +    WCHAR path[MAX_PATH];
    6.76 +    BOOL result;
    6.77 +    size_t n;
    6.78 +    const char *s;
    6.79 +    char *utf8;
    6.80 +    WCHAR *source_inf_file_name=whelk_utf8_to_utf16(luaL_checkstring(L,1),-1);
    6.81 +    WCHAR *oem_source_media_location;
    6.82 +    int oem_source_media_type=luaL_checkint(L,3);
    6.83 +    int copy_style=luaL_checkint(L,4);
    6.84 +    WCHAR *dest_in_file_name_component;
    6.85 +    s=luaL_checklstring(L,2,&n);
    6.86 +    oem_source_media_location=s?whelk_utf8_to_utf16(s,n):NULL;
    6.87 +    path[0]='\0';
    6.88 +    dest_in_file_name_component=NULL;
    6.89 +    result=SetupCopyOEMInfW(source_inf_file_name,oem_source_media_location,
    6.90 +      oem_source_media_type,copy_style,path,sizeof(path)/sizeof(*path),NULL,
    6.91 +      &dest_in_file_name_component);
    6.92 +    free(source_inf_file_name);
    6.93 +    free(oem_source_media_location);
    6.94 +    if (!result)
    6.95 +	return whelk_win32_error(L,GetLastError());
    6.96 +    utf8=whelk_utf16_to_utf8(path,-1);
    6.97 +    lua_pushstring(L,utf8);
    6.98 +    free(utf8);
    6.99 +    if (dest_in_file_name_component)
   6.100 +    {
   6.101 +	utf8=whelk_utf16_to_utf8(dest_in_file_name_component,-1);
   6.102 +	lua_pushstring(L,utf8);
   6.103 +	free(utf8);
   6.104 +    }
   6.105 +    else
   6.106 +	lua_pushnil(L);
   6.107 +    return 2;
   6.108 +}
   6.109 +
   6.110 +/*
   6.111 + * SetupUninstallOEMInf(inf_file_name[,flags])
   6.112 + *
   6.113 + * The following flags are recognised:
   6.114 + *	SUOI_FORCEDELETE
   6.115 + *		Delete the .inf file even if an installed device uses it.
   6.116 + *
   6.117 + * Returns non-nil on success.
   6.118 + */
   6.119 +
   6.120 +int whelk_setup_uninstall_oem_inf(lua_State *L)
   6.121 +{
   6.122 +    BOOL result;
   6.123 +    WCHAR *inf_file_name=whelk_utf8_to_utf16(luaL_checkstring(L,1),-1);
   6.124 +    int flags=lua_isnone(L,2)?0:luaL_checkint(L,2);
   6.125 +#ifdef HAVE_SETUPUNINSTALLOEMINFW
   6.126 +    result=SetupUninstallOEMInfW(inf_file_name,flags,NULL);
   6.127 +#else
   6.128 +    HMODULE lib;
   6.129 +    BOOL (WINAPI *SetupUninstallOEMInfW)(WCHAR *inf_file_name,DWORD flags,
   6.130 +      VOID *reserved);
   6.131 +    lib=LoadLibrary("setupapi.dll");
   6.132 +    if (lib)
   6.133 +    {
   6.134 +	SetupUninstallOEMInfW=GetProcAddress(lib,"SetupUninstallOEMInfW");
   6.135 +	if (SetupUninstallOEMInfW)
   6.136 +	    result=SetupUninstallOEMInfW(inf_file_name,flags,NULL);
   6.137 +	else
   6.138 +	{
   6.139 +	    FreeLibrary(lib);
   6.140 +	    free(inf_file_name);
   6.141 +	    return whelk_win32_error(L,ERROR_NOT_SUPPORTED);
   6.142 +	}
   6.143 +	FreeLibrary(lib);
   6.144 +    }
   6.145 +    else
   6.146 +    {
   6.147 +	free(inf_file_name);
   6.148 +	return whelk_win32_error(L,ERROR_NOT_SUPPORTED);
   6.149 +    }
   6.150 +#endif
   6.151 +    free(inf_file_name);
   6.152 +    if (!result)
   6.153 +	return whelk_win32_error(L,GetLastError());
   6.154 +    lua_pushinteger(L,1);		/* Something other than nil */
   6.155 +    return 1;
   6.156 +}
   6.157 +
   6.158 +void whelk_open_setup(lua_State *L)
   6.159 +{
   6.160 +    whelk_reg_const(L,SPOST_NONE);
   6.161 +    whelk_reg_const(L,SPOST_PATH);
   6.162 +    whelk_reg_const(L,SPOST_URL);
   6.163 +    whelk_reg_const(L,SP_COPY_DELETESOURCE);
   6.164 +    whelk_reg_const(L,SP_COPY_REPLACEONLY);
   6.165 +    whelk_reg_const(L,SP_COPY_NOOVERWRITE);
   6.166 +    whelk_reg_const(L,SP_COPY_OEMINF_CATALOG_ONLY);
   6.167 +    whelk_reg_const(L,SUOI_FORCEDELETE);
   6.168 +}
     7.1 --- a/whelk/whelk.c	Fri Oct 16 15:24:19 2009 +0100
     7.2 +++ b/whelk/whelk.c	Mon Feb 08 22:07:17 2010 +0000
     7.3 @@ -34,6 +34,9 @@
     7.4      { "GetFolderPath",WIN32_ONLY(whelk_get_folder_path) },
     7.5      { "CreateShortCut",WIN32_ONLY(whelk_create_short_cut) },
     7.6      { "Spawn",WIN32_ONLY(whelk_spawn) },
     7.7 +    { "CryptCATAdmin",WIN32_ONLY(whelk_crypt_cat_admin_new) },
     7.8 +    { "SetupCopyOEMInf",WIN32_ONLY(whelk_setup_copy_oem_inf) },
     7.9 +    { "SetupUninstallOEMInf",WIN32_ONLY(whelk_setup_uninstall_oem_inf) },
    7.10      { NULL }
    7.11  };
    7.12  
    7.13 @@ -46,6 +49,7 @@
    7.14  #ifdef __WIN32__
    7.15      whelk_open_get_folder_path(L);
    7.16      whelk_open_reg_keys(L);
    7.17 +    whelk_open_setup(L);
    7.18  #endif
    7.19      return 1;
    7.20  }