0030775: Foundation Classes - Preserve application-defined top-level exception filter
[occt.git] / src / OSD / OSD_File.cxx
1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #ifdef _WIN32
16   #include <windows.h>
17 #endif
18
19 #include <OSD_File.hxx>
20
21 #include <NCollection_Array1.hxx>
22 #include <OSD.hxx>
23 #include <OSD_OSDError.hxx>
24 #include <OSD_Path.hxx>
25 #include <OSD_Protection.hxx>
26 #include <OSD_WhoAmI.hxx>
27 #include <Standard_ProgramError.hxx>
28 #include <TCollection_ExtendedString.hxx>
29
30 #ifdef _WIN32
31
32   #include <OSD_WNT.hxx>
33
34   #include <stdio.h>
35   #include <io.h>
36
37   #include <strsafe.h>
38
39   #define ACE_HEADER_SIZE (sizeof(ACCESS_ALLOWED_ACE) - sizeof (DWORD))
40
41   #define OPEN_NEW    0
42   #define OPEN_OLD    1
43   #define OPEN_APPEND 2
44
45   void                            _osd_wnt_set_error        ( OSD_Error&, OSD_WhoAmI, ... );
46
47 #ifndef OCCT_UWP
48   PSECURITY_DESCRIPTOR __fastcall _osd_wnt_protection_to_sd ( const OSD_Protection&, BOOL, const wchar_t* );
49   BOOL                 __fastcall _osd_wnt_sd_to_protection (PSECURITY_DESCRIPTOR, OSD_Protection&, BOOL);
50
51   static int OSD_File_getBuffer (HANDLE theChannel,
52                                  char* theBuffer,
53                                  DWORD theSize,
54                                  BOOL theIsPeek,
55                                  BOOL theIsSocket)
56   {
57     if (theIsSocket)
58     {
59       const int aFlags = theIsPeek ? MSG_PEEK : 0;
60       const int aRetVal = recv ((SOCKET )theChannel, theBuffer, (int )theSize, aFlags);
61       return aRetVal != SOCKET_ERROR
62            ? aRetVal
63            : -1;
64     }
65
66     DWORD aBytesRead = 0;
67     if (theIsPeek)
68     {
69       DWORD aDummy = 0;
70       if (!PeekNamedPipe (theChannel, theBuffer, theSize, &aBytesRead, &aDummy, &aDummy)
71         && GetLastError() != ERROR_BROKEN_PIPE)
72       {
73         return -1;
74       }
75       return (int )aBytesRead;
76     }
77     else if (!ReadFile (theChannel, theBuffer, theSize, &aBytesRead, NULL))
78     {
79       return -1;
80     }
81     return (int )aBytesRead;
82   }
83
84   static OSD_SingleProtection OSD_File_getProtection (DWORD theMask)
85   {
86     switch (theMask)
87     {
88       case FILE_GENERIC_READ:
89         return OSD_R;
90       case FILE_GENERIC_WRITE:
91         return OSD_W;
92       case FILE_GENERIC_READ | FILE_GENERIC_WRITE:
93         return OSD_RW;
94       case FILE_GENERIC_EXECUTE:
95         return OSD_X;
96       case FILE_GENERIC_READ | FILE_GENERIC_EXECUTE:
97         return OSD_RX;
98       case FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE:
99         return OSD_WX;
100       case FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE:
101         return OSD_RWX;
102       case DELETE:
103         return OSD_D;
104       case FILE_GENERIC_READ | DELETE:
105         return OSD_RD;
106       case FILE_GENERIC_WRITE | DELETE:
107         return OSD_WD;
108       case FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE:
109         return OSD_RWD;
110       case FILE_GENERIC_EXECUTE | DELETE:
111         return OSD_XD;
112       case FILE_GENERIC_READ | FILE_GENERIC_EXECUTE | DELETE:
113         return OSD_RXD;
114       case FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE:
115         return OSD_WXD;
116       case FILE_ALL_ACCESS:
117       case FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE:
118         return OSD_RWXD;
119     }
120     return OSD_None;
121   }
122
123   static OSD_SingleProtection OSD_File_getProtectionDir (DWORD theMask)
124   {
125     switch (theMask)
126     {
127       case GENERIC_READ:
128         return OSD_R;
129       case GENERIC_WRITE:
130         return OSD_W;
131       case GENERIC_READ | GENERIC_WRITE:
132         return OSD_RW;
133       case GENERIC_EXECUTE:
134         return OSD_X;
135       case GENERIC_READ | GENERIC_EXECUTE:
136         return OSD_RX;
137       case GENERIC_WRITE | GENERIC_EXECUTE:
138         return OSD_WX;
139       case GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE:
140         return OSD_RWX;
141       case DELETE:
142         return OSD_D;
143       case GENERIC_READ | DELETE:
144         return OSD_RD;
145       case GENERIC_WRITE | DELETE:
146         return OSD_WD;
147       case GENERIC_READ | GENERIC_WRITE | DELETE:
148         return OSD_RWD;
149       case GENERIC_EXECUTE | DELETE:
150         return OSD_XD;
151       case GENERIC_READ | GENERIC_EXECUTE | DELETE:
152         return OSD_RXD;
153       case GENERIC_WRITE | GENERIC_EXECUTE | DELETE:
154         return OSD_WXD;
155       case FILE_ALL_ACCESS:
156       case GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE:
157         return OSD_RWXD;
158       case 0:
159         return OSD_None;
160       default:
161         // remote directories (on Samba server) have flags like for files
162         return OSD_File_getProtection (theMask);
163     }
164   }
165
166   static DWORD OSD_File_getAccessMask (OSD_SingleProtection theProtection)
167   {
168     switch (theProtection)
169     {
170       case OSD_None: return 0;
171       case OSD_R:    return FILE_GENERIC_READ;
172       case OSD_W:    return FILE_GENERIC_WRITE;
173       case OSD_RW:   return FILE_GENERIC_READ | FILE_GENERIC_WRITE;
174       case OSD_X:    return FILE_GENERIC_EXECUTE;
175       case OSD_RX:   return FILE_GENERIC_READ | FILE_GENERIC_EXECUTE;
176       case OSD_WX:   return FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE;
177       case OSD_RWX:  return FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE;
178       case OSD_D:    return DELETE;
179       case OSD_RD:   return FILE_GENERIC_READ | DELETE;
180       case OSD_WD:   return FILE_GENERIC_WRITE | DELETE;
181       case OSD_RWD:  return FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE;
182       case OSD_XD:   return FILE_GENERIC_EXECUTE | DELETE;
183       case OSD_RXD:  return FILE_GENERIC_READ | FILE_GENERIC_EXECUTE | DELETE;
184       case OSD_WXD:  return FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE;
185       case OSD_RWXD: return FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE;
186     }
187     throw Standard_ProgramError ("OSD_File_getAccessMask(): incorrect parameter");
188   }
189
190   static DWORD OSD_File_getDirAccessMask (OSD_SingleProtection theProtection)
191   {
192     switch (theProtection)
193     {
194       case OSD_None: return 0;
195       case OSD_R:    return GENERIC_READ;
196       case OSD_W:    return GENERIC_WRITE;
197       case OSD_RW:   return GENERIC_READ | GENERIC_WRITE;
198       case OSD_X:    return GENERIC_EXECUTE;
199       case OSD_RX:   return GENERIC_READ  | GENERIC_EXECUTE;
200       case OSD_WX:   return GENERIC_WRITE | GENERIC_EXECUTE;
201       case OSD_RWX:  return GENERIC_READ  | GENERIC_WRITE | GENERIC_EXECUTE;
202       case OSD_D:    return DELETE;
203       case OSD_RD:   return GENERIC_READ  | DELETE;
204       case OSD_WD:   return GENERIC_WRITE | DELETE;
205       case OSD_RWD:  return GENERIC_READ  | GENERIC_WRITE | DELETE;
206       case OSD_XD:   return GENERIC_EXECUTE | DELETE;
207       case OSD_RXD:  return GENERIC_READ  | GENERIC_EXECUTE | DELETE;
208       case OSD_WXD:  return GENERIC_WRITE | GENERIC_EXECUTE | DELETE;
209       case OSD_RWXD: return GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE;
210     }
211     throw Standard_ProgramError ("OSD_File_getDirAccessMask(): incorrect parameter");
212   }
213
214   struct OSD_File_WntKey
215   {
216     HKEY           hKey;
217     const wchar_t* keyPath;
218   };
219
220   #endif /* ! OCCT_UWP */
221
222   Standard_Integer __fastcall _get_file_type (Standard_CString theFileName,
223                                               HANDLE theFileHandle)
224   {
225     const int aFileType = theFileHandle == INVALID_HANDLE_VALUE
226                         ? FILE_TYPE_DISK
227                         : GetFileType (theFileHandle);
228     switch (aFileType)
229     {
230       case FILE_TYPE_UNKNOWN:
231         return FLAG_SOCKET;
232       case FILE_TYPE_DISK:
233       {
234         const TCollection_ExtendedString aFileNameW (theFileName, Standard_True);
235         WIN32_FILE_ATTRIBUTE_DATA aFileInfo;
236         if (GetFileAttributesExW (aFileNameW.ToWideString(), GetFileExInfoStandard, &aFileInfo))
237         {
238           return aFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? FLAG_DIRECTORY : FLAG_FILE;
239         }
240         return 0x80000000;
241       }
242       case FILE_TYPE_CHAR:
243         return FLAG_DEVICE;
244       case FILE_TYPE_PIPE:
245         return FLAG_PIPE;
246     }
247     return 0;
248   }
249
250   //! Returns number of bytes in the string (including end \n, but excluding \r);
251   static Standard_Integer OSD_File_getLine (char* theBuffer, DWORD theBuffSize, LONG& theSeekPos)
252   {
253     theBuffer[theBuffSize] = 0;
254     for (char* aCharIter = theBuffer; *aCharIter != 0; )
255     {
256       if (*aCharIter == '\n')
257       {
258         ++aCharIter;   // jump newline char
259         *aCharIter = '\0';
260         theSeekPos = LONG(aCharIter - theBuffer - theBuffSize);
261         return Standard_Integer(aCharIter - theBuffer);
262       }
263       else if (aCharIter[0] == '\r'
264             && aCharIter[1] == '\n')
265       {
266         *(aCharIter++) = '\n'; // Substitute carriage return by newline
267         *aCharIter = 0;
268         theSeekPos = LONG(aCharIter + 1 - theBuffer - theBuffSize);
269         return Standard_Integer(aCharIter - theBuffer);
270       }
271       else if (aCharIter[0] == '\r'
272             && aCharIter[1] == '\0')
273       {
274         *aCharIter = '\n' ; // Substitute carriage return by newline
275         return -1;
276       }
277       ++aCharIter;
278     }
279
280     theSeekPos = 0;
281     return theBuffSize;
282   }
283
284   static HANDLE OSD_File_openFile (const TCollection_AsciiString& theFileName,
285                                    OSD_OpenMode theOpenMode,
286                                    DWORD theOptions, bool* theIsNew = NULL)
287   {
288     DWORD  dwDesiredAccess = 0;
289     switch (theOpenMode)
290     {
291       case OSD_ReadOnly:
292         dwDesiredAccess = GENERIC_READ;
293         break;
294       case OSD_WriteOnly:
295         dwDesiredAccess = GENERIC_WRITE;
296         break;
297       case OSD_ReadWrite:
298         dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
299         break;
300       default:
301         throw Standard_ProgramError ("OSD_File_openFile(): incorrect parameter");
302     }
303
304     DWORD dwCreationDistribution = (theOptions != OPEN_NEW) ? OPEN_EXISTING : CREATE_ALWAYS;
305     const TCollection_ExtendedString aFileNameW (theFileName);
306   #ifndef OCCT_UWP
307     HANDLE aFileHandle = CreateFileW (aFileNameW.ToWideString(), dwDesiredAccess,
308                                       FILE_SHARE_READ | FILE_SHARE_WRITE,
309                                       NULL, dwCreationDistribution, FILE_ATTRIBUTE_NORMAL, NULL);
310   #else
311     CREATEFILE2_EXTENDED_PARAMETERS pCreateExParams = {};
312     pCreateExParams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
313     pCreateExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
314     pCreateExParams.lpSecurityAttributes = NULL;
315     pCreateExParams.hTemplateFile = NULL;
316     HANDLE aFileHandle = CreateFile2 (aFileNameW.ToWideString(), dwDesiredAccess,
317                                       FILE_SHARE_READ | FILE_SHARE_WRITE,
318                                       dwCreationDistribution, &pCreateExParams);
319   #endif
320     if (aFileHandle    != INVALID_HANDLE_VALUE
321      || theOptions     != OPEN_APPEND
322      || GetLastError() != ERROR_FILE_NOT_FOUND)
323     {
324       return aFileHandle;
325     }
326
327     dwCreationDistribution = CREATE_ALWAYS;
328   #ifndef OCCT_UWP
329     aFileHandle = CreateFileW (aFileNameW.ToWideString(), dwDesiredAccess,
330                                FILE_SHARE_READ | FILE_SHARE_WRITE,
331                                NULL, dwCreationDistribution, FILE_ATTRIBUTE_NORMAL, NULL );
332   #else
333     CREATEFILE2_EXTENDED_PARAMETERS pCreateExParams2 = {};
334     pCreateExParams2.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
335     pCreateExParams2.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
336     pCreateExParams2.lpSecurityAttributes = NULL;
337     pCreateExParams2.hTemplateFile = NULL;
338     aFileHandle = CreateFile2 (aFileNameW.ToWideString(), dwDesiredAccess,
339                                FILE_SHARE_READ | FILE_SHARE_WRITE,
340                                dwCreationDistribution, &pCreateExParams2 );
341   #endif
342     *theIsNew = true;
343     return aFileHandle;
344   }
345
346 #else
347
348   const OSD_WhoAmI Iam = OSD_WFile;
349
350   #if defined (sun) || defined(SOLARIS)
351     #define POSIX
352   #else
353     #define SYSV
354   #endif
355
356   #include <errno.h>
357   #include <stdlib.h>
358   #include <stdio.h>
359   #include <fcntl.h>
360   #include <unistd.h>
361   #include <sys/stat.h>
362
363   #define NEWLINE '\10';
364 #endif
365
366 // =======================================================================
367 // function : OSD_File
368 // purpose  :
369 // =======================================================================
370 OSD_File::OSD_File() :
371 #ifdef _WIN32
372   myFileHandle (INVALID_HANDLE_VALUE),
373 #else
374   myFileChannel (-1),
375   myFILE (NULL),
376 #endif
377   myIO (0),
378   myLock (OSD_NoLock),
379   myMode (OSD_ReadWrite),
380   ImperativeFlag (Standard_False)
381 {
382   //
383 }
384
385 // =======================================================================
386 // function : OSD_File
387 // purpose  :
388 // =======================================================================
389 OSD_File::OSD_File (const OSD_Path& theName)
390 : OSD_FileNode (theName),
391 #ifdef _WIN32
392   myFileHandle (INVALID_HANDLE_VALUE),
393 #else
394   myFileChannel (-1),
395   myFILE (NULL),
396 #endif
397   myIO (0),
398   myLock (OSD_NoLock),
399   myMode (OSD_ReadWrite),
400   ImperativeFlag (Standard_False)
401 {
402   //
403 }
404
405 // =======================================================================
406 // function : ~OSD_File
407 // purpose  :
408 // =======================================================================
409 OSD_File::~OSD_File()
410 {
411   if (IsOpen())
412   {
413     if (IsLocked())
414     {
415       UnLock();
416     }
417     Close();
418   }
419 }
420
421 // =======================================================================
422 // function : Build
423 // purpose  :
424 // =======================================================================
425 void OSD_File::Build (const OSD_OpenMode theMode,
426                       const OSD_Protection& theProtect)
427 {
428   if (OSD_File::KindOfFile() == OSD_DIRECTORY)
429   {
430     throw Standard_ProgramError ("OSD_File::Build(): it is a directory");
431   }
432   if (IsOpen())
433   {
434     throw Standard_ProgramError ("OSD_File::Build(): incorrect call - file already opened");
435   }
436
437   TCollection_AsciiString aFileName;
438   myPath.SystemName (aFileName);
439 #ifdef _WIN32
440   if (aFileName.IsEmpty())
441   {
442     throw Standard_ProgramError ("OSD_File::Build(): incorrect call - no filename given");
443   }
444
445   myMode = theMode;
446   myFileHandle = OSD_File_openFile (aFileName, theMode, OPEN_NEW);
447   if (myFileHandle == INVALID_HANDLE_VALUE)
448   {
449     _osd_wnt_set_error (myError, OSD_WFile);
450   }
451   else
452   {
453   #ifndef OCCT_UWP
454     SetProtection (theProtect);
455   #else
456     (void)theProtect;
457   #endif
458     myIO |= FLAG_FILE;
459   }
460 #else
461   if (myPath.Name().Length() == 0)
462   {
463     throw Standard_ProgramError ("OSD_File::Build(): no name was given");
464   }
465
466   const char* anFDOpenMode = "r";
467   Standard_Integer anOpenMode = O_CREAT | O_TRUNC;
468   switch (theMode)
469   {
470     case OSD_ReadOnly:
471       anOpenMode |= O_RDONLY;
472       anFDOpenMode = "r";
473       break;
474     case OSD_WriteOnly:
475       anOpenMode |= O_WRONLY;
476       anFDOpenMode = "w";
477       break;
478     case OSD_ReadWrite:
479       anOpenMode |= O_RDWR;
480       anFDOpenMode = "w+";
481       break;
482   }
483
484   myMode = theMode;
485   myFileChannel = open (aFileName.ToCString(), anOpenMode, theProtect.Internal());
486   if (myFileChannel >= 0)
487   {
488     myFILE = fdopen (myFileChannel, anFDOpenMode);
489   }
490   else
491   {
492     myError.SetValue (errno, Iam, "Open");
493   }
494 #endif
495 }
496
497 // =======================================================================
498 // function : Append
499 // purpose  :
500 // =======================================================================
501 void OSD_File::Append (const OSD_OpenMode theMode,
502                        const OSD_Protection& theProtect)
503 {
504   if (OSD_File::KindOfFile() == OSD_DIRECTORY)
505   {
506     throw Standard_ProgramError ("OSD_File::Append(): it is a directory");
507   }
508   if (IsOpen())
509   {
510     throw Standard_ProgramError ("OSD_File::Append(): incorrect call - file already opened");
511   }
512
513   TCollection_AsciiString aFileName;
514   myPath.SystemName (aFileName);
515 #ifdef _WIN32
516   if (aFileName.IsEmpty())
517   {
518     throw Standard_ProgramError ("OSD_File::Append(): incorrect call - no filename given");
519   }
520
521   bool isNewFile = false;
522   myMode = theMode;
523   myFileHandle = OSD_File_openFile (aFileName, theMode, OPEN_APPEND, &isNewFile);
524   if (myFileHandle == INVALID_HANDLE_VALUE)
525   {
526     _osd_wnt_set_error (myError, OSD_WFile);
527   }
528   else
529   {
530     if (!isNewFile)
531     {
532       myIO |= _get_file_type (aFileName.ToCString(), myFileHandle);
533       Seek (0, OSD_FromEnd);
534     }
535     else
536     {
537     #ifndef OCCT_UWP
538       SetProtection (theProtect);
539     #else
540       (void)theProtect;
541     #endif
542       myIO |= FLAG_FILE;
543     }
544   }
545 #else
546   if (myPath.Name().Length() == 0)
547   {
548     throw Standard_ProgramError ("OSD_File::Append(): no name was given");
549   }
550
551   const char* anFDOpenMode = "r";
552   Standard_Integer anOpenMode = O_APPEND;
553   switch (theMode)
554   {
555     case OSD_ReadOnly:
556       anOpenMode |= O_RDONLY;
557       anFDOpenMode = "r";
558       break;
559     case OSD_WriteOnly:
560       anOpenMode |= O_WRONLY;
561       anFDOpenMode = "a";
562       break;
563     case OSD_ReadWrite:
564       anOpenMode |= O_RDWR;
565       anFDOpenMode = "a+";
566       break;
567   }
568
569   if (!Exists())
570   {
571     // if file doesn't exist, creates it
572     anOpenMode |= O_CREAT;
573   }
574
575   myMode = theMode;
576   myFileChannel = open (aFileName.ToCString(), anOpenMode, theProtect.Internal());
577   if (myFileChannel >= 0)
578   {
579     myFILE = fdopen (myFileChannel, anFDOpenMode);
580   }
581   else
582   {
583     myError.SetValue (errno, Iam, "Open");
584   }
585 #endif
586 }
587
588 // =======================================================================
589 // function : Open
590 // purpose  :
591 // =======================================================================
592 void OSD_File::Open (const OSD_OpenMode theMode,
593                      const OSD_Protection& theProtect)
594 {
595   if (OSD_File::KindOfFile() == OSD_DIRECTORY)
596   {
597     throw Standard_ProgramError ("OSD_File::Open(): it is a directory");
598   }
599   if (IsOpen())
600   {
601     throw Standard_ProgramError ("OSD_File::Open(): incorrect call - file already opened");
602   }
603
604   TCollection_AsciiString aFileName;
605   myPath.SystemName (aFileName);
606 #ifdef _WIN32
607   if (aFileName.IsEmpty())
608   {
609     throw Standard_ProgramError ("OSD_File::Open(): incorrect call - no filename given");
610   }
611
612   (void )theProtect;
613   myMode = theMode;
614   myFileHandle = OSD_File_openFile (aFileName, theMode, OPEN_OLD);
615   if (myFileHandle == INVALID_HANDLE_VALUE)
616   {
617     _osd_wnt_set_error (myError, OSD_WFile);
618   }
619   else
620   {
621     myIO |= _get_file_type (aFileName.ToCString(), myFileHandle);
622   }
623 #else
624   if (myPath.Name().Length() == 0)
625   {
626     throw Standard_ProgramError ("OSD_File::Open(): no name was given");
627   }
628
629   const char* anFDOpenMode = "r";
630   Standard_Integer anOpenMode = 0;
631   switch (theMode)
632   {
633     case OSD_ReadOnly:
634       anOpenMode |= O_RDONLY;
635       anFDOpenMode = "r";
636       break;
637     case OSD_WriteOnly:
638       anOpenMode |= O_WRONLY;
639       anFDOpenMode = "w";
640       break;
641     case OSD_ReadWrite:
642       anOpenMode |= O_RDWR;
643       anFDOpenMode = "w+";
644       break;
645   }
646
647   myMode = theMode;
648   myFileChannel = open (aFileName.ToCString(), anOpenMode, theProtect.Internal());
649   if (myFileChannel >= 0)
650   {
651     myFILE = fdopen (myFileChannel, anFDOpenMode);
652   }
653   else
654   {
655     myError.SetValue (errno, Iam, "Open");
656   }
657 #endif
658 }
659
660 // =======================================================================
661 // function : BuildTemporary
662 // purpose  :
663 // =======================================================================
664 void OSD_File::BuildTemporary()
665 {
666 #ifdef _WIN32
667
668   TCollection_ExtendedString aTmpFolderW;
669   BOOL fOK = FALSE;
670 #ifndef OCCT_UWP
671   const OSD_File_WntKey TheRegKeys[2] =
672   {
673     { HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment" },
674     { HKEY_USERS,         L".DEFAULT\\Environment" }
675   };
676   for (int aKeyIter = 0; aKeyIter < 2; ++aKeyIter)
677   {
678     HKEY aRegKey = NULL;
679     if (RegOpenKeyExW (TheRegKeys[aKeyIter].hKey, TheRegKeys[aKeyIter].keyPath, 0, KEY_QUERY_VALUE, &aRegKey) != ERROR_SUCCESS)
680     {
681       continue;
682     }
683
684     DWORD aKeyType = 0, aKeySize = 0;
685     if (RegQueryValueExW (aRegKey, L"TEMP", NULL, &aKeyType, NULL, &aKeySize) == ERROR_SUCCESS)
686     {
687       NCollection_Array1<wchar_t> aKeyValW (0, aKeySize);
688       RegQueryValueExW (aRegKey, L"TEMP", NULL, &aKeyType, (LPBYTE )&aKeyValW.ChangeFirst(), &aKeySize);
689       if (aKeyType == REG_EXPAND_SZ)
690       {
691         wchar_t aTmpBuffer[MAX_PATH];
692         ExpandEnvironmentStringsW (&aKeyValW.First(), aTmpBuffer, MAX_PATH);
693         aTmpFolderW = TCollection_ExtendedString (aTmpBuffer);
694       }
695       else
696       {
697         aTmpFolderW = TCollection_ExtendedString (&aKeyValW.First());
698       }
699       fOK = TRUE;
700     }
701     RegCloseKey (aRegKey);
702     if (fOK) break;
703   }
704 #else
705   // Windows Registry not supported by UWP
706   {
707     wchar_t aTmpBuffer[MAX_PATH];
708     fOK = GetTempPathW (_countof(aTmpBuffer), aTmpBuffer) != 0;
709     aTmpFolderW = TCollection_ExtendedString (aTmpBuffer);
710   }
711 #endif
712   if (!fOK)
713   {
714     aTmpFolderW = "./";
715   }
716
717   wchar_t aTmpPathW[MAX_PATH];
718   GetTempFileNameW (aTmpFolderW.ToWideString(), L"CSF", 0, aTmpPathW);
719   if (IsOpen())
720   {
721     Close();
722   }
723
724   SetPath (OSD_Path (TCollection_AsciiString (aTmpPathW)));
725   Build (OSD_ReadWrite, OSD_Protection());
726
727 #else /* _WIN32 */
728
729   if (IsOpen())
730   {
731     Close();
732   }
733 #if defined(vax) || defined(__vms) || defined(VAXVMS)
734   FILE* fic = tmpfile();
735   int dummy = open("dummy", O_RDWR | O_CREAT); // open a dummy file
736   myFileChannel = dummy - 1;                   // this is file channel of "fic" +1
737   close (dummy);                               // close dummy file
738   unlink ("dummy");                            // removes dummy file
739 #else
740   char aTmpName[] = "/tmp/CSFXXXXXX";
741   myFileChannel = mkstemp (aTmpName);
742   const TCollection_AsciiString aName (aTmpName);
743   const OSD_Path aPath (aName);
744   SetPath (aPath);
745   myFILE = fdopen (myFileChannel, "w+");
746 #endif
747   myMode = OSD_ReadWrite;
748
749 #endif
750 }
751
752 // =======================================================================
753 // function : Read
754 // purpose  :
755 // =======================================================================
756 void OSD_File::Read (TCollection_AsciiString& theBuffer,
757                      const Standard_Integer theNbBytes)
758 {
759   if (OSD_File::KindOfFile() == OSD_DIRECTORY)
760   {
761     throw Standard_ProgramError ("OSD_File::Read(): it is a directory");
762   }
763   if (!IsOpen())
764   {
765     throw Standard_ProgramError ("OSD_File::Read(): file is not open");
766   }
767   if (Failed())
768   {
769     Perror();
770   }
771   if (myMode == OSD_WriteOnly)
772   {
773     throw Standard_ProgramError ("OSD_File::Read(): file is Write only");
774   }
775   if (theNbBytes <= 0)
776   {
777     throw Standard_ProgramError ("OSD_File::Read(): theNbBytes is 0");
778   }
779
780   NCollection_Array1<char> aBuffer (0, theNbBytes);
781   Standard_Integer aNbBytesRead = 0;
782 #ifdef _WIN32
783   Read (&aBuffer.ChangeFirst(), theNbBytes, aNbBytesRead);
784 #else
785   aNbBytesRead = read (myFileChannel, &aBuffer.ChangeFirst(), theNbBytes);
786   if (aNbBytesRead == -1)
787   {
788     aNbBytesRead = 0;
789     myError.SetValue (errno, Iam, "Read");
790   }
791   else if (aNbBytesRead < theNbBytes)
792   {
793     myIO = EOF;
794   }
795 #endif
796   if (aNbBytesRead != 0)
797   {
798     aBuffer.ChangeValue (aNbBytesRead) = '\0';
799     theBuffer = &aBuffer.First();
800   }
801   else
802   {
803     theBuffer.Clear();
804   }
805 }
806
807 // =======================================================================
808 // function : ReadLine
809 // purpose  :
810 // =======================================================================
811 void OSD_File::ReadLine (TCollection_AsciiString& theBuffer,
812                          const Standard_Integer theNbBytes,
813                          Standard_Integer& theNbBytesRead)
814 {
815   if (OSD_File::KindOfFile() == OSD_DIRECTORY)
816   {
817     throw Standard_ProgramError ("OSD_File::ReadLine(): it is a directory");
818   }
819   if (!IsOpen())
820   {
821     throw Standard_ProgramError ("OSD_File::ReadLine(): file is not open");
822   }
823   if (Failed())
824   {
825     Perror();
826   }
827   if (myMode == OSD_WriteOnly)
828   {
829     throw Standard_ProgramError ("OSD_File::ReadLine(): file is Write only");
830   }
831   if (theNbBytes <= 0)
832   {
833     throw Standard_ProgramError ("OSD_File::ReadLine(): theNbBytes is 0");
834   }
835 #ifdef _WIN32
836   if (myIO & FLAG_PIPE && !(myIO & FLAG_READ_PIPE))
837   {
838     throw Standard_ProgramError ("OSD_File::ReadLine(): attempt to read from write only pipe");
839   }
840
841   DWORD aNbBytesRead = 0;
842   LONG  aSeekPos = 0;
843   char  aPeekChar = '\0';
844   // +----> leave space for end-of-string
845   // |       plus <CR><LF> sequence
846   // |
847   NCollection_Array1<char> aBuffer (0, theNbBytes + 2);
848   if (myIO & FLAG_FILE)
849   {
850     if (!ReadFile (myFileHandle, &aBuffer.ChangeFirst(), theNbBytes, &aNbBytesRead, NULL))
851     {
852       _osd_wnt_set_error (myError, OSD_WFile);
853       theBuffer.Clear();
854       theNbBytesRead = 0;
855     }
856     else if (aNbBytesRead == 0)
857     {
858       theBuffer.Clear();
859       theNbBytesRead = 0;
860       myIO |= FLAG_EOF;
861     }
862     else
863     {
864       myIO &= ~FLAG_EOF;  // if the file increased since last read (LD)
865       theNbBytesRead = OSD_File_getLine (&aBuffer.ChangeFirst(), aNbBytesRead, aSeekPos);
866       if (theNbBytesRead == -1) // last character in the buffer is <CR> -
867       {                         // peek next character to see if it is a <LF>
868         DWORD dwDummy = 0;
869         if (!ReadFile (myFileHandle, &aPeekChar, 1, &dwDummy, NULL))
870         {
871           _osd_wnt_set_error (myError, OSD_WFile);
872         }
873         else if (dwDummy != 0) // end-of-file reached?
874         {
875           if (aPeekChar != '\n')  // if we did not get a <CR><LF> sequence
876           {
877             // adjust file position
878             LARGE_INTEGER aDistanceToMove;
879             aDistanceToMove.QuadPart = -1;
880             SetFilePointerEx (myFileHandle, aDistanceToMove, NULL, FILE_CURRENT);
881           }
882         }
883         else
884         {
885           myIO |= FLAG_EOF;
886         }
887
888         theNbBytesRead = aNbBytesRead;
889       }
890       else if (aSeekPos != 0)
891       {
892         LARGE_INTEGER aDistanceToMove;
893         aDistanceToMove.QuadPart = aSeekPos;
894         SetFilePointerEx (myFileHandle, aDistanceToMove, NULL, FILE_CURRENT);
895       }
896     }
897   }
898   else if (myIO & FLAG_SOCKET
899         || myIO & FLAG_PIPE
900         || myIO & FLAG_NAMED_PIPE)
901   {
902   #ifndef OCCT_UWP
903     aNbBytesRead = (DWORD )OSD_File_getBuffer (myFileHandle, &aBuffer.ChangeFirst(), (DWORD )theNbBytes, TRUE, myIO & FLAG_SOCKET);
904     if ((int )aNbBytesRead == -1)
905     {
906       _osd_wnt_set_error (myError, OSD_WFile);
907       theBuffer.Clear();
908       theNbBytesRead = 0;
909     }
910     else if (aNbBytesRead == 0) // connection closed - set end-of-file flag
911     {
912       theBuffer.Clear();
913       theNbBytesRead = 0;
914       myIO |= FLAG_EOF;
915     }
916     else
917     {
918       theNbBytesRead = OSD_File_getLine (&aBuffer.ChangeFirst(), aNbBytesRead, aSeekPos);
919       if (theNbBytesRead == -1)  // last character in the buffer is <CR> - peek next character to see if it is a <LF>
920       {
921         theNbBytesRead = aNbBytesRead; // (LD) always fits this case
922
923         const DWORD dwDummy = OSD_File_getBuffer (myFileHandle, &aPeekChar, 1, TRUE, myIO & FLAG_SOCKET);
924         if ((int )dwDummy == -1)
925         {
926           _osd_wnt_set_error (myError, OSD_WFile);
927         }
928         else if (dwDummy != 0) // connection closed?
929         {
930           if (aPeekChar == '\n') // we got a <CR><LF> sequence
931           {
932             ++aNbBytesRead;  // (LD) we have to jump <LF>
933           }
934         }
935         else
936         {
937           myIO |= FLAG_EOF;
938         }
939       }
940       else if (aSeekPos != 0)
941       {
942         aNbBytesRead = aNbBytesRead + aSeekPos;
943       }
944
945       // do not rewrite data in aBuffer
946       NCollection_Array1<char> aBuffer2 (0, theNbBytes + 2);
947       // remove pending input
948       OSD_File_getBuffer (myFileHandle, &aBuffer2.ChangeFirst(), aNbBytesRead, FALSE, myIO & FLAG_SOCKET);
949     }
950   #endif
951   }
952   else
953   {
954     throw Standard_ProgramError ("OSD_File::ReadLine(): incorrect call - file is a directory");
955   }
956
957   if (!Failed() && !IsAtEnd())
958   {
959     theBuffer = &aBuffer.First();
960   }
961 #else
962   NCollection_Array1<char> aBuffer (0, theNbBytes);
963   char* aBufferGets = fgets (&aBuffer.ChangeFirst(), theNbBytes, (FILE* )myFILE);
964   if (aBufferGets == NULL)
965   {
966     if (!feof ((FILE* )myFILE))
967     {
968       myError.SetValue (errno, Iam, "ReadLine");
969       return;
970     }
971
972     myIO = EOF;
973     theBuffer.Clear();
974     theNbBytesRead = 0;
975   }
976   else
977   {
978     aBuffer.ChangeLast() = '\0';
979     theNbBytesRead = (Standard_Integer )strlen (aBufferGets);
980     theBuffer.SetValue (1, aBufferGets);
981     theBuffer.Trunc (theNbBytesRead);
982   }
983 #endif
984 }
985
986 // =======================================================================
987 // function : KindOfFile
988 // purpose  :
989 // =======================================================================
990 OSD_KindFile OSD_File::KindOfFile() const
991 {
992   TCollection_AsciiString aFullName;
993   myPath.SystemName (aFullName);
994 #ifdef _WIN32
995   Standard_Integer aFlags = myIO;
996   if (myFileHandle == INVALID_HANDLE_VALUE)
997   {
998     if (aFullName.IsEmpty())
999     {
1000       throw Standard_ProgramError ("OSD_File::KindOfFile(): incorrect call - no filename given");
1001     }
1002     aFlags = _get_file_type (aFullName.ToCString(), INVALID_HANDLE_VALUE);
1003   }
1004
1005   switch (aFlags & FLAG_TYPE)
1006   {
1007     case FLAG_FILE:      return OSD_FILE;
1008     case FLAG_DIRECTORY: return OSD_DIRECTORY;
1009     case FLAG_SOCKET:    return OSD_SOCKET;
1010   }
1011   return OSD_UNKNOWN;
1012 #else
1013   struct stat aStatBuffer;
1014   if (stat (aFullName.ToCString(), &aStatBuffer) == 0)
1015   {
1016     if      (S_ISDIR (aStatBuffer.st_mode)) { return OSD_DIRECTORY; }
1017     else if (S_ISREG (aStatBuffer.st_mode)) { return OSD_FILE; }
1018     else if (S_ISLNK (aStatBuffer.st_mode)) { return OSD_LINK; }
1019     else if (S_ISSOCK(aStatBuffer.st_mode)) { return OSD_SOCKET; }
1020   }
1021   return OSD_UNKNOWN;
1022 #endif
1023 }
1024
1025 // =======================================================================
1026 // function : Read
1027 // purpose  :
1028 // =======================================================================
1029 void OSD_File::Read (const Standard_Address  theBuffer,
1030                      const Standard_Integer  theNbBytes,
1031                            Standard_Integer& theNbReadBytes)
1032 {
1033   if (OSD_File::KindOfFile ( ) == OSD_DIRECTORY)
1034   {
1035     throw Standard_ProgramError ("OSD_File::Read(): it is a directory");
1036   }
1037   if (!IsOpen())
1038   {
1039     throw Standard_ProgramError ("OSD_File::Read(): file is not open");
1040   }
1041   if (Failed())
1042   {
1043     Perror();
1044   }
1045   if (myMode == OSD_WriteOnly)
1046   {
1047     throw Standard_ProgramError ("OSD_File::Read(): file is Write only");
1048   }
1049   if (theNbBytes <= 0)
1050   {
1051     throw Standard_ProgramError ("OSD_File::Read(): theNbBytes is 0");
1052   }
1053   if (theBuffer == NULL)
1054   {
1055     throw Standard_ProgramError ("OSD_File::Read(): theBuffer is NULL");
1056   }
1057 #ifdef _WIN32
1058   if (myIO & FLAG_PIPE && !(myIO & FLAG_READ_PIPE))
1059   {
1060     throw Standard_ProgramError ("OSD_File::Read(): attempt to read from write only pipe");
1061   }
1062
1063   DWORD aNbReadBytes = 0;
1064   if (!ReadFile (myFileHandle, theBuffer, (DWORD )theNbBytes, &aNbReadBytes, NULL))
1065   {
1066     _osd_wnt_set_error (myError, OSD_WFile);
1067     aNbReadBytes = 0;
1068   }
1069   else if (aNbReadBytes == 0)
1070   {
1071     myIO |= FLAG_EOF;
1072   }
1073   else
1074   {
1075     myIO &= ~FLAG_EOF;
1076   }
1077
1078   theNbReadBytes = (Standard_Integer )aNbReadBytes;
1079 #else
1080   theNbReadBytes = 0;
1081   int aNbReadBytes = read (myFileChannel, (char* )theBuffer, theNbBytes);
1082   if (aNbReadBytes == -1)
1083   {
1084     myError.SetValue (errno, Iam, "Read");
1085   }
1086   else
1087   {
1088     if (aNbReadBytes < theNbBytes)
1089     {
1090       myIO = EOF;
1091     }
1092     theNbReadBytes = aNbReadBytes;
1093   }
1094 #endif
1095 }
1096
1097 // =======================================================================
1098 // function : Write
1099 // purpose  :
1100 // =======================================================================
1101 void OSD_File::Write (const Standard_Address theBuffer,
1102                       const Standard_Integer theNbBytes)
1103 {
1104   if (!IsOpen())
1105   {
1106     throw Standard_ProgramError ("OSD_File::Write(): file is not open");
1107   }
1108   if (Failed())
1109   {
1110     Perror();
1111   }
1112   if (myMode == OSD_ReadOnly)
1113   {
1114     throw Standard_ProgramError ("OSD_File::Write(): file is Read only");
1115   }
1116   if (theNbBytes <= 0)
1117   {
1118     throw Standard_ProgramError ("OSD_File::Write(): theNbBytes is null");
1119   }
1120 #ifdef _WIN32
1121   if ((myIO & FLAG_PIPE) != 0
1122    && (myIO & FLAG_READ_PIPE) != 0)
1123   {
1124     throw Standard_ProgramError ("OSD_File::Write(): attempt to write to read only pipe");
1125   }
1126
1127   DWORD aNbWritten = 0;
1128   if (!WriteFile (myFileHandle, theBuffer, (DWORD )theNbBytes, &aNbWritten, NULL)
1129   ||  aNbWritten != (DWORD )theNbBytes)
1130   {
1131     _osd_wnt_set_error (myError, OSD_WFile);
1132   }
1133 #else
1134   const int aNbWritten = write (myFileChannel, (const char* )theBuffer, theNbBytes);
1135   if (aNbWritten == -1)
1136   {
1137     myError.SetValue (errno, Iam, "Write");
1138   }
1139   else if (aNbWritten < theNbBytes)
1140   {
1141     myIO = EOF;
1142   }
1143 #endif
1144 }
1145
1146 // =======================================================================
1147 // function : Seek
1148 // purpose  :
1149 // =======================================================================
1150 void OSD_File::Seek (const Standard_Integer theOffset,
1151                      const OSD_FromWhere theWhence)
1152 {
1153   if (!IsOpen())
1154   {
1155     throw Standard_ProgramError ("OSD_File::Seek(): file is not open");
1156   }
1157   if (Failed())
1158   {
1159     Perror();
1160   }
1161
1162 #ifdef _WIN32
1163   DWORD aWhere = 0;
1164   if (myIO & FLAG_FILE
1165    || myIO & FLAG_DIRECTORY)
1166   {
1167     switch (theWhence)
1168     {
1169       case OSD_FromBeginning: aWhere = FILE_BEGIN;   break;
1170       case OSD_FromHere:      aWhere = FILE_CURRENT; break;
1171       case OSD_FromEnd:       aWhere = FILE_END;     break;
1172       default:
1173         throw Standard_ProgramError ("OSD_File::Seek(): invalid parameter");
1174     }
1175
1176     LARGE_INTEGER aDistanceToMove, aNewFilePointer;
1177     aNewFilePointer.QuadPart = 0;
1178     aDistanceToMove.QuadPart = theOffset;
1179     if (!SetFilePointerEx (myFileHandle, aDistanceToMove, &aNewFilePointer, aWhere))
1180     {
1181       _osd_wnt_set_error (myError, OSD_WFile);
1182     }
1183   }
1184   myIO &= ~FLAG_EOF;
1185 #else
1186   int aWhere = 0;
1187   switch (theWhence)
1188   {
1189     case OSD_FromBeginning: aWhere = SEEK_SET; break;
1190     case OSD_FromHere:      aWhere = SEEK_CUR; break;
1191     case OSD_FromEnd:       aWhere = SEEK_END; break;
1192     default:
1193       throw Standard_ProgramError ("OSD_File::Seek(): invalid parameter");
1194   }
1195
1196   off_t aStatus = lseek (myFileChannel, theOffset, aWhere);
1197   if (aStatus == -1)
1198   {
1199     myError.SetValue (errno, Iam, "Seek");
1200   }
1201 #endif
1202 }
1203
1204 // =======================================================================
1205 // function : Close
1206 // purpose  :
1207 // =======================================================================
1208 void OSD_File::Close()
1209 {
1210   if (!IsOpen())
1211   {
1212     throw Standard_ProgramError ("OSD_File::Close(): file is not open");
1213   }
1214   if (Failed())
1215   {
1216     Perror();
1217   }
1218 #ifdef _WIN32
1219   CloseHandle (myFileHandle);
1220   myFileHandle = INVALID_HANDLE_VALUE;
1221 #else
1222   // note: it probably should be single call to fclose()...
1223   int status = close (myFileChannel);
1224   if (status == -1)
1225   {
1226     myError.SetValue (errno, Iam, "Close");
1227   }
1228   myFileChannel = -1;
1229   if (myFILE != NULL)
1230   {
1231     status = fclose ((FILE* )myFILE);
1232     myFILE = NULL;
1233   }
1234 #endif
1235   myIO = 0;
1236 }
1237
1238 // =======================================================================
1239 // function : IsAtEnd
1240 // purpose  :
1241 // =======================================================================
1242 Standard_Boolean OSD_File::IsAtEnd()
1243 {
1244   if (!IsOpen())
1245   {
1246     throw Standard_ProgramError ("OSD_File::IsAtEnd(): file is not open");
1247   }
1248
1249 #ifdef _WIN32
1250   return (myIO & FLAG_EOF) != 0;
1251 #else
1252   return myIO == EOF;
1253 #endif
1254 }
1255
1256 // =======================================================================
1257 // function : Link
1258 // purpose  :
1259 // =======================================================================
1260 /*void OSD_File::Link (const TCollection_AsciiString& theToFile)
1261 {
1262   if (!IsOpen())
1263   {
1264     throw Standard_ProgramError ("OSD_File::Link(): file is not open");
1265   }
1266
1267   TCollection_AsciiString aFilePath;
1268   myPath.SystemName (aFilePath);
1269   link (aFilePath.ToCString(), theToFile.ToCString());
1270 }*/
1271
1272 #if defined(__CYGWIN32__) || defined(__MINGW32__)
1273   #ifdef __try /* is defined on MinGw as either "try" or "if (true)" */
1274   #undef __try
1275   #endif
1276   #define __try
1277   #define __finally
1278   #define __leave return
1279 #endif
1280
1281 // =======================================================================
1282 // function : SetLock
1283 // purpose  :
1284 // =======================================================================
1285 void OSD_File::SetLock (const OSD_LockType theLock)
1286 {
1287   if (!IsOpen())
1288   {
1289     throw Standard_ProgramError("OSD_File::SetLock(): file is not open");
1290   }
1291 #ifdef _WIN32
1292   DWORD dwFlags = 0;
1293   myLock = theLock;
1294   if (theLock == OSD_NoLock)
1295   {
1296     UnLock();
1297     return;
1298   }
1299   else if (theLock == OSD_ReadLock
1300         || theLock == OSD_ExclusiveLock)
1301   {
1302     dwFlags = LOCKFILE_EXCLUSIVE_LOCK;
1303   }
1304
1305   OVERLAPPED anOverlapped;
1306   ZeroMemory (&anOverlapped, sizeof(OVERLAPPED));
1307   __try
1308   {
1309     LARGE_INTEGER aSize;
1310     aSize.QuadPart = Size();
1311     if (!LockFileEx (myFileHandle, dwFlags, 0, aSize.LowPart, aSize.HighPart, &anOverlapped))
1312     {
1313       _osd_wnt_set_error (myError, OSD_WFile);
1314       __leave;
1315     }
1316     ImperativeFlag = Standard_True;
1317   }
1318   __finally {}
1319
1320 #elif defined(POSIX)
1321   int aLock = 0;
1322   switch (theLock)
1323   {
1324     case OSD_ExclusiveLock:
1325     case OSD_WriteLock:
1326       aLock = F_LOCK;
1327       break;
1328     case OSD_ReadLock:
1329       return;
1330     default:
1331       myError.SetValue (EINVAL, Iam, "SetLock");
1332       return;
1333   }
1334
1335   struct stat aStatBuf;
1336   if (fstat (myFileChannel, &aStatBuf) == -1)
1337   {
1338     myError.SetValue (errno, Iam, "SetLock");
1339     return;
1340   }
1341
1342   const int aStatus = lockf (myFileChannel, aLock, aStatBuf.st_size);
1343   if (aStatus == -1)
1344   {
1345     myError.SetValue (errno, Iam, "SetLock");
1346   }
1347   else
1348   {
1349     myLock = theLock;
1350   }
1351 #elif defined(SYSV)
1352   struct flock aLockKey;
1353   aLockKey.l_whence = 0;
1354   aLockKey.l_start = 0;
1355   aLockKey.l_len = 0;
1356   switch (theLock)
1357   {
1358     case OSD_ExclusiveLock:
1359     case OSD_WriteLock:
1360       aLockKey.l_type = F_WRLCK;
1361       break;
1362     case OSD_ReadLock:
1363       aLockKey.l_type = F_RDLCK;
1364       break;
1365     case OSD_NoLock:
1366       return;
1367     //default: myError.SetValue (EINVAL, Iam, "SetLock");
1368   }
1369
1370   const int aStatus = fcntl (myFileChannel, F_SETLKW, &aLockKey);
1371   if (aStatus == -1)
1372   {
1373     myError.SetValue (errno, Iam, "SetLock");
1374   }
1375   else
1376   {
1377     myLock = theLock;
1378   }
1379
1380   if (theLock == OSD_ExclusiveLock)
1381   {
1382     struct stat aStatBuf;
1383     fstat (myFileChannel, &aStatBuf);
1384     TCollection_AsciiString aFilePath;
1385     myPath.SystemName (aFilePath);
1386     chmod (aFilePath.ToCString(), aStatBuf.st_mode | S_ISGID);
1387     ImperativeFlag = Standard_True;
1388   }
1389 #else   /* BSD */
1390   int aLock = 0;
1391   switch (theLock)
1392   {
1393     case OSD_ExclusiveLock:
1394     case OSD_WriteLock:
1395       aLock = F_WRLCK;
1396       break;
1397     case OSD_ReadLock:
1398       aLock = F_RDLCK;
1399       break;
1400     default:
1401       myError.SetValue (EINVAL, Iam, "SetLock");
1402       return;
1403   }
1404
1405   const int aStatus = flock (myFileChannel, aLock);
1406   if (aStatus == -1)
1407   {
1408     myError.SetValue (errno, Iam, "SetLock");
1409   }
1410   else
1411   {
1412     myLock = theLock;
1413   }
1414 #endif
1415 }
1416
1417 #if defined(__CYGWIN32__) || defined(__MINGW32__)
1418   #undef __try
1419   #undef __finally
1420   #undef __leave
1421 #endif
1422
1423 // =======================================================================
1424 // function : UnLock
1425 // purpose  :
1426 // =======================================================================
1427 void OSD_File::UnLock()
1428 {
1429   if (!IsOpen())
1430   {
1431     throw Standard_ProgramError ("OSD_File::UnLock(): file is not open");
1432   }
1433 #ifdef _WIN32
1434   if (ImperativeFlag)
1435   {
1436     LARGE_INTEGER aSize;
1437     aSize.QuadPart = Size();
1438
1439     OVERLAPPED anOverlappedArea;
1440     anOverlappedArea.Offset = 0;
1441     anOverlappedArea.OffsetHigh = 0;
1442     if (!UnlockFileEx (myFileHandle, 0, aSize.LowPart, aSize.HighPart, &anOverlappedArea))
1443     {
1444       _osd_wnt_set_error (myError, OSD_WFile);
1445     }
1446     ImperativeFlag = Standard_False;
1447   }
1448 #elif defined(POSIX)
1449   struct stat aStatBuf;
1450   if (fstat (myFileChannel, &aStatBuf) == -1)
1451   {
1452     myError.SetValue (errno, Iam, "UnsetLock");
1453     return;
1454   }
1455
1456   const int aStatus = lockf (myFileChannel, F_ULOCK, aStatBuf.st_size);
1457   if (aStatus == -1)
1458   {
1459     myError.SetValue (errno, Iam, "SetLock");
1460   }
1461   else
1462   {
1463     myLock = OSD_NoLock;
1464   }
1465 #elif defined(SYSV)
1466   if (ImperativeFlag)
1467   {
1468     struct stat aStatBuf;
1469     fstat (myFileChannel, &aStatBuf);
1470     TCollection_AsciiString aBuffer;
1471     myPath.SystemName (aBuffer);
1472     chmod (aBuffer.ToCString(), aStatBuf.st_mode & ~S_ISGID);
1473     ImperativeFlag = Standard_False;
1474   }
1475
1476   struct flock aLockKey;
1477   aLockKey.l_type = F_UNLCK;
1478   const int aStatus = fcntl (myFileChannel, F_SETLK, &aLockKey);
1479   if (aStatus == -1)
1480   {
1481     myError.SetValue (errno, Iam, "UnSetLock");
1482   }
1483   else
1484   {
1485     myLock = OSD_NoLock;
1486   }
1487 #else
1488   const int aStatus = flock (myFileChannel, LOCK_UN);
1489   if (aStatus == -1)
1490   {
1491     myError.SetValue (errno, Iam, "UnSetLock");
1492   }
1493   else
1494   {
1495     myLock = OSD_NoLock;
1496   }
1497 #endif
1498 }
1499
1500 // =======================================================================
1501 // function : Size
1502 // purpose  :
1503 // =======================================================================
1504 Standard_Size OSD_File::Size()
1505 {
1506 #ifdef _WIN32
1507   if (!IsOpen())
1508   {
1509     throw Standard_ProgramError ("OSD_File::Size(): file is not open");
1510   }
1511 #if (_WIN32_WINNT >= 0x0500)
1512   LARGE_INTEGER aSize;
1513   aSize.QuadPart = 0;
1514   if (GetFileSizeEx (myFileHandle, &aSize) == 0)
1515   {
1516     _osd_wnt_set_error (myError, OSD_WFile);
1517   }
1518   return (Standard_Size )aSize.QuadPart;
1519 #else
1520   DWORD aSize = GetFileSize (myFileHandle, NULL);
1521   if (aSize == INVALID_FILE_SIZE)
1522   {
1523     _osd_wnt_set_error (myError, OSD_WFile);
1524   }
1525   return aSize;
1526 #endif
1527 #else
1528   if (myPath.Name().Length() == 0)
1529   {
1530     throw Standard_ProgramError ("OSD_File::Size(): empty file name");
1531   }
1532
1533   TCollection_AsciiString aFilePath;
1534   myPath.SystemName (aFilePath);
1535
1536   struct stat aStatBuf;
1537   const int aStatus = stat (aFilePath.ToCString(), &aStatBuf);
1538   if (aStatus == -1)
1539   {
1540     myError.SetValue (errno, Iam, "Size");
1541     return 0;
1542   }
1543   return (Standard_Size )aStatBuf.st_size;
1544 #endif
1545 }
1546
1547 // =======================================================================
1548 // function : IsOpen
1549 // purpose  :
1550 // =======================================================================
1551 Standard_Boolean OSD_File::IsOpen() const
1552 {
1553 #ifdef _WIN32
1554   return myFileHandle != INVALID_HANDLE_VALUE;
1555 #else
1556   return myFileChannel != -1;
1557 #endif
1558 }
1559
1560 // =======================================================================
1561 // function : IsReadable
1562 // purpose  :
1563 // =======================================================================
1564 Standard_Boolean OSD_File::IsReadable()
1565 {
1566   TCollection_AsciiString aFileName;
1567   myPath.SystemName (aFileName);
1568 #ifdef _WIN32
1569   HANDLE aChannel = OSD_File_openFile (aFileName, OSD_ReadOnly, OPEN_OLD);
1570   if (aChannel == INVALID_HANDLE_VALUE)
1571   {
1572     return Standard_False;
1573   }
1574
1575   CloseHandle (aChannel);
1576   return Standard_True;
1577 #else
1578   return access (aFileName.ToCString(), F_OK | R_OK) == 0;
1579 #endif
1580 }
1581
1582 // =======================================================================
1583 // function : IsWriteable
1584 // purpose  :
1585 // =======================================================================
1586 Standard_Boolean OSD_File::IsWriteable()
1587 {
1588   TCollection_AsciiString aFileName;
1589   myPath.SystemName (aFileName);
1590 #ifdef _WIN32
1591   HANDLE aChannel = OSD_File_openFile (aFileName, OSD_ReadWrite, OPEN_OLD);
1592   if (aChannel == INVALID_HANDLE_VALUE)
1593   {
1594     return Standard_False;
1595   }
1596
1597   CloseHandle (aChannel);
1598   return Standard_True;
1599 #else
1600   return access (aFileName.ToCString(), F_OK | R_OK | W_OK) == 0;
1601 #endif
1602 }
1603
1604 // =======================================================================
1605 // function : IsExecutable
1606 // purpose  :
1607 // =======================================================================
1608 Standard_Boolean OSD_File::IsExecutable()
1609 {
1610 #ifdef _WIN32
1611   return IsReadable();
1612 #else
1613   TCollection_AsciiString aFileName;
1614   myPath.SystemName (aFileName);
1615   return access (aFileName.ToCString(), F_OK | X_OK) == 0;
1616 #endif
1617 }
1618
1619 // =======================================================================
1620 // function : Rewind
1621 // purpose  :
1622 // =======================================================================
1623 void OSD_File::Rewind()
1624 {
1625 #ifdef _WIN32
1626   LARGE_INTEGER aDistanceToMove;
1627   aDistanceToMove.QuadPart = 0;
1628   SetFilePointerEx (myFileHandle, aDistanceToMove, NULL, FILE_BEGIN);
1629 #else
1630   rewind ((FILE* )myFILE);
1631 #endif
1632 }
1633
1634 // =======================================================================
1635 // function : ReadLastLine
1636 // purpose  :
1637 // =======================================================================
1638 Standard_Boolean OSD_File::ReadLastLine (TCollection_AsciiString& theLine,
1639                                          const Standard_Integer theDelay,
1640                                          const Standard_Integer theNbTries)
1641 {
1642   if (theNbTries <= 0)
1643   {
1644     return Standard_False;
1645   }
1646
1647   const Standard_Integer TheMaxLength = 1000;
1648   for (Standard_Integer Count = theNbTries; Count > 0; --Count)
1649   {
1650     Standard_Integer aLen = 0;
1651     ReadLine (theLine, TheMaxLength, aLen);
1652     if (!theLine.IsEmpty())
1653     {
1654       return Standard_True;
1655     }
1656     OSD::SecSleep (theDelay);
1657   }
1658   return Standard_False;
1659 }
1660
1661 // =======================================================================
1662 // function : Edit
1663 // purpose  :
1664 // =======================================================================
1665 Standard_Boolean OSD_File::Edit()
1666 {
1667   std::cout << "Function OSD_File::Edit() not yet implemented.\n";
1668   return Standard_False;
1669 }
1670
1671
1672 // None of the existing security APIs are supported in a UWP applications
1673 #ifdef _WIN32
1674 #ifndef OCCT_UWP
1675
1676 #if defined(__CYGWIN32__) || defined(__MINGW32__)
1677   #define __try
1678   #define __finally
1679   #define __leave return retVal
1680 #endif
1681
1682 PSECURITY_DESCRIPTOR __fastcall _osd_wnt_protection_to_sd (const OSD_Protection& theProtection, BOOL theIsDir, const wchar_t* theFileName)
1683 {
1684   BOOL                 fOK      = FALSE;
1685   PACL                 pACL     = NULL;
1686   HANDLE               hProcess = NULL;
1687   PSID                 pSIDowner;
1688   DWORD                dwACLsize       = sizeof(ACL);
1689   DWORD                dwIndex         = 0;
1690   PTOKEN_OWNER         pTkOwner        = NULL;
1691   PTOKEN_GROUPS        pTkGroups       = NULL;
1692   PTOKEN_PRIMARY_GROUP pTkPrimaryGroup = NULL;
1693   PSECURITY_DESCRIPTOR retVal = NULL;
1694   PSECURITY_DESCRIPTOR pfSD = NULL;
1695   BOOL                 fDummy;
1696   PFILE_ACE            pFileACE;
1697
1698   __try
1699   {
1700     const int j = theIsDir ? 1 : 0;
1701     if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &hProcess))
1702     {
1703        __leave;
1704     }
1705     if ((pTkGroups = (PTOKEN_GROUPS )GetTokenInformationEx (hProcess, TokenGroups)) == NULL)
1706     {
1707       __leave;
1708     }
1709     if ((pTkOwner = (PTOKEN_OWNER )GetTokenInformationEx (hProcess, TokenOwner)) == NULL)
1710     {
1711       __leave;
1712     }
1713     if ((pTkPrimaryGroup = (PTOKEN_PRIMARY_GROUP )GetTokenInformationEx (hProcess, TokenPrimaryGroup)) == NULL)
1714     {
1715       __leave;
1716     }
1717
1718 retry:
1719     if (theFileName == NULL)
1720     {
1721       pSIDowner = pTkOwner->Owner;
1722     }
1723     else
1724     {
1725       pfSD = GetFileSecurityEx (theFileName, OWNER_SECURITY_INFORMATION);
1726       if (pfSD == NULL || !GetSecurityDescriptorOwner (pfSD, &pSIDowner, &fDummy))
1727       {
1728         theFileName = NULL;
1729         goto retry;
1730       }
1731     }
1732
1733     PSID pSIDadmin = AdminSid();
1734     PSID pSIDworld = WorldSid();
1735
1736     DWORD dwAccessAdmin = OSD_File_getAccessMask (theProtection.System());
1737     DWORD dwAccessGroup = OSD_File_getAccessMask (theProtection.Group());
1738     DWORD dwAccessOwner = OSD_File_getAccessMask (theProtection.User());
1739     DWORD dwAccessWorld = OSD_File_getAccessMask (theProtection.World());
1740
1741     DWORD dwAccessAdminDir = OSD_File_getDirAccessMask (theProtection.System());
1742   //DWORD dwAccessGroupDir = OSD_File_getDirAccessMask (theProtection.Group());
1743     DWORD dwAccessOwnerDir = OSD_File_getDirAccessMask (theProtection.User());
1744   //DWORD dwAccessWorldDir = OSD_File_getDirAccessMask (theProtection.World());
1745     if (dwAccessGroup != 0)
1746     {
1747       for (int aGroupIter = 0; aGroupIter < (int )pTkGroups->GroupCount; ++aGroupIter)
1748       {
1749         PSID pSIDtemp = pTkGroups->Groups[aGroupIter].Sid;
1750         if (!NtPredefinedSid (pSIDtemp)
1751          && !EqualSid        (pSIDtemp, pSIDworld)
1752          && !EqualSid        (pSIDtemp, pTkPrimaryGroup->PrimaryGroup)
1753          &&  IsValidSid      (pSIDtemp))
1754         {
1755           dwACLsize += ((GetLengthSid (pSIDtemp) + ACE_HEADER_SIZE) << j);
1756         }
1757       }
1758     }
1759
1760     dwACLsize += (((GetLengthSid (pSIDowner) + ACE_HEADER_SIZE) << j)
1761                 + ((GetLengthSid (pSIDadmin) + ACE_HEADER_SIZE) << j)
1762                 + ((GetLengthSid (pSIDworld) + ACE_HEADER_SIZE) << j));
1763     if ((pACL = CreateAcl (dwACLsize)) == NULL)
1764     {
1765       __leave;
1766     }
1767
1768     if (dwAccessAdmin != 0)
1769     {
1770       if ((pFileACE = (PFILE_ACE )AllocAccessAllowedAce (dwAccessAdmin, 0, pSIDadmin)) != NULL)
1771       {
1772         AddAce (pACL, ACL_REVISION, dwIndex++, pFileACE, pFileACE->header.AceSize);
1773         if (theIsDir)
1774         {
1775           pFileACE->dwMask = dwAccessAdminDir;
1776           pFileACE->header.AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1777           AddAce (pACL, ACL_REVISION, dwIndex++, pFileACE, pFileACE->header.AceSize);
1778         }
1779         FreeAce (pFileACE);
1780       }
1781     }
1782
1783     if (dwAccessOwner != 0)
1784     {
1785       if ((pFileACE = (PFILE_ACE )AllocAccessAllowedAce (dwAccessOwner, 0, pSIDowner)) != NULL)
1786       {
1787         AddAce (pACL, ACL_REVISION, dwIndex++, pFileACE, pFileACE->header.AceSize);
1788         if (theIsDir)
1789         {
1790           pFileACE->dwMask = dwAccessOwnerDir;
1791           pFileACE->header.AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1792           AddAce (pACL, ACL_REVISION, dwIndex++, pFileACE, pFileACE->header.AceSize);
1793         }
1794         FreeAce (pFileACE);
1795       }
1796     }
1797
1798     if (dwAccessWorld != 0)
1799     {
1800       if ((pFileACE = (PFILE_ACE )AllocAccessAllowedAce (dwAccessWorld, 0, pSIDworld)) != NULL)
1801       {
1802         AddAce (pACL, ACL_REVISION, dwIndex++, pFileACE, pFileACE->header.AceSize);
1803         if (theIsDir)
1804         {
1805           pFileACE->header.AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1806           AddAce (pACL, ACL_REVISION, dwIndex++, pFileACE, pFileACE->header.AceSize);
1807         }
1808         FreeAce (pFileACE);
1809       }
1810     }
1811
1812     if (dwAccessGroup != 0)
1813     {
1814       for (int aGroupIter = 0; aGroupIter < (int )pTkGroups->GroupCount; ++aGroupIter)
1815       {
1816         PSID pSIDtemp = pTkGroups->Groups[aGroupIter].Sid;
1817         if (!NtPredefinedSid(pSIDtemp)
1818          && !EqualSid       (pSIDtemp, pSIDworld)
1819          && !EqualSid       (pSIDtemp, pTkPrimaryGroup->PrimaryGroup)
1820          && IsValidSid      (pSIDtemp))
1821         {
1822           if (dwAccessGroup != 0)
1823           {
1824             if ((pFileACE = (PFILE_ACE )AllocAccessAllowedAce (dwAccessGroup, 0, pSIDtemp)) != NULL)
1825             {
1826               AddAce (pACL, ACL_REVISION, dwIndex++, pFileACE, pFileACE->header.AceSize);
1827               if (theIsDir)
1828               {
1829                 pFileACE->header.AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1830                 AddAce (pACL, ACL_REVISION, dwIndex++, pFileACE, pFileACE->header.AceSize);
1831               }
1832               FreeAce (pFileACE);
1833             }
1834           }
1835         }
1836       }
1837     }
1838
1839     if ((retVal = AllocSD()) == NULL)
1840     {
1841       __leave;
1842     }
1843
1844     if (!SetSecurityDescriptorDacl (retVal, TRUE, pACL, TRUE))
1845     {
1846       __leave;
1847     }
1848     fOK = TRUE;
1849   }  // end __try
1850
1851   __finally
1852   {
1853     if (!fOK)
1854     {
1855       if (retVal != NULL)
1856       {
1857         FreeSD (retVal);
1858       }
1859       else if (pACL != NULL)
1860       {
1861         FreeAcl (pACL);
1862       }
1863       retVal = NULL;
1864     }
1865
1866     if (hProcess != NULL)
1867     {
1868       CloseHandle (hProcess);
1869     }
1870     if (pTkOwner != NULL)
1871     {
1872       FreeTokenInformation (pTkOwner);
1873     }
1874     if (pTkGroups != NULL)
1875     {
1876       FreeTokenInformation (pTkGroups);
1877     }
1878     if (pTkPrimaryGroup != NULL)
1879     {
1880       FreeTokenInformation (pTkPrimaryGroup);
1881     }
1882     if (pfSD            != NULL)
1883     {
1884       FreeFileSecurity (pfSD);
1885     }
1886   }
1887
1888   return retVal;
1889 }
1890
1891 BOOL __fastcall _osd_wnt_sd_to_protection (PSECURITY_DESCRIPTOR pSD, OSD_Protection& theProtection, BOOL theIsDir)
1892 {
1893   BOOL fPresent = FALSE;
1894   BOOL fDefaulted = FALSE;
1895   PACL pACL;
1896   PSID pSIDowner;
1897   BOOL retVal = FALSE;
1898   __try
1899   {
1900     if (!GetSecurityDescriptorOwner (pSD, &pSIDowner, &fDefaulted))
1901     {
1902       __leave;
1903     }
1904     if (!GetSecurityDescriptorDacl (pSD, &fPresent, &pACL, &fDefaulted)
1905      || !fPresent)
1906     {
1907       __leave;
1908     }
1909     if (pSIDowner == NULL || pACL == NULL)
1910     {
1911       SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
1912       __leave;
1913     }
1914
1915     PSID pSIDadmin = AdminSid();
1916     PSID pSIDworld = WorldSid();
1917     DWORD dwAccessOwner = 0;
1918     DWORD dwAccessGroup = 0;
1919     DWORD dwAccessAdmin = 0;
1920     DWORD dwAccessWorld = 0;
1921     for (DWORD anAceIter = 0; anAceIter < pACL->AceCount; ++anAceIter)
1922     {
1923       LPVOID pACE;
1924       if (GetAce (pACL, anAceIter, &pACE))
1925       {
1926         const DWORD dwAccess = ((PACE_HEADER )pACE)->AceType == ACCESS_DENIED_ACE_TYPE
1927                              ?  0
1928                              : *GET_MSK(pACE);
1929         if (EqualSid (pSIDowner, GET_SID(pACE)))
1930         {
1931           dwAccessOwner = dwAccess;
1932         }
1933         else if (EqualSid (pSIDadmin, GET_SID(pACE)))
1934         {
1935           dwAccessAdmin = dwAccess;
1936         }
1937         else if (EqualSid (pSIDworld, GET_SID(pACE)))
1938         {
1939           dwAccessWorld = dwAccess;
1940         }
1941         else
1942         {
1943           dwAccessGroup = dwAccess;
1944         }
1945       }
1946     }
1947
1948     typedef OSD_SingleProtection (*OSD_File_getProtection_t)(DWORD );
1949     OSD_File_getProtection_t aGetProtFunc = theIsDir ? &OSD_File_getProtectionDir : &OSD_File_getProtection;
1950     theProtection.SetValues (aGetProtFunc (dwAccessAdmin),
1951                              aGetProtFunc (dwAccessOwner),
1952                              aGetProtFunc (dwAccessGroup),
1953                              aGetProtFunc (dwAccessWorld));
1954     retVal = TRUE;
1955   }  // end __try
1956   __finally {}
1957
1958   return retVal;
1959 }  // end _osd_wnt_sd_to_protection
1960
1961 #if defined(__CYGWIN32__) || defined(__MINGW32__)
1962   #undef __try
1963   #undef __finally
1964   #undef __leave
1965 #endif
1966
1967 #endif
1968 #endif /* _WIN32 */