]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
a324579880bca572ddecceebb4efd417f372a36e
[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 (C)2004 Raider Solutions, Inc
6 // 
7 //   This program is free software; you can redistribute it and/or
8 //   modify it under the terms of the GNU General Public License as
9 //   published by the Free Software Foundation; either version 2 of
10 //   the License, or (at your option) any later version.
11 //
12 //   This program is distributed in the hope that it will be useful,
13 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 //   General Public License for more details.
16 //
17 //   You should have received a copy of the GNU General Public
18 //   License along with this program; if not, write to the Free
19 //   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 //   MA 02111-1307, USA.
21 //
22 // Author          : Christopher S. Hull
23 // Created On      : Sat Jan 31 15:55:00 2004
24 // Last Modified By: Christopher S. Hull
25 // Last Modified On: Sun Feb 22 16:08:54 2004
26 // Update Count    : 659
27 // $Id$
28
29 #include <stdio.h>
30
31 #include "compat.h"
32 #include "pthread.h"
33
34 extern void d_msg(const char *file, int line, int level, const char *fmt,...);
35 extern DWORD   g_platform_id;
36
37 // from CYGWIN (should be diff between Jan 1 1601 and Jan 1 1970
38 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
39
40 #define WIN32_FILETIME_SCALE  10000000             // 100ns/second
41
42 extern "C" void
43 cygwin_conv_to_win32_path(const char *name, char *win32_name)
44 {
45     const char *fname = name;
46     while (*name) {
47         /* Check for Unix separator and convert to Win32 */
48         if (*name == '/') {
49             *win32_name++ = '\\';     /* convert char */
50         /* If Win32 separated that is "quoted", remove quote */
51         } else if (*name == '\\' && name[1] == '\\') {
52             *win32_name++ = '\\';
53             name++;                   /* skip first \ */
54         } else {
55             *win32_name++ = *name;    /* copy character */
56         }
57         name++;
58     }
59     /* Strip any trailing slash, if we stored something */
60     if (*fname != 0 && win32_name[-1] == '\\') {
61         win32_name[-1] = 0;
62     } else {
63         *win32_name = 0;
64     }
65 }
66
67
68 void
69 wchar_win32_path(const char *name, WCHAR *win32_name)
70 {
71     const char *fname = name;
72     while (*name) {
73         /* Check for Unix separator and convert to Win32 */
74         if (*name == '/') {
75             *win32_name++ = '\\';     /* convert char */
76         /* If Win32 separated that is "quoted", remove quote */
77         } else if (*name == '\\' && name[1] == '\\') {
78             *win32_name++ = '\\';
79             name++;                   /* skip first \ */
80         } else {
81             *win32_name++ = *name;    /* copy character */
82         }
83         name++;
84     }
85     /* Strip any trailing slash, if we stored something */
86     if (*fname != 0 && win32_name[-1] == '\\') {
87         win32_name[-1] = 0;
88     } else {
89         *win32_name = 0;
90     }
91 }
92
93
94 int
95 open(const char *file, int flags, int mode)
96 {
97     DWORD access = 0;
98     DWORD shareMode = 0;
99     DWORD create = 0;
100     DWORD msflags = 0;
101     HANDLE foo;
102     const char *remap = file;
103
104     if (flags & O_WRONLY) access = GENERIC_WRITE;
105     else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
106     else access = GENERIC_READ;
107     
108     if (flags & O_CREAT) create = CREATE_NEW;
109     else create = OPEN_EXISTING;
110     
111     if (flags & O_TRUNC) create = TRUNCATE_EXISTING;
112     
113     if (!(flags & O_EXCL))
114         shareMode = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
115     
116     if (flags & O_APPEND)
117     {
118         printf("open...APPEND not implemented yet.");
119         exit(-1);
120     }
121     
122     foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
123     if (INVALID_HANDLE_VALUE == foo)
124         return(int) -1;
125
126     return (int)foo;
127
128 }
129
130
131 int
132 close(int fd)
133 {
134     if (!CloseHandle((HANDLE)fd))
135         return -1;
136
137     return 0;
138 }
139
140 int
141 write(int fd, const void *data, int32_t len)
142 {
143     BOOL status;
144     DWORD bwrite;
145     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
146     if (status) return bwrite;
147     return -1;
148 }
149
150
151 int
152 read(int fd, void *data, int32_t len)
153 {
154     BOOL status;
155     DWORD bread;
156
157     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
158     if (status) return bread;
159
160     return -1;
161 }
162
163 int
164 umask(int)
165 {
166     return 0;
167 }
168
169 int
170 chmod(const char *, mode_t)
171 {
172     return 0;
173 }
174
175 int
176 chown(const char *k, uid_t, gid_t)
177 {
178     return 0;
179 }
180
181 int
182 lchown(const char *k, uid_t, gid_t)
183 {
184     return 0;
185 }
186
187
188
189 long int
190 random(void)
191 {
192     return rand();
193 }
194
195 void
196 srandom(unsigned int seed)
197 {
198     srand(seed);
199 }
200 // /////////////////////////////////////////////////////////////////
201 // convert from Windows concept of time to Unix concept of time
202 // /////////////////////////////////////////////////////////////////
203 void
204 cvt_utime_to_ftime(const time_t  &time, FILETIME &wintime)
205 {
206     uint64_t mstime = time;
207     mstime *= WIN32_FILETIME_SCALE;
208     mstime += WIN32_FILETIME_ADJUST;
209
210     wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
211     wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
212 }
213
214 time_t
215 cvt_ftime_to_utime(const FILETIME &time)
216 {
217     uint64_t mstime = time.dwHighDateTime;
218     mstime <<= 32;
219     mstime |= time.dwLowDateTime;
220
221     mstime -= WIN32_FILETIME_ADJUST;
222     mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
223
224     return (time_t) (mstime & 0xffffffff);
225 }
226
227 static const char *
228 errorString(void)
229 {
230     LPVOID lpMsgBuf;
231
232     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
233                   FORMAT_MESSAGE_FROM_SYSTEM |
234                   FORMAT_MESSAGE_IGNORE_INSERTS,
235                   NULL,
236                   GetLastError(),
237                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
238                   (LPTSTR) &lpMsgBuf,
239                   0,
240                   NULL);
241
242     return (const char *) lpMsgBuf;
243 }
244
245 static int
246 statDir(const char *file, struct stat *sb)
247 {
248     WIN32_FIND_DATA info;       // window's file info
249
250     if (file[1] == ':' && file[2] == 0) {
251         d_msg(__FILE__, __LINE__, 99, "faking ROOT attrs(%s).\n", file);
252         sb->st_mode = S_IFDIR;
253         sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
254         time(&sb->st_ctime);
255         time(&sb->st_mtime);
256         time(&sb->st_atime);
257         return 0;
258     }
259     HANDLE h = FindFirstFile(file, &info);
260
261     if (h == INVALID_HANDLE_VALUE) {
262         const char *err = errorString();
263         d_msg(__FILE__, __LINE__, 99, "FindFirstFile(%s):%s\n", file, err);
264         LocalFree((void *)err);
265         errno = GetLastError();
266         return -1;
267     }
268
269     sb->st_mode = 0777;               /* start with everything */
270     if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
271         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
272     if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
273         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
274     if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
275         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
276     sb->st_mode |= S_IFDIR;
277
278     sb->st_size = info.nFileSizeHigh;
279     sb->st_size <<= 32;
280     sb->st_size |= info.nFileSizeLow;
281     sb->st_blksize = 4096;
282     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
283
284     sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
285     sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
286     sb->st_ctime = cvt_ftime_to_utime(info.ftLastWriteTime);
287     FindClose(h);
288
289     return 0;
290 }
291
292 static int
293 stat2(const char *file, struct stat *sb)
294 {
295     BY_HANDLE_FILE_INFORMATION info;
296     HANDLE h;
297     int rval = 0;
298     char tmpbuf[1024];
299     cygwin_conv_to_win32_path(file, tmpbuf);
300
301     DWORD attr = GetFileAttributes(tmpbuf);
302
303     if (attr == -1) {
304         const char *err = errorString();
305         d_msg(__FILE__, __LINE__, 99,
306               "GetFileAttrubtes(%s): %s\n", tmpbuf, err);
307         LocalFree((void *)err);
308         errno = GetLastError();
309         return -1;
310     }
311     
312     if (attr & FILE_ATTRIBUTE_DIRECTORY) 
313         return statDir(tmpbuf, sb);
314
315     h = CreateFile(tmpbuf, GENERIC_READ,
316                    FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
317
318     if (h == INVALID_HANDLE_VALUE) {
319         const char *err = errorString();
320         d_msg(__FILE__, __LINE__, 99,
321               "Cannot open file for stat (%s):%s\n", tmpbuf, err);
322         LocalFree((void *)err);
323         rval = -1;
324         errno = GetLastError();
325         goto error;
326     }
327     
328     if (!GetFileInformationByHandle(h, &info)) {
329         const char *err = errorString();
330         d_msg(__FILE__, __LINE__, 99,
331               "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
332         LocalFree((void *)err);
333         rval = -1;
334         errno = GetLastError();
335         goto error;
336     }
337     
338     sb->st_dev = info.dwVolumeSerialNumber;
339     sb->st_ino = info.nFileIndexHigh;
340     sb->st_ino <<= 32;
341     sb->st_ino |= info.nFileIndexLow;
342     sb->st_nlink = (short)info.nNumberOfLinks;
343
344     sb->st_mode = 0777;               /* start with everything */
345     if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
346         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
347     if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
348         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
349     if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
350         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
351     sb->st_mode |= S_IFREG;
352
353     sb->st_size = info.nFileSizeHigh;
354     sb->st_size <<= 32;
355     sb->st_size |= info.nFileSizeLow;
356     sb->st_blksize = 4096;
357     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
358     sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
359     sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
360     sb->st_ctime = cvt_ftime_to_utime(info.ftLastWriteTime);
361
362 error:
363     CloseHandle(h);
364     return rval;
365 }
366
367 int
368 stat(const char *file, struct stat *sb)
369 {
370     WIN32_FILE_ATTRIBUTE_DATA data;
371     errno = 0;
372
373
374     memset(sb, 0, sizeof(*sb));
375
376     if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS)
377         return stat2(file, sb);
378
379     // otherwise we're on NT
380 #if 0
381     WCHAR buf[32767];
382     buf[0] = '\\';
383     buf[1] = '\\';
384     buf[2] = '?';
385     buf[3] = '\\';
386
387     wchar_win32_path(file, buf+4);
388
389     if (!GetFileAttributesExW((WCHAR *)buf, GetFileExInfoStandard, &data))
390         return stat2(file, sb);
391 #else
392     if (!GetFileAttributesEx(file, GetFileExInfoStandard, &data))
393         return stat2(file, sb);
394 #endif
395     
396     sb->st_mode = 0777;               /* start with everything */
397     if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
398         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
399     if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
400         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
401     if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
402         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
403
404     if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
405         sb->st_mode |= S_IFDIR;
406     else
407         sb->st_mode |= S_IFREG;
408
409     sb->st_nlink = 1;
410     sb->st_size = data.nFileSizeHigh;
411     sb->st_size <<= 32;
412     sb->st_size |= data.nFileSizeLow;
413     sb->st_blksize = 4096;
414     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
415     sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
416     sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
417     sb->st_ctime = cvt_ftime_to_utime(data.ftLastWriteTime);
418     return 0;
419 }
420
421 int
422 lstat(const char *file, struct stat *sb)
423 {
424     return stat(file, sb);
425 }
426
427 void
428 sleep(int sec)
429 {
430     Sleep(sec * 1000);
431 }    
432
433 int
434 geteuid(void)
435 {
436     return 0;
437 }
438
439 int
440 execvp(const char *, char *[]) {
441     return -1;
442 }
443
444 int
445 dup2(int, int)
446 {
447     return -1;
448 }
449
450 int
451 fork(void)
452 {
453     return -1;
454 }
455
456 int
457 pipe(int[])
458 {
459     return -1;
460 }
461
462 int
463 waitpid(int, int*, int)
464 {
465     return -1;
466 }
467
468 int
469 readlink(const char *, char *, int)
470 {
471     return -1;
472 }
473
474 int
475 lseek(int fd, int offset, int whence)
476 {
477     DWORD method = 0;
478     switch (whence) {
479     case SEEK_SET :
480         method = FILE_BEGIN;
481         break;
482     case SEEK_CUR:
483         method = FILE_CURRENT;
484         break;
485     case SEEK_END:
486         method = FILE_END;
487         break;
488     default:
489         return -1;
490     }
491     
492     return SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method);
493 }
494
495 int
496 strcasecmp(const char *s1, const char *s2)
497 {
498     register int ch1, ch2;
499     
500     if (s1==s2)
501         return 0;       /* strings are equal if same object. */
502     else if (!s1)
503         return -1;
504     else if (!s2)
505         return 1;
506     do
507     {
508         ch1 = *s1;
509         ch2 = *s2;
510         s1++;
511         s2++;
512     } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
513     
514   return(ch1 - ch2);
515 }
516
517 int
518 strncasecmp(const char *s1, const char *s2, int len)
519 {
520     register int ch1, ch2;
521     
522     if (s1==s2)
523         return 0;       /* strings are equal if same object. */
524     else if (!s1)
525         return -1;
526     else if (!s2)
527         return 1;
528     do
529     {
530         ch1 = *s1;
531         ch2 = *s2;
532         s1++;
533         s2++;
534     } while (len-- && ch1 != 0 && tolower(ch1) == tolower(ch2));
535     
536     return(ch1 - ch2);
537 }
538
539 int
540 gettimeofday(struct timeval *tv, struct timezone *)
541 {
542     SYSTEMTIME now;
543     FILETIME tmp;
544     GetSystemTime(&now);
545
546     if (tv == NULL) return -1;
547     if (!SystemTimeToFileTime(&now, &tmp)) return -1;
548
549     int64_t _100nsec = tmp.dwHighDateTime;
550     _100nsec <<= 32;
551     _100nsec |= tmp.dwLowDateTime;
552     _100nsec -= WIN32_FILETIME_ADJUST;
553     
554     tv->tv_sec =(long) (_100nsec / 10000000);
555     tv->tv_usec = (long) ((_100nsec % 10000000)/10);
556     return 0;
557     
558 }
559
560 int
561 syslog(int, const char *, const char *)
562 {
563     return 0;
564 }
565
566 struct passwd *
567 getpwuid(uid_t)
568 {
569     return NULL;
570 }
571
572 struct group *
573 getgrgid(uid_t)
574 {
575     return NULL;
576 }
577
578
579 // implement opendir/readdir/closedir on top of window's API
580 typedef struct _dir
581 {
582     WIN32_FIND_DATA data;       // window's file info
583     const char *spec;           // the directory we're traversing
584     HANDLE      dirh;           // the search handle
585     BOOL        valid;          // the info in data field is valid
586     UINT32      offset;         // pseudo offset for d_off
587 } _dir;
588
589 DIR *
590 opendir(const char *path)
591 {
592     int max_len = strlen(path) + 16;
593     _dir *rval = NULL;
594     if (path == NULL) return NULL;
595     
596     rval = (_dir *)malloc(sizeof(_dir));
597     if (rval == NULL) return NULL;
598     char *tspec = (char *)malloc(max_len);
599     if (tspec == NULL) goto err1;
600     
601     if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
602         // allow path to be 32767 bytes
603         tspec[0] = '\\';
604         tspec[1] = '\\';
605         tspec[2] = '?';
606         tspec[3] = '\\';
607         tspec[4] = 0;
608         cygwin_conv_to_win32_path(path, tspec+4); 
609     } else {
610         cygwin_conv_to_win32_path(path, tspec);
611     }
612     strncat(tspec, "\\*", max_len);
613     rval->spec = tspec;
614
615     rval->dirh = FindFirstFile(rval->spec, &rval->data);
616     d_msg(__FILE__, __LINE__,
617           99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
618           path, rval->spec, rval->dirh);
619
620     rval->offset = 0;
621     if (rval->dirh == INVALID_HANDLE_VALUE)
622         goto err;
623     rval->valid = 1;
624     d_msg(__FILE__, __LINE__,
625           99, "\tFirstFile=%s\n", rval->data.cFileName);
626     return (DIR *)rval;
627 err:
628     free((void *)rval->spec);
629 err1:
630     free(rval);
631     return NULL;
632 }
633     
634 int
635 closedir(DIR *dirp)
636 {
637     _dir *dp = (_dir *)dirp;
638     FindClose(dp->dirh);
639     free((void *)dp->spec);
640     free((void *)dp);
641     return 0;
642 }
643
644 /*
645   typedef struct _WIN32_FIND_DATA {
646     DWORD dwFileAttributes;
647     FILETIME ftCreationTime;
648     FILETIME ftLastAccessTime;
649     FILETIME ftLastWriteTime;
650     DWORD nFileSizeHigh;
651     DWORD nFileSizeLow;
652     DWORD dwReserved0;
653     DWORD dwReserved1;
654     TCHAR cFileName[MAX_PATH];
655     TCHAR cAlternateFileName[14];
656 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
657 */
658
659 static int
660 copyin(struct dirent &dp, const char *fname)
661 {
662     dp.d_ino = 0;
663     dp.d_reclen = 0;
664     char *cp = dp.d_name;
665     while (*fname) {
666         *cp++ = *fname++;
667         dp.d_reclen++;
668     }
669         *cp = 0;
670     return dp.d_reclen;
671 }
672 int
673 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
674 {
675
676     _dir *dp = (_dir *)dirp;
677     if (dp->valid) {
678         entry->d_off = dp->offset;
679         dp->offset += copyin(*entry, dp->data.cFileName);
680         *result = entry;              /* return entry address */
681         d_msg(__FILE__, __LINE__,
682               99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
683               dirp, entry->d_name, entry->d_reclen, entry->d_off);
684     } else {
685 //      d_msg(__FILE__, __LINE__, 99, "readdir_r !valid\n");
686         return -1;
687     }
688     dp->valid = FindNextFile(dp->dirh, &dp->data);
689     return 0;
690 }
691
692
693 int
694 inet_aton(const char *a, struct in_addr *inp)
695 {
696
697     const char *cp = a;
698     uint32_t acc = 0, tmp = 0;
699     int dotc = 0;
700     if (!isdigit(*a)) return 0;
701     while (*cp) {
702         if (isdigit(*cp))
703             tmp = (tmp * 10) + (*cp -'0');
704         else if (*cp == '.') {
705             if (tmp > 255) return 0;
706             acc = (acc << 8) + tmp;
707             dotc++;
708         }
709         else return 0;
710     }
711
712     if (dotc != 3) return 0;
713     inp->s_addr = acc;
714     return 1;
715 }
716
717 int
718 nanosleep(const struct timespec *req, struct timespec *rem)
719 {
720     if (rem)
721         rem->tv_sec = rem->tv_nsec = 0;
722     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
723     return 0;
724 }
725
726 void
727 init_signals(void terminate(int sig))
728 {
729
730 }
731
732 void
733 init_stack_dump(void)
734 {
735
736 }
737
738
739 long
740 pathconf(const char *path, int name)
741 {
742     switch(name) {
743     case _PC_PATH_MAX :
744         if (strncmp(path, "\\\\?\\", 4) == 0)
745             return 32767;
746     case _PC_NAME_MAX :
747         return 255;
748     }
749
750     return -1;
751 }
752
753 int
754 WSA_Init(void)
755 {
756     WORD wVersionRequested = MAKEWORD( 1, 1);
757     WSADATA wsaData;
758     
759     int err = WSAStartup(wVersionRequested, &wsaData);
760     
761     
762     if (err != 0)
763     {
764         printf("Can not start Windows Sockets\n");
765         return -1;
766     }
767
768     return 0;
769 }
770
771
772 int
773 win32_chdir(const char *dir)
774 {
775     if (0 == SetCurrentDirectory(dir)) return -1;
776     return 0;
777 }
778
779 char *
780 win32_getcwd(char *buf, int maxlen)
781 {
782    int n =  GetCurrentDirectory(maxlen, buf);
783
784    if (n == 0 || n > maxlen) return NULL;
785
786    if (n+1 > maxlen) return NULL;
787    if (n != 3) {
788        buf[n] = '\\';
789        buf[n+1] = 0;
790    }
791    
792    return buf;
793 }
794
795 #include "mswinver.h"
796
797 char WIN_VERSION_LONG[64];
798 char WIN_VERSION[32];
799
800 class winver {
801 public:
802     winver(void);
803 };
804
805 static winver INIT;                     // cause constructor to be called before main()
806
807 #include "bacula.h"
808 #include "jcr.h"
809
810 winver::winver(void)
811 {
812     const char *version = "";
813     const char *platform = "";
814     OSVERSIONINFO osvinfo;
815     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
816
817     // Get the current OS version
818     if (!GetVersionEx(&osvinfo)) {
819         version = "Unknown";
820         platform = "Unknown";
821     }
822     else
823         switch (_mkversion(osvinfo.dwPlatformId, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion))
824         {
825         case MS_WINDOWS_95: (version =  "Windows 95"); break;
826         case MS_WINDOWS_98: (version =  "Windows 98"); break;
827         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
828         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
829         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
830         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
831         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
832         default: version = "Windows ??"; break;
833         }
834
835     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
836     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %d.%d.%d",
837              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
838
839 #if 0
840     BPIPE *b = open_bpipe("ls -l", 10, "r");
841     char buf[1024];
842     while (!feof(b->rfd)) {
843         fgets(buf, sizeof(buf), b->rfd);
844     }
845     close_bpipe(b);
846 #endif
847 }
848  
849 BOOL CreateChildProcess(VOID); 
850 VOID WriteToPipe(VOID); 
851 VOID ReadFromPipe(VOID); 
852 VOID ErrorExit(LPTSTR); 
853 VOID ErrMsg(LPTSTR, BOOL); 
854  
855
856 const char *
857 getArgv0(const char *cmdline)
858 {
859     const char *cp = cmdline;
860
861     while (*cp && !isspace(*cp)) cp++;
862
863     int len = cp - cmdline;
864     char *rval = (char *)malloc(len+1);
865
866     cp = cmdline;
867     char *rp = rval;
868     while (len--)
869         *rp++ = *cp++;
870
871     *rp = 0;
872     return rval;
873 }
874
875 HANDLE
876 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err) 
877
878     PROCESS_INFORMATION piProcInfo; 
879     STARTUPINFO siStartInfo;
880     BOOL bFuncRetn = FALSE; 
881     
882     // Set up members of the PROCESS_INFORMATION structure. 
883     
884     ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
885     
886     // Set up members of the STARTUPINFO structure. 
887     
888     ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
889     siStartInfo.cb = sizeof(STARTUPINFO);
890     // setup new process to use supplied handles for stdin,stdout,stderr
891     // if supplied handles are not used the send a copy of our STD_HANDLE
892     // as appropriate
893     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
894
895     if (in != INVALID_HANDLE_VALUE)
896         siStartInfo.hStdInput = in;
897     else
898         siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
899     
900     if (out != INVALID_HANDLE_VALUE)
901         siStartInfo.hStdOutput = out;
902     else
903         siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
904     if (err != INVALID_HANDLE_VALUE)
905         siStartInfo.hStdError = err;
906     else
907         siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
908     // Create the child process. 
909     
910     char cmdLine[1024];
911     char exeFile[1024];
912     // retrive the first compont of the command line which should be the
913     // executable 
914     const char *exeName = getArgv0(cmdline);
915     // check to see if absolute path was passed to us already?
916     if (exeName[1] != ':'
917         || (strchr(cmdline, '/') == NULL
918             && strchr(cmdline, '\\') == NULL))
919     {
920         // only command name so perform search of PATH to find 
921         char *file;
922         DWORD rval = SearchPath(NULL,
923                                 exeName,
924                                 ".exe",
925                                 sizeof(exeFile),
926                                 exeFile,
927                                 &file);
928         if (rval == 0)
929             return INVALID_HANDLE_VALUE;
930         if (rval > sizeof(exeFile))
931             return INVALID_HANDLE_VALUE;
932
933     }
934     else 
935         strcpy(exeFile, exeName);
936
937     // exeFile now has absolute path to program to execute.
938     free((void *)exeName);
939     // copy original command line to pass to create process
940     strcpy(cmdLine, cmdline);
941     // try to execute program
942     bFuncRetn = CreateProcess(exeFile, 
943                               cmdLine, // command line 
944                               NULL, // process security attributes 
945                               NULL, // primary thread security attributes 
946                               TRUE, // handles are inherited 
947                               0, // creation flags 
948                               NULL, // use parent's environment 
949                               NULL, // use parent's current directory 
950                               &siStartInfo, // STARTUPINFO pointer 
951                               &piProcInfo); // receives PROCESS_INFORMATION
952     
953     if (bFuncRetn == 0) {
954         ErrorExit("CreateProcess failed\n");
955         return INVALID_HANDLE_VALUE;
956     }
957     // we don't need a handle on the process primary thread so we close
958     // this now.
959     CloseHandle(piProcInfo.hThread);
960     
961     return piProcInfo.hProcess;
962 }
963
964  
965 void
966 ErrorExit (LPTSTR lpszMessage) 
967
968     d_msg(__FILE__, __LINE__, 0, "%s", lpszMessage);
969
970  
971
972 /*
973 typedef struct s_bpipe {
974    pid_t worker_pid;
975    time_t worker_stime;
976    int wait;
977    btimer_t *timer_id;
978    FILE *rfd;
979    FILE *wfd;
980 } BPIPE;
981 */
982
983 static void
984 CloseIfValid(HANDLE handle)
985 {
986     if (handle != INVALID_HANDLE_VALUE)
987         CloseHandle(handle);
988 }
989 // include <io.h> causes to many conflicts with some of
990 // the fuctions we define here.
991 extern "C" {
992 int __cdecl _open_osfhandle(long, int);
993 }
994
995 BPIPE *
996 open_bpipe(char *prog, int wait, const char *mode)
997 {
998     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, 
999         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, 
1000         hInputFile;
1001     
1002     SECURITY_ATTRIBUTES saAttr; 
1003
1004     BOOL fSuccess; 
1005
1006     hChildStdinRd = hChildStdinWr = hChildStdinWrDup = 
1007         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup = 
1008         hInputFile = INVALID_HANDLE_VALUE;
1009     
1010     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1011     memset((void *)bpipe, 0, sizeof(BPIPE));
1012
1013     int mode_read = (mode[0] == 'r');
1014     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1015     
1016     
1017     // Set the bInheritHandle flag so pipe handles are inherited. 
1018     
1019     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
1020     saAttr.bInheritHandle = TRUE; 
1021     saAttr.lpSecurityDescriptor = NULL; 
1022     
1023     if (mode_read) {
1024         
1025         // Create a pipe for the child process's STDOUT. 
1026         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1027             ErrorExit("Stdout pipe creation failed\n");
1028             goto cleanup;
1029         }
1030         // Create noninheritable read handle and close the inheritable read 
1031         // handle. 
1032         
1033         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1034                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
1035                                    FALSE,
1036                                    DUPLICATE_SAME_ACCESS);
1037         if( !fSuccess ) {
1038             ErrorExit("DuplicateHandle failed");
1039             goto cleanup;
1040         }
1041         
1042         CloseHandle(hChildStdoutRd);
1043     }
1044     
1045     if (mode_write) {
1046         
1047         // Create a pipe for the child process's STDIN. 
1048         
1049         if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1050             ErrorExit("Stdin pipe creation failed\n");
1051             goto cleanup;
1052         }
1053         
1054         // Duplicate the write handle to the pipe so it is not inherited. 
1055         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, 
1056                                    GetCurrentProcess(), &hChildStdinWrDup,
1057                                    0, 
1058                                    FALSE,                  // not inherited 
1059                                    DUPLICATE_SAME_ACCESS); 
1060         if (!fSuccess) {
1061             ErrorExit("DuplicateHandle failed");
1062             goto cleanup;
1063         }
1064         
1065         CloseHandle(hChildStdinWr); 
1066     }
1067     // spawn program with redirected handles as appropriate
1068     bpipe->worker_pid = (pid_t)
1069         CreateChildProcess(prog, // commandline
1070                            hChildStdinRd, // stdin HANDLE
1071                            hChildStdoutWr, // stdout HANDLE
1072                            hChildStdoutWr);// stderr HANDLE
1073     
1074     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1075         goto cleanup;
1076     
1077     bpipe->wait = wait;
1078     bpipe->worker_stime = time(NULL);
1079     
1080     if (mode_read) {
1081         CloseHandle(hChildStdoutWr); // close our write side so when
1082                                      // process terminates we can
1083                                      // detect eof.
1084         // ugly but convert WIN32 HANDLE to FILE*
1085         int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1086         bpipe->rfd = _fdopen(rfd, "r");
1087     }
1088     if (mode_write) {
1089         CloseHandle(hChildStdinRd); // close our read side so as not
1090                                     // to interfre with child's copy
1091         // ugly but convert WIN32 HANDLE to FILE*
1092         int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY);
1093         bpipe->wfd = _fdopen(wfd, "w");
1094     }
1095     
1096     if (wait > 0) {
1097         bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1098     }
1099     
1100     return bpipe;
1101     
1102 cleanup:
1103     
1104     CloseIfValid(hChildStdoutRd);
1105     CloseIfValid(hChildStdoutRdDup);
1106     CloseIfValid(hChildStdinWr);
1107     CloseIfValid(hChildStdinWrDup);
1108     
1109     free((void *) bpipe);
1110     
1111     return NULL;
1112 }
1113
1114 int
1115 kill(int pid, int signal)
1116 {
1117     int rval = 0;
1118     if (!TerminateProcess((HANDLE)pid, (UINT) signal))
1119         rval = -1;
1120     CloseHandle((HANDLE)pid);
1121     return rval;
1122 }
1123
1124 int
1125 close_bpipe(BPIPE *bpipe)
1126 {
1127     int rval = 0;
1128     if (bpipe->rfd) fclose(bpipe->rfd);
1129     if (bpipe->wfd) fclose(bpipe->wfd);
1130
1131     if (bpipe->wait) {
1132         int remaining_wait = bpipe->wait;
1133         do 
1134         {
1135             DWORD exitCode;
1136             if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode))
1137             {
1138                 const char *err = errorString();
1139                 rval = GetLastError();
1140                 d_msg(__FILE__, __LINE__, 0, 
1141                       "GetExitCode error %s\n", err);
1142                 LocalFree((void *)err);
1143                 break;
1144             }
1145             
1146             if (exitCode == STILL_ACTIVE) {
1147                 bmicrosleep(1, 0);             /* wait one second */
1148                 remaining_wait--;
1149             }
1150             else break;
1151         } while(remaining_wait);
1152     }
1153     
1154     if (bpipe->timer_id) {
1155         stop_child_timer(bpipe->timer_id);
1156     }
1157     free((void *)bpipe);    
1158     return rval;
1159 }
1160
1161 int
1162 close_wpipe(BPIPE *bpipe)
1163 {
1164     int stat = 1;
1165     
1166     if (bpipe->wfd) {
1167         fflush(bpipe->wfd);
1168         if (fclose(bpipe->wfd) != 0) {
1169             stat = 0;
1170       }
1171         bpipe->wfd = NULL;
1172     }
1173     return stat;
1174 }
1175
1176 #include "findlib/find.h"
1177
1178 int
1179 utime(const char *fname, struct utimbuf *times)
1180 {
1181     FILETIME acc, mod;
1182     char tmpbuf[1024];
1183
1184     cygwin_conv_to_win32_path(fname, tmpbuf);
1185
1186     cvt_utime_to_ftime(times->actime, acc);
1187     cvt_utime_to_ftime(times->modtime, mod);
1188
1189     HANDLE h = CreateFile(tmpbuf,
1190                           FILE_WRITE_ATTRIBUTES,
1191                           FILE_SHARE_WRITE,
1192                           NULL,
1193                           OPEN_EXISTING,
1194                           0,
1195                           NULL);
1196
1197     if (h == INVALID_HANDLE_VALUE) {
1198         const char *err = errorString();
1199         d_msg(__FILE__, __LINE__, 99,
1200               "Cannot open file for stat (%s):%s\n", tmpbuf, err);
1201         LocalFree((void *)err);
1202         return -1;
1203     }
1204
1205     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1206
1207     CloseHandle(h);
1208     
1209     return rval;
1210 }
1211