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