| 
									
										
										
										
											2017-04-27 20:18:03 +02:00
										 |  |  | // SPDX-License-Identifier: GPL-2.0
 | 
					
						
							| 
									
										
										
										
											2011-11-23 22:56:57 -08:00
										 |  |  | /* windows.c */ | 
					
						
							|  |  |  | /* implements Windows specific functions */ | 
					
						
							| 
									
										
										
										
											2014-11-13 19:36:08 +02:00
										 |  |  | #include <io.h>
 | 
					
						
							| 
									
										
										
										
											2012-09-09 09:06:44 -07:00
										 |  |  | #include "dive.h"
 | 
					
						
							| 
									
										
										
										
											2013-05-03 13:32:23 -07:00
										 |  |  | #include "display.h"
 | 
					
						
							| 
									
										
										
										
											2014-06-10 00:05:56 +03:00
										 |  |  | #undef _WIN32_WINNT
 | 
					
						
							| 
									
										
										
										
											2014-03-25 16:55:56 +02:00
										 |  |  | #define _WIN32_WINNT 0x500
 | 
					
						
							| 
									
										
										
										
											2011-11-23 22:56:57 -08:00
										 |  |  | #include <windows.h>
 | 
					
						
							| 
									
										
										
										
											2012-09-09 09:06:44 -07:00
										 |  |  | #include <shlobj.h>
 | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <assert.h>
 | 
					
						
							|  |  |  | #include <dirent.h>
 | 
					
						
							|  |  |  | #include <zip.h>
 | 
					
						
							| 
									
										
										
										
											2015-10-06 13:10:16 +03:00
										 |  |  | #include <lmcons.h>
 | 
					
						
							| 
									
										
										
										
											2013-01-11 17:07:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-22 15:22:02 -07:00
										 |  |  | const char non_standard_system_divelist_default_font[] = "Calibri"; | 
					
						
							|  |  |  | const char current_system_divelist_default_font[] = "Segoe UI"; | 
					
						
							|  |  |  | const char *system_divelist_default_font = non_standard_system_divelist_default_font; | 
					
						
							| 
									
										
										
										
											2014-08-27 06:00:10 -07:00
										 |  |  | double system_divelist_default_font_size = -1; | 
					
						
							| 
									
										
										
										
											2011-11-23 22:56:57 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-18 23:37:22 -07:00
										 |  |  | void subsurface_user_info(struct user_info *user) | 
					
						
							| 
									
										
										
										
											2014-04-14 14:33:46 -07:00
										 |  |  | { /* Encourage use of at least libgit2-0.20 */ } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-22 15:22:02 -07:00
										 |  |  | extern bool isWin7Or8(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void subsurface_OS_pref_setup(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (isWin7Or8()) | 
					
						
							|  |  |  | 		system_divelist_default_font = current_system_divelist_default_font; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 06:00:10 -07:00
										 |  |  | bool subsurface_ignore_font(const char *font) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// if this is running on a recent enough version of Windows and the font
 | 
					
						
							|  |  |  | 	// passed in is the pre 4.3 default font, ignore it
 | 
					
						
							|  |  |  | 	if (isWin7Or8() && strcmp(font, non_standard_system_divelist_default_font) == 0) | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 13:10:16 +03:00
										 |  |  | /* this function returns the Win32 Roaming path for the current user as UTF-8.
 | 
					
						
							|  |  |  |  * it never returns NULL but fallsback to .\ instead! | 
					
						
							|  |  |  |  * the append argument will append a wchar_t string to the end of the path. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const char *system_default_path_append(const wchar_t *append) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	wchar_t wpath[MAX_PATH] = { 0 }; | 
					
						
							|  |  |  | 	const char *fname = "system_default_path_append()"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* obtain the user path via SHGetFolderPathW.
 | 
					
						
							|  |  |  | 	 * this API is deprecated but still supported on modern Win32. | 
					
						
							|  |  |  | 	 * fallback to .\ if it fails. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, wpath))) { | 
					
						
							|  |  |  | 		fprintf(stderr, "%s: cannot obtain path!\n", fname); | 
					
						
							|  |  |  | 		wpath[0] = L'.'; | 
					
						
							|  |  |  | 		wpath[1] = L'\0'; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wcscat(wpath, L"\\Subsurface"); | 
					
						
							|  |  |  | 	if (append) { | 
					
						
							|  |  |  | 		wcscat(wpath, L"\\"); | 
					
						
							|  |  |  | 		wcscat(wpath, append); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* attempt to convert the UTF-16 string to UTF-8.
 | 
					
						
							|  |  |  | 	 * resize the buffer and fallback to .\Subsurface if it fails. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	const int wsz = wcslen(wpath); | 
					
						
							|  |  |  | 	const int sz = WideCharToMultiByte(CP_UTF8, 0, wpath, wsz, NULL, 0, NULL, NULL); | 
					
						
							|  |  |  | 	char *path = (char *)malloc(sz + 1); | 
					
						
							|  |  |  | 	if (!sz) | 
					
						
							|  |  |  | 		goto fallback; | 
					
						
							|  |  |  | 	if (WideCharToMultiByte(CP_UTF8, 0, wpath, wsz, path, sz, NULL, NULL)) { | 
					
						
							|  |  |  | 		path[sz] = '\0'; | 
					
						
							|  |  |  | 		return path; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | fallback: | 
					
						
							|  |  |  | 	fprintf(stderr, "%s: cannot obtain path as UTF-8!\n", fname); | 
					
						
							|  |  |  | 	const char *local = ".\\Subsurface"; | 
					
						
							|  |  |  | 	const int len = strlen(local) + 1; | 
					
						
							|  |  |  | 	path = (char *)realloc(path, len); | 
					
						
							|  |  |  | 	memset(path, 0, len); | 
					
						
							|  |  |  | 	strcat(path, local); | 
					
						
							|  |  |  | 	return path; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* by passing NULL to system_default_path_append() we obtain the pure path.
 | 
					
						
							|  |  |  |  * '\' not included at the end. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const char *system_default_directory(void) | 
					
						
							| 
									
										
										
										
											2012-09-09 09:06:44 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-10-06 13:10:16 +03:00
										 |  |  | 	static const char *path = NULL; | 
					
						
							|  |  |  | 	if (!path) | 
					
						
							|  |  |  | 		path = system_default_path_append(NULL); | 
					
						
							|  |  |  | 	return path; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-09-09 09:06:44 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 13:10:16 +03:00
										 |  |  | /* obtain the Roaming path and append "\\<USERNAME>.xml" to it.
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const char *system_default_filename(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-18 10:55:01 +01:00
										 |  |  | 	static const char *path = NULL; | 
					
						
							|  |  |  | 	if (!path) { | 
					
						
							| 
									
										
										
										
											2015-10-06 13:10:16 +03:00
										 |  |  | 		wchar_t username[UNLEN + 1] = { 0 }; | 
					
						
							|  |  |  | 		DWORD username_len = UNLEN + 1; | 
					
						
							|  |  |  | 		GetUserNameW(username, &username_len); | 
					
						
							| 
									
										
										
										
											2017-11-18 10:55:01 +01:00
										 |  |  | 		wchar_t filename[UNLEN + 5] = { 0 }; | 
					
						
							| 
									
										
										
										
											2015-10-06 13:10:16 +03:00
										 |  |  | 		wcscat(filename, username); | 
					
						
							|  |  |  | 		wcscat(filename, L".xml"); | 
					
						
							|  |  |  | 		path = system_default_path_append(filename); | 
					
						
							| 
									
										
										
										
											2017-11-18 10:55:01 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-06 13:10:16 +03:00
										 |  |  | 	return path; | 
					
						
							| 
									
										
										
										
											2012-09-09 09:06:44 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | int enumerate_devices(device_callback_t callback, void *userdata, int dc_type) | 
					
						
							| 
									
										
										
										
											2013-09-16 18:04:42 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	int index = -1; | 
					
						
							| 
									
										
										
										
											2013-09-17 07:50:54 -04:00
										 |  |  | 	DWORD i; | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 	if (dc_type != DC_TYPE_UEMIS) { | 
					
						
							|  |  |  | 		// Open the registry key.
 | 
					
						
							|  |  |  | 		HKEY hKey; | 
					
						
							|  |  |  | 		LONG rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey); | 
					
						
							| 
									
										
										
										
											2013-09-16 18:04:42 -03:00
										 |  |  | 		if (rc != ERROR_SUCCESS) { | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 		// Get the number of values.
 | 
					
						
							|  |  |  | 		DWORD count = 0; | 
					
						
							|  |  |  | 		rc = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL); | 
					
						
							|  |  |  | 		if (rc != ERROR_SUCCESS) { | 
					
						
							| 
									
										
										
										
											2013-09-16 18:04:42 -03:00
										 |  |  | 			RegCloseKey(hKey); | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 		for (i = 0; i < count; ++i) { | 
					
						
							|  |  |  | 			// Get the value name, data and type.
 | 
					
						
							|  |  |  | 			char name[512], data[512]; | 
					
						
							|  |  |  | 			DWORD name_len = sizeof(name); | 
					
						
							|  |  |  | 			DWORD data_len = sizeof(data); | 
					
						
							|  |  |  | 			DWORD type = 0; | 
					
						
							|  |  |  | 			rc = RegEnumValue(hKey, i, name, &name_len, NULL, &type, (LPBYTE)data, &data_len); | 
					
						
							|  |  |  | 			if (rc != ERROR_SUCCESS) { | 
					
						
							|  |  |  | 				RegCloseKey(hKey); | 
					
						
							|  |  |  | 				return -1; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Ignore non-string values.
 | 
					
						
							|  |  |  | 			if (type != REG_SZ) | 
					
						
							|  |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2013-09-16 18:04:42 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 			// Prevent a possible buffer overflow.
 | 
					
						
							|  |  |  | 			if (data_len >= sizeof(data)) { | 
					
						
							|  |  |  | 				RegCloseKey(hKey); | 
					
						
							|  |  |  | 				return -1; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-09-16 18:04:42 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 			// Null terminate the string.
 | 
					
						
							|  |  |  | 			data[data_len] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			callback(data, userdata); | 
					
						
							|  |  |  | 			index++; | 
					
						
							|  |  |  | 			if (is_default_dive_computer_device(name)) | 
					
						
							|  |  |  | 				index = i; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		RegCloseKey(hKey); | 
					
						
							| 
									
										
										
										
											2013-09-16 18:04:42 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 	if (dc_type != DC_TYPE_SERIAL) { | 
					
						
							|  |  |  | 		int i; | 
					
						
							| 
									
										
										
										
											2014-05-18 14:13:23 +09:00
										 |  |  | 		int count_drives = 0; | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 		const int bufdef = 512; | 
					
						
							|  |  |  | 		const char *dlabels[] = {"UEMISSDA", NULL}; | 
					
						
							|  |  |  | 		char bufname[bufdef], bufval[bufdef], *p; | 
					
						
							|  |  |  | 		DWORD bufname_len; | 
					
						
							| 
									
										
										
										
											2013-09-16 18:04:42 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 		/* add drive letters that match labels */ | 
					
						
							|  |  |  | 		memset(bufname, 0, bufdef); | 
					
						
							|  |  |  | 		bufname_len = bufdef; | 
					
						
							|  |  |  | 		if (GetLogicalDriveStringsA(bufname_len, bufname)) { | 
					
						
							|  |  |  | 			p = bufname; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			while (*p) { | 
					
						
							|  |  |  | 				memset(bufval, 0, bufdef); | 
					
						
							|  |  |  | 				if (GetVolumeInformationA(p, bufval, bufdef, NULL, NULL, NULL, NULL, 0)) { | 
					
						
							|  |  |  | 					for (i = 0; dlabels[i] != NULL; i++) | 
					
						
							|  |  |  | 						if (!strcmp(bufval, dlabels[i])) { | 
					
						
							|  |  |  | 							char data[512]; | 
					
						
							|  |  |  | 							snprintf(data, sizeof(data), "%s (%s)", p, dlabels[i]); | 
					
						
							|  |  |  | 							callback(data, userdata); | 
					
						
							|  |  |  | 							if (is_default_dive_computer_device(p)) | 
					
						
							| 
									
										
										
										
											2014-05-18 14:13:23 +09:00
										 |  |  | 								index = count_drives; | 
					
						
							|  |  |  | 							count_drives++; | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 						} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				p = &p[strlen(p) + 1]; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-05-18 14:13:23 +09:00
										 |  |  | 			if (count_drives == 1) /* we found exactly one Uemis "drive" */ | 
					
						
							|  |  |  | 				index = 0; /* make it the selected "device" */ | 
					
						
							| 
									
										
										
										
											2014-05-18 13:29:40 +09:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-09-16 18:04:42 -03:00
										 |  |  | 	return index; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* this function converts a utf-8 string to win32's utf-16 2 byte string.
 | 
					
						
							|  |  |  |  * the caller function should manage the allocated memory. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static wchar_t *utf8_to_utf16_fl(const char *utf8, char *file, int line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	assert(utf8 != NULL); | 
					
						
							|  |  |  | 	assert(file != NULL); | 
					
						
							|  |  |  | 	assert(line); | 
					
						
							|  |  |  | 	/* estimate buffer size */ | 
					
						
							|  |  |  | 	const int sz = strlen(utf8) + 1; | 
					
						
							|  |  |  | 	wchar_t *utf16 = (wchar_t *)malloc(sizeof(wchar_t) * sz); | 
					
						
							|  |  |  | 	if (!utf16) { | 
					
						
							|  |  |  | 		fprintf(stderr, "%s:%d: %s %d.", file, line, "cannot allocate buffer of size", sz); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, sz)) | 
					
						
							|  |  |  | 		return utf16; | 
					
						
							|  |  |  | 	fprintf(stderr, "%s:%d: %s", file, line, "cannot convert string."); | 
					
						
							|  |  |  | 	free((void *)utf16); | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define utf8_to_utf16(s) utf8_to_utf16_fl(s, __FILE__, __LINE__)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* bellow we provide a set of wrappers for some I/O functions to use wchar_t.
 | 
					
						
							|  |  |  |  * on win32 this solves the issue that we need paths to be utf-16 encoded. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2014-02-16 13:25:02 -08:00
										 |  |  | int subsurface_rename(const char *path, const char *newpath) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -1; | 
					
						
							|  |  |  | 	if (!path || !newpath) | 
					
						
							| 
									
										
										
										
											2014-11-13 19:41:47 +02:00
										 |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2014-02-16 13:25:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	wchar_t *wpath = utf8_to_utf16(path); | 
					
						
							|  |  |  | 	wchar_t *wnewpath = utf8_to_utf16(newpath); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (wpath && wnewpath) | 
					
						
							|  |  |  | 		ret = _wrename(wpath, wnewpath); | 
					
						
							|  |  |  | 	free((void *)wpath); | 
					
						
							|  |  |  | 	free((void *)wnewpath); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 12:35:21 -04:00
										 |  |  | // if the QDir based rename fails, we try this one
 | 
					
						
							|  |  |  | int subsurface_dir_rename(const char *path, const char *newpath) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// check if the folder exists
 | 
					
						
							|  |  |  | 	BOOL exists = FALSE; | 
					
						
							|  |  |  | 	DWORD attrib = GetFileAttributes(path); | 
					
						
							|  |  |  | 	if (attrib != INVALID_FILE_ATTRIBUTES && attrib & FILE_ATTRIBUTE_DIRECTORY) | 
					
						
							|  |  |  | 		exists = TRUE; | 
					
						
							|  |  |  | 	if (!exists && verbose) { | 
					
						
							|  |  |  | 		fprintf(stderr, "folder not found or path is not a folder: %s\n", path); | 
					
						
							|  |  |  | 		return EXIT_FAILURE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// list of error codes:
 | 
					
						
							|  |  |  | 	// https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
 | 
					
						
							|  |  |  | 	DWORD errorCode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if this fails something has already obatained (more) exclusive access to the folder
 | 
					
						
							|  |  |  | 	HANDLE h = CreateFile(path, GENERIC_WRITE, FILE_SHARE_WRITE | | 
					
						
							|  |  |  | 			      FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); | 
					
						
							|  |  |  | 	if (h == INVALID_HANDLE_VALUE) { | 
					
						
							|  |  |  | 		errorCode = GetLastError(); | 
					
						
							|  |  |  | 		if (verbose) | 
					
						
							|  |  |  | 			fprintf(stderr, "cannot obtain exclusive write access for folder: %u\n", (unsigned int)errorCode ); | 
					
						
							|  |  |  | 		return EXIT_FAILURE; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if (verbose) | 
					
						
							|  |  |  | 			fprintf(stderr, "exclusive write access obtained...closing handle!"); | 
					
						
							|  |  |  | 		CloseHandle(h); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// attempt to rename
 | 
					
						
							|  |  |  | 		BOOL result = MoveFile(path, newpath); | 
					
						
							|  |  |  | 		if (!result) { | 
					
						
							|  |  |  | 			errorCode = GetLastError(); | 
					
						
							|  |  |  | 			if (verbose) | 
					
						
							|  |  |  | 				fprintf(stderr, "rename failed: %u\n", (unsigned int)errorCode); | 
					
						
							|  |  |  | 			return EXIT_FAILURE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (verbose > 1) | 
					
						
							|  |  |  | 			fprintf(stderr, "folder rename success: %s ---> %s\n", path, newpath); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return EXIT_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | int subsurface_open(const char *path, int oflags, mode_t mode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -1; | 
					
						
							| 
									
										
										
										
											2014-01-07 16:41:19 +02:00
										 |  |  | 	if (!path) | 
					
						
							| 
									
										
										
										
											2014-11-13 19:41:47 +02:00
										 |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 	wchar_t *wpath = utf8_to_utf16(path); | 
					
						
							| 
									
										
										
										
											2014-11-13 19:41:47 +02:00
										 |  |  | 	if (wpath) | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 		ret = _wopen(wpath, oflags, mode); | 
					
						
							| 
									
										
										
										
											2014-11-13 19:41:47 +02:00
										 |  |  | 	free((void *)wpath); | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FILE *subsurface_fopen(const char *path, const char *mode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	FILE *ret = NULL; | 
					
						
							| 
									
										
										
										
											2014-01-07 16:41:19 +02:00
										 |  |  | 	if (!path) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 	wchar_t *wpath = utf8_to_utf16(path); | 
					
						
							|  |  |  | 	if (wpath) { | 
					
						
							|  |  |  | 		const int len = strlen(mode); | 
					
						
							|  |  |  | 		wchar_t wmode[len + 1]; | 
					
						
							|  |  |  | 		for (int i = 0; i < len; i++) | 
					
						
							|  |  |  | 			wmode[i] = (wchar_t)mode[i]; | 
					
						
							|  |  |  | 		wmode[len] = 0; | 
					
						
							|  |  |  | 		ret = _wfopen(wpath, wmode); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-13 19:41:47 +02:00
										 |  |  | 	free((void *)wpath); | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* here we return a void pointer instead of _WDIR or DIR pointer */ | 
					
						
							|  |  |  | void *subsurface_opendir(const char *path) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	_WDIR *ret = NULL; | 
					
						
							| 
									
										
										
										
											2014-01-07 16:41:19 +02:00
										 |  |  | 	if (!path) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 	wchar_t *wpath = utf8_to_utf16(path); | 
					
						
							| 
									
										
										
										
											2014-11-13 19:41:47 +02:00
										 |  |  | 	if (wpath) | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 		ret = _wopendir(wpath); | 
					
						
							| 
									
										
										
										
											2014-11-13 19:41:47 +02:00
										 |  |  | 	free((void *)wpath); | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 	return (void *)ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 19:36:08 +02:00
										 |  |  | int subsurface_access(const char *path, int mode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -1; | 
					
						
							|  |  |  | 	if (!path) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	wchar_t *wpath = utf8_to_utf16(path); | 
					
						
							|  |  |  | 	if (wpath) | 
					
						
							|  |  |  | 		ret = _waccess(wpath, mode); | 
					
						
							|  |  |  | 	free((void *)wpath); | 
					
						
							| 
									
										
										
										
											2017-02-24 14:06:48 +07:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int subsurface_stat(const char* path, struct stat* buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -1; | 
					
						
							|  |  |  | 	if (!path) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	wchar_t *wpath = utf8_to_utf16(path); | 
					
						
							|  |  |  | 	if (wpath) | 
					
						
							|  |  |  | 		ret = wstat(wpath, buf); | 
					
						
							|  |  |  | 	free((void *)wpath); | 
					
						
							| 
									
										
										
										
											2014-11-13 19:36:08 +02:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | #ifndef O_BINARY
 | 
					
						
							|  |  |  | #define O_BINARY 0
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct zip *subsurface_zip_open_readonly(const char *path, int flags, int *errorp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-12-19 17:01:54 -08:00
										 |  |  | #if defined(LIBZIP_VERSION_MAJOR)
 | 
					
						
							|  |  |  | 	/* libzip 0.10 has zip_fdopen, let's use it since zip_open doesn't have a
 | 
					
						
							|  |  |  | 	 * wchar_t version */ | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | 	int fd = subsurface_open(path, O_RDONLY | O_BINARY, 0); | 
					
						
							|  |  |  | 	struct zip *ret = zip_fdopen(fd, flags, errorp); | 
					
						
							|  |  |  | 	if (!ret) | 
					
						
							|  |  |  | 		close(fd); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2013-12-19 17:01:54 -08:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 	return zip_open(path, flags, errorp); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-12-19 15:00:50 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int subsurface_zip_close(struct zip *zip) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return zip_close(zip); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-03-25 16:55:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* win32 console */ | 
					
						
							|  |  |  | static struct { | 
					
						
							|  |  |  | 	bool allocated; | 
					
						
							|  |  |  | 	UINT cp; | 
					
						
							|  |  |  | 	FILE *out, *err; | 
					
						
							|  |  |  | } console_desc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 01:51:33 +02:00
										 |  |  | void subsurface_console_init(void) | 
					
						
							| 
									
										
										
										
											2014-03-25 16:55:56 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-04-02 22:42:44 +03:00
										 |  |  | 	(void)console_desc; | 
					
						
							| 
									
										
										
										
											2014-03-25 16:55:56 +02:00
										 |  |  | 	/* if this is a console app already, do nothing */ | 
					
						
							|  |  |  | #ifndef WIN32_CONSOLE_APP
 | 
					
						
							| 
									
										
										
										
											2017-02-02 21:50:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-25 16:55:56 +02:00
										 |  |  | 	/* just in case of multiple calls */ | 
					
						
							|  |  |  | 	memset((void *)&console_desc, 0, sizeof(console_desc)); | 
					
						
							| 
									
										
										
										
											2017-11-03 01:51:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* if AttachConsole(ATTACH_PARENT_PROCESS) returns true the parent process
 | 
					
						
							|  |  |  | 	 * is a terminal. based on the result, either redirect to that terminal or | 
					
						
							|  |  |  | 	 * to log files. | 
					
						
							| 
									
										
										
										
											2014-03-25 16:55:56 +02:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	console_desc.allocated = AttachConsole(ATTACH_PARENT_PROCESS); | 
					
						
							| 
									
										
										
										
											2017-11-03 01:51:33 +02:00
										 |  |  | 	if (console_desc.allocated) { | 
					
						
							|  |  |  | 		console_desc.cp = GetConsoleCP(); | 
					
						
							|  |  |  | 		SetConsoleOutputCP(CP_UTF8); /* make the ouput utf8 */ | 
					
						
							|  |  |  | 		console_desc.out = freopen("CON", "w", stdout); | 
					
						
							|  |  |  | 		console_desc.err = freopen("CON", "w", stderr); | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-11-15 22:04:03 +02:00
										 |  |  | 		verbose = 1; /* set the verbose level to '1' */ | 
					
						
							| 
									
										
										
										
											2017-11-03 01:51:33 +02:00
										 |  |  | 		console_desc.out = freopen("subsurface_out.log", "w", stdout); | 
					
						
							|  |  |  | 		console_desc.err = freopen("subsurface_err.log", "w", stderr); | 
					
						
							| 
									
										
										
										
											2014-03-25 16:55:56 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 01:51:33 +02:00
										 |  |  | 	puts(""); /* add an empty line */ | 
					
						
							| 
									
										
										
										
											2014-03-25 16:55:56 +02:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void subsurface_console_exit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifndef WIN32_CONSOLE_APP
 | 
					
						
							|  |  |  | 	/* close handles */ | 
					
						
							|  |  |  | 	if (console_desc.out) | 
					
						
							|  |  |  | 		fclose(console_desc.out); | 
					
						
							|  |  |  | 	if (console_desc.err) | 
					
						
							|  |  |  | 		fclose(console_desc.err); | 
					
						
							|  |  |  | 	/* reset code page and free */ | 
					
						
							| 
									
										
										
										
											2017-11-03 01:51:33 +02:00
										 |  |  | 	if (console_desc.allocated) { | 
					
						
							|  |  |  | 		SetConsoleOutputCP(console_desc.cp); | 
					
						
							|  |  |  | 		FreeConsole(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-25 16:55:56 +02:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-25 09:21:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | bool subsurface_user_is_root() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* FIXME: Detect admin rights */ | 
					
						
							|  |  |  | 	return (false); | 
					
						
							|  |  |  | } |