Logo ROOT  
Reference Guide
TWinNTSystem.cxx
Go to the documentation of this file.
1// @(#)root/winnt:$Id: db9b3139b1551a1b4e31a17f57866a276d5cd419 $
2// Author: Fons Rademakers 15/09/95
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//////////////////////////////////////////////////////////////////////////////////
13// //
14// TWinNTSystem //
15// //
16// Class providing an interface to the Windows NT/Windows 95 Operating Systems. //
17// //
18//////////////////////////////////////////////////////////////////////////////////
19
20
21#ifdef HAVE_CONFIG
22#include "config.h"
23#endif
24
25#include "Windows4Root.h"
27#include "TWinNTSystem.h"
28#include "TROOT.h"
29#include "TError.h"
30#include "TOrdCollection.h"
31#include "TRegexp.h"
32#include "TException.h"
33#include "TEnv.h"
34#include "TApplication.h"
35#include "TWin32SplashThread.h"
36#include "Win32Constants.h"
37#include "TInterpreter.h"
38#include "TVirtualX.h"
39#include "TUrl.h"
40#include "ThreadLocalStorage.h"
41#include "snprintf.h"
42#include "strlcpy.h"
43
44#include <sys/utime.h>
45#include <sys/timeb.h>
46#include <process.h>
47#include <io.h>
48#include <direct.h>
49#include <ctype.h>
50#include <float.h>
51#include <sys/stat.h>
52#include <signal.h>
53#include <stdio.h>
54#include <errno.h>
55#include <lm.h>
56#include <dbghelp.h>
57#include <Tlhelp32.h>
58#include <sstream>
59#include <iostream>
60#include <list>
61#include <shlobj.h>
62#include <conio.h>
63
64#if defined (_MSC_VER) && (_MSC_VER >= 1400)
65 #include <intrin.h>
66#elif defined (_M_IX86)
67 static void __cpuid(int* cpuid_data, int info_type)
68 {
69 __asm {
70 push ebx
71 push edi
72 mov edi, cpuid_data
73 mov eax, info_type
74 cpuid
75 mov [edi], eax
76 mov [edi + 4], ebx
77 mov [edi + 8], ecx
78 mov [edi + 12], edx
79 pop edi
80 pop ebx
81 }
82 }
83 __int64 __rdtsc()
84 {
85 LARGE_INTEGER li;
86 __asm {
87 rdtsc
88 mov li.LowPart, eax
89 mov li.HighPart, edx
90 }
91 return li.QuadPart;
92 }
93#else
94 static void __cpuid(int* cpuid_data, int) {
95 cpuid_data[0] = 0x00000000;
96 cpuid_data[1] = 0x00000000;
97 cpuid_data[2] = 0x00000000;
98 cpuid_data[3] = 0x00000000;
99 }
100 __int64 __rdtsc() { return (__int64)0; }
101#endif
102
103extern "C" {
104 extern void Gl_setwidth(int width);
105 void *_ReturnAddress(void);
106}
107
108//////////////////// Windows TFdSet ////////////////////////////////////////////////
109class TFdSet {
110private:
111 fd_set *fds_bits; // file descriptors (according MSDN maximum is 64)
112public:
113 TFdSet() { fds_bits = new fd_set; fds_bits->fd_count = 0; }
114 virtual ~TFdSet() { delete fds_bits; }
115 void Copy(TFdSet &fd) const { memcpy((void*)fd.fds_bits, fds_bits, sizeof(fd_set)); }
116 TFdSet(const TFdSet& fd) { fd.Copy(*this); }
117 TFdSet& operator=(const TFdSet& fd) { fd.Copy(*this); return *this; }
118 void Zero() { fds_bits->fd_count = 0; }
119 void Set(Int_t fd)
120 {
121 if (fds_bits->fd_count < FD_SETSIZE-1) // protect out of bound access (64)
122 fds_bits->fd_array[fds_bits->fd_count++] = (SOCKET)fd;
123 else
124 ::SysError("TFdSet::Set", "fd_count will exeed FD_SETSIZE");
125 }
126 void Clr(Int_t fd)
127 {
128 int i;
129 for (i=0; i<fds_bits->fd_count; i++) {
130 if (fds_bits->fd_array[i]==(SOCKET)fd) {
131 while (i<fds_bits->fd_count-1) {
132 fds_bits->fd_array[i] = fds_bits->fd_array[i+1];
133 i++;
134 }
135 fds_bits->fd_count--;
136 break;
137 }
138 }
139 }
140 Int_t IsSet(Int_t fd) { return __WSAFDIsSet((SOCKET)fd, fds_bits); }
141 Int_t *GetBits() { return fds_bits && fds_bits->fd_count ? (Int_t*)fds_bits : 0; }
142 UInt_t GetCount() { return (UInt_t)fds_bits->fd_count; }
143 Int_t GetFd(Int_t i) { return i<fds_bits->fd_count ? fds_bits->fd_array[i] : 0; }
144};
145
146namespace {
147 const char *kProtocolName = "tcp";
148 typedef void (*SigHandler_t)(ESignals);
149 static TWinNTSystem::ThreadMsgFunc_t gGUIThreadMsgFunc = 0; // GUI thread message handler func
150
151 static HANDLE gGlobalEvent;
152 static HANDLE gTimerThreadHandle;
153 typedef NET_API_STATUS (WINAPI *pfn1)(LPVOID);
154 typedef NET_API_STATUS (WINAPI *pfn2)(LPCWSTR, LPCWSTR, DWORD, LPBYTE*);
155 typedef NET_API_STATUS (WINAPI *pfn3)(LPCWSTR, LPCWSTR, DWORD, LPBYTE*,
156 DWORD, LPDWORD, LPDWORD, PDWORD);
157 typedef NET_API_STATUS (WINAPI *pfn4)(LPCWSTR, DWORD, LPBYTE*, DWORD, LPDWORD,
158 LPDWORD, PDWORD);
159 static pfn1 p2NetApiBufferFree;
160 static pfn2 p2NetUserGetInfo;
161 static pfn3 p2NetLocalGroupGetMembers;
162 static pfn4 p2NetLocalGroupEnum;
163
164 static struct signal_map {
165 int code;
166 SigHandler_t handler;
167 const char *signame;
168 } signal_map[kMAXSIGNALS] = { // the order of the signals should be identical
169 -1 /*SIGBUS*/, 0, "bus error", // to the one in SysEvtHandler.h
170 SIGSEGV, 0, "segmentation violation",
171 -1 /*SIGSYS*/, 0, "bad argument to system call",
172 -1 /*SIGPIPE*/, 0, "write on a pipe with no one to read it",
173 SIGILL, 0, "illegal instruction",
174 SIGABRT, 0, "abort",
175 -1 /*SIGQUIT*/, 0, "quit",
176 SIGINT, 0, "interrupt",
177 -1 /*SIGWINCH*/, 0, "window size change",
178 -1 /*SIGALRM*/, 0, "alarm clock",
179 -1 /*SIGCHLD*/, 0, "death of a child",
180 -1 /*SIGURG*/, 0, "urgent data arrived on an I/O channel",
181 SIGFPE, 0, "floating point exception",
182 SIGTERM, 0, "termination signal",
183 -1 /*SIGUSR1*/, 0, "user-defined signal 1",
184 -1 /*SIGUSR2*/, 0, "user-defined signal 2"
185 };
186
187 ////// static functions providing interface to raw WinNT ////////////////////
188
189 //---- RPC -------------------------------------------------------------------
190 //*-* Error codes set by the Windows Sockets implementation are not made available
191 //*-* via the errno variable. Additionally, for the getXbyY class of functions,
192 //*-* error codes are NOT made available via the h_errno variable. Instead, error
193 //*-* codes are accessed by using the WSAGetLastError . This function is provided
194 //*-* in Windows Sockets as a precursor (and eventually an alias) for the Win32
195 //*-* function GetLastError. This is intended to provide a reliable way for a thread
196 //*-* in a multithreaded process to obtain per-thread error information.
197
198 /////////////////////////////////////////////////////////////////////////////
199 /// Receive exactly length bytes into buffer. Returns number of bytes
200 /// received. Returns -1 in case of error, -2 in case of MSG_OOB
201 /// and errno == EWOULDBLOCK, -3 in case of MSG_OOB and errno == EINVAL
202 /// and -4 in case of kNonBlock and errno == EWOULDBLOCK.
203 /// Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
204
205 static int WinNTRecv(int socket, void *buffer, int length, int flag)
206 {
207 if (socket == -1) return -1;
208 SOCKET sock = socket;
209
210 int once = 0;
211 if (flag == -1) {
212 flag = 0;
213 once = 1;
214 }
215 if (flag == MSG_PEEK) {
216 once = 1;
217 }
218
219 int nrecv, n;
220 char *buf = (char *)buffer;
221
222 for (n = 0; n < length; n += nrecv) {
223 if ((nrecv = ::recv(sock, buf+n, length-n, flag)) <= 0) {
224 if (nrecv == 0) {
225 break; // EOF
226 }
227 if (flag == MSG_OOB) {
228 if (::WSAGetLastError() == WSAEWOULDBLOCK) {
229 return -2;
230 } else if (::WSAGetLastError() == WSAEINVAL) {
231 return -3;
232 }
233 }
234 if (::WSAGetLastError() == WSAEWOULDBLOCK) {
235 return -4;
236 } else {
237 if (::WSAGetLastError() != WSAEINTR)
238 ::SysError("TWinNTSystem::WinNTRecv", "recv");
239 if (::WSAGetLastError() == EPIPE ||
240 ::WSAGetLastError() == WSAECONNRESET)
241 return -5;
242 else
243 return -1;
244 }
245 }
246 if (once) {
247 return nrecv;
248 }
249 }
250 return n;
251 }
252
253 /////////////////////////////////////////////////////////////////////////////
254 /// Send exactly length bytes from buffer. Returns -1 in case of error,
255 /// otherwise number of sent bytes. Returns -4 in case of kNoBlock and
256 /// errno == EWOULDBLOCK. Returns -5 if pipe broken or reset by peer
257 /// (EPIPE || ECONNRESET).
258
259 static int WinNTSend(int socket, const void *buffer, int length, int flag)
260 {
261 if (socket < 0) return -1;
262 SOCKET sock = socket;
263
264 int once = 0;
265 if (flag == -1) {
266 flag = 0;
267 once = 1;
268 }
269
270 int nsent, n;
271 const char *buf = (const char *)buffer;
272
273 for (n = 0; n < length; n += nsent) {
274 if ((nsent = ::send(sock, buf+n, length-n, flag)) <= 0) {
275 if (nsent == 0) {
276 break;
277 }
278 if (::WSAGetLastError() == WSAEWOULDBLOCK) {
279 return -4;
280 } else {
281 if (::WSAGetLastError() != WSAEINTR)
282 ::SysError("TWinNTSystem::WinNTSend", "send");
283 if (::WSAGetLastError() == EPIPE ||
284 ::WSAGetLastError() == WSAECONNRESET)
285 return -5;
286 else
287 return -1;
288 }
289 }
290 if (once) {
291 return nsent;
292 }
293 }
294 return n;
295 }
296
297 /////////////////////////////////////////////////////////////////////////////
298 /// Wait for events on the file descriptors specified in the readready and
299 /// writeready masks or for timeout (in milliseconds) to occur.
300
301 static int WinNTSelect(TFdSet *readready, TFdSet *writeready, Long_t timeout)
302 {
303 int retcode;
304 fd_set* rbits = readready ? (fd_set*)readready->GetBits() : 0;
305 fd_set* wbits = writeready ? (fd_set*)writeready->GetBits() : 0;
306
307 if (timeout >= 0) {
308 timeval tv;
309 tv.tv_sec = timeout / 1000;
310 tv.tv_usec = (timeout % 1000) * 1000;
311
312 retcode = ::select(0, rbits, wbits, 0, &tv);
313 } else {
314 retcode = ::select(0, rbits, wbits, 0, 0);
315 }
316
317 if (retcode == SOCKET_ERROR) {
318 int errcode = ::WSAGetLastError();
319
320 // if file descriptor is not a socket, assume it is the pipe used
321 // by TXSocket
322 if (errcode == WSAENOTSOCK) {
323 struct __stat64 buf;
324 int result = _fstat64( readready->GetFd(0), &buf );
325 if ( result == 0 ) {
326 if (buf.st_size > 0)
327 return 1;
328 }
329 // yield execution to another thread that is ready to run
330 // if no other thread is ready, sleep 1 ms before to return
331 if (gGlobalEvent) {
332 ::WaitForSingleObject(gGlobalEvent, 1);
333 ::ResetEvent(gGlobalEvent);
334 }
335 return 0;
336 }
337
338 if ( errcode == WSAEINTR) {
339 TSystem::ResetErrno(); // errno is not self reseting
340 return -2;
341 }
342 if (errcode == EBADF) {
343 return -3;
344 }
345 return -1;
346 }
347 return retcode;
348 }
349
350 /////////////////////////////////////////////////////////////////////////////
351 /// Get shared library search path.
352
353 static const char *DynamicPath(const char *newpath = 0, Bool_t reset = kFALSE)
354 {
355 static TString dynpath;
356
357 if (reset || newpath) {
358 dynpath = "";
359 }
360 if (newpath) {
361 dynpath = newpath;
362 } else if (dynpath == "") {
363 dynpath = gSystem->Getenv("ROOT_LIBRARY_PATH");
364 TString rdynpath = gEnv ? gEnv->GetValue("Root.DynamicPath", (char*)0) : "";
365 rdynpath.ReplaceAll("; ", ";"); // in case DynamicPath was extended
366 if (rdynpath == "") {
367 rdynpath = ".;"; rdynpath += TROOT::GetBinDir();
368 }
369 TString path = gSystem->Getenv("PATH");
370 if (!path.IsNull()) {
371 if (!dynpath.IsNull())
372 dynpath += ";";
373 dynpath += path;
374 }
375 if (!rdynpath.IsNull()) {
376 if (!dynpath.IsNull())
377 dynpath += ";";
378 dynpath += rdynpath;
379 }
380 }
381 if (!dynpath.Contains(TROOT::GetLibDir())) {
382 dynpath += ";"; dynpath += TROOT::GetLibDir();
383 }
384
385 return dynpath;
386 }
387
388 /////////////////////////////////////////////////////////////////////////////
389 /// Call the signal handler associated with the signal.
390
391 static void sighandler(int sig)
392 {
393 for (int i = 0; i < kMAXSIGNALS; i++) {
394 if (signal_map[i].code == sig) {
395 (*signal_map[i].handler)((ESignals)i);
396 return;
397 }
398 }
399 }
400
401 /////////////////////////////////////////////////////////////////////////////
402 /// Set a signal handler for a signal.
403
404 static void WinNTSignal(ESignals sig, SigHandler_t handler)
405 {
406 signal_map[sig].handler = handler;
407 if (signal_map[sig].code != -1)
408 (SigHandler_t)signal(signal_map[sig].code, sighandler);
409 }
410
411 /////////////////////////////////////////////////////////////////////////////
412 /// Return the signal name associated with a signal.
413
414 static const char *WinNTSigname(ESignals sig)
415 {
416 return signal_map[sig].signame;
417 }
418
419 /////////////////////////////////////////////////////////////////////////////
420 /// WinNT signal handler.
421
422 static BOOL ConsoleSigHandler(DWORD sig)
423 {
424 switch (sig) {
425 case CTRL_C_EVENT:
426 if (gSystem) {
427 ((TWinNTSystem*)gSystem)->DispatchSignals(kSigInterrupt);
428 }
429 else {
430 Break("TInterruptHandler::Notify", "keyboard interrupt");
431 if (TROOT::Initialized()) {
432 gInterpreter->RewindDictionary();
433 }
434 }
435 return kTRUE;
436 case CTRL_BREAK_EVENT:
437 case CTRL_LOGOFF_EVENT:
438 case CTRL_SHUTDOWN_EVENT:
439 case CTRL_CLOSE_EVENT:
440 default:
441 printf("\n *** Break *** keyboard interrupt - ROOT is terminated\n");
442 gSystem->Exit(-1);
443 return kTRUE;
444 }
445 }
446
447 static CONTEXT *fgXcptContext = 0;
448 /////////////////////////////////////////////////////////////////////////////
449
450 static void SigHandler(ESignals sig)
451 {
452 if (gSystem)
453 ((TWinNTSystem*)gSystem)->DispatchSignals(sig);
454 }
455
456 /////////////////////////////////////////////////////////////////////////////
457 /// Function that's called when an unhandled exception occurs.
458 /// Produces a stack trace, and lets the system deal with it
459 /// as if it was an unhandled excecption (usually ::abort)
460
461 LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS pXcp)
462 {
463 fgXcptContext = pXcp->ContextRecord;
465 return EXCEPTION_CONTINUE_SEARCH;
466 }
467
468
469#pragma intrinsic(_ReturnAddress)
470#pragma auto_inline(off)
471 DWORD_PTR GetProgramCounter()
472 {
473 // Returns the current program counter.
474 return (DWORD_PTR)_ReturnAddress();
475 }
476#pragma auto_inline(on)
477
478 /////////////////////////////////////////////////////////////////////////////
479 /// Message processing loop for the TGWin32 related GUI
480 /// thread for processing windows messages (aka Main/Server thread).
481 /// We need to start the thread outside the TGWin32 / GUI related
482 /// dll, because starting threads at DLL init time does not work.
483 /// Instead, we start an ideling thread at binary startup, and only
484 /// call the "real" message processing function
485 /// TGWin32::GUIThreadMessageFunc() once gVirtualX comes up.
486
487 static DWORD WINAPI GUIThreadMessageProcessingLoop(void *p)
488 {
489 MSG msg;
490
491 // force to create message queue
492 ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
493
494 Int_t erret = 0;
495 Bool_t endLoop = kFALSE;
496 while (!endLoop) {
497 if (gGlobalEvent) ::SetEvent(gGlobalEvent);
498 erret = ::GetMessage(&msg, NULL, NULL, NULL);
499 if (erret <= 0) endLoop = kTRUE;
500 if (gGUIThreadMsgFunc)
501 endLoop = (*gGUIThreadMsgFunc)(&msg);
502 }
503
504 gVirtualX->CloseDisplay();
505
506 // exit thread
507 if (erret == -1) {
508 erret = ::GetLastError();
509 Error("MsgLoop", "Error in GetMessage");
510 ::ExitThread(-1);
511 } else {
512 ::ExitThread(0);
513 }
514 return 0;
515 }
516
517 //=========================================================================
518 // Load IMAGEHLP.DLL and get the address of functions in it that we'll use
519 // by Microsoft, from http://www.microsoft.com/msj/0597/hoodtextfigs.htm#fig1
520 //=========================================================================
521 // Make typedefs for some IMAGEHLP.DLL functions so that we can use them
522 // with GetProcAddress
523 typedef BOOL (__stdcall *SYMINITIALIZEPROC)( HANDLE, LPSTR, BOOL );
524 typedef BOOL (__stdcall *SYMCLEANUPPROC)( HANDLE );
525 typedef BOOL (__stdcall *STACKWALK64PROC)
526 ( DWORD, HANDLE, HANDLE, LPSTACKFRAME64, LPVOID,
527 PREAD_PROCESS_MEMORY_ROUTINE,PFUNCTION_TABLE_ACCESS_ROUTINE,
528 PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE );
529 typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESS64PROC)( HANDLE, DWORD64 );
530 typedef DWORD (__stdcall *SYMGETMODULEBASE64PROC)( HANDLE, DWORD64 );
531 typedef BOOL (__stdcall *SYMGETMODULEINFO64PROC)(HANDLE, DWORD64, PIMAGEHLP_MODULE64);
532 typedef BOOL (__stdcall *SYMGETSYMFROMADDR64PROC)( HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
533 typedef BOOL (__stdcall *SYMGETLINEFROMADDR64PROC)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
534 typedef DWORD (__stdcall *UNDECORATESYMBOLNAMEPROC)(PCSTR, PSTR, DWORD, DWORD);
535
536
537 static SYMINITIALIZEPROC _SymInitialize = 0;
538 static SYMCLEANUPPROC _SymCleanup = 0;
539 static STACKWALK64PROC _StackWalk64 = 0;
540 static SYMFUNCTIONTABLEACCESS64PROC _SymFunctionTableAccess64 = 0;
541 static SYMGETMODULEBASE64PROC _SymGetModuleBase64 = 0;
542 static SYMGETMODULEINFO64PROC _SymGetModuleInfo64 = 0;
543 static SYMGETSYMFROMADDR64PROC _SymGetSymFromAddr64 = 0;
544 static SYMGETLINEFROMADDR64PROC _SymGetLineFromAddr64 = 0;
545 static UNDECORATESYMBOLNAMEPROC _UnDecorateSymbolName = 0;
546
547 BOOL InitImagehlpFunctions()
548 {
549 // Fetches function addresses from IMAGEHLP.DLL at run-time, so we
550 // don't need to link against its import library. These functions
551 // are used in StackTrace; if they cannot be found (e.g. because
552 // IMAGEHLP.DLL doesn't exist or has the wrong version) we cannot
553 // produce a stack trace.
554
555 HMODULE hModImagehlp = LoadLibrary( "IMAGEHLP.DLL" );
556 if (!hModImagehlp)
557 return FALSE;
558
559 _SymInitialize = (SYMINITIALIZEPROC) GetProcAddress( hModImagehlp, "SymInitialize" );
560 if (!_SymInitialize)
561 return FALSE;
562
563 _SymCleanup = (SYMCLEANUPPROC) GetProcAddress( hModImagehlp, "SymCleanup" );
564 if (!_SymCleanup)
565 return FALSE;
566
567 _StackWalk64 = (STACKWALK64PROC) GetProcAddress( hModImagehlp, "StackWalk64" );
568 if (!_StackWalk64)
569 return FALSE;
570
571 _SymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESS64PROC) GetProcAddress(hModImagehlp, "SymFunctionTableAccess64" );
572 if (!_SymFunctionTableAccess64)
573 return FALSE;
574
575 _SymGetModuleBase64=(SYMGETMODULEBASE64PROC)GetProcAddress(hModImagehlp, "SymGetModuleBase64");
576 if (!_SymGetModuleBase64)
577 return FALSE;
578
579 _SymGetModuleInfo64=(SYMGETMODULEINFO64PROC)GetProcAddress(hModImagehlp, "SymGetModuleInfo64");
580 if (!_SymGetModuleInfo64)
581 return FALSE;
582
583 _SymGetSymFromAddr64=(SYMGETSYMFROMADDR64PROC)GetProcAddress(hModImagehlp, "SymGetSymFromAddr64");
584 if (!_SymGetSymFromAddr64)
585 return FALSE;
586
587 _SymGetLineFromAddr64=(SYMGETLINEFROMADDR64PROC)GetProcAddress(hModImagehlp, "SymGetLineFromAddr64");
588 if (!_SymGetLineFromAddr64)
589 return FALSE;
590
591 _UnDecorateSymbolName=(UNDECORATESYMBOLNAMEPROC)GetProcAddress(hModImagehlp, "UnDecorateSymbolName");
592 if (!_UnDecorateSymbolName)
593 return FALSE;
594
595 if (!_SymInitialize(GetCurrentProcess(), 0, TRUE ))
596 return FALSE;
597
598 return TRUE;
599 }
600
601 // stack trace helpers getModuleName, getFunctionName by
602 /**************************************************************************
603 * VRS - The Virtual Rendering System
604 * Copyright (C) 2000-2004 Computer Graphics Systems Group at the
605 * Hasso-Plattner-Institute (HPI), Potsdam, Germany.
606 * This library is free software; you can redistribute it and/or modify it
607 * under the terms of the GNU Lesser General Public License as published by
608 * the Free Software Foundation; either version 2.1 of the License, or
609 * (at your option) any later version.
610 ***************************************************************************/
611 std::string GetModuleName(DWORD64 address)
612 {
613 // Return the name of the module that contains the function at address.
614 // Used by StackTrace.
615 std::ostringstream out;
616 HANDLE process = ::GetCurrentProcess();
617
618 DWORD lineDisplacement = 0;
619 IMAGEHLP_LINE64 line;
620 ::ZeroMemory(&line, sizeof(line));
621 line.SizeOfStruct = sizeof(line);
622 if(_SymGetLineFromAddr64(process, address, &lineDisplacement, &line)) {
623 out << line.FileName << "(" << line.LineNumber << "): ";
624 } else {
625 IMAGEHLP_MODULE64 module;
626 ::ZeroMemory(&module, sizeof(module));
627 module.SizeOfStruct = sizeof(module);
628 if(_SymGetModuleInfo64(process, address, &module)) {
629 out << module.ModuleName << "!";
630 } else {
631 out << "0x" << std::hex << address << std::dec << " ";
632 }
633 }
634
635 return out.str();
636 }
637
638 std::string GetFunctionName(DWORD64 address)
639 {
640 // Return the name of the function at address.
641 // Used by StackTrace.
642 DWORD64 symbolDisplacement = 0;
643 HANDLE process = ::GetCurrentProcess();
644
645 const unsigned int SYMBOL_BUFFER_SIZE = 8192;
646 char symbolBuffer[SYMBOL_BUFFER_SIZE];
647 PIMAGEHLP_SYMBOL64 symbol = reinterpret_cast<PIMAGEHLP_SYMBOL64>(symbolBuffer);
648 ::ZeroMemory(symbol, SYMBOL_BUFFER_SIZE);
649 symbol->SizeOfStruct = SYMBOL_BUFFER_SIZE;
650 symbol->MaxNameLength = SYMBOL_BUFFER_SIZE - sizeof(IMAGEHLP_SYMBOL64);
651
652 if(_SymGetSymFromAddr64(process, address, &symbolDisplacement, symbol)) {
653 // Make the symbol readable for humans
654 const unsigned int NAME_SIZE = 8192;
655 char name[NAME_SIZE];
656 _UnDecorateSymbolName(
657 symbol->Name,
658 name,
659 NAME_SIZE,
660 UNDNAME_COMPLETE |
661 UNDNAME_NO_THISTYPE |
662 UNDNAME_NO_SPECIAL_SYMS |
663 UNDNAME_NO_MEMBER_TYPE |
664 UNDNAME_NO_MS_KEYWORDS |
665 UNDNAME_NO_ACCESS_SPECIFIERS
666 );
667
668 std::string result;
669 result += name;
670 result += "()";
671 return result;
672 } else {
673 return "??";
674 }
675 }
676
677 ////// Shortcuts helper functions IsShortcut and ResolveShortCut ///////////
678
679 /////////////////////////////////////////////////////////////////////////////
680 /// Validates if a file name has extension '.lnk'. Returns true if file
681 /// name have extension same as Window's shortcut file (.lnk).
682
683 static BOOL IsShortcut(const char *filename)
684 {
685 //File extension for the Window's shortcuts (.lnk)
686 const char *extLnk = ".lnk";
687 if (filename != NULL) {
688 //Validate extension
689 TString strfilename(filename);
690 if (strfilename.EndsWith(extLnk))
691 return TRUE;
692 }
693 return FALSE;
694 }
695
696 /////////////////////////////////////////////////////////////////////////////
697 /// Resolve a ShellLink (i.e. c:\path\shortcut.lnk) to a real path.
698
699 static BOOL ResolveShortCut(LPCSTR pszShortcutFile, char *pszPath, int maxbuf)
700 {
701 HRESULT hres;
702 IShellLink* psl;
703 char szGotPath[MAX_PATH];
704 WIN32_FIND_DATA wfd;
705
706 *pszPath = 0; // assume failure
707
708 // Make typedefs for some ole32.dll functions so that we can use them
709 // with GetProcAddress
710 typedef HRESULT (__stdcall *COINITIALIZEPROC)( LPVOID );
711 static COINITIALIZEPROC _CoInitialize = 0;
712 typedef void (__stdcall *COUNINITIALIZEPROC)( void );
713 static COUNINITIALIZEPROC _CoUninitialize = 0;
714 typedef HRESULT (__stdcall *COCREATEINSTANCEPROC)( REFCLSID, LPUNKNOWN,
715 DWORD, REFIID, LPVOID );
716 static COCREATEINSTANCEPROC _CoCreateInstance = 0;
717
718 HMODULE hModImagehlp = LoadLibrary( "ole32.dll" );
719 if (!hModImagehlp)
720 return FALSE;
721
722 _CoInitialize = (COINITIALIZEPROC) GetProcAddress( hModImagehlp, "CoInitialize" );
723 if (!_CoInitialize)
724 return FALSE;
725 _CoUninitialize = (COUNINITIALIZEPROC) GetProcAddress( hModImagehlp, "CoUninitialize");
726 if (!_CoUninitialize)
727 return FALSE;
728 _CoCreateInstance = (COCREATEINSTANCEPROC) GetProcAddress( hModImagehlp, "CoCreateInstance" );
729 if (!_CoCreateInstance)
730 return FALSE;
731
732 _CoInitialize(NULL);
733
734 hres = _CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
735 IID_IShellLink, (void **) &psl);
736 if (SUCCEEDED(hres)) {
737 IPersistFile* ppf;
738
739 hres = psl->QueryInterface(IID_IPersistFile, (void **) &ppf);
740 if (SUCCEEDED(hres)) {
741 WCHAR wsz[MAX_PATH];
742 MultiByteToWideChar(CP_ACP, 0, pszShortcutFile, -1, wsz, MAX_PATH);
743
744 hres = ppf->Load(wsz, STGM_READ);
745 if (SUCCEEDED(hres)) {
746 hres = psl->Resolve(HWND_DESKTOP, SLR_ANY_MATCH | SLR_NO_UI | SLR_UPDATE);
747 if (SUCCEEDED(hres)) {
748 strlcpy(szGotPath, pszShortcutFile,MAX_PATH);
749 hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATA *)&wfd,
750 SLGP_UNCPRIORITY | SLGP_RAWPATH);
751 strlcpy(pszPath,szGotPath, maxbuf);
752 if (maxbuf) pszPath[maxbuf-1] = 0;
753 }
754 }
755 ppf->Release();
756 }
757 psl->Release();
758 }
759 _CoUninitialize();
760
761 return SUCCEEDED(hres);
762 }
763
764 void UpdateRegistry(TWinNTSystem* sys, char* buf /* size of buffer: MAX_MODULE_NAME32 + 1 */) {
765 // register ROOT as the .root file handler:
766 GetModuleFileName(0, buf, MAX_MODULE_NAME32 + 1);
767 if (strcmp(sys->TWinNTSystem::BaseName(buf), "root.exe"))
768 return;
769 HKEY regCUS;
770 if (!::RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &regCUS) == ERROR_SUCCESS)
771 return;
772 HKEY regCUSC;
773 if (!::RegOpenKeyEx(regCUS, "Classes", 0, KEY_READ, &regCUSC) == ERROR_SUCCESS) {
774 ::RegCloseKey(regCUS);
775 return;
776 }
777
778 HKEY regROOT;
779 bool regROOTwrite = false;
780 TString iconloc(buf);
781 iconloc += ",-101";
782
783 if (::RegOpenKeyEx(regCUSC, "ROOTDEV.ROOT", 0, KEY_READ, &regROOT) != ERROR_SUCCESS) {
784 ::RegCloseKey(regCUSC);
785 if (::RegOpenKeyEx(regCUS, "Classes", 0, KEY_READ | KEY_WRITE, &regCUSC) == ERROR_SUCCESS &&
786 ::RegCreateKeyEx(regCUSC, "ROOTDEV.ROOT", 0, NULL, 0, KEY_READ | KEY_WRITE,
787 NULL, &regROOT, NULL) == ERROR_SUCCESS) {
788 regROOTwrite = true;
789 }
790 } else {
791 HKEY regROOTIcon;
792 if (::RegOpenKeyEx(regROOT, "DefaultIcon", 0, KEY_READ, &regROOTIcon) == ERROR_SUCCESS) {
793 char bufIconLoc[1024];
794 DWORD dwType;
795 DWORD dwSize = sizeof(bufIconLoc);
796
797 if (::RegQueryValueEx(regROOTIcon, NULL, NULL, &dwType, (BYTE*)bufIconLoc, &dwSize) == ERROR_SUCCESS)
798 regROOTwrite = (iconloc != bufIconLoc);
799 else
800 regROOTwrite = true;
801 ::RegCloseKey(regROOTIcon);
802 } else
803 regROOTwrite = true;
804 if (regROOTwrite) {
805 // re-open for writing
806 ::RegCloseKey(regCUSC);
807 ::RegCloseKey(regROOT);
808 if (::RegOpenKeyEx(regCUS, "Classes", 0, KEY_READ | KEY_WRITE, &regCUSC) != ERROR_SUCCESS) {
809 // error opening key for writing:
810 regROOTwrite = false;
811 } else {
812 if (::RegOpenKeyEx(regCUSC, "ROOTDEV.ROOT", 0, KEY_WRITE, &regROOT) != ERROR_SUCCESS) {
813 // error opening key for writing:
814 regROOTwrite = false;
815 ::RegCloseKey(regCUSC);
816 }
817 }
818 }
819 }
820
821 // determine the fileopen.C file path:
822 TString fileopen = "fileopen.C";
823 TString rootmacrodir = "macros";
824 sys->PrependPathName(getenv("ROOTSYS"), rootmacrodir);
825 sys->PrependPathName(rootmacrodir.Data(), fileopen);
826
827 if (regROOTwrite) {
828 // only write to registry if fileopen.C is readable
829 regROOTwrite = (::_access(fileopen, kReadPermission) == 0);
830 }
831
832 if (!regROOTwrite) {
833 ::RegCloseKey(regROOT);
834 ::RegCloseKey(regCUSC);
835 ::RegCloseKey(regCUS);
836 return;
837 }
838
839 static const char apptitle[] = "ROOT data file";
840 ::RegSetValueEx(regROOT, NULL, 0, REG_SZ, (BYTE*)apptitle, sizeof(apptitle));
841 DWORD editflags = /*FTA_OpenIsSafe*/ 0x00010000; // trust downloaded files
842 ::RegSetValueEx(regROOT, "EditFlags", 0, REG_DWORD, (BYTE*)&editflags, sizeof(editflags));
843
844 HKEY regROOTIcon;
845 if (::RegCreateKeyEx(regROOT, "DefaultIcon", 0, NULL, 0, KEY_READ | KEY_WRITE,
846 NULL, &regROOTIcon, NULL) == ERROR_SUCCESS) {
847 TString iconloc(buf);
848 iconloc += ",-101";
849 ::RegSetValueEx(regROOTIcon, NULL, 0, REG_SZ, (BYTE*)iconloc.Data(), iconloc.Length() + 1);
850 ::RegCloseKey(regROOTIcon);
851 }
852
853 // "open" verb
854 HKEY regROOTshell;
855 if (::RegCreateKeyEx(regROOT, "shell", 0, NULL, 0, KEY_READ | KEY_WRITE,
856 NULL, &regROOTshell, NULL) == ERROR_SUCCESS) {
857 HKEY regShellOpen;
858 if (::RegCreateKeyEx(regROOTshell, "open", 0, NULL, 0, KEY_READ | KEY_WRITE,
859 NULL, &regShellOpen, NULL) == ERROR_SUCCESS) {
860 HKEY regShellOpenCmd;
861 if (::RegCreateKeyEx(regShellOpen, "command", 0, NULL, 0, KEY_READ | KEY_WRITE,
862 NULL, &regShellOpenCmd, NULL) == ERROR_SUCCESS) {
863 TString cmd(buf);
864 cmd += " -l \"%1\" \"";
865 cmd += fileopen;
866 cmd += "\"";
867 ::RegSetValueEx(regShellOpenCmd, NULL, 0, REG_SZ, (BYTE*)cmd.Data(), cmd.Length() + 1);
868 ::RegCloseKey(regShellOpenCmd);
869 }
870 ::RegCloseKey(regShellOpen);
871 }
872 ::RegCloseKey(regROOTshell);
873 }
874 ::RegCloseKey(regROOT);
875
876 if (::RegCreateKeyEx(regCUSC, ".root", 0, NULL, 0, KEY_READ | KEY_WRITE,
877 NULL, &regROOT, NULL) == ERROR_SUCCESS) {
878 static const char appname[] = "ROOTDEV.ROOT";
879 ::RegSetValueEx(regROOT, NULL, 0, REG_SZ, (BYTE*)appname, sizeof(appname));
880 }
881 ::RegCloseKey(regCUSC);
882 ::RegCloseKey(regCUS);
883
884 // tell Windows that the association was changed
885 ::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
886 } // UpdateRegistry()
887
888 /////////////////////////////////////////////////////////////////////////////
889 /// return kFALSE if option "-l" was specified as main programm command arg
890
891 bool NeedSplash()
892 {
893 static bool once = true;
894 TString arg;
895
896 if (!once || gROOT->IsBatch()) return false;
897 TString cmdline(::GetCommandLine());
898 Int_t i = 0, from = 0;
899 while (cmdline.Tokenize(arg, from, " ")) {
901 if (i == 0 && ((arg != "root") && (arg != "rootn") &&
902 (arg != "root.exe") && (arg != "rootn.exe"))) return false;
903 else if ((arg == "-l") || (arg == "-b")) return false;
904 ++i;
905 }
906 if (once) {
907 once = false;
908 return true;
909 }
910 return false;
911 }
912
913 /////////////////////////////////////////////////////////////////////////////
914
915 static void SetConsoleWindowName()
916 {
917 char pszNewWindowTitle[1024]; // contains fabricated WindowTitle
918 char pszOldWindowTitle[1024]; // contains original WindowTitle
919 HANDLE hStdout;
920 CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
921
922 if (!::GetConsoleTitle(pszOldWindowTitle, 1024))
923 return;
924 // format a "unique" NewWindowTitle
925 wsprintf(pszNewWindowTitle,"%d/%d", ::GetTickCount(), ::GetCurrentProcessId());
926 // change current window title
927 if (!::SetConsoleTitle(pszNewWindowTitle))
928 return;
929 // ensure window title has been updated
930 ::Sleep(40);
931 // look for NewWindowTitle
932 gConsoleWindow = (ULong_t)::FindWindow(0, pszNewWindowTitle);
933 if (gConsoleWindow) {
934 // restore original window title
935 ::ShowWindow((HWND)gConsoleWindow, SW_RESTORE);
936 //::SetForegroundWindow((HWND)gConsoleWindow);
937 ::SetConsoleTitle("ROOT session");
938 }
939 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
940 // adding the ENABLE_VIRTUAL_TERMINAL_PROCESSING flag would enable the ANSI control
941 // character sequences (e.g. `\033[39m`), but then it breaks the WRAP_AT_EOL_OUTPUT
942 ::SetConsoleMode(hStdout, ENABLE_PROCESSED_OUTPUT |
943 ENABLE_WRAP_AT_EOL_OUTPUT);
944 if (!::GetConsoleScreenBufferInfo(hStdout, &csbiInfo))
945 return;
946 Gl_setwidth(csbiInfo.dwMaximumWindowSize.X);
947 }
948
949} // end unnamed namespace
950
951
952///////////////////////////////////////////////////////////////////////////////
954
956
957////////////////////////////////////////////////////////////////////////////////
958///
959
961{
962 TSignalHandler *sh;
963 TIter next(fSignalHandler);
964 ESignals s;
965
966 while (sh = (TSignalHandler*)next()) {
967 s = sh->GetSignal();
968 if (s == kSigInterrupt) {
969 sh->Notify();
970 Throw(SIGINT);
971 return kTRUE;
972 }
973 }
974 return kFALSE;
975}
976
977////////////////////////////////////////////////////////////////////////////////
978/// ctor
979
980TWinNTSystem::TWinNTSystem() : TSystem("WinNT", "WinNT System")
981{
982 fhProcess = ::GetCurrentProcess();
983
984 WSADATA WSAData;
985 int initwinsock = 0;
986
987 if (initwinsock = ::WSAStartup(MAKEWORD(2, 0), &WSAData)) {
988 Error("TWinNTSystem()","Starting sockets failed");
989 }
990
991 // use ::MessageBeep by default for TWinNTSystem
992 fBeepDuration = 1;
993 fBeepFreq = 0;
994 if (gEnv) {
995 fBeepDuration = gEnv->GetValue("Root.System.BeepDuration", 1);
996 fBeepFreq = gEnv->GetValue("Root.System.BeepFreq", 0);
997 }
998
999 char *buf = new char[MAX_MODULE_NAME32 + 1];
1000
1001#ifdef ROOTPREFIX
1002 if (gSystem->Getenv("ROOTIGNOREPREFIX")) {
1003#endif
1004 // set ROOTSYS
1005 HMODULE hModCore = ::GetModuleHandle("libCore.dll");
1006 if (hModCore) {
1007 ::GetModuleFileName(hModCore, buf, MAX_MODULE_NAME32 + 1);
1008 char *pLibName = strstr(buf, "libCore.dll");
1009 if (pLibName) {
1010 --pLibName; // skip trailing \\ or /
1011 while (--pLibName >= buf && *pLibName != '\\' && *pLibName != '/');
1012 *pLibName = 0; // replace trailing \\ or / with 0
1013 TString check_path = buf;
1014 check_path += "\\etc";
1015 // look for $ROOTSYS (it should contain the "etc" subdirectory)
1016 while (buf[0] && GetFileAttributes(check_path.Data()) == INVALID_FILE_ATTRIBUTES) {
1017 while (--pLibName >= buf && *pLibName != '\\' && *pLibName != '/');
1018 *pLibName = 0;
1019 check_path = buf;
1020 check_path += "\\etc";
1021 }
1022 if (buf[0]) {
1023 Setenv("ROOTSYS", buf);
1024 TString path = buf;
1025 path += "\\bin;";
1026 path += Getenv("PATH");
1027 Setenv("PATH", path.Data());
1028 }
1029 }
1030 }
1031#ifdef ROOTPREFIX
1032 }
1033#endif
1034
1035 UpdateRegistry(this, buf);
1036
1037 delete [] buf;
1038}
1039
1040////////////////////////////////////////////////////////////////////////////////
1041/// dtor
1042
1044{
1045 // Revert back the accuracy of Sleep() without needing to link to winmm.lib
1046 typedef UINT (WINAPI* LPTIMEENDPERIOD)( UINT uPeriod );
1047 HINSTANCE hInstWinMM = LoadLibrary( "winmm.dll" );
1048 if( hInstWinMM ) {
1049 LPTIMEENDPERIOD pTimeEndPeriod = (LPTIMEENDPERIOD)GetProcAddress( hInstWinMM, "timeEndPeriod" );
1050 if( NULL != pTimeEndPeriod )
1051 pTimeEndPeriod(1);
1052 FreeLibrary(hInstWinMM);
1053 }
1054 // Clean up the WinSocket connectios
1055 ::WSACleanup();
1056
1057 if (gGlobalEvent) {
1058 ::ResetEvent(gGlobalEvent);
1059 ::CloseHandle(gGlobalEvent);
1060 gGlobalEvent = 0;
1061 }
1062 if (gTimerThreadHandle) {
1063 ::TerminateThread(gTimerThreadHandle, 0);
1064 ::CloseHandle(gTimerThreadHandle);
1065 }
1066}
1067
1068////////////////////////////////////////////////////////////////////////////////
1069/// Initialize WinNT system interface.
1070
1072{
1073 if (TSystem::Init())
1074 return kTRUE;
1075
1076 fReadmask = new TFdSet;
1077 fWritemask = new TFdSet;
1078 fReadready = new TFdSet;
1079 fWriteready = new TFdSet;
1080 fSignals = new TFdSet;
1081 fNfd = 0;
1082
1083 //--- install default handlers
1084 // Actually: don't. If we want a stack trace we need a context for the
1085 // signal. Signals don't have one. If we don't handle them, Windows will
1086 // raise an exception, which has a context, and which is handled by
1087 // ExceptionFilter.
1088 //WinNTSignal(kSigChild, SigHandler);
1089 //WinNTSignal(kSigBus, SigHandler);
1091 WinNTSignal(kSigIllegalInstruction, SigHandler);
1092 WinNTSignal(kSigAbort, SigHandler);
1093 //WinNTSignal(kSigSystem, SigHandler);
1094 //WinNTSignal(kSigPipe, SigHandler);
1095 //WinNTSignal(kSigAlarm, SigHandler);
1096 WinNTSignal(kSigFloatingException, SigHandler);
1097 ::SetUnhandledExceptionFilter(ExceptionFilter);
1098
1099 fSigcnt = 0;
1100
1101 // This is a fallback in case TROOT::GetRootSys() can't determine ROOTSYS
1103
1104 // Increase the accuracy of Sleep() without needing to link to winmm.lib
1105 typedef UINT (WINAPI* LPTIMEBEGINPERIOD)( UINT uPeriod );
1106 HINSTANCE hInstWinMM = LoadLibrary( "winmm.dll" );
1107 if( hInstWinMM ) {
1108 LPTIMEBEGINPERIOD pTimeBeginPeriod = (LPTIMEBEGINPERIOD)GetProcAddress( hInstWinMM, "timeBeginPeriod" );
1109 if( NULL != pTimeBeginPeriod )
1110 pTimeBeginPeriod(1);
1111 FreeLibrary(hInstWinMM);
1112 }
1113 gTimerThreadHandle = ::CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadStub,
1114 this, NULL, NULL);
1115
1116 gGlobalEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
1117 fGUIThreadHandle = ::CreateThread( NULL, 0, &GUIThreadMessageProcessingLoop, 0, 0, &fGUIThreadId );
1118
1119 char *buf = new char[MAX_MODULE_NAME32 + 1];
1120 HMODULE hModCore = ::GetModuleHandle("libCore.dll");
1121 if (hModCore) {
1122 ::GetModuleFileName(hModCore, buf, MAX_MODULE_NAME32 + 1);
1123 char *pLibName = strstr(buf, "libCore.dll");
1124 --pLibName; // remove trailing \\ or /
1125 *pLibName = 0;
1126 // add the directory containing libCore.dll in the dynamic search path
1127 if (buf[0]) AddDynamicPath(buf);
1128 }
1129 delete [] buf;
1130 SetConsoleWindowName();
1132 fFirstFile = kTRUE;
1133
1134 return kFALSE;
1135}
1136
1137//---- Misc --------------------------------------------------------------------
1138
1139////////////////////////////////////////////////////////////////////////////////
1140/// Base name of a file name. Base name of /user/root is root.
1141/// But the base name of '/' is '/'
1142/// 'c:\' is 'c:\'
1143
1144const char *TWinNTSystem::BaseName(const char *name)
1145{
1146 // BB 28/10/05 : Removed (commented out) StrDup() :
1147 // - To get same behaviour on Windows and on Linux
1148 // - To avoid the need to use #ifdefs
1149 // - Solve memory leaks (mainly in TTF::SetTextFont())
1150 // No need for the calling routine to use free() anymore.
1151
1152 if (name) {
1153 int idx = 0;
1154 const char *symbol=name;
1155
1156 // Skip leading blanks
1157 while ( (*symbol == ' ' || *symbol == '\t') && *symbol) symbol++;
1158
1159 if (*symbol) {
1160 if (isalpha(symbol[idx]) && symbol[idx+1] == ':') idx = 2;
1161 if ( (symbol[idx] == '/' || symbol[idx] == '\\') && symbol[idx+1] == '\0') {
1162 //return StrDup(symbol);
1163 return symbol;
1164 }
1165 } else {
1166 Error("BaseName", "name = 0");
1167 return nullptr;
1168 }
1169 char *cp;
1170 char *bslash = (char *)strrchr(&symbol[idx],'\\');
1171 char *rslash = (char *)strrchr(&symbol[idx],'/');
1172 if (cp = (std::max)(rslash, bslash)) {
1173 //return StrDup(++cp);
1174 return ++cp;
1175 }
1176 //return StrDup(&symbol[idx]);
1177 return &symbol[idx];
1178 }
1179 Error("BaseName", "name = 0");
1180 return nullptr;
1181}
1182
1183////////////////////////////////////////////////////////////////////////////////
1184/// Set the application name (from command line, argv[0]) and copy it in
1185/// gProgName. Copy the application pathname in gProgPath.
1186
1188{
1189 ULong_t idot = 0;
1190 char *dot = nullptr;
1191 char *progname;
1192 char *fullname = nullptr; // the program name with extension
1193
1194 // On command prompt the progname can be supplied with no extension (under Windows)
1195 ULong_t namelen=name ? strlen(name) : 0;
1196 if (name && namelen > 0) {
1197 // Check whether the name contains "extention"
1198 fullname = new char[namelen+5];
1199 strlcpy(fullname, name,namelen+5);
1200 if ( !strrchr(fullname, '.') )
1201 strlcat(fullname, ".exe",namelen+5);
1202
1203 progname = StrDup(BaseName(fullname));
1204 dot = strrchr(progname, '.');
1205 idot = dot ? (ULong_t)(dot - progname) : strlen(progname);
1206
1207 char *which = nullptr;
1208
1209 if (IsAbsoluteFileName(fullname) && !AccessPathName(fullname)) {
1210 which = StrDup(fullname);
1211 } else {
1212 which = Which(Form("%s;%s", WorkingDirectory(), Getenv("PATH")), progname);
1213 }
1214
1215 if (which) {
1216 TString dirname;
1217 char driveletter = DriveName(which);
1218 TString d = GetDirName(which);
1219
1220 if (driveletter) {
1221 dirname.Form("%c:%s", driveletter, d.Data());
1222 } else {
1223 dirname = d;
1224 }
1225
1226 gProgPath = StrDup(dirname);
1227 } else {
1228 // Do not issue a warning - ROOT is not using gProgPath anyway.
1229 // Warning("SetProgname",
1230 // "Cannot find this program named \"%s\" (Did you create a TApplication? Is this program in your %%PATH%%?)",
1231 // fullname);
1233 }
1234
1235 // Cut the extension for progname off
1236 progname[idot] = '\0';
1237 gProgName = StrDup(progname);
1238 if (which) delete [] which;
1239 delete[] fullname;
1240 delete[] progname;
1241 }
1242 if (::NeedSplash()) {
1244 }
1245}
1246
1247////////////////////////////////////////////////////////////////////////////////
1248/// Return system error string.
1249
1251{
1252 Int_t err = GetErrno();
1253 if (err == 0 && GetLastErrorString() != "")
1254 return GetLastErrorString();
1255 if (err < 0 || err >= sys_nerr) {
1256 static TString error_msg;
1257 error_msg.Form("errno out of range %d", err);
1258 return error_msg;
1259 }
1260 return sys_errlist[err];
1261}
1262
1263////////////////////////////////////////////////////////////////////////////////
1264/// Return the system's host name.
1265
1267{
1268 if (fHostname == "")
1269 fHostname = ::getenv("COMPUTERNAME");
1270 if (fHostname == "") {
1271 // This requires a DNS query - but we need it for fallback
1272 char hn[64];
1273 DWORD il = sizeof(hn);
1274 ::GetComputerName(hn, &il);
1275 fHostname = hn;
1276 }
1277 return fHostname;
1278}
1279
1280////////////////////////////////////////////////////////////////////////////////
1281/// Beep. If freq==0 (the default for TWinNTSystem), use ::MessageBeep.
1282/// Otherwise ::Beep with freq and duration.
1283
1284void TWinNTSystem::DoBeep(Int_t freq /*=-1*/, Int_t duration /*=-1*/) const
1285{
1286 if (freq == 0) {
1287 ::MessageBeep(-1);
1288 return;
1289 }
1290 if (freq < 37) freq = 440;
1291 if (duration < 0) duration = 100;
1292 ::Beep(freq, duration);
1293}
1294
1295////////////////////////////////////////////////////////////////////////////////
1296/// Set the (static part of) the event handler func for GUI messages.
1297
1299{
1300 gGUIThreadMsgFunc = func;
1301}
1302
1303////////////////////////////////////////////////////////////////////////////////
1304/// Hook to tell TSystem that the TApplication object has been created.
1305
1307{
1308 // send a dummy message to the GUI thread to kick it into life
1309 ::PostThreadMessage(fGUIThreadId, 0, NULL, 0L);
1310}
1311
1312
1313//---- EventLoop ---------------------------------------------------------------
1314
1315////////////////////////////////////////////////////////////////////////////////
1316/// Add a file handler to the list of system file handlers. Only adds
1317/// the handler if it is not already in the list of file handlers.
1318
1320{
1322 if (h) {
1323 int fd = h->GetFd();
1324 if (!fd) return;
1325
1326 if (h->HasReadInterest()) {
1327 fReadmask->Set(fd);
1328 }
1329 if (h->HasWriteInterest()) {
1330 fWritemask->Set(fd);
1331 }
1332 }
1333}
1334
1335////////////////////////////////////////////////////////////////////////////////
1336/// Remove a file handler from the list of file handlers. Returns
1337/// the handler or 0 if the handler was not in the list of file handlers.
1338
1340{
1341 if (!h) return nullptr;
1342
1344 if (oh) { // found
1345 fReadmask->Clr(h->GetFd());
1346 fWritemask->Clr(h->GetFd());
1347 }
1348 return oh;
1349}
1350
1351////////////////////////////////////////////////////////////////////////////////
1352/// Add a signal handler to list of system signal handlers. Only adds
1353/// the handler if it is not already in the list of signal handlers.
1354
1356{
1357 Bool_t set_console = kFALSE;
1358 ESignals sig = h->GetSignal();
1359
1360 if (sig == kSigInterrupt) {
1361 set_console = kTRUE;
1362 TSignalHandler *hs;
1363 TIter next(fSignalHandler);
1364
1365 while ((hs = (TSignalHandler*) next())) {
1366 if (hs->GetSignal() == kSigInterrupt)
1367 set_console = kFALSE;
1368 }
1369 }
1371
1372 // Add our handler to the list of the console handlers
1373 if (set_console)
1374 ::SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleSigHandler, TRUE);
1375 else
1376 WinNTSignal(h->GetSignal(), SigHandler);
1377}
1378
1379////////////////////////////////////////////////////////////////////////////////
1380/// Remove a signal handler from list of signal handlers. Returns
1381/// the handler or 0 if the handler was not in the list of signal handlers.
1382
1384{
1385 if (!h) return nullptr;
1386
1387 int sig = h->GetSignal();
1388
1389 if (sig = kSigInterrupt) {
1390 Bool_t last = kTRUE;
1391 TSignalHandler *hs;
1392 TIter next(fSignalHandler);
1393
1394 while ((hs = (TSignalHandler*) next())) {
1395 if (hs->GetSignal() == kSigInterrupt)
1396 last = kFALSE;
1397 }
1398 // Remove our handler from the list of the console handlers
1399 if (last)
1400 ::SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleSigHandler, FALSE);
1401 }
1403}
1404
1405////////////////////////////////////////////////////////////////////////////////
1406/// If reset is true reset the signal handler for the specified signal
1407/// to the default handler, else restore previous behaviour.
1408
1410{
1411 //FIXME!
1412}
1413
1414////////////////////////////////////////////////////////////////////////////////
1415/// Reset signals handlers to previous behaviour.
1416
1418{
1419 //FIXME!
1420}
1421
1422////////////////////////////////////////////////////////////////////////////////
1423/// If ignore is true ignore the specified signal, else restore previous
1424/// behaviour.
1425
1427{
1428 // FIXME!
1429}
1430
1431////////////////////////////////////////////////////////////////////////////////
1432/// Print a stack trace, if gEnv entry "Root.Stacktrace" is unset or 1,
1433/// and if the image helper functions can be found (see InitImagehlpFunctions()).
1434/// The stack trace is printed for each thread; if fgXcptContext is set (e.g.
1435/// because there was an exception) use it to define the current thread's context.
1436/// For each frame in the stack, the frame's module name, the frame's function
1437/// name, and the frame's line number are printed.
1438
1440{
1441 if (!gEnv->GetValue("Root.Stacktrace", 1))
1442 return;
1443
1444 HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,::GetCurrentProcessId());
1445
1446 std::cerr.flush();
1447 fflush (stderr);
1448
1449 if (!InitImagehlpFunctions()) {
1450 std::cerr << "No stack trace: cannot find (functions in) dbghelp.dll!" << std::endl;
1451 return;
1452 }
1453
1454 // what system are we on?
1455 SYSTEM_INFO sysInfo;
1456 ::GetSystemInfo(&sysInfo);
1457 DWORD machineType = IMAGE_FILE_MACHINE_I386;
1458 switch (sysInfo.wProcessorArchitecture) {
1459 case PROCESSOR_ARCHITECTURE_AMD64:
1460 machineType = IMAGE_FILE_MACHINE_AMD64;
1461 break;
1462 case PROCESSOR_ARCHITECTURE_IA64:
1463 machineType = IMAGE_FILE_MACHINE_IA64;
1464 break;
1465 }
1466
1467 DWORD currentThreadID = ::GetCurrentThreadId();
1468 DWORD currentProcessID = ::GetCurrentProcessId();
1469
1470 if (snapshot == INVALID_HANDLE_VALUE) return;
1471
1472 THREADENTRY32 threadentry;
1473 threadentry.dwSize = sizeof(THREADENTRY32);
1474 if (!::Thread32First(snapshot, &threadentry)) return;
1475
1476 std::cerr << std::endl << "==========================================" << std::endl;
1477 std::cerr << "=============== STACKTRACE ===============" << std::endl;
1478 std::cerr << "==========================================" << std::endl << std::endl;
1479 UInt_t iThread = 0;
1480 do {
1481 if (threadentry.th32OwnerProcessID != currentProcessID)
1482 continue;
1483 HANDLE thread = ::OpenThread(THREAD_GET_CONTEXT|THREAD_SUSPEND_RESUME|THREAD_QUERY_INFORMATION,
1484 FALSE, threadentry.th32ThreadID);
1485 CONTEXT context;
1486 memset(&context, 0, sizeof(CONTEXT));
1487
1488 if (threadentry.th32ThreadID != currentThreadID) {
1489 ::SuspendThread(thread);
1490 context.ContextFlags = CONTEXT_ALL;
1491 ::GetThreadContext(thread, &context);
1492 ::ResumeThread(thread);
1493 } else {
1494 if (fgXcptContext) {
1495 context = *fgXcptContext;
1496 } else {
1497 typedef void (WINAPI *RTLCCTXT)(PCONTEXT);
1498 RTLCCTXT p2RtlCCtxt = (RTLCCTXT) ::GetProcAddress(
1499 GetModuleHandle("kernel32.dll"), "RtlCaptureContext");
1500 if (p2RtlCCtxt) {
1501 context.ContextFlags = CONTEXT_ALL;
1502 p2RtlCCtxt(&context);
1503 }
1504 }
1505 }
1506
1507 STACKFRAME64 frame;
1508 ::ZeroMemory(&frame, sizeof(frame));
1509
1510 frame.AddrPC.Mode = AddrModeFlat;
1511 frame.AddrFrame.Mode = AddrModeFlat;
1512 frame.AddrStack.Mode = AddrModeFlat;
1513#if defined(_M_IX86)
1514 frame.AddrPC.Offset = context.Eip;
1515 frame.AddrFrame.Offset = context.Ebp;
1516 frame.AddrStack.Offset = context.Esp;
1517#elif defined(_M_X64)
1518 frame.AddrPC.Offset = context.Rip;
1519 frame.AddrFrame.Offset = context.Rsp;
1520 frame.AddrStack.Offset = context.Rsp;
1521#elif defined(_M_IA64)
1522 frame.AddrPC.Offset = context.StIIP;
1523 frame.AddrFrame.Offset = context.IntSp;
1524 frame.AddrStack.Offset = context.IntSp;
1525 frame.AddrBStore.Offset= context.RsBSP;
1526#else
1527 std::cerr << "Stack traces not supported on your architecture yet." << std::endl;
1528 return;
1529#endif
1530
1531 Bool_t bFirst = kTRUE;
1532 while (_StackWalk64(machineType, (HANDLE)::GetCurrentProcess(), thread, (LPSTACKFRAME64)&frame,
1533 (LPVOID)&context, (PREAD_PROCESS_MEMORY_ROUTINE)NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE)_SymFunctionTableAccess64,
1534 (PGET_MODULE_BASE_ROUTINE)_SymGetModuleBase64, NULL)) {
1535 if (bFirst)
1536 std::cerr << std::endl << "================ Thread " << iThread++ << " ================" << std::endl;
1537 if (!bFirst || threadentry.th32ThreadID != currentThreadID) {
1538 const std::string moduleName = GetModuleName(frame.AddrPC.Offset);
1539 const std::string functionName = GetFunctionName(frame.AddrPC.Offset);
1540 std::cerr << " " << moduleName << functionName << std::endl;
1541 }
1542 bFirst = kFALSE;
1543 }
1544 ::CloseHandle(thread);
1545 } while (::Thread32Next(snapshot, &threadentry));
1546
1547 std::cerr << std::endl << "==========================================" << std::endl;
1548 std::cerr << "============= END STACKTRACE =============" << std::endl;
1549 std::cerr << "==========================================" << std::endl << std::endl;
1550 ::CloseHandle(snapshot);
1551 _SymCleanup(GetCurrentProcess());
1552}
1553
1554////////////////////////////////////////////////////////////////////////////////
1555/// Return the bitmap of conditions that trigger a floating point exception.
1556
1558{
1559 Int_t mask = 0;
1560 UInt_t oldmask = _statusfp( );
1561
1562 if (oldmask & _EM_INVALID ) mask |= kInvalid;
1563 if (oldmask & _EM_ZERODIVIDE) mask |= kDivByZero;
1564 if (oldmask & _EM_OVERFLOW ) mask |= kOverflow;
1565 if (oldmask & _EM_UNDERFLOW) mask |= kUnderflow;
1566 if (oldmask & _EM_INEXACT ) mask |= kInexact;
1567
1568 return mask;
1569}
1570
1571////////////////////////////////////////////////////////////////////////////////
1572/// Set which conditions trigger a floating point exception.
1573/// Return the previous set of conditions.
1574
1576{
1577 Int_t old = GetFPEMask();
1578
1579 UInt_t newm = 0;
1580 if (mask & kInvalid ) newm |= _EM_INVALID;
1581 if (mask & kDivByZero) newm |= _EM_ZERODIVIDE;
1582 if (mask & kOverflow ) newm |= _EM_OVERFLOW;
1583 if (mask & kUnderflow) newm |= _EM_UNDERFLOW;
1584 if (mask & kInexact ) newm |= _EM_INEXACT;
1585
1586 UInt_t cm = ::_statusfp();
1587 cm &= ~newm;
1588 ::_controlfp(cm , _MCW_EM);
1589
1590 return old;
1591}
1592
1593////////////////////////////////////////////////////////////////////////////////
1594/// process pending events, i.e. DispatchOneEvent(kTRUE)
1595
1597{
1598 return TSystem::ProcessEvents();
1599}
1600
1601////////////////////////////////////////////////////////////////////////////////
1602/// Dispatch a single event in TApplication::Run() loop
1603
1605{
1606 // check for keyboard events
1607 if (pendingOnly && gGlobalEvent) ::SetEvent(gGlobalEvent);
1608
1609 Bool_t pollOnce = pendingOnly;
1610
1611 while (1) {
1612 if (_kbhit()) {
1613 if (gROOT->GetApplication()) {
1615 if (gSplash) { // terminate splash window after first key press
1616 delete gSplash;
1617 gSplash = 0;
1618 }
1619 if (!pendingOnly) {
1620 return;
1621 }
1622 }
1623 }
1624 if (gROOT->IsLineProcessing() && (!gVirtualX || !gVirtualX->IsCmdThread())) {
1625 if (!pendingOnly) {
1626 // yield execution to another thread that is ready to run
1627 // if no other thread is ready, sleep 1 ms before to return
1628 if (gGlobalEvent) {
1629 ::WaitForSingleObject(gGlobalEvent, 1);
1630 ::ResetEvent(gGlobalEvent);
1631 }
1632 return;
1633 }
1634 }
1635 // first handle any GUI events
1636 if (gXDisplay && !gROOT->IsBatch()) {
1637 if (gXDisplay->Notify()) {
1638 if (!pendingOnly) {
1639 return;
1640 }
1641 }
1642 }
1643
1644 // check for file descriptors ready for reading/writing
1645 if ((fNfd > 0) && fFileHandler && (fFileHandler->GetSize() > 0)) {
1646 if (CheckDescriptors()) {
1647 if (!pendingOnly) {
1648 return;
1649 }
1650 }
1651 }
1652 fNfd = 0;
1653 fReadready->Zero();
1654 fWriteready->Zero();
1655
1656 if (pendingOnly && !pollOnce)
1657 return;
1658
1659 // check synchronous signals
1660 if (fSigcnt > 0 && fSignalHandler->GetSize() > 0) {
1661 if (CheckSignals(kTRUE)) {
1662 if (!pendingOnly) {
1663 return;
1664 }
1665 }
1666 }
1667 fSigcnt = 0;
1668 fSignals->Zero();
1669
1670 // handle past due timers
1671 Long_t nextto;
1672 if (fTimers && fTimers->GetSize() > 0) {
1673 if (DispatchTimers(kTRUE)) {
1674 // prevent timers from blocking the rest types of events
1675 nextto = NextTimeOut(kTRUE);
1676 if (nextto > (kItimerResolution>>1) || nextto == -1) {
1677 return;
1678 }
1679 }
1680 }
1681
1682 // if in pendingOnly mode poll once file descriptor activity
1683 nextto = NextTimeOut(kTRUE);
1684 if (pendingOnly) {
1685 if (fFileHandler && fFileHandler->GetSize() == 0)
1686 return;
1687 nextto = 0;
1688 pollOnce = kFALSE;
1689 }
1690
1691 if (fReadmask && !fReadmask->GetBits() &&
1692 fWritemask && !fWritemask->GetBits()) {
1693 // yield execution to another thread that is ready to run
1694 // if no other thread is ready, sleep 1 ms before to return
1695 if (!pendingOnly && gGlobalEvent) {
1696 ::WaitForSingleObject(gGlobalEvent, 1);
1697 ::ResetEvent(gGlobalEvent);
1698 }
1699 return;
1700 }
1701
1704
1705 fNfd = WinNTSelect(fReadready, fWriteready, nextto);
1706
1707 // serious error has happened -> reset all file descrptors
1708 if ((fNfd < 0) && (fNfd != -2)) {
1709 int rc, i;
1710
1711 for (i = 0; i < fReadmask->GetCount(); i++) {
1712 TFdSet t;
1713 Int_t fd = fReadmask->GetFd(i);
1714 t.Set(fd);
1715 if (fReadmask->IsSet(fd)) {
1716 rc = WinNTSelect(&t, 0, 0);
1717 if (rc < 0 && rc != -2) {
1718 ::SysError("DispatchOneEvent", "select: read error on %d\n", fd);
1719 fReadmask->Clr(fd);
1720 }
1721 }
1722 }
1723
1724 for (i = 0; i < fWritemask->GetCount(); i++) {
1725 TFdSet t;
1726 Int_t fd = fWritemask->GetFd(i);
1727 t.Set(fd);
1728
1729 if (fWritemask->IsSet(fd)) {
1730 rc = WinNTSelect(0, &t, 0);
1731 if (rc < 0 && rc != -2) {
1732 ::SysError("DispatchOneEvent", "select: write error on %d\n", fd);
1733 fWritemask->Clr(fd);
1734 }
1735 }
1736 t.Clr(fd);
1737 }
1738 }
1739 }
1740}
1741
1742////////////////////////////////////////////////////////////////////////////////
1743/// Exit from event loop.
1744
1746{
1748}
1749
1750//---- handling of system events -----------------------------------------------
1751////////////////////////////////////////////////////////////////////////////////
1752/// Handle and dispatch signals.
1753
1755{
1756 if (sig == kSigInterrupt) {
1757 fSignals->Set(sig);
1758 fSigcnt++;
1759 }
1760 else {
1761 if (gExceptionHandler) {
1762 //sig is ESignal, should it be mapped to the correct signal number?
1763 if (sig == kSigFloatingException) _fpreset();
1765 } else {
1766 if (sig == kSigAbort)
1767 return;
1768 //map to the real signal code + set the
1769 //high order bit to indicate a signal (?)
1770 StackTrace();
1771 if (TROOT::Initialized()) {
1772 ::Throw(sig);
1773 }
1774 }
1775 Abort(-1);
1776 }
1777
1778 // check a-synchronous signals
1779 if (fSigcnt > 0 && fSignalHandler->GetSize() > 0)
1781}
1782
1783////////////////////////////////////////////////////////////////////////////////
1784/// Check if some signals were raised and call their Notify() member.
1785
1787{
1788 TSignalHandler *sh;
1789 Int_t sigdone = -1;
1790 {
1791 TIter next(fSignalHandler);
1792
1793 while (sh = (TSignalHandler*)next()) {
1794 if (sync == sh->IsSync()) {
1795 ESignals sig = sh->GetSignal();
1796 if ((fSignals->IsSet(sig) && sigdone == -1) || sigdone == sig) {
1797 if (sigdone == -1) {
1798 fSignals->Clr(sig);
1799 sigdone = sig;
1800 fSigcnt--;
1801 }
1802 sh->Notify();
1803 }
1804 }
1805 }
1806 }
1807 if (sigdone != -1) return kTRUE;
1808
1809 return kFALSE;
1810}
1811
1812////////////////////////////////////////////////////////////////////////////////
1813/// Check if there is activity on some file descriptors and call their
1814/// Notify() member.
1815
1817{
1818 TFileHandler *fh;
1819 Int_t fddone = -1;
1820 Bool_t read = kFALSE;
1821
1823
1824 while ((fh = (TFileHandler*) it.Next())) {
1825 Int_t fd = fh->GetFd();
1826 if (!fd) continue; // ignore TTermInputHandler
1827
1828 if ((fReadready->IsSet(fd) && fddone == -1) ||
1829 (fddone == fd && read)) {
1830 if (fddone == -1) {
1831 fReadready->Clr(fd);
1832 fddone = fd;
1833 read = kTRUE;
1834 fNfd--;
1835 }
1836 fh->ReadNotify();
1837 }
1838 if ((fWriteready->IsSet(fd) && fddone == -1) ||
1839 (fddone == fd && !read)) {
1840 if (fddone == -1) {
1841 fWriteready->Clr(fd);
1842 fddone = fd;
1843 read = kFALSE;
1844 fNfd--;
1845 }
1846 fh->WriteNotify();
1847 }
1848 }
1849 if (fddone != -1) return kTRUE;
1850
1851 return kFALSE;
1852}
1853
1854//---- Directories -------------------------------------------------------------
1855
1856////////////////////////////////////////////////////////////////////////////////
1857/// Make a file system directory. Returns 0 in case of success and
1858/// -1 if the directory could not be created (either already exists or
1859/// illegal path name).
1860/// If 'recursive' is true, makes parent directories as needed.
1861
1862int TWinNTSystem::mkdir(const char *name, Bool_t recursive)
1863{
1864 if (recursive) {
1865 TString dirname = GetDirName(name);
1866 if (dirname.Length() == 0) {
1867 // well we should not have to make the root of the file system!
1868 // (and this avoid infinite recursions!)
1869 return 0;
1870 }
1871 if (IsAbsoluteFileName(name)) {
1872 // For some good reason DirName strips off the drive letter
1873 // (if present), we need it to make the directory on the
1874 // right disk, so let's put it back!
1875 const char driveletter = DriveName(name);
1876 if (driveletter) {
1877 dirname.Prepend(":");
1878 dirname.Prepend(driveletter);
1879 }
1880 }
1881 if (AccessPathName(dirname, kFileExists)) {
1882 int res = this->mkdir(dirname, kTRUE);
1883 if (res) return res;
1884 }
1886 return -1;
1887 }
1888 }
1889 return MakeDirectory(name);
1890}
1891
1892////////////////////////////////////////////////////////////////////////////////
1893/// Make a WinNT file system directory. Returns 0 in case of success and
1894/// -1 if the directory could not be created (either already exists or
1895/// illegal path name).
1896
1898{
1899 TSystem *helper = FindHelper(name);
1900 if (helper) {
1901 return helper->MakeDirectory(name);
1902 }
1903 const char *proto = (strstr(name, "file:///")) ? "file://" : "file:";
1904#ifdef WATCOM
1905 // It must be as follows
1906 if (!name) return 0;
1907 return ::mkdir(StripOffProto(name, proto));
1908#else
1909 // but to be in line with TUnixSystem I did like this
1910 if (!name) return 0;
1911 return ::_mkdir(StripOffProto(name, proto));
1912#endif
1913}
1914
1915////////////////////////////////////////////////////////////////////////////////
1916/// Close a WinNT file system directory.
1917
1919{
1920 TSystem *helper = FindHelper(0, dirp);
1921 if (helper) {
1922 helper->FreeDirectory(dirp);
1923 return;
1924 }
1925
1926 if (dirp) {
1927 ::FindClose(dirp);
1928 }
1929}
1930
1931////////////////////////////////////////////////////////////////////////////////
1932/// Returns the next directory entry.
1933
1934const char *TWinNTSystem::GetDirEntry(void *dirp)
1935{
1936 TSystem *helper = FindHelper(0, dirp);
1937 if (helper) {
1938 return helper->GetDirEntry(dirp);
1939 }
1940
1941 if (dirp) {
1942 HANDLE searchFile = (HANDLE)dirp;
1943 if (fFirstFile) {
1944 // when calling TWinNTSystem::OpenDirectory(), the fFindFileData
1945 // structure is filled by a call to FindFirstFile().
1946 // So first returns this one, before calling FindNextFile()
1948 return (const char *)fFindFileData.cFileName;
1949 }
1950 if (::FindNextFile(searchFile, &fFindFileData)) {
1951 return (const char *)fFindFileData.cFileName;
1952 }
1953 }
1954 return nullptr;
1955}
1956
1957////////////////////////////////////////////////////////////////////////////////
1958/// Change directory.
1959
1961{
1962 Bool_t ret = (Bool_t) (::chdir(path) == 0);
1963 if (fWdpath != "")
1964 fWdpath = ""; // invalidate path cache
1965 return ret;
1966}
1967
1968////////////////////////////////////////////////////////////////////////////////
1969///
1970/// Inline function to check for a double-backslash at the
1971/// beginning of a string
1972///
1973
1974__inline BOOL DBL_BSLASH(LPCTSTR psz)
1975{
1976 return (psz[0] == TEXT('\\') && psz[1] == TEXT('\\'));
1977}
1978
1979////////////////////////////////////////////////////////////////////////////////
1980/// Returns TRUE if the given string is a UNC path.
1981///
1982/// TRUE
1983/// "\\foo\bar"
1984/// "\\foo" <- careful
1985/// "\\"
1986/// FALSE
1987/// "\foo"
1988/// "foo"
1989/// "c:\foo"
1990
1991BOOL PathIsUNC(LPCTSTR pszPath)
1992{
1993 return DBL_BSLASH(pszPath);
1994}
1995
1996#pragma data_seg(".text", "CODE")
1997const TCHAR c_szColonSlash[] = TEXT(":\\");
1998#pragma data_seg()
1999
2000////////////////////////////////////////////////////////////////////////////////
2001///
2002/// check if a path is a root
2003///
2004/// returns:
2005/// TRUE for "\" "X:\" "\\foo\asdf" "\\foo\"
2006/// FALSE for others
2007///
2008
2009BOOL PathIsRoot(LPCTSTR pPath)
2010{
2011 if (!IsDBCSLeadByte(*pPath)) {
2012 if (!lstrcmpi(pPath + 1, c_szColonSlash))
2013 // "X:\" case
2014 return TRUE;
2015 }
2016 if ((*pPath == TEXT('\\')) && (*(pPath + 1) == 0))
2017 // "\" case
2018 return TRUE;
2019 if (DBL_BSLASH(pPath)) {
2020 // smells like UNC name
2021 LPCTSTR p;
2022 int cBackslashes = 0;
2023 for (p = pPath + 2; *p; p = CharNext(p)) {
2024 if (*p == TEXT('\\') && (++cBackslashes > 1))
2025 return FALSE; // not a bare UNC name, therefore not a root dir
2026 }
2027 // end of string with only 1 more backslash
2028 // must be a bare UNC, which looks like a root dir
2029 return TRUE;
2030 }
2031 return FALSE;
2032}
2033
2034////////////////////////////////////////////////////////////////////////////////
2035/// Open a directory. Returns 0 if directory does not exist.
2036
2037void *TWinNTSystem::OpenDirectory(const char *fdir)
2038{
2039 TSystem *helper = FindHelper(fdir);
2040 if (helper) {
2041 return helper->OpenDirectory(fdir);
2042 }
2043
2044 const char *proto = (strstr(fdir, "file:///")) ? "file://" : "file:";
2045 const char *sdir = StripOffProto(fdir, proto);
2046
2047 char *dir = new char[MAX_PATH];
2048 if (IsShortcut(sdir)) {
2049 if (!ResolveShortCut(sdir, dir, MAX_PATH))
2050 strlcpy(dir, sdir,MAX_PATH);
2051 }
2052 else
2053 strlcpy(dir, sdir,MAX_PATH);
2054
2055 int nche = strlen(dir)+3;
2056 char *entry = new char[nche];
2057 struct _stati64 finfo;
2058
2059 if(PathIsUNC(dir)) {
2060 strlcpy(entry, dir,nche);
2061 if ((entry[strlen(dir)-1] == '/') || (entry[strlen(dir)-1] == '\\' )) {
2062 entry[strlen(dir)-1] = '\0';
2063 }
2064 if(PathIsRoot(entry)) {
2065 strlcat(entry,"\\",nche);
2066 }
2067 if (_stati64(entry, &finfo) < 0) {
2068 delete [] entry;
2069 delete [] dir;
2070 return nullptr;
2071 }
2072 } else {
2073 strlcpy(entry, dir,nche);
2074 if ((entry[strlen(dir)-1] == '/') || (entry[strlen(dir)-1] == '\\' )) {
2075 if(!PathIsRoot(entry))
2076 entry[strlen(dir)-1] = '\0';
2077 }
2078 if (_stati64(entry, &finfo) < 0) {
2079 delete [] entry;
2080 delete [] dir;
2081 return nullptr;
2082 }
2083 }
2084
2085 if (finfo.st_mode & S_IFDIR) {
2086 strlcpy(entry, dir,nche);
2087 if (!(entry[strlen(dir)-1] == '/' || entry[strlen(dir)-1] == '\\' )) {
2088 strlcat(entry,"\\",nche);
2089 }
2090 if (entry[strlen(dir)-1] == ' ')
2091 entry[strlen(dir)-1] = '\0';
2092 strlcat(entry,"*",nche);
2093
2094 HANDLE searchFile;
2095 searchFile = ::FindFirstFile(entry, &fFindFileData);
2096 if (searchFile == INVALID_HANDLE_VALUE) {
2097 ((TWinNTSystem *)gSystem)->Error( "Unable to find' for reading:", entry);
2098 delete [] entry;
2099 delete [] dir;
2100 return nullptr;
2101 }
2102 delete [] entry;
2103 delete [] dir;
2104 fFirstFile = kTRUE;
2105 return searchFile;
2106 }
2107
2108 delete [] entry;
2109 delete [] dir;
2110 return nullptr;
2111}
2112
2113////////////////////////////////////////////////////////////////////////////////
2114/// Return the working directory for the default drive
2115
2117{
2118 return WorkingDirectory('\0');
2119}
2120
2121//////////////////////////////////////////////////////////////////////////////
2122/// Return the working directory for the default drive
2123
2125{
2126 char *wdpath = GetWorkingDirectory('\0');
2127 std::string cwd;
2128 if (wdpath) {
2129 cwd = wdpath;
2130 free(wdpath);
2131 }
2132 return cwd;
2133}
2134
2135////////////////////////////////////////////////////////////////////////////////
2136/// Return working directory for the selected drive
2137/// driveletter == 0 means return the working durectory for the default drive
2138
2139const char *TWinNTSystem::WorkingDirectory(char driveletter)
2140{
2141 char *wdpath = GetWorkingDirectory(driveletter);
2142 if (wdpath) {
2143 fWdpath = wdpath;
2144
2145 // Make sure the drive letter is upper case
2146 if (fWdpath[1] == ':')
2147 fWdpath[0] = toupper(fWdpath[0]);
2148
2149 free(wdpath);
2150 }
2151 return fWdpath;
2152}
2153
2154//////////////////////////////////////////////////////////////////////////////
2155/// Return working directory for the selected drive (helper function).
2156/// The caller must free the return value.
2157
2158char *TWinNTSystem::GetWorkingDirectory(char driveletter) const
2159{
2160 char *wdpath = nullptr;
2161 char drive = driveletter ? toupper( driveletter ) - 'A' + 1 : 0;
2162
2163 // don't use cache as user can call chdir() directly somewhere else
2164 //if (fWdpath != "" )
2165 // return fWdpath;
2166
2167 if (!(wdpath = ::_getdcwd( (int)drive, wdpath, kMAXPATHLEN))) {
2168 free(wdpath);
2169 Warning("WorkingDirectory", "getcwd() failed");
2170 return nullptr;
2171 }
2172
2173 return wdpath;
2174}
2175
2176////////////////////////////////////////////////////////////////////////////////
2177/// Return the user's home directory.
2178
2179const char *TWinNTSystem::HomeDirectory(const char *userName)
2180{
2181 static char mydir[kMAXPATHLEN] = "./";
2182 FillWithHomeDirectory(userName, mydir);
2183 return mydir;
2184}
2185
2186//////////////////////////////////////////////////////////////////////////////
2187/// Return the user's home directory.
2188
2189std::string TWinNTSystem::GetHomeDirectory(const char *userName) const
2190{
2191 char mydir[kMAXPATHLEN] = "./";
2192 FillWithHomeDirectory(userName, mydir);
2193 return std::string(mydir);
2194}
2195
2196//////////////////////////////////////////////////////////////////////////////
2197/// Fill buffer with user's home directory.
2198
2199void TWinNTSystem::FillWithHomeDirectory(const char *userName, char *mydir) const
2200{
2201 const char *h = nullptr;
2202 if (!(h = ::getenv("home"))) h = ::getenv("HOME");
2203
2204 if (h) {
2205 strlcpy(mydir, h,kMAXPATHLEN);
2206 } else {
2207 // for Windows NT HOME might be defined as either $(HOMESHARE)/$(HOMEPATH)
2208 // or $(HOMEDRIVE)/$(HOMEPATH)
2209 h = ::getenv("HOMESHARE");
2210 if (!h) h = ::getenv("HOMEDRIVE");
2211 if (h) {
2212 strlcpy(mydir, h,kMAXPATHLEN);
2213 h = ::getenv("HOMEPATH");
2214 if(h) strlcat(mydir, h,kMAXPATHLEN);
2215 }
2216 // on Windows Vista HOME is usually defined as $(USERPROFILE)
2217 if (!h) {
2218 h = ::getenv("USERPROFILE");
2219 if (h) strlcpy(mydir, h,kMAXPATHLEN);
2220 }
2221 }
2222 // Make sure the drive letter is upper case
2223 if (mydir[1] == ':')
2224 mydir[0] = toupper(mydir[0]);
2225}
2226
2227
2228////////////////////////////////////////////////////////////////////////////////
2229/// Return a user configured or systemwide directory to create
2230/// temporary files in.
2231
2233{
2234 const char *dir = gSystem->Getenv("TEMP");
2235 if (!dir) dir = gSystem->Getenv("TEMPDIR");
2236 if (!dir) dir = gSystem->Getenv("TEMP_DIR");
2237 if (!dir) dir = gSystem->Getenv("TMP");
2238 if (!dir) dir = gSystem->Getenv("TMPDIR");
2239 if (!dir) dir = gSystem->Getenv("TMP_DIR");
2240 if (!dir) dir = "c:\\";
2241
2242 return dir;
2243}
2244
2245////////////////////////////////////////////////////////////////////////////////
2246/// Create a secure temporary file by appending a unique
2247/// 6 letter string to base. The file will be created in
2248/// a standard (system) directory or in the directory
2249/// provided in dir. The full filename is returned in base
2250/// and a filepointer is returned for safely writing to the file
2251/// (this avoids certain security problems). Returns 0 in case
2252/// of error.
2253
2254FILE *TWinNTSystem::TempFileName(TString &base, const char *dir)
2255{
2256 char tmpName[MAX_PATH];
2257
2258 ::GetTempFileName(dir ? dir : TempDirectory(), base.Data(), 0, tmpName);
2259 base = tmpName;
2260 FILE *fp = fopen(tmpName, "w+");
2261
2262 if (!fp) ::SysError("TempFileName", "error opening %s", tmpName);
2263
2264 return fp;
2265}
2266
2267//---- Paths & Files -----------------------------------------------------------
2268
2269////////////////////////////////////////////////////////////////////////////////
2270/// Get list of volumes (drives) mounted on the system.
2271/// The returned TList must be deleted by the user using "delete".
2272
2274{
2275 Int_t curdrive;
2276 UInt_t type;
2277 TString sDrive, sType;
2278 char szFs[32];
2279
2280 if (!opt || !opt[0]) {
2281 return 0;
2282 }
2283
2284 // prevent the system dialog box to pop-up if a drive is empty
2285 UINT nOldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
2286 TList *drives = new TList();
2287 drives->SetOwner();
2288 // Save current drive
2289 curdrive = _getdrive();
2290 if (strstr(opt, "cur")) {
2291 *szFs='\0';
2292 sDrive.Form("%c:", (curdrive + 'A' - 1));
2293 sType.Form("Unknown Drive (%s)", sDrive.Data());
2294 ::GetVolumeInformation(Form("%s\\", sDrive.Data()), NULL, 0, NULL, NULL,
2295 NULL, (LPSTR)szFs, 32);
2296 type = ::GetDriveType(sDrive.Data());
2297 switch (type) {
2298 case DRIVE_UNKNOWN:
2299 case DRIVE_NO_ROOT_DIR:
2300 break;
2301 case DRIVE_REMOVABLE:
2302 sType.Form("Removable Disk (%s)", sDrive.Data());
2303 break;
2304 case DRIVE_FIXED:
2305 sType.Form("Local Disk (%s)", sDrive.Data());
2306 break;
2307 case DRIVE_REMOTE:
2308 sType.Form("Network Drive (%s) (%s)", szFs, sDrive.Data());
2309 break;
2310 case DRIVE_CDROM:
2311 sType.Form("CD/DVD Drive (%s)", sDrive.Data());
2312 break;
2313 case DRIVE_RAMDISK:
2314 sType.Form("RAM Disk (%s)", sDrive.Data());
2315 break;
2316 }
2317 drives->Add(new TNamed(sDrive.Data(), sType.Data()));
2318 }
2319 else if (strstr(opt, "all")) {
2320 TCHAR szTemp[512];
2321 szTemp[0] = '\0';
2322 if (::GetLogicalDriveStrings(511, szTemp)) {
2323 TCHAR szDrive[3] = TEXT(" :");
2324 TCHAR* p = szTemp;
2325 do {
2326 // Copy the drive letter to the template string
2327 *szDrive = *p;
2328 *szFs='\0';
2329 sDrive.Form("%s", szDrive);
2330 // skip floppy drives, to avoid accessing them each time...
2331 if ((sDrive == "A:") || (sDrive == "B:")) {
2332 while (*p++);
2333 continue;
2334 }
2335 sType.Form("Unknown Drive (%s)", sDrive.Data());
2336 ::GetVolumeInformation(Form("%s\\", sDrive.Data()), NULL, 0, NULL,
2337 NULL, NULL, (LPSTR)szFs, 32);
2338 type = ::GetDriveType(sDrive.Data());
2339 switch (type) {
2340 case DRIVE_UNKNOWN:
2341 case DRIVE_NO_ROOT_DIR:
2342 break;
2343 case DRIVE_REMOVABLE:
2344 sType.Form("Removable Disk (%s)", sDrive.Data());
2345 break;
2346 case DRIVE_FIXED:
2347 sType.Form("Local Disk (%s)", sDrive.Data());
2348 break;
2349 case DRIVE_REMOTE:
2350 sType.Form("Network Drive (%s) (%s)", szFs, sDrive.Data());
2351 break;
2352 case DRIVE_CDROM:
2353 sType.Form("CD/DVD Drive (%s)", sDrive.Data());
2354 break;
2355 case DRIVE_RAMDISK:
2356 sType.Form("RAM Disk (%s)", sDrive.Data());
2357 break;
2358 }
2359 drives->Add(new TNamed(sDrive.Data(), sType.Data()));
2360 // Go to the next NULL character.
2361 while (*p++);
2362 } while (*p); // end of string
2363 }
2364 }
2365 // restore previous error mode
2366 ::SetErrorMode(nOldErrorMode);
2367 return drives;
2368}
2369
2370////////////////////////////////////////////////////////////////////////////////
2371/// Return the directory name in pathname. DirName of c:/user/root is /user.
2372/// It creates output with 'new char []' operator. Returned string has to
2373/// be deleted.
2374
2375const char *TWinNTSystem::DirName(const char *pathname)
2376{
2377 fDirNameBuffer = GetDirName(pathname);
2378 return fDirNameBuffer.c_str();
2379}
2380
2381////////////////////////////////////////////////////////////////////////////////
2382/// Return the directory name in pathname. DirName of c:/user/root is /user.
2383/// DirName of c:/user/root/ is /user/root.
2384
2386{
2387 // Create a buffer to keep the path name
2388 if (pathname) {
2389 if (strchr(pathname, '/') || strchr(pathname, '\\')) {
2390 const char *rslash = strrchr(pathname, '/');
2391 const char *bslash = strrchr(pathname, '\\');
2392 const char *r = std::max(rslash, bslash);
2393 const char *ptr = pathname;
2394 while (ptr <= r) {
2395 if (*ptr == ':') {
2396 // Windows path may contain a drive letter
2397 // For NTFS ":" may be a "stream" delimiter as well
2398 pathname = ptr + 1;
2399 break;
2400 }
2401 ptr++;
2402 }
2403 int len = r - pathname;
2404 if (len > 0)
2405 return TString(pathname, len);
2406 }
2407 }
2408 return "";
2409}
2410
2411////////////////////////////////////////////////////////////////////////////////
2412/// Return the drive letter in pathname. DriveName of 'c:/user/root' is 'c'
2413///
2414/// Input:
2415/// - pathname - the string containing file name
2416///
2417/// Return:
2418/// - Letter representing the drive letter in the file name
2419/// - The current drive if the pathname has no drive assigment
2420/// - 0 if pathname is an empty string or uses UNC syntax
2421///
2422/// Note:
2423/// It doesn't check whether pathname represents a 'real' filename.
2424/// This subroutine looks for 'single letter' followed by a ':'.
2425
2426const char TWinNTSystem::DriveName(const char *pathname)
2427{
2428 if (!pathname) return 0;
2429 if (!pathname[0]) return 0;
2430
2431 const char *lpchar;
2432 lpchar = pathname;
2433
2434 // Skip blanks
2435 while(*lpchar == ' ') lpchar++;
2436
2437 if (isalpha((int)*lpchar) && *(lpchar+1) == ':') {
2438 return *lpchar;
2439 }
2440 // Test UNC syntax
2441 if ( (*lpchar == '\\' || *lpchar == '/' ) &&
2442 (*(lpchar+1) == '\\' || *(lpchar+1) == '/') ) return 0;
2443
2444 // return the current drive
2445 return DriveName(WorkingDirectory());
2446}
2447
2448////////////////////////////////////////////////////////////////////////////////
2449/// Return true if dir is an absolute pathname.
2450
2452{
2453 if (dir) {
2454 int idx = 0;
2455 if (strchr(dir,':')) idx = 2;
2456 return (dir[idx] == '/' || dir[idx] == '\\');
2457 }
2458 return kFALSE;
2459}
2460
2461////////////////////////////////////////////////////////////////////////////////
2462/// Convert a pathname to a unix pathname. E.g. form \user\root to /user/root.
2463/// General rules for applications creating names for directories and files or
2464/// processing names supplied by the user include the following:
2465///
2466/// * Use any character in the current code page for a name, but do not use
2467/// a path separator, a character in the range 0 through 31, or any character
2468/// explicitly disallowed by the file system. A name can contain characters
2469/// in the extended character set (128-255).
2470/// * Use the backslash (\‍), the forward slash (/), or both to separate
2471/// components in a path. No other character is acceptable as a path separator.
2472/// * Use a period (.) as a directory component in a path to represent the
2473/// current directory.
2474/// * Use two consecutive periods (..) as a directory component in a path to
2475/// represent the parent of the current directory.
2476/// * Use a period (.) to separate components in a directory name or filename.
2477/// * Do not use the following characters in directory names or filenames, because
2478/// they are reserved for Windows:
2479/// < > : " / \ |
2480/// * Do not use reserved words, such as aux, con, and prn, as filenames or
2481/// directory names.
2482/// * Process a path as a null-terminated string. The maximum length for a path
2483/// is given by MAX_PATH.
2484/// * Do not assume case sensitivity. Consider names such as OSCAR, Oscar, and
2485/// oscar to be the same.
2486
2487const char *TWinNTSystem::UnixPathName(const char *name)
2488{
2489 const int kBufSize = 1024;
2490 TTHREAD_TLS_ARRAY(char, kBufSize, temp);
2491
2492 strlcpy(temp, name, kBufSize);
2493 char *currentChar = temp;
2494
2495 // This can not change the size of the string.
2496 while (*currentChar != '\0') {
2497 if (*currentChar == '\\') *currentChar = '/';
2498 currentChar++;
2499 }
2500 return temp;
2501}
2502
2503////////////////////////////////////////////////////////////////////////////////
2504/// Returns FALSE if one can access a file using the specified access mode.
2505/// Mode is the same as for the WinNT access(2) function.
2506/// Attention, bizarre convention of return value!!
2507
2509{
2510 TSystem *helper = FindHelper(path);
2511 if (helper)
2512 return helper->AccessPathName(path, mode);
2513
2514 // prevent the system dialog box to pop-up if a drive is empty
2515 UINT nOldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
2516 if (mode==kExecutePermission)
2517 // cannot test on exe - use read instead
2518 mode=kReadPermission;
2519 const char *proto = (strstr(path, "file:///")) ? "file://" : "file:";
2520 if (::_access(StripOffProto(path, proto), mode) == 0) {
2521 // restore previous error mode
2522 ::SetErrorMode(nOldErrorMode);
2523 return kFALSE;
2524 }
2526 // restore previous error mode
2527 ::SetErrorMode(nOldErrorMode);
2528 return kTRUE;
2529}
2530
2531////////////////////////////////////////////////////////////////////////////////
2532/// Returns TRUE if the url in 'path' points to the local file system.
2533/// This is used to avoid going through the NIC card for local operations.
2534
2536{
2537 TSystem *helper = FindHelper(path);
2538 if (helper)
2539 return helper->IsPathLocal(path);
2540
2541 return TSystem::IsPathLocal(path);
2542}
2543
2544////////////////////////////////////////////////////////////////////////////////
2545/// Concatenate a directory and a file name.
2546
2547const char *TWinNTSystem::PrependPathName(const char *dir, TString& name)
2548{
2549 if (name == ".") name = "";
2550 if (dir && dir[0]) {
2551 // Test whether the last symbol of the directory is a separator
2552 char last = dir[strlen(dir) - 1];
2553 if (last != '/' && last != '\\') {
2554 name.Prepend('\\');
2555 }
2556 name.Prepend(dir);
2557 name.ReplaceAll("/", "\\");
2558 }
2559 return name.Data();
2560}
2561
2562////////////////////////////////////////////////////////////////////////////////
2563/// Copy a file. If overwrite is true and file already exists the
2564/// file will be overwritten. Returns 0 when successful, -1 in case
2565/// of failure, -2 in case the file already exists and overwrite was false.
2566
2567int TWinNTSystem::CopyFile(const char *f, const char *t, Bool_t overwrite)
2568{
2569 if (AccessPathName(f, kReadPermission)) return -1;
2570 if (!AccessPathName(t) && !overwrite) return -2;
2571
2572 Bool_t ret = ::CopyFileA(f, t, kFALSE);
2573
2574 if (!ret) return -1;
2575 return 0;
2576}
2577
2578////////////////////////////////////////////////////////////////////////////////
2579/// Rename a file. Returns 0 when successful, -1 in case of failure.
2580
2581int TWinNTSystem::Rename(const char *f, const char *t)
2582{
2583 int ret = ::rename(f, t);
2585 return ret;
2586}
2587
2588////////////////////////////////////////////////////////////////////////////////
2589/// Get info about a file. Info is returned in the form of a FileStat_t
2590/// structure (see TSystem.h).
2591/// The function returns 0 in case of success and 1 if the file could
2592/// not be stat'ed.
2593
2594int TWinNTSystem::GetPathInfo(const char *path, FileStat_t &buf)
2595{
2596 TSystem *helper = FindHelper(path);
2597 if (helper)
2598 return helper->GetPathInfo(path, buf);
2599
2600 struct _stati64 sbuf;
2601
2602 // Remove trailing backslashes
2603 const char *proto = (strstr(path, "file:///")) ? "file://" : "file:";
2604 char *newpath = StrDup(StripOffProto(path, proto));
2605 int l = strlen(newpath);
2606 while (l > 1) {
2607 if (newpath[--l] != '\\' || newpath[--l] != '/') {
2608 break;
2609 }
2610 newpath[l] = '\0';
2611 }
2612
2613 if (newpath && ::_stati64(newpath, &sbuf) >= 0) {
2614
2615 buf.fDev = sbuf.st_dev;
2616 buf.fIno = sbuf.st_ino;
2617 buf.fMode = sbuf.st_mode;
2618 buf.fUid = sbuf.st_uid;
2619 buf.fGid = sbuf.st_gid;
2620 buf.fSize = sbuf.st_size;
2621 buf.fMtime = sbuf.st_mtime;
2622 buf.fIsLink = IsShortcut(newpath); // kFALSE;
2623
2624 char *lpath = new char[MAX_PATH];
2625 if (IsShortcut(newpath)) {
2626 struct _stati64 sbuf2;
2627 if (ResolveShortCut(newpath, lpath, MAX_PATH)) {
2628 if (::_stati64(lpath, &sbuf2) >= 0) {
2629 buf.fMode = sbuf2.st_mode;
2630 }
2631 }
2632 }
2633 delete [] lpath;
2634
2635 delete [] newpath;
2636 return 0;
2637 }
2638 delete [] newpath;
2639 return 1;
2640}
2641
2642////////////////////////////////////////////////////////////////////////////////
2643/// Get info about a file system: id, bsize, bfree, blocks.
2644/// Id is file system type (machine dependend, see statfs())
2645/// Bsize is block size of file system
2646/// Blocks is total number of blocks in file system
2647/// Bfree is number of free blocks in file system
2648/// The function returns 0 in case of success and 1 if the file system could
2649/// not be stat'ed.
2650
2651int TWinNTSystem::GetFsInfo(const char *path, Long_t *id, Long_t *bsize,
2652 Long_t *blocks, Long_t *bfree)
2653{
2654 // address of root directory of the file system
2655 LPCTSTR lpRootPathName = path;
2656
2657 // address of name of the volume
2658 LPTSTR lpVolumeNameBuffer = 0;
2659 DWORD nVolumeNameSize = 0;
2660
2661 DWORD volumeSerialNumber; // volume serial number
2662 DWORD maximumComponentLength; // system's maximum filename length
2663
2664 // file system flags
2665 DWORD fileSystemFlags;
2666
2667 // address of name of file system
2668 char fileSystemNameBuffer[512];
2669 DWORD nFileSystemNameSize = sizeof(fileSystemNameBuffer);
2670
2671 // prevent the system dialog box to pop-up if the drive is empty
2672 UINT nOldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
2673 if (!::GetVolumeInformation(lpRootPathName,
2674 lpVolumeNameBuffer, nVolumeNameSize,
2675 &volumeSerialNumber,
2676 &maximumComponentLength,
2677 &fileSystemFlags,
2678 fileSystemNameBuffer, nFileSystemNameSize)) {
2679 // restore previous error mode
2680 ::SetErrorMode(nOldErrorMode);
2681 return 1;
2682 }
2683
2684 const char *fsNames[] = { "FAT", "NTFS" };
2685 int i;
2686 for (i = 0; i < 2; i++) {
2687 if (!strncmp(fileSystemNameBuffer, fsNames[i], nFileSystemNameSize))
2688 break;
2689 }
2690 *id = i;
2691
2692 DWORD sectorsPerCluster; // # sectors per cluster
2693 DWORD bytesPerSector; // # bytes per sector
2694 DWORD numberOfFreeClusters; // # free clusters
2695 DWORD totalNumberOfClusters; // # total of clusters
2696
2697 if (!::GetDiskFreeSpace(lpRootPathName,
2698 &sectorsPerCluster,
2699 &bytesPerSector,
2700 &numberOfFreeClusters,
2701 &totalNumberOfClusters)) {
2702 // restore previous error mode
2703 ::SetErrorMode(nOldErrorMode);
2704 return 1;
2705 }
2706 // restore previous error mode
2707 ::SetErrorMode(nOldErrorMode);
2708
2709 *bsize = sectorsPerCluster * bytesPerSector;
2710 *blocks = totalNumberOfClusters;
2711 *bfree = numberOfFreeClusters;
2712
2713 return 0;
2714}
2715
2716////////////////////////////////////////////////////////////////////////////////
2717/// Create a link from file1 to file2.
2718
2719int TWinNTSystem::Link(const char *from, const char *to)
2720{
2721 struct _stati64 finfo;
2722 char winDrive[256];
2723 char winDir[256];
2724 char winName[256];
2725 char winExt[256];
2726 char linkname[1024];
2727 LPTSTR lpszFilePart;
2728 TCHAR szPath[MAX_PATH];
2729 DWORD dwRet = 0;
2730
2731 typedef BOOL (__stdcall *CREATEHARDLINKPROC)( LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES );
2732 static CREATEHARDLINKPROC _CreateHardLink = 0;
2733
2734 HMODULE hModImagehlp = LoadLibrary( "Kernel32.dll" );
2735 if (!hModImagehlp)
2736 return -1;
2737
2738#ifdef _UNICODE
2739 _CreateHardLink = (CREATEHARDLINKPROC) GetProcAddress( hModImagehlp, "CreateHardLinkW" );
2740#else
2741 _CreateHardLink = (CREATEHARDLINKPROC) GetProcAddress( hModImagehlp, "CreateHardLinkA" );
2742#endif
2743 if (!_CreateHardLink)
2744 return -1;
2745
2746 dwRet = GetFullPathName(from, sizeof(szPath) / sizeof(TCHAR),
2747 szPath, &lpszFilePart);
2748
2749 if (_stati64(szPath, &finfo) < 0)
2750 return -1;
2751
2752 if (finfo.st_mode & S_IFDIR)
2753 return -1;
2754
2755 snprintf(linkname,1024,"%s",to);
2756 _splitpath(linkname,winDrive,winDir,winName,winExt);
2757 if ((!winDrive[0] ) &&
2758 (!winDir[0] )) {
2759 _splitpath(szPath,winDrive,winDir,winName,winExt);
2760 snprintf(linkname,1024,"%s\\%s\\%s", winDrive, winDir, to);
2761 }
2762 else if (!winDrive[0]) {
2763 _splitpath(szPath,winDrive,winDir,winName,winExt);
2764 snprintf(linkname,1024,"%s\\%s", winDrive, to);
2765 }
2766
2767 if (!_CreateHardLink(linkname, szPath, NULL))
2768 return -1;
2769
2770 return 0;
2771}
2772
2773////////////////////////////////////////////////////////////////////////////////
2774/// Create a symlink from file1 to file2. Returns 0 when successful,
2775/// -1 in case of failure.
2776
2777int TWinNTSystem::Symlink(const char *from, const char *to)
2778{
2779 HRESULT hRes; /* Returned COM result code */
2780 IShellLink* pShellLink; /* IShellLink object pointer */
2781 IPersistFile* pPersistFile; /* IPersistFile object pointer */
2782 WCHAR wszLinkfile[MAX_PATH]; /* pszLinkfile as Unicode string */
2783 int iWideCharsWritten; /* Number of wide characters written */
2784 DWORD dwRet = 0;
2785 LPTSTR lpszFilePart;
2786 TCHAR szPath[MAX_PATH];
2787
2788 hRes = E_INVALIDARG;
2789 if ((from == NULL) || (!from[0]) || (to == NULL) ||
2790 (!to[0]))
2791 return -1;
2792
2793 // Make typedefs for some ole32.dll functions so that we can use them
2794 // with GetProcAddress
2795 typedef HRESULT (__stdcall *COINITIALIZEPROC)( LPVOID );
2796 static COINITIALIZEPROC _CoInitialize = 0;
2797 typedef void (__stdcall *COUNINITIALIZEPROC)( void );
2798 static COUNINITIALIZEPROC _CoUninitialize = 0;
2799 typedef HRESULT (__stdcall *COCREATEINSTANCEPROC)( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID );
2800 static COCREATEINSTANCEPROC _CoCreateInstance = 0;
2801
2802 HMODULE hModImagehlp = LoadLibrary( "ole32.dll" );
2803 if (!hModImagehlp)
2804 return -1;
2805
2806 _CoInitialize = (COINITIALIZEPROC) GetProcAddress( hModImagehlp, "CoInitialize" );
2807 if (!_CoInitialize)
2808 return -1;
2809 _CoUninitialize = (COUNINITIALIZEPROC) GetProcAddress( hModImagehlp, "CoUninitialize" );
2810 if (!_CoUninitialize)
2811 return -1;
2812 _CoCreateInstance = (COCREATEINSTANCEPROC) GetProcAddress( hModImagehlp, "CoCreateInstance" );
2813 if (!_CoCreateInstance)
2814 return -1;
2815
2816 TString linkname(to);
2817 if (!linkname.EndsWith(".lnk"))
2818 linkname.Append(".lnk");
2819
2820 _CoInitialize(NULL);
2821
2822 // Retrieve the full path and file name of a specified file
2823 dwRet = GetFullPathName(from, sizeof(szPath) / sizeof(TCHAR),
2824 szPath, &lpszFilePart);
2825 hRes = _CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2826 IID_IShellLink, (LPVOID *)&pShellLink);
2827 if (SUCCEEDED(hRes)) {
2828 // Set the fields in the IShellLink object
2829 hRes = pShellLink->SetPath(szPath);
2830 // Use the IPersistFile object to save the shell link
2831 hRes = pShellLink->QueryInterface(IID_IPersistFile, (void **)&pPersistFile);
2832 if (SUCCEEDED(hRes)){
2833 iWideCharsWritten = MultiByteToWideChar(CP_ACP, 0, linkname.Data(), -1,
2834 wszLinkfile, MAX_PATH);
2835 hRes = pPersistFile->Save(wszLinkfile, TRUE);
2836 pPersistFile->Release();
2837 }
2838 pShellLink->Release();
2839 }
2840 _CoUninitialize();
2841 return 0;
2842}
2843
2844////////////////////////////////////////////////////////////////////////////////
2845/// Unlink, i.e. remove, a file or directory.
2846///
2847/// If the file is currently open by the current or another process Windows does not allow the file to be deleted and
2848/// the operation is a no-op.
2849
2851{
2852 TSystem *helper = FindHelper(name);
2853 if (helper)
2854 return helper->Unlink(name);
2855
2856 struct _stati64 finfo;
2857
2858 if (_stati64(name, &finfo) < 0) {
2859 return -1;
2860 }
2861
2862 if (finfo.st_mode & S_IFDIR) {
2863 return ::_rmdir(name);
2864 } else {
2865 return ::_unlink(name);
2866 }
2867}
2868
2869////////////////////////////////////////////////////////////////////////////////
2870/// Make descriptor fd non-blocking.
2871
2873{
2874 if (::ioctlsocket(fd, FIONBIO, (u_long *)1) == SOCKET_ERROR) {
2875 ::SysError("SetNonBlock", "ioctlsocket");
2876 return -1;
2877 }
2878 return 0;
2879}
2880
2881// expand the metacharacters as in the shell
2882
2883static const char
2884 *shellMeta = "~*[]{}?$%",
2885 *shellStuff = "(){}<>\"'",
2887
2888////////////////////////////////////////////////////////////////////////////////
2889/// Expand a pathname getting rid of special shell characaters like ~.$, etc.
2890
2892{
2893 const char *patbuf = (const char *)patbuf0;
2894 const char *p;
2895 char *cmd = nullptr;
2896 char *q;
2897
2898 Int_t old_level = gErrorIgnoreLevel;
2899 gErrorIgnoreLevel = kFatal; // Explicitly remove all messages
2900 if (patbuf0.BeginsWith("\\")) {
2901 const char driveletter = DriveName(patbuf);
2902 if (driveletter) {
2903 patbuf0.Prepend(":");
2904 patbuf0.Prepend(driveletter);
2905 }
2906 }
2907 TUrl urlpath(patbuf0, kTRUE);
2908 TString proto = urlpath.GetProtocol();
2909 gErrorIgnoreLevel = old_level;
2910 if (!proto.EqualTo("file")) // don't expand urls!!!
2911 return kFALSE;
2912
2913 // skip the "file:" protocol, if any
2914 if (patbuf0.BeginsWith("file:"))
2915 patbuf += 5;
2916
2917 // skip leading blanks
2918 while (*patbuf == ' ') {
2919 patbuf++;
2920 }
2921
2922 // skip leading ':'
2923 while (*patbuf == ':') {
2924 patbuf++;
2925 }
2926
2927 // skip leading ';'
2928 while (*patbuf == ';') {
2929 patbuf++;
2930 }
2931
2932 // Transform a Unix list of directories into a Windows list
2933 // by changing the separator from ':' into ';'
2934 for (q = (char*)patbuf; *q; q++) {
2935 if ( *q == ':' ) {
2936 // We are avoiding substitution in the case of
2937 // ....;c:.... and of ...;root:/... where root can be any url protocol
2938 if ( (((q-2)>patbuf) && ( (*(q-2)!=';') || !isalpha(*(q-1)) )) &&
2939 *(q+1)!='/' ) {
2940 *q=';';
2941 }
2942 }
2943 }
2944 // any shell meta characters ?
2945 for (p = patbuf; *p; p++) {
2946 if (strchr(shellMeta, *p)) {
2947 goto needshell;
2948 }
2949 }
2950 return kFALSE;
2951
2952needshell:
2953
2954 // Because (problably) we built with cygwin, the path name like:
2955 // LOCALS~1\\Temp
2956 // gets extended to
2957 // LOCALSc:\\Devel
2958 // The most likely cause is that '~' is used with Unix semantic of the
2959 // home directory (and it also cuts the path short after ... who knows why!)
2960 // So we need to detect this case and prevents its expansion :(.
2961
2962 char replacement[4];
2963
2964 // intentionally a non visible, unlikely character
2965 for (int k = 0; k<3; k++) replacement[k] = 0x1;
2966
2967 replacement[3] = 0x0;
2968 Ssiz_t pos = 0;
2969 TRegexp TildaNum = "~[0-9]";
2970
2971 while ( (pos = patbuf0.Index(TildaNum,pos)) != kNPOS ) {
2972 patbuf0.Replace(pos, 1, replacement);
2973 }
2974
2975 // escape shell quote characters
2976 // EscChar(patbuf, stuffedPat, sizeof(stuffedPat), shellStuff, shellEscape);
2977 ExpandFileName(patbuf0);
2978 Int_t lbuf = ::ExpandEnvironmentStrings(
2979 patbuf0.Data(), // pointer to string with environment variables
2980 cmd, // pointer to string with expanded environment variables
2981 0 // maximum characters in expanded string
2982 );
2983 if (lbuf > 0) {
2984 cmd = new char[lbuf+1];
2985 ::ExpandEnvironmentStrings(
2986 patbuf0.Data(), // pointer to string with environment variables
2987 cmd, // pointer to string with expanded environment variables
2988 lbuf // maximum characters in expanded string
2989 );
2990 patbuf0 = cmd;
2991 patbuf0.ReplaceAll(replacement, "~");
2992 delete [] cmd;
2993 return kFALSE;
2994 }
2995 return kTRUE;
2996}
2997
2998////////////////////////////////////////////////////////////////////////////////
2999/// Expand a pathname getting rid of special shell characaters like ~.$, etc.
3000/// User must delete returned string.
3001
3002char *TWinNTSystem::ExpandPathName(const char *path)
3003{
3004 char newpath[MAX_PATH];
3005 if (IsShortcut(path)) {
3006 if (!ResolveShortCut(path, newpath, MAX_PATH))
3007 strlcpy(newpath, path, MAX_PATH);
3008 }
3009 else
3010 strlcpy(newpath, path, MAX_PATH);
3011 TString patbuf = newpath;
3012 if (ExpandPathName(patbuf))
3013 return nullptr;
3014
3015 return StrDup(patbuf.Data());
3016}
3017
3018////////////////////////////////////////////////////////////////////////////////
3019/// Set the file permission bits. Returns -1 in case or error, 0 otherwise.
3020/// On windows mode can only be a combination of "user read" (0400),
3021/// "user write" (0200) or "user read | user write" (0600). Any other value
3022/// for mode are ignored.
3023
3024int TWinNTSystem::Chmod(const char *file, UInt_t mode)
3025{
3026 return ::_chmod(file, mode);
3027}
3028
3029////////////////////////////////////////////////////////////////////////////////
3030/// Set the process file creation mode mask.
3031
3033{
3034 return ::umask(mask);
3035}
3036
3037////////////////////////////////////////////////////////////////////////////////
3038/// Set a files modification and access times. If actime = 0 it will be
3039/// set to the modtime. Returns 0 on success and -1 in case of error.
3040
3041int TWinNTSystem::Utime(const char *file, Long_t modtime, Long_t actime)
3042{
3044 Error("Utime", "need write permission for %s to change utime", file);
3045 return -1;
3046 }
3047 if (!actime) actime = modtime;
3048
3049 struct utimbuf t;
3050 t.actime = (time_t)actime;
3051 t.modtime = (time_t)modtime;
3052 return ::utime(file, &t);
3053}
3054
3055////////////////////////////////////////////////////////////////////////////////
3056/// Find location of file in a search path.
3057/// User must delete returned string. Returns 0 in case file is not found.
3058
3059const char *TWinNTSystem::FindFile(const char *search, TString& infile, EAccessMode mode)
3060{
3061 // Windows cannot check on execution mode - all we can do is kReadPermission
3062 if (mode==kExecutePermission)
3063 mode=kReadPermission;
3064
3065 // Expand parameters
3066
3067 gSystem->ExpandPathName(infile);
3068 // Check whether this infile has the absolute path first
3069 if (IsAbsoluteFileName(infile.Data()) ) {
3070 if (!AccessPathName(infile.Data(), mode))
3071 return infile.Data();
3072 infile = "";
3073 return nullptr;
3074 }
3075 TString exsearch(search);
3076 gSystem->ExpandPathName(exsearch);
3077
3078 // Need to use Windows delimiters
3079 Int_t lastDelim = -1;
3080 for(int i=0; i < exsearch.Length(); ++i) {
3081 switch( exsearch[i] ) {
3082 case ':':
3083 // Replace the ':' unless there are after a disk suffix (aka ;c:\mydirec...)
3084 if (i-lastDelim!=2) exsearch[i] = ';';
3085 lastDelim = i;
3086 break;
3087 case ';': lastDelim = i; break;
3088 }
3089 }
3090
3091 // Check access
3092 struct stat finfo;
3093 char name[kMAXPATHLEN];
3094 char *lpFilePart = nullptr;
3095 if (::SearchPath(exsearch.Data(), infile.Data(), NULL, kMAXPATHLEN, name, &lpFilePart) &&
3096 ::access(name, mode) == 0 && stat(name, &finfo) == 0 &&
3097 finfo.st_mode & S_IFREG) {
3098 if (gEnv->GetValue("Root.ShowPath", 0)) {
3099 Printf("Which: %s = %s", infile, name);
3100 }
3101 infile = name;
3102 return infile.Data();
3103 }
3104 infile = "";
3105 return nullptr;
3106}
3107
3108//---- Users & Groups ----------------------------------------------------------
3109
3110////////////////////////////////////////////////////////////////////////////////
3111/// Collect local users and groups accounts information
3112
3114{
3115 // Net* API functions allowed and OS is Windows NT/2000/XP
3116 if ((gEnv->GetValue("WinNT.UseNetAPI", 0)) && (::GetVersion() < 0x80000000)) {
3117 fActUser = -1;
3118 fNbGroups = fNbUsers = 0;
3119 HINSTANCE netapi = ::LoadLibrary("netapi32.DLL");
3120 if (!netapi) return kFALSE;
3121
3122 p2NetApiBufferFree = (pfn1)::GetProcAddress(netapi, "NetApiBufferFree");
3123 p2NetUserGetInfo = (pfn2)::GetProcAddress(netapi, "NetUserGetInfo");
3124 p2NetLocalGroupGetMembers = (pfn3)::GetProcAddress(netapi, "NetLocalGroupGetMembers");
3125 p2NetLocalGroupEnum = (pfn4)::GetProcAddress(netapi, "NetLocalGroupEnum");
3126
3127 if (!p2NetApiBufferFree || !p2NetUserGetInfo ||
3128 !p2NetLocalGroupGetMembers || !p2NetLocalGroupEnum) return kFALSE;
3129
3130 GetNbGroups();
3131
3132 fGroups = (struct group *)calloc(fNbGroups, sizeof(struct group));
3133 for(int i=0;i<fNbGroups;i++) {
3134 fGroups[i].gr_mem = (char **)calloc(fNbUsers, sizeof (char*));
3135 }
3136 fPasswords = (struct passwd *)calloc(fNbUsers, sizeof(struct passwd));
3137
3138 CollectGroups();
3139 ::FreeLibrary(netapi);
3140 }
3142 return kTRUE;
3143}
3144
3145////////////////////////////////////////////////////////////////////////////////
3146
3147Bool_t TWinNTSystem::CountMembers(const char *lpszGroupName)
3148{
3149 NET_API_STATUS NetStatus = NERR_Success;
3150 LPBYTE Data = NULL;
3151 DWORD Index = 0, ResumeHandle = 0, Total = 0;
3152 LOCALGROUP_MEMBERS_INFO_1 *MemberInfo;
3153 WCHAR wszGroupName[256];
3154 int iRetOp = 0;
3155 DWORD dwLastError = 0;
3156
3157 iRetOp = MultiByteToWideChar (
3158 (UINT)CP_ACP, // code page
3159 (DWORD)MB_PRECOMPOSED, // character-type options
3160 (LPCSTR)lpszGroupName, // address of string to map
3161 (int)-1, // number of bytes in string
3162 (LPWSTR)wszGroupName, // address of wide-character buffer
3163 (int)sizeof(wszGroupName) ); // size of buffer
3164
3165 if (iRetOp == 0) {
3166 dwLastError = GetLastError();
3167 if (Data)
3168 p2NetApiBufferFree(Data);
3169 return FALSE;
3170 }
3171
3172 // The NetLocalGroupGetMembers() API retrieves a list of the members
3173 // of a particular local group.
3174 NetStatus = p2NetLocalGroupGetMembers (NULL, wszGroupName, 1,
3175 &Data, 8192, &Index, &Total, &ResumeHandle );
3176
3177 if (NetStatus != NERR_Success || Data == NULL) {
3178 dwLastError = GetLastError();
3179
3180 if (dwLastError == ERROR_ENVVAR_NOT_FOUND) {
3181 // This usually means that the current Group has no members.
3182 // We call NetLocalGroupGetMembers() again.
3183 // This time, we set the level to 0.
3184 // We do this just to confirm that the number of members in
3185 // this group is zero.
3186 NetStatus = p2NetLocalGroupGetMembers ( NULL, wszGroupName, 0,
3187 &Data, 8192, &Index, &Total, &ResumeHandle );
3188 }
3189
3190 if (Data)
3191 p2NetApiBufferFree(Data);
3192 return FALSE;
3193 }
3194
3195 fNbUsers += Total;
3196 MemberInfo = (LOCALGROUP_MEMBERS_INFO_1 *)Data;
3197
3198 if (Data)
3199 p2NetApiBufferFree(Data);
3200
3201 return TRUE;
3202}
3203
3204////////////////////////////////////////////////////////////////////////////////
3205
3207{
3208 NET_API_STATUS NetStatus = NERR_Success;
3209 LPBYTE Data = NULL;
3210 DWORD Index = 0, ResumeHandle = 0, Total = 0, i;
3211 LOCALGROUP_INFO_0 *GroupInfo;
3212 char szAnsiName[256];
3213 DWORD dwLastError = 0;
3214 int iRetOp = 0;
3215
3216 NetStatus = p2NetLocalGroupEnum(NULL, 0, &Data, 8192, &Index,
3217 &Total, &ResumeHandle );
3218
3219 if (NetStatus != NERR_Success || Data == NULL) {
3220 dwLastError = GetLastError();
3221 if (Data)
3222 p2NetApiBufferFree(Data);
3223 return FALSE;
3224 }
3225
3226 fNbGroups = Total;
3227 GroupInfo = (LOCALGROUP_INFO_0 *)Data;
3228 for (i=0; i < Total; i++) {
3229 // Convert group name from UNICODE to ansi.
3230 iRetOp = WideCharToMultiByte (
3231 (UINT)CP_ACP, // code page
3232 (DWORD)0, // performance and mapping flags
3233 (LPCWSTR)(GroupInfo->lgrpi0_name), // address of wide-char string
3234 (int)-1, // number of characters in string
3235 (LPSTR)szAnsiName, // address of buffer for new string
3236 (int)(sizeof(szAnsiName)), // size of buffer
3237 (LPCSTR)NULL, // address of default for unmappable characters
3238 (LPBOOL)NULL ); // address of flag set when default char used.
3239
3240 // Now lookup all members of this group and record down their names and
3241 // SIDs into the output file.
3242 CountMembers((LPCTSTR)szAnsiName);
3243
3244 GroupInfo++;
3245 }
3246
3247 if (Data)
3248 p2NetApiBufferFree(Data);
3249
3250 return TRUE;
3251}
3252
3253////////////////////////////////////////////////////////////////////////////////
3254///
3255/// Take the name and look up a SID so that we can get full
3256/// domain/user information
3257///
3258
3259Long_t TWinNTSystem::LookupSID (const char *lpszAccountName, int what,
3260 int &groupIdx, int &memberIdx)
3261{
3262 BOOL bRetOp = FALSE;
3263 PSID pSid = NULL;
3264 DWORD dwSidSize, dwDomainNameSize;
3265 BYTE bySidBuffer[MAX_SID_SIZE];
3266 char szDomainName[MAX_NAME_STRING];
3267 SID_NAME_USE sidType;
3268 PUCHAR puchar_SubAuthCount = NULL;
3269 SID_IDENTIFIER_AUTHORITY sid_identifier_authority;
3270 PSID_IDENTIFIER_AUTHORITY psid_identifier_authority = NULL;
3271 unsigned char j = 0;
3272 DWORD dwLastError = 0;
3273
3274 pSid = (PSID)bySidBuffer;
3275 dwSidSize = sizeof(bySidBuffer);
3276 dwDomainNameSize = sizeof(szDomainName);
3277
3278 bRetOp = LookupAccountName (
3279 (LPCTSTR)NULL, // address of string for system name
3280 (LPCTSTR)lpszAccountName, // address of string for account name
3281 (PSID)pSid, // address of security identifier
3282 (LPDWORD)&dwSidSize, // address of size of security identifier
3283 (LPTSTR)szDomainName, // address of string for referenced domain
3284 (LPDWORD)&dwDomainNameSize,// address of size of domain string
3285 (PSID_NAME_USE)&sidType ); // address of SID-type indicator
3286
3287 if (bRetOp == FALSE) {
3288 dwLastError = GetLastError();
3289 return -1; // Unable to obtain Account SID.
3290 }
3291
3292 bRetOp = IsValidSid((PSID)pSid);
3293
3294 if (bRetOp == FALSE) {
3295 dwLastError = GetLastError();
3296 return -2; // SID returned is invalid.
3297 }
3298
3299 // Obtain via APIs the identifier authority value.
3300 psid_identifier_authority = GetSidIdentifierAuthority ((PSID)pSid);
3301
3302 // Make a copy of it.
3303 memcpy (&sid_identifier_authority, psid_identifier_authority,
3304 sizeof(SID_IDENTIFIER_AUTHORITY));
3305
3306 // Determine how many sub-authority values there are in the current SID.
3307 puchar_SubAuthCount = (PUCHAR)GetSidSubAuthorityCount((PSID)pSid);
3308 // Assign it to a more convenient variable.
3309 j = (unsigned char)(*puchar_SubAuthCount);
3310 // Now obtain all the sub-authority values from the current SID.
3311 DWORD dwSubAuth = 0;
3312 PDWORD pdwSubAuth = NULL;
3313 // Obtain the current sub-authority DWORD (referenced by a pointer)
3314 pdwSubAuth = (PDWORD)GetSidSubAuthority (
3315 (PSID)pSid, // address of security identifier to query
3316 (DWORD)j-1); // index of subauthority to retrieve
3317 dwSubAuth = *pdwSubAuth;
3318 if(what == SID_MEMBER) {
3319 fPasswords[memberIdx].pw_uid = dwSubAuth;
3320 fPasswords[memberIdx].pw_gid = fGroups[groupIdx].gr_gid;
3321 fPasswords[memberIdx].pw_group = strdup(fGroups[groupIdx].gr_name);
3322 }
3323 else if(what == SID_GROUP) {
3324 fGroups[groupIdx].gr_gid = dwSubAuth;
3325 }
3326 return 0;
3327}
3328
3329////////////////////////////////////////////////////////////////////////////////
3330///
3331
3332Bool_t TWinNTSystem::CollectMembers(const char *lpszGroupName, int &groupIdx,
3333 int &memberIdx)
3334{
3335
3336 NET_API_STATUS NetStatus = NERR_Success;
3337 LPBYTE Data = NULL;
3338 DWORD Index = 0, ResumeHandle = 0, Total = 0, i;
3339 LOCALGROUP_MEMBERS_INFO_1 *MemberInfo;
3340 char szAnsiMemberName[256];
3341 char szFullMemberName[256];
3342 char szMemberHomeDir[256];
3343 WCHAR wszGroupName[256];
3344 int iRetOp = 0;
3345 char act_name[256];
3346 DWORD length = sizeof (act_name);
3347 DWORD dwLastError = 0;
3348 LPUSER_INFO_11 pUI11Buf = NULL;
3349 NET_API_STATUS nStatus;
3350
3351 iRetOp = MultiByteToWideChar (
3352 (UINT)CP_ACP, // code page
3353 (DWORD)MB_PRECOMPOSED, // character-type options
3354 (LPCSTR)lpszGroupName, // address of string to map
3355 (int)-1, // number of bytes in string
3356 (LPWSTR)wszGroupName, // address of wide-character buffer
3357 (int)sizeof(wszGroupName) ); // size of buffer
3358
3359 if (iRetOp == 0) {
3360 dwLastError = GetLastError();
3361 if (Data)
3362 p2NetApiBufferFree(Data);
3363 return FALSE;
3364 }
3365
3366 GetUserName (act_name, &length);
3367
3368 // The NetLocalGroupGetMembers() API retrieves a list of the members
3369 // of a particular local group.
3370 NetStatus = p2NetLocalGroupGetMembers (NULL, wszGroupName, 1,
3371 &Data, 8192, &Index, &Total, &ResumeHandle );
3372
3373 if (NetStatus != NERR_Success || Data == NULL) {
3374 dwLastError = GetLastError();
3375
3376 if (dwLastError == ERROR_ENVVAR_NOT_FOUND) {
3377 // This usually means that the current Group has no members.
3378 // We call NetLocalGroupGetMembers() again.
3379 // This time, we set the level to 0.
3380 // We do this just to confirm that the number of members in
3381 // this group is zero.
3382 NetStatus = p2NetLocalGroupGetMembers ( NULL, wszGroupName, 0,
3383 &Data, 8192, &Index, &Total, &ResumeHandle );
3384 }
3385
3386 if (Data)
3387 p2NetApiBufferFree(Data);
3388 return FALSE;
3389 }
3390
3391 MemberInfo = (LOCALGROUP_MEMBERS_INFO_1 *)Data;
3392 for (i=0; i < Total; i++) {
3393 iRetOp = WideCharToMultiByte (
3394 (UINT)CP_ACP, // code page
3395 (DWORD)0, // performance and mapping flags
3396 (LPCWSTR)(MemberInfo->lgrmi1_name), // address of wide-char string
3397 (int)-1, // number of characters in string
3398 (LPSTR)szAnsiMemberName, // address of buffer for new string
3399 (int)(sizeof(szAnsiMemberName)), // size of buffer
3400 (LPCSTR)NULL, // address of default for unmappable characters
3401 (LPBOOL)NULL ); // address of flag set when default char used.
3402
3403 if (iRetOp == 0) {
3404 dwLastError = GetLastError();
3405 }
3406
3407 fPasswords[memberIdx].pw_name = strdup(szAnsiMemberName);
3408 fPasswords[memberIdx].pw_passwd = strdup("");
3409 fGroups[groupIdx].gr_mem[i] = strdup(szAnsiMemberName);
3410
3411 if(fActUser == -1 && !stricmp(fPasswords[memberIdx].pw_name,act_name))
3412 fActUser = memberIdx;
3413
3414
3415 TCHAR szUserName[255]=TEXT("");
3416 MultiByteToWideChar(CP_ACP, 0, szAnsiMemberName, -1, (LPWSTR)szUserName, 255);
3417 //
3418 // Call the NetUserGetInfo function; specify level 10.
3419 //
3420 nStatus = p2NetUserGetInfo(NULL, (LPCWSTR)szUserName, 11, (LPBYTE *)&pUI11Buf);
3421 //
3422 // If the call succeeds, print the user information.
3423 //
3424 if (nStatus == NERR_Success) {
3425 if (pUI11Buf != NULL) {
3426 wsprintf(szFullMemberName,"%S",pUI11Buf->usri11_full_name);
3427 fPasswords[memberIdx].pw_gecos = strdup(szFullMemberName);
3428 wsprintf(szMemberHomeDir,"%S",pUI11Buf->usri11_home_dir);
3429 fPasswords[memberIdx].pw_dir = strdup(szMemberHomeDir);
3430 }
3431 }
3432 if((fPasswords[memberIdx].pw_gecos == NULL) || (strlen(fPasswords[memberIdx].pw_gecos) == 0))
3433 fPasswords[memberIdx].pw_gecos = strdup(fPasswords[memberIdx].pw_name);
3434 if((fPasswords[memberIdx].pw_dir == NULL) || (strlen(fPasswords[memberIdx].pw_dir) == 0))
3435 fPasswords[memberIdx].pw_dir = strdup("c:\\");
3436 //
3437 // Free the allocated memory.
3438 //
3439 if (pUI11Buf != NULL) {
3440 p2NetApiBufferFree(pUI11Buf);
3441 pUI11Buf = NULL;
3442 }
3443
3444 /* Ensure SHELL is defined. */
3445 if (getenv("SHELL") == NULL)
3446 putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
3447
3448 /* Set dir and shell from environment variables. */
3449 fPasswords[memberIdx].pw_shell = getenv("SHELL");
3450
3451 // Find out the SID of the Member.
3452 LookupSID ((LPCTSTR)szAnsiMemberName, SID_MEMBER, groupIdx, memberIdx);
3453 memberIdx++;
3454 MemberInfo++;
3455 }
3456 if(fActUser == -1) fActUser = 0;
3457
3458 if (Data)
3459 p2NetApiBufferFree(Data);
3460
3461 return TRUE;
3462}
3463
3464////////////////////////////////////////////////////////////////////////////////
3465///
3466
3468{
3469 NET_API_STATUS NetStatus = NERR_Success;
3470 LPBYTE Data = NULL;
3471 DWORD Index = 0, ResumeHandle = 0, Total = 0, i;
3472 LOCALGROUP_INFO_0 *GroupInfo;
3473 char szAnsiName[256];
3474 DWORD dwLastError = 0;
3475 int iRetOp = 0, iGroupIdx = 0, iMemberIdx = 0;
3476
3477 NetStatus = p2NetLocalGroupEnum(NULL, 0, &Data, 8192, &Index,
3478 &Total, &ResumeHandle );
3479
3480 if (NetStatus != NERR_Success || Data == NULL) {
3481 dwLastError = GetLastError();
3482 if (Data)
3483 p2NetApiBufferFree(Data);
3484 return FALSE;
3485 }
3486
3487 GroupInfo = (LOCALGROUP_INFO_0 *)Data;
3488 for (i=0; i < Total; i++) {
3489 // Convert group name from UNICODE to ansi.
3490 iRetOp = WideCharToMultiByte (
3491 (UINT)CP_ACP, // code page
3492 (DWORD)0, // performance and mapping flags
3493 (LPCWSTR)(GroupInfo->lgrpi0_name), // address of wide-char string
3494 (int)-1, // number of characters in string
3495 (LPSTR)szAnsiName, // address of buffer for new string
3496 (int)(sizeof(szAnsiName)), // size of buffer
3497 (LPCSTR)NULL, // address of default for unmappable characters
3498 (LPBOOL)NULL ); // address of flag set when default char used.
3499
3500 fGroups[iGroupIdx].gr_name = strdup(szAnsiName);
3501 fGroups[iGroupIdx].gr_passwd = strdup("");
3502
3503 // Find out the SID of the Group.
3504 LookupSID ((LPCTSTR)szAnsiName, SID_GROUP, iGroupIdx, iMemberIdx);
3505 // Now lookup all members of this group and record down their names and
3506 // SIDs into the output file.
3507 CollectMembers((LPCTSTR)szAnsiName, iGroupIdx, iMemberIdx);
3508
3509 iGroupIdx++;
3510 GroupInfo++;
3511 }
3512
3513 if (Data)
3514 p2NetApiBufferFree(Data);
3515
3516 return TRUE;
3517}
3518
3519////////////////////////////////////////////////////////////////////////////////
3520/// Returns the user's id. If user = 0, returns current user's id.
3521
3523{
3524 if(!fGroupsInitDone)
3526
3527 // Net* API functions not allowed or OS not Windows NT/2000/XP
3528 if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
3529 int uid;
3530 char name[256];
3531 DWORD length = sizeof (name);
3532 if (::GetUserName (name, &length)) {
3533 if (stricmp ("administrator", name) == 0)
3534 uid = 0;
3535 else
3536 uid = 123;
3537 }
3538 else {
3539 uid = 123;
3540 }
3541 return uid;
3542 }
3543 if (!user || !user[0])
3544 return fPasswords[fActUser].pw_uid;
3545 else {
3546 struct passwd *pwd = nullptr;
3547 for(int i=0;i<fNbUsers;i++) {
3548 if (!stricmp (user, fPasswords[i].pw_name)) {
3549 pwd = &fPasswords[i];
3550 break;
3551 }
3552 }
3553 if (pwd)
3554 return pwd->pw_uid;
3555 }
3556 return 0;
3557}
3558
3559////////////////////////////////////////////////////////////////////////////////
3560/// Returns the effective user id. The effective id corresponds to the
3561/// set id bit on the file being executed.
3562
3564{
3565 if(!fGroupsInitDone)
3567
3568 // Net* API functions not allowed or OS not Windows NT/2000/XP
3569 if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
3570 int uid;
3571 char name[256];
3572 DWORD length = sizeof (name);
3573 if (::GetUserName (name, &length)) {
3574 if (stricmp ("administrator", name) == 0)
3575 uid = 0;
3576 else
3577 uid = 123;
3578 }
3579 else {
3580 uid = 123;
3581 }
3582 return uid;
3583 }
3584 return fPasswords[fActUser].pw_uid;
3585}
3586
3587////////////////////////////////////////////////////////////////////////////////
3588/// Returns the group's id. If group = 0, returns current user's group.
3589
3591{
3592 if(!fGroupsInitDone)
3594
3595 // Net* API functions not allowed or OS not Windows NT/2000/XP
3596 if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
3597 int gid;
3598 char name[256];
3599 DWORD length = sizeof (name);
3600 if (::GetUserName (name, &length)) {
3601 if (stricmp ("administrator", name) == 0)
3602 gid = 0;
3603 else
3604 gid = 123;
3605 }
3606 else {
3607 gid = 123;
3608 }
3609 return gid;
3610 }
3611 if (!group || !group[0])
3612 return fPasswords[fActUser].pw_gid;
3613 else {
3614 struct group *grp = nullptr;
3615 for(int i=0;i<fNbGroups;i++) {
3616 if (!stricmp (group, fGroups[i].gr_name)) {
3617 grp = &fGroups[i];
3618 break;
3619 }
3620 }
3621 if (grp)
3622 return grp->gr_gid;
3623 }
3624 return 0;
3625}
3626
3627////////////////////////////////////////////////////////////////////////////////
3628/// Returns the effective group id. The effective group id corresponds
3629/// to the set id bit on the file being executed.
3630
3632{
3633 if(!fGroupsInitDone)
3635
3636 // Net* API functions not allowed or OS not Windows NT/2000/XP
3637 if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
3638 int gid;
3639 char name[256];
3640 DWORD length = sizeof (name);
3641 if (::GetUserName (name, &length)) {
3642 if (stricmp ("administrator", name) == 0)
3643 gid = 0;
3644 else
3645 gid = 123;
3646 }
3647 else {
3648 gid = 123;
3649 }
3650 return gid;
3651 }
3652 return fPasswords[fActUser].pw_gid;
3653}
3654
3655////////////////////////////////////////////////////////////////////////////////
3656/// Returns all user info in the UserGroup_t structure. The returned
3657/// structure must be deleted by the user. In case of error 0 is returned.
3658
3660{
3661 if(!fGroupsInitDone)
3663
3664 // Net* API functions not allowed or OS not Windows NT/2000/XP
3665 if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
3666 char name[256];
3667 DWORD length = sizeof (name);
3668 UserGroup_t *ug = new UserGroup_t;
3669 if (::GetUserName (name, &length)) {
3670 ug->fUser = name;
3671 if (stricmp ("administrator", name) == 0) {
3672 ug->fUid = 0;
3673 ug->fGroup = "administrators";
3674 }
3675 else {
3676 ug->fUid = 123;
3677 ug->fGroup = "users";
3678 }
3679 ug->fGid = ug->fUid;
3680 }
3681 else {
3682 ug->fUser = "unknown";
3683 ug->fGroup = "unknown";
3684 ug->fUid = ug->fGid = 123;
3685 }
3686 ug->fPasswd = "";
3687 ug->fRealName = ug->fUser;
3688 ug->fShell = "command";
3689 return ug;
3690 }
3691 struct passwd *pwd = 0;
3692 if (uid == 0)
3694 else {
3695 for (int i = 0; i < fNbUsers; i++) {
3696 if (uid == fPasswords[i].pw_uid) {
3697 pwd = &fPasswords[i];
3698 break;
3699 }
3700 }
3701 }
3702 if (pwd) {
3703 UserGroup_t *ug = new UserGroup_t;
3704 ug->fUid = pwd->pw_uid;
3705 ug->fGid = pwd->pw_gid;
3706 ug->fUser = pwd->pw_name;
3707 ug->fPasswd = pwd->pw_passwd;
3708 ug->fRealName = pwd->pw_gecos;
3709 ug->fShell = pwd->pw_shell;
3710 ug->fGroup = pwd->pw_group;
3711 return ug;
3712 }
3713 return nullptr;
3714}
3715
3716////////////////////////////////////////////////////////////////////////////////
3717/// Returns all user info in the UserGroup_t structure. If user = 0, returns
3718/// current user's id info. The returned structure must be deleted by the
3719/// user. In case of error 0 is returned.
3720
3722{
3723 return GetUserInfo(GetUid(user));
3724}
3725
3726////////////////////////////////////////////////////////////////////////////////
3727/// Returns all group info in the UserGroup_t structure. The only active
3728/// fields in the UserGroup_t structure for this call are:
3729/// fGid and fGroup
3730/// The returned structure must be deleted by the user. In case of
3731/// error 0 is returned.
3732
3734{
3735 if(!fGroupsInitDone)
3737
3738 // Net* API functions not allowed or OS not Windows NT/2000/XP
3739 if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
3740 char name[256];
3741 DWORD length = sizeof (name);
3742 UserGroup_t *gr = new UserGroup_t;
3743 if (::GetUserName (name, &length)) {
3744 if (stricmp ("administrator", name) == 0) {
3745 gr->fGroup = "administrators";
3746 gr->fGid = 0;
3747 }
3748 else {
3749 gr->fGroup = "users";
3750 gr->fGid = 123;
3751 }
3752 }
3753 else {
3754 gr->fGroup = "unknown";
3755 gr->fGid = 123;
3756 }
3757 gr->fUid = 0;
3758 return gr;
3759 }
3760 struct group *grp = nullptr;
3761 for(int i=0;i<fNbGroups;i++) {
3762 if (gid == fGroups[i].gr_gid) {
3763 grp = &fGroups[i];
3764 break;
3765 }
3766 }
3767 if (grp) {
3768 UserGroup_t *gr = new UserGroup_t;
3769 gr->fUid = 0;
3770 gr->fGid = grp->gr_gid;
3771 gr->fGroup = grp->gr_name;
3772 return gr;
3773 }
3774 return nullptr;
3775}
3776
3777////////////////////////////////////////////////////////////////////////////////
3778/// Returns all group info in the UserGroup_t structure. The only active
3779/// fields in the UserGroup_t structure for this call are:
3780/// fGid and fGroup
3781/// If group = 0, returns current user's group. The returned structure
3782/// must be deleted by the user. In case of error 0 is returned.
3783
3785{
3786 return GetGroupInfo(GetGid(group));
3787}
3788
3789//---- environment manipulation ------------------------------------------------
3790
3791////////////////////////////////////////////////////////////////////////////////
3792/// Set environment variable.
3793
3794void TWinNTSystem::Setenv(const char *name, const char *value)
3795{
3796 ::_putenv(TString::Format("%s=%s", name, value));
3797}
3798
3799////////////////////////////////////////////////////////////////////////////////
3800/// Get environment variable.
3801
3802const char *TWinNTSystem::Getenv(const char *name)
3803{
3804 const char *env = ::getenv(name);
3805 if (!env) {
3806 if (::_stricmp(name,"home") == 0 ) {
3807 env = HomeDirectory();
3808 } else if (::_stricmp(name, "rootsys") == 0 ) {
3809 env = gRootDir;
3810 }
3811 }
3812 return env;
3813}
3814
3815//---- Processes ---------------------------------------------------------------
3816
3817////////////////////////////////////////////////////////////////////////////////
3818/// Execute a command.
3819
3820int TWinNTSystem::Exec(const char *shellcmd)
3821{
3822 return ::system(shellcmd);
3823}
3824
3825////////////////////////////////////////////////////////////////////////////////
3826/// Open a pipe.
3827
3828FILE *TWinNTSystem::OpenPipe(const char *command, const char *mode)
3829{
3830 return ::_popen(command, mode);
3831}
3832
3833////////////////////////////////////////////////////////////////////////////////
3834/// Close the pipe.
3835
3837{
3838 return ::_pclose(pipe);
3839}
3840
3841////////////////////////////////////////////////////////////////////////////////
3842/// Get process id.
3843
3845{
3846 return ::getpid();
3847}
3848
3849////////////////////////////////////////////////////////////////////////////////
3850/// Get current process handle
3851
3853{
3854 return fhProcess;
3855}
3856
3857////////////////////////////////////////////////////////////////////////////////
3858/// Exit the application.
3859
3860void TWinNTSystem::Exit(int code, Bool_t mode)
3861{
3862 // Insures that the files and sockets are closed before any library is unloaded
3863 // and before emptying CINT.
3864 // FIXME: Unify with TROOT::ShutDown.
3865 if (gROOT) {
3866 gROOT->CloseFiles();
3867 if (gROOT->GetListOfBrowsers()) {
3868 // GetListOfBrowsers()->Delete() creates problems when a browser is
3869 // created on the stack, calling CloseWindow() solves the problem
3870 if (gROOT->IsBatch())
3871 gROOT->GetListOfBrowsers()->Delete();
3872 else {
3873 TBrowser *b;
3874 TIter next(gROOT->GetListOfBrowsers());
3875 while ((b = (TBrowser*) next()))
3876 gROOT->ProcessLine(TString::Format("\
3877 if (((TBrowser*)0x%lx)->GetBrowserImp() &&\
3878 ((TBrowser*)0x%lx)->GetBrowserImp()->GetMainFrame()) \
3879 ((TBrowser*)0x%lx)->GetBrowserImp()->GetMainFrame()->CloseWindow();\
3880 else delete (TBrowser*)0x%lx", (ULong_t)b, (ULong_t)b, (ULong_t)b, (ULong_t)b));
3881 }
3882 }
3883 }
3885 gVirtualX->CloseDisplay();
3886
3887 if (mode) {
3888 ::exit(code);
3889 } else {
3890 ::_exit(code);
3891 }
3892}
3893
3894////////////////////////////////////////////////////////////////////////////////
3895/// Abort the application.
3896
3898{
3900 ::abort();
3901}
3902
3903//---- Standard output redirection ---------------------------------------------
3904
3905////////////////////////////////////////////////////////////////////////////////
3906/// Redirect standard output (stdout, stderr) to the specified file.
3907/// If the file argument is 0 the output is set again to stderr, stdout.
3908/// The second argument specifies whether the output should be added to the
3909/// file ("a", default) or the file be truncated before ("w").
3910/// This function saves internally the current state into a static structure.
3911/// The call can be made reentrant by specifying the opaque structure pointed
3912/// by 'h', which is filled with the relevant information. The handle 'h'
3913/// obtained on the first call must then be used in any subsequent call,
3914/// included ShowOutput, to display the redirected output.
3915/// Returns 0 on success, -1 in case of error.
3916
3917Int_t TWinNTSystem::RedirectOutput(const char *file, const char *mode,
3919{
3920 FILE *fout, *ferr;
3921 static int fd1=0, fd2=0;
3922 static fpos_t pos1=0, pos2=0;
3923 // Instance to be used if the caller does not passes 'h'
3924 static RedirectHandle_t loch;
3925 Int_t rc = 0;
3926
3927 // Which handle to use ?
3928 RedirectHandle_t *xh = (h) ? h : &loch;
3929
3930 if (file) {
3931 // Make sure mode makes sense; default "a"
3932 const char *m = (mode[0] == 'a' || mode[0] == 'w') ? mode : "a";
3933
3934 // Current file size
3935 xh->fReadOffSet = 0;
3936 if (m[0] == 'a') {
3937 // If the file exists, save the current size
3938 FileStat_t st;
3939 if (!gSystem->GetPathInfo(file, st))
3940 xh->fReadOffSet = (st.fSize > 0) ? st.fSize : xh->fReadOffSet;
3941 }
3942 xh->fFile = file;
3943
3944 fflush(stdout);
3945 fgetpos(stdout, &pos1);
3946 fd1 = _dup(fileno(stdout));
3947 // redirect stdout & stderr
3948 if ((fout = freopen(file, m, stdout)) == 0) {
3949 SysError("RedirectOutput", "could not freopen stdout");
3950 if (fd1 > 0) {
3951 _dup2(fd1, fileno(stdout));
3952 close(fd1);
3953 }
3954 clearerr(stdout);
3955 fsetpos(stdout, &pos1);
3956 fd1 = fd2 = 0;
3957 return -1;
3958 }
3959 fflush(stderr);
3960 fgetpos(stderr, &pos2);
3961 fd2 = _dup(fileno(stderr));
3962 if ((ferr = freopen(file, m, stderr)) == 0) {
3963 SysError("RedirectOutput", "could not freopen stderr");
3964 if (fd1 > 0) {
3965 _dup2(fd1, fileno(stdout));
3966 close(fd1);
3967 }
3968 clearerr(stdout);
3969 fsetpos(stdout, &pos1);
3970 if (fd2 > 0) {
3971 _dup2(fd2, fileno(stderr));
3972 close(fd2);
3973 }
3974 clearerr(stderr);
3975 fsetpos(stderr, &pos2);
3976 fd1 = fd2 = 0;
3977 return -1;
3978 }
3979 if (m[0] == 'a') {
3980 fseek(fout, 0, SEEK_END);
3981 fseek(ferr, 0, SEEK_END);
3982 }
3983 } else {
3984 // Restore stdout & stderr
3985 fflush(stdout);
3986 if (fd1) {
3987 if (fd1 > 0) {
3988 if (_dup2(fd1, fileno(stdout))) {
3989 SysError("RedirectOutput", "could not restore stdout");
3990 rc = -1;
3991 }
3992 close(fd1);
3993 }
3994 clearerr(stdout);
3995 fsetpos(stdout, &pos1);
3996 fd1 = 0;
3997 }
3998
3999 fflush(stderr);
4000 if (fd2) {
4001 if (fd2 > 0) {
4002 if (_dup2(fd2, fileno(stderr))) {
4003 SysError("RedirectOutput", "could not restore stderr");
4004 rc = -1;
4005 }
4006 close(fd2);
4007 }
4008 clearerr(stderr);
4009 fsetpos(stderr, &pos2);
4010 fd2 = 0;
4011 }
4012
4013 // Reset the static instance, if using that
4014 if (xh == &loch)
4015 xh->Reset();
4016 }
4017 return rc;
4018}
4019
4020//---- dynamic loading and linking ---------------------------------------------
4021
4022////////////////////////////////////////////////////////////////////////////////
4023/// Add a new directory to the dynamic path.
4024
4025void TWinNTSystem::AddDynamicPath(const char *dir)
4026{
4027 if (dir) {
4028 TString oldpath = DynamicPath(0, kFALSE);
4029 oldpath.Append(";");
4030 oldpath.Append(dir);
4031 DynamicPath(oldpath);
4032 }
4033}
4034
4035////////////////////////////////////////////////////////////////////////////////
4036/// Return the dynamic path (used to find shared libraries).
4037
4039{
4040 return DynamicPath(0, kFALSE);
4041}
4042
4043////////////////////////////////////////////////////////////////////////////////
4044/// Set the dynamic path to a new value.
4045/// If the value of 'path' is zero, the dynamic path is reset to its
4046/// default value.
4047
4048void TWinNTSystem::SetDynamicPath(const char *path)
4049{
4050 if (!path)
4051 DynamicPath(0, kTRUE);
4052 else
4053 DynamicPath(path);
4054}
4055
4056////////////////////////////////////////////////////////////////////////////////
4057/// Returns and updates sLib to the path of a dynamic library
4058/// (searches for library in the dynamic library search path).
4059/// If no file name extension is provided it tries .DLL.
4060
4062{
4063 int len = sLib.Length();
4064 if (len > 4 && (!stricmp(sLib.Data()+len-4, ".dll"))) {
4066 return sLib.Data();
4067 } else {
4068 TString sLibDll(sLib);
4069 sLibDll += ".dll";
4070 if (gSystem->FindFile(GetDynamicPath(), sLibDll, kReadPermission)) {
4071 sLibDll.Swap(sLib);
4072 return sLib.Data();
4073 }
4074 }
4075
4076 if (!quiet) {
4077 Error("DynamicPathName",
4078 "%s does not exist in %s,\nor has wrong file extension (.dll)",
4079 sLib.Data(), GetDynamicPath());
4080 }
4081 return nullptr;
4082}
4083
4084////////////////////////////////////////////////////////////////////////////////
4085/// Load a shared library. Returns 0 on successful loading, 1 in
4086/// case lib was already loaded and -1 in case lib does not exist
4087/// or in case of error.
4088
4089int TWinNTSystem::Load(const char *module, const char *entry, Bool_t system)
4090{
4091 return TSystem::Load(module, entry, system);
4092}
4093
4094/* nonstandard extension used : zero-sized array in struct/union */
4095#pragma warning(push)
4096#pragma warning(disable:4200)
4097////////////////////////////////////////////////////////////////////////////////
4098/// Get list of shared libraries loaded at the start of the executable.
4099/// Returns 0 in case list cannot be obtained or in case of error.
4100
4102{
4103 char winDrive[256];
4104 char winDir[256];
4105 char winName[256];
4106 char winExt[256];
4107
4108 if (!gApplication) return nullptr;
4109
4110 static Bool_t once = kFALSE;
4111 static TString linkedLibs;
4112
4113 if (!linkedLibs.IsNull())
4114 return linkedLibs;
4115
4116 if (once)
4117 return nullptr;
4118
4119 char *exe = gSystem->Which(Getenv("PATH"), gApplication->Argv(0),
4121 if (!exe) {
4122 once = kTRUE;
4123 return nullptr;
4124 }
4125
4126 HANDLE hFile, hMapping;
4127 void *basepointer;
4128
4129 if((hFile = CreateFile(exe,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0))==INVALID_HANDLE_VALUE) {
4130 delete [] exe;
4131 return nullptr;
4132 }
4133 if(!(hMapping = CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT,0,0,0))) {
4134 CloseHandle(hFile);
4135 delete [] exe;
4136 return nullptr;
4137 }
4138 if(!(basepointer = MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0))) {
4139 CloseHandle(hMapping);
4140 CloseHandle(hFile);
4141 delete [] exe;
4142 return nullptr;
4143 }
4144
4145 int sect;
4146 IMAGE_DOS_HEADER *dos_head = (IMAGE_DOS_HEADER *)basepointer;
4147 struct header {
4148 DWORD signature;
4149 IMAGE_FILE_HEADER _head;
4150 IMAGE_OPTIONAL_HEADER opt_head;
4151 IMAGE_SECTION_HEADER section_header[]; // actual number in NumberOfSections
4152 };
4153 struct header *pheader;
4154 const IMAGE_SECTION_HEADER * section_header;
4155
4156 if(dos_head->e_magic!='ZM') {
4157 delete [] exe;
4158 return nullptr;
4159 } // verify DOS-EXE-Header
4160 // after end of DOS-EXE-Header: offset to PE-Header
4161 pheader = (struct header *)((char*)dos_head + dos_head->e_lfanew);
4162
4163 if(IsBadReadPtr(pheader,sizeof(struct header))) { // start of PE-Header
4164 delete [] exe;
4165 return nullptr;
4166 }
4167 if(pheader->signature!=IMAGE_NT_SIGNATURE) { // verify PE format
4168 switch((unsigned short)pheader->signature) {
4169 case IMAGE_DOS_SIGNATURE:
4170 delete [] exe;
4171 return nullptr;
4172 case IMAGE_OS2_SIGNATURE:
4173 delete [] exe;
4174 return nullptr;
4175 case IMAGE_OS2_SIGNATURE_LE:
4176 delete [] exe;
4177 return nullptr;
4178 default: // unknown signature
4179 delete [] exe;
4180 return nullptr;
4181 }
4182 }
4183#define isin(address,start,length) ((address)>=(start) && (address)<(start)+(length))
4184 TString odump;
4185 // walk through sections
4186 for(sect=0,section_header=pheader->section_header;
4187 sect<pheader->_head.NumberOfSections;sect++,section_header++) {
4188 int directory;
4189 const void * const section_data =
4190 (char*)basepointer + section_header->PointerToRawData;
4191 for(directory=0;directory<IMAGE_NUMBEROF_DIRECTORY_ENTRIES;directory++) {
4192 if(isin(pheader->opt_head.DataDirectory[directory].VirtualAddress,
4193 section_header->VirtualAddress,
4194 section_header->SizeOfRawData)) {
4195 const IMAGE_IMPORT_DESCRIPTOR *stuff_start =
4196 (IMAGE_IMPORT_DESCRIPTOR *)((char*)section_data +
4197 (pheader->opt_head.DataDirectory[directory].VirtualAddress -
4198 section_header->VirtualAddress));
4199 // (virtual address of stuff - virtual address of section) =
4200 // offset of stuff in section
4201 const unsigned stuff_length =
4202 pheader->opt_head.DataDirectory[directory].Size;
4203 if(directory == IMAGE_DIRECTORY_ENTRY_IMPORT) {
4204 while(!IsBadReadPtr(stuff_start,sizeof(*stuff_start)) &&
4205 stuff_start->Name) {
4206 TString dll = (char*)section_data +
4207 ((DWORD)(stuff_start->Name)) -
4208 section_header->VirtualAddress;
4209 if (dll.EndsWith(".dll")) {
4210 char *dllPath = DynamicPathName(dll, kTRUE);
4211 if (dllPath) {
4212 char *winPath = getenv("windir");
4213 _splitpath(winPath,winDrive,winDir,winName,winExt);
4214 if(!strstr(dllPath, winDir)) {
4215 if (!linkedLibs.IsNull())
4216 linkedLibs += " ";
4217 linkedLibs += dllPath;
4218 }
4219 }
4220 delete [] dllPath;
4221 }
4222 stuff_start++;
4223 }
4224 }
4225 }
4226 }
4227 }
4228
4229 UnmapViewOfFile(basepointer);
4230 CloseHandle(hMapping);
4231 CloseHandle(hFile);
4232
4233 delete [] exe;
4234
4235 once = kTRUE;
4236
4237 if (linkedLibs.IsNull())
4238 return nullptr;
4239
4240 return linkedLibs;
4241}
4242#pragma warning(pop)
4243
4244////////////////////////////////////////////////////////////////////////////////
4245/// Return a space separated list of loaded shared libraries.
4246/// This list is of a format suitable for a linker, i.e it may contain
4247/// -Lpathname and/or -lNameOfLib.
4248/// Option can be any of:
4249/// S: shared libraries loaded at the start of the executable, because
4250/// they were specified on the link line.
4251/// D: shared libraries dynamically loaded after the start of the program.
4252/// L: list the .LIB rather than the .DLL (this is intended for linking)
4253/// [This options is not the default]
4254
4255const char *TWinNTSystem::GetLibraries(const char *regexp, const char *options,
4256 Bool_t isRegexp)
4257{
4258 TString ntlibs;
4259 struct _stat buf;
4260 std::string str;
4261 char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
4262 TString libs(TSystem::GetLibraries(regexp, options, isRegexp));
4263 TString opt = options;
4264 std::vector<std::string> all_libs, libpaths;
4265
4266 if ( (opt.First('L')!=kNPOS) ) {
4267 libs.ReplaceAll("/","\\");
4268 // get the %LIB% environment path list
4269 std::stringstream libenv(gSystem->Getenv("LIB"));
4270 while (getline(libenv, str, ';')) {
4271 libpaths.push_back(str);
4272 }
4273 // now get the list of libraries
4274 std::stringstream libraries(libs.Data());
4275 while (getline(libraries, str, ' ')) {
4276 std::string::size_type first, last;
4277 // if the line begins with "-L", it's a linker option
4278 // (e.g. -LIBPATH:%ROOTSYS%\\lib), so add it to the path list
4279 if (str.rfind("-L", 0) == 0) {
4280 first = str.find_first_of('%');
4281 last = str.find_last_of('%');
4282 if ((first != std::string::npos) && (last != std::string::npos) &&
4283 (first != last)) {
4284 // if there is a string between %%, this is an environment
4285 // variable (e.g. %ROOTSYS%), so let's try to resolve it
4286 // and replace it with the real path
4287 std::string var = str.substr(first+1, last-first-1);
4288 std::string env(gSystem->Getenv(var.c_str()));
4289 if (!env.empty()) {
4290 // the environment variable exist and properly resolved
4291 // so add the last part of the path and add it to the list
4292 env += str.substr(last+1);
4293 libpaths.push_back(env);
4294 }
4295 }
4296 // keep the linker instuction in the final list
4297 ntlibs.Append(str.c_str());
4298 ntlibs += " ";
4299 continue;
4300 }
4301 // replace the '.dll' or '.DLL' extension by '.lib'
4302 last = str.rfind(".dll");
4303 if (last != std::string::npos)
4304 str.replace(last, 4, ".lib");
4305 last = str.rfind(".DLL");
4306 if (last != std::string::npos)
4307 str.replace(last, 4, ".lib");
4308 if (str.rfind(".lib") != std::string::npos ||
4309 str.rfind(".LIB") != std::string::npos) {
4310 // check if the .lib with its full path exists
4311 if (_stat( str.c_str(), &buf ) == 0) {
4312 // file exists, so keep it with full path in our final list
4313 ntlibs.Append(str.c_str());
4314 ntlibs += " ";
4315 continue;
4316 }
4317 }
4318 // full path not found, so split it to extract the library name
4319 // only, set its extension to '.lib' and add it to the list of
4320 // libraries to search
4321 _splitpath(str.c_str(), drive, dir, fname, ext);
4322 std::string libname(fname);
4323 libname += ".lib";
4324 all_libs.push_back(libname);
4325 }
4326 for (auto lib : all_libs) {
4327 // loop over all libraries to check which one exists
4328 for (auto libpath : libpaths) {
4329 // check in each path of the %LIB% environment
4330 std::string path_lib(libpath);
4331 path_lib += "\\";
4332 path_lib += lib;
4333 if (_stat( path_lib.c_str(), &buf ) == 0) {
4334 // file exists, add it to the final list of libraries
4335 ntlibs.Append(lib.c_str());
4336 ntlibs += " ";
4337 }
4338 }
4339 }
4340 } else {
4341 ntlibs = libs;
4342 }
4343
4344 fListLibs = ntlibs;
4345 fListLibs.ReplaceAll("/","\\");
4346 return fListLibs;
4347}
4348
4349//---- Time & Date -------------------------------------------------------------
4350
4351////////////////////////////////////////////////////////////////////////////////
4352/// Add timer to list of system timers.
4353
4355{
4357}
4358
4359////////////////////////////////////////////////////////////////////////////////
4360/// Remove timer from list of system timers.
4361
4363{
4364 if (!ti) return nullptr;
4365
4367 return t;
4368}
4369
4370////////////////////////////////////////////////////////////////////////////////
4371/// Special Thread to check asynchronous timers.
4372
4374{
4375 while (1) {
4376 if (!fInsideNotify)
4379 }
4380}
4381
4382////////////////////////////////////////////////////////////////////////////////
4383/// Handle and dispatch timers. If mode = kTRUE dispatch synchronous
4384/// timers else a-synchronous timers.
4385
4387{
4388 if (!fTimers) return kFALSE;
4389
4391
4393 TTimer *t;
4394 Bool_t timedout = kFALSE;
4395
4396 while ((t = (TTimer *) it.Next())) {
4397 // NB: the timer resolution is added in TTimer::CheckTimer()
4398 TTime now = Now();
4399 if (mode && t->IsSync()) {
4400 if (t->CheckTimer(now)) {
4401 timedout = kTRUE;
4402 }
4403 } else if (!mode && t->IsAsync()) {
4404 if (t->CheckTimer(now)) {
4405 timedout = kTRUE;
4406 }
4407 }
4408 }
4410
4411 return timedout;
4412}
4413
4414const Double_t gTicks = 1.0e-7;
4415////////////////////////////////////////////////////////////////////////////////
4416///
4417
4419{
4420 union {
4421 FILETIME ftFileTime;
4422 __int64 ftInt64;
4423 } ftRealTime; // time the process has spent in kernel mode
4424
4425 ::GetSystemTimeAsFileTime(&ftRealTime.ftFileTime);
4426 return (Double_t)ftRealTime.ftInt64 * gTicks;
4427}
4428
4429////////////////////////////////////////////////////////////////////////////////
4430///
4431
4433{
4434 OSVERSIONINFO OsVersionInfo;
4435
4436//*-* Value Platform
4437//*-* ----------------------------------------------------
4438//*-* VER_PLATFORM_WIN32s Win32s on Windows 3.1
4439//*-* VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95
4440//*-* VER_PLATFORM_WIN32_NT Windows NT
4441//*-*
4442
4443 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
4444 GetVersionEx(&OsVersionInfo);
4445 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
4446 DWORD ret;
4447 FILETIME ftCreate, // when the process was created
4448 ftExit; // when the process exited
4449
4450 union {
4451 FILETIME ftFileTime;
4452 __int64 ftInt64;
4453 } ftKernel; // time the process has spent in kernel mode
4454
4455 union {
4456 FILETIME ftFileTime;
4457 __int64 ftInt64;
4458 } ftUser; // time the process has spent in user mode
4459
4460 HANDLE hThread = GetCurrentThread();
4461 ret = GetThreadTimes (hThread, &ftCreate, &ftExit,
4462 &ftKernel.ftFileTime,
4463 &ftUser.ftFileTime);
4464 if (ret != TRUE){
4465 ret = ::GetLastError();
4466 ::Error("GetCPUTime", " Error on GetProcessTimes 0x%lx", (int)ret);
4467 }
4468
4469 // Process times are returned in a 64-bit structure, as the number of
4470 // 100 nanosecond ticks since 1 January 1601. User mode and kernel mode
4471 // times for this process are in separate 64-bit structures.
4472 // To convert to floating point seconds, we will:
4473 // Convert sum of high 32-bit quantities to 64-bit int
4474
4475 return (Double_t) (ftKernel.ftInt64 + ftUser.ftInt64) * gTicks;
4476 } else {
4477 return GetRealTime();
4478 }
4479}
4480
4481////////////////////////////////////////////////////////////////////////////////
4482/// Get current time in milliseconds since 0:00 Jan 1 1995.
4483
4485{
4486 static time_t jan95 = 0;
4487 if (!jan95) {
4488 struct tm tp;
4489 tp.tm_year = 95;
4490 tp.tm_mon = 0;
4491 tp.tm_mday = 1;
4492 tp.tm_hour = 0;
4493 tp.tm_min = 0;
4494 tp.tm_sec = 0;
4495 tp.tm_isdst = -1;
4496
4497 jan95 = mktime(&tp);
4498 if ((int)jan95 == -1) {
4499 ::SysError("TWinNTSystem::Now", "error converting 950001 0:00 to time_t");
4500 return 0;
4501 }
4502 }
4503
4504 _timeb now;
4505 _ftime(&now);
4506 return TTime((now.time-(Long_t)jan95)*1000 + now.millitm);
4507}
4508
4509////////////////////////////////////////////////////////////////////////////////
4510/// Sleep milliSec milli seconds.
4511/// The Sleep function suspends the execution of the CURRENT THREAD for
4512/// a specified interval.
4513
4515{
4516 ::Sleep(milliSec);
4517}
4518
4519////////////////////////////////////////////////////////////////////////////////
4520/// Select on file descriptors. The timeout to is in millisec.
4521
4523{
4524 Int_t rc = -4;
4525
4526 TFdSet rd, wr;
4527 Int_t mxfd = -1;
4528 TIter next(act);
4529 TFileHandler *h = nullptr;
4530 while ((h = (TFileHandler *) next())) {
4531 Int_t fd = h->GetFd();
4532 if (h->HasReadInterest())
4533 rd.Set(fd);
4534 if (h->HasWriteInterest())
4535 wr.Set(fd);
4536 h->ResetReadyMask();
4537 }
4538 rc = WinNTSelect(&rd, &wr, to);
4539
4540 // Set readiness bits
4541 if (rc > 0) {
4542 next.Reset();
4543 while ((h = (TFileHandler *) next())) {
4544 Int_t fd = h->GetFd();
4545 if (rd.IsSet(fd))
4546 h->SetReadReady();
4547 if (wr.IsSet(fd))
4548 h->SetWriteReady();
4549 }
4550 }
4551
4552 return rc;
4553}
4554
4555////////////////////////////////////////////////////////////////////////////////
4556/// Select on the file descriptor related to file handler h.
4557/// The timeout to is in millisec.
4558
4560{
4561 Int_t rc = -4;
4562
4563 TFdSet rd, wr;
4564 Int_t fd = -1;
4565 if (h) {
4566 fd = h->GetFd();
4567 if (h->HasReadInterest())
4568 rd.Set(fd);
4569 if (h->HasWriteInterest())
4570 wr.Set(fd);
4571 h->ResetReadyMask();
4572 rc = WinNTSelect(&rd, &wr, to);
4573 }
4574
4575 // Fill output lists, if required
4576 if (rc > 0) {
4577 if (rd.IsSet(fd))
4578 h->SetReadReady();
4579 if (wr.IsSet(fd))
4580 h->SetWriteReady();
4581 }
4582
4583 return rc;
4584}
4585
4586//---- RPC ---------------------------------------------------------------------
4587////////////////////////////////////////////////////////////////////////////////
4588/// Get port # of internet service.
4589
4590int TWinNTSystem::GetServiceByName(const char *servicename)
4591{
4592 struct servent *sp;
4593
4594 if ((sp = ::getservbyname(servicename, kProtocolName)) == 0) {
4595 Error("GetServiceByName", "no service \"%s\" with protocol \"%s\"\n",
4596 servicename, kProtocolName);
4597 return -1;
4598 }
4599 return ::ntohs(sp->s_port);
4600}
4601
4602////////////////////////////////////////////////////////////////////////////////
4603
4605{
4606 // Get name of internet service.
4607
4608 struct servent *sp;
4609
4610 if ((sp = ::getservbyport(::htons(port), kProtocolName)) == 0) {
4611 return Form("%d", port);
4612 }
4613 return sp->s_name;
4614}
4615
4616////////////////////////////////////////////////////////////////////////////////
4617/// Get Internet Protocol (IP) address of host.
4618
4620{
4621 struct hostent *host_ptr;
4622 const char *host;
4623 int type;
4624 UInt_t addr; // good for 4 byte addresses
4625
4626 if ((addr = ::inet_addr(hostname)) != INADDR_NONE) {
4627 type = AF_INET;
4628 if ((host_ptr = ::gethostbyaddr((const char *)&addr,
4629 sizeof(addr), AF_INET))) {
4630 host = host_ptr->h_name;
4631 TInetAddress a(host, ntohl(addr), type);
4632 UInt_t addr2;
4633 Int_t i;
4634 for (i = 1; host_ptr->h_addr_list[i]; i++) {
4635 memcpy(&addr2, host_ptr->h_addr_list[i], host_ptr->h_length);
4636 a.AddAddress(ntohl(addr2));
4637 }
4638 for (i = 0; host_ptr->h_aliases[i]; i++)
4639 a.AddAlias(host_ptr->h_aliases[i]);
4640 return a;
4641 } else {
4642 host = "UnNamedHost";
4643 }
4644 } else if ((host_ptr = ::gethostbyname(hostname))) {
4645 // Check the address type for an internet host
4646 if (host_ptr->h_addrtype != AF_INET) {
4647 Error("GetHostByName", "%s is not an internet host\n", hostname);
4648 return TInetAddress();
4649 }
4650 memcpy(&addr, host_ptr->h_addr, host_ptr->h_length);
4651 host = host_ptr->h_name;
4652 type = host_ptr->h_addrtype;
4653 TInetAddress a(host, ntohl(addr), type);
4654 UInt_t addr2;
4655 Int_t i;
4656 for (i = 1; host_ptr->h_addr_list[i]; i++) {
4657 memcpy(&addr2, host_ptr->h_addr_list[i], host_ptr->h_length);
4658 a.AddAddress(ntohl(addr2));
4659 }
4660 for (i = 0; host_ptr->h_aliases[i]; i++)
4661 a.AddAlias(host_ptr->h_aliases[i]);
4662 return a;
4663 } else {
4664 if (gDebug > 0) Error("GetHostByName", "unknown host %s", hostname);
4665 return TInetAddress(hostname, 0, -1);
4666 }
4667
4668 return TInetAddress(host, ::ntohl(addr), type);
4669}
4670
4671////////////////////////////////////////////////////////////////////////////////
4672/// Get Internet Protocol (IP) address of remote host and port #.
4673
4675{
4676 SOCKET sock = socket;
4677 struct sockaddr_in addr;
4678 int len = sizeof(addr);
4679
4680 if (::getpeername(sock, (struct sockaddr *)&addr, &len) == SOCKET_ERROR) {
4681 ::SysError("GetPeerName", "getpeername");
4682 return TInetAddress();
4683 }
4684
4685 struct hostent *host_ptr;
4686 const char *hostname;
4687 int family;
4688 UInt_t iaddr;
4689
4690 if ((host_ptr = ::gethostbyaddr((const char *)&addr.sin_addr,
4691 sizeof(addr.sin_addr), AF_INET))) {
4692 memcpy(&iaddr, host_ptr->h_addr, host_ptr->h_length);
4693 hostname = host_ptr->h_name;
4694 family = host_ptr->h_addrtype;
4695 } else {
4696 memcpy(&iaddr, &addr.sin_addr, sizeof(addr.sin_addr));
4697 hostname = "????";
4698 family = AF_INET;
4699 }
4700
4701 return TInetAddress(hostname, ::ntohl(iaddr), family, ::ntohs(addr.sin_port));
4702}
4703
4704////////////////////////////////////////////////////////////////////////////////
4705/// Get Internet Protocol (IP) address of host and port #.
4706
4708{
4709 SOCKET sock = socket;
4710 struct sockaddr_in addr;
4711 int len = sizeof(addr);
4712
4713 if (::getsockname(sock, (struct sockaddr *)&addr, &len) == SOCKET_ERROR) {
4714 ::SysError("GetSockName", "getsockname");
4715 return TInetAddress();
4716 }
4717
4718 struct hostent *host_ptr;
4719 const char *hostname;
4720 int family;
4721 UInt_t iaddr;
4722
4723 if ((host_ptr = ::gethostbyaddr((const char *)&addr.sin_addr,
4724 sizeof(addr.sin_addr), AF_INET))) {
4725 memcpy(&iaddr, host_ptr->h_addr, host_ptr->h_length);
4726 hostname = host_ptr->h_name;
4727 family = host_ptr->h_addrtype;
4728 } else {
4729 memcpy(&iaddr, &addr.sin_addr, sizeof(addr.sin_addr));
4730 hostname = "????";
4731 family = AF_INET;
4732 }
4733
4734 return TInetAddress(hostname, ::ntohl(iaddr), family, ::ntohs(addr.sin_port));
4735}
4736
4737////////////////////////////////////////////////////////////////////////////////
4738/// Announce unix domain service.
4739
4740int TWinNTSystem::AnnounceUnixService(int port, int backlog)
4741{
4742 SOCKET sock;
4743
4744 // Create socket
4745 if ((sock = ::socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
4746 ::SysError("TWinNTSystem::AnnounceUnixService", "socket");
4747 return -1;
4748 }
4749
4750 struct sockaddr_in inserver;
4751 memset(&inserver, 0, sizeof(inserver));
4752 inserver.sin_family = AF_INET;
4753 inserver.sin_addr.s_addr = ::htonl(INADDR_LOOPBACK);
4754 inserver.sin_port = port;
4755
4756 // Bind socket
4757 if (port > 0) {
4758 if (::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver)) == SOCKET_ERROR) {
4759 ::SysError("TWinNTSystem::AnnounceUnixService", "bind");
4760 return -2;
4761 }
4762 }
4763 // Start accepting connections
4764 if (::listen(sock, backlog)) {
4765 ::SysError("TWinNTSystem::AnnounceUnixService", "listen");
4766 return -1;
4767 }
4768 return (int)sock;
4769}
4770
4771////////////////////////////////////////////////////////////////////////////////
4772/// Open a socket on path 'sockpath', bind to it and start listening for Unix
4773/// domain connections to it. Returns socket fd or -1.
4774
4775int TWinNTSystem::AnnounceUnixService(const char *sockpath, int backlog)
4776{
4777 if (!sockpath || strlen(sockpath) <= 0) {
4778 ::SysError("TWinNTSystem::AnnounceUnixService", "socket path undefined");
4779 return -1;
4780 }
4781
4782 struct sockaddr_in myaddr;
4783 FILE * fp;
4784 int len = sizeof myaddr;
4785 int rc;
4786 int sock;
4787
4788 // Create socket
4789 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
4790 ::SysError("TWinNTSystem::AnnounceUnixService", "socket");
4791 return -1;
4792 }
4793
4794 memset(&myaddr, 0, sizeof(myaddr));
4795 myaddr.sin_port = 0;
4796 myaddr.sin_family = AF_INET;
4797 myaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
4798
4799 rc = bind(sock, (struct sockaddr *)&myaddr, len);
4800 if (rc) {
4801 ::SysError("TWinNTSystem::AnnounceUnixService", "bind");
4802 return rc;
4803 }
4804 rc = getsockname(sock, (struct sockaddr *)&myaddr, &len);
4805 if (rc) {
4806 ::SysError("TWinNTSystem::AnnounceUnixService", "getsockname");
4807 return rc;
4808 }
4809 TString socketpath = sockpath;
4810 socketpath.ReplaceAll("/", "\\");
4811 fp = fopen(socketpath, "wb");
4812 if (!fp) {
4813 ::SysError("TWinNTSystem::AnnounceUnixService", "fopen");
4814 return -1;
4815 }
4816 fprintf(fp, "%d", myaddr.sin_port);
4817 fclose(fp);
4818
4819 // Start accepting connections
4820 if (listen(sock, backlog)) {
4821 ::SysError("TWinNTSystem::AnnounceUnixService", "listen");
4822 return -1;
4823 }
4824
4825 return sock;
4826}
4827
4828////////////////////////////////////////////////////////////////////////////////
4829/// Close socket.
4830
4832{
4833 if (socket == -1) return;
4834 SOCKET sock = socket;
4835
4836 if (force) {
4837 ::shutdown(sock, 2);
4838 }
4839 struct linger linger = {0, 0};
4840 ::setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger));
4841 while (::closesocket(sock) == SOCKET_ERROR && WSAGetLastError() == WSAEINTR) {
4843 }
4844}
4845
4846////////////////////////////////////////////////////////////////////////////////
4847/// Receive a buffer headed by a length indicator. Length is the size of
4848/// the buffer. Returns the number of bytes received in buf or -1 in
4849/// case of error.
4850
4851int TWinNTSystem::RecvBuf(int sock, void *buf, int length)
4852{
4853 Int_t header;
4854
4855 if (WinNTRecv(sock, &header, sizeof(header), 0) > 0) {
4856 int count = ::ntohl(header);
4857
4858 if (count > length) {
4859 Error("RecvBuf", "record header exceeds buffer size");
4860 return -1;
4861 } else if (count > 0) {
4862 if (WinNTRecv(sock, buf, count, 0) < 0) {
4863 Error("RecvBuf", "cannot receive buffer");
4864 return -1;
4865 }
4866 }
4867 return count;
4868 }
4869 return -1;
4870}
4871
4872////////////////////////////////////////////////////////////////////////////////
4873/// Send a buffer headed by a length indicator. Returns length of sent buffer
4874/// or -1 in case of error.
4875
4876int TWinNTSystem::SendBuf(int sock, const void *buf, int length)
4877{
4878 Int_t header = ::htonl(length);
4879
4880 if (WinNTSend(sock, &header, sizeof(header), 0) < 0) {
4881 Error("SendBuf", "cannot send header");
4882 return -1;
4883 }
4884 if (length > 0) {
4885 if (WinNTSend(sock, buf, length, 0) < 0) {
4886 Error("SendBuf", "cannot send buffer");
4887 return -1;
4888 }
4889 }
4890 return length;
4891}
4892
4893////////////////////////////////////////////////////////////////////////////////
4894/// Receive exactly length bytes into buffer. Use opt to receive out-of-band
4895/// data or to have a peek at what is in the buffer (see TSocket). Buffer
4896/// must be able to store at least length bytes. Returns the number of
4897/// bytes received (can be 0 if other side of connection was closed) or -1
4898/// in case of error, -2 in case of MSG_OOB and errno == EWOULDBLOCK, -3
4899/// in case of MSG_OOB and errno == EINVAL and -4 in case of kNoBlock and
4900/// errno == EWOULDBLOCK. Returns -5 if pipe broken or reset by peer
4901/// (EPIPE || ECONNRESET).
4902
4903int TWinNTSystem::RecvRaw(int sock, void *buf, int length, int opt)
4904{
4905 int flag;
4906
4907 switch (opt) {
4908 case kDefault:
4909 flag = 0;
4910 break;
4911 case kOob:
4912 flag = MSG_OOB;
4913 break;
4914 case kPeek:
4915 flag = MSG_PEEK;
4916 break;
4917 case kDontBlock:
4918 flag = -1;
4919 break;
4920 default:
4921 flag = 0;
4922 break;
4923 }
4924
4925 int n;
4926 if ((n = WinNTRecv(sock, buf, length, flag)) <= 0) {
4927 if (n == -1) {
4928 Error("RecvRaw", "cannot receive buffer");
4929 }
4930 return n;
4931 }
4932 return n;
4933}
4934
4935////////////////////////////////////////////////////////////////////////////////
4936/// Send exactly length bytes from buffer. Use opt to send out-of-band
4937/// data (see TSocket). Returns the number of bytes sent or -1 in case of
4938/// error. Returns -4 in case of kNoBlock and errno == EWOULDBLOCK.
4939/// Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
4940
4941int TWinNTSystem::SendRaw(int sock, const void *buf, int length, int opt)
4942{
4943 int flag;
4944
4945 switch (opt) {
4946 case kDefault:
4947 flag = 0;
4948 break;
4949 case kOob:
4950 flag = MSG_OOB;
4951 break;
4952 case kDontBlock:
4953 flag = -1;
4954 break;
4955 case kPeek: // receive only option (see RecvRaw)
4956 default:
4957 flag = 0;
4958 break;
4959 }
4960
4961 int n;
4962 if ((n = WinNTSend(sock, buf, length, flag)) <= 0) {
4963 if (n == -1 && GetErrno() != EINTR) {
4964 Error("SendRaw", "cannot send buffer");
4965 }
4966 return n;
4967 }
4968 return n;
4969}
4970
4971////////////////////////////////////////////////////////////////////////////////
4972/// Set socket option.
4973
4974int TWinNTSystem::SetSockOpt(int socket, int opt, int value)
4975{
4976 u_long val = value;
4977 if (socket == -1) return -1;
4978 SOCKET sock = socket;
4979
4980 switch (opt) {
4981 case kSendBuffer:
4982 if (::setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
4983 ::SysError("SetSockOpt", "setsockopt(SO_SNDBUF)");
4984 return -1;
4985 }
4986 break;
4987 case kRecvBuffer:
4988 if (::setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
4989 ::SysError("SetSockOpt", "setsockopt(SO_RCVBUF)");
4990 return -1;
4991 }
4992 break;
4993 case kOobInline:
4994 if (::setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
4995 SysError("SetSockOpt", "setsockopt(SO_OOBINLINE)");
4996 return -1;
4997 }
4998 break;
4999 case kKeepAlive:
5000 if (::setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
5001 ::SysError("SetSockOpt", "setsockopt(SO_KEEPALIVE)");
5002 return -1;
5003 }
5004 break;
5005 case kReuseAddr:
5006 if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
5007 ::SysError("SetSockOpt", "setsockopt(SO_REUSEADDR)");
5008 return -1;
5009 }
5010 break;
5011 case kNoDelay:
5012 if (::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
5013 ::SysError("SetSockOpt", "setsockopt(TCP_NODELAY)");
5014 return -1;
5015 }
5016 break;
5017 case kNoBlock:
5018 if (::ioctlsocket(sock, FIONBIO, &val) == SOCKET_ERROR) {
5019 ::SysError("SetSockOpt", "ioctl(FIONBIO)");
5020 return -1;
5021 }
5022 break;
5023#if 0
5024 case kProcessGroup:
5025 if (::ioctl(sock, SIOCSPGRP, &val) == -1) {
5026 ::SysError("SetSockOpt", "ioctl(SIOCSPGRP)");
5027 return -1;
5028 }
5029 break;
5030#endif
5031 case kAtMark: // read-only option (see GetSockOpt)
5032 case kBytesToRead: // read-only option
5033 default:
5034 Error("SetSockOpt", "illegal option (%d)", opt);
5035 return -1;
5036 break;
5037 }
5038 return 0;
5039}
5040
5041////////////////////////////////////////////////////////////////////////////////
5042/// Get socket option.
5043
5044int TWinNTSystem::GetSockOpt(int socket, int opt, int *val)
5045{
5046 if (socket == -1) return -1;
5047 SOCKET sock = socket;
5048
5049 int optlen = sizeof(*val);
5050
5051 switch (opt) {
5052 case kSendBuffer:
5053 if (::getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)val, &optlen) == SOCKET_ERROR) {
5054 ::SysError("GetSockOpt", "getsockopt(SO_SNDBUF)");
5055 return -1;
5056 }
5057 break;
5058 case kRecvBuffer:
5059 if (::getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)val, &optlen) == SOCKET_ERROR) {
5060 ::SysError("GetSockOpt", "getsockopt(SO_RCVBUF)");
5061 return -1;
5062 }
5063 break;
5064 case kOobInline:
5065 if (::getsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char*)val, &optlen) == SOCKET_ERROR) {
5066 ::SysError("GetSockOpt", "getsockopt(SO_OOBINLINE)");
5067 return -1;
5068 }
5069 break;
5070 case kKeepAlive:
5071 if (::getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)val, &optlen) == SOCKET_ERROR) {
5072 ::SysError("GetSockOpt", "getsockopt(SO_KEEPALIVE)");
5073 return -1;
5074 }
5075 break;
5076 case kReuseAddr:
5077 if (::getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)val, &optlen) == SOCKET_ERROR) {
5078 ::SysError("GetSockOpt", "getsockopt(SO_REUSEADDR)");
5079 return -1;
5080 }
5081 break;
5082 case kNoDelay:
5083 if (::getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)val, &optlen) == SOCKET_ERROR) {
5084 ::SysError("GetSockOpt", "getsockopt(TCP_NODELAY)");
5085 return -1;
5086 }
5087 break;
5088 case kNoBlock:
5089 {
5090 int flg = 0;
5091 if (sock == INVALID_SOCKET) {
5092 ::SysError("GetSockOpt", "INVALID_SOCKET");
5093 }
5094 *val = flg; // & O_NDELAY; It is not been defined for WIN32
5095 return -1;
5096 }
5097 break;
5098#if 0
5099 case kProcessGroup:
5100 if (::ioctlsocket(sock, SIOCGPGRP, (u_long*)val) == SOCKET_ERROR) {
5101 ::SysError("GetSockOpt", "ioctl(SIOCGPGRP)");
5102 return -1;
5103 }
5104 break;
5105#endif
5106 case kAtMark:
5107 if (::ioctlsocket(sock, SIOCATMARK, (u_long*)val) == SOCKET_ERROR) {
5108 ::SysError("GetSockOpt", "ioctl(SIOCATMARK)");
5109 return -1;
5110 }
5111 break;
5112 case kBytesToRead:
5113 if (::ioctlsocket(sock, FIONREAD, (u_long*)val) == SOCKET_ERROR) {
5114 ::SysError("GetSockOpt", "ioctl(FIONREAD)");
5115 return -1;
5116 }
5117 break;
5118 default:
5119 Error("GetSockOpt", "illegal option (%d)", opt);
5120 *val = 0;
5121 return -1;
5122 break;
5123 }
5124 return 0;
5125}
5126
5127////////////////////////////////////////////////////////////////////////////////
5128/// Connect to service servicename on server servername.
5129
5130int TWinNTSystem::ConnectService(const char *servername, int port,
5131 int tcpwindowsize, const char *protocol)
5132{
5133 short sport;
5134 struct servent *sp;
5135
5136 if (!strcmp(servername, "unix")) {
5137 return WinNTUnixConnect(port);
5138 }
5139 else if (!gSystem->AccessPathName(servername) || servername[0] == '/' ||
5140 (servername[1] == ':' && servername[2] == '/')) {
5141 return WinNTUnixConnect(servername);
5142 }
5143
5144 if (!strcmp(protocol, "udp")){
5145 return WinNTUdpConnect(servername, port);
5146 }
5147
5148 if ((sp = ::getservbyport(::htons(port), kProtocolName))) {
5149 sport = sp->s_port;
5150 } else {
5151 sport = ::htons(port);
5152 }
5153
5154 TInetAddress addr = gSystem->GetHostByName(servername);
5155 if (!addr.IsValid()) return -1;
5156 UInt_t adr = ::htonl(addr.GetAddress());
5157
5158 struct sockaddr_in server;
5159 memset(&server, 0, sizeof(server));
5160 memcpy(&server.sin_addr, &adr, sizeof(adr));
5161 server.sin_family = addr.GetFamily();
5162 server.sin_port = sport;
5163
5164 // Create socket
5165 SOCKET sock;
5166 if ((sock = ::socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
5167 ::SysError("TWinNTSystem::WinNTConnectTcp", "socket");
5168 return -1;
5169 }
5170
5171 if (tcpwindowsize > 0) {
5172 gSystem->SetSockOpt((int)sock, kRecvBuffer, tcpwindowsize);
5173 gSystem->SetSockOpt((int)sock, kSendBuffer, tcpwindowsize);
5174 }
5175
5176 if (::connect(sock, (struct sockaddr*) &server, sizeof(server)) == INVALID_SOCKET) {
5177 //::SysError("TWinNTSystem::UnixConnectTcp", "connect");
5178 ::closesocket(sock);
5179 return -1;
5180 }
5181 return (int) sock;
5182}
5183
5184////////////////////////////////////////////////////////////////////////////////
5185/// Connect to a Unix domain socket.
5186
5188{
5189 struct sockaddr_in myaddr;
5190 int sock;
5191
5192 memset(&myaddr, 0, sizeof(myaddr));
5193 myaddr.sin_family = AF_INET;
5194 myaddr.sin_port = port;
5195 myaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
5196
5197 // Open socket
5198 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
5199 ::SysError("TWinNTSystem::WinNTUnixConnect", "socket");
5200 return -1;
5201 }
5202
5203 while ((connect(sock, (struct sockaddr *)&myaddr, sizeof myaddr)) == -1) {
5204 if (GetErrno() == EINTR)
5205 ResetErrno();
5206 else {
5207 ::SysError("TWinNTSystem::WinNTUnixConnect", "connect");
5208 close(sock);
5209 return -1;
5210 }
5211 }
5212 return sock;
5213}
5214
5215////////////////////////////////////////////////////////////////////////////////
5216/// Connect to a Unix domain socket. Returns -1 in case of error.
5217
5218int TWinNTSystem::WinNTUnixConnect(const char *sockpath)
5219{
5220 FILE *fp;
5221 int port = 0;
5222
5223 if (!sockpath || strlen(sockpath) <= 0) {
5224 ::SysError("TWinNTSystem::WinNTUnixConnect", "socket path undefined");
5225 return -1;
5226 }
5227 TString socketpath = sockpath;
5228 socketpath.ReplaceAll("/", "\\");
5229 fp = fopen(socketpath.Data(), "rb");
5230 if (!fp) {
5231 ::SysError("TWinNTSystem::WinNTUnixConnect", "fopen");
5232 return -1;
5233 }
5234 fscanf(fp, "%d", &port);
5235 fclose(fp);
5236 /* XXX: set errno in this case */
5237 if (port < 0 || port > 65535) {
5238 ::SysError("TWinNTSystem::WinNTUnixConnect", "invalid port");
5239 return -1;
5240 }
5241 return WinNTUnixConnect(port);
5242}
5243
5244////////////////////////////////////////////////////////////////////////////////
5245/// Creates a UDP socket connection
5246/// Is called via the TSocket constructor. Returns -1 in case of error.
5247
5248int TWinNTSystem::WinNTUdpConnect(const char *hostname, int port)
5249{
5250 short sport;
5251 struct servent *sp;
5252
5253 if ((sp = getservbyport(htons(port), kProtocolName)))
5254 sport = sp->s_port;
5255 else
5256 sport = htons(port);
5257
5258 TInetAddress addr = gSystem->GetHostByName(hostname);
5259 if (!addr.IsValid()) return -1;
5260 UInt_t adr = htonl(addr.GetAddress());
5261
5262 struct sockaddr_in server;
5263 memset(&server, 0, sizeof(server));
5264 memcpy(&server.sin_addr, &adr, sizeof(adr));
5265 server.sin_family = addr.GetFamily();
5266 server.sin_port = sport;
5267
5268 // Create socket
5269 int sock;
5270 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
5271 ::SysError("TWinNTSystem::WinNTUdpConnect", "socket (%s:%d)",
5272 hostname, port);
5273 return -1;
5274 }
5275
5276 while (connect(sock, (struct sockaddr*) &server, sizeof(server)) == -1) {
5277 if (GetErrno() == EINTR)
5278 ResetErrno();
5279 else {
5280 ::SysError("TWinNTSystem::WinNTUdpConnect", "connect (%s:%d)",
5281 hostname, port);
5282 close(sock);
5283 return -1;
5284 }
5285 }
5286 return sock;
5287}
5288
5289////////////////////////////////////////////////////////////////////////////////
5290/// Open a connection to a service on a server. Returns -1 in case
5291/// connection cannot be opened.
5292/// Use tcpwindowsize to specify the size of the receive buffer, it has
5293/// to be specified here to make sure the window scale option is set (for
5294/// tcpwindowsize > 65KB and for platforms supporting window scaling).
5295/// Is called via the TSocket constructor.
5296
5297int TWinNTSystem::OpenConnection(const char *server, int port, int tcpwindowsize,
5298 const char *protocol)
5299{
5300 return ConnectService(server, port, tcpwindowsize, protocol);
5301}
5302
5303////////////////////////////////////////////////////////////////////////////////
5304/// Announce TCP/IP service.
5305/// Open a socket, bind to it and start listening for TCP/IP connections
5306/// on the port. If reuse is true reuse the address, backlog specifies
5307/// how many sockets can be waiting to be accepted.
5308/// Use tcpwindowsize to specify the size of the receive buffer, it has
5309/// to be specified here to make sure the window scale option is set (for
5310/// tcpwindowsize > 65KB and for platforms supporting window scaling).
5311/// Returns socket fd or -1 if socket() failed, -2 if bind() failed
5312/// or -3 if listen() failed.
5313
5314int TWinNTSystem::AnnounceTcpService(int port, Bool_t reuse, int backlog,
5315 int tcpwindowsize)
5316{
5317 short sport;
5318 struct servent *sp;
5319 const short kSOCKET_MINPORT = 5000, kSOCKET_MAXPORT = 15000;
5320 short tryport = kSOCKET_MINPORT;
5321
5322 if ((sp = ::getservbyport(::htons(port), kProtocolName))) {
5323 sport = sp->s_port;
5324 } else {
5325 sport = ::htons(port);
5326 }
5327
5328 if (port == 0 && reuse) {
5329 ::Error("TWinNTSystem::WinNTTcpService", "cannot do a port scan while reuse is true");
5330 return -1;
5331 }
5332
5333 if ((sp = ::getservbyport(::htons(port), kProtocolName))) {
5334 sport = sp->s_port;
5335 } else {
5336 sport = ::htons(port);
5337 }
5338
5339 // Create tcp socket
5340 SOCKET sock;
5341 if ((sock = ::socket(AF_INET, SOCK_STREAM, 0)) < 0) {
5342 ::SysError("TWinNTSystem::WinNTTcpService", "socket");
5343 return -1;
5344 }
5345
5346 if (reuse) {
5347 gSystem->SetSockOpt((int)sock, kReuseAddr, 1);
5348 }
5349
5350 if (tcpwindowsize > 0) {
5351 gSystem->SetSockOpt((int)sock, kRecvBuffer, tcpwindowsize);
5352 gSystem->SetSockOpt((int)sock, kSendBuffer, tcpwindowsize);
5353 }
5354
5355 struct sockaddr_in inserver;
5356 memset(&inserver, 0, sizeof(inserver));
5357 inserver.sin_family = AF_INET;
5358 inserver.sin_addr.s_addr = ::htonl(INADDR_ANY);
5359 inserver.sin_port = sport;
5360
5361 // Bind socket
5362 if (port > 0) {
5363 if (::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver)) == SOCKET_ERROR) {
5364 ::SysError("TWinNTSystem::WinNTTcpService", "bind");
5365 return -2;
5366 }
5367 } else {
5368 int bret;
5369 do {
5370 inserver.sin_port = ::htons(tryport);
5371 bret = ::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver));
5372 tryport++;
5373 } while (bret == SOCKET_ERROR && WSAGetLastError() == WSAEADDRINUSE &&
5374 tryport < kSOCKET_MAXPORT);
5375 if (bret == SOCKET_ERROR) {
5376 ::SysError("TWinNTSystem::WinNTTcpService", "bind (port scan)");
5377 return -2;
5378 }
5379 }
5380
5381 // Start accepting connections
5382 if (::listen(sock, backlog) == SOCKET_ERROR) {
5383 ::SysError("TWinNTSystem::WinNTTcpService", "listen");
5384 return -3;
5385 }
5386 return (int)sock;
5387}
5388
5389////////////////////////////////////////////////////////////////////////////////
5390/// Announce UDP service.
5391
5392int TWinNTSystem::AnnounceUdpService(int port, int backlog)
5393{
5394 // Open a socket, bind to it and start listening for UDP connections
5395 // on the port. If reuse is true reuse the address, backlog specifies
5396 // how many sockets can be waiting to be accepted. If port is 0 a port
5397 // scan will be done to find a free port. This option is mutual exlusive
5398 // with the reuse option.
5399
5400 const short kSOCKET_MINPORT = 5000, kSOCKET_MAXPORT = 15000;
5401 short sport, tryport = kSOCKET_MINPORT;
5402 struct servent *sp;
5403
5404 if ((sp = getservbyport(htons(port), kProtocolName)))
5405 sport = sp->s_port;
5406 else
5407 sport = htons(port);
5408
5409 // Create udp socket
5410 int sock;
5411 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
5412 ::SysError("TUnixSystem::UnixUdpService", "socket");
5413 return -1;
5414 }
5415
5416 struct sockaddr_in inserver;
5417 memset(&inserver, 0, sizeof(inserver));
5418 inserver.sin_family = AF_INET;
5419 inserver.sin_addr.s_addr = htonl(INADDR_ANY);
5420 inserver.sin_port = sport;
5421
5422 // Bind socket
5423 if (port > 0) {
5424 if (bind(sock, (struct sockaddr*) &inserver, sizeof(inserver))) {
5425 ::SysError("TWinNTSystem::AnnounceUdpService", "bind");
5426 return -2;
5427 }
5428 } else {
5429 int bret;
5430 do {
5431 inserver.sin_port = htons(tryport);
5432 bret = bind(sock, (struct sockaddr*) &inserver, sizeof(inserver));
5433 tryport++;
5434 } while (bret == SOCKET_ERROR && WSAGetLastError() == WSAEADDRINUSE &&
5435 tryport < kSOCKET_MAXPORT);
5436 if (bret < 0) {
5437 ::SysError("TWinNTSystem::AnnounceUdpService", "bind (port scan)");
5438 return -2;
5439 }
5440 }
5441
5442 // Start accepting connections
5443 if (listen(sock, backlog)) {
5444 ::SysError("TWinNTSystem::AnnounceUdpService", "listen");
5445 return -3;
5446 }
5447
5448 return sock;
5449}
5450
5451////////////////////////////////////////////////////////////////////////////////
5452/// Accept a connection. In case of an error return -1. In case
5453/// non-blocking I/O is enabled and no connections are available
5454/// return -2.
5455
5457{
5458 int soc = -1;
5459 SOCKET sock = socket;
5460
5461 while ((soc = ::accept(sock, 0, 0)) == INVALID_SOCKET &&
5462 (::WSAGetLastError() == WSAEINTR)) {
5464 }
5465
5466 if (soc == -1) {
5467 if (::WSAGetLastError() == WSAEWOULDBLOCK) {
5468 return -2;
5469 } else {
5470 ::SysError("AcceptConnection", "accept");
5471 return -1;
5472 }
5473 }
5474 return soc;
5475}
5476
5477//---- System, CPU and Memory info ---------------------------------------------
5478
5479// !!! using undocumented functions and structures !!!
5480
5481#define SystemBasicInformation 0
5482#define SystemPerformanceInformation 2
5483
5484typedef struct
5485{
5486 DWORD dwUnknown1;
5487 ULONG uKeMaximumIncrement;
5488 ULONG uPageSize;
5489 ULONG uMmNumberOfPhysicalPages;
5490 ULONG uMmLowestPhysicalPage;
5491 ULONG UMmHighestPhysicalPage;
5492 ULONG uAllocationGranularity;
5493 PVOID pLowestUserAddress;
5494 PVOID pMmHighestUserAddress;
5495 ULONG uKeActiveProcessors;
5496 BYTE bKeNumberProcessors;
5497 BYTE bUnknown2;
5498 WORD bUnknown3;
5499} SYSTEM_BASIC_INFORMATION;
5500
5501typedef struct
5502{
5503 LARGE_INTEGER liIdleTime;
5504 DWORD dwSpare[76];
5505} SYSTEM_PERFORMANCE_INFORMATION;
5506
5507typedef struct _PROCESS_MEMORY_COUNTERS {
5508 DWORD cb;
5509 DWORD PageFaultCount;
5510 SIZE_T PeakWorkingSetSize;
5511 SIZE_T WorkingSetSize;
5512 SIZE_T QuotaPeakPagedPoolUsage;
5513 SIZE_T QuotaPagedPoolUsage;
5514 SIZE_T QuotaPeakNonPagedPoolUsage;
5515 SIZE_T QuotaNonPagedPoolUsage;
5516 SIZE_T PagefileUsage;
5517 SIZE_T PeakPagefileUsage;
5519
5520typedef LONG (WINAPI *PROCNTQSI) (UINT, PVOID, ULONG, PULONG);
5521
5522#define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 + (double)((x).LowPart))
5523
5524////////////////////////////////////////////////////////////////////////////////
5525/// Calculate the CPU clock speed using the 'rdtsc' instruction.
5526/// RDTSC: Read Time Stamp Counter.
5527
5528static DWORD GetCPUSpeed()
5529{
5530 LARGE_INTEGER ulFreq, ulTicks, ulValue, ulStartCounter;
5531
5532 // Query for high-resolution counter frequency
5533 // (this is not the CPU frequency):
5534 if (QueryPerformanceFrequency(&ulFreq)) {
5535 // Query current value:
5536 QueryPerformanceCounter(&ulTicks);
5537 // Calculate end value (one second interval);
5538 // this is (current + frequency)
5539 ulValue.QuadPart = ulTicks.QuadPart + ulFreq.QuadPart/10;
5540 ulStartCounter.QuadPart = __rdtsc();
5541
5542 // Loop for one second (measured with the high-resolution counter):
5543 do {
5544 QueryPerformanceCounter(&ulTicks);
5545 } while (ulTicks.QuadPart <= ulValue.QuadPart);
5546 // Now again read CPU time-stamp counter:
5547 return (DWORD)((__rdtsc() - ulStartCounter.QuadPart)/100000);
5548 } else {
5549 // No high-resolution counter present:
5550 return 0;
5551 }
5552}
5553
5554#define BUFSIZE 80
5555#define SM_SERVERR2 89
5556typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
5557
5558////////////////////////////////////////////////////////////////////////////////
5559
5560static const char *GetWindowsVersion()
5561{
5562 OSVERSIONINFOEX osvi;
5563 SYSTEM_INFO si;
5564 PGNSI pGNSI;
5565 BOOL bOsVersionInfoEx;
5566 static char *strReturn = nullptr;
5567 char temp[512];
5568
5569 if (!strReturn)
5570 strReturn = new char[2048];
5571 else
5572 return strReturn;
5573
5574 ZeroMemory(&si, sizeof(SYSTEM_INFO));
5575 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
5576
5577 // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
5578 // If that fails, try using the OSVERSIONINFO structure.
5579
5580 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
5581
5582 if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
5583 {
5584 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
5585 if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
5586 return "";
5587 }
5588
5589 // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
5590 pGNSI = (PGNSI) GetProcAddress( GetModuleHandle("kernel32.dll"),
5591 "GetNativeSystemInfo");
5592 if(NULL != pGNSI)
5593 pGNSI(&si);
5594 else GetSystemInfo(&si);
5595
5596 switch (osvi.dwPlatformId)
5597 {
5598 // Test for the Windows NT product family.
5599 case VER_PLATFORM_WIN32_NT:
5600
5601 // Test for the specific product.
5602 if ( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0 )
5603 {
5604 if( osvi.wProductType == VER_NT_WORKSTATION )
5605 strlcpy(strReturn, "Microsoft Windows Vista ",2048);
5606 else strlcpy(strReturn, "Windows Server \"Longhorn\" " ,2048);
5607 }
5608 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
5609 {
5610 if( GetSystemMetrics(SM_SERVERR2) )
5611 strlcpy(strReturn, "Microsoft Windows Server 2003 \"R2\" ",2048);
5612 else if( osvi.wProductType == VER_NT_WORKSTATION &&
5613 si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
5614 {
5615 strlcpy(strReturn, "Microsoft Windows XP Professional x64 Edition ",2048);
5616 }
5617 else strlcpy(strReturn, "Microsoft Windows Server 2003, ",2048);
5618 }
5619 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
5620 strlcpy(strReturn, "Microsoft Windows XP ",2048);
5621
5622 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
5623 strlcpy(strReturn, "Microsoft Windows 2000 ",2048);
5624
5625 if ( osvi.dwMajorVersion <= 4 )
5626 strlcpy(strReturn, "Microsoft Windows NT ",2048);
5627
5628 // Test for specific product on Windows NT 4.0 SP6 and later.
5629 if( bOsVersionInfoEx )
5630 {
5631 // Test for the workstation type.
5632 if ( osvi.wProductType == VER_NT_WORKSTATION &&
5633 si.wProcessorArchitecture!=PROCESSOR_ARCHITECTURE_AMD64)
5634 {
5635 if( osvi.dwMajorVersion == 4 )
5636 strlcat(strReturn, "Workstation 4.0 ",2048 );
5637 else if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
5638 strlcat(strReturn, "Home Edition " ,2048);
5639 else strlcat(strReturn, "Professional " ,2048);
5640 }
5641 // Test for the server type.
5642 else if ( osvi.wProductType == VER_NT_SERVER ||
5643 osvi.wProductType == VER_NT_DOMAIN_CONTROLLER )
5644 {
5645 if(osvi.dwMajorVersion==5 && osvi.dwMinorVersion==2)
5646 {
5647 if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
5648 {
5649 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
5650 strlcat(strReturn, "Datacenter Edition for Itanium-based Systems",2048 );
5651 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
5652 strlcat(strReturn, "Enterprise Edition for Itanium-based Systems" ,2048);
5653 }
5654 else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
5655 {
5656 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
5657 strlcat(strReturn, "Datacenter x64 Edition ",2048 );
5658 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
5659 strlcat(strReturn, "Enterprise x64 Edition ",2048 );
5660 else strlcat(strReturn, "Standard x64 Edition ",2048 );
5661 }
5662 else
5663 {
5664 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
5665 strlcat(strReturn, "Datacenter Edition ",2048 );
5666 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
5667 strlcat(strReturn, "Enterprise Edition ",2048 );
5668 else if ( osvi.wSuiteMask == VER_SUITE_BLADE )
5669 strlcat(strReturn, "Web Edition " ,2048);
5670 else strlcat(strReturn, "Standard Edition ",2048 );
5671 }
5672 }
5673 else if(osvi.dwMajorVersion==5 && osvi.dwMinorVersion==0)
5674 {
5675 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
5676 strlcat(strReturn, "Datacenter Server ",2048 );
5677 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
5678 strlcat(strReturn, "Advanced Server ",2048 );
5679 else strlcat(strReturn, "Server ",2048 );
5680 }
5681 else // Windows NT 4.0
5682 {
5683 if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
5684 strlcat(strReturn, "Server 4.0, Enterprise Edition " ,2048);
5685 else strlcat(strReturn, "Server 4.0 ",2048 );
5686 }
5687 }
5688 }
5689 // Test for specific product on Windows NT 4.0 SP5 and earlier
5690 else
5691 {
5692 HKEY hKey;
5693 TCHAR szProductType[BUFSIZE];
5694 DWORD dwBufLen=BUFSIZE*sizeof(TCHAR);
5695 LONG lRet;
5696
5697 lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
5698 "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
5699 0, KEY_QUERY_VALUE, &hKey );
5700 if( lRet != ERROR_SUCCESS )
5701 return "";
5702
5703 lRet = RegQueryValueEx( hKey, "ProductType", NULL, NULL,
5704 (LPBYTE) szProductType, &dwBufLen);
5705 RegCloseKey( hKey );
5706
5707 if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE*sizeof(TCHAR)) )
5708 return "";
5709
5710 if ( lstrcmpi( "WINNT", szProductType) == 0 )
5711 strlcat(strReturn, "Workstation " ,2048);
5712 if ( lstrcmpi( "LANMANNT", szProductType) == 0 )
5713 strlcat(strReturn, "Server " ,2048);
5714 if ( lstrcmpi( "SERVERNT", szProductType) == 0 )
5715 strlcat(strReturn, "Advanced Server " ,2048);
5716 snprintf(temp,512, "%d.%d ", osvi.dwMajorVersion, osvi.dwMinorVersion);
5717 strlcat(strReturn, temp,2048);
5718 }
5719
5720 // Display service pack (if any) and build number.
5721
5722 if( osvi.dwMajorVersion == 4 &&
5723 lstrcmpi( osvi.szCSDVersion, "Service Pack 6" ) == 0 )
5724 {
5725 HKEY hKey;
5726 LONG lRet;
5727
5728 // Test for SP6 versus SP6a.
5729 lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
5730 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009",
5731 0, KEY_QUERY_VALUE, &hKey );
5732 if( lRet == ERROR_SUCCESS ) {
5733 snprintf(temp, 512, "Service Pack 6a (Build %d)", osvi.dwBuildNumber & 0xFFFF );
5734 strlcat(strReturn, temp,2048 );
5735 }
5736 else // Windows NT 4.0 prior to SP6a
5737 {
5738 snprintf(temp,512, "%s (Build %d)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
5739 strlcat(strReturn, temp,2048 );
5740 }
5741
5742 RegCloseKey( hKey );
5743 }
5744 else // not Windows NT 4.0
5745 {
5746 snprintf(temp, 512,"%s (Build %d)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
5747 strlcat(strReturn, temp,2048 );
5748 }
5749
5750 break;
5751
5752 // Test for the Windows Me/98/95.
5753 case VER_PLATFORM_WIN32_WINDOWS:
5754
5755 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
5756 {
5757 strlcpy(strReturn, "Microsoft Windows 95 ",2048);
5758 if (osvi.szCSDVersion[1]=='C' || osvi.szCSDVersion[1]=='B')
5759 strlcat(strReturn, "OSR2 " ,2048);
5760 }
5761
5762 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
5763 {
5764 strlcpy(strReturn, "Microsoft Windows 98 ",2048);
5765 if ( osvi.szCSDVersion[1]=='A' || osvi.szCSDVersion[1]=='B')
5766 strlcat(strReturn, "SE ",2048 );
5767 }
5768
5769 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
5770 {
5771 strlcpy(strReturn, "Microsoft Windows Millennium Edition",2048);
5772 }
5773 break;
5774
5775 case VER_PLATFORM_WIN32s:
5776 strlcpy(strReturn, "Microsoft Win32s",2048);
5777 break;
5778 }
5779 return strReturn;
5780}
5781
5782////////////////////////////////////////////////////////////////////////////////
5783/// Use assembly to retrieve the L2 cache information ...
5784
5785static int GetL2CacheSize()
5786{
5787 unsigned nHighestFeatureEx;
5788 int nBuff[4];
5789
5790 __cpuid(nBuff, 0x80000000);
5791 nHighestFeatureEx = (unsigned)nBuff[0];
5792 // Get cache size
5793 if (nHighestFeatureEx >= 0x80000006) {
5794 __cpuid(nBuff, 0x80000006);
5795 return (((unsigned)nBuff[2])>>16);
5796 }
5797 else return 0;
5798}
5799
5800////////////////////////////////////////////////////////////////////////////////
5801/// Get system info for Windows NT.
5802
5803static void GetWinNTSysInfo(SysInfo_t *sysinfo)
5804{
5805 SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
5806 SYSTEM_INFO sysInfo;
5807 MEMORYSTATUSEX statex;
5808 OSVERSIONINFO OsVersionInfo;
5809 HKEY hKey;
5810 char szKeyValueString[80];
5811 DWORD szKeyValueDword;
5812 DWORD dwBufLen;
5813 LONG status;
5814 PROCNTQSI NtQuerySystemInformation;
5815
5816 NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(
5817 GetModuleHandle("ntdll"), "NtQuerySystemInformation");
5818
5819 if (!NtQuerySystemInformation) {
5820 ::Error("GetWinNTSysInfo",
5821 "Error on GetProcAddress(NtQuerySystemInformation)");
5822 return;
5823 }
5824
5825 status = NtQuerySystemInformation(SystemPerformanceInformation,
5826 &SysPerfInfo, sizeof(SysPerfInfo),
5827 NULL);
5828 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
5829 GetVersionEx(&OsVersionInfo);
5830 GetSystemInfo(&sysInfo);
5831 statex.dwLength = sizeof(statex);
5832 if (!GlobalMemoryStatusEx(&statex)) {
5833 ::Error("GetWinNTSysInfo", "Error on GlobalMemoryStatusEx()");
5834 return;
5835 }
5836 sysinfo->fCpus = sysInfo.dwNumberOfProcessors;
5837 sysinfo->fPhysRam = (Int_t)(statex.ullTotalPhys >> 20);
5838 sysinfo->fOS = GetWindowsVersion();
5839 sysinfo->fModel = "";
5840 sysinfo->fCpuType = "";
5841 sysinfo->fCpuSpeed = GetCPUSpeed();
5842 sysinfo->fBusSpeed = 0; // bus speed in MHz
5843 sysinfo->fL2Cache = GetL2CacheSize();
5844
5845 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System",
5846 0, KEY_QUERY_VALUE, &hKey);
5847 if (status == ERROR_SUCCESS) {
5848 dwBufLen = sizeof(szKeyValueString);
5849 RegQueryValueEx(hKey, "Identifier", NULL, NULL,(LPBYTE)szKeyValueString,
5850 &dwBufLen);
5851 sysinfo->fModel = szKeyValueString;
5852 RegCloseKey (hKey);
5853 }
5854 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
5855 "Hardware\\Description\\System\\CentralProcessor\\0",
5856 0, KEY_QUERY_VALUE, &hKey);
5857 if (status == ERROR_SUCCESS) {
5858 dwBufLen = sizeof(szKeyValueString);
5859 status = RegQueryValueEx(hKey, "ProcessorNameString", NULL, NULL,
5860 (LPBYTE)szKeyValueString, &dwBufLen);
5861 if (status == ERROR_SUCCESS)
5862 sysinfo->fCpuType = szKeyValueString;
5863 dwBufLen = sizeof(DWORD);
5864 status = RegQueryValueEx(hKey,"~MHz",NULL,NULL,(LPBYTE)&szKeyValueDword,
5865 &dwBufLen);
5866 if ((status == ERROR_SUCCESS) && ((sysinfo->fCpuSpeed <= 0) ||
5867 (sysinfo->fCpuSpeed < (szKeyValueDword >> 1))))
5868 sysinfo->fCpuSpeed = (Int_t)szKeyValueDword;
5869 RegCloseKey (hKey);
5870 }
5871 sysinfo->fCpuType.Remove(TString::kBoth, ' ');
5872 sysinfo->fModel.Remove(TString::kBoth, ' ');
5873}
5874
5875////////////////////////////////////////////////////////////////////////////////
5876/// Get CPU stat for Window. Use sampleTime to set the interval over which
5877/// the CPU load will be measured, in ms (default 1000).
5878
5879static