ef38d808fad82c5dc72aa32a075d1b0ec978d102
[occt.git] / src / OSD / OSD_WNT.cxx
1 // Created by: PLOTNIKOV Eugeny
2 // Copyright (c) 1996-1999 Matra Datavision
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #ifdef _WIN32
17
18 /******************************************************************************/
19 /* File:      OSD_WNT.cxx                                                     */
20 /* Purpose:   Security management routines ( more convinient than WIN32       */
21 /*            ones ) and other convinient functions.                          */
22 /******************************************************************************/
23 /***/
24 #include <OSD_WNT.hxx>
25
26 #include <strsafe.h>
27 #include <wchar.h>
28 #include <stdlib.h>
29
30 #include <Standard_Macro.hxx>
31
32 /***/
33 #ifndef OCCT_UWP
34 static void Init ( void );
35 /***/
36 class Init_OSD_WNT {  // provides initialization
37
38  public:
39
40   Init_OSD_WNT () { Init (); }
41
42 }; // end Init_OSD_WNT
43
44 static Init_OSD_WNT initOsdWnt;
45 #endif
46 /***/
47 static BOOL   fInit = FALSE;
48 static PSID*  predefinedSIDs;
49 static HANDLE hHeap;
50 /***/
51 static MOVE_DIR_PROC     _move_dir_proc;
52 static COPY_DIR_PROC     _copy_dir_proc;
53 static RESPONSE_DIR_PROC _response_dir_proc;
54 /***/
55 #define PREDEFINED_SIDs_COUNT           9
56 #define UNIVERSAL_PREDEFINED_SIDs_COUNT 5
57 /***/
58 #define SID_INTERACTIVE   0
59 #define SID_NETWORK       1
60 #define SID_LOCAL         2
61 #define SID_DIALUP        3
62 #define SID_BATCH         4
63 #define SID_CREATOR_OWNER 5
64 #define SID_ADMIN         6
65 #define SID_WORLD         7
66 #define SID_NULL          8
67 /***/
68 #ifndef OCCT_UWP
69 // None of the existing security APIs are supported in a UWP applications
70 /******************************************************************************/
71 /* Function : AllocSD                                                       */
72 /* Purpose  : Allocates and initializes security identifier                 */
73 /* Returns  : Pointer to allocated SID on success, NULL otherwise           */
74 /* Warning  : Allocated SID must be deallocated by 'FreeSD' function        */
75 /******************************************************************************/
76 /***/
77 PSECURITY_DESCRIPTOR AllocSD ( void ) {
78
79  PSECURITY_DESCRIPTOR retVal =
80   ( PSECURITY_DESCRIPTOR )HeapAlloc (
81                            hHeap, 0, sizeof ( SECURITY_DESCRIPTOR )
82                           );
83
84  if ( retVal != NULL &&
85       !InitializeSecurityDescriptor ( retVal, SECURITY_DESCRIPTOR_REVISION )
86  ) {
87  
88   HeapFree (  hHeap, 0, ( PVOID )retVal  );
89   retVal = NULL;
90  
91  }  /* end if */
92
93  return retVal; 
94
95 }  /* end AllocSD */
96 /***/
97 /******************************************************************************/
98 /* Function : FreeSD                                                        */
99 /* Purpose  : Deallocates security identifier which was allocated by the    */
100 /*            'AllocSD' function                                            */
101 /******************************************************************************/
102 /***/
103 void FreeSD ( PSECURITY_DESCRIPTOR pSD ) {
104
105  BOOL   fPresent;
106  BOOL   fDaclDefaulted;
107  PACL   pACL;
108  
109  if (  GetSecurityDescriptorDacl ( pSD, &fPresent, &pACL, &fDaclDefaulted ) &&
110        fPresent
111  )
112
113   HeapFree (  hHeap, 0, ( PVOID )pACL  );
114
115  HeapFree (  hHeap, 0, ( PVOID )pSD  );
116
117 }  /* end FreeSD */
118 /***/
119 /******************************************************************************/
120 /* Function : GetTokenInformationEx                                         */
121 /* Purpose  : Allocates and fills out access token                          */
122 /* Returns  : Pointer to the access token on success, NULL otherwise        */
123 /* Warning  : Allocated access token  must be deallocated by                */
124 /*            'FreeTokenInformation' function                               */
125 /******************************************************************************/
126 /***/
127
128 #if defined(__CYGWIN32__) || defined(__MINGW32__)
129 #define __try
130 #define __finally
131 #define __leave return buffer
132 #endif
133
134 LPVOID GetTokenInformationEx ( HANDLE hToken, TOKEN_INFORMATION_CLASS tic ) {
135
136  DWORD  errVal;
137  DWORD  dwSize;
138  DWORD  dwSizeNeeded = 0;
139  LPVOID buffer       = NULL;
140  BOOL   fOK          = FALSE;
141
142  __try {
143
144   do {
145
146    dwSize = dwSizeNeeded;
147    errVal = ERROR_SUCCESS;
148  
149    if (  !GetTokenInformation ( hToken, tic, buffer, dwSize, &dwSizeNeeded )  ) {
150
151     if (   (  errVal = GetLastError ()  ) != ERROR_INSUFFICIENT_BUFFER   )
152         
153      __leave;
154
155     if (  ( buffer = HeapAlloc (  hHeap, 0, dwSizeNeeded  ) ) == NULL  )
156
157      __leave;
158
159    }  /* end if */
160  
161   } while ( errVal != ERROR_SUCCESS );
162
163   fOK = TRUE;
164
165  }  /* end __try */
166
167  __finally {
168  
169   if ( !fOK && buffer != NULL ) {
170   
171    HeapFree ( hHeap, 0, buffer );
172    buffer = NULL;
173   
174   }  /* end if */
175  
176  }  /* end __finally */
177
178 #ifdef VAC
179 leave: ;     // added for VisualAge
180 #endif
181
182  return buffer;
183
184 }  /* end GetTokenInformationEx */
185
186 #if defined(__CYGWIN32__) || defined(__MINGW32__)
187 #undef __try
188 #undef __finally
189 #undef __leave
190 #endif
191
192 /***/
193 /******************************************************************************/
194 /* Function : FreeTokenInformation                                          */
195 /* Purpose  : Deallocates access token which was allocated by the           */
196 /*            'GetTokenInformationEx' function                              */
197 /******************************************************************************/
198 /***/
199 void FreeTokenInformation ( LPVOID lpvTkInfo ) {
200
201  HeapFree (  hHeap, 0, lpvTkInfo  );
202
203 }  /* end FreeTokenInformation */
204 /***/
205 /******************************************************************************/
206 /* Function : Init                                                          */
207 /* Purpose  : Allocates and initializes predefined security identifiers     */
208 /* Warning  : Generates 'STATUS_NO_MEMORY' software exception if there are  */
209 /*            insufficient of memory. This exception can be caught by using */
210 /*            software exception handling ( SEH ) mechanism                 */
211 /*            ( __try / __except )                                          */
212 /******************************************************************************/
213 /***/
214 static void Init ( void ) {
215
216  SID_IDENTIFIER_AUTHORITY sidIDAnull    = SECURITY_NULL_SID_AUTHORITY;
217  SID_IDENTIFIER_AUTHORITY sidIDAworld   = SECURITY_WORLD_SID_AUTHORITY;
218  SID_IDENTIFIER_AUTHORITY sidIDANT      = SECURITY_NT_AUTHORITY;
219  SID_IDENTIFIER_AUTHORITY sidIDAlocal   = SECURITY_LOCAL_SID_AUTHORITY;
220  SID_IDENTIFIER_AUTHORITY sidIDAcreator = SECURITY_CREATOR_SID_AUTHORITY;
221
222  if ( !fInit ) {
223
224   predefinedSIDs = ( PSID* )HeapAlloc (
225                              hHeap = GetProcessHeap (),
226                              HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY,
227                              PREDEFINED_SIDs_COUNT * sizeof ( PSID* )
228                             );
229
230   AllocateAndInitializeSid (
231    &sidIDANT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
232    0, 0, 0, 0, 0, 0, &predefinedSIDs[ SID_ADMIN ]
233   );
234
235   AllocateAndInitializeSid (
236    &sidIDAworld, 1, SECURITY_WORLD_RID,
237    0, 0, 0, 0, 0, 0, 0, &predefinedSIDs[ SID_WORLD ]
238   );
239
240   AllocateAndInitializeSid (
241    &sidIDANT, 1, SECURITY_INTERACTIVE_RID,
242    0, 0, 0, 0, 0, 0, 0, &predefinedSIDs[ SID_INTERACTIVE ]
243   );
244
245   AllocateAndInitializeSid (
246    &sidIDANT, 1, SECURITY_NETWORK_RID,
247    0, 0, 0, 0, 0, 0, 0, &predefinedSIDs[ SID_NETWORK ]
248   );
249
250   AllocateAndInitializeSid (
251    &sidIDAlocal, 1, SECURITY_LOCAL_RID,
252    0, 0, 0, 0, 0, 0, 0, &predefinedSIDs[ SID_LOCAL ]
253   );
254
255   AllocateAndInitializeSid (
256    &sidIDANT, 1, SECURITY_DIALUP_RID,
257    0, 0, 0, 0, 0, 0, 0, &predefinedSIDs[ SID_DIALUP ]
258   );
259
260   AllocateAndInitializeSid (
261    &sidIDANT, 1, SECURITY_BATCH_RID,
262    0, 0, 0, 0, 0, 0, 0, &predefinedSIDs[ SID_BATCH ]
263   );
264
265   AllocateAndInitializeSid (
266    &sidIDAcreator, 1, SECURITY_CREATOR_OWNER_RID,
267    0, 0, 0, 0, 0, 0, 0, &predefinedSIDs[ SID_CREATOR_OWNER ]
268   );
269
270   AllocateAndInitializeSid (
271    &sidIDAnull, 1, SECURITY_NULL_RID,
272    0, 0, 0, 0, 0, 0, 0, &predefinedSIDs[ SID_NULL ]
273   );
274
275   fInit = TRUE;
276
277  }  /* end if */
278
279 }  /* end init */
280 /***/
281 /******************************************************************************/
282 /* Function : PredefinedSid                                                 */
283 /* Purpose  : Checks whether specified SID predefined or not                */
284 /* Returns  : TRUE if specified SID is predefined, FALSE otherwise          */
285 /******************************************************************************/
286 /***/
287 BOOL PredefinedSid ( PSID pSID ) {
288
289  int i;
290
291  for ( i = 0; i < PREDEFINED_SIDs_COUNT; ++i )
292  
293   if (  EqualSid ( pSID, predefinedSIDs[ i ] )  )
294
295    return TRUE;
296  
297  return FALSE;
298
299 }  /* end PredefinedSid */
300 /***/
301 /******************************************************************************/
302 /* Function : NtPredefinedSid                                               */
303 /* Purpose  : Checks whether specified SID universal or not                 */
304 /* Returns  : TRUE if specified SID is NOT universal, FALSE otherwise       */
305 /******************************************************************************/
306 /***/
307 BOOL NtPredefinedSid ( PSID pSID ) {
308
309  int                       i;
310  PSID_IDENTIFIER_AUTHORITY pTestIDA;
311  SID_IDENTIFIER_AUTHORITY  ntIDA = SECURITY_NT_AUTHORITY;
312  PDWORD                    pdwTestSA;
313
314  for ( i = 0; i < UNIVERSAL_PREDEFINED_SIDs_COUNT; ++i )
315
316   if (  EqualSid ( pSID, predefinedSIDs[ i ] )  )
317
318    return TRUE;
319
320  pTestIDA = GetSidIdentifierAuthority ( pSID );
321
322  if (   memcmp (  pTestIDA, &ntIDA, sizeof ( SID_IDENTIFIER_AUTHORITY )  ) == 0   ) {
323  
324   pdwTestSA = GetSidSubAuthority ( pSID, 0 );
325
326   if ( *pdwTestSA == SECURITY_LOGON_IDS_RID )
327
328    return TRUE;
329      
330  }  /* end if */
331
332  return FALSE;
333
334 }  /* end NtPredefinedSid */
335 /***/
336 /******************************************************************************/
337 /* Function : AdminSid                                                      */
338 /* Purpose  : Returns SID of the administrative user account                */
339 /******************************************************************************/
340 /***/
341 PSID AdminSid ( void ) {
342
343  return predefinedSIDs[ SID_ADMIN ];
344
345 }  /* end AdminSid */
346 /***/
347 /******************************************************************************/
348 /* Function : WorldSid                                                      */
349 /* Purpose  : Returns SID of group that includes all users                  */
350 /******************************************************************************/
351 /***/
352 PSID WorldSid ( void ) {
353
354  return predefinedSIDs[ SID_WORLD ];
355
356 }  /* end WorldSid */
357 /***/
358 /******************************************************************************/
359 /* Function : InteractiveSid                                                */
360 /* Purpose  : Returns SID of group that includes all users logged on for    */
361 /*            interactive operation                                         */
362 /******************************************************************************/
363 /***/
364 PSID InteractiveSid ( void ) {
365
366  return predefinedSIDs[ SID_INTERACTIVE ];
367
368 }  /* end InteractiveSID */
369 /***/
370 /******************************************************************************/
371 /* Function : NetworkSid                                                    */
372 /* Purpose  : Returns SID of group that includes all users logged on across */
373 /*            a network                                                     */
374 /******************************************************************************/
375 /***/
376 PSID NetworkSid ( void ) {
377
378  return predefinedSIDs[ SID_NETWORK ];
379
380 }  /* end NetworkSid */
381 /***/
382 /******************************************************************************/
383 /* Function : LocalSid                                                      */
384 /* Purpose  : Returns SID of group that includes all users logged on locally*/
385 /******************************************************************************/
386 /***/
387 PSID LocalSid ( void ) {
388
389  return predefinedSIDs[ SID_LOCAL ];
390
391 }  /* end LocalSid */
392 /***/
393 /******************************************************************************/
394 /* Function : DialupSid                                                     */
395 /* Purpose  : Returns SID of group that includes all users logged on to     */
396 /*            terminals using a dialup modem                                */
397 /******************************************************************************/
398 /***/
399 PSID DialupSid ( void ) {
400
401  return predefinedSIDs[ SID_DIALUP ];
402           
403 }  /* end DialupSid */
404 /***/
405 /******************************************************************************/
406 /* Function : BatchSid                                                      */
407 /* Purpose  : Returns SID of group that includes all users logged on using  */
408 /*            a batch queue facility                                        */
409 /******************************************************************************/
410 /***/
411 PSID BatchSid ( void ) {
412
413  return predefinedSIDs[ SID_BATCH ];
414
415 }  /* end BatchSid */
416 /***/
417 /******************************************************************************/
418 /* Function : CreatorOwnerSid                                               */
419 /* Purpose  : Returns SID of 'CREATOR OWNER' special group                  */
420 /******************************************************************************/
421 /***/
422 PSID CreatorOwnerSid ( void ) {
423
424  return predefinedSIDs[ SID_CREATOR_OWNER ];
425
426 }  /* end CreatorOwnerSid */
427 /***/
428 /******************************************************************************/
429 /* Function : NullSid                                                       */
430 /* Purpose  : Returns null SID                                              */
431 /******************************************************************************/
432 /***/
433 PSID NullSid ( void ) {
434
435  return predefinedSIDs[ SID_NULL ];
436
437 }  /* end NullSid */
438 /***/
439 /******************************************************************************/
440 /* Function : GetFileSecurityEx                                             */
441 /* Purpose  : Allocates a security descriptor and fills it out by security  */
442 /*            information which belongs to the specified file               */
443 /* Returns  : Pointer to the allocated security descriptor on success       */
444 /*            NULL otherwise                                                */
445 /* Warning  : Allocated security descriptor must be deallocated by          */
446 /*            'FreeFileSecurity' function                                   */
447 /******************************************************************************/
448 /***/
449
450
451 #if defined(__CYGWIN32__) || defined(__MINGW32__)
452 #define __try
453 #define __finally
454 #define __leave return retVal
455 #endif
456
457 PSECURITY_DESCRIPTOR GetFileSecurityEx ( LPCWSTR fileName, SECURITY_INFORMATION si ) {
458
459  DWORD                errVal;
460  DWORD                dwSize;
461  DWORD                dwSizeNeeded = 0;
462  PSECURITY_DESCRIPTOR retVal = NULL;
463  BOOL                 fOK    = FALSE;
464
465  __try {
466
467   do {
468
469    dwSize = dwSizeNeeded;
470    errVal = ERROR_SUCCESS;
471
472    if (  !GetFileSecurityW (
473            fileName, si,
474            retVal, dwSize, &dwSizeNeeded
475           )
476    ) {
477  
478     if (   (  errVal = GetLastError ()  ) != ERROR_INSUFFICIENT_BUFFER   ) __leave;
479
480     if (   (  retVal = ( PSECURITY_DESCRIPTOR )HeapAlloc ( hHeap, 0, dwSizeNeeded )
481            ) == NULL
482     ) __leave;
483
484    }  /* end if */
485  
486   } while ( errVal != ERROR_SUCCESS );
487
488   fOK = TRUE;
489
490  }  /* end __try */
491
492  __finally {
493  
494   if ( !fOK && retVal != NULL ) {
495   
496    HeapFree ( hHeap, 0, retVal );
497    retVal = NULL;
498   
499   }  /* end if */
500  
501  }  /* end __finally */
502
503 #ifdef VAC
504 leave: ;        // added for VisualAge
505 #endif
506
507  return retVal;
508
509 }  /* end GetFileSecurityEx */
510
511 #if defined(__CYGWIN32__) || defined(__MINGW32__)
512 #undef __try
513 #undef __finally
514 #undef __leave
515 #endif
516
517 /***/
518 /******************************************************************************/
519 /* Function : FreeFileSecurity                                              */
520 /* Purpose  : Deallocates security descriptor which was allocated by the    */
521 /*            'GetFileSecurityEx' function                                  */
522 /******************************************************************************/
523 /***/
524 void FreeFileSecurity ( PSECURITY_DESCRIPTOR pSD ) {
525
526  HeapFree (  hHeap, 0, ( LPVOID )pSD  );
527
528 }  /* end FreeFileSecurity */
529
530
531 /******************************************************************************/
532 /* Function : CreateAcl                                                     */
533 /* Purpose  : Allocates and initializes access-control list                 */
534 /* Returns  : Pointer to the allocated and initialized ACL on success,      */
535 /*            NULL otherwise                                                */
536 /* Warning  : Allocated ACL must be deallocated by 'FreeAcl' function       */
537 /******************************************************************************/
538 /***/
539 PACL CreateAcl ( DWORD dwAclSize ) {
540
541  PACL retVal;
542
543  retVal = ( PACL )HeapAlloc ( hHeap, 0, dwAclSize );
544
545  if ( retVal != NULL )
546
547   InitializeAcl ( retVal, dwAclSize, ACL_REVISION );
548
549  return retVal;
550
551 }  /* end CreateAcl */
552 /***/
553 /******************************************************************************/
554 /* Function : FreeAcl                                                       */
555 /* Purpose  : Deallocates access-control list which was allocated by the    */
556 /*            'CreateAcl' function                                          */
557 /******************************************************************************/
558 /***/
559 void FreeAcl ( PACL pACL ) {
560
561  HeapFree (  hHeap, 0, ( PVOID )pACL  );
562
563 }  /* end FreeAcl */
564
565 /******************************************************************************/
566 /* Function : AllocAccessAllowedAce                                         */
567 /* Purpose  : Allocates and initializes access-control entry                */
568 /* Returns  : Pointer to the ACE on success, NULL othrwise                  */
569 /* Warning  : Allocated ACE must be deallocated by the 'FreeAce' function   */
570 /******************************************************************************/
571 /***/
572 PVOID AllocAccessAllowedAce ( DWORD dwMask, BYTE flags, PSID pSID ) {
573
574  PFILE_ACE retVal;
575  WORD      wSize;
576
577  wSize = (WORD)( sizeof ( ACE_HEADER ) + sizeof ( DWORD ) + GetLengthSid ( pSID ) );
578
579  retVal = ( PFILE_ACE )HeapAlloc ( hHeap, 0, wSize );
580
581  if ( retVal != NULL ) {
582  
583   retVal -> header.AceType  = ACCESS_ALLOWED_ACE_TYPE;
584   retVal -> header.AceFlags = flags;
585   retVal -> header.AceSize  = wSize;
586
587   retVal -> dwMask = dwMask;
588
589   CopySid (  GetLengthSid ( pSID ), &retVal -> pSID, pSID  );
590  
591  }  /* end if */
592
593  return retVal;
594
595 }  /* end AllocAccessAllowedAce */
596 /***/
597 /******************************************************************************/
598 /* Function : FreeAce                                                       */
599 /* Purpose  : Deallocates an ACE which was allocated by the                 */
600 /*            'AllocAccessAllowedAce ' function                             */
601 /******************************************************************************/
602 /***/
603 void FreeAce ( PVOID pACE ) {
604
605  HeapFree ( hHeap, 0, pACE );
606
607 }  /* end FreeAce */
608 #endif
609 #define WILD_CARD     L"/*.*"
610 #define WILD_CARD_LEN (  sizeof ( WILD_CARD )  )
611
612 /***/
613 /******************************************************************************/
614 /* Function : MoveDirectory                                                 */
615 /* Purpose  : Moves specified directory tree to the new location            */
616 /* Returns  : TRUE on success, FALSE otherwise                              */
617 /******************************************************************************/
618 /***/
619 static BOOL MoveDirectory (const wchar_t* oldDir, const wchar_t* newDir, DWORD& theRecurseLevel)
620 {
621   wchar_t* driveSrc = NULL;
622   wchar_t* driveDst = NULL;
623   wchar_t* pathSrc = NULL;
624   wchar_t* pathDst = NULL;
625   BOOL     retVal = FALSE;
626   if (theRecurseLevel == 0)
627   {
628     ++theRecurseLevel;
629     BOOL fFind = FALSE;
630     if ((driveSrc = (wchar_t* )HeapAlloc (hHeap, 0, _MAX_DRIVE * sizeof(wchar_t))) != NULL
631      && (driveDst = (wchar_t* )HeapAlloc (hHeap, 0, _MAX_DRIVE * sizeof(wchar_t))) != NULL
632      && (pathSrc  = (wchar_t* )HeapAlloc (hHeap, 0, _MAX_DIR   * sizeof(wchar_t))) != NULL
633      && (pathDst  = (wchar_t* )HeapAlloc (hHeap, 0, _MAX_DIR   * sizeof(wchar_t))) != NULL)
634     {
635       _wsplitpath (oldDir, driveSrc, pathSrc, NULL, NULL);
636       _wsplitpath (newDir, driveDst, pathDst, NULL, NULL);
637       if (wcscmp (driveSrc, driveDst) == 0
638        && wcscmp (pathSrc,  pathDst ) == 0)
639       {
640 retry:
641         retVal = MoveFileExW (oldDir, newDir, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED);
642         fFind  = TRUE;
643         if (!retVal)
644         {
645           if (_response_dir_proc != NULL)
646           {
647             const DIR_RESPONSE response = _response_dir_proc (oldDir);
648             if (response == DIR_RETRY)
649             {
650               goto retry;
651             }
652             else if (response == DIR_IGNORE)
653             {
654               retVal = TRUE;
655             }
656           }
657         }
658         else if (_move_dir_proc != NULL)
659         {
660           _move_dir_proc (oldDir, newDir);
661         }
662       }
663     }
664
665     if (pathDst  != NULL)
666     {
667       HeapFree (hHeap, 0, pathDst);
668     }
669     if (pathSrc  != NULL)
670     {
671       HeapFree (hHeap, 0, pathSrc);
672     }
673     if (driveDst != NULL)
674     {
675       HeapFree (hHeap, 0, driveDst);
676     }
677     if (driveSrc != NULL)
678     {
679       HeapFree (hHeap, 0, driveSrc);
680     }
681
682     if (fFind)
683     {
684       --theRecurseLevel;
685       return retVal;
686     }
687   }
688   else
689   {
690     ++theRecurseLevel;
691   }
692
693   WIN32_FIND_DATAW* pFD = NULL;
694   wchar_t* pName = NULL;
695   wchar_t* pFullNameSrc = NULL;
696   wchar_t* pFullNameDst = NULL;
697   HANDLE hFindFile = INVALID_HANDLE_VALUE;
698   retVal = CreateDirectoryW (newDir, NULL);
699   if (retVal || (!retVal && GetLastError() == ERROR_ALREADY_EXISTS))
700   {
701     size_t anOldDirLength;
702     StringCchLengthW (oldDir, sizeof(oldDir) / sizeof(oldDir[0]), &anOldDirLength);
703     if ((pFD = (WIN32_FIND_DATAW* )HeapAlloc (hHeap, 0, sizeof(WIN32_FIND_DATAW))) != NULL
704      && (pName =        (wchar_t* )HeapAlloc (hHeap, 0, anOldDirLength + WILD_CARD_LEN + sizeof(L'\x00'))) != NULL)
705     {
706       StringCchCopyW (pName, sizeof(pName) / sizeof(pName[0]), oldDir);
707       StringCchCatW  (pName, sizeof(pName), WILD_CARD);
708       retVal = TRUE;
709       hFindFile = FindFirstFileExW (pName, FindExInfoStandard, pFD, FindExSearchNameMatch, NULL, 0);
710       for (BOOL fFind = hFindFile != INVALID_HANDLE_VALUE; fFind; fFind = FindNextFileW (hFindFile, pFD))
711       {
712         if ((pFD->cFileName[0] == L'.' && pFD->cFileName[1] == L'\0')
713          || (pFD->cFileName[0] == L'.' && pFD->cFileName[1] == L'.' && pFD->cFileName[2] == L'\0'))
714         {
715           continue;
716         }
717
718         size_t anOldDirLength2 = 0, aNewDirLength = 0, aFileNameLength = 0;
719         StringCchLengthW (oldDir, sizeof(oldDir) / sizeof(oldDir[0]), &anOldDirLength2);
720         StringCchLengthW (newDir, sizeof(newDir) / sizeof(newDir[0]), &aNewDirLength);
721         StringCchLengthW (pFD->cFileName, sizeof(pFD->cFileName) / sizeof(pFD->cFileName[0]), &aFileNameLength);
722         if ((pFullNameSrc = (wchar_t* )HeapAlloc (hHeap, 0, anOldDirLength2 + aFileNameLength + sizeof(L'/') + sizeof(L'\x00'))) == NULL
723           || (pFullNameDst = (wchar_t* )HeapAlloc (hHeap, 0, aNewDirLength   + aFileNameLength + sizeof(L'/') + sizeof(L'\x00'))) == NULL)
724         {
725           break;
726         }
727
728         StringCchCopyW (pFullNameSrc, sizeof(pFullNameSrc) / sizeof(pFullNameSrc[0]), oldDir);
729         StringCchCatW  (pFullNameSrc, sizeof(pFullNameSrc) / sizeof(pFullNameSrc[0]), L"/");
730         StringCchCatW  (pFullNameSrc, sizeof(pFullNameSrc) / sizeof(pFullNameSrc[0]), pFD->cFileName);
731
732         StringCchCopyW (pFullNameDst, sizeof(pFullNameDst) / sizeof(pFullNameDst[0]), newDir);
733         StringCchCatW  (pFullNameDst, sizeof(pFullNameDst) / sizeof(pFullNameDst[0]), L"/");
734         StringCchCatW  (pFullNameDst, sizeof(pFullNameDst) / sizeof(pFullNameDst[0]), pFD->cFileName);
735
736         if ((pFD->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
737         {
738           retVal = MoveDirectory (pFullNameSrc, pFullNameDst, theRecurseLevel);
739           if (!retVal)
740           {
741             break;
742           }
743         }
744         else
745         {
746 retry_1:
747           retVal = MoveFileExW (pFullNameSrc, pFullNameDst, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED);
748           if (!retVal)
749           {
750             if (_response_dir_proc != NULL)
751             {
752               const DIR_RESPONSE response = _response_dir_proc (pFullNameSrc);
753               if (response == DIR_ABORT)
754               {
755                 break;
756               }
757               else if (response == DIR_RETRY)
758               {
759                 goto retry_1;
760               }
761               else if (response == DIR_IGNORE)
762               {
763                 retVal = TRUE;
764               }
765               else
766               {
767                 break;
768               }
769             }
770           }
771           else if (_move_dir_proc != NULL)
772           {
773             _move_dir_proc (pFullNameSrc, pFullNameDst);
774           }
775         }
776
777         HeapFree (hHeap, 0, pFullNameDst);
778         HeapFree (hHeap, 0, pFullNameSrc);
779         pFullNameSrc = pFullNameDst = NULL;
780       }
781     }
782   }
783
784   if (hFindFile != INVALID_HANDLE_VALUE)
785   {
786     FindClose (hFindFile);
787   }
788
789   if (pFullNameSrc != NULL)
790   {
791     HeapFree (hHeap, 0, pFullNameSrc);
792   }
793   if (pFullNameDst != NULL)
794   {
795     HeapFree (hHeap, 0, pFullNameDst);
796   }
797   if (pName != NULL)
798   {
799     HeapFree (hHeap, 0, pName);
800   }
801   if (pFD != NULL)
802   {
803     HeapFree (hHeap, 0, pFD);
804   }
805
806   if (retVal)
807   {
808 retry_2:
809     retVal = RemoveDirectoryW (oldDir);
810     if (!retVal)
811     {
812       if (_response_dir_proc != NULL)
813       {
814         const DIR_RESPONSE response = _response_dir_proc (oldDir);
815         if (response == DIR_RETRY)
816         {
817           goto retry_2;
818         }
819         else if (response == DIR_IGNORE)
820         {
821           retVal = TRUE;
822         }
823       }
824     }
825   }
826
827   --theRecurseLevel;
828   return retVal;
829 }
830
831 BOOL MoveDirectory (const wchar_t* oldDir, const wchar_t* newDir)
832 {
833   DWORD aRecurseLevel = 0;
834   return MoveDirectory (oldDir, newDir, aRecurseLevel);
835 }
836
837 /***/
838 /******************************************************************************/
839 /* Function : CopyDirectory                                                 */
840 /* Purpose  : Copies specified directory tree to the new location           */
841 /* Returns  : TRUE on success, FALSE otherwise                              */
842 /******************************************************************************/
843 /***/
844 BOOL CopyDirectory (const wchar_t* dirSrc, const wchar_t* dirDst)
845 {
846   WIN32_FIND_DATAW* pFD = NULL;
847   wchar_t* pName = NULL;
848   wchar_t* pFullNameSrc = NULL;
849   wchar_t* pFullNameDst = NULL;
850   HANDLE   hFindFile = INVALID_HANDLE_VALUE;
851
852   BOOL retVal = CreateDirectoryW (dirDst, NULL);
853   if (retVal || (!retVal && GetLastError() == ERROR_ALREADY_EXISTS))
854   {
855     size_t aDirSrcLength = 0;
856     StringCchLengthW (dirSrc, sizeof(dirSrc) / sizeof(dirSrc[0]), &aDirSrcLength);
857     if ((pFD = (WIN32_FIND_DATAW* )HeapAlloc (hHeap, 0, sizeof(WIN32_FIND_DATAW))) != NULL
858      && (pName = (wchar_t* )HeapAlloc (hHeap, 0, aDirSrcLength + WILD_CARD_LEN + sizeof(L'\x00'))) != NULL)
859     {
860       StringCchCopyW(pName, sizeof(pName) / sizeof(pName[0]), dirSrc);
861       StringCchCatW (pName, sizeof(pName) / sizeof(pName[0]), WILD_CARD);
862
863       retVal = TRUE;
864       hFindFile = FindFirstFileExW (pName, FindExInfoStandard, pFD, FindExSearchNameMatch, NULL, 0);
865       for (BOOL fFind = hFindFile != INVALID_HANDLE_VALUE; fFind; fFind = FindNextFileW (hFindFile, pFD))
866       {
867         if ((pFD->cFileName[0] == L'.' && pFD->cFileName[1] == L'\0')
868          || (pFD->cFileName[0] == L'.' && pFD->cFileName[1] == L'.' && pFD->cFileName[2] == L'\0'))
869         {
870           continue;
871         }
872
873         size_t aDirSrcLength2 = 0, aDirDstLength = 0, aFileNameLength = 0;
874         StringCchLengthW (dirSrc, sizeof(dirSrc) / sizeof(dirSrc[0]), &aDirSrcLength2);
875         StringCchLengthW (dirDst, sizeof(dirDst) / sizeof(dirDst[0]), &aDirDstLength);
876         StringCchLengthW (pFD->cFileName, sizeof(pFD->cFileName) / sizeof(pFD->cFileName[0]), &aFileNameLength);
877         if ((pFullNameSrc = (wchar_t* )HeapAlloc (hHeap, 0, aDirSrcLength2 + aFileNameLength + sizeof(L'/') + sizeof(L'\x00'))) == NULL
878          || (pFullNameDst = (wchar_t* )HeapAlloc (hHeap, 0, aDirDstLength  + aFileNameLength + sizeof(L'/') + sizeof(L'\x00'))) == NULL)
879         {
880           break;
881         }
882
883         StringCchCopyW (pFullNameSrc, sizeof(pFullNameSrc) / sizeof(pFullNameSrc[0]), dirSrc);
884         StringCchCatW  (pFullNameSrc, sizeof(pFullNameSrc) / sizeof(pFullNameSrc[0]), L"/");
885         StringCchCatW  (pFullNameSrc, sizeof(pFullNameSrc) / sizeof(pFullNameSrc[0]), pFD->cFileName);
886
887         StringCchCopyW (pFullNameDst, sizeof(pFullNameDst) / sizeof(pFullNameDst[0]), dirDst);
888         StringCchCatW  (pFullNameDst, sizeof(pFullNameDst) / sizeof(pFullNameDst[0]), L"/");
889         StringCchCatW  (pFullNameDst, sizeof(pFullNameDst) / sizeof(pFullNameDst[0]), pFD->cFileName);
890         if ((pFD->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
891         {
892           retVal = CopyDirectory (pFullNameSrc, pFullNameDst);
893           if (!retVal)
894           {
895             break;
896           }
897         }
898         else
899         {
900 retry:
901         #ifndef OCCT_UWP
902           retVal = CopyFileW (pFullNameSrc, pFullNameDst, FALSE);
903         #else
904           retVal = (CopyFile2 (pFullNameSrc, pFullNameDst, FALSE) == S_OK) ? TRUE : FALSE;
905         #endif
906           if (!retVal)
907           {
908             if (_response_dir_proc != NULL)
909             {
910               const DIR_RESPONSE response = _response_dir_proc (pFullNameSrc);
911               if (response == DIR_ABORT)
912               {
913                 break;
914               }
915               else if (response == DIR_RETRY)
916               {
917                 goto retry;
918               }
919               else if (response == DIR_IGNORE)
920               {
921                 retVal = TRUE;
922               }
923               else
924               {
925                 break;
926               }
927             }
928           }
929           else if (_copy_dir_proc != NULL)
930           {
931             _copy_dir_proc (pFullNameSrc, pFullNameDst);
932           }
933         }
934
935         HeapFree (hHeap, 0, pFullNameDst);
936         HeapFree (hHeap, 0, pFullNameSrc);
937         pFullNameSrc = pFullNameDst = NULL;
938       }
939     }
940   }
941
942   if (hFindFile != INVALID_HANDLE_VALUE)
943   {
944     FindClose (hFindFile);
945   }
946
947   if (pFullNameSrc != NULL)
948   {
949     HeapFree (hHeap, 0, pFullNameSrc);
950   }
951   if (pFullNameDst != NULL)
952   {
953     HeapFree (hHeap, 0, pFullNameDst);
954   }
955   if (pName != NULL)
956   {
957     HeapFree (hHeap, 0, pName);
958   }
959   if (pFD != NULL)
960   {
961     HeapFree (hHeap, 0, pFD);
962   }
963
964   return retVal;
965 }  /* end CopyDirectory */
966 /***/
967 /******************************************************************************/
968 /* Function : SetMoveDirectoryProc                                          */
969 /* Purpose  : Sets callback procedure which is calling by the               */ 
970 /*            'MoveDirectory' after moving of each item in the              */
971 /*            directory. To unregister this callback function supply NULL   */
972 /*            pointer                                                       */
973 /******************************************************************************/
974 /***/
975 void SetMoveDirectoryProc ( MOVE_DIR_PROC proc ) {
976
977  _move_dir_proc = proc;
978
979 }  /* end SetMoveDirectoryProc */
980 /***/
981 /******************************************************************************/
982 /* Function : SetCopyDirectoryProc                                          */
983 /* Purpose  : Sets callback procedure which is calling by the               */ 
984 /*            'CopyDirectory' after copying of each item in the             */
985 /*            directory. To unregister this callback function supply NULL   */
986 /*            pointer                                                       */
987 /******************************************************************************/
988 /***/
989 void SetCopyDirectoryProc ( COPY_DIR_PROC proc ) {
990
991  _copy_dir_proc = proc;
992
993 }  /* end SetCopyDirectoryProc */
994 /***/
995 /******************************************************************************/
996 /* Function : SetResponseDirectoryProc                                      */
997 /* Purpose  : Sets callback procedure which is calling by the               */ 
998 /*            directoy processing function if an error was occur.           */
999 /*            The return value of that callback procedure determines        */
1000 /*            behaviour of directoy processing functions in case of error.  */
1001 /*            To unregister this callback function supply NULL pointer      */
1002 /******************************************************************************/
1003 /***/
1004 void SetResponseDirectoryProc ( RESPONSE_DIR_PROC proc ) {
1005
1006  _response_dir_proc = proc;
1007
1008 }  /* end SetResponseDirectoryProc */
1009 /***/
1010 /******************************************************************************/
1011 /******************************************************************************/
1012 /******************************************************************************/
1013 #endif