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