]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
a9f46a1173aa145577a0a10e18660e1fc20e576a
[bacula/bacula] / bacula / src / win32 / compat / compat.cpp
1 //                              -*- Mode: C++ -*-
2 // compat.cpp -- compatibilty layer to make bacula-fd run
3 //               natively under windows
4 //
5 // Copyright transferred from Raider Solutions, Inc to
6 //   Kern Sibbald and John Walker by express permission.
7 //
8 //  Copyright (C) 2004-2006 Kern Sibbald
9 //
10 //  This program is free software; you can redistribute it and/or
11 //  modify it under the terms of the GNU General Public License
12 //  version 2 as amended with additional clauses defined in the
13 //  file LICENSE in the main source directory.
14 //
15 //  This program is distributed in the hope that it will be useful,
16 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 //  the file LICENSE for additional details.
19 //
20 // Author          : Christopher S. Hull
21 // Created On      : Sat Jan 31 15:55:00 2004
22 // $Id$
23
24 #ifdef __APCUPSD__
25
26 #include "apc.h"
27 #include "compat.h"
28 #include "winapi.h"
29
30 #else
31
32 #include "bacula.h"
33 #include "compat.h"
34 #include "jcr.h"
35 #include "../../lib/winapi.h"
36 #include "vss.h"
37
38 #endif
39
40 #define b_errno_win32 (1<<29)
41
42
43 /* UTF-8 to UCS2 path conversion is expensive,
44    so we cache the conversion. During backup the
45    conversion is called 3 times (lstat, attribs, open),
46    by using the cache this is reduced to 1 time */
47
48 static POOLMEM *g_pWin32ConvUTF8Cache = get_pool_memory (PM_FNAME);
49 static POOLMEM *g_pWin32ConvUCS2Cache = get_pool_memory (PM_FNAME);
50 static DWORD g_dwWin32ConvUTF8strlen = 0;
51 static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER;
52
53 void Win32ConvCleanupCache()
54 {
55    if (g_pWin32ConvUTF8Cache) {
56       free_pool_memory(g_pWin32ConvUTF8Cache);
57       g_pWin32ConvUTF8Cache = NULL;
58    }
59
60    if (g_pWin32ConvUCS2Cache) {
61       free_pool_memory(g_pWin32ConvUCS2Cache);   
62       g_pWin32ConvUCS2Cache = NULL;
63    }
64
65    g_dwWin32ConvUTF8strlen = 0;
66 }
67
68
69 /* to allow the usage of the original version in this file here */
70 #undef fputs
71
72
73 #define USE_WIN32_COMPAT_IO 1
74 #define USE_WIN32_32KPATHCONVERSION 1
75
76 extern void d_msg(const char *file, int line, int level, const char *fmt,...);
77 extern DWORD   g_platform_id;
78 extern int enable_vss;
79
80 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
81 #ifdef HAVE_MINGW
82 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL 
83 #else
84 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
85 #endif
86
87 #define WIN32_FILETIME_SCALE  10000000             // 100ns/second
88
89 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
90 {
91     const char *fname = name;
92     char *tname = win32_name;
93     while (*name) {
94         /* Check for Unix separator and convert to Win32 */
95         if (name[0] == '/' && name[1] == '/') {  /* double slash? */
96            name++;                               /* yes, skip first one */
97         }
98         if (*name == '/') {
99             *win32_name++ = '\\';     /* convert char */
100         /* If Win32 separated that is "quoted", remove quote */
101         } else if (*name == '\\' && name[1] == '\\') {
102             *win32_name++ = '\\';
103             name++;                   /* skip first \ */
104         } else {
105             *win32_name++ = *name;    /* copy character */
106         }
107         name++;
108     }
109     /* Strip any trailing slash, if we stored something */
110     /* but leave "c:\" with backslash (root directory case */
111     if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
112         win32_name[-1] = 0;
113     } else {
114         *win32_name = 0;
115     }
116
117 #ifdef WIN32_VSS
118     /* here we convert to VSS specific file name which
119        can get longer because VSS will make something like
120        \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
121        from c:\bacula\uninstall.exe
122     */
123     if (g_pVSSClient && enable_vss && g_pVSSClient->IsInitialized()) {
124        POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
125        pszBuf = check_pool_memory_size(pszBuf, dwSize);
126        bstrncpy(pszBuf, tname, strlen(tname)+1);
127        g_pVSSClient->GetShadowPath(pszBuf, tname, dwSize);
128        free_pool_memory(pszBuf);
129     }
130 #endif
131 }
132
133 POOLMEM* 
134 make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
135 {
136    /* created 02/27/2006 Thorsten Engel
137       
138       This function expects an UCS-encoded standard wchar_t in pszUCSPath and
139       will complete the input path to an absolue path of the form \\?\c:\path\file
140
141       With this trick, it is possible to have 32K characters long paths.
142
143       Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
144       to a raw windows partition */
145
146    if (pBIsRawPath)
147       *pBIsRawPath = FALSE;
148
149    if (!p_GetCurrentDirectoryW)
150       return pszUCSPath;
151    
152    wchar_t *name = (wchar_t *) pszUCSPath;
153
154    /* if it has already the desired form, exit without changes */
155    if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0)
156       return pszUCSPath;
157
158    POOLMEM *pwszBuf = get_pool_memory(PM_FNAME);
159    POOLMEM *pwszCurDirBuf = get_pool_memory(PM_FNAME);
160    DWORD dwCurDirPathSize = 0;
161
162    /* get buffer with enough size (name+max 6. wchars+1 null terminator */
163    DWORD dwBufCharsNeeded = (wcslen(name)+7);
164    pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
165       
166    /* add \\?\ to support 32K long filepaths 
167       it is important to make absolute paths, so we add drive and
168       current path if necessary */
169
170    BOOL bAddDrive = TRUE;
171    BOOL bAddCurrentPath = TRUE;
172    BOOL bAddPrefix = TRUE;
173
174    /* does path begin with drive? if yes, it is absolute */
175    if (wcslen(name) >= 3 && (iswalpha (*name) && *(name+1) == ':'
176        && (*(name+2) == '\\' || *(name+2) == '/'))) {
177       bAddDrive = FALSE;
178       bAddCurrentPath = FALSE;
179    }
180
181    /* is path absolute? */
182    if (*name == '/' || *name == '\\')
183       bAddCurrentPath = FALSE; 
184
185    /* is path relative to itself?, if yes, skip ./ */
186    if (wcslen(name) > 2 && ((wcsncmp(name, L"./", 2) == 0) || (wcsncmp(name, L".\\", 2) == 0))) {
187       name+=2;
188    }
189
190    /* is path of form '//./'? */   
191    if (wcslen(name) > 3 && ((wcsncmp(name, L"//./", 4) == 0) || (wcsncmp(name, L"\\\\.\\", 4) == 0))) {
192       bAddDrive = FALSE;
193       bAddCurrentPath = FALSE;
194       bAddPrefix = FALSE;
195       if (pBIsRawPath)
196          *pBIsRawPath = TRUE;
197    }
198
199    int nParseOffset = 0;
200    
201    /* add 4 bytes header */
202    if (bAddPrefix) {
203       nParseOffset = 4;
204       wcscpy ((wchar_t *) pwszBuf,L"\\\\?\\");
205    }
206
207    /* get current path if needed */
208    if (bAddDrive || bAddCurrentPath) {
209       dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
210       if (dwCurDirPathSize > 0) {
211          /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */         
212          pwszCurDirBuf = check_pool_memory_size(pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
213          p_GetCurrentDirectoryW(dwCurDirPathSize,(wchar_t *)pwszCurDirBuf);
214       }
215       else
216       {
217          /* we have no info for doing so */
218          bAddDrive = FALSE;
219          bAddCurrentPath = FALSE;
220       }
221    }
222       
223
224    /* add drive if needed */
225    if (bAddDrive && !bAddCurrentPath) {
226       wchar_t szDrive[3];
227
228       if (dwCurDirPathSize > 3 && wcsncmp((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0)
229          /* copy drive character */
230          wcsncpy((wchar_t *) szDrive, (LPCWSTR)pwszCurDirBuf+4,2);          
231       else
232          /* copy drive character */
233          wcsncpy((wchar_t *) szDrive, (LPCWSTR)pwszCurDirBuf,2);  
234
235       szDrive[2] = 0;
236             
237       wcscat((wchar_t *) pwszBuf, szDrive);  
238       nParseOffset +=2;
239    }
240
241    /* add path if needed */
242    if (bAddCurrentPath) {
243       /* the 1 add. character is for the eventually added backslash */
244       dwBufCharsNeeded += dwCurDirPathSize+1; 
245       pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
246       /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
247       
248       if (dwCurDirPathSize > 3 && wcsncmp((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0)
249          /* copy complete string */
250          wcscpy((wchar_t *) pwszBuf, (LPCWSTR)pwszCurDirBuf);          
251       else
252          /* append path  */
253          wcscat((wchar_t *) pwszBuf, (LPCWSTR)pwszCurDirBuf);       
254
255       nParseOffset = wcslen ((LPCWSTR) pwszBuf);
256
257       /* check if path ends with backslash, if not, add one */
258       if (*((wchar_t *) pwszBuf+nParseOffset-1) != L'\\') {
259          wcscat((wchar_t *) pwszBuf, L"\\");
260          nParseOffset++;
261       }      
262    }
263
264
265    wchar_t *win32_name = (wchar_t *)pwszBuf+nParseOffset;
266
267    while (*name) {
268       /* Check for Unix separator and convert to Win32 */
269       if (*name == '/') {
270          *win32_name++ = '\\';     /* convert char */
271          /* If Win32 separated that is "quoted", remove quote */
272 /* HELPME (Thorsten Engel): I don't understand the following part
273    and it removes a backslash from e.g. "\\.\c:" which I need for 
274    RAW device access. So I took it out */
275 /*      } else if (*name == '\\' && name[1] == '\\') {
276          *win32_name++ = '\\';
277          name++;  */                 /* skip first \ */ 
278       } else {
279          *win32_name++ = *name;    /* copy character */
280       }
281       name++;
282    }
283    
284    /* null terminate string */
285    *win32_name = 0;
286
287 #ifdef WIN32_VSS
288    /* here we convert to VSS specific file name which
289    can get longer because VSS will make something like
290    \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
291    from c:\bacula\uninstall.exe
292    */ 
293    if (g_pVSSClient && enable_vss && g_pVSSClient->IsInitialized()) {
294       /* is output buffer large enough? */
295       pwszBuf = check_pool_memory_size(pwszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
296       /* create temp. buffer */
297       POOLMEM* pszBuf = get_pool_memory(PM_FNAME);
298       pszBuf = check_pool_memory_size(pszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
299       if (bAddPrefix)
300          nParseOffset = 4;
301       else
302          nParseOffset = 0; 
303       wcsncpy((wchar_t *) pszBuf, (wchar_t *) pwszBuf+nParseOffset, wcslen((wchar_t *)pwszBuf)+1-nParseOffset);
304       g_pVSSClient->GetShadowPathW((wchar_t *)pszBuf,(wchar_t *)pwszBuf,dwBufCharsNeeded+MAX_PATH);
305       free_pool_memory(pszBuf);
306    }   
307 #endif
308
309    free_pool_memory(pszUCSPath);
310    free_pool_memory(pwszCurDirBuf);
311
312    return pwszBuf;
313 }
314
315 int
316 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
317 {
318    /* the return value is the number of bytes written to the buffer.
319       The number includes the byte for the null terminator. */
320
321    if (p_WideCharToMultiByte) {
322          int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
323          ASSERT (nRet > 0);
324          return nRet;
325       }
326    else
327       return 0;
328 }
329
330 int
331 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
332 {
333    /* the return value is the number of wide characters written to the buffer. */
334    /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
335
336    if (p_MultiByteToWideChar) {
337       /* strlen of UTF8 +1 is enough */
338       DWORD cchSize = (strlen(pszUTF)+1);
339       *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
340
341       int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
342       ASSERT (nRet > 0);
343       return nRet;
344    }
345    else
346       return 0;
347 }
348
349
350 void
351 wchar_win32_path(const char *name, wchar_t *win32_name)
352 {
353     const char *fname = name;
354     while (*name) {
355         /* Check for Unix separator and convert to Win32 */
356         if (*name == '/') {
357             *win32_name++ = '\\';     /* convert char */
358         /* If Win32 separated that is "quoted", remove quote */
359         } else if (*name == '\\' && name[1] == '\\') {
360             *win32_name++ = '\\';
361             name++;                   /* skip first \ */
362         } else {
363             *win32_name++ = *name;    /* copy character */
364         }
365         name++;
366     }
367     /* Strip any trailing slash, if we stored something */
368     if (*fname != 0 && win32_name[-1] == '\\') {
369         win32_name[-1] = 0;
370     } else {
371         *win32_name = 0;
372     }
373 }
374
375 int 
376 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
377 {
378    P(Win32Convmutex);
379    /* if we find the utf8 string in cache, we use the cached ucs2 version.
380       we compare the stringlength first (quick check) and then compare the content.            
381    */
382    if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
383       if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
384          int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
385          *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);      
386          wcscpy((LPWSTR) *pszUCS, (LPWSTR) g_pWin32ConvUCS2Cache);
387          V(Win32Convmutex);
388          return nBufSize / sizeof (WCHAR);
389       }
390    }
391
392    /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
393    int nRet = UTF8_2_wchar(pszUCS, pszUTF);
394
395 #ifdef USE_WIN32_32KPATHCONVERSION
396    /* add \\?\ to support 32K long filepaths */
397    *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
398 #else
399    if (pBIsRawPath)
400       *pBIsRawPath = FALSE;
401 #endif
402
403    /* populate cache */      
404    g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
405    wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
406    
407    g_dwWin32ConvUTF8strlen = strlen(pszUTF);
408    g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+1);
409    bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
410    V(Win32Convmutex);
411
412    return nRet;
413 }
414
415 #ifndef HAVE_VC8
416 int umask(int)
417 {
418    return 0;
419 }
420 #endif
421
422 int chmod(const char *, mode_t)
423 {
424    return 0;
425 }
426
427 int chown(const char *k, uid_t, gid_t)
428 {
429    return 0;
430 }
431
432 int lchown(const char *k, uid_t, gid_t)
433 {
434    return 0;
435 }
436
437 #ifdef needed
438 bool fstype(const char *fname, char *fs, int fslen)
439 {
440    return true;                       /* accept anything */
441 }
442 #endif
443
444
445 long int
446 random(void)
447 {
448     return rand();
449 }
450
451 void
452 srandom(unsigned int seed)
453 {
454    srand(seed);
455 }
456 // /////////////////////////////////////////////////////////////////
457 // convert from Windows concept of time to Unix concept of time
458 // /////////////////////////////////////////////////////////////////
459 void
460 cvt_utime_to_ftime(const time_t  &time, FILETIME &wintime)
461 {
462     uint64_t mstime = time;
463     mstime *= WIN32_FILETIME_SCALE;
464     mstime += WIN32_FILETIME_ADJUST;
465
466     #ifdef HAVE_MINGW
467     wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
468     #else
469     wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
470     #endif
471     wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
472 }
473
474 time_t
475 cvt_ftime_to_utime(const FILETIME &time)
476 {
477     uint64_t mstime = time.dwHighDateTime;
478     mstime <<= 32;
479     mstime |= time.dwLowDateTime;
480
481     mstime -= WIN32_FILETIME_ADJUST;
482     mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
483
484     return (time_t) (mstime & 0xffffffff);
485 }
486
487 static const char *
488 errorString(void)
489 {
490    LPVOID lpMsgBuf;
491
492    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
493                  FORMAT_MESSAGE_FROM_SYSTEM |
494                  FORMAT_MESSAGE_IGNORE_INSERTS,
495                  NULL,
496                  GetLastError(),
497                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
498                  (LPTSTR) &lpMsgBuf,
499                  0,
500                  NULL);
501
502    /* Strip any \r or \n */
503    char *rval = (char *) lpMsgBuf;
504    char *cp = strchr(rval, '\r');
505    if (cp != NULL) {
506       *cp = 0;
507    } else {
508       cp = strchr(rval, '\n');
509       if (cp != NULL)
510          *cp = 0;
511    }
512    return rval;
513 }
514
515
516 static int
517 statDir(const char *file, struct stat *sb)
518 {
519    WIN32_FIND_DATAW info_w;       // window's file info
520    WIN32_FIND_DATAA info_a;       // window's file info
521
522    // cache some common vars to make code more transparent
523    DWORD* pdwFileAttributes;
524    DWORD* pnFileSizeHigh;
525    DWORD* pnFileSizeLow;
526    FILETIME* pftLastAccessTime;
527    FILETIME* pftLastWriteTime;
528    FILETIME* pftCreationTime;
529
530    if (file[1] == ':' && file[2] == 0) {
531         d_msg(__FILE__, __LINE__, 99, "faking ROOT attrs(%s).\n", file);
532         sb->st_mode = S_IFDIR;
533         sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
534         time(&sb->st_ctime);
535         time(&sb->st_mtime);
536         time(&sb->st_atime);
537         return 0;
538     }
539
540    HANDLE h = INVALID_HANDLE_VALUE;
541
542    // use unicode or ascii
543    if (p_FindFirstFileW) {
544       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
545       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
546
547       h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
548       free_pool_memory(pwszBuf);
549
550       pdwFileAttributes = &info_w.dwFileAttributes;
551       pnFileSizeHigh    = &info_w.nFileSizeHigh;
552       pnFileSizeLow     = &info_w.nFileSizeLow;
553       pftLastAccessTime = &info_w.ftLastAccessTime;
554       pftLastWriteTime  = &info_w.ftLastWriteTime;
555       pftCreationTime   = &info_w.ftCreationTime;
556    }
557    else if (p_FindFirstFileA) {
558       h = p_FindFirstFileA(file, &info_a);
559
560       pdwFileAttributes = &info_a.dwFileAttributes;
561       pnFileSizeHigh    = &info_a.nFileSizeHigh;
562       pnFileSizeLow     = &info_a.nFileSizeLow;
563       pftLastAccessTime = &info_a.ftLastAccessTime;
564       pftLastWriteTime  = &info_a.ftLastWriteTime;
565       pftCreationTime   = &info_a.ftCreationTime;
566    }
567
568     if (h == INVALID_HANDLE_VALUE) {
569         const char *err = errorString();
570         d_msg(__FILE__, __LINE__, 99, "FindFirstFile(%s):%s\n", file, err);
571         LocalFree((void *)err);
572         errno = b_errno_win32;
573         return -1;
574     }
575
576     sb->st_mode = 0777;               /* start with everything */
577     if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
578         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
579     if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
580         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
581     if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
582         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
583     sb->st_mode |= S_IFDIR;
584
585     sb->st_size = *pnFileSizeHigh;
586     sb->st_size <<= 32;
587     sb->st_size |= *pnFileSizeLow;
588     sb->st_blksize = 4096;
589     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
590
591     sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
592     sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
593     sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
594     FindClose(h);
595
596     return 0;
597 }
598
599 static int
600 stat2(const char *file, struct stat *sb)
601 {
602     BY_HANDLE_FILE_INFORMATION info;
603     HANDLE h;
604     int rval = 0;
605     char tmpbuf[1024];
606     conv_unix_to_win32_path(file, tmpbuf, 1024);
607
608     DWORD attr = (DWORD)-1;
609
610     if (p_GetFileAttributesW) {
611       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
612       make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
613
614       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
615       free_pool_memory(pwszBuf);
616     } else if (p_GetFileAttributesA) {
617        attr = p_GetFileAttributesA(tmpbuf);
618     }
619
620     if (attr == -1) {
621         const char *err = errorString();
622         d_msg(__FILE__, __LINE__, 99,
623               "GetFileAttributes(%s): %s\n", tmpbuf, err);
624         LocalFree((void *)err);
625         errno = b_errno_win32;
626         return -1;
627     }
628
629     if (attr & FILE_ATTRIBUTE_DIRECTORY)
630         return statDir(tmpbuf, sb);
631
632     h = CreateFileA(tmpbuf, GENERIC_READ,
633                    FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
634
635     if (h == INVALID_HANDLE_VALUE) {
636         const char *err = errorString();
637         d_msg(__FILE__, __LINE__, 99,
638               "Cannot open file for stat (%s):%s\n", tmpbuf, err);
639         LocalFree((void *)err);
640         rval = -1;
641         errno = b_errno_win32;
642         goto error;
643     }
644
645     if (!GetFileInformationByHandle(h, &info)) {
646         const char *err = errorString();
647         d_msg(__FILE__, __LINE__, 99,
648               "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
649         LocalFree((void *)err);
650         rval = -1;
651         errno = b_errno_win32;
652         goto error;
653     }
654
655     sb->st_dev = info.dwVolumeSerialNumber;
656     sb->st_ino = info.nFileIndexHigh;
657     sb->st_ino <<= 32;
658     sb->st_ino |= info.nFileIndexLow;
659     sb->st_nlink = (short)info.nNumberOfLinks;
660     if (sb->st_nlink > 1) {
661        d_msg(__FILE__, __LINE__, 99,  "st_nlink=%d\n", sb->st_nlink);
662     }
663
664     sb->st_mode = 0777;               /* start with everything */
665     if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
666         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
667     if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
668         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
669     if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
670         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
671     sb->st_mode |= S_IFREG;
672
673     sb->st_size = info.nFileSizeHigh;
674     sb->st_size <<= 32;
675     sb->st_size |= info.nFileSizeLow;
676     sb->st_blksize = 4096;
677     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
678     sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
679     sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
680     sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
681
682 error:
683     CloseHandle(h);
684     return rval;
685 }
686
687 int
688 stat(const char *file, struct stat *sb)
689 {
690    WIN32_FILE_ATTRIBUTE_DATA data;
691    errno = 0;
692
693
694    memset(sb, 0, sizeof(*sb));
695
696    /* why not allow win 95 to use p_GetFileAttributesExA ? 
697     * this function allows _some_ open files to be stat'ed 
698     * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
699     *    return stat2(file, sb);
700     * }
701     */
702
703    if (p_GetFileAttributesExW) {
704       /* dynamically allocate enough space for UCS2 filename */
705       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
706       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
707
708       BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
709       free_pool_memory(pwszBuf);
710
711       if (!b) {
712          return stat2(file, sb);
713       }
714    } else if (p_GetFileAttributesExA) {
715       if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
716          return stat2(file, sb);
717        }
718    } else {
719       return stat2(file, sb);
720    }
721
722    sb->st_mode = 0777;               /* start with everything */
723    if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
724       sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
725    }
726    if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
727       sb->st_mode &= ~S_IRWXO; /* remove everything for other */
728    }
729    if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
730       sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
731    }
732    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
733       sb->st_mode |= S_IFDIR;
734    } else {
735       sb->st_mode |= S_IFREG;
736    }
737
738    sb->st_nlink = 1;
739    sb->st_size = data.nFileSizeHigh;
740    sb->st_size <<= 32;
741    sb->st_size |= data.nFileSizeLow;
742    sb->st_blksize = 4096;
743    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
744    sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
745    sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
746    sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
747    return 0;
748 }
749
750 int
751 lstat(const char *file, struct stat *sb)
752 {
753    return stat(file, sb);
754 }
755
756 void
757 sleep(int sec)
758 {
759    Sleep(sec * 1000);
760 }
761
762 int
763 geteuid(void)
764 {
765    return 0;
766 }
767
768 int
769 execvp(const char *, char *[]) {
770    errno = ENOSYS;
771    return -1;
772 }
773
774
775 int
776 fork(void)
777 {
778    errno = ENOSYS;
779    return -1;
780 }
781
782 int
783 pipe(int[])
784 {
785    errno = ENOSYS;
786    return -1;
787 }
788
789 int
790 waitpid(int, int*, int)
791 {
792    errno = ENOSYS;
793    return -1;
794 }
795
796 int
797 readlink(const char *, char *, int)
798 {
799    errno = ENOSYS;
800    return -1;
801 }
802
803
804 #ifndef HAVE_MINGW
805 int
806 strcasecmp(const char *s1, const char *s2)
807 {
808    register int ch1, ch2;
809
810    if (s1==s2)
811       return 0;       /* strings are equal if same object. */
812    else if (!s1)
813       return -1;
814    else if (!s2)
815       return 1;
816    do {
817       ch1 = *s1;
818       ch2 = *s2;
819       s1++;
820       s2++;
821    } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
822
823    return(ch1 - ch2);
824 }
825 #endif //HAVE_MINGW
826
827 int
828 strncasecmp(const char *s1, const char *s2, int len)
829 {
830     register int ch1, ch2;
831
832     if (s1==s2)
833         return 0;       /* strings are equal if same object. */
834     else if (!s1)
835         return -1;
836     else if (!s2)
837         return 1;
838     while (len--) {
839         ch1 = *s1;
840         ch2 = *s2;
841         s1++;
842         s2++;
843         if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
844     }
845
846     return (ch1 - ch2);
847 }
848
849 int
850 gettimeofday(struct timeval *tv, struct timezone *)
851 {
852     SYSTEMTIME now;
853     FILETIME tmp;
854     GetSystemTime(&now);
855
856     if (tv == NULL) {
857        errno = EINVAL;
858        return -1;
859     }
860     if (!SystemTimeToFileTime(&now, &tmp)) {
861        errno = b_errno_win32;
862        return -1;
863     }
864
865     int64_t _100nsec = tmp.dwHighDateTime;
866     _100nsec <<= 32;
867     _100nsec |= tmp.dwLowDateTime;
868     _100nsec -= WIN32_FILETIME_ADJUST;
869
870     tv->tv_sec =(long) (_100nsec / 10000000);
871     tv->tv_usec = (long) ((_100nsec % 10000000)/10);
872     return 0;
873
874 }
875
876 /* For apcupsd this is in src/lib/wincompat.c */
877 #ifndef __APCUPSD__
878 extern "C" void syslog(int type, const char *fmt, ...) 
879 {
880 /*#ifndef HAVE_CONSOLE
881     MessageBox(NULL, msg, "Bacula", MB_OK);
882 #endif*/
883 }
884 #endif
885
886 struct passwd *
887 getpwuid(uid_t)
888 {
889     return NULL;
890 }
891
892 struct group *
893 getgrgid(uid_t)
894 {
895     return NULL;
896 }
897
898 // implement opendir/readdir/closedir on top of window's API
899
900 typedef struct _dir
901 {
902     WIN32_FIND_DATAA data_a;    // window's file info (ansii version)
903     WIN32_FIND_DATAW data_w;    // window's file info (wchar version)
904     const char *spec;           // the directory we're traversing
905     HANDLE      dirh;           // the search handle
906     BOOL        valid_a;        // the info in data_a field is valid
907     BOOL        valid_w;        // the info in data_w field is valid
908     UINT32      offset;         // pseudo offset for d_off
909 } _dir;
910
911 DIR *
912 opendir(const char *path)
913 {
914     /* enough space for VSS !*/
915     int max_len = strlen(path) + MAX_PATH;
916     _dir *rval = NULL;
917     if (path == NULL) {
918        errno = ENOENT;
919        return NULL;
920     }
921
922     rval = (_dir *)malloc(sizeof(_dir));
923     memset (rval, 0, sizeof (_dir));
924     if (rval == NULL) return NULL;
925     char *tspec = (char *)malloc(max_len);
926     if (tspec == NULL) return NULL;
927
928     if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
929 #ifdef WIN32_VSS
930        /* will append \\?\ at front itself */
931        conv_unix_to_win32_path(path, tspec, max_len-4);
932 #else
933        /* allow path to be 32767 bytes */
934        tspec[0] = '\\';
935        tspec[1] = '\\';
936        tspec[2] = '?';
937        tspec[3] = '\\';
938        tspec[4] = 0;
939        conv_unix_to_win32_path(path, tspec+4, max_len-4);
940 #endif
941     } else {
942        conv_unix_to_win32_path(path, tspec, max_len);
943     }
944
945     // add backslash only if there is none yet (think of c:\)
946     if (tspec[strlen(tspec)-1] != '\\')
947       bstrncat(tspec, "\\*", max_len);
948     else
949       bstrncat(tspec, "*", max_len);
950
951     rval->spec = tspec;
952
953     // convert to wchar_t
954     if (p_FindFirstFileW) {
955       POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
956       make_win32_path_UTF8_2_wchar(&pwcBuf,rval->spec);
957
958       rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
959
960       free_pool_memory(pwcBuf);
961
962       if (rval->dirh != INVALID_HANDLE_VALUE)
963         rval->valid_w = 1;
964     } else if (p_FindFirstFileA) {
965       rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
966
967       if (rval->dirh != INVALID_HANDLE_VALUE)
968         rval->valid_a = 1;
969     } else goto err;
970
971
972     d_msg(__FILE__, __LINE__,
973           99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
974           path, rval->spec, rval->dirh);
975
976     rval->offset = 0;
977     if (rval->dirh == INVALID_HANDLE_VALUE)
978         goto err;
979
980     if (rval->valid_w)
981       d_msg(__FILE__, __LINE__,
982             99, "\tFirstFile=%s\n", rval->data_w.cFileName);
983
984     if (rval->valid_a)
985       d_msg(__FILE__, __LINE__,
986             99, "\tFirstFile=%s\n", rval->data_a.cFileName);
987
988     return (DIR *)rval;
989
990 err:
991     free((void *)rval->spec);
992     free(rval);
993     errno = b_errno_win32;
994     return NULL;
995 }
996
997 int
998 closedir(DIR *dirp)
999 {
1000     _dir *dp = (_dir *)dirp;
1001     FindClose(dp->dirh);
1002     free((void *)dp->spec);
1003     free((void *)dp);
1004     return 0;
1005 }
1006
1007 /*
1008   typedef struct _WIN32_FIND_DATA {
1009     DWORD dwFileAttributes;
1010     FILETIME ftCreationTime;
1011     FILETIME ftLastAccessTime;
1012     FILETIME ftLastWriteTime;
1013     DWORD nFileSizeHigh;
1014     DWORD nFileSizeLow;
1015     DWORD dwReserved0;
1016     DWORD dwReserved1;
1017     TCHAR cFileName[MAX_PATH];
1018     TCHAR cAlternateFileName[14];
1019 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1020 */
1021
1022 static int
1023 copyin(struct dirent &dp, const char *fname)
1024 {
1025     dp.d_ino = 0;
1026     dp.d_reclen = 0;
1027     char *cp = dp.d_name;
1028     while (*fname) {
1029         *cp++ = *fname++;
1030         dp.d_reclen++;
1031     }
1032         *cp = 0;
1033     return dp.d_reclen;
1034 }
1035
1036 int
1037 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1038 {
1039     _dir *dp = (_dir *)dirp;
1040     if (dp->valid_w || dp->valid_a) {
1041       entry->d_off = dp->offset;
1042
1043       // copy unicode
1044       if (dp->valid_w) {
1045          char szBuf[MAX_PATH_UTF8+1];
1046          wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1047          dp->offset += copyin(*entry, szBuf);
1048       } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1049          dp->offset += copyin(*entry, dp->data_a.cFileName);
1050       }
1051
1052       *result = entry;              /* return entry address */
1053       d_msg(__FILE__, __LINE__,
1054             99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1055             dirp, entry->d_name, entry->d_reclen, entry->d_off);
1056     } else {
1057 //      d_msg(__FILE__, __LINE__, 99, "readdir_r !valid\n");
1058         errno = b_errno_win32;
1059         return -1;
1060     }
1061
1062     // get next file, try unicode first
1063     if (p_FindNextFileW)
1064        dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1065     else if (p_FindNextFileA)
1066        dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1067     else {
1068        dp->valid_a = FALSE;
1069        dp->valid_w = FALSE;
1070     }
1071
1072     return 0;
1073 }
1074
1075 /*
1076  * Dotted IP address to network address
1077  *
1078  * Returns 1 if  OK
1079  *         0 on error
1080  */
1081 int
1082 inet_aton(const char *a, struct in_addr *inp)
1083 {
1084    const char *cp = a;
1085    uint32_t acc = 0, tmp = 0;
1086    int dotc = 0;
1087
1088    if (!isdigit(*cp)) {         /* first char must be digit */
1089       return 0;                 /* error */
1090    }
1091    do {
1092       if (isdigit(*cp)) {
1093          tmp = (tmp * 10) + (*cp -'0');
1094       } else if (*cp == '.' || *cp == 0) {
1095          if (tmp > 255) {
1096             return 0;           /* error */
1097          }
1098          acc = (acc << 8) + tmp;
1099          dotc++;
1100          tmp = 0;
1101       } else {
1102          return 0;              /* error */
1103       }
1104    } while (*cp++ != 0);
1105    if (dotc != 4) {              /* want 3 .'s plus EOS */
1106       return 0;                  /* error */
1107    }
1108    inp->s_addr = htonl(acc);     /* store addr in network format */
1109    return 1;
1110 }
1111
1112 int
1113 nanosleep(const struct timespec *req, struct timespec *rem)
1114 {
1115     if (rem)
1116         rem->tv_sec = rem->tv_nsec = 0;
1117     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1118     return 0;
1119 }
1120
1121 void
1122 init_signals(void terminate(int sig))
1123 {
1124
1125 }
1126
1127 void
1128 init_stack_dump(void)
1129 {
1130
1131 }
1132
1133
1134 long
1135 pathconf(const char *path, int name)
1136 {
1137     switch(name) {
1138     case _PC_PATH_MAX :
1139         if (strncmp(path, "\\\\?\\", 4) == 0)
1140             return 32767;
1141     case _PC_NAME_MAX :
1142         return 255;
1143     }
1144     errno = ENOSYS;
1145     return -1;
1146 }
1147
1148 int
1149 WSA_Init(void)
1150 {
1151     WORD wVersionRequested = MAKEWORD( 1, 1);
1152     WSADATA wsaData;
1153
1154     int err = WSAStartup(wVersionRequested, &wsaData);
1155
1156
1157     if (err != 0) {
1158         printf("Can not start Windows Sockets\n");
1159         errno = ENOSYS;
1160         return -1;
1161     }
1162
1163     return 0;
1164 }
1165
1166
1167 int
1168 win32_chdir(const char *dir)
1169 {
1170    if (p_SetCurrentDirectoryW) {
1171       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1172       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1173
1174       BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1175       
1176       free_pool_memory(pwszBuf);
1177
1178       if (!b) {
1179          errno = b_errno_win32;
1180          return -1;
1181       }
1182    }
1183    else if (p_SetCurrentDirectoryA) {
1184       if (0 == p_SetCurrentDirectoryA(dir)) {
1185          errno = b_errno_win32;
1186          return -1;
1187       }
1188    }
1189    else return -1;
1190
1191    return 0;
1192 }
1193
1194 int
1195 win32_mkdir(const char *dir)
1196 {
1197    if (p_wmkdir){
1198       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1199       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1200
1201       int n = p_wmkdir((LPCWSTR)pwszBuf);
1202       free_pool_memory(pwszBuf);
1203       return n;
1204    }
1205
1206    return _mkdir(dir);
1207 }
1208
1209
1210 char *
1211 win32_getcwd(char *buf, int maxlen)
1212 {
1213    int n=0;
1214
1215    if (p_GetCurrentDirectoryW) {
1216       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1217       pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1218
1219       n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1220       if (n!=0)
1221          n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1222       free_pool_memory(pwszBuf);
1223
1224    } else if (p_GetCurrentDirectoryA)
1225       n = p_GetCurrentDirectoryA(maxlen, buf);
1226
1227    if (n == 0 || n > maxlen) return NULL;
1228
1229    if (n+1 > maxlen) return NULL;
1230    if (n != 3) {
1231        buf[n] = '\\';
1232        buf[n+1] = 0;
1233    }
1234    return buf;
1235 }
1236
1237 int
1238 win32_fputs(const char *string, FILE *stream)
1239 {
1240    /* we use WriteConsoleA / WriteConsoleA
1241       so we can be sure that unicode support works on win32.
1242       with fallback if something fails
1243    */
1244
1245    HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1246    if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1247        p_MultiByteToWideChar && (stream == stdout)) {
1248
1249       POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1250
1251       DWORD dwCharsWritten;
1252       DWORD dwChars;
1253
1254       dwChars = UTF8_2_wchar(&pwszBuf, string);
1255
1256       /* try WriteConsoleW */
1257       if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1258          free_pool_memory(pwszBuf);
1259          return dwCharsWritten;
1260       }
1261
1262       /* convert to local codepage and try WriteConsoleA */
1263       POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1264       pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1265
1266       dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1267       free_pool_memory(pwszBuf);
1268
1269       if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1270          free_pool_memory(pszBuf);
1271          return dwCharsWritten;
1272       }
1273    }
1274
1275    return fputs(string, stream);
1276 }
1277
1278 char*
1279 win32_cgets (char* buffer, int len)
1280 {
1281    /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1282       from the win32 console and fallback if seomething fails */
1283
1284    HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1285    if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1286       DWORD dwRead;
1287       wchar_t wszBuf[1024];
1288       char  szBuf[1024];
1289
1290       /* nt and unicode conversion */
1291       if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1292
1293          /* null terminate at end */
1294          if (wszBuf[dwRead-1] == L'\n') {
1295             wszBuf[dwRead-1] = L'\0';
1296             dwRead --;
1297          }
1298
1299          if (wszBuf[dwRead-1] == L'\r') {
1300             wszBuf[dwRead-1] = L'\0';
1301             dwRead --;
1302          }
1303
1304          wchar_2_UTF8(buffer, wszBuf, len);
1305          return buffer;
1306       }
1307
1308       /* win 9x and unicode conversion */
1309       if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1310
1311          /* null terminate at end */
1312          if (szBuf[dwRead-1] == L'\n') {
1313             szBuf[dwRead-1] = L'\0';
1314             dwRead --;
1315          }
1316
1317          if (szBuf[dwRead-1] == L'\r') {
1318             szBuf[dwRead-1] = L'\0';
1319             dwRead --;
1320          }
1321
1322          /* convert from ansii to wchar_t */
1323          p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1324          /* convert from wchar_t to UTF-8 */
1325          if (wchar_2_UTF8(buffer, wszBuf, len))
1326             return buffer;
1327       }
1328    }
1329
1330    /* fallback */
1331    if (fgets(buffer, len, stdin))
1332       return buffer;
1333    else
1334       return NULL;
1335 }
1336
1337 int
1338 win32_unlink(const char *filename)
1339 {
1340    int nRetCode;
1341    if (p_wunlink) {
1342       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1343       make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1344
1345       nRetCode = _wunlink((LPCWSTR) pwszBuf);
1346
1347       /* special case if file is readonly,
1348       we retry but unset attribute before */
1349       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1350          DWORD dwAttr =  p_GetFileAttributesW((LPCWSTR)pwszBuf);
1351          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1352             if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1353                nRetCode = _wunlink((LPCWSTR) pwszBuf);
1354                /* reset to original if it didn't help */
1355                if (nRetCode == -1)
1356                   p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1357             }
1358          }
1359       }
1360       free_pool_memory(pwszBuf);
1361    } else {
1362       nRetCode = _unlink(filename);
1363
1364       /* special case if file is readonly,
1365       we retry but unset attribute before */
1366       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1367          DWORD dwAttr =  p_GetFileAttributesA(filename);
1368          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1369             if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1370                nRetCode = _unlink(filename);
1371                /* reset to original if it didn't help */
1372                if (nRetCode == -1)
1373                   p_SetFileAttributesA(filename, dwAttr);
1374             }
1375          }
1376       }
1377    }
1378    return nRetCode;
1379 }
1380
1381
1382 #include "mswinver.h"
1383
1384 char WIN_VERSION_LONG[64];
1385 char WIN_VERSION[32];
1386 char WIN_RAWVERSION[32];
1387
1388 class winver {
1389 public:
1390     winver(void);
1391 };
1392
1393 static winver INIT;                     // cause constructor to be called before main()
1394
1395
1396 winver::winver(void)
1397 {
1398     const char *version = "";
1399     const char *platform = "";
1400     OSVERSIONINFO osvinfo;
1401     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1402
1403     // Get the current OS version
1404     if (!GetVersionEx(&osvinfo)) {
1405         version = "Unknown";
1406         platform = "Unknown";
1407     }
1408         const int ver = _mkversion(osvinfo.dwPlatformId,
1409                                    osvinfo.dwMajorVersion,
1410                                    osvinfo.dwMinorVersion);
1411         snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1412          switch (ver)
1413         {
1414         case MS_WINDOWS_95: (version =  "Windows 95"); break;
1415         case MS_WINDOWS_98: (version =  "Windows 98"); break;
1416         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
1417         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
1418         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
1419         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
1420         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
1421         default: version = WIN_RAWVERSION; break;
1422         }
1423
1424     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1425     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %d.%d.%d",
1426              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1427
1428 #if 0
1429     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1430     CloseHandle(h);
1431 #endif
1432 #if 0
1433     BPIPE *b = open_bpipe("ls -l", 10, "r");
1434     char buf[1024];
1435     while (!feof(b->rfd)) {
1436         fgets(buf, sizeof(buf), b->rfd);
1437     }
1438     close_bpipe(b);
1439 #endif
1440 }
1441
1442 BOOL CreateChildProcess(VOID);
1443 VOID WriteToPipe(VOID);
1444 VOID ReadFromPipe(VOID);
1445 VOID ErrorExit(LPCSTR);
1446 VOID ErrMsg(LPTSTR, BOOL);
1447
1448 /**
1449  * Check for a quoted path,  if an absolute path name is given and it contains
1450  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
1451  * CreateProcess() says the best way to ensure proper results with executables
1452  * with spaces in path or filename is to quote the string.
1453  */
1454 const char *
1455 getArgv0(const char *cmdline)
1456 {
1457
1458     int inquote = 0;
1459     const char *cp;
1460     for (cp = cmdline; *cp; cp++)
1461     {
1462         if (*cp == '"') {
1463             inquote = !inquote;
1464         }
1465         if (!inquote && isspace(*cp))
1466             break;
1467     }
1468
1469
1470     int len = cp - cmdline;
1471     char *rval = (char *)malloc(len+1);
1472
1473     cp = cmdline;
1474     char *rp = rval;
1475
1476     while (len--)
1477         *rp++ = *cp++;
1478
1479     *rp = 0;
1480     return rval;
1481 }
1482
1483
1484 /**
1485  * OK, so it would seem CreateProcess only handles true executables:
1486  *  .com or .exe files.
1487  * So test to see whether we're getting a .bat file and if so grab
1488  * $COMSPEC value and pass batch file to it.
1489  */
1490 HANDLE
1491 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1492 {
1493     static const char *comspec = NULL;
1494     PROCESS_INFORMATION piProcInfo;
1495     STARTUPINFOA siStartInfo;
1496     BOOL bFuncRetn = FALSE;
1497
1498     if (comspec == NULL) {
1499        comspec = getenv("COMSPEC");
1500     }
1501     if (comspec == NULL) // should never happen
1502         return INVALID_HANDLE_VALUE;
1503
1504     // Set up members of the PROCESS_INFORMATION structure.
1505     ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1506
1507     // Set up members of the STARTUPINFO structure.
1508
1509     ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1510     siStartInfo.cb = sizeof(STARTUPINFO);
1511     // setup new process to use supplied handles for stdin,stdout,stderr
1512     // if supplied handles are not used the send a copy of our STD_HANDLE
1513     // as appropriate
1514     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
1515
1516     if (in != INVALID_HANDLE_VALUE)
1517         siStartInfo.hStdInput = in;
1518     else
1519         siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1520
1521     if (out != INVALID_HANDLE_VALUE)
1522         siStartInfo.hStdOutput = out;
1523     else
1524         siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1525     if (err != INVALID_HANDLE_VALUE)
1526         siStartInfo.hStdError = err;
1527     else
1528         siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1529     // Create the child process.
1530
1531     char exeFile[256];
1532     int cmdLen = strlen(cmdline) + strlen(comspec) + 16;
1533
1534     char *cmdLine = (char *)alloca(cmdLen);
1535
1536     bstrncpy(exeFile, comspec, sizeof(exeFile));
1537     bstrncpy(cmdLine, comspec, cmdLen);
1538     bstrncat(cmdLine, " /c ", cmdLen);
1539     bstrncat(cmdLine, cmdline, cmdLen);
1540
1541     // try to execute program
1542     bFuncRetn = CreateProcessA(exeFile,
1543                               cmdLine, // command line
1544                               NULL, // process security attributes
1545                               NULL, // primary thread security attributes
1546                               TRUE, // handles are inherited
1547                               0, // creation flags
1548                               NULL, // use parent's environment
1549                               NULL, // use parent's current directory
1550                               &siStartInfo, // STARTUPINFO pointer
1551                               &piProcInfo); // receives PROCESS_INFORMATION
1552
1553     if (bFuncRetn == 0) {
1554         ErrorExit("CreateProcess failed\n");
1555         const char *err = errorString();
1556         d_msg(__FILE__, __LINE__, 99,
1557               "CreateProcess(%s, %s, ...)=%s\n", exeFile, cmdLine, err);
1558         LocalFree((void *)err);
1559         return INVALID_HANDLE_VALUE;
1560     }
1561     // we don't need a handle on the process primary thread so we close
1562     // this now.
1563     CloseHandle(piProcInfo.hThread);
1564
1565     return piProcInfo.hProcess;
1566 }
1567
1568
1569 void
1570 ErrorExit (LPCSTR lpszMessage)
1571 {
1572     d_msg(__FILE__, __LINE__, 0, "%s", lpszMessage);
1573 }
1574
1575
1576 /*
1577 typedef struct s_bpipe {
1578    pid_t worker_pid;
1579    time_t worker_stime;
1580    int wait;
1581    btimer_t *timer_id;
1582    FILE *rfd;
1583    FILE *wfd;
1584 } BPIPE;
1585 */
1586
1587 static void
1588 CloseIfValid(HANDLE handle)
1589 {
1590     if (handle != INVALID_HANDLE_VALUE)
1591         CloseHandle(handle);
1592 }
1593
1594 #ifndef HAVE_MINGW
1595 BPIPE *
1596 open_bpipe(char *prog, int wait, const char *mode)
1597 {
1598     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1599         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1600         hInputFile;
1601
1602     SECURITY_ATTRIBUTES saAttr;
1603
1604     BOOL fSuccess;
1605
1606     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1607         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1608         hInputFile = INVALID_HANDLE_VALUE;
1609
1610     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1611     memset((void *)bpipe, 0, sizeof(BPIPE));
1612
1613     int mode_read = (mode[0] == 'r');
1614     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1615
1616
1617     // Set the bInheritHandle flag so pipe handles are inherited.
1618
1619     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1620     saAttr.bInheritHandle = TRUE;
1621     saAttr.lpSecurityDescriptor = NULL;
1622
1623     if (mode_read) {
1624
1625         // Create a pipe for the child process's STDOUT.
1626         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1627             ErrorExit("Stdout pipe creation failed\n");
1628             goto cleanup;
1629         }
1630         // Create noninheritable read handle and close the inheritable read
1631         // handle.
1632
1633         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1634                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
1635                                    FALSE,
1636                                    DUPLICATE_SAME_ACCESS);
1637         if ( !fSuccess ) {
1638             ErrorExit("DuplicateHandle failed");
1639             goto cleanup;
1640         }
1641
1642         CloseHandle(hChildStdoutRd);
1643         hChildStdoutRd = INVALID_HANDLE_VALUE;
1644     }
1645
1646     if (mode_write) {
1647
1648         // Create a pipe for the child process's STDIN.
1649
1650         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1651             ErrorExit("Stdin pipe creation failed\n");
1652             goto cleanup;
1653         }
1654
1655         // Duplicate the write handle to the pipe so it is not inherited.
1656         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1657                                    GetCurrentProcess(), &hChildStdinWrDup,
1658                                    0,
1659                                    FALSE,                  // not inherited
1660                                    DUPLICATE_SAME_ACCESS);
1661         if (!fSuccess) {
1662             ErrorExit("DuplicateHandle failed");
1663             goto cleanup;
1664         }
1665
1666         CloseHandle(hChildStdinWr);
1667         hChildStdinWr = INVALID_HANDLE_VALUE;
1668     }
1669     // spawn program with redirected handles as appropriate
1670     bpipe->worker_pid = (pid_t)
1671         CreateChildProcess(prog,             // commandline
1672                            hChildStdinRd,    // stdin HANDLE
1673                            hChildStdoutWr,   // stdout HANDLE
1674                            hChildStdoutWr);  // stderr HANDLE
1675
1676     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1677         goto cleanup;
1678
1679     bpipe->wait = wait;
1680     bpipe->worker_stime = time(NULL);
1681
1682     if (mode_read) {
1683         CloseHandle(hChildStdoutWr); // close our write side so when
1684                                      // process terminates we can
1685                                      // detect eof.
1686         // ugly but convert WIN32 HANDLE to FILE*
1687         int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1688         if (rfd >= 0) {
1689            bpipe->rfd = _fdopen(rfd, "r");
1690         }
1691     }
1692     if (mode_write) {
1693         CloseHandle(hChildStdinRd); // close our read side so as not
1694                                     // to interfre with child's copy
1695         // ugly but convert WIN32 HANDLE to FILE*
1696         int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY);
1697         if (wfd >= 0) {
1698            bpipe->wfd = _fdopen(wfd, "w");
1699         }
1700     }
1701
1702     if (wait > 0) {
1703         bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1704     }
1705
1706     return bpipe;
1707
1708 cleanup:
1709
1710     CloseIfValid(hChildStdoutRd);
1711     CloseIfValid(hChildStdoutRdDup);
1712     CloseIfValid(hChildStdinWr);
1713     CloseIfValid(hChildStdinWrDup);
1714
1715     free((void *) bpipe);
1716     errno = b_errno_win32;            /* do GetLastError() for error code */
1717     return NULL;
1718 }
1719
1720 #endif //HAVE_MINGW
1721
1722 int
1723 kill(int pid, int signal)
1724 {
1725    int rval = 0;
1726    if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
1727       rval = -1;
1728       errno = b_errno_win32;
1729    }
1730    CloseHandle((HANDLE)pid);
1731    return rval;
1732 }
1733
1734 #ifndef HAVE_MINGW
1735
1736 int
1737 close_bpipe(BPIPE *bpipe)
1738 {
1739    int rval = 0;
1740    int32_t remaining_wait = bpipe->wait;
1741
1742    if (remaining_wait == 0) {         /* wait indefinitely */
1743       remaining_wait = INT32_MAX;
1744    }
1745    for ( ;; ) {
1746       DWORD exitCode;
1747       if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
1748          const char *err = errorString();
1749          rval = b_errno_win32;
1750          d_msg(__FILE__, __LINE__, 0,
1751                "GetExitCode error %s\n", err);
1752          LocalFree((void *)err);
1753          break;
1754       }
1755       if (exitCode == STILL_ACTIVE) {
1756          if (remaining_wait <= 0) {
1757             rval = ETIME;             /* timed out */
1758             break;
1759          }
1760          bmicrosleep(1, 0);           /* wait one second */
1761          remaining_wait--;
1762       } else if (exitCode != 0) {
1763          /* Truncate exit code as it doesn't seem to be correct */
1764          rval = (exitCode & 0xFF) | b_errno_exit;
1765          break;
1766       } else {
1767          break;                       /* Shouldn't get here */
1768       }
1769    }
1770
1771    if (bpipe->timer_id) {
1772        stop_child_timer(bpipe->timer_id);
1773    }
1774    if (bpipe->rfd) fclose(bpipe->rfd);
1775    if (bpipe->wfd) fclose(bpipe->wfd);
1776    free((void *)bpipe);
1777    return rval;
1778 }
1779
1780 int
1781 close_wpipe(BPIPE *bpipe)
1782 {
1783     int stat = 1;
1784
1785     if (bpipe->wfd) {
1786         fflush(bpipe->wfd);
1787         if (fclose(bpipe->wfd) != 0) {
1788             stat = 0;
1789         }
1790         bpipe->wfd = NULL;
1791     }
1792     return stat;
1793 }
1794
1795 #include "findlib/find.h"
1796
1797 int
1798 utime(const char *fname, struct utimbuf *times)
1799 {
1800     FILETIME acc, mod;
1801     char tmpbuf[5000];
1802
1803     conv_unix_to_win32_path(fname, tmpbuf, 5000);
1804
1805     cvt_utime_to_ftime(times->actime, acc);
1806     cvt_utime_to_ftime(times->modtime, mod);
1807
1808     HANDLE h = INVALID_HANDLE_VALUE;
1809
1810     if (p_CreateFileW) {
1811       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1812       make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
1813
1814       h = p_CreateFileW((LPCWSTR)pwszBuf,
1815                         FILE_WRITE_ATTRIBUTES,
1816                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1817                         NULL,
1818                         OPEN_EXISTING,
1819                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1820                         NULL);
1821
1822       free_pool_memory(pwszBuf);
1823     } else if (p_CreateFileA) {
1824       h = p_CreateFileA(tmpbuf,
1825                         FILE_WRITE_ATTRIBUTES,
1826                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1827                         NULL,
1828                         OPEN_EXISTING,
1829                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1830                         NULL);
1831     }
1832
1833     if (h == INVALID_HANDLE_VALUE) {
1834         const char *err = errorString();
1835         d_msg(__FILE__, __LINE__, 99,
1836               "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
1837         LocalFree((void *)err);
1838         errno = b_errno_win32;
1839         return -1;
1840     }
1841
1842     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1843     CloseHandle(h);
1844     if (rval == -1) {
1845        errno = b_errno_win32;
1846     }
1847     return rval;
1848 }
1849
1850 #if USE_WIN32_COMPAT_IO
1851
1852 int
1853 open(const char *file, int flags, int mode)
1854 {
1855    if (p_wopen) {
1856       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1857       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
1858
1859       int nRet = p_wopen((LPCWSTR) pwszBuf, flags|_O_BINARY, mode);
1860       free_pool_memory(pwszBuf);
1861
1862       return nRet;
1863    }
1864
1865    return _open(file, flags|_O_BINARY, mode);
1866 }
1867
1868 /*
1869  * Note, this works only for a file. If you want
1870  *   to close a socket, use closesocket().
1871  *   Bacula has been modified in src/lib/bnet.c
1872  *   to use closesocket().
1873  */
1874 #ifndef HAVE_VC8
1875 int
1876 close(int fd)
1877 {
1878     return _close(fd);
1879 }
1880
1881 #ifndef HAVE_WXCONSOLE
1882 ssize_t
1883 read(int fd, void *buf, ssize_t len)
1884 {
1885     return _read(fd, buf, (size_t)len);
1886 }
1887
1888 ssize_t
1889 write(int fd, const void *buf, ssize_t len)
1890 {
1891     return _write(fd, buf, (size_t)len);
1892 }
1893 #endif
1894
1895
1896 off_t
1897 lseek(int fd, off_t offset, int whence)
1898 {
1899     return (off_t)_lseeki64(fd, offset, whence);
1900 }
1901
1902 int
1903 dup2(int fd1, int fd2)
1904 {
1905     return _dup2(fd1, fd2);
1906 }
1907 #endif
1908 #else
1909 int
1910 open(const char *file, int flags, int mode)
1911 {
1912     DWORD access = 0;
1913     DWORD shareMode = 0;
1914     DWORD create = 0;
1915     DWORD msflags = 0;
1916     HANDLE foo = INVALID_HANDLE_VALUE;
1917     const char *remap = file;
1918
1919     if (flags & O_WRONLY) access = GENERIC_WRITE;
1920     else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
1921     else access = GENERIC_READ;
1922
1923     if (flags & O_CREAT) create = CREATE_NEW;
1924     else create = OPEN_EXISTING;
1925
1926     if (flags & O_TRUNC) create = TRUNCATE_EXISTING;
1927
1928     if (!(flags & O_EXCL))
1929         shareMode = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
1930
1931     if (flags & O_APPEND) {
1932         printf("open...APPEND not implemented yet.");
1933         exit(-1);
1934     }
1935
1936     if (p_CreateFileW) {
1937        POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1938        make_win32_path_UTF8_2_wchar(pwszBuf, file);
1939
1940        foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
1941        free_pool_memory(pwszBuf);
1942     } else if (p_CreateFileA)
1943        foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
1944
1945     if (INVALID_HANDLE_VALUE == foo) {
1946         errno = b_errno_win32;
1947         return(int) -1;
1948     }
1949     return (int)foo;
1950
1951 }
1952
1953
1954 int
1955 close(int fd)
1956 {
1957     if (!CloseHandle((HANDLE)fd)) {
1958         errno = b_errno_win32;
1959         return -1;
1960     }
1961
1962     return 0;
1963 }
1964
1965 ssize_t
1966 write(int fd, const void *data, ssize_t len)
1967 {
1968     BOOL status;
1969     DWORD bwrite;
1970     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
1971     if (status) return bwrite;
1972     errno = b_errno_win32;
1973     return -1;
1974 }
1975
1976
1977 ssize_t
1978 read(int fd, void *data, ssize_t len)
1979 {
1980     BOOL status;
1981     DWORD bread;
1982
1983     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
1984     if (status) return bread;
1985     errno = b_errno_win32;
1986     return -1;
1987 }
1988
1989 off_t
1990 lseek(int fd, off_t offset, int whence)
1991 {
1992     DWORD method = 0;
1993     DWORD val;
1994     switch (whence) {
1995     case SEEK_SET :
1996         method = FILE_BEGIN;
1997         break;
1998     case SEEK_CUR:
1999         method = FILE_CURRENT;
2000         break;
2001     case SEEK_END:
2002         method = FILE_END;
2003         break;
2004     default:
2005         errno = EINVAL;
2006         return -1;
2007     }
2008
2009     if ((val=SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method)) == INVALID_SET_FILE_POINTER) {
2010        errno = b_errno_win32;
2011        return -1;
2012     }
2013     /* ***FIXME*** I doubt this works right */
2014     return val;
2015 }
2016
2017 int
2018 dup2(int, int)
2019 {
2020     errno = ENOSYS;
2021     return -1;
2022 }
2023
2024
2025 #endif
2026
2027 #endif //HAVE_MINGW
2028
2029 #ifdef HAVE_MINGW
2030 /* syslog function, added by Nicolas Boichat */
2031 void closelog() {}
2032 void openlog(const char *ident, int option, int facility) {}  
2033 #endif //HAVE_MINGW
2034
2035 /* Temp kludges ***FIXME**** */
2036 #ifdef __APCUPSD__
2037 unsigned int alarm(unsigned int seconds) 
2038 {
2039    return 0;
2040 }
2041 #endif