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