[Box Backup-dev] COMMIT r381 - in box/chris/win32/vc2005-compile-fixes: bin/bbackupquery lib/win32

boxbackup-dev@fluffy.co.uk boxbackup-dev@fluffy.co.uk
Sat, 4 Feb 2006 19:51:28 +0000 (GMT)


Author: chris
Date: 2006-02-04 19:51:22 +0000 (Sat, 04 Feb 2006)
New Revision: 381

Modified:
   box/chris/win32/vc2005-compile-fixes/bin/bbackupquery/BackupQueries.cpp
   box/chris/win32/vc2005-compile-fixes/lib/win32/emu.cpp
   box/chris/win32/vc2005-compile-fixes/lib/win32/emu.h
Log:
* lib/win32/emu.cpp, lib/win32/emu.h, bin/bbackupquery/BackupQueries.cpp
- First pass at listing files with wide characters on Win32


Modified: box/chris/win32/vc2005-compile-fixes/bin/bbackupquery/BackupQueries.cpp
===================================================================
--- box/chris/win32/vc2005-compile-fixes/bin/bbackupquery/BackupQueries.cpp	2006-02-04 15:42:05 UTC (rev 380)
+++ box/chris/win32/vc2005-compile-fixes/bin/bbackupquery/BackupQueries.cpp	2006-02-04 19:51:22 UTC (rev 381)
@@ -335,7 +335,16 @@
 		rootDir = FindDirectoryObjectID(args[0], opts[LIST_OPTION_ALLOWOLD], opts[LIST_OPTION_ALLOWDELETED]);
 		if(rootDir == 0)
 		{
-			printf("Directory %s not found on store\n", args[0].c_str());
+			char* pMsg = "Directory '%s' not found on store\n";
+#ifdef WIN32
+			WCHAR* pMsgBuffer  = ConvertUtf8ToMultiByte(pMsg);
+			WCHAR* pNameBuffer = ConvertUtf8ToMultiByte(args[0].c_str());
+			wprintf(pMsgBuffer, pNameBuffer);
+			delete [] pNameBuffer;
+			delete [] pMsgBuffer;
+#else
+			printf(msg, args[0].c_str());
+#endif
 			return;
 		}
 	}
@@ -379,19 +388,16 @@
 	{
 		// Display this entry
 		BackupStoreFilenameClear clear(en->GetName());
-		std::string line;
 		
 		// Object ID?
 		if(!opts[LIST_OPTION_NOOBJECTID])
 		{
 			// add object ID to line
-			char oid[32];
-#ifdef WIN32
-			sprintf(oid, "%08I64x ", en->GetObjectID());
+#ifdef _MSC_VER
+			printf("%08I64x ", (int64_t)en->GetObjectID());
 #else
-			sprintf(oid, "%08llx ", en->GetObjectID());
+			printf("%08llx ", (long long)en->GetObjectID());
 #endif
-			line += oid;
 		}
 		
 		// Flags?
@@ -418,58 +424,71 @@
 			// terminate
 			*(f++) = ' ';
 			*(f++) = '\0';
-			line += displayflags;
+			printf(displayflags);
+			
 			if(en_flags != 0)
 			{
-				line += "[ERROR: Entry has additional flags set] ";
+				printf("[ERROR: Entry has additional flags set] ");
 			}
 		}
 		
 		if(opts[LIST_OPTION_TIMES])
 		{
 			// Show times...
-			line += BoxTimeToISO8601String(en->GetModificationTime());
-			line += ' ';
+			printf("%s ", BoxTimeToISO8601String(en->GetModificationTime()));
 		}
 		
 		if(opts[LIST_OPTION_DISPLAY_HASH])
 		{
-			char hash[64];
-#ifdef WIN32
-			::sprintf(hash, "%016I64x ", en->GetAttributesHash());
+#ifdef _MSC_VER
+			printf("%016I64x ", (int64_t)en->GetAttributesHash());
 #else
-			::sprintf(hash, "%016llx ", en->GetAttributesHash());
+			printf("%016llx ", (long long)en->GetAttributesHash());
 #endif
-			line += hash;
 		}
 		
 		if(opts[LIST_OPTION_SIZEINBLOCKS])
 		{
-			char num[32];
-#ifdef WIN32
-			sprintf(num, "%05I64d ", en->GetSizeInBlocks());
+#ifdef _MSC_VER
+			printf("%05I64d ", (int64_t)en->GetSizeInBlocks());
 #else
-			sprintf(num, "%05lld ", en->GetSizeInBlocks());
+			printf("%05lld ", (long long)en->GetSizeInBlocks());
 #endif
-			line += num;
 		}
 		
 		// add name
 		if(!FirstLevel)
 		{
-			line += rListRoot;
-			line += '/';
+#ifdef WIN32
+			pMsgBuffer  = ConvertUtf8ToMultiByte("%s");
+			pNameBuffer = ConvertUtf8ToMultiByte(rListRoot);
+			wprintf(pMsgBuffer, pNameBuffer);
+			delete [] pNameBuffer;
+			delete [] pMsgBuffer;
+			printf("/");
+#else
+			printf("%s/", rListRoot.c_str());
+#endif
 		}
