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