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