-		line += clear.GetClearFilename().c_str();
 		
+#ifdef WIN32
+		{
+			pMsgBuffer  = ConvertUtf8ToMultiByte("%s");
+			pNameBuffer = ConvertUtf8ToMultiByte(
+				clear.GetClearFilename().c_str());
+			wprintf(pMsgBuffer, pNameBuffer);
+			delete [] pNameBuffer;
+			delete [] pMsgBuffer;
+		}
+#else
+		printf("%s", clear.GetClearFilename().c_str());
+#endif
+		
 		if(!en->GetName().IsEncrypted())
 		{
-			line += "[FILENAME NOT ENCRYPTED]";
+			printf("[FILENAME NOT ENCRYPTED]");
 		}
 		
-		// print line
-		printf("%s\n", line.c_str());
-		
 		// Directory?
 		if((en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) != 0)
 		{
@@ -1715,8 +1734,3 @@
 	// Undelete
 	mrConnection.QueryUndeleteDirectory(dirID);
 }
-
-
-
-
-

Modified: box/chris/win32/vc2005-compile-fixes/lib/win32/emu.cpp
===================================================================
--- box/chris/win32/vc2005-compile-fixes/lib/win32/emu.cpp	2006-02-04 15:42:05 UTC (rev 380)
+++ box/chris/win32/vc2005-compile-fixes/lib/win32/emu.cpp	2006-02-04 19:51:22 UTC (rev 381)
@@ -203,131 +203,177 @@
 // --------------------------------------------------------------------------
 //
 // Function
-//		Name:    openfile
-//		Purpose: replacement for any open calls - handles unicode filenames - supplied in utf8
-//		Created: 25th October 2004
+//		Name:    ConvertUtf8ToMultiByte
+//		Purpose: Converts a string from UTF-8 to multibyte characters (MBCS).
+//			Returns a buffer which MUST be freed by the caller with delete[].
+//			In case of fire, logs the error and returns NULL.
+//		Created: 4th February 2006
 //
 // --------------------------------------------------------------------------
