# Checks for header files.
##################################################
AC_HEADER_STDC
+AC_CHECK_HEADERS_ONCE([softpub.h mscat.h])
##################################################
# Checks for typedefs, structures, and compiler characteristics.
##################################################
case $host_os in
mingw*)
- EXTRA_LIBS="-lole32"
+ EXTRA_LIBS="-lole32 -lsetupapi"
EXTRA_BUILD_LIBS="-Wl,-luuid"
EXTRA_PRIVATE_LIBS="-luuid"
;;
##################################################
# 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.
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)
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
--- /dev/null
+#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;
+}
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);
}
--- /dev/null
+#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);
+}
{ "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 }
};
#ifdef __WIN32__
whelk_open_get_folder_path(L);
whelk_open_reg_keys(L);
+ whelk_open_setup(L);
#endif
return 1;
}