1 /*
2    Bacula® - The Network Backup Solution
3 
4    Copyright (C) 2004-2009 Free Software Foundation Europe e.V.
5 
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 //                              -*- Mode: C++ -*-
29 // compat.cpp -- compatibilty layer to make bacula-fd run
30 //               natively under windows
31 //
32 // Copyright transferred from Raider Solutions, Inc to
33 //   Kern Sibbald and John Walker by express permission.
34 //
35 // Author          : Christopher S. Hull
36 // Created On      : Sat Jan 31 15:55:00 2004
37 
38 #include "burp.h"
39 #include "compat.h"
40 #include "sys/time.h"
41 #include "mem_pool.h"
42 #include "berrno.h"
43 
44 /* UTF-8 to UCS2 path conversion is expensive,
45    so we cache the conversion. During backup the
46    conversion is called 3 times (lstat, attribs, open),
47    by using the cache this is reduced to 1 time */
48 
49 static char *g_pWin32ConvUTF8Cache = NULL;
50 static char *g_pWin32ConvUCS2Cache = NULL;
51 static DWORD g_dwWin32ConvUTF8strlen = 0;
52 
53 static t_pVSSPathConvert g_pVSSPathConvert;
54 static t_pVSSPathConvertW g_pVSSPathConvertW;
55 
56 // Forward referenced functions.
57 static const char *errorString(void);
58 
SetVSSPathConvert(t_pVSSPathConvert pPathConvert,t_pVSSPathConvertW pPathConvertW)59 void SetVSSPathConvert(t_pVSSPathConvert pPathConvert,
60 	t_pVSSPathConvertW pPathConvertW)
61 {
62 	g_pVSSPathConvert = pPathConvert;
63 	g_pVSSPathConvertW = pPathConvertW;
64 }
65 
Win32ConvInitCache(void)66 static void Win32ConvInitCache(void)
67 {
68 	if(g_pWin32ConvUTF8Cache) return;
69 	g_pWin32ConvUTF8Cache=sm_get_pool_memory();
70 	g_pWin32ConvUCS2Cache=sm_get_pool_memory();
71 }
72 
Win32ConvCleanupCache(void)73 void Win32ConvCleanupCache(void)
74 {
75 	if(g_pWin32ConvUTF8Cache)
76 	{
77 		sm_free_pool_memory(g_pWin32ConvUTF8Cache);
78 		g_pWin32ConvUTF8Cache=NULL;
79 	}
80 
81 	if(g_pWin32ConvUCS2Cache)
82 	{
83 		sm_free_pool_memory(g_pWin32ConvUCS2Cache);
84 		g_pWin32ConvUCS2Cache=NULL;
85 	}
86 
87 	g_dwWin32ConvUTF8strlen=0;
88 }
89 
90 //#define USE_WIN32_COMPAT_IO 1
91 #define USE_WIN32_32KPATHCONVERSION 1
92 
93 extern DWORD g_platform_id;
94 extern DWORD g_MinorVersion;
95 
96 // From MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970.
97 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
98 
99 #define WIN32_FILETIME_SCALE 10000000 // 100ns/second
100 
conv_unix_to_win32_path(const char * name,char * win32_name,DWORD dwSize)101 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
102 {
103 	char *tname=win32_name;
104 	const char *fname=name;
105 
106 	if(IsPathSeparator(name[0])
107 	  && IsPathSeparator(name[1])
108 	  && name[2]=='.'
109 	  && IsPathSeparator(name[3]))
110 	{
111 		*win32_name++='\\';
112 		*win32_name++='\\';
113 		*win32_name++='.';
114 		*win32_name++='\\';
115 		name+=4;
116 	}
117 	else if(g_platform_id!=VER_PLATFORM_WIN32_WINDOWS
118 	  && !g_pVSSPathConvert)
119 	{
120 		// Allow path to be 32767 bytes.
121 		*win32_name++='\\';
122 		*win32_name++='\\';
123 		*win32_name++='?';
124 		*win32_name++='\\';
125 	}
126 
127 	while(*name)
128 	{
129 		// Check for Unix separator and convert to Win32.
130 		if(name[0]=='/' && name[1]=='/')
131 			name++;
132 		if(*name=='/')
133 			*win32_name++='\\';
134 		else if(*name=='\\'&& name[1]=='\\')
135 		{
136 			*win32_name++='\\';
137 			name++;
138 		}
139 		else
140 			*win32_name++=*name;
141 		name++;
142 	}
143 
144 	// Strip any trailing slash, if we stored something.
145 	// But leave "c:\" with backslash (root directory case).
146 	if(*fname && win32_name[-1]=='\\' && strlen(fname)!=3)
147 		win32_name[-1]=0;
148 	else
149 		*win32_name=0;
150 
151 	/* Here we convert to VSS specific file name which
152 	   can get longer because VSS will make something like
153 	   \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\burp\\x.exe
154 	   from c:\burp\x.exe
155 	 */
156 	if(g_pVSSPathConvert)
157 	{
158 		char *pszBuf=sm_get_pool_memory();
159 		pszBuf=sm_check_pool_memory_size(pszBuf, dwSize);
160 		snprintf(pszBuf, strlen(tname)+1, "%s", tname);
161 		g_pVSSPathConvert(pszBuf, tname, dwSize);
162 		sm_free_pool_memory(pszBuf);
163 	}
164 }
165 
166 // Conversion of a Unix filename to a Win32 filename.
unix_name_to_win32(char * name)167 char *unix_name_to_win32(char *name)
168 {
169 	char *ret=NULL;
170 	char *tmp=NULL;
171 
172 	// One extra byte should suffice, but we double it.
173 	// Add MAX_PATH bytes for VSS shadow copy name.
174 	DWORD dwSize=2*strlen(name)+MAX_PATH;
175 	tmp=sm_get_pool_memory();
176 	tmp=sm_check_pool_memory_size(tmp, dwSize);
177 	conv_unix_to_win32_path(name, tmp, dwSize);
178 	if(tmp) ret=strdup(tmp);
179 	sm_free_pool_memory(tmp);
180 	return ret;
181 }
182 
183 /* Created 02/27/2006 Thorsten Engel.
184    This function expects an UCS-encoded standard wchar_t in pszUCSPath and
185    will complete the input path to an absolue path of the form \\?\c:\path\file
186 
187    With this trick, it is possible to have 32K characters long paths.
188 
189    Optionally one can use pBIsRawPath to determine id pszUCSPath contains a
190    path to a raw windows partition. */
make_wchar_win32_path(char * pszUCSPath,BOOL * pBIsRawPath)191 char *make_wchar_win32_path(char *pszUCSPath, BOOL *pBIsRawPath)
192 {
193 	if(pBIsRawPath) *pBIsRawPath=FALSE;
194 
195 	if(!p_GetCurrentDirectoryW) return pszUCSPath;
196 
197 	wchar_t *name=(wchar_t *)pszUCSPath;
198 
199 	// If it has already the desired form, exit without changes.
200 	if(wcslen(name)>3 && !wcsncmp(name, L"\\\\?\\", 4))
201 		return pszUCSPath;
202 
203 	wchar_t *pwszBuf=(wchar_t *)sm_get_pool_memory();
204 	wchar_t *pwszCurDirBuf=(wchar_t *)sm_get_pool_memory();
205 	DWORD dwCurDirPathSize=0;
206 
207 	// Get buffer with enough size (name+max 6. wchars+1 null terminator.
208 	DWORD dwBufCharsNeeded=(wcslen(name)+7);
209 	pwszBuf=(wchar_t *)sm_check_pool_memory_size((char *)pwszBuf,
210 		dwBufCharsNeeded*sizeof(wchar_t));
211 
212 	/* Add \\?\ to support 32K long filepaths.
213 	   It is important to make absolute paths, so we add drive and
214 	   current path if necessary. */
215 
216 	BOOL bAddDrive=TRUE;
217 	BOOL bAddCurrentPath=TRUE;
218 	BOOL bAddPrefix=TRUE;
219 
220 	// Does path begin with drive? if yes, it is absolute.
221 	if(iswalpha(name[0]) && name[1]==':' && IsPathSeparator(name[2]))
222 	{
223 		bAddDrive=FALSE;
224 		bAddCurrentPath=FALSE;
225 	}
226 
227 	// Is path absolute?
228 	if(IsPathSeparator(name[0])) bAddCurrentPath=FALSE;
229 
230 	// Skip ./ if path is relative to itself?
231 	if(name[0]=='.' && IsPathSeparator(name[1])) name+=2;
232 
233 	// Is path of form '//./'?
234 	if(IsPathSeparator(name[0])
235 	  && IsPathSeparator(name[1])
236 	  && name[2]=='.'
237 	  && IsPathSeparator(name[3]))
238 	{
239 		bAddDrive=FALSE;
240 		bAddCurrentPath=FALSE;
241 		bAddPrefix=FALSE;
242 		if(pBIsRawPath) *pBIsRawPath=TRUE;
243 	}
244 
245 	int nParseOffset=0;
246 
247 	// add 4 bytes header.
248 	if(bAddPrefix)
249 	{
250 		nParseOffset=4;
251 		wcscpy(pwszBuf, L"\\\\?\\");
252 	}
253 
254 	// Get current path if needed.
255 	if(bAddDrive || bAddCurrentPath)
256 	{
257 		dwCurDirPathSize=p_GetCurrentDirectoryW(0, NULL);
258 		if(dwCurDirPathSize>0)
259 		{
260 			/* Get directory into own buffer as it may either
261 			   return c:\... or \\?\C:\.... */
262 			pwszCurDirBuf=(wchar_t *)sm_check_pool_memory_size(
263 				(char *)pwszCurDirBuf,
264 				(dwCurDirPathSize+1)*sizeof(wchar_t));
265 			p_GetCurrentDirectoryW(dwCurDirPathSize,
266 				pwszCurDirBuf);
267 		}
268 		else
269 		{
270 			// We have no info for doing so.
271 			bAddDrive=FALSE;
272 			bAddCurrentPath=FALSE;
273 		}
274 	}
275 
276 	// Add drive if needed.
277 	if(bAddDrive && !bAddCurrentPath)
278 	{
279 		wchar_t szDrive[3];
280 
281 		if(IsPathSeparator(pwszCurDirBuf[0])
282 		  && IsPathSeparator(pwszCurDirBuf[1])
283 		  && pwszCurDirBuf[2]=='?'
284 		  && IsPathSeparator(pwszCurDirBuf[3]))
285 			szDrive[0]=pwszCurDirBuf[4];
286 		else
287 			szDrive[0]=pwszCurDirBuf[0];
288 
289 		szDrive[1]=':';
290 		szDrive[2]=0;
291 
292 		wcscat(pwszBuf, szDrive);
293 		nParseOffset+=2;
294 	}
295 
296 	// Add path if needed.
297 	if(bAddCurrentPath)
298 	{
299 		// The 1 add. character is for the eventually added backslash.
300 		dwBufCharsNeeded+=dwCurDirPathSize+1;
301 		pwszBuf=(wchar_t *)sm_check_pool_memory_size((char *)pwszBuf,
302 			dwBufCharsNeeded*sizeof(wchar_t));
303 		/* get directory into own buffer as it may either
304 		   return c:\... or \\?\C:\.... */
305 
306 		if(IsPathSeparator(pwszCurDirBuf[0])
307 		  && IsPathSeparator(pwszCurDirBuf[1])
308 		  && pwszCurDirBuf[2]=='?'
309 		  && IsPathSeparator(pwszCurDirBuf[3]))
310 			wcscpy(pwszBuf, pwszCurDirBuf);
311 		else
312 			wcscat(pwszBuf, pwszCurDirBuf);
313 
314 		nParseOffset=wcslen((LPCWSTR) pwszBuf);
315 
316 		// check if path ends with backslash, if not, add one.
317 		if(!IsPathSeparator(pwszBuf[nParseOffset-1]))
318 		{
319 			wcscat(pwszBuf, L"\\");
320 			nParseOffset++;
321 		}
322 	}
323 
324 	wchar_t *win32_name=&pwszBuf[nParseOffset];
325 	wchar_t *name_start=name;
326 
327 	while(*name)
328 	{
329 		/* Check for Unix separator and convert to Win32, eliminating
330 		  duplicate separators.  */
331 		if(IsPathSeparator(*name))
332 		{
333 			*win32_name++ = '\\';
334 			/* Eliminate consecutive slashes, but not at the start
335 			   so that  \\.\ still works.  */
336 			if(name_start!=name && IsPathSeparator(name[1]))
337 				name++;
338 		}
339 		else
340 			*win32_name++=*name;
341 		name++;
342 	}
343 
344 	// Null terminate string.
345 	*win32_name=0;
346 
347 	/* here we convert to VSS specific file name which
348 	   can get longer because VSS will make something like
349 	   \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\burp\\x.exe
350 	   from c:\burp\x.exe */
351 	if(g_pVSSPathConvertW)
352 	{
353 		// Is output buffer large enough?
354 		pwszBuf=(wchar_t *)sm_check_pool_memory_size((char *)pwszBuf,
355 			(dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
356 		// Create temp. buffer.
357 		wchar_t *pszBuf=(wchar_t *)sm_get_pool_memory();
358 		pszBuf=(wchar_t *)sm_check_pool_memory_size((char *)pszBuf,
359 			(dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
360 		if(bAddPrefix) nParseOffset=4;
361 		else nParseOffset=0;
362 		wcsncpy(pszBuf, &pwszBuf[nParseOffset],
363 			wcslen(pwszBuf)+1-nParseOffset);
364 		g_pVSSPathConvertW(pszBuf, pwszBuf, dwBufCharsNeeded+MAX_PATH);
365 		sm_free_pool_memory((char *)pszBuf);
366 	}
367 
368 	sm_free_pool_memory(pszUCSPath);
369 	sm_free_pool_memory((char *)pwszCurDirBuf);
370 
371 	return (char *)pwszBuf;
372 }
373 
374 /* The return value is the number of bytes written to the buffer.
375    The number includes the byte for the null terminator. */
wchar_2_UTF8(char * pszUTF,const wchar_t * pszUCS,int cchChar)376 int wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
377 {
378 	int ret=0;
379 	ret=p_WideCharToMultiByte(CP_UTF8,
380 		0, pszUCS, -1, pszUTF, cchChar, NULL, NULL);
381 	ASSERT(ret>0);
382 	return ret;
383 }
384 
385 /* The return value is the number of wide characters written to the buffer.
386    Convert null terminated string from utf-8 to ucs2, enlarge buffer if
387    necessary. */
UTF8_2_wchar(char ** ppszUCS,const char * pszUTF)388 int UTF8_2_wchar(char **ppszUCS, const char *pszUTF)
389 {
390 	int ret=0;
391 	DWORD cchSize;
392 	if(!p_MultiByteToWideChar) return ret;
393 
394 	// strlen of UTF8 +1 is enough.
395 	cchSize=strlen(pszUTF)+1;
396 	*ppszUCS=sm_check_pool_memory_size(*ppszUCS, cchSize*sizeof(wchar_t));
397 	ret=p_MultiByteToWideChar(CP_UTF8,
398 		0, pszUTF, -1, (LPWSTR)*ppszUCS, cchSize);
399 
400 	ASSERT(ret>0);
401 	return ret;
402 }
403 
wchar_win32_path(const char * name,wchar_t * win32_name)404 void wchar_win32_path(const char *name, wchar_t *win32_name)
405 {
406 	const char *fname=name;
407 	while(*name)
408 	{
409 		// Check for Unix separator and convert to Win32.
410 		if(*name=='/')
411 			*win32_name++='\\';
412 		else if(*name=='\\' && name[1]=='\\')
413 		{
414 			*win32_name++='\\';
415 			name++;
416 		}
417 		else
418 			*win32_name++=*name;
419 		name++;
420 	}
421 	// Strip any trailing slash, if we stored something.
422 	if(*fname && win32_name[-1]=='\\')
423 		win32_name[-1]=0;
424 	else
425 		*win32_name=0;
426 }
427 
428 // Allows one or both pointers to be NULL
bstrcmp(const char * s1,const char * s2)429 static bool bstrcmp(const char *s1, const char *s2)
430 {
431 	if(s1 == s2) return true;
432 	if(!s1 || !s2) return false;
433 	return !strcmp(s1, s2);
434 }
435 
436 /* If we find the utf8 string in cache, we use the cached ucs2 version.
437    We compare the stringlength first (quick check) and then compare the
438    content.            */
make_win32_path_UTF8_2_wchar(char ** pszUCS,const char * pszUTF,BOOL * pBIsRawPath)439 int make_win32_path_UTF8_2_wchar(
440 	char **pszUCS,
441 	const char *pszUTF,
442 	BOOL *pBIsRawPath
443 ) {
444 	if(!g_pWin32ConvUTF8Cache)
445 		Win32ConvInitCache();
446 	else if(g_dwWin32ConvUTF8strlen==strlen(pszUTF))
447 	{
448 		if(bstrcmp(pszUTF, g_pWin32ConvUTF8Cache))
449 		{
450 			// Return cached value.
451 			int32_t nBufSize=sm_sizeof_pool_memory(
452 				g_pWin32ConvUCS2Cache);
453 			*pszUCS=sm_check_pool_memory_size(*pszUCS, nBufSize);
454 			wcscpy((LPWSTR)*pszUCS, (LPWSTR)g_pWin32ConvUCS2Cache);
455 			return nBufSize/sizeof(WCHAR);
456 		}
457 	}
458 
459 	/* Helper to convert from utf-8 to UCS-2 and to complete a path for 32K
460 	   path syntax */
461 	int nRet=UTF8_2_wchar(pszUCS, pszUTF);
462 
463 #ifdef USE_WIN32_32KPATHCONVERSION
464 	// Add \\?\ to support 32K long filepaths.
465 	*pszUCS=make_wchar_win32_path(*pszUCS, pBIsRawPath);
466 #else
467 	if(pBIsRawPath) *pBIsRawPath=FALSE;
468 #endif
469 
470 	// Populate cache.
471 	g_pWin32ConvUCS2Cache=sm_check_pool_memory_size(g_pWin32ConvUCS2Cache,
472 		sm_sizeof_pool_memory(*pszUCS));
473 	wcscpy((LPWSTR)g_pWin32ConvUCS2Cache, (LPWSTR)*pszUCS);
474 
475 	g_dwWin32ConvUTF8strlen=strlen(pszUTF);
476 	g_pWin32ConvUTF8Cache=sm_check_pool_memory_size(g_pWin32ConvUTF8Cache,
477 		g_dwWin32ConvUTF8strlen+2);
478 	snprintf(g_pWin32ConvUTF8Cache,
479 		g_dwWin32ConvUTF8strlen+1, "%s", pszUTF);
480 
481 	return nRet;
482 }
483 
make_win32_path_UTF8_2_wchar_w(const char * pszUTF)484 char *make_win32_path_UTF8_2_wchar_w(const char *pszUTF)
485 {
486 	int size=0;
487 	char *ret=NULL;
488 	char *tmp=sm_get_pool_memory();
489 
490 	size=make_win32_path_UTF8_2_wchar(&tmp, pszUTF);
491 	if(size>0)
492 	{
493 		ret=(char *)malloc(2*strlen(pszUTF)+MAX_PATH);
494 		wcscpy((LPWSTR)ret, (LPWSTR)tmp);
495 	}
496 	sm_free_pool_memory(tmp);
497 	return ret;
498 }
499 
500 #if !defined(_MSC_VER) || (_MSC_VER < 1400) // VC8+
umask(int)501 int umask(int)
502 {
503 	return 0;
504 }
505 #endif
506 
507 #ifndef LOAD_WITH_ALTERED_SEARCH_PATH
508 #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
509 #endif
510 
dlopen(const char * file,int mode)511 void *dlopen(const char *file, int mode)
512 {
513 	void *handle;
514 	handle=LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
515 	return handle;
516 }
517 
dlsym(void * handle,const char * name)518 void *dlsym(void *handle, const char *name)
519 {
520 	void *symaddr;
521 	symaddr=(void *)GetProcAddress((HMODULE)handle, name);
522 	return symaddr;
523 }
524 
dlclose(void * handle)525 int dlclose(void *handle)
526 {
527 	if(handle && !FreeLibrary((HMODULE)handle))
528 	{
529 		errno=b_errno_win32;
530 		return 1; // Failed.
531 	}
532 	return 0;
533 }
534 
dlerror(void)535 char *dlerror(void)
536 {
537 	static char buf[200];
538 	const char *err=errorString();
539 	snprintf(buf, sizeof(buf), "%s", (char *)err);
540 	LocalFree((void *)err);
541 	return buf;
542 }
543 
fcntl(int fd,int cmd)544 int fcntl(int fd, int cmd)
545 {
546 	return 0;
547 }
548 
chown(const char * k,uid_t,gid_t)549 int chown(const char *k, uid_t, gid_t)
550 {
551 	return 0;
552 }
553 
lchown(const char * k,uid_t,gid_t)554 int lchown(const char *k, uid_t, gid_t)
555 {
556 	return 0;
557 }
558 
random(void)559 long int random(void)
560 {
561 	return rand();
562 }
563 
srandom(unsigned int seed)564 void srandom(unsigned int seed)
565 {
566 	srand(seed);
567 }
568 
569 // Convert from Windows concept of time to Unix concept of time.
cvt_utime_to_ftime(const time_t & time,FILETIME & wintime)570 void cvt_utime_to_ftime(const time_t &time, FILETIME &wintime)
571 {
572 	uint64_t mstime=time;
573 	mstime*=WIN32_FILETIME_SCALE;
574 	mstime+=WIN32_FILETIME_ADJUST;
575 
576 #if defined(_MSC_VER)
577 	wintime.dwLowDateTime=(DWORD)(mstime & 0xffffffffI64);
578 #else
579 	wintime.dwLowDateTime=(DWORD)(mstime & 0xffffffffUL);
580 #endif
581 	wintime.dwHighDateTime=(DWORD)((mstime>>32)& 0xffffffffUL);
582 }
583 
cvt_ftime_to_utime(const FILETIME & time)584 time_t cvt_ftime_to_utime(const FILETIME &time)
585 {
586 	uint64_t mstime=time.dwHighDateTime;
587 	mstime<<=32;
588 	mstime|=time.dwLowDateTime;
589 
590 	mstime-=WIN32_FILETIME_ADJUST;
591 	mstime/=WIN32_FILETIME_SCALE; // convert to seconds.
592 
593 	return (time_t)(mstime & 0xffffffff);
594 }
595 
errorString(void)596 static const char *errorString(void)
597 {
598 	char *cp;
599 	char *rval;
600 	LPVOID lpMsgBuf;
601 
602 	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
603 		| FORMAT_MESSAGE_FROM_SYSTEM
604 		| FORMAT_MESSAGE_IGNORE_INSERTS,
605 		NULL,
606 		GetLastError(),
607 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
608 		(LPTSTR)&lpMsgBuf,
609 		0,
610 		NULL);
611 
612 	// Strip any \r or \n.
613 	rval=(char *)lpMsgBuf;
614 	if((cp=strchr(rval, '\r'))) *cp=0;
615 	else if((cp=strchr(rval, '\n'))) *cp=0;
616 	return rval;
617 }
618 
619 // Explicitly open the file to read the reparse point, then call
620 // DeviceIoControl to find out if it points to a volume or to a directory.
reparse_or_mount_song_and_dance(const char * file,struct stat * sb,DWORD reparse_tag)621 static void reparse_or_mount_song_and_dance(
622 	const char *file,
623 	struct stat *sb,
624 	DWORD reparse_tag
625 ) {
626 	char dummy[1000]="";
627 	char *utf8=NULL;
628 	char *pwszBuf=NULL;
629 	REPARSE_DATA_BUFFER *rdb=NULL;
630 	HANDLE h=INVALID_HANDLE_VALUE;
631 	DWORD bytes;
632 
633 	sb->st_rdev=WIN32_MOUNT_POINT;
634 
635 	pwszBuf=sm_get_pool_memory();
636 	make_win32_path_UTF8_2_wchar(&pwszBuf, file);
637 	rdb=(REPARSE_DATA_BUFFER *)dummy;
638 
639 	h=CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ,
640 		FILE_SHARE_READ, NULL, OPEN_EXISTING,
641 		FILE_FLAG_BACKUP_SEMANTICS
642 		| FILE_FLAG_OPEN_REPARSE_POINT,
643 		NULL);
644 	sm_free_pool_memory(pwszBuf);
645 
646 	if(h==INVALID_HANDLE_VALUE)
647 		return;
648 	rdb->ReparseTag=reparse_tag;
649 	if(!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT,
650 		NULL, 0, // in buffer, bytes
651 		(LPVOID)rdb,
652 		(DWORD)sizeof(dummy), // out buffer, btyes
653 		(LPDWORD)&bytes, (LPOVERLAPPED)0))
654 			return;
655 
656 	utf8=sm_get_pool_memory();
657 
658 	wchar_2_UTF8(utf8,
659 		(wchar_t *)rdb->SymbolicLinkReparseBuffer.PathBuffer);
660 	if(!strncasecmp(utf8, "\\??\\volume{", 11))
661 		sb->st_rdev=WIN32_MOUNT_POINT;
662 	else // Points to a directory so we ignore it.
663 		sb->st_rdev=WIN32_JUNCTION_POINT;
664 	sm_free_pool_memory(utf8);
665 
666 	CloseHandle(h);
667 }
668 
statDir(const char * file,struct stat * sb,uint64_t * winattr)669 static int statDir(const char *file, struct stat *sb, uint64_t *winattr)
670 {
671 	WIN32_FIND_DATAW info_w; // window's file info
672 
673 	// cache some common vars to make code more transparent
674 	DWORD *pdwFileAttributes;
675 	DWORD *pnFileSizeHigh;
676 	DWORD *pnFileSizeLow;
677 	DWORD *pdwReserved0;
678 	FILETIME *pftLastAccessTime;
679 	FILETIME *pftLastWriteTime;
680 	FILETIME *pftCreationTime;
681 
682 	/* Oh, cool, another exception: Microsoft doesn't let us do
683 	   FindFile operations on a Drive, so simply fake root attibutes. */
684 	if(file[1]==':' && !file[2])
685 	{
686 		time_t now=time(NULL);
687 		sb->st_mode=S_IFDIR;
688 		sb->st_mode|=S_IREAD|S_IEXEC|S_IWRITE;
689 		sb->st_ctime=now;
690 		sb->st_mtime=now;
691 		sb->st_atime=now;
692 		sb->st_rdev=0;
693 		return 0;
694 	}
695 
696 	HANDLE h=INVALID_HANDLE_VALUE;
697 
698 	// use unicode
699 	if(p_FindFirstFileW)
700 	{
701 		char *pwszBuf=sm_get_pool_memory();
702 		make_win32_path_UTF8_2_wchar(&pwszBuf, file);
703 
704 		h=p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w);
705 		sm_free_pool_memory(pwszBuf);
706 
707 		pdwFileAttributes=&info_w.dwFileAttributes;
708 		pdwReserved0     =&info_w.dwReserved0;
709 		pnFileSizeHigh   =&info_w.nFileSizeHigh;
710 		pnFileSizeLow    =&info_w.nFileSizeLow;
711 		pftLastAccessTime=&info_w.ftLastAccessTime;
712 		pftLastWriteTime =&info_w.ftLastWriteTime;
713 		pftCreationTime  =&info_w.ftCreationTime;
714 		// use ASCII
715 	}
716 
717 	if(h==INVALID_HANDLE_VALUE)
718 	{
719 		const char *err = errorString();
720 		/* Note, in creating leading paths, it is normal that
721 		   the file does not exist. */
722 		LocalFree((void *)err);
723 		errno=b_errno_win32;
724 		return -1;
725 	}
726 	else
727 		FindClose(h);
728 
729 	*winattr=(int64_t)*pdwFileAttributes;
730 
731 	/* Graham says: all the following stuff seems rather complicated.
732 	   It is probably not all needed anymore, since I have added *winattr
733 	   above, which bacula did not do.
734 	   One reason for keeping it is that some of the values get converted
735 	   to unix-style permissions that show up in the long list
736 	   functionality.
737 	   I think I would prefer to remove it all at some point. */
738 
739 	sb->st_mode = 0777;  // start with everything
740 	if(*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
741 		sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
742 	if(*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
743 		sb->st_mode &= ~S_IRWXO; // remove everything for other
744 	if(*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
745 		sb->st_mode |= S_ISVTX; // use sticky bit -> hidden
746 	sb->st_mode |= S_IFDIR;
747 
748 	/* Store reparse/mount point info in st_rdev.  Note a
749 	   Win32 reparse point (junction point) is like a link
750 	   though it can have many properties (directory link,
751 	   soft link, hard link, HSM, ...
752 	   A mount point is a reparse point where another volume
753 	   is mounted, so it is like a Unix mount point (change of
754 	   filesystem).  */
755 	sb->st_rdev=0;
756 	if(*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
757 		reparse_or_mount_song_and_dance(file, sb, *pdwReserved0);
758 
759 	sb->st_size=*pnFileSizeHigh;
760 	sb->st_size<<=32;
761 	sb->st_size|=*pnFileSizeLow;
762 	sb->st_blksize=4096;
763 	sb->st_blocks=(uint32_t)(sb->st_size+4095)/4096;
764 
765 	sb->st_atime=cvt_ftime_to_utime(*pftLastAccessTime);
766 	sb->st_mtime=cvt_ftime_to_utime(*pftLastWriteTime);
767 	sb->st_ctime=cvt_ftime_to_utime(*pftCreationTime);
768 
769 	return 0;
770 }
771 
do_fstat(intptr_t fd,struct stat * sb,uint64_t * winattr)772 static int do_fstat(intptr_t fd, struct stat *sb, uint64_t *winattr)
773 {
774 	BY_HANDLE_FILE_INFORMATION info;
775 
776 	if(!GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info))
777 	{
778 		const char *err=errorString();
779 		LocalFree((void *)err);
780 		errno=b_errno_win32;
781 		return -1;
782 	}
783 
784 	sb->st_dev=info.dwVolumeSerialNumber;
785 	sb->st_ino=info.nFileIndexHigh;
786 	sb->st_ino<<=32;
787 	sb->st_ino|=info.nFileIndexLow;
788 	sb->st_nlink=(short)info.nNumberOfLinks;
789 	*winattr=(int64_t)info.dwFileAttributes;
790 
791 	/* Graham says: all the following stuff seems rather complicated.
792 	   It is probably not all needed anymore, since I have added *winattr
793 	   above, which bacula did not do.
794 	   One reason for keeping it is that some of the values get converted
795 	   to unix-style permissions that show up in the long list
796 	   functionality.
797 	   I think I would prefer to remove it all though.  */
798 	sb->st_mode = 0777; // Start with everything.
799 	if(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
800 		sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
801 	if(info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
802 		sb->st_mode &= ~S_IRWXO; // Remove everything for other.
803 	if(info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
804 		sb->st_mode |= S_ISVTX; // Use sticky bit -> hidden.
805 	sb->st_mode |= S_IFREG;
806 
807 	// Use st_rdev to store reparse attribute.
808 	if(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
809 		sb->st_rdev=WIN32_REPARSE_POINT;
810 
811 	sb->st_size=info.nFileSizeHigh;
812 	sb->st_size<<=32;
813 	sb->st_size|=info.nFileSizeLow;
814 	sb->st_blksize=4096;
815 	sb->st_blocks=(uint32_t)(sb->st_size + 4095)/4096;
816 	sb->st_atime=cvt_ftime_to_utime(info.ftLastAccessTime);
817 	sb->st_mtime=cvt_ftime_to_utime(info.ftLastWriteTime);
818 	sb->st_ctime=cvt_ftime_to_utime(info.ftCreationTime);
819 
820 	return 0;
821 }
822 
fstat(intptr_t fd,struct stat * sb)823 int fstat(intptr_t fd, struct stat *sb)
824 {
825 	uint64_t winattr=0;
826 	return do_fstat(fd, sb, &winattr);
827 }
828 
829 static char tmpbuf[_MAX_PATH]="";
830 
stat2(const char * file,struct stat * sb,uint64_t * winattr)831 static int stat2(const char *file, struct stat *sb, uint64_t *winattr)
832 {
833 	HANDLE h=INVALID_HANDLE_VALUE;
834 	int rval=0;
835 	conv_unix_to_win32_path(file, tmpbuf, _MAX_PATH);
836 
837 	DWORD attr=(DWORD)-1;
838 
839 	if(p_GetFileAttributesW)
840 	{
841 		char *pwszBuf=sm_get_pool_memory();
842 		make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
843 
844 		attr=p_GetFileAttributesW((LPCWSTR) pwszBuf);
845 		if(p_CreateFileW)
846 			h=CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ,
847 				FILE_SHARE_READ,
848 				NULL, OPEN_EXISTING, 0, NULL);
849 		sm_free_pool_memory(pwszBuf);
850 	}
851 
852 	if(attr==(DWORD)-1)
853 	{
854 		const char *err=errorString();
855 		LocalFree((void *)err);
856 		if(h!=INVALID_HANDLE_VALUE) CloseHandle(h);
857 		errno=b_errno_win32;
858 		return -1;
859 	}
860 
861 	if(h==INVALID_HANDLE_VALUE)
862 	{
863 		const char *err=errorString();
864 		LocalFree((void *)err);
865 		errno=b_errno_win32;
866 		return -1;
867 	}
868 
869 	rval=do_fstat((intptr_t)h, sb, winattr);
870 	CloseHandle(h);
871 
872 	if(attr & FILE_ATTRIBUTE_DIRECTORY && file[1]==':' && file[2])
873 		rval = statDir(file, sb, winattr);
874 
875 	return rval;
876 }
877 
do_stat(const char * file,struct stat * sb,uint64_t * winattr)878 static int do_stat(const char *file, struct stat *sb, uint64_t *winattr)
879 {
880 	WIN32_FILE_ATTRIBUTE_DATA data;
881 	errno=0;
882 
883 	memset(sb, 0, sizeof(*sb));
884 	memset(winattr, 0, sizeof(*winattr));
885 
886 	if(p_GetFileAttributesExW)
887 	{
888 		// Dynamically allocate enough space for UCS2 filename.
889 		char *pwszBuf=sm_get_pool_memory();
890 		make_win32_path_UTF8_2_wchar(&pwszBuf, file);
891 
892 		BOOL b=p_GetFileAttributesExW((LPCWSTR)pwszBuf,
893 			GetFileExInfoStandard, &data);
894 		sm_free_pool_memory(pwszBuf);
895 
896 		if(!b) return stat2(file, sb, winattr);
897 
898 	}
899 
900 	*winattr=(int64_t)data.dwFileAttributes;
901 
902 	/* Graham says: all the following stuff seems rather complicated.
903 	   It is probably not all needed anymore, since I have added *winattr
904 	   above, which bacula did not do.
905 	   One reason for keeping it is that some of the values get converted to
906 	   unix-style permissions that show up in the long list functionality.
907 	   I think I would prefer to remove it all though.
908 	 */
909 	sb->st_mode = 0777; // Start with everything.
910 	if(data.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
911 		sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
912 	if(data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
913 		sb->st_mode &= ~S_IRWXO; // Remove everything for other.
914 	if(data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
915 		sb->st_mode |= S_ISVTX; // use sticky bit -> hidden.
916 	if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
917 		sb->st_mode |= S_IFDIR;
918 	else
919 		sb->st_mode |= S_IFREG;
920 
921 	// Use st_rdev to store reparse attribute.
922 	sb->st_rdev=(data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)?1:0;
923 
924 	sb->st_nlink=1;
925 	sb->st_size=data.nFileSizeHigh;
926 	sb->st_size<<=32;
927 	sb->st_size|=data.nFileSizeLow;
928 	sb->st_blksize=4096;
929 	sb->st_blocks=(uint32_t)(sb->st_size + 4095)/4096;
930 	sb->st_atime=cvt_ftime_to_utime(data.ftLastAccessTime);
931 	sb->st_mtime=cvt_ftime_to_utime(data.ftLastWriteTime);
932 	sb->st_ctime=cvt_ftime_to_utime(data.ftCreationTime);
933 
934 	/* If we are not at the root, then to distinguish a reparse
935 	   point from a mount point, we must call FindFirstFile() to
936 	   get the WIN32_FIND_DATA, which has the bit that indicates
937 	   that this directory is a mount point -- aren't Win32 APIs
938 	   wonderful? (sarcasm).  The code exists in the statDir
939 	   subroutine.  */
940 	if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
941 	  && file[1]==':' && file[2])
942 		statDir(file, sb, winattr);
943 	return 0;
944 }
945 
946 /* We write our own ftruncate because the one in the
947    Microsoft library mrcrt.dll does not truncate
948    files greater than 2GB.
949    KES - May 2007 */
win32_ftruncate(int fd,int64_t length)950 int win32_ftruncate(int fd, int64_t length)
951 {
952 	// Set point we want to truncate file.
953 	__int64 pos=_lseeki64(fd, (__int64)length, SEEK_SET);
954 
955 	if(pos!=(__int64)length)
956 	{
957 		errno=EACCES;
958 		return -1;
959 	}
960 
961 	// Truncate file.
962 	if(!SetEndOfFile((HANDLE)_get_osfhandle(fd)))
963 	{
964 		errno=b_errno_win32;
965 		return -1;
966 	}
967 	errno=0;
968 	return 0;
969 }
970 
fcntl(int fd,int cmd,long arg)971 int fcntl(int fd, int cmd, long arg)
972 {
973 	int rval=0;
974 
975 	switch(cmd)
976 	{
977 		case F_GETFL:
978 			rval=O_NONBLOCK;
979 			break;
980 		case F_SETFL:
981 			break;
982 		default:
983 			errno=EINVAL;
984 			rval=-1;
985 			break;
986 	}
987 
988 	return rval;
989 }
990 
stat(const char * file,struct stat * sb)991 int stat(const char *file, struct stat *sb)
992 {
993 	uint64_t winattr=0;
994 	return do_stat(file, sb, &winattr);
995 }
996 
lstat(const char * file,struct stat * sb)997 int lstat(const char *file, struct stat *sb)
998 {
999 	uint64_t winattr=0;
1000 	return do_stat(file, sb, &winattr);
1001 }
1002 
win32_lstat(const char * file,struct stat * sb,uint64_t * winattr)1003 int win32_lstat(const char *file, struct stat *sb, uint64_t *winattr)
1004 {
1005 	return do_stat(file, sb, winattr);
1006 }
1007 
sleep(int sec)1008 void sleep(int sec)
1009 {
1010 	Sleep(sec*1000);
1011 }
1012 
geteuid(void)1013 int geteuid(void)
1014 {
1015 	return 0;
1016 }
1017 
system_error(void)1018 static int system_error(void)
1019 {
1020 	errno=ENOSYS;
1021 	return -1;
1022 }
1023 
execvp(const char *,char * [])1024 int execvp(const char *, char *[]) { return system_error(); }
fork(void)1025 int fork(void) { return system_error(); }
pipe(int[])1026 int pipe(int[]) { return system_error(); }
waitpid(int,int *,int)1027 int waitpid(int, int *, int) { return system_error(); }
readlink(const char *,char *,int)1028 int readlink(const char *, char *, int) { return system_error(); }
1029 
strncasecmp(const char * s1,const char * s2,int len)1030 int strncasecmp(const char *s1, const char *s2, int len)
1031 {
1032 	register int ch1=0;
1033 	register int ch2=0;
1034 
1035 	if(s1==s2)
1036 		return 0; // Strings are equal if same object.
1037 	else if(!s1)
1038 		return -1;
1039 	else if(!s2)
1040 		return 1;
1041 
1042 	while(len--)
1043 	{
1044 		ch1=*s1;
1045 		ch2=*s2;
1046 		s1++;
1047 		s2++;
1048 		if(!ch1 || tolower(ch1)!=tolower(ch2))
1049 			break;
1050 	}
1051 
1052 	return (ch1-ch2);
1053 }
1054 
gettimeofday(struct timeval * tv,struct timezone *)1055 int gettimeofday(struct timeval *tv, struct timezone *)
1056 {
1057 	SYSTEMTIME now;
1058 	FILETIME tmp;
1059 
1060 	GetSystemTime(&now);
1061 
1062 	if(!tv)
1063 	{
1064 		errno=EINVAL;
1065 		return -1;
1066 	}
1067 	if(!SystemTimeToFileTime(&now, &tmp))
1068 	{
1069 		errno=b_errno_win32;
1070 		return -1;
1071 	}
1072 
1073 	int64_t _100nsec=tmp.dwHighDateTime;
1074 	_100nsec<<=32;
1075 	_100nsec|=tmp.dwLowDateTime;
1076 	_100nsec-=WIN32_FILETIME_ADJUST;
1077 
1078 	tv->tv_sec=(long)(_100nsec / 10000000);
1079 	tv->tv_usec=(long)((_100nsec % 10000000)/10);
1080 	return 0;
1081 
1082 }
1083 
1084 // For apcupsd this is in src/lib/wincompat.c.
syslog(int type,const char * fmt,...)1085 extern "C" void syslog(int type, const char *fmt, ...)
1086 {
1087 }
1088 
closelog()1089 void closelog()
1090 {
1091 }
1092 
getpwuid(uid_t)1093 struct passwd *getpwuid(uid_t)
1094 {
1095 	return NULL;
1096 }
1097 
getgrgid(uid_t)1098 struct group * getgrgid(uid_t)
1099 {
1100 	return NULL;
1101 }
1102 
1103 // Implement opendir/readdir/closedir on top of window's API.
1104 
1105 typedef struct _dir
1106 {
1107 	WIN32_FIND_DATAA data_a; // Window's file info (ansii version).
1108 	WIN32_FIND_DATAW data_w; // Window's file info (wchar version).
1109 	const char *spec;        // The directory we're traversing.
1110 	HANDLE dirh;             // The search handle.
1111 	UINT32 offset;           // Pseudo offset for d_off.
1112 	struct dirent entry;
1113 } _dir;
1114 
_dir_free(_dir * d)1115 static void _dir_free(_dir *d)
1116 {
1117 	if(!d) return;
1118 	if(d->spec) free((void *)d->spec);
1119 	free((void *)d);
1120 }
1121 
opendir(const char * path)1122 DIR *opendir(const char *path)
1123 {
1124 	ssize_t len=0;
1125 	char *tspec=NULL;
1126 	_dir *rval=NULL;
1127 	int max_len;
1128 
1129 	max_len=strlen(path)+MAX_PATH; // Enough space for VSS!
1130 
1131 	if(!path)
1132 	{
1133 		errno=ENOENT;
1134 		goto err;
1135 	}
1136 
1137 	if(!(rval=(_dir *)calloc(1, sizeof(_dir)))
1138 	  || !(tspec=(char *)malloc(max_len)))
1139 	{
1140 		errno=b_errno_win32;
1141 		goto err;
1142 	}
1143 	rval->dirh=INVALID_HANDLE_VALUE;
1144 
1145 	conv_unix_to_win32_path(path, tspec, max_len);
1146 
1147 	len=strlen(tspec);
1148 	// Add backslash only if there is none yet (think of c:\).
1149 	if(tspec[len-1] != '\\' && len+1<max_len)
1150 	{
1151 		tspec[len++]='\\';
1152 		tspec[len]='\0';
1153 	}
1154 	if(len+1<max_len)
1155 	{
1156 		tspec[len++]='*';
1157 		tspec[len]='\0';
1158 	}
1159 
1160 	rval->spec=tspec;
1161 
1162 	return (DIR *)rval;
1163 err:
1164 	_dir_free(rval);
1165 	return NULL;
1166 }
1167 
closedir(DIR * dirp)1168 int closedir(DIR *dirp)
1169 {
1170 	if(!dirp) return 0;
1171 	_dir *dp=(_dir *)dirp;
1172 	FindClose(dp->dirh);
1173 	_dir_free(dp);
1174 	return 0;
1175 }
1176 
copyin(struct dirent * entry,const char * fname)1177 static void copyin(struct dirent *entry, const char *fname)
1178 {
1179 	char *cp=entry->d_name;
1180 	while( *fname && entry->d_reclen < (MAX_PATH_UTF8-1) )
1181 	{
1182 		*cp++=*fname++;
1183 		entry->d_reclen++;
1184 	}
1185 	*cp=0;
1186 }
1187 
readdir(DIR * dirp)1188 struct dirent *readdir(DIR *dirp)
1189 {
1190 	_dir *dp=(_dir *)dirp;
1191 	BOOL valid_a=FALSE;
1192 	BOOL valid_w=FALSE;
1193 
1194 	if(dp->dirh==INVALID_HANDLE_VALUE)
1195 	{
1196 		// First time through.
1197 
1198 		// Convert to wchar_t.
1199 		if(p_FindFirstFileW)
1200 		{
1201 			char *pwcBuf=sm_get_pool_memory();
1202 			make_win32_path_UTF8_2_wchar(&pwcBuf, dp->spec);
1203 
1204 			dp->dirh=p_FindFirstFileW((LPCWSTR)pwcBuf,
1205 				&dp->data_w);
1206 
1207 			sm_free_pool_memory(pwcBuf);
1208 
1209 			if(dp->dirh==INVALID_HANDLE_VALUE)
1210 				goto err;
1211 			valid_w=TRUE;
1212 		}
1213 		else
1214 			goto err;
1215 
1216 		dp->offset=0;
1217 	}
1218 	else
1219 	{
1220 		// Get next file, try unicode first.
1221 		if(p_FindNextFileW)
1222 			valid_w=p_FindNextFileW(dp->dirh, &dp->data_w);
1223 	}
1224 
1225 	dp->entry.d_ino=0;
1226 	dp->entry.d_reclen=0;
1227 	dp->entry.d_off=dp->offset;
1228 
1229 	if(valid_w)
1230 	{
1231 		// Copy unicode.
1232 		char szBuf[MAX_PATH_UTF8+1];
1233 		wchar_2_UTF8(szBuf, dp->data_w.cFileName);
1234 		copyin(&dp->entry, szBuf);
1235 	}
1236 	else if(valid_a)
1237 	{
1238 		// Copy ansi.
1239 		copyin(&dp->entry, dp->data_a.cFileName);
1240 	}
1241 	else
1242 	{
1243 		if(GetLastError()!=ERROR_NO_MORE_FILES)
1244 			goto err;
1245 		return NULL;
1246 	}
1247 
1248 	dp->offset=dp->entry.d_reclen;
1249 
1250 	return &dp->entry;
1251 err:
1252 	errno=b_errno_win32;
1253 	return NULL;
1254 }
1255 
init_stack_dump(void)1256 void init_stack_dump(void)
1257 {
1258 }
1259 
1260 
pathconf(const char * path,int name)1261 long pathconf(const char *path, int name)
1262 {
1263 	switch(name)
1264 	{
1265 		case _PC_PATH_MAX:
1266 			if(!strncmp(path, "\\\\?\\", 4))
1267 				return MAX_PATH_W;
1268 		case _PC_NAME_MAX:
1269 			return MAX_PATH;
1270 	}
1271 	return system_error();
1272 }
1273 
WSA_Init(void)1274 int WSA_Init(void)
1275 {
1276 	WORD wVersionRequested=MAKEWORD(1, 1);
1277 	WSADATA wsaData;
1278 
1279 	if(WSAStartup(wVersionRequested, &wsaData))
1280 	{
1281 		printf("Can not start Windows Sockets\n");
1282 		return system_error();
1283 	}
1284 
1285 	return 0;
1286 }
1287 
win32_chmod_old(const char * path,mode_t mode)1288 static int win32_chmod_old(const char *path, mode_t mode)
1289 {
1290 	DWORD attr=(DWORD)-1;
1291 
1292 	if(p_GetFileAttributesW)
1293 	{
1294 		char *pwszBuf=sm_get_pool_memory();
1295 		make_win32_path_UTF8_2_wchar(&pwszBuf, path);
1296 
1297 		attr=p_GetFileAttributesW((LPCWSTR)pwszBuf);
1298 		if(attr!=INVALID_FILE_ATTRIBUTES)
1299 		{
1300 			// Use mappings defined in stat() above.
1301 			if(!(mode & (S_IRUSR|S_IRGRP|S_IROTH)))
1302 				attr |= FILE_ATTRIBUTE_READONLY;
1303 			else
1304 				attr &= ~FILE_ATTRIBUTE_READONLY;
1305 			if(!(mode & S_IRWXO))
1306 				attr |= FILE_ATTRIBUTE_SYSTEM;
1307 			else
1308 				attr &= ~FILE_ATTRIBUTE_SYSTEM;
1309 			if(mode & S_ISVTX)
1310 				attr |= FILE_ATTRIBUTE_HIDDEN;
1311 			else
1312 				attr &= ~FILE_ATTRIBUTE_HIDDEN;
1313 			attr=p_SetFileAttributesW((LPCWSTR)pwszBuf, attr);
1314 		}
1315 		sm_free_pool_memory(pwszBuf);
1316 	}
1317 
1318 	if(attr==(DWORD)-1)
1319 	{
1320 		const char *err=errorString();
1321 		LocalFree((void *)err);
1322 		errno=b_errno_win32;
1323 		return -1;
1324 	}
1325 	return 0;
1326 }
1327 
1328 // Define attributes that are legal to set with SetFileAttributes().
1329 #define SET_ATTRS ( \
1330 	FILE_ATTRIBUTE_ARCHIVE| \
1331 	FILE_ATTRIBUTE_HIDDEN| \
1332 	FILE_ATTRIBUTE_NORMAL| \
1333 	FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
1334 	FILE_ATTRIBUTE_OFFLINE| \
1335 	FILE_ATTRIBUTE_READONLY| \
1336 	FILE_ATTRIBUTE_SYSTEM| \
1337 	FILE_ATTRIBUTE_TEMPORARY)
1338 
win32_chmod_new(const char * path,int64_t winattr)1339 static int win32_chmod_new(const char *path, int64_t winattr)
1340 {
1341 	//if(winattr & FILE_ATTRIBUTE_ENCRYPTED)
1342 	//	printf("\n   %s was encrypted!\n", path);
1343 	DWORD attr=(DWORD)-1;
1344 
1345 	if(p_GetFileAttributesW)
1346 	{
1347 		char *pwszBuf=sm_get_pool_memory();
1348 		make_win32_path_UTF8_2_wchar(&pwszBuf, path);
1349 
1350 		attr=p_GetFileAttributesW((LPCWSTR) pwszBuf);
1351 		if(attr!=INVALID_FILE_ATTRIBUTES)
1352 			attr=p_SetFileAttributesW((LPCWSTR)pwszBuf,
1353 				winattr & SET_ATTRS);
1354 		sm_free_pool_memory(pwszBuf);
1355 	}
1356 
1357 	if(attr==(DWORD)-1)
1358 	{
1359 		const char *err=errorString();
1360 		LocalFree((void *)err);
1361 		errno=b_errno_win32;
1362 		return -1;
1363 	}
1364 	return 0;
1365 }
1366 
win32_chmod(const char * path,mode_t mode,int64_t winattr)1367 int win32_chmod(const char *path, mode_t mode, int64_t winattr)
1368 {
1369 	/* Graham says: used to try to encode attributes in a mode_t.
1370 	   The new way is to just have an int64_t with them set properly.
1371 	   Old backups will not have winattr set, so if we have winattr,
1372 	   use it, other try to use the mode_t. */
1373 	/* After a few releases, get rid of the old stuff. */
1374 	if(winattr) return win32_chmod_new(path, winattr);
1375 	else if(mode) return win32_chmod_old(path, mode);
1376 	return 0;
1377 }
1378 
win32_chdir(const char * dir)1379 int win32_chdir(const char *dir)
1380 {
1381 	if(p_SetCurrentDirectoryW)
1382 	{
1383 		char *pwszBuf=sm_get_pool_memory();
1384 		make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1385 
1386 		BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1387 
1388 		sm_free_pool_memory(pwszBuf);
1389 
1390 		if(!b)
1391 		{
1392 			errno=b_errno_win32;
1393 			return -1;
1394 		}
1395 	}
1396 	else
1397 		return -1;
1398 
1399 	return 0;
1400 }
1401 
win32_mkdir(const char * dir)1402 int win32_mkdir(const char *dir)
1403 {
1404 	if(p_wmkdir)
1405 	{
1406 		char *pwszBuf=sm_get_pool_memory();
1407 		make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1408 
1409 		int n=p_wmkdir((LPCWSTR)pwszBuf);
1410 		sm_free_pool_memory(pwszBuf);
1411 		return n;
1412 	}
1413 	return _mkdir(dir);
1414 }
1415 
backslashes_to_forward_slashes(char * path)1416 static void backslashes_to_forward_slashes(char *path)
1417 {
1418 	char *cp;
1419 	// Windows gives us backslashes, but we want forward slashes.
1420 	for(cp=path; *cp; cp++)
1421 		if(*cp=='\\')
1422 			*cp='/';
1423 }
1424 
win32_getcwd(char * buf,int maxlen)1425 char *win32_getcwd(char *buf, int maxlen)
1426 {
1427 	int n=0;
1428 
1429 	if(p_GetCurrentDirectoryW)
1430 	{
1431 		char *pwszBuf=sm_get_pool_memory();
1432 		pwszBuf=sm_check_pool_memory_size(pwszBuf,
1433 			maxlen*sizeof(wchar_t));
1434 
1435 		if((n=p_GetCurrentDirectoryW(maxlen, (LPWSTR)pwszBuf)))
1436 			n=wchar_2_UTF8(buf, (wchar_t *)pwszBuf, maxlen)-1;
1437 		sm_free_pool_memory(pwszBuf);
1438 	}
1439 
1440 	if(!n || n>maxlen) return NULL;
1441 
1442 	if(n+1 > maxlen) return NULL;
1443 	if(n!=3)
1444 		buf[n]=0;
1445 
1446 	backslashes_to_forward_slashes(buf);
1447 
1448 	return buf;
1449 }
1450 
win32_cgets(char * buffer,int len)1451 char *win32_cgets(char* buffer, int len)
1452 {
1453 	/* We use console ReadConsoleA / ReadConsoleW to be able to read
1454 	   unicode from the win32 console and fallback if seomething fails. */
1455 
1456 	HANDLE hIn=GetStdHandle (STD_INPUT_HANDLE);
1457 	if(hIn
1458 	  && (hIn!=INVALID_HANDLE_VALUE))
1459 	{
1460 		DWORD dwRead;
1461 		wchar_t wszBuf[1024];
1462 		char  szBuf[1024];
1463 
1464 		// NT and unicode conversion.
1465 		if(ReadConsoleW(hIn, wszBuf, 1024, &dwRead, NULL))
1466 		{
1467 			// Null terminate at end.
1468 			if(wszBuf[dwRead-1]==L'\n')
1469 			{
1470 				wszBuf[dwRead-1]=L'\0';
1471 				dwRead--;
1472 			}
1473 
1474 			if(wszBuf[dwRead-1]==L'\r')
1475 			{
1476 				wszBuf[dwRead-1]=L'\0';
1477 				dwRead--;
1478 			}
1479 
1480 			wchar_2_UTF8(buffer, wszBuf, len);
1481 			return buffer;
1482 		}
1483 
1484 		// Win 9x and unicode conversion.
1485 		if(ReadConsoleA(hIn, szBuf, 1024, &dwRead, NULL))
1486 		{
1487 			// Null terminate at end.
1488 			if(szBuf[dwRead-1]==L'\n')
1489 			{
1490 				szBuf[dwRead-1]=L'\0';
1491 				dwRead--;
1492 			}
1493 
1494 			if(szBuf[dwRead-1]==L'\r')
1495 			{
1496 				szBuf[dwRead-1]=L'\0';
1497 				dwRead--;
1498 			}
1499 
1500 			// Convert from ansii to wchar_t.
1501 			p_MultiByteToWideChar(GetConsoleCP(),
1502 				0, szBuf, -1, wszBuf, 1024);
1503 			// Convert from wchar_t to UTF-8.
1504 			if(wchar_2_UTF8(buffer, wszBuf, len))
1505 				return buffer;
1506 		}
1507 	}
1508 
1509 	// Fallback.
1510 	if(fgets(buffer, len, stdin)) return buffer;
1511 	return NULL;
1512 }
1513 
win32_unlink(const char * filename)1514 int win32_unlink(const char *filename)
1515 {
1516 	int nRetCode=-1;
1517 
1518 	if(p_wunlink)
1519 	{
1520 		char* pwszBuf=sm_get_pool_memory();
1521 		make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1522 
1523 		nRetCode=_wunlink((LPCWSTR) pwszBuf);
1524 
1525 		/* Special case if file is readonly,
1526 		   we retry but unset attribute before. */
1527 		if(nRetCode==-1
1528 		  && errno==EACCES
1529 		  && p_SetFileAttributesW
1530 		  && p_GetFileAttributesW)
1531 		{
1532 			DWORD dwAttr=p_GetFileAttributesW((LPCWSTR)pwszBuf);
1533 			if(dwAttr!=INVALID_FILE_ATTRIBUTES)
1534 			{
1535 				if(p_SetFileAttributesW((LPCWSTR)pwszBuf,
1536 				  dwAttr & ~FILE_ATTRIBUTE_READONLY))
1537 				{
1538 					nRetCode=_wunlink((LPCWSTR) pwszBuf);
1539 					// Reset to original if it didn't help.
1540 					if(nRetCode==-1)
1541 						p_SetFileAttributesW(
1542 						  (LPCWSTR)pwszBuf, dwAttr);
1543 				}
1544 			}
1545 		}
1546 		sm_free_pool_memory(pwszBuf);
1547 	}
1548 	return nRetCode;
1549 }
1550 
1551 
1552 #include "mswinver.h"
1553 
1554 char WIN_VERSION_LONG[64];
1555 char WIN_VERSION[32];
1556 char WIN_RAWVERSION[32];
1557 
1558 class winver
1559 {
1560 public:
1561 	winver(void);
1562 };
1563 
1564 static winver INIT; // cause constructor to be called before main()
1565 
winver(void)1566 winver::winver(void)
1567 {
1568 	const char *version="";
1569 	const char *platform="";
1570 	OSVERSIONINFO osvinfo;
1571 	osvinfo.dwOSVersionInfoSize=sizeof(osvinfo);
1572 
1573 	// Get the current OS version.
1574 	if(!GetVersionEx(&osvinfo))
1575 	{
1576 		version = "Unknown";
1577 		platform = "Unknown";
1578 	}
1579 	const int ver =_mkversion(osvinfo.dwPlatformId,
1580 			osvinfo.dwMajorVersion,
1581 			osvinfo.dwMinorVersion);
1582 	snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1583 	switch(ver)
1584 	{
1585 		case MS_WINDOWS_95: (version="Windows 95"); break;
1586 		case MS_WINDOWS_98: (version="Windows 98"); break;
1587 		case MS_WINDOWS_ME: (version="Windows ME"); break;
1588 		case MS_WINDOWS_NT4:(version="Windows NT 4.0");
1589 				platform = "NT"; break;
1590 		case MS_WINDOWS_2K: (version="Windows 2000");
1591 				platform = "NT"; break;
1592 		case MS_WINDOWS_XP: (version="Windows XP");
1593 				platform = "NT"; break;
1594 		case MS_WINDOWS_S2003: (version =  "Windows Server 2003");
1595 				platform = "NT"; break;
1596 		default: version = WIN_RAWVERSION; break;
1597 	}
1598 
1599 	snprintf(WIN_VERSION_LONG, sizeof(WIN_VERSION_LONG), "%s", version);
1600 	snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1601 			platform, osvinfo.dwMajorVersion,
1602 			osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1603 }
1604 
1605 VOID WriteToPipe(VOID);
1606 VOID ReadFromPipe(VOID);
1607 VOID ErrorExit(LPCSTR);
1608 VOID ErrMsg(LPTSTR, BOOL);
1609 
dwAltNameLength_ok(DWORD dwAltNameLength)1610 static int dwAltNameLength_ok(DWORD dwAltNameLength)
1611 {
1612 	return dwAltNameLength>0 && dwAltNameLength<MAX_PATH_UTF8;
1613 }
1614 
1615 /* Extracts the executable or script name from the first string in
1616    cmdline.
1617 
1618    If the name contains blanks then it must be quoted with double quotes,
1619    otherwise quotes are optional.  If the name contains blanks then it
1620    will be converted to a short name.
1621 
1622    The optional quotes will be removed.  The result is copied to a malloc'ed
1623    buffer and returned through the pexe argument.  The pargs parameter is set
1624    to the address of the character in cmdline located after the name.
1625 
1626    The malloc'ed buffer returned in *pexe must be freed by the caller.  */
GetApplicationName(const char * cmdline,char ** pexe,const char ** pargs)1627 bool GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1628 {
1629 	// Start of executable name in cmdline.
1630 	const char *pExeStart=NULL;
1631 	// Character after executable name (separator).
1632 	const char *pExeEnd=NULL;
1633 
1634 	// Character after last path separator.
1635 	const char *pBasename=NULL;
1636 	// Period at start of extension.
1637 	const char *pExtension=NULL;
1638 
1639 	const char *current=cmdline;
1640 
1641 	bool bQuoted=false;
1642 
1643 	// Skip initial whitespace.
1644 	while(*current==' ' || *current=='\t') current++;
1645 
1646 	// Calculate start of name and determine if quoted.
1647 
1648 	if(*current=='"')
1649 	{
1650 		pExeStart=++current;
1651 		bQuoted=true;
1652 	}
1653 	else
1654 	{
1655 		pExeStart=current;
1656 		bQuoted=false;
1657 	}
1658 
1659 	*pargs=NULL;
1660 	*pexe=NULL;
1661 
1662 	/* Scan command line looking for path separators (/ and \\) and the
1663 	   terminator, either a quote or a blank.  The location of the
1664 	   extension is also noted.  */
1665 	for( ; *current!='\0'; current++)
1666 	{
1667 		if(*current=='.')
1668 			pExtension=current;
1669 		else if(IsPathSeparator(*current) && current[1]!='\0')
1670 		{
1671 			pBasename=&current[1];
1672 			pExtension=NULL;
1673 		}
1674 
1675 		// Check for terminator, either quote or blank.
1676 		if(bQuoted)
1677 		{
1678 			if(*current!='"') continue;
1679 		}
1680 		else
1681 		{
1682 			if(*current!=' ') continue;
1683 		}
1684 
1685 		/* Hit terminator, remember end of name (address of terminator)
1686 		   and start of arguments. */
1687 		pExeEnd=current;
1688 
1689 		if(bQuoted && *current=='"')
1690 			*pargs=&current[1];
1691 		else
1692 			*pargs=current;
1693 		break;
1694 	}
1695 
1696 	if(!pBasename) pBasename=pExeStart;
1697 
1698 	if(!pExeEnd) pExeEnd=current;
1699 
1700 	if(!*pargs) *pargs=current;
1701 
1702 	bool bHasPathSeparators=pExeStart!=pBasename;
1703 
1704 	// We have pointers to all the useful parts of the name.
1705 
1706 	// Default extensions in the order cmd.exe uses to search.
1707 
1708 	static const char ExtensionList[][5]={".com", ".exe", ".bat", ".cmd"};
1709 	DWORD dwBasePathLength=pExeEnd-pExeStart;
1710 
1711 	DWORD dwAltNameLength=0;
1712 	char *pPathname=(char *)alloca(MAX_PATH_UTF8+1);
1713 	char *pAltPathname=(char *)alloca(MAX_PATH_UTF8+1);
1714 
1715 	pPathname[MAX_PATH_UTF8]='\0';
1716 	pAltPathname[MAX_PATH_UTF8]='\0';
1717 
1718 	memcpy(pPathname, pExeStart, dwBasePathLength);
1719 	pPathname[dwBasePathLength]='\0';
1720 
1721 	if(!pExtension)
1722 	{
1723 		// Try appending extensions.
1724 		for(int index=0;
1725 		  index<(int)(sizeof(ExtensionList)/sizeof(ExtensionList[0]));
1726 		  index++)
1727 		{
1728 			if(!bHasPathSeparators)
1729 			{
1730 				// There are no path separators, search in the
1731 				// standard locations
1732 				dwAltNameLength=SearchPath(NULL, pPathname,
1733 				  ExtensionList[index], MAX_PATH_UTF8,
1734 				  pAltPathname, NULL);
1735 				if(dwAltNameLength_ok(dwAltNameLength))
1736 				{
1737 					memcpy(pPathname, pAltPathname,
1738 						dwAltNameLength);
1739 					pPathname[dwAltNameLength]='\0';
1740 					break;
1741 				}
1742 			}
1743 			else
1744 			{
1745 				snprintf(&pPathname[dwBasePathLength],
1746 					MAX_PATH_UTF8-dwBasePathLength,
1747 					"%s", ExtensionList[index]);
1748 				if(GetFileAttributes(pPathname)
1749 				  !=INVALID_FILE_ATTRIBUTES)
1750 					break;
1751 				pPathname[dwBasePathLength]='\0';
1752 			}
1753 		}
1754 	}
1755 	else if(!bHasPathSeparators)
1756 	{
1757 		// There are no path separators, search in the standard
1758 		// locations.
1759 		dwAltNameLength=SearchPath(NULL, pPathname,
1760 			NULL, MAX_PATH_UTF8, pAltPathname, NULL);
1761 		if(dwAltNameLength_ok(dwAltNameLength))
1762 		{
1763 			memcpy(pPathname, pAltPathname, dwAltNameLength);
1764 			pPathname[dwAltNameLength] = '\0';
1765 		}
1766 	}
1767 
1768 	if(strchr(pPathname, ' '))
1769 	{
1770 		dwAltNameLength=GetShortPathName(pPathname,
1771 			pAltPathname, MAX_PATH_UTF8);
1772 
1773 		if(dwAltNameLength_ok(dwAltNameLength))
1774 		{
1775 			*pexe=(char *)malloc(dwAltNameLength+1);
1776 			if(!*pexe) return false;
1777 			memcpy(*pexe, pAltPathname, dwAltNameLength+1);
1778 		}
1779 	}
1780 
1781 	if(!*pexe)
1782 	{
1783 		DWORD dwPathnameLength=strlen(pPathname);
1784 		*pexe=(char *)malloc(dwPathnameLength+1);
1785 		if(!*pexe) return false;
1786 		memcpy(*pexe, pPathname, dwPathnameLength+1);
1787 	}
1788 
1789 	return true;
1790 }
1791 
ErrorExit(LPCSTR lpszMessage)1792 void ErrorExit(LPCSTR lpszMessage)
1793 {
1794 }
1795 
1796 // syslog function, added by Nicolas Boichat.
openlog(const char * ident,int option,int facility)1797 void openlog(const char *ident, int option, int facility)
1798 {
1799 }
1800 
do_forkchild(struct fzp ** sin,struct fzp ** sout,struct fzp ** serr,const char * path,char * const argv[],int do_wait)1801 static pid_t do_forkchild(struct fzp **sin,
1802 	struct fzp **sout, struct fzp **serr,
1803 	const char *path, char * const argv[], int do_wait)
1804 {
1805 	int a=0;
1806 	char cmd[1024]="";
1807 	STARTUPINFO si;
1808 	PROCESS_INFORMATION pi;
1809 
1810 	ZeroMemory(&si, sizeof(si));
1811 	si.cb=sizeof(si);
1812 	ZeroMemory(&pi, sizeof(pi));
1813 
1814 	while(argv[a] && strlen(cmd)+strlen(argv[a])+10<sizeof(cmd))
1815 	{
1816 		if(a>0) strcat(cmd, " ");
1817 		strcat(cmd, "\"");
1818 		strcat(cmd, argv[a++]);
1819 		strcat(cmd, "\"");
1820 	}
1821 	if(!CreateProcess(NULL, cmd, NULL, NULL,
1822 		FALSE, 0, NULL, NULL, &si, &pi))
1823 	{
1824 		printf( "CreateProcess %s failed\n", path);
1825 		return -1;
1826 	}
1827 	if(do_wait) WaitForSingleObject(pi.hProcess, INFINITE);
1828 	CloseHandle(pi.hProcess);
1829 	CloseHandle(pi.hThread);
1830 	return 0;
1831 }
1832 
forkchild(struct fzp ** sin,struct fzp ** sout,struct fzp ** serr,const char * path,char * const argv[])1833 pid_t forkchild(struct fzp **sin, struct fzp **sout, struct fzp **serr,
1834 	const char *path, char * const argv[])
1835 {
1836 	return do_forkchild(sin, sout, serr, path, argv, 1 /* wait */);
1837 }
1838 
forkchild_no_wait(struct fzp ** sin,struct fzp ** sout,struct fzp ** serr,const char * path,char * const argv[])1839 pid_t forkchild_no_wait(struct fzp **sin, struct fzp **sout, struct fzp **serr,
1840 	const char *path, char * const argv[])
1841 {
1842 	return do_forkchild(sin, sout, serr, path, argv, 0 /* do not wait */);
1843 }
1844 
win32_utime(const char * fname,struct stat * statp)1845 int win32_utime(const char *fname, struct stat *statp)
1846 {
1847 	FILETIME cre;
1848 	FILETIME acc;
1849 	FILETIME mod;
1850 
1851 	conv_unix_to_win32_path(fname, tmpbuf, _MAX_PATH);
1852 
1853 	// We save creation date in st_ctime.
1854 	cvt_utime_to_ftime(statp->st_ctime, cre);
1855 	cvt_utime_to_ftime(statp->st_atime, acc);
1856 	cvt_utime_to_ftime(statp->st_mtime, mod);
1857 
1858 	HANDLE h=INVALID_HANDLE_VALUE;
1859 
1860 	if(p_CreateFileW)
1861 	{
1862 		char* pwszBuf=sm_get_pool_memory();
1863 		make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
1864 
1865 		h=p_CreateFileW((LPCWSTR)pwszBuf,
1866 				FILE_WRITE_ATTRIBUTES,
1867 				FILE_SHARE_WRITE
1868 				|FILE_SHARE_READ
1869 				|FILE_SHARE_DELETE,
1870 				NULL,
1871 				OPEN_EXISTING,
1872 				// required for directories
1873 				FILE_FLAG_BACKUP_SEMANTICS,
1874 				NULL);
1875 
1876 		sm_free_pool_memory(pwszBuf);
1877 	}
1878 
1879 	if(h==INVALID_HANDLE_VALUE)
1880 	{
1881 		const char *err=errorString();
1882 		fprintf(stderr, "Cannot open %s for utime(): ERR=%s\n",
1883 			tmpbuf, err);
1884 		LocalFree((void *)err);
1885 		errno=b_errno_win32;
1886 		return -1;
1887 	}
1888 
1889 	int rval=SetFileTime(h, &cre, &acc, &mod)?0:-1;
1890 	CloseHandle(h);
1891 	if(rval==-1) errno=b_errno_win32;
1892 	return rval;
1893 }
1894 
win32_getfsname(const char * path,char * fsname,size_t fsname_size)1895 int win32_getfsname(const char *path, char *fsname, size_t fsname_size)
1896 {
1897 	// I do not think anyone still needs non-Unicode stuff.
1898 	WCHAR fsname_ucs2[MAX_PATH + 1];
1899 	{
1900 		WCHAR *pwsz_path=(WCHAR*)sm_get_pool_memory();
1901 		make_win32_path_UTF8_2_wchar((char**)&pwsz_path, path);
1902 		int path_len=wcslen(pwsz_path);
1903 		if (path_len && pwsz_path[path_len-1] != '\\')
1904 		{
1905 			pwsz_path=(WCHAR*)sm_check_pool_memory_size((char*)pwsz_path,
1906 				sizeof(WCHAR)*path_len+sizeof(L"\\"));
1907 			wcscpy(pwsz_path+path_len++, L"\\");
1908 		}
1909 
1910 		int error;
1911 		for(;;)
1912 		{
1913 			error=GetVolumeInformationW(
1914 				pwsz_path /* lpRootPathName */,
1915 				NULL /* lpVolumeNameBuffer */,
1916 				0 /* nVolumeNameSize */,
1917 				NULL /* lpVolumeSerialNumber */,
1918 				NULL /* lpMaximumComponentLength */,
1919 				NULL /* lpFileSystemFlags */,
1920 				fsname_ucs2 /* lpFileSystemNameBuffer */,
1921 				MAX_PATH + 1 /* nFileSystemNameSize */
1922 			) ? 0 : GetLastError();
1923 			if(error!=ERROR_DIR_NOT_ROOT)
1924 				break;
1925 
1926 			// We are not in root, let's try upper directory.
1927 			do --path_len; while(path_len && pwsz_path[path_len-1]!='\\');
1928 			if (!path_len)
1929 				break;
1930 			// Terminate string right after earlier slash.
1931 			pwsz_path[path_len]=0;
1932 		}
1933 		sm_free_pool_memory((char*)pwsz_path);
1934 
1935 		if(error)
1936 		{
1937 			char used_path[MAX_PATH_UTF8 + 1];
1938 			wchar_2_UTF8(used_path, (WCHAR*)pwsz_path, sizeof(used_path));
1939 			fprintf(stderr, "Cannot get volume information for %s: ERR=%d\n",
1940 				used_path, error);
1941 			return error;
1942 		}
1943 	}
1944 	wchar_2_UTF8(fsname, fsname_ucs2, fsname_size);
1945 	return 0;
1946 }
1947 
realpath(const char * path,char * resolved_path)1948 char *realpath(const char *path, char *resolved_path)
1949 {
1950 	DWORD size=0;
1951 	char *ret=NULL;
1952 	HANDLE h=INVALID_HANDLE_VALUE;
1953 	char *pwszBuf=NULL;
1954 	size_t s=strlen(path);
1955 	int junk_len=4;
1956 
1957 	// Passing in an existing buffer is not supported.
1958 	ASSERT(resolved_path==NULL);
1959 
1960 	// Have to special case the drive letter by itself, because the
1961 	// functions that are provided to us fail on them.
1962 	if((s==2 || s==3) // Could have a trailing slash.
1963 	  && isalpha(path[0])
1964 	  && path[1]==':')
1965 		return strdup(path);
1966 
1967 	errno=0;
1968 	SetLastError(0);
1969 	conv_unix_to_win32_path(path, tmpbuf, _MAX_PATH);
1970 
1971 	pwszBuf=sm_get_pool_memory();
1972 
1973 	if(p_CreateFileW)
1974 	{
1975 		make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
1976 
1977 		h=p_CreateFileW(
1978 			(LPCWSTR)pwszBuf,
1979 			GENERIC_READ,
1980 			FILE_SHARE_READ,
1981 			NULL,
1982 			OPEN_EXISTING,
1983 			FILE_FLAG_BACKUP_SEMANTICS,
1984 			NULL
1985 		);
1986 	}
1987 
1988 	if(h==INVALID_HANDLE_VALUE)
1989 	{
1990 		DWORD e=GetLastError();
1991 		switch(e)
1992 		{
1993 			case ERROR_NOT_ENOUGH_MEMORY:
1994 				errno=ENOMEM;
1995 				break;
1996 			case ERROR_FILE_NOT_FOUND:
1997 			case ERROR_PATH_NOT_FOUND:
1998 				errno=ENOENT;
1999 				break;
2000 			case ERROR_ACCESS_DENIED:
2001 			default:
2002 				errno=EACCES;
2003 				break;
2004 		}
2005 		goto end;
2006 	}
2007 
2008 	if(!(size=p_GetFinalPathNameByHandleW(h, NULL, 0, 0)))
2009 	{
2010 		errno=ENOENT;
2011 		goto end;
2012 	}
2013 
2014 	pwszBuf=sm_check_pool_memory_size(pwszBuf, size);
2015 	if(p_GetFinalPathNameByHandleW(h,
2016 		(LPWSTR)pwszBuf, size, 0)<junk_len)
2017 			goto end;
2018 	// Get size of wanted buffer.
2019 	size=p_WideCharToMultiByte(CP_UTF8, 0,
2020 		(LPCWSTR)pwszBuf+junk_len, -1,
2021 		NULL, 0, // <- 0 to get buffer size
2022 		NULL, NULL);
2023 	ASSERT(size>0);
2024 	// Allocate and fill buffer.
2025 	if(!(ret=(char *)malloc(size+1)))
2026 		goto end;
2027 	size=p_WideCharToMultiByte(CP_UTF8, 0,
2028 		(LPCWSTR)pwszBuf+junk_len, -1,
2029 		ret, size,
2030 		NULL, NULL);
2031 	ASSERT(size>0);
2032 
2033 	backslashes_to_forward_slashes(ret);
2034 end:
2035 	if(pwszBuf) sm_free_pool_memory(pwszBuf);
2036 	if(h!=INVALID_HANDLE_VALUE)
2037 		CloseHandle(h);
2038 	return ret;
2039 }
2040 
get_fixed_drives(void)2041 char *get_fixed_drives(void)
2042 {
2043 	static char ret[256]="";
2044 	size_t r=0;
2045 	char *drive=NULL;
2046 	char pwszBuf[256];
2047 
2048 	memset(&ret, 0, sizeof(ret));
2049 
2050 	if(!p_GetLogicalDriveStringsW(sizeof(pwszBuf), (LPWSTR)pwszBuf))
2051 		return NULL;
2052 
2053 	// The function above fills a buffer with widechars like this:
2054 	// C:/<null>D:/<null><null>
2055 	// So we have to work to extract the letters.
2056 	drive=pwszBuf;
2057 	while(*drive)
2058 	{
2059 		int l;
2060 		char u[8];
2061 		l=wchar_2_UTF8(u, (const wchar_t *)drive, sizeof(u));
2062 		if(GetDriveTypeW((const wchar_t *)drive)==DRIVE_FIXED)
2063 		{
2064 			if(isalpha(*u))
2065 				ret[r++]=toupper(*u);
2066 		}
2067 		drive+=l*2;
2068 	}
2069 
2070 	return ret;
2071 }
2072