-HANDLE openfile(const char *filename, int flags, int mode)
+WCHAR* ConvertUtf8ToMultiByte(const char* pName)
 {
-	try
-	{
-		wchar_t *buffer;
-		std::string fileN(filename);
+	int strlen = MultiByteToWideChar(
+		CP_UTF8,       // source code page
+		0,             // character-type options
+		pName,         // string to map
+		strlen(pName), // number of bytes in string
+		NULL,          // wide-character buffer
+		0              // size of buffer - work out 
+		               //   how much space we need
+		);
 
-		std::string tmpStr("\\\\?\\");
-		//is the path relative or otherwise
-		if ( fileN[1] != ':' )
-		{
-			//we need to get the current directory
-			char wd[PATH_MAX];
-			if(::getcwd(wd, PATH_MAX) == 0)
-			{
-				return NULL;
-			}
-			tmpStr += wd;
-			if (tmpStr[tmpStr.length()] != '\\')
-			{
-				tmpStr += '\\';
-			}
-		}
-		tmpStr += filename;
+	WCHAR* buffer = new WCHAR[strlen+1];
 
-		int strlen = MultiByteToWideChar(
-			CP_UTF8,               // code page
-			0,                     // character-type options
-			tmpStr.c_str(),        // string to map
-			(int)tmpStr.length(),       // number of bytes in string
-			NULL,                  // wide-character buffer
-			0                      // size of buffer - work out how much space we need
-			);
+	if (buffer == NULL)
+	{
+		::syslog(LOG_WARNING, 
+			"Failed to convert string to multibyte: '%s': "
+			"out of memory", pName);
+		errno = ENOMEM;
+		return NULL;
+	}
 
-		buffer = new wchar_t[strlen+1];
-		if ( buffer == NULL )
-		{
-			::syslog(LOG_WARNING, "Failed to allocate buffer "
-				"for converting file name: %s",
-				tmpStr.c_str());
-			return NULL;
-		}
+	strlen = MultiByteToWideChar(
+		CP_UTF8,       // source code page
+		0,             // character-type options
+		pName,         // string to map
+		strlen(pName), // number of bytes in string
+		buffer,        // wide-character buffer
+		strlen         // size of buffer
+		);
 
-		strlen = MultiByteToWideChar(
-			CP_UTF8,               // code page
-			0,                     // character-type options
-			tmpStr.c_str(),        // string to map
-			(int)tmpStr.length(),       // number of bytes in string
-			buffer,                // wide-character buffer
-			strlen                 // size of buffer
-			);
+	if (strlen == 0)
+	{
+		::syslog(LOG_WARNING, 
+			"Failed to convert string to multibyte: '%s': "
+			"error %i", pName, GetLastError());
+		errno = EACCES;
+		delete [] buffer;
+		return NULL;
+	}
 
-		if ( strlen == 0 )
-		{
-			::syslog(LOG_WARNING, "Failed to convert filename "
-				"to unicode: %s (error %i)",
-				tmpStr.c_str(), GetLastError());
-			delete [] buffer;
-			return NULL;
-		}
+	buffer[strlen] = L'\0';
 
-		buffer[strlen] = L'\0';
+	return buffer;
+}
 
-		//flags could be O_WRONLY | O_CREAT | O_RDONLY
-		DWORD createDisposition = OPEN_EXISTING;
-		DWORD shareMode = FILE_SHARE_READ;
-		DWORD accessRights = FILE_READ_ATTRIBUTES | FILE_LIST_DIRECTORY | FILE_READ_EA;
-
-		if (flags & O_WRONLY)
+// --------------------------------------------------------------------------
+//
+// Function
+//		Name:    ConvertPathToAbsoluteUnicode
+//		Purpose: Converts relative paths to absolute (with unicode marker)
+//		Created: 4th February 2006
+//
+// --------------------------------------------------------------------------
+std::string ConvertPathToAbsoluteUnicode(const char *filename)
+{
+	std::string tmpStr("\\\\?\\");
+	
+	// Is the path relative or absolute?
+	// Absolute paths on Windows are always a drive letter
+	// followed by ':'
+	
+	if (fileN[1] != ':')
+	{
+		// Must be relative. We need to get the 
+		// current directory to make it absolute.
+		
+		char wd[PATH_MAX];
+		if (::getcwd(wd, PATH_MAX) == 0)
 		{
-			shareMode = FILE_SHARE_WRITE;
+			::syslog(LOG_WARNING, 
+				"Failed to open '%s': path too long", pName);
+			errno = ENAMETOOLONG;
+			tmpStr = "";
+			return tmpStr;
 		}
-		if (flags & O_RDWR)
+		
+		tmpStr += wd;
+		if (tmpStr[tmpStr.length()] != '\\')
 		{
-			shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+			tmpStr += '\\';
 		}
-		if (flags & O_CREAT)
-		{
-			createDisposition = OPEN_ALWAYS;
-			shareMode |= FILE_SHARE_WRITE;
-			accessRights |= FILE_WRITE_ATTRIBUTES 
-				| FILE_WRITE_DATA | FILE_WRITE_EA 
-				| FILE_ALL_ACCESS;
-		}
-		if (flags & O_TRUNC)
-		{
-			createDisposition = CREATE_ALWAYS;
-		}
-		if (flags & O_EXCL)
-		{
-			shareMode = 0;
-		}
+	}
+	
+	tmpStr += filename;
+	return tmpStr;
+}
 
-		HANDLE hdir = CreateFileW(buffer, 
-			accessRights, 
-			shareMode, 
-			NULL, 
-			createDisposition, 
-			FILE_FLAG_BACKUP_SEMANTICS,
-			NULL);
+// --------------------------------------------------------------------------
+//
+// Function
+//		Name:    openfile
+//		Purpose: replacement for any open calls - handles unicode filenames - supplied in utf8
+//		Created: 25th October 2004
+//
+// --------------------------------------------------------------------------
+HANDLE openfile(const char *pFileName, int flags, int mode)
+{
+	std::string AbsPathWithUnicode = ConvertPathToAbsoluteUnicode(pFileName);
+	
+	if (AbsPathWithUnicode.size() == 0)
+	{
+		// error already logged by ConvertPathToAbsoluteUnicode()
+		return NULL;
+	}
+	
+	WCHAR* pBuffer = ConvertUtf8ToMultiByte(AbsPathWithUnicode.c_str());
+	// We are responsible for freeing pBuffer
+	
+	if (pBuffer == NULL)
+	{
+		// error already logged by ConvertUtf8ToMultiByte()
+		return NULL;
+	}
 
-		if ( hdir == INVALID_HANDLE_VALUE )
-		{
-			DWORD err = GetLastError();
-			::syslog(LOG_WARNING, "Failed to open file %s: "
-				"error %i", filename, err);
-			delete [] buffer;
-			return NULL;
-		}
+	// flags could be O_WRONLY | O_CREAT | O_RDONLY
+	DWORD createDisposition = OPEN_EXISTING;
+	DWORD shareMode = FILE_SHARE_READ;
+	DWORD accessRights = FILE_READ_ATTRIBUTES | FILE_LIST_DIRECTORY | FILE_READ_EA;
 
-		delete [] buffer;
-		return hdir;
-
+	if (flags & O_WRONLY)
+	{
+		shareMode = FILE_SHARE_WRITE;
 	}
-	catch(...)
+	if (flags & O_RDWR)
 	{
-		::syslog(LOG_ERR, "Caught openfile: %s", filename);
+		shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
 	}
-	return NULL;
+	if (flags & O_CREAT)
+	{
+		createDisposition = OPEN_ALWAYS;
+		shareMode |= FILE_SHARE_WRITE;
+		accessRights |= FILE_WRITE_ATTRIBUTES 
+			| FILE_WRITE_DATA | FILE_WRITE_EA 
+			| FILE_ALL_ACCESS;
+	}
+	if (flags & O_TRUNC)
+	{
+		createDisposition = CREATE_ALWAYS;
+	}
+	if (flags & O_EXCL)
+	{
+		shareMode = 0;
+	}
 
+	HANDLE hdir = CreateFileW(pBuffer, 
+		accessRights, 
+		shareMode, 
+		NULL, 
+		createDisposition, 
+		FILE_FLAG_BACKUP_SEMANTICS,
+		NULL);
+	
+	delete [] pBuffer;
+
+	if (hdir == INVALID_HANDLE_VALUE)
+	{
+		::syslog(LOG_WARNING, "Failed to open file %s: "
+			"error %i", pFileName, GetLastError());
+		return NULL;
+	}
+
+	return hdir;
 }
 
 // MinGW provides a getopt implementation
@@ -427,76 +473,26 @@
 //		Created: 10th December 2004
 //
 // --------------------------------------------------------------------------
-HANDLE OpenFileByNameUtf8(const char* pName)
+HANDLE OpenFileByNameUtf8(const char* pFileName)
 {
-	//some string thing - required by ms to indicate long/unicode filename
-	std::string tmpStr("\\\\?\\");
-
-	// is the path relative or otherwise
-	std::string fileN(pName);
-	if (fileN[1] != ':')
+	std::string AbsPathWithUnicode = ConvertPathToAbsoluteUnicode(pFileName);
+	
+	if (AbsPathWithUnicode.size() == 0)
 	{
-		// we need to get the current directory
-		char wd[PATH_MAX];
-		if(::getcwd(wd, PATH_MAX) == 0)
-		{
-			::syslog(LOG_WARNING, 
-				"Failed to open '%s': path too long", pName);
-			errno = ENAMETOOLONG;
-			return NULL;
-		}
-
-		tmpStr += wd;
-		if (tmpStr[tmpStr.length()] != '\\')
-		{
-			tmpStr += '\\';
-		}
-	}
-
-	tmpStr += fileN;
-
-	int strlen = MultiByteToWideChar(
-		CP_UTF8,               // code page
-		0,                     // character-type options
-		tmpStr.c_str(),        // string to map
-		(int)tmpStr.length(),  // number of bytes in string
-		NULL,                  // wide-character buffer
-		0                      // size of buffer - work out 
-		                       //   how much space we need
-		);
-
-	wchar_t* buffer = new wchar_t[strlen+1];
-
-	if (buffer == NULL)
-	{
-		::syslog(LOG_WARNING, 
-			"Failed to open '%s': out of memory", pName);
-		errno = ENOMEM;
+		// error already logged by ConvertPathToAbsoluteUnicode()
 		return NULL;
 	}
-
-	strlen = MultiByteToWideChar(
-		CP_UTF8,               // code page
-		0,                     // character-type options
-		tmpStr.c_str(),        // string to map
-		(int)tmpStr.length(),  // number of bytes in string
-		buffer,                // wide-character buffer
-		strlen                 // size of buffer
-		);
-
-	if (strlen == 0)
+	
+	WCHAR* pBuffer = ConvertUtf8ToMultiByte(AbsPathWithUnicode.c_str());
+	// We are responsible for freeing pBuffer
+	
+	if (pBuffer == NULL)
 	{
-		::syslog(LOG_WARNING, 
-			"Failed to open '%s': could not convert "
-			"file name to Unicode", pName);
-		errno = EACCES;
-		delete [] buffer;
+		// error already logged by ConvertUtf8ToMultiByte()
 		return NULL;
 	}
 
-	buffer[strlen] = L'\0';
-
-	HANDLE handle = CreateFileW(buffer, 
+	HANDLE handle = CreateFileW(pBuffer, 
 		FILE_READ_ATTRIBUTES | FILE_LIST_DIRECTORY | FILE_READ_EA, 
 		FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, 
 		NULL, 
@@ -510,7 +506,7 @@
 		// open in this mode - to get the inode information
 		// at least one process must have the file open - 
 		// in this case someone else does.
-		handle = CreateFileW(buffer, 
+		handle = CreateFileW(pBuffer, 
 			0, 
 			FILE_SHARE_READ, 
 			NULL, 
@@ -532,7 +528,7 @@
 		else
 		{
 			::syslog(LOG_WARNING, 
-				"Failed to open '%s': error %d", pName);
+				"Failed to open '%s': error %d", pFileName, err);
 			errno = EACCES;
 		}
 
@@ -630,105 +626,50 @@
 // --------------------------------------------------------------------------
 DIR *opendir(const char *name)
 {
-	try
+	if (!name || !name[0])
 	{
-		DIR *dir = 0;
-		std::string dirName(name);
+		errno = EINVAL;
+		return NULL;
+	}
+	
+	std::string dirName(name);
 
-		//append a '\' win32 findfirst is sensitive to this
-		if ( dirName[dirName.size()] != '\\' || dirName[dirName.size()] != '/' )
-		{
-			dirName += '\\';
-		}
+	//append a '\' win32 findfirst is sensitive to this
+	if ( dirName[dirName.size()] != '\\' || dirName[dirName.size()] != '/' )
+	{
+		dirName += '\\';
+	}
 
-		//what is the search string? - everything
-		dirName += '*';
+	// what is the search string? - everything
+	dirName += '*';
 
-		if(name && name[0])
-		{
-			if ( ( dir = new DIR ) != 0 )
-			{
-				//mbstowcs(dir->name, dirName.c_str(),100);
-				//wcscpy((wchar_t*)dir->name, (const wchar_t*)dirName.c_str());
-				//mbstowcs(dir->name, dirName.c_str(), dirName.size()+1);
-				//wchar_t *buffer;
+	DIR *pDir = new DIR;
+	if (pDir == NULL)
+	{
+		errno = ENOMEM;
+		return NULL;
+	}
 
-				int strlen = MultiByteToWideChar(
-					CP_UTF8,               // code page
-					0,                     // character-type options
-					dirName.c_str(),       // string to map
-					(int)dirName.length(), // number of bytes in string
-					NULL,                  // wide-character buffer
-					0                      // size of buffer - work out how much space we need
-					);
+	pDir->name = ConvertUtf8ToMultiByte(dirName.c_str());
+	// We are responsible for freeing dir->name
+	
+	if (pDir->name == NULL)
+	{
+		delete pDir;
+		return NULL;
+	}
 
-				dir->name = new wchar_t[strlen+1];
+	pDir->fd = _wfindfirst((const wchar_t*)pDir->name, &(pDir->info));
 
-				if (dir->name == NULL)
-				{
-					delete dir;
-					dir   = 0;
-					errno = ENOMEM;
-					return NULL;
-				}
-
-				strlen = MultiByteToWideChar(
-					CP_UTF8,               // code page
-					0,                     // character-type options
-					dirName.c_str(),        // string to map
-					(int)dirName.length(),       // number of bytes in string
-					dir->name,                // wide-character buffer
-					strlen                 // size of buffer
-					);
-
-				if (strlen == 0)
-				{
-					delete dir->name;
-					delete dir;
-					dir   = 0;
-					errno = ENOMEM;
-					return NULL;
-				}
-
-				dir->name[strlen] = L'\0';
-
-				
-				dir->fd = _wfindfirst(
-					(const wchar_t*)dir->name,
-					&dir->info);
-
-				if (dir->fd != -1)
-				{
-					dir->result.d_name = 0;
-				}
-				else // go back
-				{
-					delete [] dir->name;
-					delete dir;
-					dir = 0;
-				}
-			}
-			else // backwards again
-			{
-				delete dir;
-				dir   = 0;
-				errno = ENOMEM;
-			}
-		}
-		else
-		{
-			errno = EINVAL;
-		}
-
-		return dir;
-
-	}
-	catch(...)
+	if (pDir->fd == -1)
 	{
-		printf("Caught opendir");
+		delete [] pDir->name;
+		delete pDir;
+		return NULL;
 	}
-
-	return NULL;
+		
+	pDir->result.d_name = 0;
+	return pDir;
 }
 
 // this kinda makes it not thread friendly!
@@ -915,19 +856,18 @@
 		break;
 	}
 
-
-	//taken from MSDN
+	// taken from MSDN
 	int sixfourpos;
 	while ( (sixfourpos = (int)sixfour.find("%ll")) != -1 )
 	{
-		//maintain portability - change the 64 bit formater...
+		// maintain portability - change the 64 bit formater...
 		std::string temp = sixfour.substr(0,sixfourpos);
 		temp += "%I64";
 		temp += sixfour.substr(sixfourpos+3, sixfour.length());
 		sixfour = temp;
 	}
 
-	//printf("parsed string is:%s\r\n", sixfour.c_str());
+	// printf("parsed string is:%s\r\n", sixfour.c_str());
 
 	va_list args;
 	va_start(args, frmt);
@@ -939,16 +879,16 @@
 
 	LPCSTR strings[] = { buffer, NULL };
 
-	if (!ReportEvent(gSyslogH,    // event log handle 
-		errinfo,              // event type 
-		0,                    // category zero 
-		MSG_ERR_EXIST,	      // event identifier - 
-		                      // we will call them all the same
-		NULL,                 // no user security identifier 
-		1,                    // one substitution string 
-		0,                    // no data 
-		strings,     // pointer to string array 
-		NULL))                // pointer to data 
+	if (!ReportEvent(gSyslogH, // event log handle 
+		errinfo,               // event type 
+		0,                     // category zero 
+		MSG_ERR_EXIST,	       // event identifier - 
+		                       // we will call them all the same
+		NULL,                  // no user security identifier 
+		1,                     // one substitution string 
+		0,                     // no data 
+		strings,               // pointer to string array 
+		NULL))                 // pointer to data 
 
 	{
 		DWORD err = GetLastError();

Modified: box/chris/win32/vc2005-compile-fixes/lib/win32/emu.h
===================================================================
--- box/chris/win32/vc2005-compile-fixes/lib/win32/emu.h	2006-02-04 15:42:05 UTC (rev 380)
+++ box/chris/win32/vc2005-compile-fixes/lib/win32/emu.h	2006-02-04 19:51:22 UTC (rev 381)
@@ -428,6 +428,10 @@
 int poll (struct pollfd *ufds, unsigned long nfds, int timeout);
 bool EnableBackupRights( void );
 
+// caller must free the returned buffer from ConvertUtf8ToMultiByte()
+// with delete[]
+WCHAR* ConvertUtf8ToMultiByte(const char* pName);
+
 //
 // MessageId: MSG_ERR_EXIST
 // MessageText: