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=¤t[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=¤t[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