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