TWinNTSystem.cxx

Go to the documentation of this file.
00001 // @(#)root/winnt:$Id: TWinNTSystem.cxx 37110 2010-11-30 16:52:03Z pcanal $
00002 // Author: Fons Rademakers   15/09/95
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////////////
00013 //                                                                              //
00014 // TWinNTSystem                                                                 //
00015 //                                                                              //
00016 // Class providing an interface to the Windows NT/Windows 95 Operating Systems. //
00017 //                                                                              //
00018 //////////////////////////////////////////////////////////////////////////////////
00019 
00020 
00021 #ifdef HAVE_CONFIG
00022 #include "config.h"
00023 #endif
00024 
00025 #include "Windows4Root.h"
00026 #include "TWinNTSystem.h"
00027 #include "TROOT.h"
00028 #include "TError.h"
00029 #include "TOrdCollection.h"
00030 #include "TRegexp.h"
00031 #include "TException.h"
00032 #include "TEnv.h"
00033 #include "TSocket.h"
00034 #include "TApplication.h"
00035 #include "TWin32SplashThread.h"
00036 #include "Win32Constants.h"
00037 #include "TInterpreter.h"
00038 #include "TObjString.h"
00039 #include "TVirtualX.h"
00040 
00041 #include <sys/utime.h>
00042 #include <sys/timeb.h>
00043 #include <process.h>
00044 #include <io.h>
00045 #include <direct.h>
00046 #include <ctype.h>
00047 #include <float.h>
00048 #include <sys/stat.h>
00049 #include <signal.h>
00050 #include <stdio.h>
00051 #include <errno.h>
00052 #include <lm.h>
00053 #include <dbghelp.h>
00054 #include <Tlhelp32.h>
00055 #include <sstream>
00056 #include <iostream>
00057 #include <list>
00058 #include <shlobj.h>
00059 #include <conio.h>
00060 
00061 extern "C" {
00062    extern void Gl_setwidth(int width);
00063    extern int G__get_security_error();
00064    extern int G__genericerror(const char* msg);
00065    void *_ReturnAddress(void);
00066 }
00067 
00068 //////////////////// Windows TFdSet ////////////////////////////////////////////////
00069 class TFdSet {
00070 private:
00071    fd_set *fds_bits; // file descriptors (according MSDN maximum is 64)
00072 public:
00073    TFdSet() { fds_bits = new fd_set; fds_bits->fd_count = 0; }
00074    virtual ~TFdSet() { delete fds_bits; }
00075    void  Copy(TFdSet &fd) const { memcpy((void*)fd.fds_bits, fds_bits, sizeof(fd_set)); }
00076    TFdSet(const TFdSet& fd) { fd.Copy(*this); }
00077    TFdSet& operator=(const TFdSet& fd)  { fd.Copy(*this); return *this; }
00078    void  Zero() { fds_bits->fd_count = 0; }
00079    void  Set(Int_t fd)
00080    {
00081       if (fds_bits->fd_count < FD_SETSIZE-1) // protect out of bound access (64)
00082          fds_bits->fd_array[fds_bits->fd_count++] = (SOCKET)fd;
00083       else
00084          ::SysError("TFdSet::Set", "fd_count will exeed FD_SETSIZE");
00085    }
00086    void  Clr(Int_t fd)
00087    {
00088       int i;
00089       for (i=0; i<fds_bits->fd_count; i++) {
00090          if (fds_bits->fd_array[i]==(SOCKET)fd) {
00091             while (i<fds_bits->fd_count-1) {
00092                fds_bits->fd_array[i] = fds_bits->fd_array[i+1];
00093                i++;
00094             }
00095             fds_bits->fd_count--;
00096             break;
00097          }
00098       }
00099    }
00100    Int_t IsSet(Int_t fd) { return __WSAFDIsSet((SOCKET)fd, fds_bits); }
00101    Int_t *GetBits() { return fds_bits && fds_bits->fd_count ? (Int_t*)fds_bits : 0; }
00102    UInt_t GetCount() { return (UInt_t)fds_bits->fd_count; }
00103    Int_t GetFd(Int_t i) { return i<fds_bits->fd_count ? fds_bits->fd_array[i] : 0; }
00104 };
00105 
00106 namespace {
00107    const char *kProtocolName   = "tcp";
00108    typedef void (*SigHandler_t)(ESignals);
00109    static TWinNTSystem::ThreadMsgFunc_t gGUIThreadMsgFunc = 0;      // GUI thread message handler func
00110 
00111    static HANDLE gGlobalEvent;
00112    static HANDLE gTimerThreadHandle;
00113    typedef NET_API_STATUS (WINAPI *pfn1)(LPVOID);
00114    typedef NET_API_STATUS (WINAPI *pfn2)(LPCWSTR, LPCWSTR, DWORD, LPBYTE*);
00115    typedef NET_API_STATUS (WINAPI *pfn3)(LPCWSTR, LPCWSTR, DWORD, LPBYTE*,
00116                                        DWORD, LPDWORD, LPDWORD, PDWORD);
00117    typedef NET_API_STATUS (WINAPI *pfn4)(LPCWSTR, DWORD, LPBYTE*, DWORD, LPDWORD,
00118                                        LPDWORD, PDWORD);
00119    static pfn1 p2NetApiBufferFree;
00120    static pfn2 p2NetUserGetInfo;
00121    static pfn3 p2NetLocalGroupGetMembers;
00122    static pfn4 p2NetLocalGroupEnum;
00123 
00124    static struct signal_map {
00125       int code;
00126       SigHandler_t handler;
00127       char *signame;
00128    } signal_map[kMAXSIGNALS] = {   // the order of the signals should be identical
00129       -1 /*SIGBUS*/,   0, "bus error",    // to the one in SysEvtHandler.h
00130       SIGSEGV,  0, "segmentation violation",
00131       -1 /*SIGSYS*/,   0, "bad argument to system call",
00132       -1 /*SIGPIPE*/,  0, "write on a pipe with no one to read it",
00133       SIGILL,   0, "illegal instruction",
00134       -1 /*SIGQUIT*/,  0, "quit",
00135       SIGINT,   0, "interrupt",
00136       -1 /*SIGWINCH*/, 0, "window size change",
00137       -1 /*SIGALRM*/,  0, "alarm clock",
00138       -1 /*SIGCHLD*/,  0, "death of a child",
00139       -1 /*SIGURG*/,   0, "urgent data arrived on an I/O channel",
00140       SIGFPE,   0, "floating point exception",
00141       SIGTERM,  0, "termination signal",
00142       -1 /*SIGUSR1*/,  0, "user-defined signal 1",
00143       -1 /*SIGUSR2*/,  0, "user-defined signal 2"
00144    };
00145 
00146    ////// static functions providing interface to raw WinNT ////////////////////
00147 
00148    //---- RPC -------------------------------------------------------------------
00149    //*-* Error codes set by the Windows Sockets implementation are not made available
00150    //*-* via the errno variable. Additionally, for the getXbyY class of functions,
00151    //*-* error codes are NOT made available via the h_errno variable. Instead, error
00152    //*-* codes are accessed by using the WSAGetLastError . This function is provided
00153    //*-* in Windows Sockets as a precursor (and eventually an alias) for the Win32
00154    //*-* function GetLastError. This is intended to provide a reliable way for a thread
00155    //*-* in a multithreaded process to obtain per-thread error information.
00156 
00157    //______________________________________________________________________________
00158    static int WinNTRecv(int socket, void *buffer, int length, int flag)
00159    {
00160       // Receive exactly length bytes into buffer. Returns number of bytes
00161       // received. Returns -1 in case of error, -2 in case of MSG_OOB
00162       // and errno == EWOULDBLOCK, -3 in case of MSG_OOB and errno == EINVAL
00163       // and -4 in case of kNonBlock and errno == EWOULDBLOCK.
00164       // Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
00165 
00166       if (socket == -1) return -1;
00167       SOCKET sock = socket;
00168 
00169       int once = 0;
00170       if (flag == -1) {
00171          flag = 0;
00172          once = 1;
00173       }
00174       if (flag == MSG_PEEK) {
00175          once = 1;
00176       }
00177 
00178       int nrecv, n;
00179       char *buf = (char *)buffer;
00180 
00181       for (n = 0; n < length; n += nrecv) {
00182          if ((nrecv = ::recv(sock, buf+n, length-n, flag)) <= 0) {
00183             if (nrecv == 0) {
00184                break;        // EOF
00185             }
00186             if (flag == MSG_OOB) {
00187                if (::WSAGetLastError() == WSAEWOULDBLOCK) {
00188                   return -2;
00189                } else if (::WSAGetLastError() == WSAEINVAL) {
00190                   return -3;
00191                }
00192             }
00193             if (::WSAGetLastError() == WSAEWOULDBLOCK) {
00194                return -4;
00195             } else {
00196                if (::WSAGetLastError() != WSAEINTR)
00197                   ::SysError("TWinNTSystem::WinNTRecv", "recv");
00198                if (::WSAGetLastError() == EPIPE ||
00199                   ::WSAGetLastError() == WSAECONNRESET)
00200                   return -5;
00201                else
00202                   return -1;
00203             }
00204          }
00205          if (once) {
00206             return nrecv;
00207          }
00208       }
00209       return n;
00210    }
00211 
00212    //______________________________________________________________________________
00213    static int WinNTSend(int socket, const void *buffer, int length, int flag)
00214    {
00215       // Send exactly length bytes from buffer. Returns -1 in case of error,
00216       // otherwise number of sent bytes. Returns -4 in case of kNoBlock and
00217       // errno == EWOULDBLOCK. Returns -5 if pipe broken or reset by peer
00218       // (EPIPE || ECONNRESET).
00219 
00220       if (socket < 0) return -1;
00221       SOCKET sock = socket;
00222 
00223       int once = 0;
00224       if (flag == -1) {
00225          flag = 0;
00226          once = 1;
00227       }
00228 
00229       int nsent, n;
00230       const char *buf = (const char *)buffer;
00231 
00232       for (n = 0; n < length; n += nsent) {
00233          if ((nsent = ::send(sock, buf+n, length-n, flag)) <= 0) {
00234             if (nsent == 0) {
00235                break;
00236             }
00237             if (::WSAGetLastError() == WSAEWOULDBLOCK) {
00238                return -4;
00239             } else {
00240                if (::WSAGetLastError() != WSAEINTR)
00241                   ::SysError("TWinNTSystem::WinNTSend", "send");
00242                if (::WSAGetLastError() == EPIPE ||
00243                   ::WSAGetLastError() == WSAECONNRESET)
00244                   return -5;
00245                else
00246                   return -1;
00247             }
00248          }
00249          if (once) {
00250             return nsent;
00251          }
00252       }
00253       return n;
00254    }
00255 
00256    //______________________________________________________________________________
00257    static int WinNTSelect(TFdSet *readready, TFdSet *writeready, Long_t timeout)
00258    {
00259       // Wait for events on the file descriptors specified in the readready and
00260       // writeready masks or for timeout (in milliseconds) to occur.
00261 
00262       int retcode;
00263       fd_set* rbits = readready ? (fd_set*)readready->GetBits() : 0;
00264       fd_set* wbits = writeready ? (fd_set*)writeready->GetBits() : 0;
00265 
00266       if (timeout >= 0) {
00267          timeval tv;
00268          tv.tv_sec  = timeout / 1000;
00269          tv.tv_usec = (timeout % 1000) * 1000;
00270 
00271          retcode = ::select(0, rbits, wbits, 0, &tv);
00272       } else {
00273          retcode = ::select(0, rbits, wbits, 0, 0);
00274       }
00275 
00276       if (retcode == SOCKET_ERROR) {
00277          int errcode = ::WSAGetLastError();
00278 
00279          // if file descriptor is not a socket, assume it is the pipe used
00280          // by TXSocket
00281          if (errcode == WSAENOTSOCK) {
00282             struct __stat64 buf;
00283             int result = _fstat64( readready->GetFd(0), &buf );
00284             if ( result == 0 ) {
00285                if (buf.st_size > 0)
00286                   return 1;
00287             }
00288             // yield execution to another thread that is ready to run
00289             // if no other thread is ready, sleep 1 ms before to return
00290             if (gGlobalEvent) {
00291                ::WaitForSingleObject(gGlobalEvent, 1);
00292                ::ResetEvent(gGlobalEvent);
00293             }
00294             return 0;
00295          }
00296 
00297          if ( errcode == WSAEINTR) {
00298             TSystem::ResetErrno();  // errno is not self reseting
00299             return -2;
00300          }
00301          if (errcode == EBADF) {
00302             return -3;
00303          }
00304          return -1;
00305       }
00306       return retcode;
00307    }
00308 
00309    //______________________________________________________________________________
00310    static const char *DynamicPath(const char *newpath = 0, Bool_t reset = kFALSE)
00311    {
00312       // Get shared library search path.
00313 
00314       static TString dynpath;
00315 
00316       if (reset || newpath) {
00317          dynpath = "";
00318       }
00319       if (newpath) {
00320 
00321          dynpath = newpath;
00322 
00323       } else if (dynpath == "") {
00324          TString rdynpath = gEnv->GetValue("Root.DynamicPath", (char*)0);
00325          rdynpath.ReplaceAll("; ", ";");  // in case DynamicPath was extended
00326          if (rdynpath == "") {
00327 #ifdef ROOTBINDIR
00328             rdynpath = ".;"; rdynpath += ROOTBINDIR;
00329 #else
00330             rdynpath = ".;"; rdynpath += gRootDir; rdynpath += "/bin";
00331 #endif
00332          }
00333          TString path = gSystem->Getenv("PATH");
00334          if (path == "")
00335             dynpath = rdynpath;
00336          else {
00337             dynpath = path; dynpath += ";"; dynpath += rdynpath;
00338          }
00339 
00340       }
00341 #ifdef ROOTLIBDIR
00342       if (!dynpath.Contains(ROOTLIBDIR)) {
00343          dynpath += ";"; dynpath += ROOTLIBDIR;
00344       }
00345 #else
00346       if (!dynpath.Contains(TString::Format("%s/lib", gRootDir))) {
00347          dynpath += ";"; dynpath += gRootDir; dynpath += "/lib";
00348       }
00349 #endif
00350 
00351 #ifdef CINTINCDIR
00352       TString cintinc(TString::Format("%s/cint/stl",CINTINCDIR));
00353 #else
00354       TString cintinc(TString::Format("%s/cint/cint/stl",gRootDir));
00355 #endif
00356       if (!dynpath.Contains( cintinc)) {
00357          dynpath += ";"; dynpath += cintinc;
00358       }
00359       return dynpath;
00360    }
00361 
00362    //______________________________________________________________________________
00363    static void sighandler(int sig)
00364    {
00365       // Call the signal handler associated with the signal.
00366 
00367       for (int i = 0; i < kMAXSIGNALS; i++) {
00368          if (signal_map[i].code == sig) {
00369             (*signal_map[i].handler)((ESignals)i);
00370             return;
00371          }
00372       }
00373    }
00374 
00375    //______________________________________________________________________________
00376    static void WinNTSignal(ESignals sig, SigHandler_t handler)
00377    {
00378       // Set a signal handler for a signal.
00379       signal_map[sig].handler = handler;
00380       if (signal_map[sig].code != -1)
00381          (SigHandler_t)signal(signal_map[sig].code, sighandler);
00382    }
00383 
00384    //______________________________________________________________________________
00385    static char *WinNTSigname(ESignals sig)
00386    {
00387       // Return the signal name associated with a signal.
00388 
00389       return signal_map[sig].signame;
00390    }
00391 
00392    //______________________________________________________________________________
00393    static BOOL ConsoleSigHandler(DWORD sig)
00394    {
00395       // WinNT signal handler.
00396 
00397       switch (sig) {
00398          case CTRL_C_EVENT:
00399             if (!G__get_security_error()) {
00400                G__genericerror("\n *** Break *** keyboard interrupt");
00401             } else {
00402                Break("TInterruptHandler::Notify", "keyboard interrupt");
00403                if (TROOT::Initialized()) {
00404                   gInterpreter->RewindDictionary();
00405                }
00406             }
00407             return kTRUE;
00408          case CTRL_BREAK_EVENT:
00409          case CTRL_LOGOFF_EVENT:
00410          case CTRL_SHUTDOWN_EVENT:
00411          case CTRL_CLOSE_EVENT:
00412          default:
00413             printf("\n *** Break *** keyboard interrupt - ROOT is terminated\n");
00414             gSystem->Exit(-1);
00415             return kTRUE;
00416       }
00417    }
00418 
00419    static CONTEXT *fgXcptContext = 0;
00420    //______________________________________________________________________________
00421    static void SigHandler(ESignals sig)
00422    {
00423       if (gSystem) {
00424          gSystem->StackTrace();
00425          if (TROOT::Initialized()) {
00426             ::Throw(sig);
00427          }
00428          gSystem->Abort(-1);
00429       }
00430    }
00431 
00432    //______________________________________________________________________________
00433    LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS pXcp)
00434    {
00435       // Function that's called when an unhandled exception occurs.
00436       // Produces a stack trace, and lets the system deal with it
00437       // as if it was an unhandled excecption (usually ::abort)
00438       fgXcptContext = pXcp->ContextRecord;
00439       gSystem->StackTrace();
00440       return EXCEPTION_CONTINUE_SEARCH;
00441    }
00442 
00443 
00444 #pragma intrinsic(_ReturnAddress)
00445 #pragma auto_inline(off)
00446    DWORD_PTR GetProgramCounter()
00447    {
00448       // Returns the current program counter.
00449       return (DWORD_PTR)_ReturnAddress();
00450    }
00451 #pragma auto_inline(on)
00452 
00453    //______________________________________________________________________________
00454    static DWORD WINAPI GUIThreadMessageProcessingLoop(void *p)
00455    {
00456       // Message processing loop for the TGWin32 related GUI
00457       // thread for processing windows messages (aka Main/Server thread).
00458       // We need to start the thread outside the TGWin32 / GUI related
00459       // dll, because starting threads at DLL init time does not work.
00460       // Indead, we start an ideling thread at binary startup, and only
00461       // call the "real" message provcessing function
00462       // TGWin32::GUIThreadMessageFunc() once gVirtualX comes up.
00463 
00464       MSG msg;
00465 
00466       // force to create message queue
00467       ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
00468 
00469       Int_t erret = 0;
00470       Bool_t endLoop = kFALSE;
00471       while (!endLoop) {
00472          if (gGlobalEvent) ::SetEvent(gGlobalEvent);
00473          erret = ::GetMessage(&msg, NULL, NULL, NULL);
00474          if (erret <= 0) endLoop = kTRUE;
00475          if (gGUIThreadMsgFunc)
00476             endLoop = (*gGUIThreadMsgFunc)(&msg);
00477       }
00478 
00479       gVirtualX->CloseDisplay();
00480 
00481       // exit thread
00482       if (erret == -1) {
00483          erret = ::GetLastError();
00484          Error("MsgLoop", "Error in GetMessage");
00485          ::ExitThread(-1);
00486       } else {
00487          ::ExitThread(0);
00488       }
00489       return 0;
00490    }
00491 
00492    //=========================================================================
00493    // Load IMAGEHLP.DLL and get the address of functions in it that we'll use
00494    // by Microsoft, from http://www.microsoft.com/msj/0597/hoodtextfigs.htm#fig1
00495    //=========================================================================
00496    // Make typedefs for some IMAGEHLP.DLL functions so that we can use them
00497    // with GetProcAddress
00498    typedef BOOL (__stdcall *SYMINITIALIZEPROC)( HANDLE, LPSTR, BOOL );
00499    typedef BOOL (__stdcall *SYMCLEANUPPROC)( HANDLE );
00500    typedef BOOL (__stdcall *STACKWALK64PROC)
00501                ( DWORD, HANDLE, HANDLE, LPSTACKFRAME64, LPVOID,
00502                PREAD_PROCESS_MEMORY_ROUTINE,PFUNCTION_TABLE_ACCESS_ROUTINE,
00503                PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE );
00504    typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESS64PROC)( HANDLE, DWORD64 );
00505    typedef DWORD (__stdcall *SYMGETMODULEBASE64PROC)( HANDLE, DWORD64 );
00506    typedef BOOL (__stdcall *SYMGETMODULEINFO64PROC)(HANDLE, DWORD64, PIMAGEHLP_MODULE64);
00507    typedef BOOL (__stdcall *SYMGETSYMFROMADDR64PROC)( HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
00508    typedef BOOL (__stdcall *SYMGETLINEFROMADDR64PROC)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
00509    typedef DWORD (__stdcall *UNDECORATESYMBOLNAMEPROC)(PCSTR, PSTR, DWORD, DWORD);
00510 
00511 
00512    static SYMINITIALIZEPROC _SymInitialize = 0;
00513    static SYMCLEANUPPROC _SymCleanup = 0;
00514    static STACKWALK64PROC _StackWalk64 = 0;
00515    static SYMFUNCTIONTABLEACCESS64PROC _SymFunctionTableAccess64 = 0;
00516    static SYMGETMODULEBASE64PROC _SymGetModuleBase64 = 0;
00517    static SYMGETMODULEINFO64PROC _SymGetModuleInfo64 = 0;
00518    static SYMGETSYMFROMADDR64PROC _SymGetSymFromAddr64 = 0;
00519    static SYMGETLINEFROMADDR64PROC _SymGetLineFromAddr64 = 0;
00520    static UNDECORATESYMBOLNAMEPROC _UnDecorateSymbolName = 0;
00521 
00522    BOOL InitImagehlpFunctions()
00523    {
00524       // Fetches function addresses from IMAGEHLP.DLL at run-time, so we
00525       // don't need to link against its import library. These functions
00526       // are used in StackTrace; if they cannot be found (e.g. because
00527       // IMAGEHLP.DLL doesn't exist or has the wrong version) we cannot
00528       // produce a stack trace.
00529 
00530       HMODULE hModImagehlp = LoadLibrary( "IMAGEHLP.DLL" );
00531       if (!hModImagehlp)
00532          return FALSE;
00533 
00534       _SymInitialize = (SYMINITIALIZEPROC) GetProcAddress( hModImagehlp, "SymInitialize" );
00535       if (!_SymInitialize)
00536          return FALSE;
00537 
00538       _SymCleanup = (SYMCLEANUPPROC) GetProcAddress( hModImagehlp, "SymCleanup" );
00539       if (!_SymCleanup)
00540          return FALSE;
00541 
00542       _StackWalk64 = (STACKWALK64PROC) GetProcAddress( hModImagehlp, "StackWalk64" );
00543       if (!_StackWalk64)
00544          return FALSE;
00545 
00546       _SymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESS64PROC) GetProcAddress(hModImagehlp, "SymFunctionTableAccess64" );
00547       if (!_SymFunctionTableAccess64)
00548          return FALSE;
00549 
00550       _SymGetModuleBase64=(SYMGETMODULEBASE64PROC)GetProcAddress(hModImagehlp, "SymGetModuleBase64");
00551       if (!_SymGetModuleBase64)
00552          return FALSE;
00553 
00554       _SymGetModuleInfo64=(SYMGETMODULEINFO64PROC)GetProcAddress(hModImagehlp, "SymGetModuleInfo64");
00555       if (!_SymGetModuleInfo64)
00556          return FALSE;
00557 
00558       _SymGetSymFromAddr64=(SYMGETSYMFROMADDR64PROC)GetProcAddress(hModImagehlp, "SymGetSymFromAddr64");
00559       if (!_SymGetSymFromAddr64)
00560          return FALSE;
00561 
00562       _SymGetLineFromAddr64=(SYMGETLINEFROMADDR64PROC)GetProcAddress(hModImagehlp, "SymGetLineFromAddr64");
00563       if (!_SymGetLineFromAddr64)
00564          return FALSE;
00565 
00566       _UnDecorateSymbolName=(UNDECORATESYMBOLNAMEPROC)GetProcAddress(hModImagehlp, "UnDecorateSymbolName");
00567       if (!_UnDecorateSymbolName)
00568          return FALSE;
00569 
00570       if (!_SymInitialize(GetCurrentProcess(), 0, TRUE ))
00571          return FALSE;
00572 
00573       return TRUE;
00574    }
00575 
00576    // stack trace helpers getModuleName, getFunctionName by
00577    /**************************************************************************
00578    * VRS - The Virtual Rendering System
00579    * Copyright (C) 2000-2004 Computer Graphics Systems Group at the
00580    * Hasso-Plattner-Institute (HPI), Potsdam, Germany.
00581    * This library is free software; you can redistribute it and/or modify it
00582    * under the terms of the GNU Lesser General Public License as published by
00583    * the Free Software Foundation; either version 2.1 of the License, or
00584    * (at your option) any later version.
00585    ***************************************************************************/
00586    std::string GetModuleName(DWORD64 address)
00587    {
00588       // Return the name of the module that contains the function at address.
00589       // Used by StackTrace.
00590       std::ostringstream out;
00591       HANDLE process = ::GetCurrentProcess();
00592 
00593       DWORD lineDisplacement = 0;
00594       IMAGEHLP_LINE64 line;
00595       ::ZeroMemory(&line, sizeof(line));
00596       line.SizeOfStruct = sizeof(line);
00597       if(_SymGetLineFromAddr64(process, address, &lineDisplacement, &line)) {
00598             out << line.FileName << "(" << line.LineNumber << "): ";
00599       } else {
00600             IMAGEHLP_MODULE64 module;
00601             ::ZeroMemory(&module, sizeof(module));
00602             module.SizeOfStruct = sizeof(module);
00603             if(_SymGetModuleInfo64(process, address, &module)) {
00604                out << module.ModuleName << "!";
00605             } else {
00606                out << "0x" << std::hex << address << std::dec << " ";
00607             }
00608       }
00609 
00610       return out.str();
00611    }
00612 
00613    std::string GetFunctionName(DWORD64 address)
00614    {
00615       // Return the name of the function at address.
00616       // Used by StackTrace.
00617       DWORD64 symbolDisplacement = 0;
00618       HANDLE process = ::GetCurrentProcess();
00619 
00620       const unsigned int SYMBOL_BUFFER_SIZE = 8192;
00621       char symbolBuffer[SYMBOL_BUFFER_SIZE];
00622       PIMAGEHLP_SYMBOL64 symbol = reinterpret_cast<PIMAGEHLP_SYMBOL64>(symbolBuffer);
00623       ::ZeroMemory(symbol, SYMBOL_BUFFER_SIZE);
00624       symbol->SizeOfStruct = SYMBOL_BUFFER_SIZE;
00625       symbol->MaxNameLength = SYMBOL_BUFFER_SIZE - sizeof(IMAGEHLP_SYMBOL64);
00626 
00627       if(_SymGetSymFromAddr64(process, address, &symbolDisplacement, symbol)) {
00628             // Make the symbol readable for humans
00629             const unsigned int NAME_SIZE = 8192;
00630             char name[NAME_SIZE];
00631             _UnDecorateSymbolName(
00632                symbol->Name,
00633                name,
00634                NAME_SIZE,
00635                UNDNAME_COMPLETE             |
00636                UNDNAME_NO_THISTYPE          |
00637                UNDNAME_NO_SPECIAL_SYMS      |
00638                UNDNAME_NO_MEMBER_TYPE       |
00639                UNDNAME_NO_MS_KEYWORDS       |
00640                UNDNAME_NO_ACCESS_SPECIFIERS
00641             );
00642 
00643             std::string result;
00644             result += name;
00645             result += "()";
00646             return result;
00647       } else {
00648             return "??";
00649       }
00650    }
00651 
00652    ////// Shortcuts helper functions IsShortcut and ResolveShortCut ///////////
00653 
00654    //__________________________________________________________________________
00655    static BOOL IsShortcut(const char *filename)
00656    {
00657       // Validates if a file name has extension '.lnk'. Returns true if file
00658       // name have extension same as Window's shortcut file (.lnk).
00659 
00660       //File extension for the Window's shortcuts (.lnk)
00661       const char *extLnk = ".lnk";
00662       if (filename != NULL) {
00663          //Validate extension
00664          TString strfilename(filename);
00665          if (strfilename.EndsWith(extLnk))
00666             return TRUE;
00667       }
00668       return FALSE;
00669    }
00670 
00671    //__________________________________________________________________________
00672    static BOOL ResolveShortCut(LPCSTR pszShortcutFile, char *pszPath, int maxbuf)
00673    {
00674       // Resolve a ShellLink (i.e. c:\path\shortcut.lnk) to a real path.
00675 
00676       HRESULT hres;
00677       IShellLink* psl;
00678       char szGotPath[MAX_PATH];
00679       WIN32_FIND_DATA wfd;
00680 
00681       *pszPath = 0;   // assume failure
00682 
00683       // Make typedefs for some ole32.dll functions so that we can use them
00684       // with GetProcAddress
00685       typedef HRESULT (__stdcall *COINITIALIZEPROC)( LPVOID );
00686       static COINITIALIZEPROC _CoInitialize = 0;
00687       typedef void (__stdcall *COUNINITIALIZEPROC)( void );
00688       static COUNINITIALIZEPROC _CoUninitialize = 0;
00689       typedef HRESULT (__stdcall *COCREATEINSTANCEPROC)( REFCLSID, LPUNKNOWN,
00690                        DWORD, REFIID, LPVOID );
00691       static COCREATEINSTANCEPROC _CoCreateInstance = 0;
00692 
00693       HMODULE hModImagehlp = LoadLibrary( "ole32.dll" );
00694       if (!hModImagehlp)
00695          return FALSE;
00696 
00697       _CoInitialize = (COINITIALIZEPROC) GetProcAddress( hModImagehlp, "CoInitialize" );
00698       if (!_CoInitialize)
00699          return FALSE;
00700       _CoUninitialize = (COUNINITIALIZEPROC) GetProcAddress( hModImagehlp, "CoUninitialize");
00701       if (!_CoUninitialize)
00702          return FALSE;
00703       _CoCreateInstance = (COCREATEINSTANCEPROC) GetProcAddress( hModImagehlp, "CoCreateInstance" );
00704       if (!_CoCreateInstance)
00705          return FALSE;
00706 
00707       _CoInitialize(NULL);
00708 
00709       hres = _CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
00710                                IID_IShellLink, (void **) &psl);
00711       if (SUCCEEDED(hres)) {
00712          IPersistFile* ppf;
00713 
00714          hres = psl->QueryInterface(IID_IPersistFile, (void **) &ppf);
00715          if (SUCCEEDED(hres)) {
00716             WCHAR wsz[MAX_PATH];
00717             MultiByteToWideChar(CP_ACP, 0, pszShortcutFile, -1, wsz, MAX_PATH);
00718 
00719             hres = ppf->Load(wsz, STGM_READ);
00720             if (SUCCEEDED(hres)) {
00721                hres = psl->Resolve(HWND_DESKTOP, SLR_ANY_MATCH);
00722                if (SUCCEEDED(hres)) {
00723                   strlcpy(szGotPath, pszShortcutFile,MAX_PATH);
00724                   hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATA *)&wfd,
00725                                       SLGP_UNCPRIORITY | SLGP_RAWPATH);
00726                   strlcpy(pszPath,szGotPath, maxbuf);
00727                   if (maxbuf) pszPath[maxbuf-1] = 0;
00728                }
00729             }
00730             ppf->Release();
00731          }
00732          psl->Release();
00733       }
00734       _CoUninitialize();
00735 
00736       return SUCCEEDED(hres);
00737    }
00738 
00739    void UpdateRegistry(TWinNTSystem* sys, char* buf /* size of buffer: MAX_MODULE_NAME32 + 1 */) {
00740       // register ROOT as the .root file handler:
00741       GetModuleFileName(0, buf, MAX_MODULE_NAME32 + 1);
00742       if (strcmp(sys->TWinNTSystem::BaseName(buf), "root.exe"))
00743          return;
00744       HKEY regCUS;
00745       if (!::RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &regCUS) == ERROR_SUCCESS)
00746          return;
00747       HKEY regCUSC;
00748       if (!::RegOpenKeyEx(regCUS, "Classes", 0, KEY_READ, &regCUSC) == ERROR_SUCCESS) {
00749          ::RegCloseKey(regCUS);
00750          return;
00751       }
00752 
00753       HKEY regROOT;
00754       bool regROOTwrite = false;
00755       TString iconloc(buf);
00756       iconloc += ",-101";
00757 
00758       if (::RegOpenKeyEx(regCUSC, "ROOTDEV.ROOT", 0, KEY_READ, &regROOT) != ERROR_SUCCESS) {
00759          ::RegCloseKey(regCUSC);
00760          if (::RegOpenKeyEx(regCUS, "Classes", 0, KEY_READ | KEY_WRITE, &regCUSC) == ERROR_SUCCESS &&
00761             ::RegCreateKeyEx(regCUSC, "ROOTDEV.ROOT", 0, NULL, 0, KEY_READ | KEY_WRITE,
00762             NULL, &regROOT, NULL) == ERROR_SUCCESS) {
00763             regROOTwrite = true;
00764          }
00765       } else {
00766          HKEY regROOTIcon;
00767          if (::RegOpenKeyEx(regROOT, "DefaultIcon", 0, KEY_READ, &regROOTIcon) == ERROR_SUCCESS) {
00768             char bufIconLoc[1024];
00769             DWORD dwType;
00770             DWORD dwSize = sizeof(bufIconLoc);
00771 
00772             if (::RegQueryValueEx(regROOTIcon, NULL, NULL, &dwType, (BYTE*)bufIconLoc, &dwSize) == ERROR_SUCCESS)
00773                regROOTwrite = (iconloc != bufIconLoc);
00774             else
00775                regROOTwrite = true;
00776             ::RegCloseKey(regROOTIcon);
00777          } else
00778             regROOTwrite = true;
00779          if (regROOTwrite) {
00780             // re-open for writing
00781             ::RegCloseKey(regCUSC);
00782             ::RegCloseKey(regROOT);
00783             if (::RegOpenKeyEx(regCUS, "Classes", 0, KEY_READ | KEY_WRITE, &regCUSC) != ERROR_SUCCESS) {
00784                // error opening key for writing:
00785                regROOTwrite = false;
00786             } else {
00787                if (::RegOpenKeyEx(regCUSC, "ROOTDEV.ROOT", 0, KEY_WRITE, &regROOT) != ERROR_SUCCESS) {
00788                   // error opening key for writing:
00789                   regROOTwrite = false;
00790                   ::RegCloseKey(regCUSC);
00791                }
00792             }
00793          }
00794       }
00795 
00796       // determine the fileopen.C file path:
00797       TString fileopen;
00798 #ifndef ROOT_PREFIX
00799       fileopen += sys->TWinNTSystem::DriveName(buf);
00800       fileopen += ":";
00801       fileopen += sys->TWinNTSystem::DirName(sys->TWinNTSystem::DirName(buf));
00802       fileopen += "\\macros";
00803 #else
00804       fileopen += ROOTMACRODIR;
00805 #endif
00806       fileopen += "\\fileopen.C";
00807 
00808       if (regROOTwrite) {
00809          // only write to registry if fileopen.C is readable
00810          regROOTwrite = (::_access(fileopen, kReadPermission) == 0);
00811       }
00812 
00813       if (!regROOTwrite) {
00814          ::RegCloseKey(regROOT);
00815          ::RegCloseKey(regCUSC);
00816          ::RegCloseKey(regCUS);
00817          return;
00818       }
00819 
00820       static const char apptitle[] = "ROOT data file";
00821       ::RegSetValueEx(regROOT, NULL, 0, REG_SZ, (BYTE*)apptitle, sizeof(apptitle));
00822       DWORD editflags = /*FTA_OpenIsSafe*/ 0x00010000; // trust downloaded files
00823       ::RegSetValueEx(regROOT, "EditFlags", 0, REG_DWORD, (BYTE*)&editflags, sizeof(editflags));
00824 
00825       HKEY regROOTIcon;
00826       if (::RegCreateKeyEx(regROOT, "DefaultIcon", 0, NULL, 0, KEY_READ | KEY_WRITE,
00827                            NULL, &regROOTIcon, NULL) == ERROR_SUCCESS) {
00828          TString iconloc(buf);
00829          iconloc += ",-101";
00830          ::RegSetValueEx(regROOTIcon, NULL, 0, REG_SZ, (BYTE*)iconloc.Data(), iconloc.Length() + 1);
00831          ::RegCloseKey(regROOTIcon);
00832       }
00833 
00834       // "open" verb
00835       HKEY regROOTshell;
00836       if (::RegCreateKeyEx(regROOT, "shell", 0, NULL, 0, KEY_READ | KEY_WRITE,
00837                            NULL, &regROOTshell, NULL) == ERROR_SUCCESS) {
00838          HKEY regShellOpen;
00839          if (::RegCreateKeyEx(regROOTshell, "open", 0, NULL, 0, KEY_READ | KEY_WRITE,
00840                               NULL, &regShellOpen, NULL) == ERROR_SUCCESS) {
00841             HKEY regShellOpenCmd;
00842             if (::RegCreateKeyEx(regShellOpen, "command", 0, NULL, 0, KEY_READ | KEY_WRITE,
00843                                  NULL, &regShellOpenCmd, NULL) == ERROR_SUCCESS) {
00844                TString cmd(buf);
00845                cmd += " -l \"%1\" \"";
00846                cmd += fileopen;
00847                cmd += "\"";
00848                ::RegSetValueEx(regShellOpenCmd, NULL, 0, REG_SZ, (BYTE*)cmd.Data(), cmd.Length() + 1);
00849                ::RegCloseKey(regShellOpenCmd);
00850             }
00851             ::RegCloseKey(regShellOpen);
00852          }
00853          ::RegCloseKey(regROOTshell);
00854       }
00855       ::RegCloseKey(regROOT);
00856 
00857       if (::RegCreateKeyEx(regCUSC, ".root", 0, NULL, 0, KEY_READ | KEY_WRITE,
00858                            NULL, &regROOT, NULL) == ERROR_SUCCESS) {
00859          static const char appname[] = "ROOTDEV.ROOT";
00860          ::RegSetValueEx(regROOT, NULL, 0, REG_SZ, (BYTE*)appname, sizeof(appname));
00861       }
00862       ::RegCloseKey(regCUSC);
00863       ::RegCloseKey(regCUS);
00864 
00865       // tell Windows that the association was changed
00866       ::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
00867    } // UpdateRegistry()
00868 
00869    //______________________________________________________________________________
00870    bool NeedSplash()
00871    {
00872       // return kFALSE if option "-l" was specified as main programm command arg
00873 
00874       static bool once = true;
00875       if (!once || gROOT->IsBatch() || !gApplication) return false;
00876       TString arg = gSystem->BaseName(gApplication->Argv(0));
00877       if ((arg != "root") && (arg != "rootn") &&
00878           (arg != "root.exe") && (arg != "rootn.exe")) return false;
00879       for(int i=1; i<gApplication->Argc(); i++) {
00880          arg = gApplication->Argv(i);
00881          arg.Strip(TString::kBoth);
00882          if ((arg == "-l") || (arg == "-b")) {
00883             return false;
00884          }
00885       }
00886       if (once) {
00887          once = false;
00888          return true;
00889       }
00890       return false;
00891    }
00892 
00893    //______________________________________________________________________________
00894    static void SetConsoleWindowName()
00895    {
00896 
00897       char pszNewWindowTitle[1024]; // contains fabricated WindowTitle
00898       char pszOldWindowTitle[1024]; // contains original WindowTitle
00899       HANDLE hStdout;
00900       CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
00901 
00902       if (!::GetConsoleTitle(pszOldWindowTitle, 1024))
00903          return;
00904       // format a "unique" NewWindowTitle
00905       wsprintf(pszNewWindowTitle,"%d/%d", ::GetTickCount(), ::GetCurrentProcessId());
00906       // change current window title
00907       if (!::SetConsoleTitle(pszNewWindowTitle))
00908          return;
00909       // ensure window title has been updated
00910       ::Sleep(40);
00911       // look for NewWindowTitle
00912       gConsoleWindow = (ULong_t)::FindWindow(0, pszNewWindowTitle);
00913       if (gConsoleWindow) {
00914          // restore original window title
00915          ::ShowWindow((HWND)gConsoleWindow, SW_RESTORE);
00916          //::SetForegroundWindow((HWND)gConsoleWindow);
00917          ::SetConsoleTitle("ROOT session");
00918       }
00919       hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
00920       ::SetConsoleMode(hStdout, ENABLE_PROCESSED_OUTPUT |
00921                        ENABLE_WRAP_AT_EOL_OUTPUT);
00922       if (!::GetConsoleScreenBufferInfo(hStdout, &csbiInfo))
00923          return;
00924       Gl_setwidth(csbiInfo.dwMaximumWindowSize.X);
00925    }
00926 
00927 } // end unnamed namespace
00928 
00929 
00930 ///////////////////////////////////////////////////////////////////////////////
00931 ClassImp(TWinNTSystem)
00932 
00933 ULong_t gConsoleWindow = 0;
00934 
00935 //______________________________________________________________________________
00936 Bool_t TWinNTSystem::HandleConsoleEvent()
00937 {
00938    //
00939 
00940    TSignalHandler *sh;
00941    TIter next(fSignalHandler);
00942    ESignals s;
00943 
00944    while (sh = (TSignalHandler*)next()) {
00945       s = sh->GetSignal();
00946       if (s == kSigInterrupt) {
00947          sh->Notify();
00948          Throw(SIGINT);
00949          return kTRUE;
00950       }
00951    }
00952    return kFALSE;
00953 }
00954 
00955 //______________________________________________________________________________
00956 TWinNTSystem::TWinNTSystem() : TSystem("WinNT", "WinNT System"),
00957 fGUIThreadHandle(0), fGUIThreadId(0)
00958 {
00959    // ctor
00960 
00961    fhProcess = ::GetCurrentProcess();
00962    fDirNameBuffer = 0;
00963 
00964    WSADATA WSAData;
00965    int initwinsock = 0;
00966 
00967    if (initwinsock = ::WSAStartup(MAKEWORD(2, 0), &WSAData)) {
00968       Error("TWinNTSystem()","Starting sockets failed");
00969    }
00970 
00971    // use ::MessageBeep by default for TWinNTSystem
00972    fBeepDuration = 1;
00973    fBeepFreq     = 0;
00974    if (gEnv) {
00975       fBeepDuration = gEnv->GetValue("Root.System.BeepDuration", 1);
00976       fBeepFreq     = gEnv->GetValue("Root.System.BeepFreq", 0);
00977    }
00978 
00979    char *buf = new char[MAX_MODULE_NAME32 + 1];
00980 
00981 #ifndef ROOTPREFIX
00982    // set ROOTSYS
00983    HMODULE hModCore = ::GetModuleHandle("libCore.dll");
00984    if (hModCore) {
00985       ::GetModuleFileName(hModCore, buf, MAX_MODULE_NAME32 + 1);
00986       char* pLibName = strstr(buf, "libCore.dll");
00987       if (pLibName) {
00988          --pLibName; // skip trailing \\ or /
00989          while (--pLibName >= buf && *pLibName != '\\' && *pLibName != '/');
00990          *pLibName = 0;
00991          if (buf[0])
00992             Setenv("ROOTSYS", buf);
00993       }
00994    }
00995 #endif
00996 
00997    UpdateRegistry(this, buf);
00998 
00999    delete [] buf;
01000 }
01001 
01002 //______________________________________________________________________________
01003 TWinNTSystem::~TWinNTSystem()
01004 {
01005    // dtor
01006 
01007    // Revert back the accuracy of Sleep() without needing to link to winmm.lib
01008    typedef UINT (WINAPI* LPTIMEENDPERIOD)( UINT uPeriod );
01009    HINSTANCE hInstWinMM = LoadLibrary( "winmm.dll" );
01010    if( hInstWinMM ) {
01011       LPTIMEENDPERIOD pTimeEndPeriod = (LPTIMEENDPERIOD)GetProcAddress( hInstWinMM, "timeEndPeriod" );
01012       if( NULL != pTimeEndPeriod )
01013          pTimeEndPeriod(1);
01014       FreeLibrary(hInstWinMM);
01015    }
01016    // Clean up the WinSocket connectios
01017    ::WSACleanup();
01018 
01019    if (fDirNameBuffer) {
01020       delete [] fDirNameBuffer;
01021       fDirNameBuffer = 0;
01022    }
01023 
01024    if (gGlobalEvent) {
01025       ::ResetEvent(gGlobalEvent);
01026       ::CloseHandle(gGlobalEvent);
01027       gGlobalEvent = 0;
01028    }
01029    if (gTimerThreadHandle) {
01030       ::TerminateThread(gTimerThreadHandle, 0);
01031       ::CloseHandle(gTimerThreadHandle);
01032    }
01033 }
01034 
01035 //______________________________________________________________________________
01036 Bool_t TWinNTSystem::Init()
01037 {
01038    // Initialize WinNT system interface.
01039 
01040    const char *dir = 0;
01041 
01042    if (TSystem::Init()) {
01043       return kTRUE;
01044    }
01045 
01046    fReadmask = new TFdSet;
01047    fWritemask = new TFdSet;
01048    fReadready = new TFdSet;
01049    fWriteready = new TFdSet;
01050    fSignals = new TFdSet;
01051    fNfd    = 0;
01052 
01053    //--- install default handlers
01054    // Actually: don't. If we want a stack trace we need a context for the
01055    // signal. Signals don't have one. If we don't handle them, Windows will
01056    // raise an exception, which has a context, and which is handled by
01057    // ExceptionFilter.
01058    /*
01059    WinNTSignal(kSigChild,                 SigHandler);
01060    WinNTSignal(kSigBus,                   SigHandler);
01061    WinNTSignal(kSigSegmentationViolation, SigHandler);
01062    WinNTSignal(kSigIllegalInstruction,    SigHandler);
01063    WinNTSignal(kSigSystem,                SigHandler);
01064    WinNTSignal(kSigPipe,                  SigHandler);
01065    WinNTSignal(kSigAlarm,                 SigHandler);
01066    WinNTSignal(kSigFloatingException,     SigHandler);
01067    */
01068    ::SetUnhandledExceptionFilter(ExceptionFilter);
01069 
01070    fSigcnt = 0;
01071 
01072 #ifndef ROOTPREFIX
01073    gRootDir = Getenv("ROOTSYS");
01074    if (gRootDir == 0) {
01075       static char lpFilename[MAX_PATH];
01076       if (::GetModuleFileName(NULL,               // handle to module to find filename for
01077                             lpFilename,           // pointer to buffer to receive module path
01078                             sizeof(lpFilename)))  // size of buffer, in characters
01079       {
01080          const char *dirName = DirName(DirName(lpFilename));
01081          gRootDir = StrDup(dirName);
01082       } else {
01083          gRootDir = 0;
01084       }
01085    }
01086 #else
01087    gRootDir= ROOTPREFIX;
01088 #endif
01089 
01090    // Increase the accuracy of Sleep() without needing to link to winmm.lib
01091    typedef UINT (WINAPI* LPTIMEBEGINPERIOD)( UINT uPeriod );
01092    HINSTANCE hInstWinMM = LoadLibrary( "winmm.dll" );
01093    if( hInstWinMM ) {
01094       LPTIMEBEGINPERIOD pTimeBeginPeriod = (LPTIMEBEGINPERIOD)GetProcAddress( hInstWinMM, "timeBeginPeriod" );
01095       if( NULL != pTimeBeginPeriod )
01096          pTimeBeginPeriod(1);
01097       FreeLibrary(hInstWinMM);
01098    }
01099    gTimerThreadHandle = ::CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadStub,
01100                         this, NULL, NULL);
01101 
01102    gGlobalEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
01103    fGUIThreadHandle = ::CreateThread( NULL, 0, &GUIThreadMessageProcessingLoop, 0, 0, &fGUIThreadId );
01104 
01105    SetConsoleWindowName();
01106    fGroupsInitDone = kFALSE;
01107    fFirstFile = kTRUE;
01108 
01109    return kFALSE;
01110 }
01111 
01112 //---- Misc --------------------------------------------------------------------
01113 
01114 //______________________________________________________________________________
01115 const char *TWinNTSystem::BaseName(const char *name)
01116 {
01117    // Base name of a file name. Base name of /user/root is root.
01118    // But the base name of '/' is '/'
01119    //                      'c:\' is 'c:\'
01120 
01121    // BB 28/10/05 : Removed (commented out) StrDup() :
01122    // - To get same behaviour on Windows and on Linux
01123    // - To avoid the need to use #ifdefs
01124    // - Solve memory leaks (mainly in TTF::SetTextFont())
01125    // No need for the calling routine to use free() anymore.
01126 
01127    if (name) {
01128       int idx = 0;
01129       const char *symbol=name;
01130 
01131       // Skip leading blanks
01132       while ( (*symbol == ' ' || *symbol == '\t') && *symbol) symbol++;
01133 
01134       if (*symbol) {
01135          if (isalpha(symbol[idx]) && symbol[idx+1] == ':') idx = 2;
01136          if ( (symbol[idx] == '/'  ||  symbol[idx] == '\\')  &&  symbol[idx+1] == '\0') {
01137             //return StrDup(symbol);
01138             return symbol;
01139          }
01140       } else {
01141          Error("BaseName", "name = 0");
01142          return 0;
01143       }
01144       char *cp;
01145       char *bslash = (char *)strrchr(&symbol[idx],'\\');
01146       char *rslash = (char *)strrchr(&symbol[idx],'/');
01147       if (cp = max(rslash, bslash)) {
01148          //return StrDup(++cp);
01149          return ++cp;
01150       }
01151       //return StrDup(&symbol[idx]);
01152       return &symbol[idx];
01153    }
01154    Error("BaseName", "name = 0");
01155    return 0;
01156 }
01157 
01158 //______________________________________________________________________________
01159 void TWinNTSystem::SetProgname(const char *name)
01160 {
01161    // Set the application name (from command line, argv[0]) and copy it in
01162    // gProgName. Copy the application pathname in gProgPath.
01163 
01164    ULong_t  idot = 0;
01165    char *dot = 0;
01166    char *progname;
01167    char *fullname = 0; // the program name with extension
01168 
01169   // On command prompt the progname can be supplied with no extension (under Windows)
01170    ULong_t namelen=name ? strlen(name) : 0;
01171    if (name && namelen > 0) {
01172       // Check whether the name contains "extention"
01173       fullname = new char[namelen+5];
01174       strlcpy(fullname, name,namelen+5);
01175       if ( !strrchr(fullname, '.') )
01176          strlcat(fullname, ".exe",namelen+5);
01177 
01178       progname = StrDup(BaseName(fullname));
01179       dot = strrchr(progname, '.');
01180       idot = dot ? (ULong_t)(dot - progname) : strlen(progname);
01181 
01182       char *which = 0;
01183 
01184       if (IsAbsoluteFileName(fullname) && !AccessPathName(fullname)) {
01185          which = StrDup(fullname);
01186       } else {
01187          which = Which(Form("%s;%s", WorkingDirectory(), Getenv("PATH")), progname);
01188       }
01189 
01190       if (which) {
01191          const char *dirname;
01192          char driveletter = DriveName(which);
01193          const char *d = DirName(which);
01194 
01195          if (driveletter) {
01196             dirname = Form("%c:%s", driveletter, d);
01197          } else {
01198             dirname = Form("%s", d);
01199          }
01200 
01201          gProgPath = StrDup(dirname);
01202       } else {
01203          // Do not issue a warning - ROOT is not using gProgPath anyway.
01204          // Warning("SetProgname",
01205          //   "Cannot find this program named \"%s\" (Did you create a TApplication? Is this program in your %%PATH%%?)",
01206          //   fullname);
01207          gProgPath = WorkingDirectory();
01208       }
01209 
01210       // Cut the extension for progname off
01211       progname[idot] = '\0';
01212       gProgName = StrDup(progname);
01213       if (which) delete [] which;
01214       delete[] fullname;
01215       delete[] progname;
01216    }
01217    if (::NeedSplash()) {
01218       new TWin32SplashThread(FALSE);
01219    }
01220 }
01221 
01222 //______________________________________________________________________________
01223 const char *TWinNTSystem::GetError()
01224 {
01225    // Return system error string.
01226 
01227    Int_t err = GetErrno();
01228    if (err == 0 && fLastErrorString != "")
01229       return fLastErrorString;
01230    if (err < 0 || err >= sys_nerr) {
01231       return Form("errno out of range %d", err);
01232    }
01233    return sys_errlist[err];
01234 }
01235 
01236 //______________________________________________________________________________
01237 const char *TWinNTSystem::HostName()
01238 {
01239    // Return the system's host name.
01240 
01241    if (fHostname == "")
01242       fHostname = ::getenv("COMPUTERNAME");
01243    if (fHostname == "") {
01244       // This requires a DNS query - but we need it for fallback
01245       char hn[64];
01246       DWORD il = sizeof(hn);
01247       ::GetComputerName(hn, &il);
01248       fHostname = hn;
01249    }
01250    return fHostname;
01251 }
01252 
01253 //______________________________________________________________________________
01254 void TWinNTSystem::DoBeep(Int_t freq /*=-1*/, Int_t duration /*=-1*/) const
01255 {
01256    // Beep. If freq==0 (the default for TWinNTSystem), use ::MessageBeep.
01257    // Otherwise ::Beep with freq and duration.
01258 
01259    if (freq == 0) {
01260       ::MessageBeep(-1);
01261       return;
01262    }
01263    if (freq < 37) freq = 440;
01264    if (duration < 0) duration = 100;
01265    ::Beep(freq, duration);
01266 }
01267 
01268 //______________________________________________________________________________
01269 void TWinNTSystem::SetGUIThreadMsgHandler(ThreadMsgFunc_t func)
01270 {
01271    // Set the (static part of) the event handler func for GUI messages.
01272 
01273    gGUIThreadMsgFunc = func;
01274 }
01275 
01276 //______________________________________________________________________________
01277 void TWinNTSystem::NotifyApplicationCreated()
01278 {
01279    // Hook to tell TSystem that the TApplication object has been created.
01280 
01281    // send a dummy message to the GUI thread to kick it into life
01282    ::PostThreadMessage(fGUIThreadId, 0, NULL, 0L);
01283 }
01284 
01285 
01286 //---- EventLoop ---------------------------------------------------------------
01287 
01288 //______________________________________________________________________________
01289 void TWinNTSystem::AddFileHandler(TFileHandler *h)
01290 {
01291    // Add a file handler to the list of system file handlers. Only adds
01292    // the handler if it is not already in the list of file handlers.
01293 
01294    TSystem::AddFileHandler(h);
01295    if (h) {
01296       int fd = h->GetFd();
01297       if (!fd) return;
01298 
01299       if (h->HasReadInterest()) {
01300          fReadmask->Set(fd);
01301       }
01302       if (h->HasWriteInterest()) {
01303          fWritemask->Set(fd);
01304       }
01305    }
01306 }
01307 
01308 //______________________________________________________________________________
01309 TFileHandler *TWinNTSystem::RemoveFileHandler(TFileHandler *h)
01310 {
01311    // Remove a file handler from the list of file handlers. Returns
01312    // the handler or 0 if the handler was not in the list of file handlers.
01313 
01314    if (!h) return 0;
01315 
01316    TFileHandler *oh = TSystem::RemoveFileHandler(h);
01317    if (oh) {       // found
01318       fReadmask->Clr(h->GetFd());
01319       fWritemask->Clr(h->GetFd());
01320    }
01321    return oh;
01322 }
01323 
01324 //______________________________________________________________________________
01325 void TWinNTSystem::AddSignalHandler(TSignalHandler *h)
01326 {
01327    // Add a signal handler to list of system signal handlers. Only adds
01328    // the handler if it is not already in the list of signal handlers.
01329 
01330    TSystem::AddSignalHandler(h);
01331    ESignals  sig = h->GetSignal();
01332 
01333    // Add a new handler to the list of the console handlers
01334    if (sig == kSigInterrupt) {
01335       ::SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleSigHandler, TRUE);
01336    } else
01337    WinNTSignal(h->GetSignal(), SigHandler);
01338 }
01339 
01340 //______________________________________________________________________________
01341 TSignalHandler *TWinNTSystem::RemoveSignalHandler(TSignalHandler *h)
01342 {
01343    // Remove a signal handler from list of signal handlers. Returns
01344    // the handler or 0 if the handler was not in the list of signal handlers.
01345 
01346    if (!h) return 0;
01347 
01348    int sig = h->GetSignal();
01349 
01350    if (sig = kSigInterrupt) {
01351       // Remove a  handler to the list of the console handlers
01352       ::SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleSigHandler, FALSE);
01353    }
01354    return TSystem::RemoveSignalHandler(h);
01355 }
01356 
01357 //______________________________________________________________________________
01358 void TWinNTSystem::ResetSignal(ESignals sig, Bool_t reset)
01359 {
01360    // If reset is true reset the signal handler for the specified signal
01361    // to the default handler, else restore previous behaviour.
01362 
01363    //FIXME!
01364 }
01365 
01366 //______________________________________________________________________________
01367 void TWinNTSystem::IgnoreSignal(ESignals sig, Bool_t ignore)
01368 {
01369    // If ignore is true ignore the specified signal, else restore previous
01370    // behaviour.
01371 
01372    // FIXME!
01373 }
01374 
01375 //______________________________________________________________________________
01376 void TWinNTSystem::StackTrace()
01377 {
01378    // Print a stack trace, if gEnv entry "Root.Stacktrace" is unset or 1,
01379    // and if the image helper functions can be found (see InitImagehlpFunctions()).
01380    // The stack trace is printed for each thread; if fgXcptContext is set (e.g.
01381    // because there was an exception) use it to define the current thread's context.
01382    // For each frame in the stack, the frame's module name, the frame's function
01383    // name, and the frame's line number are printed.
01384 
01385    if (!gEnv->GetValue("Root.Stacktrace", 1))
01386       return;
01387 
01388    HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,::GetCurrentProcessId());
01389 
01390    std::cerr.flush();
01391    fflush (stderr);
01392 
01393    if (!InitImagehlpFunctions()) {
01394       std::cerr << "No stack trace: cannot find (functions in) dbghelp.dll!" << std::endl;
01395       return;
01396    }
01397 
01398    // what system are we on?
01399    SYSTEM_INFO sysInfo;
01400    ::GetSystemInfo(&sysInfo);
01401    DWORD machineType = IMAGE_FILE_MACHINE_I386;
01402    switch (sysInfo.wProcessorArchitecture) {
01403       case PROCESSOR_ARCHITECTURE_AMD64:
01404          machineType = IMAGE_FILE_MACHINE_AMD64;
01405          break;
01406       case PROCESSOR_ARCHITECTURE_IA64:
01407          machineType = IMAGE_FILE_MACHINE_IA64;
01408          break;
01409    }
01410 
01411    DWORD currentThreadID = ::GetCurrentThreadId();
01412    DWORD currentProcessID = ::GetCurrentProcessId();
01413 
01414    if (snapshot == INVALID_HANDLE_VALUE) return;
01415 
01416    THREADENTRY32 threadentry;
01417    threadentry.dwSize = sizeof(THREADENTRY32);
01418    if (!::Thread32First(snapshot, &threadentry)) return;
01419 
01420    std::cerr << std::endl << "==========================================" << std::endl;
01421    std::cerr << "=============== STACKTRACE ===============" << std::endl;
01422    std::cerr << "==========================================" << std::endl << std::endl;
01423    UInt_t iThread = 0;
01424    do {
01425       if (threadentry.th32OwnerProcessID != currentProcessID)
01426          continue;
01427       HANDLE thread = ::OpenThread(THREAD_GET_CONTEXT|THREAD_SUSPEND_RESUME|THREAD_QUERY_INFORMATION,
01428          FALSE, threadentry.th32ThreadID);
01429       CONTEXT context;
01430       memset(&context, 0, sizeof(CONTEXT));
01431 
01432       if (threadentry.th32ThreadID != currentThreadID) {
01433          ::SuspendThread(thread);
01434          context.ContextFlags = CONTEXT_ALL;
01435          ::GetThreadContext(thread, &context);
01436          ::ResumeThread(thread);
01437       } else {
01438          if (fgXcptContext) {
01439             context = *fgXcptContext;
01440          } else {
01441             typedef void (WINAPI *RTLCCTXT)(PCONTEXT);
01442             RTLCCTXT p2RtlCCtxt = (RTLCCTXT) ::GetProcAddress(
01443                GetModuleHandle("kernel32.dll"), "RtlCaptureContext");
01444             if (p2RtlCCtxt) {
01445                context.ContextFlags = CONTEXT_ALL;
01446                p2RtlCCtxt(&context);
01447             }
01448          }
01449       }
01450 
01451       STACKFRAME64 frame;
01452       ::ZeroMemory(&frame, sizeof(frame));
01453 
01454       frame.AddrPC.Mode      = AddrModeFlat;
01455       frame.AddrFrame.Mode   = AddrModeFlat;
01456       frame.AddrStack.Mode   = AddrModeFlat;
01457 #if defined(_M_IX86)
01458       frame.AddrPC.Offset    = context.Eip;
01459       frame.AddrFrame.Offset = context.Ebp;
01460       frame.AddrStack.Offset = context.Esp;
01461 #elif defined(_M_X64)
01462       frame.AddrPC.Offset    = context.Rip;
01463       frame.AddrFrame.Offset = context.Rsp;
01464       frame.AddrStack.Offset = context.Rsp;
01465 #elif defined(_M_IA64)
01466       frame.AddrPC.Offset    = context.StIIP;
01467       frame.AddrFrame.Offset = context.IntSp;
01468       frame.AddrStack.Offset = context.IntSp;
01469       frame.AddrBStore.Offset= context.RsBSP;
01470 #else
01471       std::cerr << "Stack traces not supported on your architecture yet." << std::endl;
01472       return;
01473 #endif
01474 
01475       Bool_t bFirst = kTRUE;
01476       while (_StackWalk64(machineType, (HANDLE)::GetCurrentProcess(), thread, (LPSTACKFRAME64)&frame,
01477          (LPVOID)&context, (PREAD_PROCESS_MEMORY_ROUTINE)NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE)_SymFunctionTableAccess64,
01478          (PGET_MODULE_BASE_ROUTINE)_SymGetModuleBase64, NULL)) {
01479          if (bFirst)
01480             std::cerr << std::endl << "================ Thread " << iThread++ << " ================" << std::endl;
01481          if (!bFirst || threadentry.th32ThreadID != currentThreadID) {
01482             const std::string moduleName   = GetModuleName(frame.AddrPC.Offset);
01483             const std::string functionName = GetFunctionName(frame.AddrPC.Offset);
01484             std::cerr << "  " << moduleName << functionName << std::endl;
01485          }
01486          bFirst = kFALSE;
01487       }
01488       ::CloseHandle(thread);
01489    } while (::Thread32Next(snapshot, &threadentry));
01490 
01491    std::cerr << std::endl << "==========================================" << std::endl;
01492    std::cerr << "============= END STACKTRACE =============" << std::endl;
01493    std::cerr << "==========================================" << std::endl << std::endl;
01494    ::CloseHandle(snapshot);
01495    _SymCleanup(GetCurrentProcess());
01496 }
01497 
01498 //______________________________________________________________________________
01499 Int_t TWinNTSystem::GetFPEMask()
01500 {
01501    // Return the bitmap of conditions that trigger a floating point exception.
01502 
01503    Int_t mask = 0;
01504    UInt_t oldmask = _statusfp( );
01505 
01506    if (oldmask & _EM_INVALID  )   mask |= kInvalid;
01507    if (oldmask & _EM_ZERODIVIDE)  mask |= kDivByZero;
01508    if (oldmask & _EM_OVERFLOW )   mask |= kOverflow;
01509    if (oldmask & _EM_UNDERFLOW)   mask |= kUnderflow;
01510    if (oldmask & _EM_INEXACT  )   mask |= kInexact;
01511 
01512    return mask;
01513 }
01514 
01515 //______________________________________________________________________________
01516 Int_t TWinNTSystem::SetFPEMask(Int_t mask)
01517 {
01518    // Set which conditions trigger a floating point exception.
01519    // Return the previous set of conditions.
01520 
01521    Int_t old = GetFPEMask();
01522 
01523    UInt_t newm = 0;
01524    if (mask & kInvalid  )   newm |= _EM_INVALID;
01525    if (mask & kDivByZero)   newm |= _EM_ZERODIVIDE;
01526    if (mask & kOverflow )   newm |= _EM_OVERFLOW;
01527    if (mask & kUnderflow)   newm |= _EM_UNDERFLOW;
01528    if (mask & kInexact  )   newm |= _EM_INEXACT;
01529 
01530    UInt_t cm = ::_statusfp();
01531    cm &= ~newm;
01532    ::_controlfp(cm , _MCW_EM);
01533 
01534    return old;
01535 }
01536 
01537 //______________________________________________________________________________
01538 Bool_t TWinNTSystem::ProcessEvents()
01539 {
01540    // process pending events, i.e. DispatchOneEvent(kTRUE)
01541 
01542    return TSystem::ProcessEvents();
01543 }
01544 
01545 //______________________________________________________________________________
01546 void TWinNTSystem::DispatchOneEvent(Bool_t pendingOnly)
01547 {
01548    // Dispatch a single event in TApplication::Run() loop
01549 
01550    // check for keyboard events
01551    if (pendingOnly && gGlobalEvent) ::SetEvent(gGlobalEvent);
01552 
01553    Bool_t pollOnce = pendingOnly;
01554 
01555    while (1) {
01556       if (_kbhit()) {
01557          if (gROOT->GetApplication()) {
01558             gApplication->HandleTermInput();
01559             if (gSplash) {    // terminate splash window after first key press
01560                delete gSplash;
01561                gSplash = 0;
01562             }
01563             if (!pendingOnly) {
01564                return;
01565             }
01566          }
01567       }
01568       if (gROOT->IsLineProcessing() && (!gVirtualX || !gVirtualX->IsCmdThread())) {
01569          if (!pendingOnly) {
01570             // yield execution to another thread that is ready to run
01571             // if no other thread is ready, sleep 1 ms before to return
01572             if (gGlobalEvent) {
01573                ::WaitForSingleObject(gGlobalEvent, 1);
01574                ::ResetEvent(gGlobalEvent);
01575             }
01576             return;
01577          }
01578       }
01579       // first handle any GUI events
01580       if (gXDisplay && !gROOT->IsBatch()) {
01581          if (gXDisplay->Notify()) {
01582             if (!pendingOnly) {
01583                return;
01584             }
01585          }
01586       }
01587 
01588       // check for file descriptors ready for reading/writing
01589       if ((fNfd > 0) && fFileHandler && (fFileHandler->GetSize() > 0)) {
01590          if (CheckDescriptors()) {
01591             if (!pendingOnly) {
01592                return;
01593             }
01594          }
01595       }
01596       fNfd = 0;
01597       fReadready->Zero();
01598       fWriteready->Zero();
01599 
01600       if (pendingOnly && !pollOnce)
01601          return;
01602 
01603       // check synchronous signals
01604       if (fSigcnt > 0 && fSignalHandler->GetSize() > 0) {
01605          if (CheckSignals(kTRUE)) {
01606             if (!pendingOnly) {
01607                return;
01608             }
01609          }
01610       }
01611       fSigcnt = 0;
01612       fSignals->Zero();
01613 
01614       // handle past due timers
01615       Long_t nextto;
01616       if (fTimers && fTimers->GetSize() > 0) {
01617          if (DispatchTimers(kTRUE)) {
01618             // prevent timers from blocking the rest types of events
01619             nextto = NextTimeOut(kTRUE);
01620             if (nextto > kItimerResolution || nextto == -1) {
01621                return;
01622             }
01623          }
01624       }
01625 
01626       // if in pendingOnly mode poll once file descriptor activity
01627       nextto = NextTimeOut(kTRUE);
01628       if (pendingOnly) {
01629          if (fFileHandler && fFileHandler->GetSize() == 0)
01630             return;
01631          nextto = 0;
01632          pollOnce = kFALSE;
01633       }
01634 
01635       if (fReadmask && !fReadmask->GetBits() &&
01636           fWritemask && !fWritemask->GetBits()) {
01637          // yield execution to another thread that is ready to run
01638          // if no other thread is ready, sleep 1 ms before to return
01639          if (!pendingOnly && gGlobalEvent) {
01640             ::WaitForSingleObject(gGlobalEvent, 1);
01641             ::ResetEvent(gGlobalEvent);
01642          }
01643          return;
01644       }
01645 
01646       *fReadready  = *fReadmask;
01647       *fWriteready = *fWritemask;
01648 
01649       fNfd = WinNTSelect(fReadready, fWriteready, nextto);
01650 
01651       // serious error has happened -> reset all file descrptors
01652       if ((fNfd < 0) && (fNfd != -2)) {
01653          int rc, i;
01654 
01655          for (i = 0; i < fReadmask->GetCount(); i++) {
01656             TFdSet t;
01657             Int_t fd = fReadmask->GetFd(i);
01658             t.Set(fd);
01659             if (fReadmask->IsSet(fd)) {
01660                rc = WinNTSelect(&t, 0, 0);
01661                if (rc < 0 && rc != -2) {
01662                   ::SysError("DispatchOneEvent", "select: read error on %d\n", fd);
01663                   fReadmask->Clr(fd);
01664                }
01665             }
01666          }
01667 
01668          for (i = 0; i < fWritemask->GetCount(); i++) {
01669             TFdSet t;
01670             Int_t fd = fWritemask->GetFd(i);
01671             t.Set(fd);
01672 
01673             if (fWritemask->IsSet(fd)) {
01674                rc = WinNTSelect(0, &t, 0);
01675                if (rc < 0 && rc != -2) {
01676                   ::SysError("DispatchOneEvent", "select: write error on %d\n", fd);
01677                   fWritemask->Clr(fd);
01678                }
01679             }
01680             t.Clr(fd);
01681          }
01682       }
01683    }
01684 }
01685 
01686 //______________________________________________________________________________
01687 void TWinNTSystem::ExitLoop()
01688 {
01689    // Exit from event loop.
01690 
01691    TSystem::ExitLoop();
01692 }
01693 
01694 //---- handling of system events -----------------------------------------------
01695 //______________________________________________________________________________
01696 Bool_t TWinNTSystem::CheckSignals(Bool_t sync)
01697 {
01698    // Check if some signals were raised and call their Notify() member.
01699 
01700    TSignalHandler *sh;
01701    Int_t sigdone = -1;
01702    {
01703       TIter next(fSignalHandler);
01704 
01705       while (sh = (TSignalHandler*)next()) {
01706          if (sync == sh->IsSync()) {
01707             ESignals sig = sh->GetSignal();
01708             if ((fSignals->IsSet(sig) && sigdone == -1) || sigdone == sig) {
01709                if (sigdone == -1) {
01710                   fSignals->Clr(sig);
01711                   sigdone = sig;
01712                   fSigcnt--;
01713                }
01714                sh->Notify();
01715             }
01716          }
01717       }
01718    }
01719    if (sigdone != -1) return kTRUE;
01720 
01721    return kFALSE;
01722 }
01723 
01724 //______________________________________________________________________________
01725 Bool_t TWinNTSystem::CheckDescriptors()
01726 {
01727    // Check if there is activity on some file descriptors and call their
01728    // Notify() member.
01729 
01730    TFileHandler *fh;
01731    Int_t  fddone = -1;
01732    Bool_t read   = kFALSE;
01733 
01734    TOrdCollectionIter it((TOrdCollection*)fFileHandler);
01735 
01736    while ((fh = (TFileHandler*) it.Next())) {
01737       Int_t fd = fh->GetFd();
01738       if (!fd) continue; // ignore TTermInputHandler
01739 
01740       if ((fReadready->IsSet(fd) && fddone == -1) ||
01741           (fddone == fd && read)) {
01742          if (fddone == -1) {
01743             fReadready->Clr(fd);
01744             fddone = fd;
01745             read = kTRUE;
01746             fNfd--;
01747          }
01748          fh->ReadNotify();
01749       }
01750       if ((fWriteready->IsSet(fd) && fddone == -1) ||
01751           (fddone == fd && !read)) {
01752          if (fddone == -1) {
01753             fWriteready->Clr(fd);
01754             fddone = fd;
01755             read = kFALSE;
01756             fNfd--;
01757          }
01758          fh->WriteNotify();
01759       }
01760    }
01761    if (fddone != -1) return kTRUE;
01762 
01763    return kFALSE;
01764 }
01765 
01766 //---- Directories -------------------------------------------------------------
01767 
01768 //______________________________________________________________________________
01769 int TWinNTSystem::mkdir(const char *name, Bool_t recursive)
01770 {
01771    // Make a file system directory. Returns 0 in case of success and
01772    // -1 if the directory could not be created (either already exists or
01773    // illegal path name).
01774    // If 'recursive' is true, makes parent directories as needed.
01775 
01776    if (recursive) {
01777       TString dirname = DirName(name);
01778       if (dirname.Length() == 0) {
01779          // well we should not have to make the root of the file system!
01780          // (and this avoid infinite recursions!)
01781          return 0;
01782       }
01783       if (IsAbsoluteFileName(name)) {
01784          // For some good reason DirName strips off the drive letter
01785          // (if present), we need it to make the directory on the
01786          // right disk, so let's put it back!
01787          const char driveletter = DriveName(name);
01788          if (driveletter) {
01789             dirname.Prepend(":");
01790             dirname.Prepend(driveletter);
01791          }
01792       }
01793       if (AccessPathName(dirname, kFileExists)) {
01794          int res = this->mkdir(dirname, kTRUE);
01795          if (res) return res;
01796       }
01797       if (!AccessPathName(name, kFileExists)) {
01798          return -1;
01799       }
01800    }
01801    return MakeDirectory(name);
01802 }
01803 
01804 //______________________________________________________________________________
01805 int  TWinNTSystem::MakeDirectory(const char *name)
01806 {
01807    // Make a WinNT file system directory. Returns 0 in case of success and
01808    // -1 if the directory could not be created (either already exists or
01809    // illegal path name).
01810 
01811    TSystem *helper = FindHelper(name);
01812    if (helper) {
01813       return helper->MakeDirectory(name);
01814    }
01815    const char *proto = (strstr(name, "file:///")) ? "file://" : "file:";
01816 #ifdef WATCOM
01817    // It must be as follows
01818    if (!name) return 0;
01819    return ::mkdir(StripOffProto(name, proto));
01820 #else
01821    // but to be in line with TUnixSystem I did like this
01822    if (!name) return 0;
01823    return ::_mkdir(StripOffProto(name, proto));
01824 #endif
01825 }
01826 
01827 //______________________________________________________________________________
01828 void TWinNTSystem::FreeDirectory(void *dirp)
01829 {
01830    // Close a WinNT file system directory.
01831 
01832    TSystem *helper = FindHelper(0, dirp);
01833    if (helper) {
01834       helper->FreeDirectory(dirp);
01835       return;
01836    }
01837 
01838    if (dirp) {
01839       ::FindClose(dirp);
01840    }
01841 }
01842 
01843 //______________________________________________________________________________
01844 const char *TWinNTSystem::GetDirEntry(void *dirp)
01845 {
01846    // Returns the next directory entry.
01847 
01848    TSystem *helper = FindHelper(0, dirp);
01849    if (helper) {
01850       return helper->GetDirEntry(dirp);
01851    }
01852 
01853    if (dirp) {
01854       HANDLE searchFile = (HANDLE)dirp;
01855       if (fFirstFile) {
01856          // when calling TWinNTSystem::OpenDirectory(), the fFindFileData
01857          // structure is filled by a call to FindFirstFile().
01858          // So first returns this one, before calling FindNextFile()
01859          fFirstFile = kFALSE;
01860          return (const char *)fFindFileData.cFileName;
01861       }
01862       if (::FindNextFile(searchFile, &fFindFileData)) {
01863          return (const char *)fFindFileData.cFileName;
01864       }
01865    }
01866    return 0;
01867 }
01868 
01869 //______________________________________________________________________________
01870 Bool_t TWinNTSystem::ChangeDirectory(const char *path)
01871 {
01872    // Change directory.
01873 
01874    Bool_t ret = (Bool_t) (::chdir(path) == 0);
01875    if (fWdpath != "") {
01876       fWdpath = "";   // invalidate path cache
01877    }
01878    return ret;
01879 }
01880 
01881 //______________________________________________________________________________
01882 __inline BOOL DBL_BSLASH(LPCTSTR psz)
01883 {
01884    //
01885    // Inline function to check for a double-backslash at the
01886    // beginning of a string
01887    //
01888    return (psz[0] == TEXT('\\') && psz[1] == TEXT('\\'));
01889 }
01890 
01891 //______________________________________________________________________________
01892 BOOL PathIsUNC(LPCTSTR pszPath)
01893 {
01894    // Returns TRUE if the given string is a UNC path.
01895    //
01896    // TRUE
01897    //      "\\foo\bar"
01898    //      "\\foo"         <- careful
01899    //      "\\"
01900    // FALSE
01901    //      "\foo"
01902    //      "foo"
01903    //      "c:\foo"
01904    return DBL_BSLASH(pszPath);
01905 }
01906 
01907 #pragma data_seg(".text", "CODE")
01908 const TCHAR c_szColonSlash[] = TEXT(":\\");
01909 #pragma data_seg()
01910 
01911 //______________________________________________________________________________
01912 BOOL PathIsRoot(LPCTSTR pPath)
01913 {
01914    //
01915    // check if a path is a root
01916    //
01917    // returns:
01918    //  TRUE for "\" "X:\" "\\foo\asdf" "\\foo\"
01919    //  FALSE for others
01920    //
01921    if (!IsDBCSLeadByte(*pPath)) {
01922       if (!lstrcmpi(pPath + 1, c_szColonSlash))
01923          // "X:\" case
01924          return TRUE;
01925    }
01926    if ((*pPath == TEXT('\\')) && (*(pPath + 1) == 0))
01927       // "\" case
01928       return TRUE;
01929    if (DBL_BSLASH(pPath)) {
01930       // smells like UNC name
01931       LPCTSTR p;
01932       int cBackslashes = 0;
01933       for (p = pPath + 2; *p; p = CharNext(p)) {
01934          if (*p == TEXT('\\') && (++cBackslashes > 1))
01935             return FALSE;   // not a bare UNC name, therefore not a root dir
01936       }
01937       // end of string with only 1 more backslash
01938       // must be a bare UNC, which looks like a root dir
01939       return TRUE;
01940    }
01941    return FALSE;
01942 }
01943 
01944 //______________________________________________________________________________
01945 void *TWinNTSystem::OpenDirectory(const char *fdir)
01946 {
01947    // Open a directory. Returns 0 if directory does not exist.
01948 
01949    TSystem *helper = FindHelper(fdir);
01950    if (helper) {
01951       return helper->OpenDirectory(fdir);
01952    }
01953 
01954    const char *proto = (strstr(fdir, "file:///")) ? "file://" : "file:";
01955    const char *sdir = StripOffProto(fdir, proto);
01956 
01957    char *dir = new char[MAX_PATH];
01958    if (IsShortcut(sdir)) {
01959       if (!ResolveShortCut(sdir, dir, MAX_PATH))
01960          strlcpy(dir, sdir,MAX_PATH);
01961    }
01962    else
01963       strlcpy(dir, sdir,MAX_PATH);
01964 
01965    int nche = strlen(dir)+3;
01966    char *entry = new char[nche];
01967    struct _stati64 finfo;
01968 
01969    if(PathIsUNC(dir)) {
01970       strlcpy(entry, dir,nche);
01971       if ((entry[strlen(dir)-1] == '/') || (entry[strlen(dir)-1] == '\\' )) {
01972          entry[strlen(dir)-1] = '\0';
01973       }
01974       if(PathIsRoot(entry)) {
01975          strlcat(entry,"\\",nche);
01976       }
01977       if (_stati64(entry, &finfo) < 0) {
01978          delete [] entry;
01979          delete [] dir;
01980          return 0;
01981       }
01982    }
01983    else {
01984       strlcpy(entry, dir,nche);
01985       if ((entry[strlen(dir)-1] == '/') || (entry[strlen(dir)-1] == '\\' )) {
01986          if(!PathIsRoot(entry))
01987             entry[strlen(dir)-1] = '\0';
01988       }
01989       if (_stati64(entry, &finfo) < 0) {
01990          delete [] entry;
01991          delete [] dir;
01992          return 0;
01993       }
01994    }
01995 
01996    if (finfo.st_mode & S_IFDIR) {
01997       strlcpy(entry, dir,nche);
01998       if (!(entry[strlen(dir)-1] == '/' || entry[strlen(dir)-1] == '\\' )) {
01999          strlcat(entry,"\\",nche);
02000       }
02001       strlcat(entry,"*",nche);
02002 
02003       HANDLE searchFile;
02004       searchFile = ::FindFirstFile(entry, &fFindFileData);
02005       if (searchFile == INVALID_HANDLE_VALUE) {
02006          ((TWinNTSystem *)gSystem)->Error( "Unable to find' for reading:", entry);
02007          delete [] entry;
02008          delete [] dir;
02009          return 0;
02010       }
02011       delete [] entry;
02012       delete [] dir;
02013       fFirstFile = kTRUE;
02014       return searchFile;
02015    } else {
02016       delete [] entry;
02017       delete [] dir;
02018       return 0;
02019    }
02020 }
02021 
02022 //______________________________________________________________________________
02023 const char *TWinNTSystem::WorkingDirectory()
02024 {
02025    // Return the working directory for the default drive
02026 
02027    return WorkingDirectory('\0');
02028 }
02029 
02030 //______________________________________________________________________________
02031 const char *TWinNTSystem::WorkingDirectory(char driveletter)
02032 {
02033    //  Return working directory for the selected drive
02034    //  driveletter == 0 means return the working durectory for the default drive
02035 
02036    char *wdpath = 0;
02037    char drive = driveletter ? toupper( driveletter ) - 'A' + 1 : 0;
02038 
02039    if (fWdpath != "" ) {
02040       return fWdpath;
02041    }
02042 
02043    if (!(wdpath = ::_getdcwd( (int)drive, wdpath, kMAXPATHLEN))) {
02044       free(wdpath);
02045       Warning("WorkingDirectory", "getcwd() failed");
02046       return 0;
02047    }
02048    fWdpath = wdpath;
02049    // Make sure the drive letter is upper case
02050    if (fWdpath[1] == ':')
02051       fWdpath[0] = toupper(fWdpath[0]);
02052    free(wdpath);
02053    return fWdpath;
02054 }
02055 
02056 //______________________________________________________________________________
02057 const char *TWinNTSystem::HomeDirectory(const char *userName)
02058 {
02059    // Return the user's home directory.
02060 
02061    static char mydir[kMAXPATHLEN] = "./";
02062    const char *h = 0;
02063    if (!(h = ::getenv("home"))) h = ::getenv("HOME");
02064 
02065    if (h) {
02066       strlcpy(mydir, h,kMAXPATHLEN);
02067    } else {
02068       // for Windows NT HOME might be defined as either $(HOMESHARE)/$(HOMEPATH)
02069       //                                         or     $(HOMEDRIVE)/$(HOMEPATH)
02070       h = ::getenv("HOMESHARE");
02071       if (!h)  h = ::getenv("HOMEDRIVE");
02072       if (h) {
02073          strlcpy(mydir, h,kMAXPATHLEN);
02074          h = ::getenv("HOMEPATH");
02075          if(h) strlcat(mydir, h,kMAXPATHLEN);
02076       }
02077       // on Windows Vista HOME is usually defined as $(USERPROFILE)
02078       if (!h) {
02079          h = ::getenv("USERPROFILE");
02080          if (h) strlcpy(mydir, h,kMAXPATHLEN);
02081       }
02082    }
02083    // Make sure the drive letter is upper case
02084    if (mydir[1] == ':')
02085       mydir[0] = toupper(mydir[0]);
02086    return mydir;
02087 }
02088 
02089 //______________________________________________________________________________
02090 const char *TWinNTSystem::TempDirectory() const
02091 {
02092    // Return a user configured or systemwide directory to create
02093    // temporary files in.
02094 
02095    const char *dir =  gSystem->Getenv("TEMP");
02096    if (!dir)   dir =  gSystem->Getenv("TEMPDIR");
02097    if (!dir)   dir =  gSystem->Getenv("TEMP_DIR");
02098    if (!dir)   dir =  gSystem->Getenv("TMP");
02099    if (!dir)   dir =  gSystem->Getenv("TMPDIR");
02100    if (!dir)   dir =  gSystem->Getenv("TMP_DIR");
02101    if (!dir) dir = "c:\\";
02102 
02103    return dir;
02104 }
02105 
02106 //______________________________________________________________________________
02107 FILE *TWinNTSystem::TempFileName(TString &base, const char *dir)
02108 {
02109    // Create a secure temporary file by appending a unique
02110    // 6 letter string to base. The file will be created in
02111    // a standard (system) directory or in the directory
02112    // provided in dir. The full filename is returned in base
02113    // and a filepointer is returned for safely writing to the file
02114    // (this avoids certain security problems). Returns 0 in case
02115    // of error.
02116 
02117    char tmpName[MAX_PATH];
02118 
02119    ::GetTempFileName(dir ? dir : TempDirectory(), base.Data(), 0, tmpName);
02120    base = tmpName;
02121    FILE *fp = fopen(tmpName, "w+");
02122 
02123    if (!fp) ::SysError("TempFileName", "error opening %s", tmpName);
02124 
02125    return fp;
02126 }
02127 
02128 //---- Paths & Files -----------------------------------------------------------
02129 
02130 //______________________________________________________________________________
02131 TList *TWinNTSystem::GetVolumes(Option_t *opt) const
02132 {
02133    // Get list of volumes (drives) mounted on the system.
02134    // The returned TList must be deleted by the user using "delete".
02135 
02136    Int_t   curdrive;
02137    UInt_t  type;
02138    TString sDrive, sType;
02139    char    szFs[32];
02140 
02141    if (!opt || !strlen(opt)) {
02142       return 0;
02143    }
02144 
02145    // prevent the system dialog box to pop-up if a drive is empty
02146    UINT nOldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
02147    TList *drives = new TList();
02148    drives->SetOwner();
02149    // Save current drive
02150    curdrive = _getdrive();
02151    if (strstr(opt, "cur")) {
02152       *szFs='\0';
02153       sDrive.Form("%c:", (curdrive + 'A' - 1));
02154       sType.Form("Unknown Drive (%s)", sDrive.Data());
02155       ::GetVolumeInformation(Form("%s\\", sDrive.Data()), NULL, 0, NULL, NULL,
02156                              NULL, (LPSTR)szFs, 32);
02157       type = ::GetDriveType(sDrive.Data());
02158       switch (type) {
02159          case DRIVE_UNKNOWN:
02160          case DRIVE_NO_ROOT_DIR:
02161             break;
02162          case DRIVE_REMOVABLE:
02163             sType.Form("Removable Disk (%s)", sDrive.Data());
02164             break;
02165          case DRIVE_FIXED:
02166             sType.Form("Local Disk (%s)", sDrive.Data());
02167             break;
02168          case DRIVE_REMOTE:
02169             sType.Form("Network Drive (%s) (%s)", szFs, sDrive.Data());
02170             break;
02171          case DRIVE_CDROM:
02172             sType.Form("CD/DVD Drive (%s)", sDrive.Data());
02173             break;
02174          case DRIVE_RAMDISK:
02175             sType.Form("RAM Disk (%s)", sDrive.Data());
02176             break;
02177       }
02178       drives->Add(new TNamed(sDrive.Data(), sType.Data()));
02179    }
02180    else if (strstr(opt, "all")) {
02181       TCHAR szTemp[512];
02182       szTemp[0] = '\0';
02183       if (::GetLogicalDriveStrings(511, szTemp)) {
02184          TCHAR szDrive[3] = TEXT(" :");
02185          TCHAR* p = szTemp;
02186          do {
02187             // Copy the drive letter to the template string
02188             *szDrive = *p;
02189             *szFs='\0';
02190             sDrive.Form("%s", szDrive);
02191             // skip floppy drives, to avoid accessing them each time...
02192             if ((sDrive == "A:") || (sDrive == "B:")) {
02193                while (*p++);
02194                continue;
02195             }
02196             sType.Form("Unknown Drive (%s)", sDrive.Data());
02197             ::GetVolumeInformation(Form("%s\\", sDrive.Data()), NULL, 0, NULL,
02198                                    NULL, NULL, (LPSTR)szFs, 32);
02199             type = ::GetDriveType(sDrive.Data());
02200             switch (type) {
02201                case DRIVE_UNKNOWN:
02202                case DRIVE_NO_ROOT_DIR:
02203                   break;
02204                case DRIVE_REMOVABLE:
02205                   sType.Form("Removable Disk (%s)", sDrive.Data());
02206                   break;
02207                case DRIVE_FIXED:
02208                   sType.Form("Local Disk (%s)", sDrive.Data());
02209                   break;
02210                case DRIVE_REMOTE:
02211                   sType.Form("Network Drive (%s) (%s)", szFs, sDrive.Data());
02212                   break;
02213                case DRIVE_CDROM:
02214                   sType.Form("CD/DVD Drive (%s)", sDrive.Data());
02215                   break;
02216                case DRIVE_RAMDISK:
02217                   sType.Form("RAM Disk (%s)", sDrive.Data());
02218                   break;
02219             }
02220             drives->Add(new TNamed(sDrive.Data(), sType.Data()));
02221             // Go to the next NULL character.
02222             while (*p++);
02223          } while (*p); // end of string
02224       }
02225    }
02226    // restore previous error mode
02227    ::SetErrorMode(nOldErrorMode);
02228    return drives;
02229 }
02230 
02231 //______________________________________________________________________________
02232 const char *TWinNTSystem::DirName(const char *pathname)
02233 {
02234    // Return the directory name in pathname. DirName of c:/user/root is /user.
02235    // It creates output with 'new char []' operator. Returned string has to
02236    // be deleted.
02237 
02238    // Delete old buffer
02239    if (fDirNameBuffer) {
02240       // delete [] fDirNameBuffer;
02241       fDirNameBuffer = 0;
02242    }
02243 
02244    // Create a buffer to keep the path name
02245    if (pathname) {
02246       if (strchr(pathname, '/') || strchr(pathname, '\\')) {
02247          const char *rslash = strrchr(pathname, '/');
02248          const char *bslash = strrchr(pathname, '\\');
02249          const char *r = max(rslash, bslash);
02250          const char *ptr = pathname;
02251          while (ptr <= r) {
02252             if (*ptr == ':') {
02253                // Windows path may contain a drive letter
02254                // For NTFS ":" may be a "stream" delimiter as well
02255                pathname =  ptr + 1;
02256                break;
02257             }
02258             ptr++;
02259          }
02260          int len =  r - pathname;
02261          if (len > 0) {
02262             fDirNameBuffer = new char[len+1];
02263             memcpy(fDirNameBuffer, pathname, len);
02264             fDirNameBuffer[len] = 0;
02265          }
02266       }
02267    }
02268    if (!fDirNameBuffer) {
02269       fDirNameBuffer = new char[1];
02270       *fDirNameBuffer = '\0'; // Set the empty default response
02271    }
02272    return fDirNameBuffer;
02273 }
02274 
02275 //______________________________________________________________________________
02276 const char TWinNTSystem::DriveName(const char *pathname)
02277 {
02278    ////////////////////////////////////////////////////////////////////////////
02279    // Return the drive letter in pathname. DriveName of 'c:/user/root' is 'c'//
02280    //   Input:                                                               //
02281    //      pathname - the string containing file name                        //
02282    //   Return:                                                              //
02283    //     = Letter presenting the drive letter in the file name              //
02284    //     = The current drive if the pathname has no drive assigment         //
02285    //     = 0 if pathname is an empty string  or uses UNC syntax             //
02286    //   Note:                                                                //
02287    //      It doesn't chech whether pathname presents the 'real filename     //
02288    //      This subroutine looks for 'single letter' is follows with a ':'   //
02289    ////////////////////////////////////////////////////////////////////////////
02290 
02291    if (!pathname)    return 0;
02292    if (!pathname[0]) return 0;
02293 
02294    const char *lpchar;
02295    lpchar = pathname;
02296 
02297    // Skip blanks
02298    while(*lpchar == ' ') lpchar++;
02299 
02300    if (isalpha((int)*lpchar) && *(lpchar+1) == ':') {
02301       return *lpchar;
02302    }
02303    // Test UNC syntax
02304    if ( (*lpchar == '\\' || *lpchar == '/' ) &&
02305         (*(lpchar+1) == '\\' || *(lpchar+1) == '/') ) return 0;
02306 
02307    // return the current drive
02308    return DriveName(WorkingDirectory());
02309 }
02310 
02311 //______________________________________________________________________________
02312 Bool_t TWinNTSystem::IsAbsoluteFileName(const char *dir)
02313 {
02314    // Return true if dir is an absolute pathname.
02315 
02316    if (dir) {
02317       int idx = 0;
02318       if (strchr(dir,':')) idx = 2;
02319       return  (dir[idx] == '/' || dir[idx] == '\\');
02320    }
02321    return kFALSE;
02322 }
02323 
02324 //______________________________________________________________________________
02325 const char *TWinNTSystem::UnixPathName(const char *name)
02326 {
02327    // Convert a pathname to a unix pathname. E.g. form \user\root to /user/root.
02328    // General rules for applications creating names for directories and files or
02329    // processing names supplied by the user include the following:
02330    //
02331    //  ·  Use any character in the current code page for a name, but do not use
02332    //     a path separator, a character in the range 0 through 31, or any character
02333    //     explicitly disallowed by the file system. A name can contain characters
02334    //     in the extended character set (128-255).
02335    //  ·  Use the backslash (\), the forward slash (/), or both to separate
02336    //     components in a path. No other character is acceptable as a path separator.
02337    //  ·  Use a period (.) as a directory component in a path to represent the
02338    //     current directory.
02339    //  ·  Use two consecutive periods (..) as a directory component in a path to
02340    //     represent the parent of the current directory.
02341    //  ·  Use a period (.) to separate components in a directory name or filename.
02342    //  ·  Do not use the following characters in directory names or filenames, because
02343    //     they are reserved for Windows:
02344    //                      < > : " / \ |
02345    //  ·  Do not use reserved words, such as aux, con, and prn, as filenames or
02346    //     directory names.
02347    //  ·  Process a path as a null-terminated string. The maximum length for a path
02348    //     is given by MAX_PATH.
02349    //  ·  Do not assume case sensitivity. Consider names such as OSCAR, Oscar, and
02350    //     oscar to be the same.
02351 
02352    static char temp[1024];
02353    strlcpy(temp, name,1024);
02354    char *currentChar = temp;
02355 
02356    while (*currentChar != '\0') {
02357       if (*currentChar == '\\') *currentChar = '/';
02358       currentChar++;
02359    }
02360    return temp;
02361 }
02362 
02363 //______________________________________________________________________________
02364 Bool_t TWinNTSystem::AccessPathName(const char *path, EAccessMode mode)
02365 {
02366    // Returns FALSE if one can access a file using the specified access mode.
02367    // Mode is the same as for the WinNT access(2) function.
02368    // Attention, bizarre convention of return value!!
02369 
02370    TSystem *helper = FindHelper(path);
02371    if (helper)
02372       return helper->AccessPathName(path, mode);
02373 
02374    if (mode==kExecutePermission)
02375       // cannot test on exe - use read instead
02376       mode=kReadPermission;
02377    const char *proto = (strstr(path, "file:///")) ? "file://" : "file:";
02378    if (::_access(StripOffProto(path, proto), mode) == 0)
02379       return kFALSE;
02380    fLastErrorString = GetError();
02381    return kTRUE;
02382 }
02383 
02384 //______________________________________________________________________________
02385 Bool_t TWinNTSystem::IsPathLocal(const char *path)
02386 {
02387    // Returns TRUE if the url in 'path' points to the local file system.
02388    // This is used to avoid going through the NIC card for local operations.
02389 
02390    TSystem *helper = FindHelper(path);
02391    if (helper)
02392       return helper->IsPathLocal(path);
02393 
02394    return TSystem::IsPathLocal(path);
02395 }
02396 
02397 //______________________________________________________________________________
02398 const char *TWinNTSystem::PrependPathName(const char *dir, TString& name)
02399 {
02400    // Concatenate a directory and a file name.
02401 
02402    if (name == ".") name = "";
02403    if (dir && dir[0]) {
02404       // Test whether the last symbol of the directory is a separator
02405       char last = dir[strlen(dir) - 1];
02406       if (last != '/' && last != '\\') {
02407          name.Prepend('\\');
02408       }
02409       name.Prepend(dir);
02410       name.ReplaceAll("/", "\\");
02411    }
02412    return name.Data();
02413 }
02414 
02415 //______________________________________________________________________________
02416 int TWinNTSystem::CopyFile(const char *f, const char *t, Bool_t overwrite)
02417 {
02418    // Copy a file. If overwrite is true and file already exists the
02419    // file will be overwritten. Returns 0 when successful, -1 in case
02420    // of failure, -2 in case the file already exists and overwrite was false.
02421 
02422    if (AccessPathName(f, kReadPermission)) return -1;
02423    if (!AccessPathName(t) && !overwrite) return -2;
02424 
02425    Bool_t ret = ::CopyFileA(f, t, kFALSE);
02426 
02427    if (!ret) return -1;
02428    return 0;
02429 }
02430 
02431 //______________________________________________________________________________
02432 int TWinNTSystem::Rename(const char *f, const char *t)
02433 {
02434    // Rename a file. Returns 0 when successful, -1 in case of failure.
02435 
02436    int ret = ::rename(f, t);
02437    fLastErrorString = GetError();
02438    return ret;
02439 }
02440 
02441 //______________________________________________________________________________
02442 int TWinNTSystem::GetPathInfo(const char *path, FileStat_t &buf)
02443 {
02444    // Get info about a file. Info is returned in the form of a FileStat_t
02445    // structure (see TSystem.h).
02446    // The function returns 0 in case of success and 1 if the file could
02447    // not be stat'ed.
02448 
02449    TSystem *helper = FindHelper(path);
02450    if (helper)
02451       return helper->GetPathInfo(path, buf);
02452 
02453    struct _stati64 sbuf;
02454 
02455    // Remove trailing backslashes
02456    const char *proto = (strstr(path, "file:///")) ? "file://" : "file:";
02457    char *newpath = StrDup(StripOffProto(path, proto));
02458    int l = strlen(newpath);
02459    while (l > 1) {
02460       if (newpath[--l] != '\\' || newpath[--l] != '/') {
02461          break;
02462       }
02463       newpath[l] = '\0';
02464    }
02465 
02466    if (newpath && ::_stati64(newpath, &sbuf) >= 0) {
02467 
02468       buf.fDev    = sbuf.st_dev;
02469       buf.fIno    = sbuf.st_ino;
02470       buf.fMode   = sbuf.st_mode;
02471       buf.fUid    = sbuf.st_uid;
02472       buf.fGid    = sbuf.st_gid;
02473       buf.fSize   = sbuf.st_size;
02474       buf.fMtime  = sbuf.st_mtime;
02475       buf.fIsLink = IsShortcut(newpath); // kFALSE;
02476 /*
02477       char *lpath = new char[MAX_PATH];
02478       if (IsShortcut(newpath)) {
02479          struct _stati64 sbuf2;
02480          if (ResolveShortCut(newpath, lpath, MAX_PATH)) {
02481             if (::_stati64(lpath, &sbuf2) >= 0) {
02482                buf.fMode   = sbuf2.st_mode;
02483             }
02484          }
02485       }
02486 */
02487       delete [] newpath;
02488       return 0;
02489    }
02490    delete [] newpath;
02491    return 1;
02492 }
02493 
02494 //______________________________________________________________________________
02495 int TWinNTSystem::GetFsInfo(const char *path, Long_t *id, Long_t *bsize,
02496                             Long_t *blocks, Long_t *bfree)
02497 {
02498    // Get info about a file system: id, bsize, bfree, blocks.
02499    // Id      is file system type (machine dependend, see statfs())
02500    // Bsize   is block size of file system
02501    // Blocks  is total number of blocks in file system
02502    // Bfree   is number of free blocks in file system
02503    // The function returns 0 in case of success and 1 if the file system could
02504    // not be stat'ed.
02505 
02506    // address of root directory of the file system
02507    LPCTSTR lpRootPathName = path;
02508 
02509    // address of name of the volume
02510    LPTSTR  lpVolumeNameBuffer = 0;
02511    DWORD   nVolumeNameSize = 0;
02512 
02513    DWORD   volumeSerialNumber;     // volume serial number
02514    DWORD   maximumComponentLength; // system's maximum filename length
02515 
02516    // file system flags
02517    DWORD fileSystemFlags;
02518 
02519    // address of name of file system
02520    char  fileSystemNameBuffer[512];
02521    DWORD nFileSystemNameSize = sizeof(fileSystemNameBuffer);
02522 
02523    // prevent the system dialog box to pop-up if the drive is empty
02524    UINT nOldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
02525    if (!::GetVolumeInformation(lpRootPathName,
02526                                lpVolumeNameBuffer, nVolumeNameSize,
02527                                &volumeSerialNumber,
02528                                &maximumComponentLength,
02529                                &fileSystemFlags,
02530                                fileSystemNameBuffer, nFileSystemNameSize)) {
02531       // restore previous error mode
02532       ::SetErrorMode(nOldErrorMode);
02533       return 1;
02534    }
02535 
02536    const char *fsNames[] = { "FAT", "NTFS" };
02537    int i;
02538    for (i = 0; i < 2; i++) {
02539       if (!strncmp(fileSystemNameBuffer, fsNames[i], nFileSystemNameSize))
02540          break;
02541    }
02542    *id = i;
02543 
02544    DWORD sectorsPerCluster;      // # sectors per cluster
02545    DWORD bytesPerSector;         // # bytes per sector
02546    DWORD numberOfFreeClusters;   // # free clusters
02547    DWORD totalNumberOfClusters;  // # total of clusters
02548 
02549    if (!::GetDiskFreeSpace(lpRootPathName,
02550                            &sectorsPerCluster,
02551                            &bytesPerSector,
02552                            &numberOfFreeClusters,
02553                            &totalNumberOfClusters)) {
02554       // restore previous error mode
02555       ::SetErrorMode(nOldErrorMode);
02556       return 1;
02557    }
02558    // restore previous error mode
02559    ::SetErrorMode(nOldErrorMode);
02560 
02561    *bsize  = sectorsPerCluster * bytesPerSector;
02562    *blocks = totalNumberOfClusters;
02563    *bfree  = numberOfFreeClusters;
02564 
02565    return 0;
02566 }
02567 
02568 //______________________________________________________________________________
02569 int TWinNTSystem::Link(const char *from, const char *to)
02570 {
02571    // Create a link from file1 to file2.
02572 
02573    struct   _stati64 finfo;
02574    char     winDrive[256];
02575    char     winDir[256];
02576    char     winName[256];
02577    char     winExt[256];
02578    char     linkname[1024];
02579    LPTSTR   lpszFilePart;
02580    TCHAR    szPath[MAX_PATH];
02581    DWORD    dwRet = 0;
02582 
02583    typedef BOOL (__stdcall *CREATEHARDLINKPROC)( LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES );
02584    static CREATEHARDLINKPROC _CreateHardLink = 0;
02585 
02586    HMODULE hModImagehlp = LoadLibrary( "Kernel32.dll" );
02587    if (!hModImagehlp)
02588       return -1;
02589 
02590 #ifdef _UNICODE
02591    _CreateHardLink = (CREATEHARDLINKPROC) GetProcAddress( hModImagehlp, "CreateHardLinkW" );
02592 #else
02593    _CreateHardLink = (CREATEHARDLINKPROC) GetProcAddress( hModImagehlp, "CreateHardLinkA" );
02594 #endif
02595    if (!_CreateHardLink)
02596       return -1;
02597 
02598    dwRet = GetFullPathName(from, sizeof(szPath) / sizeof(TCHAR),
02599                            szPath, &lpszFilePart);
02600 
02601    if (_stati64(szPath, &finfo) < 0)
02602       return -1;
02603 
02604    if (finfo.st_mode & S_IFDIR)
02605       return -1;
02606 
02607    snprintf(linkname,1024,"%s",to);
02608    _splitpath(linkname,winDrive,winDir,winName,winExt);
02609    if ((strlen(winDrive) == 0 ) &&
02610        (strlen(winDir) == 0 ))  {
02611       _splitpath(szPath,winDrive,winDir,winName,winExt);
02612       snprintf(linkname,1024,"%s\\%s\\%s", winDrive, winDir, to);
02613    }
02614    else if (strlen(winDrive) == 0)  {
02615       _splitpath(szPath,winDrive,winDir,winName,winExt);
02616       snprintf(linkname,1024,"%s\\%s", winDrive, to);
02617    }
02618 
02619    if (!_CreateHardLink(linkname, szPath, NULL))
02620       return -1;
02621 
02622    return 0;
02623 }
02624 
02625 //______________________________________________________________________________
02626 int TWinNTSystem::Symlink(const char *from, const char *to)
02627 {
02628    // Create a symlink from file1 to file2. Returns 0 when succesfull,
02629    // -1 in case of failure.
02630 
02631    HRESULT        hRes;                  /* Returned COM result code */
02632    IShellLink*    pShellLink;            /* IShellLink object pointer */
02633    IPersistFile*  pPersistFile;          /* IPersistFile object pointer */
02634    WCHAR          wszLinkfile[MAX_PATH]; /* pszLinkfile as Unicode string */
02635    int            iWideCharsWritten;     /* Number of wide characters written */
02636    DWORD          dwRet = 0;
02637    LPTSTR         lpszFilePart;
02638    TCHAR          szPath[MAX_PATH];
02639 
02640    hRes = E_INVALIDARG;
02641    if ((from == NULL) || (strlen(from) == 0) || (to == NULL) ||
02642        (strlen(to) == 0))
02643       return -1;
02644 
02645    // Make typedefs for some ole32.dll functions so that we can use them
02646    // with GetProcAddress
02647    typedef HRESULT (__stdcall *COINITIALIZEPROC)( LPVOID );
02648    static COINITIALIZEPROC _CoInitialize = 0;
02649    typedef void (__stdcall *COUNINITIALIZEPROC)( void );
02650    static COUNINITIALIZEPROC _CoUninitialize = 0;
02651    typedef HRESULT (__stdcall *COCREATEINSTANCEPROC)( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID );
02652    static COCREATEINSTANCEPROC _CoCreateInstance = 0;
02653 
02654    HMODULE hModImagehlp = LoadLibrary( "ole32.dll" );
02655    if (!hModImagehlp)
02656       return -1;
02657 
02658    _CoInitialize = (COINITIALIZEPROC) GetProcAddress( hModImagehlp, "CoInitialize" );
02659    if (!_CoInitialize)
02660       return -1;
02661    _CoUninitialize = (COUNINITIALIZEPROC) GetProcAddress( hModImagehlp, "CoUninitialize" );
02662    if (!_CoUninitialize)
02663       return -1;
02664    _CoCreateInstance = (COCREATEINSTANCEPROC) GetProcAddress( hModImagehlp, "CoCreateInstance" );
02665    if (!_CoCreateInstance)
02666       return -1;
02667 
02668    TString linkname(to);
02669    if (!linkname.EndsWith(".lnk"))
02670       linkname.Append(".lnk");
02671 
02672    _CoInitialize(NULL);
02673 
02674    // Retrieve the full path and file name of a specified file
02675    dwRet = GetFullPathName(from, sizeof(szPath) / sizeof(TCHAR),
02676                            szPath, &lpszFilePart);
02677    hRes = _CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
02678                            IID_IShellLink, (LPVOID *)&pShellLink);
02679    if (SUCCEEDED(hRes)) {
02680       // Set the fields in the IShellLink object
02681       hRes = pShellLink->SetPath(szPath);
02682       // Use the IPersistFile object to save the shell link
02683       hRes = pShellLink->QueryInterface(IID_IPersistFile, (void **)&pPersistFile);
02684       if (SUCCEEDED(hRes)){
02685          iWideCharsWritten = MultiByteToWideChar(CP_ACP, 0, linkname.Data(), -1,
02686                                                  wszLinkfile, MAX_PATH);
02687          hRes = pPersistFile->Save(wszLinkfile, TRUE);
02688          pPersistFile->Release();
02689       }
02690       pShellLink->Release();
02691    }
02692    _CoUninitialize();
02693    return 0;
02694 }
02695 
02696 //______________________________________________________________________________
02697 int TWinNTSystem::Unlink(const char *name)
02698 {
02699    // Unlink, i.e. remove, a file or directory.
02700 
02701    TSystem *helper = FindHelper(name);
02702    if (helper)
02703       return helper->Unlink(name);
02704 
02705    struct _stati64 finfo;
02706 
02707    if (_stati64(name, &finfo) < 0) {
02708       return -1;
02709    }
02710 
02711    if (finfo.st_mode & S_IFDIR) {
02712       return ::_rmdir(name);
02713    } else {
02714       return ::_unlink(name);
02715    }
02716 }
02717 
02718 //______________________________________________________________________________
02719 int TWinNTSystem::SetNonBlock(int fd)
02720 {
02721    // Make descriptor fd non-blocking.
02722 
02723    if (::ioctlsocket(fd, FIONBIO, (u_long *)1) == SOCKET_ERROR) {
02724       ::SysError("SetNonBlock", "ioctlsocket");
02725       return -1;
02726    }
02727    return 0;
02728 }
02729 
02730 // expand the metacharacters as in the shell
02731 
02732 static char
02733    *shellMeta      = "~*[]{}?$%",
02734    *shellStuff     = "(){}<>\"'",
02735    shellEscape     = '\\';
02736 
02737 //______________________________________________________________________________
02738 Bool_t TWinNTSystem::ExpandPathName(TString &patbuf0)
02739 {
02740    // Expand a pathname getting rid of special shell characaters like ~.$, etc.
02741 
02742    const char *patbuf = (const char *)patbuf0;
02743    const char *p;
02744    char   *cmd = 0;
02745    char  *q;
02746 
02747    // skip leading blanks
02748    while (*patbuf == ' ') {
02749       patbuf++;
02750    }
02751 
02752    // skip leading ':'
02753    while (*patbuf == ':') {
02754       patbuf++;
02755    }
02756 
02757    // skip leading ';'
02758    while (*patbuf == ';') {
02759       patbuf++;
02760    }
02761 
02762    // Transform a Unix list of directories into a Windows list
02763    // by changing the separator from ':' into ';'
02764    for (q = (char*)patbuf; *q; q++) {
02765       if ( *q == ':' ) {
02766          // We are avoiding substitution in the case of
02767          // ....;c:.... and of ...;root:/... where root can be any url protocol
02768          if ( (((q-2)>patbuf) && ( (*(q-2)!=';') || !isalpha(*(q-1)) )) &&
02769               *(q+1)!='/' ) {
02770             *q=';';
02771          }
02772       }
02773    }
02774    // any shell meta characters ?
02775    for (p = patbuf; *p; p++) {
02776       if (strchr(shellMeta, *p)) {
02777          goto needshell;
02778       }
02779    }
02780    return kFALSE;
02781 
02782 needshell:
02783 
02784    // Because (problably) we built with cygwin, the path name like:
02785    //     LOCALS~1\\Temp
02786    // gets extended to
02787    //     LOCALSc:\\Devel
02788    // The most likely cause is that '~' is used with Unix semantic of the
02789    // home directory (and it also cuts the path short after ... who knows why!)
02790    // So we need to detect this case and prevents its expansion :(.
02791 
02792    char replacement[4];
02793 
02794    // intentionally a non visible, unlikely character
02795    for (int k = 0; k<3; k++) replacement[k] = 0x1;
02796 
02797    replacement[3] = 0x0;
02798    Ssiz_t pos = 0;
02799    TRegexp TildaNum = "~[0-9]";
02800 
02801    while ( (pos = patbuf0.Index(TildaNum,pos)) != kNPOS ) {
02802       patbuf0.Replace(pos, 1, replacement);
02803    }
02804 
02805    // escape shell quote characters
02806    // EscChar(patbuf, stuffedPat, sizeof(stuffedPat), shellStuff, shellEscape);
02807    patbuf0 = ExpandFileName(patbuf0.Data());
02808    Int_t lbuf = ::ExpandEnvironmentStrings(
02809                                  patbuf0.Data(), // pointer to string with environment variables
02810                                  cmd,            // pointer to string with expanded environment variables
02811                                  0               // maximum characters in expanded string
02812                               );
02813    if (lbuf > 0) {
02814       cmd = new char[lbuf+1];
02815       ::ExpandEnvironmentStrings(
02816                                patbuf0.Data(), // pointer to string with environment variables
02817                                cmd,            // pointer to string with expanded environment variables
02818                                lbuf            // maximum characters in expanded string
02819                                );
02820       patbuf0 = cmd;
02821       patbuf0.ReplaceAll(replacement, "~");
02822       delete [] cmd;
02823       return kFALSE;
02824    }
02825    return kTRUE;
02826 }
02827 
02828 //______________________________________________________________________________
02829 char *TWinNTSystem::ExpandPathName(const char *path)
02830 {
02831    // Expand a pathname getting rid of special shell characaters like ~.$, etc.
02832    // User must delete returned string.
02833 
02834    char newpath[MAX_PATH];
02835    if (IsShortcut(path)) {
02836       if (!ResolveShortCut(path, newpath, MAX_PATH))
02837          strlcpy(newpath, path,MAX_PATH);
02838    }
02839    else
02840       strlcpy(newpath, path,MAX_PATH);
02841    TString patbuf = newpath;
02842    if (ExpandPathName(patbuf)) return 0;
02843 
02844    return StrDup(patbuf.Data());
02845 }
02846 
02847 //______________________________________________________________________________
02848 int TWinNTSystem::Chmod(const char *file, UInt_t mode)
02849 {
02850    // Set the file permission bits. Returns -1 in case or error, 0 otherwise.
02851    // On windows mode can only be a combination of "user read" (0400),
02852    // "user write" (0200) or "user read | user write" (0600). Any other value
02853    // for mode are ignored.
02854 
02855    return ::_chmod(file, mode);
02856 }
02857 
02858 //______________________________________________________________________________
02859 int TWinNTSystem::Umask(Int_t mask)
02860 {
02861    // Set the process file creation mode mask.
02862 
02863    return ::umask(mask);
02864 }
02865 
02866 //______________________________________________________________________________
02867 int TWinNTSystem::Utime(const char *file, Long_t modtime, Long_t actime)
02868 {
02869    // Set a files modification and access times. If actime = 0 it will be
02870    // set to the modtime. Returns 0 on success and -1 in case of error.
02871 
02872    if (AccessPathName(file, kWritePermission)) {
02873       Error("Utime", "need write permission for %s to change utime", file);
02874       return -1;
02875    }
02876    if (!actime) actime = modtime;
02877 
02878    struct utimbuf t;
02879    t.actime  = (time_t)actime;
02880    t.modtime = (time_t)modtime;
02881    return ::utime(file, &t);
02882 }
02883 
02884 //______________________________________________________________________________
02885 const char *TWinNTSystem::FindFile(const char *search, TString& infile, EAccessMode mode)
02886 {
02887    // Find location of file in a search path.
02888    // User must delete returned string. Returns 0 in case file is not found.
02889 
02890    // Windows cannot check on execution mode - all we can do is kReadPermission
02891    if (mode==kExecutePermission)
02892       mode=kReadPermission;
02893 
02894    // Expand parameters
02895 
02896    gSystem->ExpandPathName(infile);
02897    // Check whether this infile has the absolute path first
02898    if (IsAbsoluteFileName(infile.Data()) ) {
02899       if (!AccessPathName(infile.Data(), mode))
02900       return infile.Data();
02901       infile = "";
02902       return 0;
02903    }
02904    TString exsearch(search);
02905    gSystem->ExpandPathName(exsearch);
02906 
02907    // Need to use Windows delimiters
02908    Int_t lastDelim = -1;
02909    for(int i=0; i < exsearch.Length(); ++i) {
02910       switch( exsearch[i] ) {
02911          case ':':
02912             // Replace the ':' unless there are after a disk suffix (aka ;c:\mydirec...)
02913             if (i-lastDelim!=2) exsearch[i] = ';';
02914             lastDelim = i;
02915             break;
02916          case ';': lastDelim = i; break;
02917       }
02918    }
02919 
02920    // Check access
02921    struct stat finfo;
02922    char name[kMAXPATHLEN];
02923    char *lpFilePart = 0;
02924    if (::SearchPath(exsearch.Data(), infile.Data(), NULL, kMAXPATHLEN, name, &lpFilePart) &&
02925        ::access(name, mode) == 0 && stat(name, &finfo) == 0 &&
02926        finfo.st_mode & S_IFREG) {
02927       if (gEnv->GetValue("Root.ShowPath", 0)) {
02928          Printf("Which: %s = %s", infile, name);
02929       }
02930       infile = name;
02931       return infile.Data();
02932    }
02933    infile = "";
02934    return 0;
02935 }
02936 
02937 //---- Users & Groups ----------------------------------------------------------
02938 
02939 //______________________________________________________________________________
02940 Bool_t TWinNTSystem::InitUsersGroups()
02941 {
02942    // Collect local users and groups accounts informations
02943 
02944    // Net* API functions allowed and OS is Windows NT/2000/XP
02945    if ((gEnv->GetValue("WinNT.UseNetAPI", 0)) && (::GetVersion() < 0x80000000)) {
02946       fActUser = -1;
02947       fNbGroups = fNbUsers = 0;
02948       HINSTANCE netapi = ::LoadLibrary("netapi32.DLL");
02949       if (!netapi) return kFALSE;
02950 
02951       p2NetApiBufferFree  = (pfn1)::GetProcAddress(netapi, "NetApiBufferFree");
02952       p2NetUserGetInfo  = (pfn2)::GetProcAddress(netapi, "NetUserGetInfo");
02953       p2NetLocalGroupGetMembers  = (pfn3)::GetProcAddress(netapi, "NetLocalGroupGetMembers");
02954       p2NetLocalGroupEnum = (pfn4)::GetProcAddress(netapi, "NetLocalGroupEnum");
02955 
02956       if (!p2NetApiBufferFree || !p2NetUserGetInfo ||
02957           !p2NetLocalGroupGetMembers || !p2NetLocalGroupEnum) return kFALSE;
02958 
02959       GetNbGroups();
02960 
02961       fGroups = (struct group *)calloc(fNbGroups, sizeof(struct group));
02962       for(int i=0;i<fNbGroups;i++) {
02963         fGroups[i].gr_mem = (char **)calloc(fNbUsers, sizeof (char*));
02964       }
02965       fPasswords = (struct passwd *)calloc(fNbUsers, sizeof(struct passwd));
02966 
02967       CollectGroups();
02968       ::FreeLibrary(netapi);
02969    }
02970    fGroupsInitDone = kTRUE;
02971    return kTRUE;
02972 }
02973 
02974 //________________________________________________________________________________
02975 Bool_t TWinNTSystem::CountMembers(const char *lpszGroupName)
02976 {
02977    NET_API_STATUS NetStatus = NERR_Success;
02978    LPBYTE Data = NULL;
02979    DWORD Index = 0, ResumeHandle = 0, Total = 0;
02980    LOCALGROUP_MEMBERS_INFO_1 *MemberInfo;
02981    WCHAR wszGroupName[256];
02982    int iRetOp = 0;
02983    DWORD dwLastError = 0;
02984 
02985    iRetOp = MultiByteToWideChar (
02986             (UINT)CP_ACP,                // code page
02987             (DWORD)MB_PRECOMPOSED,       // character-type options
02988             (LPCSTR)lpszGroupName,       // address of string to map
02989             (int)-1,                     // number of bytes in string
02990             (LPWSTR)wszGroupName,        // address of wide-character buffer
02991             (int)sizeof(wszGroupName) ); // size of buffer
02992 
02993    if (iRetOp == 0) {
02994       dwLastError = GetLastError();
02995       if (Data)
02996          p2NetApiBufferFree(Data);
02997       return FALSE;
02998    }
02999 
03000    // The NetLocalGroupGetMembers() API retrieves a list of the members
03001    // of a particular local group.
03002    NetStatus = p2NetLocalGroupGetMembers (NULL, wszGroupName, 1,
03003                             &Data, 8192, &Index, &Total, &ResumeHandle );
03004 
03005    if (NetStatus != NERR_Success || Data == NULL) {
03006       dwLastError = GetLastError();
03007 
03008       if (dwLastError == ERROR_ENVVAR_NOT_FOUND) {
03009          // This usually means that the current Group has no members.
03010          // We call NetLocalGroupGetMembers() again.
03011          // This time, we set the level to 0.
03012          // We do this just to confirm that the number of members in
03013          // this group is zero.
03014          NetStatus = p2NetLocalGroupGetMembers ( NULL, wszGroupName, 0,
03015                                   &Data, 8192, &Index, &Total, &ResumeHandle );
03016       }
03017 
03018       if (Data)
03019          p2NetApiBufferFree(Data);
03020       return FALSE;
03021    }
03022 
03023    fNbUsers += Total;
03024    MemberInfo = (LOCALGROUP_MEMBERS_INFO_1 *)Data;
03025 
03026    if (Data)
03027       p2NetApiBufferFree(Data);
03028 
03029    return TRUE;
03030 }
03031 
03032 //________________________________________________________________________________
03033 Bool_t TWinNTSystem::GetNbGroups()
03034 {
03035    NET_API_STATUS NetStatus = NERR_Success;
03036    LPBYTE Data = NULL;
03037    DWORD Index = 0, ResumeHandle = 0, Total = 0, i;
03038    LOCALGROUP_INFO_0 *GroupInfo;
03039    char szAnsiName[256];
03040    DWORD dwLastError = 0;
03041    int  iRetOp = 0;
03042 
03043    NetStatus = p2NetLocalGroupEnum(NULL, 0, &Data, 8192, &Index,
03044                                     &Total, &ResumeHandle );
03045 
03046    if (NetStatus != NERR_Success || Data == NULL) {
03047       dwLastError = GetLastError();
03048       if (Data)
03049          p2NetApiBufferFree(Data);
03050       return FALSE;
03051    }
03052 
03053    fNbGroups = Total;
03054    GroupInfo = (LOCALGROUP_INFO_0 *)Data;
03055    for (i=0; i < Total; i++) {
03056       // Convert group name from UNICODE to ansi.
03057       iRetOp = WideCharToMultiByte (
03058                (UINT)CP_ACP,                    // code page
03059                (DWORD)0,                        // performance and mapping flags
03060                (LPCWSTR)(GroupInfo->lgrpi0_name), // address of wide-char string
03061                (int)-1,                        // number of characters in string
03062                (LPSTR)szAnsiName,            // address of buffer for new string
03063                (int)(sizeof(szAnsiName)),    // size of buffer
03064                (LPCSTR)NULL,     // address of default for unmappable characters
03065                (LPBOOL)NULL );     // address of flag set when default char used.
03066 
03067       // Now lookup all members of this group and record down their names and
03068       // SIDs into the output file.
03069       CountMembers((LPCTSTR)szAnsiName);
03070 
03071       GroupInfo++;
03072    }
03073 
03074    if (Data)
03075       p2NetApiBufferFree(Data);
03076 
03077    return TRUE;
03078 }
03079 
03080 //________________________________________________________________________________
03081 Long_t TWinNTSystem::LookupSID (const char *lpszAccountName, int what,
03082                                 int &groupIdx, int &memberIdx)
03083 {
03084    //
03085    // Take the name and look up a SID so that we can get full
03086    // domain/user information
03087    //
03088    BOOL bRetOp = FALSE;
03089    PSID pSid = NULL;
03090    DWORD dwSidSize, dwDomainNameSize;
03091    BYTE bySidBuffer[MAX_SID_SIZE];
03092    char szDomainName[MAX_NAME_STRING];
03093    SID_NAME_USE sidType;
03094    PUCHAR puchar_SubAuthCount = NULL;
03095    SID_IDENTIFIER_AUTHORITY sid_identifier_authority;
03096    PSID_IDENTIFIER_AUTHORITY psid_identifier_authority = NULL;
03097    unsigned char j = 0;
03098    DWORD dwLastError = 0;
03099 
03100    pSid = (PSID)bySidBuffer;
03101    dwSidSize = sizeof(bySidBuffer);
03102    dwDomainNameSize = sizeof(szDomainName);
03103 
03104    bRetOp = LookupAccountName (
03105             (LPCTSTR)NULL,             // address of string for system name
03106             (LPCTSTR)lpszAccountName,  // address of string for account name
03107             (PSID)pSid,                // address of security identifier
03108             (LPDWORD)&dwSidSize,       // address of size of security identifier
03109             (LPTSTR)szDomainName,      // address of string for referenced domain
03110             (LPDWORD)&dwDomainNameSize,// address of size of domain string
03111             (PSID_NAME_USE)&sidType ); // address of SID-type indicator
03112 
03113    if (bRetOp == FALSE) {
03114       dwLastError = GetLastError();
03115       return -1;  // Unable to obtain Account SID.
03116    }
03117 
03118    bRetOp = IsValidSid((PSID)pSid);
03119 
03120    if (bRetOp == FALSE) {
03121       dwLastError = GetLastError();
03122       return -2;  // SID returned is invalid.
03123    }
03124 
03125    // Obtain via APIs the identifier authority value.
03126    psid_identifier_authority = GetSidIdentifierAuthority ((PSID)pSid);
03127 
03128    // Make a copy of it.
03129    memcpy (&sid_identifier_authority, psid_identifier_authority,
03130        sizeof(SID_IDENTIFIER_AUTHORITY));
03131 
03132    // Determine how many sub-authority values there are in the current SID.
03133    puchar_SubAuthCount = (PUCHAR)GetSidSubAuthorityCount((PSID)pSid);
03134    // Assign it to a more convenient variable.
03135    j = (unsigned char)(*puchar_SubAuthCount);
03136    // Now obtain all the sub-authority values from the current SID.
03137    DWORD dwSubAuth = 0;
03138    PDWORD pdwSubAuth = NULL;
03139    // Obtain the current sub-authority DWORD (referenced by a pointer)
03140    pdwSubAuth = (PDWORD)GetSidSubAuthority (
03141                 (PSID)pSid,  // address of security identifier to query
03142                 (DWORD)j-1); // index of subauthority to retrieve
03143    dwSubAuth = *pdwSubAuth;
03144    if(what == SID_MEMBER) {
03145        fPasswords[memberIdx].pw_uid = dwSubAuth;
03146        fPasswords[memberIdx].pw_gid = fGroups[groupIdx].gr_gid;
03147        fPasswords[memberIdx].pw_group = strdup(fGroups[groupIdx].gr_name);
03148    }
03149    else if(what == SID_GROUP) {
03150        fGroups[groupIdx].gr_gid = dwSubAuth;
03151    }
03152    return 0;
03153 }
03154 
03155 //________________________________________________________________________________
03156 Bool_t TWinNTSystem::CollectMembers(const char *lpszGroupName, int &groupIdx,
03157                                     int &memberIdx)
03158 {
03159    //
03160 
03161 
03162    NET_API_STATUS NetStatus = NERR_Success;
03163    LPBYTE Data = NULL;
03164    DWORD Index = 0, ResumeHandle = 0, Total = 0, i;
03165    LOCALGROUP_MEMBERS_INFO_1 *MemberInfo;
03166    char szAnsiMemberName[256];
03167    char szFullMemberName[256];
03168    char szMemberHomeDir[256];
03169    WCHAR wszGroupName[256];
03170    int iRetOp = 0;
03171    char  act_name[256];
03172    DWORD length = sizeof (act_name);
03173    DWORD dwLastError = 0;
03174    LPUSER_INFO_11  pUI11Buf = NULL;
03175    NET_API_STATUS  nStatus;
03176 
03177    iRetOp = MultiByteToWideChar (
03178             (UINT)CP_ACP,                // code page
03179             (DWORD)MB_PRECOMPOSED,       // character-type options
03180             (LPCSTR)lpszGroupName,       // address of string to map
03181             (int)-1,                     // number of bytes in string
03182             (LPWSTR)wszGroupName,        // address of wide-character buffer
03183             (int)sizeof(wszGroupName) ); // size of buffer
03184 
03185    if (iRetOp == 0) {
03186       dwLastError = GetLastError();
03187       if (Data)
03188          p2NetApiBufferFree(Data);
03189       return FALSE;
03190    }
03191 
03192    GetUserName (act_name, &length);
03193 
03194    // The NetLocalGroupGetMembers() API retrieves a list of the members
03195    // of a particular local group.
03196    NetStatus = p2NetLocalGroupGetMembers (NULL, wszGroupName, 1,
03197                             &Data, 8192, &Index, &Total, &ResumeHandle );
03198 
03199    if (NetStatus != NERR_Success || Data == NULL) {
03200       dwLastError = GetLastError();
03201 
03202       if (dwLastError == ERROR_ENVVAR_NOT_FOUND) {
03203          // This usually means that the current Group has no members.
03204          // We call NetLocalGroupGetMembers() again.
03205          // This time, we set the level to 0.
03206          // We do this just to confirm that the number of members in
03207          // this group is zero.
03208          NetStatus = p2NetLocalGroupGetMembers ( NULL, wszGroupName, 0,
03209                                   &Data, 8192, &Index, &Total, &ResumeHandle );
03210       }
03211 
03212       if (Data)
03213          p2NetApiBufferFree(Data);
03214       return FALSE;
03215    }
03216 
03217    MemberInfo = (LOCALGROUP_MEMBERS_INFO_1 *)Data;
03218    for (i=0; i < Total; i++) {
03219       iRetOp = WideCharToMultiByte (
03220                (UINT)CP_ACP,                     // code page
03221                (DWORD)0,                         // performance and mapping flags
03222                (LPCWSTR)(MemberInfo->lgrmi1_name), // address of wide-char string
03223                (int)-1,                         // number of characters in string
03224                (LPSTR)szAnsiMemberName,       // address of buffer for new string
03225                (int)(sizeof(szAnsiMemberName)), // size of buffer
03226                (LPCSTR)NULL,      // address of default for unmappable characters
03227                (LPBOOL)NULL );      // address of flag set when default char used.
03228 
03229       if (iRetOp == 0) {
03230          dwLastError = GetLastError();
03231       }
03232 
03233       fPasswords[memberIdx].pw_name = strdup(szAnsiMemberName);
03234       fPasswords[memberIdx].pw_passwd = strdup("");
03235       fGroups[groupIdx].gr_mem[i] = strdup(szAnsiMemberName);
03236 
03237       if(fActUser == -1 && !stricmp(fPasswords[memberIdx].pw_name,act_name))
03238                       fActUser = memberIdx;
03239 
03240 
03241       TCHAR szUserName[255]=TEXT("");
03242       MultiByteToWideChar(CP_ACP, 0, szAnsiMemberName, -1, (LPWSTR)szUserName, 255);
03243       //
03244       // Call the NetUserGetInfo function; specify level 10.
03245       //
03246       nStatus = p2NetUserGetInfo(NULL, (LPCWSTR)szUserName, 11, (LPBYTE *)&pUI11Buf);
03247       //
03248       // If the call succeeds, print the user information.
03249       //
03250       if (nStatus == NERR_Success) {
03251          if (pUI11Buf != NULL) {
03252             wsprintf(szFullMemberName,"%S",pUI11Buf->usri11_full_name);
03253             fPasswords[memberIdx].pw_gecos = strdup(szFullMemberName);
03254             wsprintf(szMemberHomeDir,"%S",pUI11Buf->usri11_home_dir);
03255             fPasswords[memberIdx].pw_dir = strdup(szMemberHomeDir);
03256          }
03257       }
03258       if((fPasswords[memberIdx].pw_gecos == NULL) || (strlen(fPasswords[memberIdx].pw_gecos) == 0))
03259          fPasswords[memberIdx].pw_gecos = strdup(fPasswords[memberIdx].pw_name);
03260       if((fPasswords[memberIdx].pw_dir == NULL) || (strlen(fPasswords[memberIdx].pw_dir) == 0))
03261          fPasswords[memberIdx].pw_dir = strdup("c:\\");
03262       //
03263       // Free the allocated memory.
03264       //
03265       if (pUI11Buf != NULL) {
03266          p2NetApiBufferFree(pUI11Buf);
03267          pUI11Buf = NULL;
03268       }
03269 
03270       /* Ensure SHELL is defined. */
03271       if (getenv("SHELL") == NULL)
03272          putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
03273 
03274       /* Set dir and shell from environment variables. */
03275       fPasswords[memberIdx].pw_shell = getenv("SHELL");
03276 
03277       // Find out the SID of the Member.
03278       LookupSID ((LPCTSTR)szAnsiMemberName, SID_MEMBER, groupIdx, memberIdx);
03279       memberIdx++;
03280       MemberInfo++;
03281    }
03282    if(fActUser == -1)  fActUser = 0;
03283 
03284    if (Data)
03285       p2NetApiBufferFree(Data);
03286 
03287    return TRUE;
03288 }
03289 
03290 //________________________________________________________________________________
03291 Bool_t TWinNTSystem::CollectGroups()
03292 {
03293    //
03294 
03295    NET_API_STATUS NetStatus = NERR_Success;
03296    LPBYTE Data = NULL;
03297    DWORD Index = 0, ResumeHandle = 0, Total = 0, i;
03298    LOCALGROUP_INFO_0 *GroupInfo;
03299    char szAnsiName[256];
03300    DWORD dwLastError = 0;
03301    int  iRetOp = 0, iGroupIdx = 0, iMemberIdx = 0;
03302 
03303    NetStatus = p2NetLocalGroupEnum(NULL, 0, &Data, 8192, &Index,
03304                                     &Total, &ResumeHandle );
03305 
03306    if (NetStatus != NERR_Success || Data == NULL) {
03307       dwLastError = GetLastError();
03308       if (Data)
03309          p2NetApiBufferFree(Data);
03310       return FALSE;
03311    }
03312 
03313    GroupInfo = (LOCALGROUP_INFO_0 *)Data;
03314    for (i=0; i < Total; i++) {
03315       // Convert group name from UNICODE to ansi.
03316       iRetOp = WideCharToMultiByte (
03317                (UINT)CP_ACP,                    // code page
03318                (DWORD)0,                        // performance and mapping flags
03319                (LPCWSTR)(GroupInfo->lgrpi0_name), // address of wide-char string
03320                (int)-1,                        // number of characters in string
03321                (LPSTR)szAnsiName,            // address of buffer for new string
03322                (int)(sizeof(szAnsiName)),    // size of buffer
03323                (LPCSTR)NULL,     // address of default for unmappable characters
03324                (LPBOOL)NULL );     // address of flag set when default char used.
03325 
03326       fGroups[iGroupIdx].gr_name = strdup(szAnsiName);
03327       fGroups[iGroupIdx].gr_passwd = strdup("");
03328 
03329       // Find out the SID of the Group.
03330       LookupSID ((LPCTSTR)szAnsiName, SID_GROUP, iGroupIdx, iMemberIdx);
03331       // Now lookup all members of this group and record down their names and
03332       // SIDs into the output file.
03333       CollectMembers((LPCTSTR)szAnsiName, iGroupIdx, iMemberIdx);
03334 
03335       iGroupIdx++;
03336       GroupInfo++;
03337    }
03338 
03339    if (Data)
03340       p2NetApiBufferFree(Data);
03341 
03342    return TRUE;
03343 }
03344 
03345 //______________________________________________________________________________
03346 Int_t TWinNTSystem::GetUid(const char *user)
03347 {
03348    // Returns the user's id. If user = 0, returns current user's id.
03349 
03350    if(!fGroupsInitDone)
03351       InitUsersGroups();
03352 
03353    // Net* API functions not allowed or OS not Windows NT/2000/XP
03354    if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
03355       int   uid;
03356       char  name[256];
03357       DWORD length = sizeof (name);
03358       if (::GetUserName (name, &length)) {
03359          if (stricmp ("administrator", name) == 0)
03360             uid = 0;
03361          else
03362             uid = 123;
03363       }
03364       else {
03365          uid = 123;
03366       }
03367       return uid;
03368    }
03369    if (!user || !user[0])
03370       return fPasswords[fActUser].pw_uid;
03371    else {
03372       struct passwd *pwd = 0;
03373       for(int i=0;i<fNbUsers;i++) {
03374          if (!stricmp (user, fPasswords[i].pw_name)) {
03375             pwd = &fPasswords[i];
03376             break;
03377          }
03378       }
03379       if (pwd)
03380          return pwd->pw_uid;
03381    }
03382    return 0;
03383 }
03384 
03385 //______________________________________________________________________________
03386 Int_t TWinNTSystem::GetEffectiveUid()
03387 {
03388    // Returns the effective user id. The effective id corresponds to the
03389    // set id bit on the file being executed.
03390 
03391    if(!fGroupsInitDone)
03392       InitUsersGroups();
03393 
03394    // Net* API functions not allowed or OS not Windows NT/2000/XP
03395    if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
03396       int   uid;
03397       char  name[256];
03398       DWORD length = sizeof (name);
03399       if (::GetUserName (name, &length)) {
03400          if (stricmp ("administrator", name) == 0)
03401             uid = 0;
03402          else
03403             uid = 123;
03404       }
03405       else {
03406          uid = 123;
03407       }
03408       return uid;
03409    }
03410    return fPasswords[fActUser].pw_uid;
03411 }
03412 
03413 //______________________________________________________________________________
03414 Int_t TWinNTSystem::GetGid(const char *group)
03415 {
03416    // Returns the group's id. If group = 0, returns current user's group.
03417 
03418    if(!fGroupsInitDone)
03419       InitUsersGroups();
03420 
03421    // Net* API functions not allowed or OS not Windows NT/2000/XP
03422    if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
03423       int   gid;
03424       char  name[256];
03425       DWORD length = sizeof (name);
03426       if (::GetUserName (name, &length)) {
03427          if (stricmp ("administrator", name) == 0)
03428             gid = 0;
03429          else
03430             gid = 123;
03431       }
03432       else {
03433          gid = 123;
03434       }
03435       return gid;
03436    }
03437    if (!group || !group[0])
03438       return fPasswords[fActUser].pw_gid;
03439    else {
03440       struct group *grp = 0;
03441       for(int i=0;i<fNbGroups;i++) {
03442          if (!stricmp (group, fGroups[i].gr_name)) {
03443             grp = &fGroups[i];
03444             break;
03445          }
03446       }
03447       if (grp)
03448          return grp->gr_gid;
03449    }
03450    return 0;
03451 }
03452 
03453 //______________________________________________________________________________
03454 Int_t TWinNTSystem::GetEffectiveGid()
03455 {
03456    // Returns the effective group id. The effective group id corresponds
03457    // to the set id bit on the file being executed.
03458 
03459    if(!fGroupsInitDone)
03460       InitUsersGroups();
03461 
03462    // Net* API functions not allowed or OS not Windows NT/2000/XP
03463    if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
03464       int   gid;
03465       char  name[256];
03466       DWORD length = sizeof (name);
03467       if (::GetUserName (name, &length)) {
03468          if (stricmp ("administrator", name) == 0)
03469             gid = 0;
03470          else
03471             gid = 123;
03472       }
03473       else {
03474          gid = 123;
03475       }
03476       return gid;
03477    }
03478    return fPasswords[fActUser].pw_gid;
03479 }
03480 
03481 //______________________________________________________________________________
03482 UserGroup_t *TWinNTSystem::GetUserInfo(Int_t uid)
03483 {
03484    // Returns all user info in the UserGroup_t structure. The returned
03485    // structure must be deleted by the user. In case of error 0 is returned.
03486 
03487    if(!fGroupsInitDone)
03488       InitUsersGroups();
03489 
03490    // Net* API functions not allowed or OS not Windows NT/2000/XP
03491    if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
03492       char  name[256];
03493       DWORD length = sizeof (name);
03494       UserGroup_t *ug = new UserGroup_t;
03495       if (::GetUserName (name, &length)) {
03496          ug->fUser = name;
03497          if (stricmp ("administrator", name) == 0) {
03498             ug->fUid = 0;
03499             ug->fGroup = "administrators";
03500          }
03501          else {
03502             ug->fUid = 123;
03503             ug->fGroup = "users";
03504          }
03505          ug->fGid = ug->fUid;
03506       }
03507       else {
03508          ug->fUser = "unknown";
03509          ug->fGroup = "unknown";
03510          ug->fUid = ug->fGid = 123;
03511       }
03512       ug->fPasswd = "";
03513       ug->fRealName = ug->fUser;
03514       ug->fShell = "command";
03515       return ug;
03516    }
03517    struct passwd *pwd = 0;
03518    if (uid == 0)
03519       pwd = &fPasswords[fActUser];
03520    else {
03521       for (int i = 0; i < fNbUsers; i++) {
03522          if (uid == fPasswords[i].pw_uid) {
03523             pwd = &fPasswords[i];
03524             break;
03525          }
03526       }
03527    }
03528    if (pwd) {
03529       UserGroup_t *ug = new UserGroup_t;
03530       ug->fUid      = pwd->pw_uid;
03531       ug->fGid      = pwd->pw_gid;
03532       ug->fUser     = pwd->pw_name;
03533       ug->fPasswd   = pwd->pw_passwd;
03534       ug->fRealName = pwd->pw_gecos;
03535       ug->fShell    = pwd->pw_shell;
03536       ug->fGroup    = pwd->pw_group;
03537       return ug;
03538    }
03539    return 0;
03540 }
03541 
03542 //______________________________________________________________________________
03543 UserGroup_t *TWinNTSystem::GetUserInfo(const char *user)
03544 {
03545    // Returns all user info in the UserGroup_t structure. If user = 0, returns
03546    // current user's id info. The returned structure must be deleted by the
03547    // user. In case of error 0 is returned.
03548 
03549    return GetUserInfo(GetUid(user));
03550 }
03551 
03552 //______________________________________________________________________________
03553 UserGroup_t *TWinNTSystem::GetGroupInfo(Int_t gid)
03554 {
03555    // Returns all group info in the UserGroup_t structure. The only active
03556    // fields in the UserGroup_t structure for this call are:
03557    //    fGid and fGroup
03558    // The returned structure must be deleted by the user. In case of
03559    // error 0 is returned.
03560 
03561    if(!fGroupsInitDone)
03562       InitUsersGroups();
03563 
03564    // Net* API functions not allowed or OS not Windows NT/2000/XP
03565    if ((!gEnv->GetValue("WinNT.UseNetAPI", 0)) || (::GetVersion() >= 0x80000000)) {
03566       char  name[256];
03567       DWORD length = sizeof (name);
03568       UserGroup_t *gr = new UserGroup_t;
03569       if (::GetUserName (name, &length)) {
03570          if (stricmp ("administrator", name) == 0) {
03571             gr->fGroup = "administrators";
03572             gr->fGid = 0;
03573          }
03574          else {
03575             gr->fGroup = "users";
03576             gr->fGid = 123;
03577          }
03578       }
03579       else {
03580          gr->fGroup = "unknown";
03581          gr->fGid = 123;
03582       }
03583       gr->fUid = 0;
03584       return gr;
03585    }
03586    struct group *grp = 0;
03587    for(int i=0;i<fNbGroups;i++) {
03588       if (gid == fGroups[i].gr_gid) {
03589          grp = &fGroups[i];
03590          break;
03591       }
03592    }
03593    if (grp) {
03594       UserGroup_t *gr = new UserGroup_t;
03595       gr->fUid   = 0;
03596       gr->fGid   = grp->gr_gid;
03597       gr->fGroup = grp->gr_name;
03598       return gr;
03599    }
03600    return 0;
03601 
03602 }
03603 
03604 //______________________________________________________________________________
03605 UserGroup_t *TWinNTSystem::GetGroupInfo(const char *group)
03606 {
03607    // Returns all group info in the UserGroup_t structure. The only active
03608    // fields in the UserGroup_t structure for this call are:
03609    //    fGid and fGroup
03610    // If group = 0, returns current user's group. The returned structure
03611    // must be deleted by the user. In case of error 0 is returned.
03612 
03613    return GetGroupInfo(GetGid(group));
03614 }
03615 
03616 //---- environment manipulation ------------------------------------------------
03617 
03618 //______________________________________________________________________________
03619 void TWinNTSystem::Setenv(const char *name, const char *value)
03620 {
03621    // Set environment variable.
03622 
03623    ::_putenv(Form("%s=%s", name, value));
03624 }
03625 
03626 //______________________________________________________________________________
03627 const char *TWinNTSystem::Getenv(const char *name)
03628 {
03629    // Get environment variable.
03630 
03631    const char *env = ::getenv(name);
03632    if (!env) {
03633       if (::_stricmp(name,"home") == 0 ) {
03634         env = HomeDirectory();
03635       } else if (::_stricmp(name, "rootsys") == 0 ) {
03636         env = gRootDir;
03637       }
03638    }
03639    return env;
03640 }
03641 
03642 //---- Processes ---------------------------------------------------------------
03643 
03644 //______________________________________________________________________________
03645 int TWinNTSystem::Exec(const char *shellcmd)
03646 {
03647    // Execute a command.
03648 
03649    return ::system(shellcmd);
03650 }
03651 
03652 //______________________________________________________________________________
03653 FILE *TWinNTSystem::OpenPipe(const char *command, const char *mode)
03654 {
03655    // Open a pipe.
03656 
03657   return ::_popen(command, mode);
03658 }
03659 
03660 //______________________________________________________________________________
03661 int TWinNTSystem::ClosePipe(FILE *pipe)
03662 {
03663    // Close the pipe.
03664 
03665   return ::_pclose(pipe);
03666 }
03667 
03668 //______________________________________________________________________________
03669 int TWinNTSystem::GetPid()
03670 {
03671    // Get process id.
03672 
03673    return ::getpid();
03674 }
03675 
03676 //______________________________________________________________________________
03677 HANDLE TWinNTSystem::GetProcess()
03678 {
03679   // Get current process handle
03680 
03681   return fhProcess;
03682 }
03683 
03684 //______________________________________________________________________________
03685 void TWinNTSystem::Exit(int code, Bool_t mode)
03686 {
03687    // Exit the application.
03688 
03689    // Insures that the files and sockets are closed before any library is unloaded!
03690    if (gROOT) {
03691       if (gROOT->GetListOfFiles()) gROOT->GetListOfFiles()->Delete("slow");
03692       if (gROOT->GetListOfSockets()) gROOT->GetListOfSockets()->Delete();
03693       if (gROOT->GetListOfMappedFiles()) gROOT->GetListOfMappedFiles()->Delete("slow");
03694       if (gROOT->GetListOfBrowsers()) gROOT->GetListOfBrowsers()->Delete();
03695    }
03696    gVirtualX->CloseDisplay();
03697 
03698    if (mode) {
03699       ::exit(code);
03700    } else {
03701       ::_exit(code);
03702    }
03703 }
03704 
03705 //______________________________________________________________________________
03706 void TWinNTSystem::Abort(int)
03707 {
03708    // Abort the application.
03709 
03710    ::abort();
03711 }
03712 
03713 //---- Standard output redirection ---------------------------------------------
03714 
03715 //______________________________________________________________________________
03716 Int_t TWinNTSystem::RedirectOutput(const char *file, const char *mode,
03717                                    RedirectHandle_t *h)
03718 {
03719    // Redirect standard output (stdout, stderr) to the specified file.
03720    // If the file argument is 0 the output is set again to stderr, stdout.
03721    // The second argument specifies whether the output should be added to the
03722    // file ("a", default) or the file be truncated before ("w").
03723    // This function saves internally the current state into a static structure.
03724    // The call can be made reentrant by specifying the opaque structure pointed
03725    // by 'h', which is filled with the relevant information. The handle 'h'
03726    // obtained on the first call must then be used in any subsequent call,
03727    // included ShowOutput, to display the redirected output.
03728    // Returns 0 on success, -1 in case of error.
03729 
03730    // Instance to be used if the caller does not passes 'h'
03731    static RedirectHandle_t loch;
03732    Int_t rc = 0;
03733 
03734    // Which handle to use ?
03735    RedirectHandle_t *xh = (h) ? h : &loch;
03736 
03737    if (file) {
03738       // Make sure mode makes sense; default "a"
03739       const char *m = (mode[0] == 'a' || mode[0] == 'w') ? mode : "a";
03740 
03741       // Current file size
03742       xh->fReadOffSet = 0;
03743       if (m[0] == 'a') {
03744          // If the file exists, save the current size
03745          FileStat_t st;
03746          if (!gSystem->GetPathInfo(file, st))
03747             xh->fReadOffSet = (st.fSize > 0) ? st.fSize : xh->fReadOffSet;
03748       }
03749       xh->fFile = file;
03750 
03751       // redirect stdout & stderr
03752       if (freopen(file, m, stdout) == 0) {
03753          SysError("RedirectOutput", "could not freopen stdout");
03754          return -1;
03755       }
03756       if (freopen(file, m, stderr) == 0) {
03757          SysError("RedirectOutput", "could not freopen stderr");
03758          freopen("CONOUT$", "a", stdout);
03759          return -1;
03760       }
03761    } else {
03762       // Restore stdout & stderr
03763       fflush(stdout);
03764       if (freopen("CONOUT$", "a", stdout) == 0) {
03765          SysError("RedirectOutput", "could not restore stdout");
03766          rc = -1;
03767       }
03768       fflush(stderr);
03769       if (freopen("CONOUT$", "a", stderr) == 0) {
03770          SysError("RedirectOutput", "could not restore stderr");
03771          rc = -1;
03772       }
03773       // Reset the static instance, if using that
03774       if (xh == &loch)
03775          xh->Reset();
03776    }
03777    return rc;
03778 }
03779 
03780 //---- dynamic loading and linking ---------------------------------------------
03781 
03782 //______________________________________________________________________________
03783 void TWinNTSystem::AddDynamicPath(const char *dir)
03784 {
03785    // Add a new directory to the dynamic path.
03786    
03787    if (dir) {
03788       TString oldpath = DynamicPath(0, kFALSE);
03789       oldpath.Append(";");
03790       oldpath.Append(dir);
03791       DynamicPath(oldpath);
03792    }
03793 }
03794 
03795 //______________________________________________________________________________
03796 const char* TWinNTSystem::GetDynamicPath()
03797 {
03798    // Return the dynamic path (used to find shared libraries).
03799 
03800    return DynamicPath(0, kFALSE);
03801 }
03802 
03803 //______________________________________________________________________________
03804 void TWinNTSystem::SetDynamicPath(const char *path)
03805 {
03806    // Set the dynamic path to a new value.
03807    // If the value of 'path' is zero, the dynamic path is reset to its
03808    // default value.
03809 
03810    if (!path)
03811       DynamicPath(0, kTRUE);
03812    else
03813       DynamicPath(path);
03814 }
03815 
03816 //______________________________________________________________________________
03817 char *TWinNTSystem::DynamicPathName(const char *lib, Bool_t quiet)
03818 {
03819    // Returns the path of a dynamic library (searches for library in the
03820    // dynamic library search path). If no file name extension is provided
03821    // it tries .DLL. Returned string must be deleted.
03822 
03823    char *name;
03824 
03825    int len = strlen(lib);
03826    if (len > 4 && (!stricmp(lib+len-4, ".dll"))) {
03827       name = gSystem->Which(GetDynamicPath(), lib, kReadPermission);
03828    } else {
03829       name = Form("%s.dll", lib);
03830       name = gSystem->Which(GetDynamicPath(), name, kReadPermission);
03831    }
03832 
03833    if (!name && !quiet) {
03834       Error("DynamicPathName",
03835             "%s does not exist in %s,\nor has wrong file extension (.dll)", lib,
03836             GetDynamicPath());
03837    }
03838    return name;
03839 }
03840 
03841 //______________________________________________________________________________
03842 int TWinNTSystem::Load(const char *module, const char *entry, Bool_t system)
03843 {
03844    // Load a shared library. Returns 0 on successful loading, 1 in
03845    // case lib was already loaded and -1 in case lib does not exist
03846    // or in case of error.
03847    return TSystem::Load(module, entry, system);
03848 }
03849 
03850 /* nonstandard extension used : zero-sized array in struct/union */
03851 #pragma warning(push)
03852 #pragma warning(disable:4200)
03853 //______________________________________________________________________________
03854 const char *TWinNTSystem::GetLinkedLibraries()
03855 {
03856    // Get list of shared libraries loaded at the start of the executable.
03857    // Returns 0 in case list cannot be obtained or in case of error.
03858    char winDrive[256];
03859    char winDir[256];
03860    char winName[256];
03861    char winExt[256];
03862 
03863    if (!gApplication) return 0;
03864 
03865    static Bool_t once = kFALSE;
03866    static TString linkedLibs;
03867 
03868    if (!linkedLibs.IsNull())
03869       return linkedLibs;
03870 
03871    if (once)
03872       return 0;
03873 
03874    char *exe = gSystem->Which(Getenv("PATH"), gApplication->Argv(0),
03875                               kExecutePermission);
03876    if (!exe) {
03877       once = kTRUE;
03878       return 0;
03879    }
03880 
03881    HANDLE hFile, hMapping;
03882    void *basepointer;
03883 
03884    if((hFile = CreateFile(exe,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0))==INVALID_HANDLE_VALUE) {
03885       delete [] exe;
03886       return 0;
03887    }
03888    if(!(hMapping = CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT,0,0,0))) {
03889       CloseHandle(hFile);
03890       delete [] exe;
03891       return 0;
03892    }
03893    if(!(basepointer = MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0))) {
03894       CloseHandle(hMapping);
03895       CloseHandle(hFile);
03896       delete [] exe;
03897       return 0;
03898    }
03899 
03900    int sect;
03901    IMAGE_DOS_HEADER *dos_head = (IMAGE_DOS_HEADER *)basepointer;
03902    struct header {
03903       DWORD signature;
03904       IMAGE_FILE_HEADER _head;
03905       IMAGE_OPTIONAL_HEADER opt_head;
03906       IMAGE_SECTION_HEADER section_header[];  // actual number in NumberOfSections
03907    };
03908    struct header *pheader;
03909    const IMAGE_SECTION_HEADER * section_header;
03910 
03911    if(dos_head->e_magic!='ZM') {
03912       delete [] exe;
03913       return 0;
03914    }  // verify DOS-EXE-Header
03915    // after end of DOS-EXE-Header: offset to PE-Header
03916    pheader = (struct header *)((char*)dos_head + dos_head->e_lfanew);
03917 
03918    if(IsBadReadPtr(pheader,sizeof(struct header))) { // start of PE-Header
03919       delete [] exe;
03920       return 0;
03921    }
03922    if(pheader->signature!=IMAGE_NT_SIGNATURE) {      // verify PE format
03923       switch((unsigned short)pheader->signature) {
03924          case IMAGE_DOS_SIGNATURE:
03925             delete [] exe;
03926             return 0;
03927          case IMAGE_OS2_SIGNATURE:
03928             delete [] exe;
03929             return 0;
03930          case IMAGE_OS2_SIGNATURE_LE:
03931             delete [] exe;
03932             return 0;
03933          default: // unknown signature
03934             delete [] exe;
03935             return 0;
03936       }
03937    }
03938 #define isin(address,start,length) ((address)>=(start) && (address)<(start)+(length))
03939    TString odump;
03940    // walk through sections
03941    for(sect=0,section_header=pheader->section_header;
03942        sect<pheader->_head.NumberOfSections;sect++,section_header++) {
03943       int directory;
03944       const void * const section_data =
03945             (char*)basepointer + section_header->PointerToRawData;
03946       for(directory=0;directory<IMAGE_NUMBEROF_DIRECTORY_ENTRIES;directory++) {
03947          if(isin(pheader->opt_head.DataDirectory[directory].VirtualAddress,
03948                  section_header->VirtualAddress,
03949                  section_header->SizeOfRawData)) {
03950             const IMAGE_IMPORT_DESCRIPTOR *stuff_start =
03951                  (IMAGE_IMPORT_DESCRIPTOR *)((char*)section_data +
03952                  (pheader->opt_head.DataDirectory[directory].VirtualAddress -
03953                   section_header->VirtualAddress));
03954             // (virtual address of stuff - virtual address of section) =
03955             // offset of stuff in section
03956             const unsigned stuff_length =
03957                   pheader->opt_head.DataDirectory[directory].Size;
03958             if(directory == IMAGE_DIRECTORY_ENTRY_IMPORT) {
03959                while(!IsBadReadPtr(stuff_start,sizeof(*stuff_start)) &&
03960                       stuff_start->Name) {
03961                   TString dll = (char*)section_data +
03962                                ((DWORD)(stuff_start->Name)) -
03963                                 section_header->VirtualAddress;
03964                   if (dll.EndsWith(".dll")) {
03965                      char *dllPath = DynamicPathName(dll, kTRUE);
03966                      if (dllPath) {
03967                         char *winPath = getenv("windir");
03968                         _splitpath(winPath,winDrive,winDir,winName,winExt);
03969                         if(!strstr(dllPath, winDir)) {
03970                            if (!linkedLibs.IsNull())
03971                               linkedLibs += " ";
03972                            linkedLibs += dllPath;
03973                         }
03974                      }
03975                      delete [] dllPath;
03976                   }
03977                   stuff_start++;
03978                }
03979             }
03980          }
03981       }
03982    }
03983 
03984    UnmapViewOfFile(basepointer);
03985    CloseHandle(hMapping);
03986    CloseHandle(hFile);
03987 
03988    delete [] exe;
03989 
03990    once = kTRUE;
03991 
03992    if (linkedLibs.IsNull())
03993       return 0;
03994 
03995    return linkedLibs;
03996 }
03997 #pragma warning(pop)
03998 
03999 //______________________________________________________________________________
04000 const char *TWinNTSystem::GetLibraries(const char *regexp, const char *options,
04001                                        Bool_t isRegexp)
04002 {
04003    // Return a space separated list of loaded shared libraries.
04004    // This list is of a format suitable for a linker, i.e it may contain
04005    // -Lpathname and/or -lNameOfLib.
04006    // Option can be any of:
04007    //   S: shared libraries loaded at the start of the executable, because
04008    //      they were specified on the link line.
04009    //   D: shared libraries dynamically loaded after the start of the program.
04010    //   L: list the .LIB rather than the .DLL (this is intended for linking)
04011    //      [This options is not the default]
04012 
04013    TString libs(TSystem::GetLibraries(regexp, options, isRegexp));
04014    TString ntlibs;
04015    TString opt = options;
04016 
04017    if ( (opt.First('L')!=kNPOS) ) {
04018       TRegexp separator("[^ \\t\\s]+");
04019       TRegexp user_dll("\\.dll$");
04020       TRegexp user_lib("\\.lib$");
04021       FileStat_t sbuf;
04022       TString s;
04023       Ssiz_t start, index, end;
04024       start = index = end = 0;
04025 
04026       while ((start < libs.Length()) && (index != kNPOS)) {
04027          index = libs.Index(separator, &end, start);
04028          if (index >= 0) {
04029             // Change .dll into .lib and remove the
04030             // path info if it not accessible.
04031             s = libs(index, end);
04032             if (s.Index(user_dll) != kNPOS) {
04033                s.ReplaceAll(".dll",".lib");
04034                if ( GetPathInfo( s, sbuf ) != 0 ) {
04035                   s.Replace( 0, s.Last('/')+1, 0, 0);
04036                   s.Replace( 0, s.Last('\\')+1, 0, 0);
04037                }
04038             } else if (s.Index(user_lib) != kNPOS) {
04039                if ( GetPathInfo( s, sbuf ) != 0 ) {
04040                   s.Replace( 0, s.Last('/')+1, 0, 0);
04041                   s.Replace( 0, s.Last('\\')+1, 0, 0);
04042                }
04043             }
04044             if (!ntlibs.IsNull()) ntlibs.Append(" ");
04045             ntlibs.Append(s);
04046          }
04047          start += end+1;
04048       }
04049    } else {
04050       ntlibs = libs;
04051    }
04052 
04053    fListLibs = ntlibs;
04054    fListLibs.ReplaceAll("/","\\");
04055    return fListLibs;
04056 }
04057 
04058 //---- Time & Date -------------------------------------------------------------
04059 
04060 //______________________________________________________________________________
04061 void TWinNTSystem::AddTimer(TTimer *ti)
04062 {
04063    // Add timer to list of system timers.
04064 
04065    TSystem::AddTimer(ti);
04066 }
04067 
04068 //______________________________________________________________________________
04069 TTimer *TWinNTSystem::RemoveTimer(TTimer *ti)
04070 {
04071    // Remove timer from list of system timers.
04072 
04073    if (!ti) return 0;
04074 
04075    TTimer *t = TSystem::RemoveTimer(ti);
04076    return t;
04077 }
04078 
04079 //______________________________________________________________________________
04080 void TWinNTSystem::TimerThread()
04081 {
04082    // Special Thread to check asynchronous timers.
04083 
04084    while (1) {
04085       if (!fInsideNotify)
04086          DispatchTimers(kFALSE);
04087       ::Sleep(kItimerResolution/2);
04088    }
04089 }
04090 
04091 //______________________________________________________________________________
04092 Bool_t TWinNTSystem::DispatchTimers(Bool_t mode)
04093 {
04094    // Handle and dispatch timers. If mode = kTRUE dispatch synchronous
04095    // timers else a-synchronous timers.
04096 
04097    if (!fTimers) return kFALSE;
04098 
04099    fInsideNotify = kTRUE;
04100 
04101    TOrdCollectionIter it((TOrdCollection*)fTimers);
04102    TTimer *t;
04103    Bool_t  timedout = kFALSE;
04104 
04105    while ((t = (TTimer *) it.Next())) {
04106       // NB: the timer resolution is added in TTimer::CheckTimer()
04107       TTime now = Now();
04108       if (mode && t->IsSync()) {
04109          if (t->CheckTimer(now)) {
04110             timedout = kTRUE;
04111          }
04112       } else if (!mode && t->IsAsync()) {
04113          if (t->CheckTimer(now)) {
04114             timedout = kTRUE;
04115          }
04116       }
04117    }
04118    fInsideNotify = kFALSE;
04119 
04120    return timedout;
04121 }
04122 
04123 const Double_t gTicks = 1.0e-7;
04124 //______________________________________________________________________________
04125 Double_t TWinNTSystem::GetRealTime()
04126 {
04127    //
04128 
04129    union {
04130       FILETIME ftFileTime;
04131       __int64  ftInt64;
04132    } ftRealTime; // time the process has spent in kernel mode
04133 
04134    ::GetSystemTimeAsFileTime(&ftRealTime.ftFileTime);
04135    return (Double_t)ftRealTime.ftInt64 * gTicks;
04136 }
04137 
04138 //______________________________________________________________________________
04139 Double_t TWinNTSystem::GetCPUTime()
04140 {
04141    //
04142 
04143    OSVERSIONINFO OsVersionInfo;
04144 
04145 //*-*         Value                      Platform
04146 //*-*  ----------------------------------------------------
04147 //*-*  VER_PLATFORM_WIN32s              Win32s on Windows 3.1
04148 //*-*  VER_PLATFORM_WIN32_WINDOWS       Win32 on Windows 95
04149 //*-*  VER_PLATFORM_WIN32_NT            Windows NT
04150 //*-*
04151 
04152    OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
04153    GetVersionEx(&OsVersionInfo);
04154    if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
04155       DWORD       ret;
04156       FILETIME    ftCreate,       // when the process was created
04157                   ftExit;         // when the process exited
04158 
04159       union {
04160          FILETIME ftFileTime;
04161          __int64  ftInt64;
04162       } ftKernel; // time the process has spent in kernel mode
04163 
04164       union {
04165          FILETIME ftFileTime;
04166          __int64  ftInt64;
04167       } ftUser;   // time the process has spent in user mode
04168 
04169       HANDLE hThread = GetCurrentThread();
04170       ret = GetThreadTimes (hThread, &ftCreate, &ftExit,
04171                                      &ftKernel.ftFileTime,
04172                                      &ftUser.ftFileTime);
04173       if (ret != TRUE){
04174          ret = ::GetLastError();
04175          ::Error("GetCPUTime", " Error on GetProcessTimes 0x%lx", (int)ret);
04176       }
04177 
04178       // Process times are returned in a 64-bit structure, as the number of
04179       // 100 nanosecond ticks since 1 January 1601.  User mode and kernel mode
04180       // times for this process are in separate 64-bit structures.
04181       // To convert to floating point seconds, we will:
04182       //          Convert sum of high 32-bit quantities to 64-bit int
04183 
04184        return (Double_t) (ftKernel.ftInt64 + ftUser.ftInt64) * gTicks;
04185    } else {
04186       return GetRealTime();
04187    }
04188 }
04189 
04190 //______________________________________________________________________________
04191 TTime TWinNTSystem::Now()
04192 {
04193    // Get current time in milliseconds since 0:00 Jan 1 1995.
04194 
04195    static time_t jan95 = 0;
04196    if (!jan95) {
04197       struct tm tp;
04198       tp.tm_year  = 95;
04199       tp.tm_mon   = 0;
04200       tp.tm_mday  = 1;
04201       tp.tm_hour  = 0;
04202       tp.tm_min   = 0;
04203       tp.tm_sec   = 0;
04204       tp.tm_isdst = -1;
04205 
04206       jan95 = mktime(&tp);
04207       if ((int)jan95 == -1) {
04208          ::SysError("TWinNTSystem::Now", "error converting 950001 0:00 to time_t");
04209          return 0;
04210       }
04211    }
04212 
04213    _timeb now;
04214    _ftime(&now);
04215    return TTime((now.time-(Long_t)jan95)*1000 + now.millitm);
04216 }
04217 
04218 //______________________________________________________________________________
04219 void TWinNTSystem::Sleep(UInt_t milliSec)
04220 {
04221    // Sleep milliSec milli seconds.
04222    // The Sleep function suspends the execution of the CURRENT THREAD for
04223    // a specified interval.
04224 
04225    ::Sleep(milliSec);
04226 }
04227 
04228 //______________________________________________________________________________
04229 Int_t TWinNTSystem::Select(TList *act, Long_t to)
04230 {
04231    // Select on file descriptors. The timeout to is in millisec.
04232    Int_t rc = -4;
04233 
04234    TFdSet rd, wr;
04235    Int_t mxfd = -1;
04236    TIter next(act);
04237    TFileHandler *h = 0;
04238    while ((h = (TFileHandler *) next())) {
04239       Int_t fd = h->GetFd();
04240       if (h->HasReadInterest())
04241          rd.Set(fd);
04242       if (h->HasWriteInterest())
04243          wr.Set(fd);
04244       h->ResetReadyMask();
04245    }
04246    rc = WinNTSelect(&rd, &wr, to);
04247 
04248    // Set readiness bits
04249    if (rc > 0) {
04250       next.Reset();
04251       while ((h = (TFileHandler *) next())) {
04252          Int_t fd = h->GetFd();
04253          if (rd.IsSet(fd))
04254             h->SetReadReady();
04255          if (wr.IsSet(fd))
04256             h->SetWriteReady();
04257       }
04258    }
04259 
04260    return rc;
04261 }
04262 
04263 //______________________________________________________________________________
04264 Int_t TWinNTSystem::Select(TFileHandler *h, Long_t to)
04265 {
04266    // Select on the file descriptor related to file handler h.
04267    // The timeout to is in millisec.
04268    Int_t rc = -4;
04269 
04270    TFdSet rd, wr;
04271    Int_t fd = -1;
04272    if (h) {
04273       fd = h->GetFd();
04274       if (h->HasReadInterest())
04275          rd.Set(fd);
04276       if (h->HasWriteInterest())
04277          wr.Set(fd);
04278       h->ResetReadyMask();
04279       rc = WinNTSelect(&rd, &wr, to);
04280    }
04281 
04282    // Fill output lists, if required
04283    if (rc > 0) {
04284       if (rd.IsSet(fd))
04285          h->SetReadReady();
04286       if (wr.IsSet(fd))
04287          h->SetWriteReady();
04288    }
04289 
04290    return rc;
04291 }
04292 
04293 //---- RPC ---------------------------------------------------------------------
04294 //______________________________________________________________________________
04295 int TWinNTSystem::GetServiceByName(const char *servicename)
04296 {
04297    // Get port # of internet service.
04298 
04299    struct servent *sp;
04300 
04301    if ((sp = ::getservbyname(servicename, kProtocolName)) == 0) {
04302       Error("GetServiceByName", "no service \"%s\" with protocol \"%s\"\n",
04303              servicename, kProtocolName);
04304       return -1;
04305    }
04306    return ::ntohs(sp->s_port);
04307 }
04308 
04309 //______________________________________________________________________________
04310 char *TWinNTSystem::GetServiceByPort(int port)
04311 {
04312 
04313    // Get name of internet service.
04314 
04315    struct servent *sp;
04316 
04317    if ((sp = ::getservbyport(::htons(port), kProtocolName)) == 0) {
04318       return Form("%d", port);
04319    }
04320    return sp->s_name;
04321 }
04322 
04323 //______________________________________________________________________________
04324 TInetAddress TWinNTSystem::GetHostByName(const char *hostname)
04325 {
04326    // Get Internet Protocol (IP) address of host.
04327 
04328    struct hostent *host_ptr;
04329    const char     *host;
04330    int             type;
04331    UInt_t          addr;    // good for 4 byte addresses
04332 
04333    if ((addr = ::inet_addr(hostname)) != INADDR_NONE) {
04334       type = AF_INET;
04335       if ((host_ptr = ::gethostbyaddr((const char *)&addr,
04336                                       sizeof(addr), AF_INET))) {
04337          host = host_ptr->h_name;
04338          TInetAddress a(host, ntohl(addr), type);
04339          UInt_t addr2;
04340          Int_t  i;
04341          for (i = 1; host_ptr->h_addr_list[i]; i++) {
04342             memcpy(&addr2, host_ptr->h_addr_list[i], host_ptr->h_length);
04343             a.AddAddress(ntohl(addr2));
04344          }
04345          for (i = 0; host_ptr->h_aliases[i]; i++)
04346             a.AddAlias(host_ptr->h_aliases[i]);
04347          return a;
04348       } else {
04349          host = "UnNamedHost";
04350       }
04351    } else if ((host_ptr = ::gethostbyname(hostname))) {
04352       // Check the address type for an internet host
04353       if (host_ptr->h_addrtype != AF_INET) {
04354          Error("GetHostByName", "%s is not an internet host\n", hostname);
04355          return TInetAddress();
04356       }
04357       memcpy(&addr, host_ptr->h_addr, host_ptr->h_length);
04358       host = host_ptr->h_name;
04359       type = host_ptr->h_addrtype;
04360       TInetAddress a(host, ntohl(addr), type);
04361       UInt_t addr2;
04362       Int_t  i;
04363       for (i = 1; host_ptr->h_addr_list[i]; i++) {
04364          memcpy(&addr2, host_ptr->h_addr_list[i], host_ptr->h_length);
04365          a.AddAddress(ntohl(addr2));
04366       }
04367       for (i = 0; host_ptr->h_aliases[i]; i++)
04368          a.AddAlias(host_ptr->h_aliases[i]);
04369       return a;
04370    } else {
04371       if (gDebug > 0) Error("GetHostByName", "unknown host %s", hostname);
04372       return TInetAddress(hostname, 0, -1);
04373    }
04374 
04375    return TInetAddress(host, ::ntohl(addr), type);
04376 }
04377 
04378 //______________________________________________________________________________
04379 TInetAddress TWinNTSystem::GetPeerName(int socket)
04380 {
04381    // Get Internet Protocol (IP) address of remote host and port #.
04382 
04383    SOCKET sock = socket;
04384    struct sockaddr_in addr;
04385    int len = sizeof(addr);
04386 
04387    if (::getpeername(sock, (struct sockaddr *)&addr, &len) == SOCKET_ERROR) {
04388       ::SysError("GetPeerName", "getpeername");
04389       return TInetAddress();
04390    }
04391 
04392    struct hostent *host_ptr;
04393    const char *hostname;
04394    int         family;
04395    UInt_t      iaddr;
04396 
04397    if ((host_ptr = ::gethostbyaddr((const char *)&addr.sin_addr,
04398                                    sizeof(addr.sin_addr), AF_INET))) {
04399       memcpy(&iaddr, host_ptr->h_addr, host_ptr->h_length);
04400       hostname = host_ptr->h_name;
04401       family   = host_ptr->h_addrtype;
04402    } else {
04403       memcpy(&iaddr, &addr.sin_addr, sizeof(addr.sin_addr));
04404       hostname = "????";
04405       family   = AF_INET;
04406    }
04407 
04408    return TInetAddress(hostname, ::ntohl(iaddr), family, ::ntohs(addr.sin_port));
04409 }
04410 
04411 //______________________________________________________________________________
04412 TInetAddress TWinNTSystem::GetSockName(int socket)
04413 {
04414    // Get Internet Protocol (IP) address of host and port #.
04415 
04416    SOCKET sock = socket;
04417    struct sockaddr_in addr;
04418    int len = sizeof(addr);
04419 
04420    if (::getsockname(sock, (struct sockaddr *)&addr, &len) == SOCKET_ERROR) {
04421       ::SysError("GetSockName", "getsockname");
04422       return TInetAddress();
04423    }
04424 
04425    struct hostent *host_ptr;
04426    const char *hostname;
04427    int         family;
04428    UInt_t      iaddr;
04429 
04430    if ((host_ptr = ::gethostbyaddr((const char *)&addr.sin_addr,
04431                                    sizeof(addr.sin_addr), AF_INET))) {
04432       memcpy(&iaddr, host_ptr->h_addr, host_ptr->h_length);
04433       hostname = host_ptr->h_name;
04434       family   = host_ptr->h_addrtype;
04435    } else {
04436       memcpy(&iaddr, &addr.sin_addr, sizeof(addr.sin_addr));
04437       hostname = "????";
04438       family   = AF_INET;
04439    }
04440 
04441    return TInetAddress(hostname, ::ntohl(iaddr), family, ::ntohs(addr.sin_port));
04442 }
04443 
04444 //______________________________________________________________________________
04445 int TWinNTSystem::AnnounceUnixService(int port, int backlog)
04446 {
04447    // Announce unix domain service.
04448 
04449    SOCKET sock;
04450 
04451    // Create socket
04452    if ((sock = ::socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
04453       ::SysError("TWinNTSystem::AnnounceUnixService", "socket");
04454       return -1;
04455    }
04456 
04457    struct sockaddr_in inserver;
04458    memset(&inserver, 0, sizeof(inserver));
04459    inserver.sin_family = AF_INET;
04460    inserver.sin_addr.s_addr = ::htonl(INADDR_LOOPBACK);
04461    inserver.sin_port = port;
04462 
04463    // Bind socket
04464    if (port > 0) {
04465       if (::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver)) == SOCKET_ERROR) {
04466          ::SysError("TWinNTSystem::AnnounceUnixService", "bind");
04467          return -2;
04468       }
04469    }
04470    // Start accepting connections
04471    if (::listen(sock, backlog)) {
04472       ::SysError("TWinNTSystem::AnnounceUnixService", "listen");
04473       return -1;
04474    }
04475    return (int)sock;
04476 }
04477 
04478 //______________________________________________________________________________
04479 int TWinNTSystem::AnnounceUnixService(const char *sockpath, int backlog)
04480 {
04481    // Open a socket on path 'sockpath', bind to it and start listening for Unix
04482    // domain connections to it. Returns socket fd or -1.
04483 
04484    if (!sockpath || strlen(sockpath) <= 0) {
04485       ::SysError("TWinNTSystem::AnnounceUnixService", "socket path undefined");
04486       return -1;
04487    }
04488 
04489    struct sockaddr_in myaddr;
04490    FILE * fp;
04491    int len = sizeof myaddr;
04492    int rc;
04493    int sock;
04494 
04495    // Create socket
04496    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
04497       ::SysError("TWinNTSystem::AnnounceUnixService", "socket");
04498       return -1;
04499    }
04500 
04501    memset(&myaddr, 0, sizeof(myaddr));
04502    myaddr.sin_port = 0;
04503    myaddr.sin_family = AF_INET;
04504    myaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
04505 
04506    rc = bind(sock, (struct sockaddr *)&myaddr, len);
04507    if (rc) {
04508       ::SysError("TWinNTSystem::AnnounceUnixService", "bind");
04509       return rc;
04510    }
04511    rc = getsockname(sock, (struct sockaddr *)&myaddr, &len);
04512    if (rc) {
04513       ::SysError("TWinNTSystem::AnnounceUnixService", "getsockname");
04514       return rc;
04515    }
04516    TString socketpath = sockpath;
04517    socketpath.ReplaceAll("/", "\\");
04518    fp = fopen(socketpath, "wb");
04519    if (!fp) {
04520       ::SysError("TWinNTSystem::AnnounceUnixService", "fopen");
04521       return -1;
04522    }
04523    fprintf(fp, "%d", myaddr.sin_port);
04524    fclose(fp);
04525 
04526    // Start accepting connections
04527    if (listen(sock, backlog)) {
04528       ::SysError("TWinNTSystem::AnnounceUnixService", "listen");
04529       return -1;
04530    }
04531 
04532    return sock;
04533 }
04534 
04535 //______________________________________________________________________________
04536 void TWinNTSystem::CloseConnection(int socket, Bool_t force)
04537 {
04538    // Close socket.
04539 
04540    if (socket == -1) return;
04541    SOCKET sock = socket;
04542 
04543    if (force) {
04544       ::shutdown(sock, 2);
04545    }
04546    struct linger linger = {0, 0};
04547    ::setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger));
04548    while (::closesocket(sock) == SOCKET_ERROR && WSAGetLastError() == WSAEINTR) {
04549       TSystem::ResetErrno();
04550    }
04551 }
04552 
04553 //______________________________________________________________________________
04554 int TWinNTSystem::RecvBuf(int sock, void *buf, int length)
04555 {
04556    // Receive a buffer headed by a length indicator. Lenght is the size of
04557    // the buffer. Returns the number of bytes received in buf or -1 in
04558    // case of error.
04559 
04560    Int_t header;
04561 
04562    if (WinNTRecv(sock, &header, sizeof(header), 0) > 0) {
04563       int count = ::ntohl(header);
04564 
04565       if (count > length) {
04566          Error("RecvBuf", "record header exceeds buffer size");
04567          return -1;
04568       } else if (count > 0) {
04569          if (WinNTRecv(sock, buf, count, 0) < 0) {
04570             Error("RecvBuf", "cannot receive buffer");
04571             return -1;
04572          }
04573       }
04574       return count;
04575    }
04576    return -1;
04577 }
04578 
04579 //______________________________________________________________________________
04580 int TWinNTSystem::SendBuf(int sock, const void *buf, int length)
04581 {
04582    // Send a buffer headed by a length indicator. Returns length of sent buffer
04583    // or -1 in case of error.
04584 
04585    Int_t header = ::htonl(length);
04586 
04587    if (WinNTSend(sock, &header, sizeof(header), 0) < 0) {
04588       Error("SendBuf", "cannot send header");
04589       return -1;
04590    }
04591    if (length > 0) {
04592       if (WinNTSend(sock, buf, length, 0) < 0) {
04593          Error("SendBuf", "cannot send buffer");
04594          return -1;
04595       }
04596    }
04597    return length;
04598 }
04599 
04600 //______________________________________________________________________________
04601 int TWinNTSystem::RecvRaw(int sock, void *buf, int length, int opt)
04602 {
04603    // Receive exactly length bytes into buffer. Use opt to receive out-of-band
04604    // data or to have a peek at what is in the buffer (see TSocket). Buffer
04605    // must be able to store at least lenght bytes. Returns the number of
04606    // bytes received (can be 0 if other side of connection was closed) or -1
04607    // in case of error, -2 in case of MSG_OOB and errno == EWOULDBLOCK, -3
04608    // in case of MSG_OOB and errno == EINVAL and -4 in case of kNoBlock and
04609    // errno == EWOULDBLOCK. Returns -5 if pipe broken or reset by peer
04610    // (EPIPE || ECONNRESET).
04611 
04612    int flag;
04613 
04614    switch (opt) {
04615    case kDefault:
04616       flag = 0;
04617       break;
04618    case kOob:
04619       flag = MSG_OOB;
04620       break;
04621    case kPeek:
04622       flag = MSG_PEEK;
04623       break;
04624    case kDontBlock:
04625       flag = -1;
04626       break;
04627    default:
04628       flag = 0;
04629       break;
04630    }
04631 
04632    int n;
04633    if ((n = WinNTRecv(sock, buf, length, flag)) <= 0) {
04634       if (n == -1) {
04635          Error("RecvRaw", "cannot receive buffer");
04636       }
04637       return n;
04638    }
04639    return n;
04640 }
04641 
04642 //______________________________________________________________________________
04643 int TWinNTSystem::SendRaw(int sock, const void *buf, int length, int opt)
04644 {
04645    // Send exactly length bytes from buffer. Use opt to send out-of-band
04646    // data (see TSocket). Returns the number of bytes sent or -1 in case of
04647    // error. Returns -4 in case of kNoBlock and errno == EWOULDBLOCK.
04648    // Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
04649 
04650    int flag;
04651 
04652    switch (opt) {
04653    case kDefault:
04654       flag = 0;
04655       break;
04656    case kOob:
04657       flag = MSG_OOB;
04658       break;
04659    case kDontBlock:
04660       flag = -1;
04661       break;
04662    case kPeek:            // receive only option (see RecvRaw)
04663    default:
04664       flag = 0;
04665       break;
04666    }
04667 
04668    int n;
04669    if ((n = WinNTSend(sock, buf, length, flag)) <= 0) {
04670       if (n == -1 && GetErrno() != EINTR) {
04671          Error("SendRaw", "cannot send buffer");
04672       }
04673       return n;
04674    }
04675    return n;
04676 }
04677 
04678 //______________________________________________________________________________
04679 int  TWinNTSystem::SetSockOpt(int socket, int opt, int value)
04680 {
04681    // Set socket option.
04682 
04683    u_long val = value;
04684    if (socket == -1) return -1;
04685    SOCKET sock = socket;
04686 
04687    switch (opt) {
04688    case kSendBuffer:
04689       if (::setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
04690          ::SysError("SetSockOpt", "setsockopt(SO_SNDBUF)");
04691          return -1;
04692       }
04693       break;
04694    case kRecvBuffer:
04695       if (::setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
04696          ::SysError("SetSockOpt", "setsockopt(SO_RCVBUF)");
04697          return -1;
04698       }
04699       break;
04700    case kOobInline:
04701       if (::setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
04702          SysError("SetSockOpt", "setsockopt(SO_OOBINLINE)");
04703          return -1;
04704       }
04705       break;
04706    case kKeepAlive:
04707       if (::setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
04708          ::SysError("SetSockOpt", "setsockopt(SO_KEEPALIVE)");
04709          return -1;
04710       }
04711       break;
04712    case kReuseAddr:
04713       if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
04714          ::SysError("SetSockOpt", "setsockopt(SO_REUSEADDR)");
04715          return -1;
04716       }
04717       break;
04718    case kNoDelay:
04719       if (::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
04720          ::SysError("SetSockOpt", "setsockopt(TCP_NODELAY)");
04721          return -1;
04722       }
04723       break;
04724    case kNoBlock:
04725       if (::ioctlsocket(sock, FIONBIO, &val) == SOCKET_ERROR) {
04726          ::SysError("SetSockOpt", "ioctl(FIONBIO)");
04727          return -1;
04728       }
04729       break;
04730 #if 0
04731    case kProcessGroup:
04732       if (::ioctl(sock, SIOCSPGRP, &val) == -1) {
04733          ::SysError("SetSockOpt", "ioctl(SIOCSPGRP)");
04734          return -1;
04735       }
04736       break;
04737 #endif
04738    case kAtMark:       // read-only option (see GetSockOpt)
04739    case kBytesToRead:  // read-only option
04740    default:
04741       Error("SetSockOpt", "illegal option (%d)", opt);
04742       return -1;
04743       break;
04744    }
04745    return 0;
04746 }
04747 
04748 //______________________________________________________________________________
04749 int TWinNTSystem::GetSockOpt(int socket, int opt, int *val)
04750 {
04751    // Get socket option.
04752 
04753    if (socket == -1) return -1;
04754    SOCKET sock = socket;
04755 
04756    int optlen = sizeof(*val);
04757 
04758    switch (opt) {
04759    case kSendBuffer:
04760       if (::getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)val, &optlen) == SOCKET_ERROR) {
04761          ::SysError("GetSockOpt", "getsockopt(SO_SNDBUF)");
04762          return -1;
04763       }
04764       break;
04765    case kRecvBuffer:
04766       if (::getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)val, &optlen) == SOCKET_ERROR) {
04767          ::SysError("GetSockOpt", "getsockopt(SO_RCVBUF)");
04768          return -1;
04769       }
04770       break;
04771    case kOobInline:
04772       if (::getsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char*)val, &optlen) == SOCKET_ERROR) {
04773          ::SysError("GetSockOpt", "getsockopt(SO_OOBINLINE)");
04774          return -1;
04775       }
04776       break;
04777    case kKeepAlive:
04778       if (::getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)val, &optlen) == SOCKET_ERROR) {
04779          ::SysError("GetSockOpt", "getsockopt(SO_KEEPALIVE)");
04780          return -1;
04781       }
04782       break;
04783    case kReuseAddr:
04784       if (::getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)val, &optlen) == SOCKET_ERROR) {
04785          ::SysError("GetSockOpt", "getsockopt(SO_REUSEADDR)");
04786          return -1;
04787       }
04788       break;
04789    case kNoDelay:
04790       if (::getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)val, &optlen) == SOCKET_ERROR) {
04791          ::SysError("GetSockOpt", "getsockopt(TCP_NODELAY)");
04792          return -1;
04793       }
04794       break;
04795    case kNoBlock:
04796       {
04797          int flg = 0;
04798          if (sock == INVALID_SOCKET) {
04799             ::SysError("GetSockOpt", "INVALID_SOCKET");
04800          }
04801          return -1;
04802          *val = flg; //  & O_NDELAY;  It is not been defined for WIN32
04803       }
04804       break;
04805 #if 0
04806    case kProcessGroup:
04807       if (::ioctlsocket(sock, SIOCGPGRP, (u_long*)val) == SOCKET_ERROR) {
04808          ::SysError("GetSockOpt", "ioctl(SIOCGPGRP)");
04809          return -1;
04810       }
04811       break;
04812 #endif
04813    case kAtMark:
04814       if (::ioctlsocket(sock, SIOCATMARK, (u_long*)val) == SOCKET_ERROR) {
04815          ::SysError("GetSockOpt", "ioctl(SIOCATMARK)");
04816          return -1;
04817       }
04818       break;
04819    case kBytesToRead:
04820       if (::ioctlsocket(sock, FIONREAD, (u_long*)val) == SOCKET_ERROR) {
04821          ::SysError("GetSockOpt", "ioctl(FIONREAD)");
04822          return -1;
04823       }
04824       break;
04825    default:
04826       Error("GetSockOpt", "illegal option (%d)", opt);
04827       *val = 0;
04828       return -1;
04829       break;
04830    }
04831    return 0;
04832 }
04833 
04834 //______________________________________________________________________________
04835 int TWinNTSystem::ConnectService(const char *servername, int port,
04836                                  int tcpwindowsize)
04837 {
04838    // Connect to service servicename on server servername.
04839 
04840    short  sport;
04841    struct servent *sp;
04842 
04843    if (!strcmp(servername, "unix")) {
04844       return WinNTUnixConnect(port);
04845    }
04846    else if (!gSystem->AccessPathName(servername) || servername[0] == '/' ||
04847             (servername[1] == ':' && servername[2] == '/')) {
04848       return WinNTUnixConnect(servername);
04849    }
04850 
04851    if ((sp = ::getservbyport(::htons(port), kProtocolName))) {
04852       sport = sp->s_port;
04853    } else {
04854       sport = ::htons(port);
04855    }
04856 
04857    TInetAddress addr = gSystem->GetHostByName(servername);
04858    if (!addr.IsValid()) return -1;
04859    UInt_t adr = ::htonl(addr.GetAddress());
04860 
04861    struct sockaddr_in server;
04862    memset(&server, 0, sizeof(server));
04863    memcpy(&server.sin_addr, &adr, sizeof(adr));
04864    server.sin_family = addr.GetFamily();
04865    server.sin_port   = sport;
04866 
04867    // Create socket
04868    SOCKET sock;
04869    if ((sock = ::socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
04870       ::SysError("TWinNTSystem::WinNTConnectTcp", "socket");
04871       return -1;
04872    }
04873 
04874    if (tcpwindowsize > 0) {
04875       gSystem->SetSockOpt((int)sock, kRecvBuffer, tcpwindowsize);
04876       gSystem->SetSockOpt((int)sock, kSendBuffer, tcpwindowsize);
04877    }
04878 
04879    if (::connect(sock, (struct sockaddr*) &server, sizeof(server)) == INVALID_SOCKET) {
04880       //::SysError("TWinNTSystem::UnixConnectTcp", "connect");
04881       ::closesocket(sock);
04882       return -1;
04883    }
04884    return (int) sock;
04885 }
04886 
04887 //______________________________________________________________________________
04888 int TWinNTSystem::WinNTUnixConnect(int port)
04889 {
04890    // Connect to a Unix domain socket.
04891 
04892    struct sockaddr_in myaddr;
04893    int sock;
04894 
04895    memset(&myaddr, 0, sizeof(myaddr));
04896    myaddr.sin_family = AF_INET;
04897    myaddr.sin_port = port;
04898    myaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
04899 
04900    // Open socket
04901    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
04902       ::SysError("TWinNTSystem::WinNTUnixConnect", "socket");
04903       return -1;
04904    }
04905 
04906    while ((connect(sock, (struct sockaddr *)&myaddr, sizeof myaddr)) == -1) {
04907       if (GetErrno() == EINTR)
04908          ResetErrno();
04909       else {
04910          ::SysError("TWinNTSystem::WinNTUnixConnect", "connect");
04911          close(sock);
04912          return -1;
04913       }
04914    }
04915    return sock;
04916 }
04917 
04918 //______________________________________________________________________________
04919 int TWinNTSystem::WinNTUnixConnect(const char *sockpath)
04920 {
04921    // Connect to a Unix domain socket. Returns -1 in case of error.
04922 
04923    FILE *fp;
04924    int port = 0;
04925 
04926    if (!sockpath || strlen(sockpath) <= 0) {
04927       ::SysError("TWinNTSystem::WinNTUnixConnect", "socket path undefined");
04928       return -1;
04929    }
04930    TString socketpath = sockpath;
04931    socketpath.ReplaceAll("/", "\\");
04932    fp = fopen(socketpath.Data(), "rb");
04933    if (!fp) {
04934       ::SysError("TWinNTSystem::WinNTUnixConnect", "fopen");
04935       return -1;
04936    }
04937    fscanf(fp, "%d", &port);
04938    fclose(fp);
04939    /* XXX: set errno in this case */
04940    if (port < 0 || port > 65535) {
04941       ::SysError("TWinNTSystem::WinNTUnixConnect", "invalid port");
04942       return -1;
04943    }
04944    return WinNTUnixConnect(port);
04945 }
04946 
04947 
04948 //______________________________________________________________________________
04949 int TWinNTSystem::OpenConnection(const char *server, int port, int tcpwindowsize)
04950 {
04951    // Open a connection to a service on a server. Returns -1 in case
04952    // connection cannot be opened.
04953    // Use tcpwindowsize to specify the size of the receive buffer, it has
04954    // to be specified here to make sure the window scale option is set (for
04955    // tcpwindowsize > 65KB and for platforms supporting window scaling).
04956    // Is called via the TSocket constructor.
04957 
04958    return ConnectService(server, port, tcpwindowsize);
04959 }
04960 
04961 //______________________________________________________________________________
04962 int TWinNTSystem::AnnounceTcpService(int port, Bool_t reuse, int backlog,
04963                                      int tcpwindowsize)
04964 {
04965    // Announce TCP/IP service.
04966    // Open a socket, bind to it and start listening for TCP/IP connections
04967    // on the port. If reuse is true reuse the address, backlog specifies
04968    // how many sockets can be waiting to be accepted.
04969    // Use tcpwindowsize to specify the size of the receive buffer, it has
04970    // to be specified here to make sure the window scale option is set (for
04971    // tcpwindowsize > 65KB and for platforms supporting window scaling).
04972    // Returns socket fd or -1 if socket() failed, -2 if bind() failed
04973    // or -3 if listen() failed.
04974 
04975    short  sport;
04976    struct servent *sp;
04977    const short kSOCKET_MINPORT = 5000, kSOCKET_MAXPORT = 15000;
04978    short tryport = kSOCKET_MINPORT;
04979 
04980    if ((sp = ::getservbyport(::htons(port), kProtocolName))) {
04981       sport = sp->s_port;
04982    } else {
04983       sport = ::htons(port);
04984    }
04985 
04986    if (port == 0 && reuse) {
04987       ::Error("TWinNTSystem::WinNTTcpService", "cannot do a port scan while reuse is true");
04988       return -1;
04989    }
04990 
04991    if ((sp = ::getservbyport(::htons(port), kProtocolName))) {
04992       sport = sp->s_port;
04993    } else {
04994       sport = ::htons(port);
04995    }
04996 
04997    // Create tcp socket
04998    SOCKET sock;
04999    if ((sock = ::socket(AF_INET, SOCK_STREAM, 0)) < 0) {
05000       ::SysError("TWinNTSystem::WinNTTcpService", "socket");
05001       return -1;
05002    }
05003 
05004    if (reuse) {
05005       gSystem->SetSockOpt((int)sock, kReuseAddr, 1);
05006    }
05007 
05008    if (tcpwindowsize > 0) {
05009       gSystem->SetSockOpt((int)sock, kRecvBuffer, tcpwindowsize);
05010       gSystem->SetSockOpt((int)sock, kSendBuffer, tcpwindowsize);
05011    }
05012 
05013    struct sockaddr_in inserver;
05014    memset(&inserver, 0, sizeof(inserver));
05015    inserver.sin_family = AF_INET;
05016    inserver.sin_addr.s_addr = ::htonl(INADDR_ANY);
05017    inserver.sin_port = sport;
05018 
05019    // Bind socket
05020    if (port > 0) {
05021       if (::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver)) == SOCKET_ERROR) {
05022          ::SysError("TWinNTSystem::WinNTTcpService", "bind");
05023          return -2;
05024       }
05025    } else {
05026       int bret;
05027       do {
05028          inserver.sin_port = ::htons(tryport++);
05029          bret = ::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver));
05030       } while (bret == SOCKET_ERROR && WSAGetLastError() == WSAEADDRINUSE &&
05031                tryport < kSOCKET_MAXPORT);
05032       if (bret == SOCKET_ERROR) {
05033          ::SysError("TWinNTSystem::WinNTTcpService", "bind (port scan)");
05034          return -2;
05035       }
05036    }
05037 
05038    // Start accepting connections
05039    if (::listen(sock, backlog) == SOCKET_ERROR) {
05040       ::SysError("TWinNTSystem::WinNTTcpService", "listen");
05041       return -3;
05042    }
05043    return (int)sock;
05044 }
05045 
05046 //______________________________________________________________________________
05047 int TWinNTSystem::AcceptConnection(int socket)
05048 {
05049    // Accept a connection. In case of an error return -1. In case
05050    // non-blocking I/O is enabled and no connections are available
05051    // return -2.
05052 
05053    int soc = -1;
05054    SOCKET sock = socket;
05055 
05056    while ((soc = ::accept(sock, 0, 0)) == INVALID_SOCKET &&
05057           (::WSAGetLastError() == WSAEINTR)) {
05058       TSystem::ResetErrno();
05059    }
05060 
05061    if (soc == -1) {
05062       if (::WSAGetLastError() == WSAEWOULDBLOCK) {
05063          return -2;
05064       } else {
05065          ::SysError("AcceptConnection", "accept");
05066          return -1;
05067       }
05068    }
05069    return soc;
05070 }
05071 
05072 //---- System, CPU and Memory info ---------------------------------------------
05073 
05074 // !!! using undocumented functions and structures !!!
05075 
05076 #define SystemBasicInformation         0
05077 #define SystemPerformanceInformation   2
05078 
05079 typedef struct
05080 {
05081    DWORD dwUnknown1;
05082    ULONG uKeMaximumIncrement;
05083    ULONG uPageSize;
05084    ULONG uMmNumberOfPhysicalPages;
05085    ULONG uMmLowestPhysicalPage;
05086    ULONG UMmHighestPhysicalPage;
05087    ULONG uAllocationGranularity;
05088    PVOID pLowestUserAddress;
05089    PVOID pMmHighestUserAddress;
05090    ULONG uKeActiveProcessors;
05091    BYTE  bKeNumberProcessors;
05092    BYTE  bUnknown2;
05093    WORD  bUnknown3;
05094 } SYSTEM_BASIC_INFORMATION;
05095 
05096 typedef struct
05097 {
05098    LARGE_INTEGER  liIdleTime;
05099    DWORD    dwSpare[76];
05100 } SYSTEM_PERFORMANCE_INFORMATION;
05101 
05102 typedef struct _PROCESS_MEMORY_COUNTERS {
05103    DWORD cb;
05104    DWORD PageFaultCount;
05105    SIZE_T PeakWorkingSetSize;
05106    SIZE_T WorkingSetSize;
05107    SIZE_T QuotaPeakPagedPoolUsage;
05108    SIZE_T QuotaPagedPoolUsage;
05109    SIZE_T QuotaPeakNonPagedPoolUsage;
05110    SIZE_T QuotaNonPagedPoolUsage;
05111    SIZE_T PagefileUsage;
05112    SIZE_T PeakPagefileUsage;
05113 } PROCESS_MEMORY_COUNTERS, *PPROCESS_MEMORY_COUNTERS;
05114 
05115 typedef LONG (WINAPI *PROCNTQSI) (UINT, PVOID, ULONG, PULONG);
05116 
05117 #define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 + (double)((x).LowPart))
05118 
05119 //_____________________________________________________________________________
05120 static DWORD GetCPUSpeed()
05121 {
05122    // Calculate the CPU clock speed using the 'rdtsc' instruction.
05123    // RDTSC: Read Time Stamp Counter.
05124 
05125    LARGE_INTEGER ulFreq, ulTicks, ulValue, ulStartCounter, ulEAX_EDX;
05126 
05127    // Query for high-resolution counter frequency
05128    // (this is not the CPU frequency):
05129    if (QueryPerformanceFrequency(&ulFreq)) {
05130       // Query current value:
05131       QueryPerformanceCounter(&ulTicks);
05132       // Calculate end value (one second interval);
05133       // this is (current + frequency)
05134       ulValue.QuadPart = ulTicks.QuadPart + ulFreq.QuadPart/10;
05135       // Read CPU time-stamp counter:
05136       __asm RDTSC
05137       // And save in ulEAX_EDX:
05138       __asm mov ulEAX_EDX.LowPart, EAX
05139       __asm mov ulEAX_EDX.HighPart, EDX
05140       // Store starting counter value:
05141       ulStartCounter.QuadPart = ulEAX_EDX.QuadPart;
05142       // Loop for one second (measured with the high-resolution counter):
05143       do {
05144               QueryPerformanceCounter(&ulTicks);
05145       } while (ulTicks.QuadPart <= ulValue.QuadPart);
05146       // Now again read CPU time-stamp counter:
05147       __asm RDTSC
05148       // And save:
05149       __asm mov ulEAX_EDX.LowPart, EAX
05150       __asm mov ulEAX_EDX.HighPart, EDX
05151       // Calculate number of cycles done in interval; 1000000 Hz = 1 MHz
05152       return (DWORD)((ulEAX_EDX.QuadPart - ulStartCounter.QuadPart)/100000);
05153         } else {
05154       // No high-resolution counter present:
05155       return 0;
05156         }
05157 }
05158 
05159 #define BUFSIZE 80
05160 #define SM_SERVERR2 89
05161 typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
05162 
05163 //_____________________________________________________________________________
05164 static char *GetWindowsVersion()
05165 {
05166    OSVERSIONINFOEX osvi;
05167    SYSTEM_INFO si;
05168    PGNSI pGNSI;
05169    BOOL bOsVersionInfoEx;
05170    static char *strReturn = 0;
05171    char temp[512];
05172 
05173    if (strReturn == 0)
05174       strReturn = new char[2048];
05175    else
05176       return strReturn;
05177 
05178    ZeroMemory(&si, sizeof(SYSTEM_INFO));
05179    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
05180 
05181    // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
05182    // If that fails, try using the OSVERSIONINFO structure.
05183 
05184    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
05185 
05186    if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
05187    {
05188       osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
05189       if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
05190          return "";
05191    }
05192 
05193    // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
05194    pGNSI = (PGNSI) GetProcAddress( GetModuleHandle("kernel32.dll"),
05195                                    "GetNativeSystemInfo");
05196    if(NULL != pGNSI)
05197       pGNSI(&si);
05198    else GetSystemInfo(&si);
05199 
05200    switch (osvi.dwPlatformId)
05201    {
05202       // Test for the Windows NT product family.
05203       case VER_PLATFORM_WIN32_NT:
05204 
05205          // Test for the specific product.
05206          if ( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0 )
05207          {
05208             if( osvi.wProductType == VER_NT_WORKSTATION )
05209                 strlcpy(strReturn, "Microsoft Windows Vista ",2048);
05210             else strlcpy(strReturn, "Windows Server \"Longhorn\" " ,2048);
05211          }
05212          if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
05213          {
05214             if( GetSystemMetrics(SM_SERVERR2) )
05215                strlcpy(strReturn, "Microsoft Windows Server 2003 \"R2\" ",2048);
05216             else if( osvi.wProductType == VER_NT_WORKSTATION &&
05217                       si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
05218             {
05219                strlcpy(strReturn, "Microsoft Windows XP Professional x64 Edition ",2048);
05220             }
05221             else strlcpy(strReturn, "Microsoft Windows Server 2003, ",2048);
05222          }
05223          if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
05224             strlcpy(strReturn, "Microsoft Windows XP ",2048);
05225 
05226          if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
05227             strlcpy(strReturn, "Microsoft Windows 2000 ",2048);
05228 
05229          if ( osvi.dwMajorVersion <= 4 )
05230             strlcpy(strReturn, "Microsoft Windows NT ",2048);
05231 
05232          // Test for specific product on Windows NT 4.0 SP6 and later.
05233          if( bOsVersionInfoEx )
05234          {
05235             // Test for the workstation type.
05236             if ( osvi.wProductType == VER_NT_WORKSTATION &&
05237                  si.wProcessorArchitecture!=PROCESSOR_ARCHITECTURE_AMD64)
05238             {
05239                if( osvi.dwMajorVersion == 4 )
05240                   strlcat(strReturn, "Workstation 4.0 ",2048 );
05241                else if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
05242                   strlcat(strReturn, "Home Edition " ,2048);
05243                else strlcat(strReturn, "Professional " ,2048);
05244             }
05245             // Test for the server type.
05246             else if ( osvi.wProductType == VER_NT_SERVER ||
05247                       osvi.wProductType == VER_NT_DOMAIN_CONTROLLER )
05248             {
05249                if(osvi.dwMajorVersion==5 && osvi.dwMinorVersion==2)
05250                {
05251                   if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
05252                   {
05253                       if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
05254                          strlcat(strReturn, "Datacenter Edition for Itanium-based Systems",2048 );
05255                       else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
05256                          strlcat(strReturn, "Enterprise Edition for Itanium-based Systems" ,2048);
05257                   }
05258                   else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
05259                   {
05260                       if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
05261                          strlcat(strReturn, "Datacenter x64 Edition ",2048 );
05262                       else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
05263                          strlcat(strReturn, "Enterprise x64 Edition ",2048 );
05264                       else strlcat(strReturn, "Standard x64 Edition ",2048 );
05265                   }
05266                   else
05267                   {
05268                       if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
05269                          strlcat(strReturn, "Datacenter Edition ",2048 );
05270                       else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
05271                          strlcat(strReturn, "Enterprise Edition ",2048 );
05272                       else if ( osvi.wSuiteMask == VER_SUITE_BLADE )
05273                          strlcat(strReturn, "Web Edition " ,2048);
05274                       else strlcat(strReturn, "Standard Edition ",2048 );
05275                   }
05276                }
05277                else if(osvi.dwMajorVersion==5 && osvi.dwMinorVersion==0)
05278                {
05279                   if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
05280                      strlcat(strReturn, "Datacenter Server ",2048 );
05281                   else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
05282                      strlcat(strReturn, "Advanced Server ",2048 );
05283                   else strlcat(strReturn, "Server ",2048 );
05284                }
05285                else  // Windows NT 4.0
05286                {
05287                   if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
05288                      strlcat(strReturn, "Server 4.0, Enterprise Edition " ,2048);
05289                   else strlcat(strReturn, "Server 4.0 ",2048 );
05290                }
05291             }
05292          }
05293          // Test for specific product on Windows NT 4.0 SP5 and earlier
05294          else
05295          {
05296             HKEY hKey;
05297             TCHAR szProductType[BUFSIZE];
05298             DWORD dwBufLen=BUFSIZE*sizeof(TCHAR);
05299             LONG lRet;
05300 
05301             lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
05302                                  "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
05303                                  0, KEY_QUERY_VALUE, &hKey );
05304             if( lRet != ERROR_SUCCESS )
05305                return "";
05306 
05307             lRet = RegQueryValueEx( hKey, "ProductType", NULL, NULL,
05308                                    (LPBYTE) szProductType, &dwBufLen);
05309             RegCloseKey( hKey );
05310 
05311             if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE*sizeof(TCHAR)) )
05312                return "";
05313 
05314             if ( lstrcmpi( "WINNT", szProductType) == 0 )
05315                strlcat(strReturn, "Workstation " ,2048);
05316             if ( lstrcmpi( "LANMANNT", szProductType) == 0 )
05317                strlcat(strReturn, "Server " ,2048);
05318             if ( lstrcmpi( "SERVERNT", szProductType) == 0 )
05319                strlcat(strReturn, "Advanced Server " ,2048);
05320             snprintf(temp,512, "%d.%d ", osvi.dwMajorVersion, osvi.dwMinorVersion);
05321             strlcat(strReturn, temp,2048);
05322          }
05323 
05324          // Display service pack (if any) and build number.
05325 
05326          if( osvi.dwMajorVersion == 4 &&
05327              lstrcmpi( osvi.szCSDVersion, "Service Pack 6" ) == 0 )
05328          {
05329             HKEY hKey;
05330             LONG lRet;
05331 
05332             // Test for SP6 versus SP6a.
05333             lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
05334                                  "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009",
05335                                  0, KEY_QUERY_VALUE, &hKey );
05336             if( lRet == ERROR_SUCCESS ) {
05337                snprintf(temp, 512, "Service Pack 6a (Build %d)", osvi.dwBuildNumber & 0xFFFF );
05338                strlcat(strReturn, temp,2048 );
05339             }
05340             else // Windows NT 4.0 prior to SP6a
05341             {
05342                snprintf(temp,512, "%s (Build %d)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
05343                strlcat(strReturn, temp,2048 );
05344             }
05345 
05346             RegCloseKey( hKey );
05347          }
05348          else // not Windows NT 4.0
05349          {
05350             snprintf(temp, 512,"%s (Build %d)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
05351             strlcat(strReturn, temp,2048 );
05352          }
05353 
05354          break;
05355 
05356       // Test for the Windows Me/98/95.
05357       case VER_PLATFORM_WIN32_WINDOWS:
05358 
05359          if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
05360          {
05361              strlcpy(strReturn, "Microsoft Windows 95 ",2048);
05362              if (osvi.szCSDVersion[1]=='C' || osvi.szCSDVersion[1]=='B')
05363                 strlcat(strReturn, "OSR2 " ,2048);
05364          }
05365 
05366          if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
05367          {
05368              strlcpy(strReturn, "Microsoft Windows 98 ",2048);
05369              if ( osvi.szCSDVersion[1]=='A' || osvi.szCSDVersion[1]=='B')
05370                 strlcat(strReturn, "SE ",2048 );
05371          }
05372 
05373          if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
05374          {
05375              strlcpy(strReturn, "Microsoft Windows Millennium Edition",2048);
05376          }
05377          break;
05378 
05379       case VER_PLATFORM_WIN32s:
05380          strlcpy(strReturn, "Microsoft Win32s",2048);
05381          break;
05382    }
05383    return strReturn;
05384 }
05385 
05386 //______________________________________________________________________________
05387 static int GetL2CacheSize()
05388 {
05389    // Use assembly to retrieve the L2 cache information ...
05390 
05391    unsigned long eaxreg, ebxreg, ecxreg, edxreg;;
05392 
05393    __try {
05394       _asm {
05395          push eax
05396          push ebx
05397          push ecx
05398          push edx
05399          ; eax = 0x80000006 --> eax: L2 cache information.
05400          mov eax, 0x80000006
05401          cpuid
05402          mov eaxreg, eax
05403          mov ebxreg, ebx
05404          mov ecxreg, ecx
05405          mov edxreg, edx
05406          pop edx
05407          pop ecx
05408          pop ebx
05409          pop eax
05410       }
05411    }
05412    __except (1) {
05413       return 0;
05414    }
05415    // Return the L2 cache size (in KB) from ecxreg
05416    return ((ecxreg & 0xFFFF0000) >> 16);
05417 }
05418 
05419 //______________________________________________________________________________
05420 static void GetWinNTSysInfo(SysInfo_t *sysinfo)
05421 {
05422    // Get system info for Windows NT.
05423 
05424    SYSTEM_PERFORMANCE_INFORMATION   SysPerfInfo;
05425    SYSTEM_INFO sysInfo;
05426    MEMORYSTATUSEX statex;
05427    OSVERSIONINFO OsVersionInfo;
05428    HKEY hKey;
05429    char  szKeyValueString[80];
05430    DWORD szKeyValueDword;
05431    DWORD dwBufLen;
05432    LONG  status;
05433    PROCNTQSI  NtQuerySystemInformation;
05434 
05435    NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(
05436          GetModuleHandle("ntdll"), "NtQuerySystemInformation");
05437 
05438    if (!NtQuerySystemInformation) {
05439       ::Error("GetWinNTSysInfo",
05440               "Error on GetProcAddress(NtQuerySystemInformation)");
05441       return;
05442    }
05443 
05444    status = NtQuerySystemInformation(SystemPerformanceInformation,
05445                                      &SysPerfInfo, sizeof(SysPerfInfo),
05446                                      NULL);
05447    OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
05448    GetVersionEx(&OsVersionInfo);
05449    GetSystemInfo(&sysInfo);
05450    statex.dwLength = sizeof(statex);
05451    if (!GlobalMemoryStatusEx(&statex)) {
05452       ::Error("GetWinNTSysInfo", "Error on GlobalMemoryStatusEx()");
05453       return;
05454    }
05455    sysinfo->fCpus     = sysInfo.dwNumberOfProcessors;
05456    sysinfo->fPhysRam  = (Int_t)(statex.ullTotalPhys  >> 20);
05457    sysinfo->fOS       = GetWindowsVersion();
05458    sysinfo->fModel    = "";
05459    sysinfo->fCpuType  = "";
05460    sysinfo->fCpuSpeed = GetCPUSpeed();
05461    sysinfo->fBusSpeed = 0;  // bus speed in MHz
05462    sysinfo->fL2Cache  = GetL2CacheSize();
05463 
05464    status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System",
05465                          0, KEY_QUERY_VALUE, &hKey);
05466    if (status == ERROR_SUCCESS) {
05467       dwBufLen = sizeof(szKeyValueString);
05468       RegQueryValueEx(hKey, "Identifier", NULL, NULL,(LPBYTE)szKeyValueString,
05469                       &dwBufLen);
05470       sysinfo->fModel = szKeyValueString;
05471       RegCloseKey (hKey);
05472    }
05473    status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
05474                          "Hardware\\Description\\System\\CentralProcessor\\0",
05475                          0, KEY_QUERY_VALUE, &hKey);
05476    if (status == ERROR_SUCCESS) {
05477       dwBufLen = sizeof(szKeyValueString);
05478       status = RegQueryValueEx(hKey, "ProcessorNameString", NULL, NULL,
05479                                (LPBYTE)szKeyValueString, &dwBufLen);
05480       if (status == ERROR_SUCCESS)
05481          sysinfo->fCpuType = szKeyValueString;
05482       dwBufLen = sizeof(DWORD);
05483       status = RegQueryValueEx(hKey,"~MHz",NULL,NULL,(LPBYTE)&szKeyValueDword,
05484                                &dwBufLen);
05485       if ((status == ERROR_SUCCESS) && ((sysinfo->fCpuSpeed <= 0) ||
05486          (sysinfo->fCpuSpeed < (szKeyValueDword >> 1))))
05487          sysinfo->fCpuSpeed = (Int_t)szKeyValueDword;
05488       RegCloseKey (hKey);
05489    }
05490    sysinfo->fCpuType.Remove(TString::kBoth, ' ');
05491    sysinfo->fModel.Remove(TString::kBoth, ' ');
05492 }
05493 
05494 //______________________________________________________________________________
05495 static void GetWinNTCpuInfo(CpuInfo_t *cpuinfo, Int_t sampleTime)
05496 {
05497    // Get CPU stat for Window. Use sampleTime to set the interval over which
05498    // the CPU load will be measured, in ms (default 1000).
05499 
05500    SYSTEM_INFO sysInfo;
05501    Float_t  idle_ratio, kernel_ratio, user_ratio, total_ratio;
05502    FILETIME ft_sys_idle, ft_sys_kernel, ft_sys_user, ft_fun_time;
05503    SYSTEMTIME st_fun_time;
05504 
05505    ULARGE_INTEGER ul_sys_idle, ul_sys_kernel, ul_sys_user;
05506    static ULARGE_INTEGER ul_sys_idleold = {0, 0};
05507    static ULARGE_INTEGER ul_sys_kernelold = {0, 0};
05508    static ULARGE_INTEGER ul_sys_userold = {0, 0};
05509    ULARGE_INTEGER ul_sys_idle_diff, ul_sys_kernel_diff, ul_sys_user_diff;
05510 
05511    ULARGE_INTEGER ul_fun_time;
05512    ULARGE_INTEGER ul_fun_timeold = {0, 0};
05513    ULARGE_INTEGER ul_fun_time_diff;
05514 
05515    typedef BOOL (__stdcall *GetSystemTimesProc)( LPFILETIME lpIdleTime,
05516                  LPFILETIME lpKernelTime, LPFILETIME lpUserTime );
05517    static GetSystemTimesProc pGetSystemTimes = 0;
05518 
05519    HMODULE hModImagehlp = LoadLibrary( "Kernel32.dll" );
05520    if (!hModImagehlp) {
05521       ::Error("GetWinNTCpuInfo", "Error on LoadLibrary(Kernel32.dll)");
05522       return;
05523    }
05524 
05525    pGetSystemTimes = (GetSystemTimesProc) GetProcAddress( hModImagehlp,
05526                       "GetSystemTimes" );
05527    if (!pGetSystemTimes) {
05528       ::Error("GetWinNTCpuInfo", "Error on GetProcAddress(GetSystemTimes)");
05529       return;
05530    }
05531    GetSystemInfo(&sysInfo);
05532 
05533 again:
05534    pGetSystemTimes(&ft_sys_idle,&ft_sys_kernel,&ft_sys_user);
05535    GetSystemTime(&st_fun_time);
05536    SystemTimeToFileTime(&st_fun_time,&ft_fun_time);
05537 
05538    memcpy(&ul_sys_idle, &ft_sys_idle, sizeof(FILETIME));
05539    memcpy(&ul_sys_kernel, &ft_sys_kernel, sizeof(FILETIME));
05540    memcpy(&ul_sys_user, &ft_sys_user, sizeof(FILETIME));
05541    memcpy(&ul_fun_time, &ft_fun_time, sizeof(FILETIME));
05542 
05543    ul_sys_idle_diff.QuadPart   = ul_sys_idle.QuadPart -
05544                                  ul_sys_idleold.QuadPart;
05545    ul_sys_kernel_diff.QuadPart = ul_sys_kernel.QuadPart -
05546                                  ul_sys_kernelold.QuadPart;
05547    ul_sys_user_diff.QuadPart   = ul_sys_user.QuadPart -
05548                                  ul_sys_userold.QuadPart;
05549 
05550    ul_fun_time_diff.QuadPart = ul_fun_time.QuadPart -
05551                                ul_fun_timeold.QuadPart;
05552 
05553    ul_sys_idleold.QuadPart   = ul_sys_idle.QuadPart;
05554    ul_sys_kernelold.QuadPart = ul_sys_kernel.QuadPart;
05555    ul_sys_userold.QuadPart   = ul_sys_user.QuadPart;
05556 
05557    if (ul_fun_timeold.QuadPart == 0) {
05558       Sleep(sampleTime);
05559       ul_fun_timeold.QuadPart = ul_fun_time.QuadPart;
05560       goto again;
05561    }
05562    ul_fun_timeold.QuadPart = ul_fun_time.QuadPart;
05563 
05564    idle_ratio = (Float_t)(Li2Double(ul_sys_idle_diff)/
05565                           Li2Double(ul_fun_time_diff))*100.0;
05566    user_ratio = (Float_t)(Li2Double(ul_sys_user_diff)/
05567                           Li2Double(ul_fun_time_diff))*100.0;
05568    kernel_ratio = (Float_t)(Li2Double(ul_sys_kernel_diff)/
05569                             Li2Double(ul_fun_time_diff))*100.0;
05570    idle_ratio /= (Float_t)sysInfo.dwNumberOfProcessors;
05571    user_ratio /= (Float_t)sysInfo.dwNumberOfProcessors;
05572    kernel_ratio /= (Float_t)sysInfo.dwNumberOfProcessors;
05573    total_ratio = 100.0 - idle_ratio;
05574 
05575    cpuinfo->fLoad1m  = 0; // cpu load average over 1 m
05576    cpuinfo->fLoad5m  = 0; // cpu load average over 5 m
05577    cpuinfo->fLoad15m = 0; // cpu load average over 15 m
05578    cpuinfo->fUser    = user_ratio; // cpu user load in percentage
05579    cpuinfo->fSys     = kernel_ratio; // cpu sys load in percentage
05580    cpuinfo->fTotal   = total_ratio; // cpu user+sys load in percentage
05581    cpuinfo->fIdle    = idle_ratio; // cpu idle percentage
05582 }
05583 
05584 //______________________________________________________________________________
05585 static void GetWinNTMemInfo(MemInfo_t *meminfo)
05586 {
05587    // Get VM stat for Windows NT.
05588 
05589    Long64_t total, used, free, swap_total, swap_used, swap_avail;
05590    MEMORYSTATUSEX statex;
05591    statex.dwLength = sizeof(statex);
05592    if (!GlobalMemoryStatusEx(&statex)) {
05593       ::Error("GetWinNTMemInfo", "Error on GlobalMemoryStatusEx()");
05594       return;
05595    }
05596    used  = (Long64_t)(statex.ullTotalPhys - statex.ullAvailPhys);
05597    free  = (Long64_t) statex.ullAvailPhys;
05598    total = (Long64_t) statex.ullTotalPhys;
05599 
05600    meminfo->fMemTotal  = (Int_t) (total >> 20); // divide by 1024 * 1024
05601    meminfo->fMemUsed   = (Int_t) (used >> 20);
05602    meminfo->fMemFree   = (Int_t) (free >> 20);
05603 
05604    swap_total = (Long64_t)(statex.ullTotalPageFile - statex.ullTotalPhys);
05605    swap_avail = (Long64_t)(statex.ullAvailPageFile - statex.ullAvailPhys);
05606    swap_used  = swap_total - swap_avail;
05607 
05608    meminfo->fSwapTotal = (Int_t) (swap_total >> 20);
05609    meminfo->fSwapUsed  = (Int_t) (swap_used >> 20);
05610    meminfo->fSwapFree  = (Int_t) (swap_avail >> 20);
05611 }
05612 
05613 //______________________________________________________________________________
05614 static void GetWinNTProcInfo(ProcInfo_t *procinfo)
05615 {
05616    // Get process info for this process on Windows NT.
05617 
05618    PROCESS_MEMORY_COUNTERS pmc;
05619    FILETIME    starttime, exittime, kerneltime, usertime;
05620    timeval     ru_stime, ru_utime;
05621    ULARGE_INTEGER li;
05622 
05623    typedef BOOL (__stdcall *GetProcessMemoryInfoProc)( HANDLE Process,
05624                  PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb );
05625    static GetProcessMemoryInfoProc pGetProcessMemoryInfo = 0;
05626 
05627    HMODULE hModImagehlp = LoadLibrary( "Psapi.dll" );
05628    if (!hModImagehlp) {
05629       ::Error("GetWinNTProcInfo", "Error on LoadLibrary(Psapi.dll)");
05630       return;
05631    }
05632 
05633    pGetProcessMemoryInfo = (GetProcessMemoryInfoProc) GetProcAddress(
05634                             hModImagehlp, "GetProcessMemoryInfo" );
05635    if (!pGetProcessMemoryInfo) {
05636       ::Error("GetWinNTProcInfo",
05637               "Error on GetProcAddress(GetProcessMemoryInfo)");
05638       return;
05639    }
05640 
05641    if ( pGetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) ) {
05642       procinfo->fMemResident = pmc.WorkingSetSize / 1024;
05643       procinfo->fMemVirtual  = pmc.PagefileUsage / 1024;
05644    }
05645    if ( GetProcessTimes(GetCurrentProcess(), &starttime, &exittime,
05646       &kerneltime, &usertime)) {
05647 
05648       /* Convert FILETIMEs (0.1 us) to struct timeval */
05649       memcpy(&li, &kerneltime, sizeof(FILETIME));
05650       li.QuadPart /= 10L;         /* Convert to microseconds */
05651       ru_stime.tv_sec = li.QuadPart / 1000000L;
05652       ru_stime.tv_usec = li.QuadPart % 1000000L;
05653 
05654       memcpy(&li, &usertime, sizeof(FILETIME));
05655       li.QuadPart /= 10L;         /* Convert to microseconds */
05656       ru_utime.tv_sec = li.QuadPart / 1000000L;
05657       ru_utime.tv_usec = li.QuadPart % 1000000L;
05658 
05659       procinfo->fCpuUser = (Float_t)(ru_utime.tv_sec) +
05660                            ((Float_t)(ru_utime.tv_usec) / 1000000.);
05661       procinfo->fCpuSys  = (Float_t)(ru_stime.tv_sec) +
05662                            ((Float_t)(ru_stime.tv_usec) / 1000000.);
05663    }
05664 }
05665 
05666 //______________________________________________________________________________
05667 Int_t TWinNTSystem::GetSysInfo(SysInfo_t *info) const
05668 {
05669    // Returns static system info, like OS type, CPU type, number of CPUs
05670    // RAM size, etc into the SysInfo_t structure. Returns -1 in case of error,
05671    // 0 otherwise.
05672 
05673    if (!info) return -1;
05674    GetWinNTSysInfo(info);
05675    return 0;
05676 }
05677 
05678 //______________________________________________________________________________
05679 Int_t TWinNTSystem::GetCpuInfo(CpuInfo_t *info, Int_t sampleTime) const
05680 {
05681    // Returns cpu load average and load info into the CpuInfo_t structure.
05682    // Returns -1 in case of error, 0 otherwise. Use sampleTime to set the
05683    // interval over which the CPU load will be measured, in ms (default 1000).
05684 
05685    if (!info) return -1;
05686    GetWinNTCpuInfo(info, sampleTime);
05687    return 0;
05688 }
05689 
05690 //______________________________________________________________________________
05691 Int_t TWinNTSystem::GetMemInfo(MemInfo_t *info) const
05692 {
05693    // Returns ram and swap memory usage info into the MemInfo_t structure.
05694    // Returns -1 in case of error, 0 otherwise.
05695 
05696    if (!info) return -1;
05697    GetWinNTMemInfo(info);
05698    return 0;
05699 }
05700 
05701 //______________________________________________________________________________
05702 Int_t TWinNTSystem::GetProcInfo(ProcInfo_t *info) const
05703 {
05704    // Returns cpu and memory used by this process into the ProcInfo_t structure.
05705    // Returns -1 in case of error, 0 otherwise.
05706 
05707    if (!info) return -1;
05708    GetWinNTProcInfo(info);
05709    return 0;
05710 }

Generated on Tue Jul 5 14:12:04 2011 for ROOT_528-00b_version by  doxygen 1.5.1