Add support for installing drivers 0.3
authorJ. Ali Harlow <ali@juiblex.co.uk>
Mon, 8 Feb 2010 22:07:17 +0000 (22:07 +0000)
committerJ. Ali Harlow <ali@juiblex.co.uk>
Mon, 8 Feb 2010 22:07:17 +0000 (22:07 +0000)
configure.ac
whelk/Makefile.am
whelk/_whelk.h
whelk/catalog.c [new file with mode: 0644]
whelk/reg_keys.c
whelk/setup.c [new file with mode: 0644]
whelk/whelk.c

index 09508ff..f047eb8 100644 (file)
@@ -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.
index 301a63e..6d4ed82 100644 (file)
@@ -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)
 
index 5d018d7..d27ecce 100644 (file)
@@ -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 (file)
index 0000000..d0a821e
--- /dev/null
@@ -0,0 +1,191 @@
+#include "config.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <windows.h>
+#if HAVE_MSCAT_H
+#include <mscat.h>
+#else
+typedef HANDLE HCATADMIN;
+typedef HANDLE HCATINFO;
+#endif
+#if HAVE_SOFTPUB_H
+#include <Softpub.h>
+#endif
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#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;
+}
index 3a2fa47..c76a2dd 100644 (file)
@@ -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 (file)
index 0000000..556fd42
--- /dev/null
@@ -0,0 +1,165 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <windows.h>
+#include <setupapi.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#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);
+}
index ab32cf4..204d2ff 100644 (file)
@@ -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;
 }