Merge remote branch 'public/win_unicode_fixes'

This commit is contained in:
Nick Mathewson 2010-09-06 10:06:07 -04:00
commit edc9256e95
7 changed files with 125 additions and 103 deletions

11
changes/win32_unicode Normal file
View File

@ -0,0 +1,11 @@
o Minor bugfixes
- On Windows, build correctly either with or without Unicode support.
This is necessary so that Tor can support fringe platforms like
Windows 98 (which has no Unicode), or Windows CE (which has no
non-Unicode). Bugfix on 0.2.2.14-alpha. Fixes bug 1797.
- Fix the Windows directory-listing code. A bug introduced in
0.2.2.14-alpha could make Windows directory servers forget to
load some of their cached v2 networkstatus files.
o Testing
- Add a unit test for cross-platform directory-listing code.

View File

@ -169,13 +169,17 @@ tor_munmap_file(tor_mmap_t *handle)
tor_mmap_t *
tor_mmap_file(const char *filename)
{
WCHAR wfilename[MAX_PATH]= {0};
TCHAR tfilename[MAX_PATH]= {0};
tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t));
int empty = 0;
res->file_handle = INVALID_HANDLE_VALUE;
res->mmap_handle = NULL;
mbstowcs(wfilename,filename,MAX_PATH);
res->file_handle = CreateFileW(wfilename,
#ifdef UNICODE
mbstowcs(tfilename,filename,MAX_PATH);
#else
strlcpy(tfilename,filename,MAX_PATH);
#endif
res->file_handle = CreateFile(tfilename,
GENERIC_READ, FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
@ -1698,11 +1702,7 @@ get_uname(void)
#endif
{
#ifdef MS_WINDOWS
#if defined (WINCE)
OSVERSIONINFO info;
#else
OSVERSIONINFOEXW info;
#endif
OSVERSIONINFOEX info;
int i;
const char *plat = NULL;
const char *extra = NULL;
@ -1724,13 +1724,17 @@ get_uname(void)
};
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
if (! GetVersionExW((LPOSVERSIONINFOW)&info)) {
if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx"
" doesn't work.", sizeof(uname_result));
uname_result_is_set = 1;
return uname_result;
}
#ifdef UNICODE
wcstombs(acsd, info.szCSDVersion, MAX_PATH);
#else
strlcpy(acsd, info.szCSDVersion, sizeof(acsd));
#endif
if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
plat = "Windows NT 4.0";
@ -2517,22 +2521,26 @@ network_init(void)
char *
format_win32_error(DWORD err)
{
LPVOID str = NULL;
char abuf[1024] = {0};
TCHAR *str = NULL;
char *result;
/* Somebody once decided that this interface was better than strerror(). */
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR) &str,
(LPVOID)&str,
0, NULL);
if (str) {
#ifdef UNICODE
char abuf[1024] = {0};
wcstombs(abuf,str,1024);
result = tor_strdup((char*)abuf);
result = tor_strdup(abuf);
#else
result = tor_strdup(str);
#endif
LocalFree(str); /* LocalFree != free() */
} else {
result = tor_strdup("<unformattable error>");

View File

@ -2569,26 +2569,34 @@ tor_listdir(const char *dirname)
smartlist_t *result;
#ifdef MS_WINDOWS
char *pattern;
WCHAR wpattern[MAX_PATH] = {0};
TCHAR tpattern[MAX_PATH] = {0};
char name[MAX_PATH] = {0};
HANDLE handle;
WIN32_FIND_DATAW findData;
WIN32_FIND_DATA findData;
size_t pattern_len = strlen(dirname)+16;
pattern = tor_malloc(pattern_len);
tor_snprintf(pattern, pattern_len, "%s\\*", dirname);
mbstowcs(wpattern,pattern,MAX_PATH);
if (INVALID_HANDLE_VALUE == (handle = FindFirstFileW(wpattern, &findData))) {
#ifdef UNICODE
mbstowcs(tpattern,pattern,MAX_PATH);
#else
strlcpy(tpattern, pattern, MAX_PATH);
#endif
if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(tpattern, &findData))) {
tor_free(pattern);
return NULL;
}
wcstombs(name,findData.cFileName,MAX_PATH);
result = smartlist_create();
while (1) {
#ifdef UNICODE
wcstombs(name,findData.cFileName,MAX_PATH);
#else
strlcpy(name,findData.cFileName,sizeof(name));
#endif
if (strcmp(name, ".") &&
strcmp(name, "..")) {
smartlist_add(result, tor_strdup(name));
}
if (!FindNextFileW(handle, &findData)) {
if (!FindNextFile(handle, &findData)) {
DWORD err;
if ((err = GetLastError()) != ERROR_NO_MORE_FILES) {
char *errstr = format_win32_error(err);

View File

@ -3832,7 +3832,7 @@ get_windows_conf_root(void)
{
static int is_set = 0;
static char path[MAX_PATH+1];
WCHAR wpath[MAX_PATH] = {0};
TCHAR tpath[MAX_PATH] = {0};
LPITEMIDLIST idl;
IMalloc *m;
@ -3859,8 +3859,12 @@ get_windows_conf_root(void)
return path;
}
/* Convert the path from an "ID List" (whatever that is!) to a path. */
result = SHGetPathFromIDListW(idl, wpath);
wcstombs(path,wpath,MAX_PATH);
result = SHGetPathFromIDList(idl, tpath);
#ifdef UNICODE
wcstombs(path,tpath,MAX_PATH);
#else
strlcpy(path,tpath,sizeof(path));
#endif
/* Now we need to free the memory that the path-idl was stored in. In
* typical Windows fashion, we can't just call 'free()' on it. */

View File

@ -3132,7 +3132,7 @@ load_nameservers_with_getnetworkparams(void)
GetNetworkParams_fn_t fn;
/* XXXX Possibly, we should hardcode the location of this DLL. */
if (!(handle = LoadLibraryW(L"iphlpapi.dll"))) {
if (!(handle = LoadLibrary(TEXT("iphlpapi.dll"))) {
log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
/* right now status = 0, doesn't that mean "good" - mikec */
status = -1;
@ -3201,46 +3201,44 @@ load_nameservers_with_getnetworkparams(void)
}
static int
config_nameserver_from_reg_key(HKEY key, const char *subkey)
config_nameserver_from_reg_key(HKEY key, const TCHAR *subkey)
{
char *buf;
DWORD bufsz = 0, type = 0;
WCHAR wsubkey[MAX_PATH] = {0};
char ansibuf[MAX_PATH] = {0};
int status = 0;
mbstowcs(wsubkey,subkey,MAX_PATH);
if (RegQueryValueExW(key, wsubkey, 0, &type, NULL, &bufsz)
if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
!= ERROR_MORE_DATA)
return -1;
if (!(buf = mm_malloc(bufsz)))
return -1;
if (RegQueryValueExW(key, wsubkey, 0, &type, (LPBYTE)buf, &bufsz)
if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
== ERROR_SUCCESS && bufsz > 1) {
wcstombs(ansibuf,(wchar_t*)buf,MAX_PATH);
status = evdns_nameserver_ip_add_line(ansibuf);
wcstombs(ansibuf,(wchar_t*)buf,MAX_PATH);/*XXXX UNICODE */
status = evdns_nameserver_ip_add_line(buf);
}
mm_free(buf);
return status;
}
#define SERVICES_KEY L"System\\CurrentControlSet\\Services\\"
#define WIN_NS_9X_KEY SERVICES_KEY L"VxD\\MSTCP"
#define WIN_NS_NT_KEY SERVICES_KEY L"Tcpip\\Parameters"
#define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\")
#define WIN_NS_9X_KEY SERVICES_KEY TEXT("VxD\\MSTCP")
#define WIN_NS_NT_KEY SERVICES_KEY TEXT("Tcpip\\Parameters")
static int
load_nameservers_from_registry(void)
{
int found = 0;
int r;
OSVERSIONINFO info = {0};
OSVERSIONINFO info;
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof (info);
GetVersionExW((LPOSVERSIONINFO)&info);
GetVersionEx(&info);
#define TRY(k, name) \
if (!found && config_nameserver_from_reg_key(k,name) == 0) { \
if (!found && config_nameserver_from_reg_key(k,TEXT(name)) == 0) { \
log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
found = 1; \
} else if (!found) { \
@ -3251,12 +3249,12 @@ load_nameservers_from_registry(void)
if (info.dwMajorVersion >= 5) { /* NT */
HKEY nt_key = 0, interfaces_key = 0;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
KEY_READ, &nt_key) != ERROR_SUCCESS) {
log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
return -1;
}
r = RegOpenKeyExW(nt_key, L"Interfaces", 0,
r = RegOpenKeyEx(nt_key, Text("Interfaces"), 0,
KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
&interfaces_key);
if (r != ERROR_SUCCESS) {
@ -3271,7 +3269,7 @@ load_nameservers_from_registry(void)
RegCloseKey(nt_key);
} else {
HKEY win_key = 0;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
KEY_READ, &win_key) != ERROR_SUCCESS) {
log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
return -1;

View File

@ -15,12 +15,12 @@
#include <event.h>
#endif
#include <tchar.h>
#define GENSRV_SERVICENAME TEXT("tor")
#define GENSRV_DISPLAYNAME TEXT("Tor Win32 Service")
#include <windows.h>
#define GENSRV_SERVICENAME "tor"
#define GENSRV_DISPLAYNAME "Tor Win32 Service"
#define GENSRV_DESCRIPTION \
TEXT("Provides an anonymous Internet communication system")
#define GENSRV_USERACCT TEXT("NT AUTHORITY\\LocalService")
"Provides an anonymous Internet communication system"
#define GENSRV_USERACCT "NT AUTHORITY\\LocalService"
// Cheating: using the pre-defined error codes, tricks Windows into displaying
// a semi-related human-readable error message if startup fails as
@ -36,7 +36,6 @@ static SERVICE_STATUS_HANDLE hStatus;
* to the NT service functions. */
static char **backup_argv;
static int backup_argc;
static char* nt_strerror(uint32_t errnum);
static void nt_service_control(DWORD request);
static void nt_service_body(int argc, char **argv);
@ -70,30 +69,30 @@ struct service_fns {
SC_HANDLE (WINAPI *CreateServiceA_fn)(
SC_HANDLE hSCManager,
LPCTSTR lpServiceName,
LPCTSTR lpDisplayName,
LPCSTR lpServiceName,
LPCSTR lpDisplayName,
DWORD dwDesiredAccess,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
LPCTSTR lpBinaryPathName,
LPCTSTR lpLoadOrderGroup,
LPCSTR lpBinaryPathName,
LPCSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCTSTR lpDependencies,
LPCTSTR lpServiceStartName,
LPCTSTR lpPassword);
LPCSTR lpDependencies,
LPCSTR lpServiceStartName,
LPCSTR lpPassword);
BOOL (WINAPI *DeleteService_fn)(
SC_HANDLE hService);
SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
LPCTSTR lpMachineName,
LPCTSTR lpDatabaseName,
LPCSTR lpMachineName,
LPCSTR lpDatabaseName,
DWORD dwDesiredAccess);
SC_HANDLE (WINAPI *OpenServiceA_fn)(
SC_HANDLE hSCManager,
LPCTSTR lpServiceName,
LPCSTR lpServiceName,
DWORD dwDesiredAccess);
BOOL (WINAPI *QueryServiceStatus_fn)(
@ -101,23 +100,23 @@ struct service_fns {
LPSERVICE_STATUS lpServiceStatus);
SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
LPCTSTR lpServiceName,
LPCSTR lpServiceName,
LPHANDLER_FUNCTION lpHandlerProc);
BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
LPSERVICE_STATUS);
BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
const SERVICE_TABLE_ENTRY* lpServiceTable);
const SERVICE_TABLE_ENTRYA* lpServiceTable);
BOOL (WINAPI *StartServiceA_fn)(
SC_HANDLE hService,
DWORD dwNumServiceArgs,
LPCTSTR* lpServiceArgVectors);
LPCSTR* lpServiceArgVectors);
BOOL (WINAPI *LookupAccountNameA_fn)(
LPCTSTR lpSystemName,
LPCTSTR lpAccountName,
LPCSTR lpSystemName,
LPCSTR lpAccountName,
PSID Sid,
LPDWORD cbSid,
LPTSTR ReferencedDomainName,
@ -140,7 +139,7 @@ nt_service_loadlibrary(void)
return;
/* XXXX Possibly, we should hardcode the location of this DLL. */
if (!(library = LoadLibrary("advapi32.dll"))) {
if (!(library = LoadLibrary(TEXT("advapi32.dll")))) {
log_err(LD_GENERAL, "Couldn't open advapi32.dll. Are you trying to use "
"NT services on Windows 98? That doesn't work.");
goto err;
@ -284,20 +283,20 @@ nt_service_body(int argc, char **argv)
static void
nt_service_main(void)
{
SERVICE_TABLE_ENTRY table[2];
SERVICE_TABLE_ENTRYA table[2];
DWORD result = 0;
char *errmsg;
nt_service_loadlibrary();
table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)nt_service_body;
table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)nt_service_body;
table[1].lpServiceName = NULL;
table[1].lpServiceProc = NULL;
if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
result = GetLastError();
errmsg = nt_strerror(result);
errmsg = format_win32_error(result);
printf("Service error %d : %s\n", (int) result, errmsg);
LocalFree(errmsg);
tor_free(errmsg);
if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
if (tor_init(backup_argc, backup_argv) < 0)
return;
@ -332,9 +331,9 @@ nt_service_open_scm(void)
nt_service_loadlibrary();
if ((hSCManager = service_fns.OpenSCManagerA_fn(
NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
errmsg = nt_strerror(GetLastError());
errmsg = format_win32_error(GetLastError());
printf("OpenSCManager() failed : %s\n", errmsg);
LocalFree(errmsg);
tor_free(errmsg);
}
return hSCManager;
}
@ -349,9 +348,9 @@ nt_service_open(SC_HANDLE hSCManager)
nt_service_loadlibrary();
if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
SERVICE_ALL_ACCESS)) == NULL) {
errmsg = nt_strerror(GetLastError());
errmsg = format_win32_error(GetLastError());
printf("OpenService() failed : %s\n", errmsg);
LocalFree(errmsg);
tor_free(errmsg);
}
return hService;
}
@ -383,14 +382,14 @@ nt_service_start(SC_HANDLE hService)
printf("Service started successfully\n");
return 0;
} else {
errmsg = nt_strerror(service_status.dwWin32ExitCode);
errmsg = format_win32_error(service_status.dwWin32ExitCode);
printf("Service failed to start : %s\n", errmsg);
LocalFree(errmsg);
tor_free(errmsg);
}
} else {
errmsg = nt_strerror(GetLastError());
errmsg = format_win32_error(GetLastError());
printf("StartService() failed : %s\n", errmsg);
LocalFree(errmsg);
tor_free(errmsg);
}
return -1;
}
@ -427,14 +426,14 @@ nt_service_stop(SC_HANDLE hService)
} else if (wait_time == MAX_SERVICE_WAIT_TIME) {
printf("Service did not stop within %d seconds.\n", wait_time);
} else {
errmsg = nt_strerror(GetLastError());
errmsg = format_win32_error(GetLastError());
printf("QueryServiceStatus() failed : %s\n",errmsg);
LocalFree(errmsg);
tor_free(errmsg);
}
} else {
errmsg = nt_strerror(GetLastError());
errmsg = format_win32_error(GetLastError());
printf("ControlService() failed : %s\n", errmsg);
LocalFree(errmsg);
tor_free(errmsg);
}
return -1;
}
@ -448,6 +447,7 @@ static char *
nt_service_command_line(int *using_default_torrc)
{
TCHAR tor_exe[MAX_PATH+1];
char tor_exe_ascii[MAX_PATH+1];
char *command, *options=NULL;
smartlist_t *sl;
int i, cmdlen;
@ -473,18 +473,25 @@ nt_service_command_line(int *using_default_torrc)
options = smartlist_join_strings(sl,"\" \"",0,NULL);
smartlist_free(sl);
#ifdef UNICODE
wcstombs(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
#else
strlcpy(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
#endif
/* Allocate a string for the NT service command line */
cmdlen = strlen(tor_exe) + (options?strlen(options):0) + 32;
cmdlen = strlen(tor_exe_ascii) + (options?strlen(options):0) + 32;
command = tor_malloc(cmdlen);
/* Format the service command */
if (options) {
if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service \"%s\"",
tor_exe, options)<0) {
tor_exe_ascii, options)<0) {
tor_free(command); /* sets command to NULL. */
}
} else { /* ! options */
if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service", tor_exe)<0) {
if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service",
tor_exe_ascii)<0) {
tor_free(command); /* sets command to NULL. */
}
}
@ -509,7 +516,7 @@ nt_service_install(int argc, char **argv)
SC_HANDLE hSCManager = NULL;
SC_HANDLE hService = NULL;
SERVICE_DESCRIPTION sdBuff;
SERVICE_DESCRIPTIONA sdBuff;
char *command;
char *errmsg;
const char *user_acct = GENSRV_USERACCT;
@ -599,10 +606,10 @@ nt_service_install(int argc, char **argv)
SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
command, NULL, NULL, NULL,
user_acct, password)) == NULL) {
errmsg = nt_strerror(GetLastError());
errmsg = format_win32_error(GetLastError());
printf("CreateService() failed : %s\n", errmsg);
service_fns.CloseServiceHandle_fn(hSCManager);
LocalFree(errmsg);
tor_free(errmsg);
tor_free(command);
return -1;
}
@ -643,9 +650,9 @@ nt_service_remove(void)
nt_service_stop(hService);
if (service_fns.DeleteService_fn(hService) == FALSE) {
errmsg = nt_strerror(GetLastError());
errmsg = format_win32_error(GetLastError());
printf("DeleteService() failed : %s\n", errmsg);
LocalFree(errmsg);
tor_free(errmsg);
service_fns.CloseServiceHandle_fn(hService);
service_fns.CloseServiceHandle_fn(hSCManager);
return -1;
@ -702,20 +709,6 @@ nt_service_cmd_stop(void)
return stop;
}
/** Given a Win32 error code, this attempts to make Windows
* return a human-readable error message. The char* returned
* is allocated by Windows, but should be freed with LocalFree()
* when finished with it. */
static char*
nt_strerror(uint32_t errnum)
{
char *msgbuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&msgbuf, 0, NULL);
return msgbuf;
}
int
nt_service_parse_options(int argc, char **argv, int *should_exit)
{

View File

@ -111,7 +111,7 @@ _testcase_run_forked(const struct testgroup_t *group,
*/
int ok;
char buffer[LONGEST_TEST_NAME+256];
STARTUPINFO si;
STARTUPINFOA si;
PROCESS_INFORMATION info;
DWORD exitcode;
@ -130,7 +130,7 @@ _testcase_run_forked(const struct testgroup_t *group,
memset(&info, 0, sizeof(info));
si.cb = sizeof(si);
ok = CreateProcess(commandname, buffer, NULL, NULL, 0,
ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
0, NULL, NULL, &si, &info);
if (!ok) {
printf("CreateProcess failed!\n");