From: J. Ali Harlow Date: Mon, 8 Feb 2010 22:07:17 +0000 (+0000) Subject: Add support for installing drivers X-Git-Tag: 0.3^0 X-Git-Url: http://project.juiblex.co.uk/git/?a=commitdiff_plain;h=c5edfb2459bf75dbd0a1129c44218f05cddba252;p=whelk.git Add support for installing drivers --- diff --git a/configure.ac b/configure.ac index 09508ff..f047eb8 100644 --- a/configure.ac +++ b/configure.ac @@ -45,6 +45,7 @@ PKG_PROG_PKG_CONFIG # Checks for header files. ################################################## AC_HEADER_STDC +AC_CHECK_HEADERS_ONCE([softpub.h mscat.h]) ################################################## # Checks for typedefs, structures, and compiler characteristics. @@ -55,7 +56,7 @@ AC_HEADER_STDC ################################################## case $host_os in mingw*) - EXTRA_LIBS="-lole32" + EXTRA_LIBS="-lole32 -lsetupapi" EXTRA_BUILD_LIBS="-Wl,-luuid" EXTRA_PRIVATE_LIBS="-luuid" ;; @@ -75,6 +76,14 @@ AC_SUBST([LUA_BINARY_VERSION],[$lua_binary_version]) ################################################## # Checks for library functions. ################################################## +case $host_os in + mingw*) + save_libs="$LIBS" + LIBS="-lsetupapi $LIBS" + AC_CHECK_FUNCS_ONCE([SetupUninstallOEMInfW]) + LIBS="$save_libs" + ;; +esac ################################################## # Checks for processor independent files. diff --git a/whelk/Makefile.am b/whelk/Makefile.am index 301a63e..6d4ed82 100644 --- a/whelk/Makefile.am +++ b/whelk/Makefile.am @@ -9,7 +9,7 @@ lib_LTLIBRARIES=libwhelk.la libwhelk_la_SOURCES=whelk.c whelk.h _whelk.h string.c if WHELK_MINGW libwhelk_la_SOURCES+=unicode.c get_folder_path.c registry.c reg_keys.c \ - shelllink.c spawn.c wait.c + shelllink.c spawn.c wait.c catalog.c setup.c endif libwhelk_la_LDFLAGS=-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) diff --git a/whelk/_whelk.h b/whelk/_whelk.h index 5d018d7..d27ecce 100644 --- a/whelk/_whelk.h +++ b/whelk/_whelk.h @@ -53,4 +53,10 @@ int whelk_wait_add_object(struct whelk_wait *wait,HANDLE object); void whelk_wait_remove_object(struct whelk_wait *wait,HANDLE object); HANDLE whelk_wait_poll(struct whelk_wait *wait); void whelk_wait_free(struct whelk_wait *wait); + +int whelk_crypt_cat_admin_new(lua_State *L); + +int whelk_setup_copy_oem_inf(lua_State *L); +int whelk_setup_uninstall_oem_inf(lua_State *L); +void whelk_open_setup(lua_State *L); #endif diff --git a/whelk/catalog.c b/whelk/catalog.c new file mode 100644 index 0000000..d0a821e --- /dev/null +++ b/whelk/catalog.c @@ -0,0 +1,191 @@ +#include "config.h" +#include +#include +#include +#if HAVE_MSCAT_H +#include +#else +typedef HANDLE HCATADMIN; +typedef HANDLE HCATINFO; +#endif +#if HAVE_SOFTPUB_H +#include +#endif +#include +#include +#include +#include "_whelk.h" + +#ifndef DRIVER_ACTION_VERIFY +#define DRIVER_ACTION_VERIFY \ + { 0xf750e6c3, 0x38ee, 0x11d1, { 0x85,0xe5,0x00,0xc0,0x4f,0xc2,0x95,0xee }} +#endif + +#define WHELK_TYPE_CAT_ADMIN "whelk-cat-admin" +#define WHELK_CAT_ADMIN(L,n) \ + ((struct whelk_cat_admin *)luaL_checkudata(L,n,WHELK_TYPE_CAT_ADMIN)) + +struct whelk_cat_admin_class { + HMODULE wintrust; + BOOL (WINAPI *acquire_context)(HCATADMIN *ca,const GUID *subsystem, + DWORD flags); + HCATINFO (WINAPI *add_catalog)(HCATADMIN ca,WCHAR *catalog_file, + WCHAR *select_base_name,DWORD flags); + BOOL (WINAPI *remove_catalog)(HCATADMIN ca,WCHAR *catalog_file,DWORD flags); + BOOL (WINAPI *release_catalog_context)(HCATADMIN ca,HCATINFO ci, + DWORD flags); + BOOL (WINAPI *release_context)(HCATADMIN ca,DWORD flags); +}; + +struct whelk_cat_admin { + struct whelk_cat_admin_class *klass; + HCATADMIN handle; +}; + +/* + * AddCatalog(catalog_file,select_base_name) + * + * select_base_name can be nil. + * + * Returns nil and an error message on error and something other than nil + * on success. + * + * Note that add_catalog should return a CryptCatInfo if we were + * to follow the native API. We don't at present since there's + * nothing the caller could do with it yet. Callers should check + * for failure by comparing the result with nil. + */ + +static int add_catalog(lua_State *L) +{ + int retval; + HCATINFO result; + size_t n; + const char *s; + struct whelk_cat_admin *this=WHELK_CAT_ADMIN(L,1); + WCHAR *catalog_file=whelk_utf8_to_utf16(luaL_checkstring(L,2),-1); + WCHAR *select_base_name; + s=luaL_checklstring(L,3,&n); + select_base_name=s?whelk_utf8_to_utf16(s,n):NULL; + result=this->klass->add_catalog(this->handle,catalog_file,select_base_name, + 0); + if (result) + { + this->klass->release_catalog_context(this->handle,result,0); + lua_pushinteger(L,1); /* Something other than nil */ + retval=1; + } + else + { + lua_pushnil(L); + lua_pushfstring(L,"%s: Failed to add catalog",catalog_file); + lua_pushinteger(L,-1); + retval=3; + } + free(catalog_file); + free(select_base_name); + return retval; +} + +/* + * RemoveCatalog(catalog_file) + * + * Returns nil and an error message on error and something other than nil + * on success. + */ + +static int remove_catalog(lua_State *L) +{ + int retval; + BOOL result; + struct whelk_cat_admin *this=WHELK_CAT_ADMIN(L,1); + WCHAR *catalog_file=whelk_utf8_to_utf16(luaL_checkstring(L,2),-1); + result=this->klass->remove_catalog(this->handle,catalog_file,0); + if (result) + { + lua_pushinteger(L,1); /* Something other than nil */ + retval=1; + } + else + { + lua_pushnil(L); + lua_pushfstring(L,"%s: Failed to remove catalog",catalog_file); + lua_pushinteger(L,-1); + retval=3; + } + free(catalog_file); + return retval; +} + +static int whelk_cat_admin_gc(lua_State *L) +{ + struct whelk_cat_admin *this=WHELK_CAT_ADMIN(L,1); + this->klass->release_context(this->handle,0); + this->handle=INVALID_HANDLE_VALUE; + return 0; +} + +static const luaL_Reg whelk_cat_admin_methods[]={ + { "AddCatalog",add_catalog }, + { "RemoveCatalog",remove_catalog }, + { "__gc",whelk_cat_admin_gc }, + { NULL } +}; + +static struct whelk_cat_admin_class *whelk_cat_admin_class_new(lua_State *L) +{ + struct whelk_cat_admin_class *klass; + klass=calloc(sizeof(struct whelk_cat_admin_class),1); + klass->wintrust=LoadLibrary("wintrust.dll"); + if (!klass->wintrust) + { + free(klass); + return NULL; + } + klass->acquire_context= + GetProcAddress(klass->wintrust,"CryptCATAdminAcquireContext"); + klass->add_catalog=(HCATINFO (WINAPI *)()) + GetProcAddress(klass->wintrust,"CryptCATAdminAddCatalog"); + klass->remove_catalog= + GetProcAddress(klass->wintrust,"CryptCATAdminRemoveCatalog"); + klass->release_catalog_context= + GetProcAddress(klass->wintrust,"CryptCATAdminReleaseCatalogContext"); + klass->release_context= + GetProcAddress(klass->wintrust,"CryptCATAdminReleaseContext"); + if (!klass->acquire_context || !klass->add_catalog || + !klass->release_catalog_context || !klass->release_context) + { + FreeLibrary(klass->wintrust); + free(klass); + return NULL; + } + luaL_newmetatable(L,WHELK_TYPE_CAT_ADMIN); + lua_pushvalue(L,-1); + lua_setfield(L,-2,"__index"); + luaL_register(L,NULL,whelk_cat_admin_methods); + return klass; +} + +static struct whelk_cat_admin *newcatadmin(lua_State *L) +{ + struct whelk_cat_admin *ca; + static struct whelk_cat_admin_class *klass=NULL; + if (!klass) + klass=whelk_cat_admin_class_new(L); + ca=lua_newuserdata(L,sizeof(struct whelk_cat_admin)); + ca->klass=klass; + ca->handle=INVALID_HANDLE_VALUE; + luaL_getmetatable(L,WHELK_TYPE_CAT_ADMIN); + lua_setmetatable(L,-2); + return ca; +} + +int whelk_crypt_cat_admin_new(lua_State *L) +{ + struct whelk_cat_admin *ca; + static GUID subsystem=DRIVER_ACTION_VERIFY; + ca=newcatadmin(L); + if (!ca->klass->acquire_context(&ca->handle,&subsystem,0)) + lua_pushnil(L); + return 1; +} diff --git a/whelk/reg_keys.c b/whelk/reg_keys.c index 3a2fa47..c76a2dd 100644 --- a/whelk/reg_keys.c +++ b/whelk/reg_keys.c @@ -165,4 +165,5 @@ void whelk_open_reg_keys(lua_State *L) create_predefined_key(L,HKEY_CURRENT_USER,"KEY_CURRENT_USER"); create_predefined_key(L,HKEY_LOCAL_MACHINE,"KEY_LOCAL_MACHINE"); create_predefined_key(L,HKEY_USERS,"KEY_USERS"); + lua_pop(L,1); } diff --git a/whelk/setup.c b/whelk/setup.c new file mode 100644 index 0000000..556fd42 --- /dev/null +++ b/whelk/setup.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include +#include +#include +#include "_whelk.h" + +#ifndef SUOI_FORCEDELETE +#define SUOI_FORCEDELETE 1 +#endif + +int whelk_win32_error(lua_State *L,DWORD err) +{ + DWORD n; + WCHAR *buf; + char *utf8; + lua_pushnil(L); + buf=NULL; + n=FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|\ + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,0,err,0, + (LPWSTR)&buf,0,NULL); + if (n) + { + if (n>2 && buf[n-2]=='\r' && buf[n-1]=='\n') + n-=2; + utf8=whelk_utf16_to_utf8(buf,n); + LocalFree(buf); + lua_pushstring(L,utf8); + free(utf8); + } + else + lua_pushstring(L,"Unknown error"); + lua_pushinteger(L,err); + return 3; +} + +/* + * SetupCopyOEMInf(source_inf_file_name,oem_source_media_location, + * oem_source_media_type,copy_style) + * + * oem_source_media_type is one of: + * SPOST_NONE + * No source media information is stored. + * + * SPOST_PATH + * oem_source_media_location contains a path to the source media + * (eg., "A:\"). + * + * SPOST_URL + * oem_source_media_locationcontains a universal resource locator. + * + * copy_style is one of: + * SP_COPY_DELETESOURCE + * Delete source file on successful copy. + * SP_COPY_REPLACEONLY + * Copy only if this file already exists in the Inf directory. + * SP_COPY_NOOVERWRITE + * Copy only if this file does not already exist in the Inf + * directory. + * SP_COPY_OEMINF_CATALOG_ONLY + * The specified .inf file's corresponding catalog files is + * copied to %windir%\Inf. + * + * Returns two strings: the destination .inf file path (including file name) + * and just the file name component. + */ + +int whelk_setup_copy_oem_inf(lua_State *L) +{ + WCHAR path[MAX_PATH]; + BOOL result; + size_t n; + const char *s; + char *utf8; + WCHAR *source_inf_file_name=whelk_utf8_to_utf16(luaL_checkstring(L,1),-1); + WCHAR *oem_source_media_location; + int oem_source_media_type=luaL_checkint(L,3); + int copy_style=luaL_checkint(L,4); + WCHAR *dest_in_file_name_component; + s=luaL_checklstring(L,2,&n); + oem_source_media_location=s?whelk_utf8_to_utf16(s,n):NULL; + path[0]='\0'; + dest_in_file_name_component=NULL; + result=SetupCopyOEMInfW(source_inf_file_name,oem_source_media_location, + oem_source_media_type,copy_style,path,sizeof(path)/sizeof(*path),NULL, + &dest_in_file_name_component); + free(source_inf_file_name); + free(oem_source_media_location); + if (!result) + return whelk_win32_error(L,GetLastError()); + utf8=whelk_utf16_to_utf8(path,-1); + lua_pushstring(L,utf8); + free(utf8); + if (dest_in_file_name_component) + { + utf8=whelk_utf16_to_utf8(dest_in_file_name_component,-1); + lua_pushstring(L,utf8); + free(utf8); + } + else + lua_pushnil(L); + return 2; +} + +/* + * SetupUninstallOEMInf(inf_file_name[,flags]) + * + * The following flags are recognised: + * SUOI_FORCEDELETE + * Delete the .inf file even if an installed device uses it. + * + * Returns non-nil on success. + */ + +int whelk_setup_uninstall_oem_inf(lua_State *L) +{ + BOOL result; + WCHAR *inf_file_name=whelk_utf8_to_utf16(luaL_checkstring(L,1),-1); + int flags=lua_isnone(L,2)?0:luaL_checkint(L,2); +#ifdef HAVE_SETUPUNINSTALLOEMINFW + result=SetupUninstallOEMInfW(inf_file_name,flags,NULL); +#else + HMODULE lib; + BOOL (WINAPI *SetupUninstallOEMInfW)(WCHAR *inf_file_name,DWORD flags, + VOID *reserved); + lib=LoadLibrary("setupapi.dll"); + if (lib) + { + SetupUninstallOEMInfW=GetProcAddress(lib,"SetupUninstallOEMInfW"); + if (SetupUninstallOEMInfW) + result=SetupUninstallOEMInfW(inf_file_name,flags,NULL); + else + { + FreeLibrary(lib); + free(inf_file_name); + return whelk_win32_error(L,ERROR_NOT_SUPPORTED); + } + FreeLibrary(lib); + } + else + { + free(inf_file_name); + return whelk_win32_error(L,ERROR_NOT_SUPPORTED); + } +#endif + free(inf_file_name); + if (!result) + return whelk_win32_error(L,GetLastError()); + lua_pushinteger(L,1); /* Something other than nil */ + return 1; +} + +void whelk_open_setup(lua_State *L) +{ + whelk_reg_const(L,SPOST_NONE); + whelk_reg_const(L,SPOST_PATH); + whelk_reg_const(L,SPOST_URL); + whelk_reg_const(L,SP_COPY_DELETESOURCE); + whelk_reg_const(L,SP_COPY_REPLACEONLY); + whelk_reg_const(L,SP_COPY_NOOVERWRITE); + whelk_reg_const(L,SP_COPY_OEMINF_CATALOG_ONLY); + whelk_reg_const(L,SUOI_FORCEDELETE); +} diff --git a/whelk/whelk.c b/whelk/whelk.c index ab32cf4..204d2ff 100644 --- a/whelk/whelk.c +++ b/whelk/whelk.c @@ -34,6 +34,9 @@ static const luaL_reg whelk_functions[]={ { "GetFolderPath",WIN32_ONLY(whelk_get_folder_path) }, { "CreateShortCut",WIN32_ONLY(whelk_create_short_cut) }, { "Spawn",WIN32_ONLY(whelk_spawn) }, + { "CryptCATAdmin",WIN32_ONLY(whelk_crypt_cat_admin_new) }, + { "SetupCopyOEMInf",WIN32_ONLY(whelk_setup_copy_oem_inf) }, + { "SetupUninstallOEMInf",WIN32_ONLY(whelk_setup_uninstall_oem_inf) }, { NULL } }; @@ -46,6 +49,7 @@ LUALIB_API int luaopen_whelk(lua_State *L) #ifdef __WIN32__ whelk_open_get_folder_path(L); whelk_open_reg_keys(L); + whelk_open_setup(L); #endif return 1; }