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