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