// Copyright (c) 1998-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <OSD_FileNode.hxx>

#include <OSD_Protection.hxx>
#include <Quantity_Date.hxx>
#include <Standard_ProgramError.hxx>

#ifndef _WIN32

//----------------------------------------------------------------------------
//------------------- Linux Sources of OSD_FileNode --------------------------
//----------------------------------------------------------------------------

  #include <OSD_OSDError.hxx>
  #include <OSD_Path.hxx>
  #include <OSD_WhoAmI.hxx>
  #include <Standard_NullObject.hxx>

  #include <cerrno>
  #include <fcntl.h>
  #include <cstdio>
  #include <cstdlib>
  #include <sys/stat.h>
  #include <unistd.h>
// For "system"
const OSD_WhoAmI Iam = OSD_WFileNode;

// Create a file/directory object

OSD_FileNode::OSD_FileNode() = default;

// Create and initialize a file/directory object

OSD_FileNode::OSD_FileNode(const OSD_Path& Name)
{
  SetPath(Name);
}

// Get values of object

void OSD_FileNode::Path(OSD_Path& Name) const
{
  Name = myPath;
}

// Set values of object

void OSD_FileNode::SetPath(const OSD_Path& Name)
{
  myError.Reset();
  myPath = Name;
}

// Test if specified file/directory exists

bool OSD_FileNode::Exists()
{
  int status;

  // if (myPath.Name().Length()==0)  A directory can have a null name field (ex: root)
  //  throw OSD_OSDError("OSD_FileNode::Exists : no name was given"); (LD)

  // if (Failed()) Perror();

  TCollection_AsciiString aBuffer;
  myPath.SystemName(aBuffer);
  status = access(aBuffer.ToCString(), F_OK);

  if (status == 0)
  {
    return (true);
  }
  else
  {
    return (false);
  }
}

// Physically remove a file/directory

void OSD_FileNode::Remove()
{

  // if (myPath.Name().Length()==0) A directory can have a null name field (ex: root)
  //  throw OSD_OSDError("OSD_FileNode::Remove : no name was given"); (LD)

  // if (Failed()) Perror();

  TCollection_AsciiString aBuffer;
  myPath.SystemName(aBuffer);

  if (access(aBuffer.ToCString(), W_OK))
  {
    myError.SetValue(errno, Iam, "Remove");
    return;
  }

  struct stat stat_buf;

  if (stat(aBuffer.ToCString(), &stat_buf))
  {
    myError.SetValue(errno, Iam, "Remove");
    return;
  }

  if (S_ISDIR(stat_buf.st_mode))
  {
    // DIRECTORY

    if (rmdir(aBuffer.ToCString()))
    {
      myError.SetValue(errno, Iam, "Remove");
      return;
    }
    return;
  }
  else if (S_ISREG(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode) || S_ISFIFO(stat_buf.st_mode))
  {

    if (unlink(aBuffer.ToCString()) == -1)
    {
      myError.SetValue(errno, Iam, "Remove");
    }
    return;
  }
  myError.SetValue(EINVAL, Iam, "Remove");
}

// Move a file/directory to another path

void OSD_FileNode::Move(const OSD_Path& NewPath)
{
  int                     status;
  TCollection_AsciiString thisPath;

  // if (myPath.Name().Length()==0)
  //  throw OSD_OSDError("OSD_FileNode::Move : no name was given");

  // if (Failed()) Perror();

  NewPath.SystemName(thisPath); // Get internal path name
  TCollection_AsciiString aBuffer;
  myPath.SystemName(aBuffer);
  status = rename(aBuffer.ToCString(), thisPath.ToCString());

  if (status == -1)
  {
    myError.SetValue(errno, Iam, "Move");
  }
}

// Copy a file to another path and name
int static copy_file(const char* src, const char* trg)
{
  int err = 0;
  errno   = 0;
  int fds = open(src, O_RDONLY);
  if (fds < 0)
  {
    return errno;
  }

  int fdo = open(trg, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  if (fdo < 0)
  {
    err = errno;
    close(fds);
    return err;
  }

  const int BUFSIZE = 4096;
  char      buf[BUFSIZE];
  int       n = 0;
  while ((n = (int)read(fds, buf, BUFSIZE)) > 0)
  {
    if (write(fdo, buf, n) != n)
    {
      // writing error
      if (!errno)
      {
        errno = ENOSPC;
      }
      break;
    }
  }

  err = errno;
  close(fdo);
  if (!err)
  {
    err = errno;
  }
  close(fds);
  if (!err)
  {
    err = errno;
  }
  return err;
}

void OSD_FileNode::Copy(const OSD_Path& ToPath)
{
  int                     status;
  TCollection_AsciiString second_name;

  // if (myPath.Name().Length()==0)   Copy .login would raise !!
  //  throw OSD_OSDError("OSD_FileNode::Copy : no name was given");
  // if (Failed()) Perror();

  ToPath.SystemName(second_name);

  TCollection_AsciiString aBuffer;
  myPath.SystemName(aBuffer);
  status = copy_file(aBuffer.ToCString(), second_name.ToCString());
  if (status != 0)
  {
    myError.SetValue(-1, Iam, "Copy failed"); // (LD)
  }
  #ifdef OCCT_DEBUG
  printf("Status %d : errno # %d\n", status, errno);
  #endif
}

// Get protections of a file/directory

OSD_Protection OSD_FileNode::Protection()
{
  OSD_Protection thisProt;
  struct stat    myStat;
  int            status;
  int            s, u, g, w;

  // if (myPath.Name().Length()==0)
  //  throw OSD_OSDError("OSD_FileNode::Protection : no name was given");

  // if (Failed()) Perror();

  TCollection_AsciiString aBuffer;
  myPath.SystemName(aBuffer);
  status = stat(aBuffer.ToCString(), &myStat);
  if (status == -1)
  {
    myError.SetValue(errno, Iam, "Protection");
  }

  u = g = w = OSD_None;

  if (myStat.st_mode & S_IRUSR)
  {
    u |= OSD_R;
  }
  if (myStat.st_mode & S_IWUSR)
  {
    u |= OSD_W;
  }
  if (myStat.st_mode & S_IXUSR)
  {
    u |= OSD_X;
  }

  if (myStat.st_mode & S_IRGRP)
  {
    g |= OSD_R;
  }
  if (myStat.st_mode & S_IWGRP)
  {
    g |= OSD_W;
  }
  if (myStat.st_mode & S_IXGRP)
  {
    g |= OSD_X;
  }

  if (myStat.st_mode & S_IROTH)
  {
    w |= OSD_R;
  }
  if (myStat.st_mode & S_IWOTH)
  {
    w |= OSD_W;
  }
  if (myStat.st_mode & S_IXOTH)
  {
    w |= OSD_X;
  }

  s = g;
  thisProt.SetValues((OSD_SingleProtection)s,
                     (OSD_SingleProtection)u,
                     (OSD_SingleProtection)g,
                     (OSD_SingleProtection)w);

  return (thisProt);
}

// Set protections of a file/directory

void OSD_FileNode::SetProtection(const OSD_Protection& Prot)
{
  int status;

  //  if (myPath.Name().Length()==0)
  //  throw OSD_OSDError("OSD_FileNode::SetProtection : no name was given");

  // if (Failed()) Perror();

  TCollection_AsciiString aBuffer;
  myPath.SystemName(aBuffer);
  status = chmod(aBuffer.ToCString(), (mode_t)Prot.Internal());
  if (status == -1)
  {
    myError.SetValue(errno, Iam, "SetProtection");
  }
}

// return the date of last access of file/directory

Quantity_Date OSD_FileNode::CreationMoment()
{

  Quantity_Date result;
  struct tm*    decode;
  struct stat   buffer;

  // if (myPath.Name().Length()==0)
  //  throw OSD_OSDError("OSD_FileNode::CreationMoment : no name was given");

  // if (Failed()) Perror();

  /* Get File Information */

  TCollection_AsciiString aBuffer;
  myPath.SystemName(aBuffer);
  if (!stat(aBuffer.ToCString(), &buffer))
  {
    time_t aTime = (time_t)buffer.st_ctime;
    decode       = localtime(&aTime);
    result.SetValues(decode->tm_mon + 1,
                     decode->tm_mday,
                     decode->tm_year + 1900,
                     decode->tm_hour,
                     decode->tm_min,
                     decode->tm_sec,
                     0,
                     0);
  }
  else
  {
    result.SetValues(1, 1, 1979, 0, 0, 0, 0, 0);
  }
  return (result);
}

// return Last access of file/directory

Quantity_Date OSD_FileNode::AccessMoment()
{

  Quantity_Date result;
  struct tm*    decode;
  struct stat   buffer;

  // if (myPath.Name().Length()==0)
  //  throw OSD_OSDError("OSD_FileNode::AccessMoment : no name was given");

  // if (Failed()) Perror();

  /* Get File Information */

  TCollection_AsciiString aBuffer;
  myPath.SystemName(aBuffer);
  if (!stat(aBuffer.ToCString(), &buffer))
  {
    time_t aTime = (time_t)buffer.st_ctime;
    decode       = localtime(&aTime);
    result.SetValues(decode->tm_mon + 1,
                     decode->tm_mday,
                     decode->tm_year + 1900,
                     decode->tm_hour,
                     decode->tm_min,
                     decode->tm_sec,
                     0,
                     0);
  }
  else
  {
    result.SetValues(1, 1, 1979, 0, 0, 0, 0, 0);
  }
  return (result);
}

void OSD_FileNode::Reset()
{
  myError.Reset();
}

bool OSD_FileNode::Failed() const
{
  return (myError.Failed());
}

void OSD_FileNode::Perror()
{
  myError.Perror();
}

int OSD_FileNode::Error() const
{
  return (myError.Error());
}

#else /* _WIN32 */

//----------------------------------------------------------------------------
//-------------------  WNT Sources of OSD_FileNode ---------------------------
//----------------------------------------------------------------------------

  #ifdef NONLS
    #undef NONLS
  #endif
  #include <windows.h>

  #include <TCollection_ExtendedString.hxx>

  #include <OSD_WNT.hxx>

  #ifndef _INC_TCHAR
    #include <tchar.h>
  #endif // _INC_TCHAR

  #include <strsafe.h>

  #define TEST_RAISE(arg) _test_raise(fName, (arg))
  #define RAISE(arg) throw Standard_ProgramError((arg))

  #ifndef OCCT_UWP
// None of the existing security APIs are supported in a UWP applications
PSECURITY_DESCRIPTOR __fastcall _osd_wnt_protection_to_sd(const OSD_Protection&,
                                                          BOOL,
                                                          const wchar_t*);
BOOL __fastcall _osd_wnt_sd_to_protection(PSECURITY_DESCRIPTOR pSD, OSD_Protection& prot, BOOL);
  #endif
int __fastcall _get_file_type(const char*, HANDLE);

void _osd_wnt_set_error(OSD_Error&, int, ...);

static BOOL __fastcall _get_file_time(const wchar_t*, LPSYSTEMTIME, BOOL);
static void __fastcall _test_raise(TCollection_AsciiString, const char*);

//=================================================================================================

OSD_FileNode::OSD_FileNode() {}

//=================================================================================================

OSD_FileNode::OSD_FileNode(const OSD_Path& Name)
{
  myPath = Name;
} // end constructor ( 2 )

//=================================================================================================

void OSD_FileNode::Path(OSD_Path& Name) const
{

  Name = myPath;

} // end OSD_FileNode :: Path

//=================================================================================================

void OSD_FileNode::SetPath(const OSD_Path& Name)
{

  myPath = Name;

} // end OSD_FileNode :: SetPath

//=================================================================================================

bool OSD_FileNode::Exists()
{
  myError.Reset();

  bool                    retVal = false;
  TCollection_AsciiString fName;

  myPath.SystemName(fName);

  if (fName.IsEmpty())
    return false;
  TEST_RAISE("Exists");

  // make wide character string from UTF-8
  TCollection_ExtendedString fNameW(fName);

  WIN32_FILE_ATTRIBUTE_DATA aFileInfo;

  if (!GetFileAttributesExW(fNameW.ToWideString(), GetFileExInfoStandard, &aFileInfo))
  {
    if (GetLastError() != ERROR_FILE_NOT_FOUND)
    {
      _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString());
    }
  }
  else
  {
    retVal = true;
  }

  return retVal;

} // end OSD_FileNode :: Exists

//=================================================================================================

void OSD_FileNode::Remove()
{

  TCollection_AsciiString fName;

  myPath.SystemName(fName);
  TCollection_ExtendedString fNameW(fName);

  TEST_RAISE("Remove");

  switch (_get_file_type(fName.ToCString(), INVALID_HANDLE_VALUE))
  {

    case FLAG_FILE:

      if (!DeleteFileW(fNameW.ToWideString()))
        _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString());
      break;

    case FLAG_DIRECTORY:

      // LD : Suppression de l'appel a DeleteDirectory pour
      //      ne pas detruire un repertoire no vide.

      if (!RemoveDirectoryW(fNameW.ToWideString()))
        _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString());
      break;

    default:
      RAISE("OSD_FileNode :: Remove (): invalid file type - neither file nor directory");
  } // end switch

} // end OSD_FileNode :: Remove

//=================================================================================================

void OSD_FileNode::Move(const OSD_Path& NewPath)
{

  TCollection_AsciiString fName;
  TCollection_AsciiString fNameDst;

  myPath.SystemName(fName);
  TCollection_ExtendedString fNameW(fName);

  TEST_RAISE("Move");

  NewPath.SystemName(fNameDst);
  TCollection_ExtendedString fNameDstW(fNameDst);

  switch (_get_file_type(fName.ToCString(), INVALID_HANDLE_VALUE))
  {

    case FLAG_FILE:

      if (!MoveFileExW(fNameW.ToWideString(),
                       fNameDstW.ToWideString(),
                       MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
        _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString(), fNameDstW.ToWideString());
      break;

    case FLAG_DIRECTORY:

      if (!MoveDirectory(fNameW.ToWideString(), fNameDstW.ToWideString()))
        _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString(), fNameDstW.ToWideString());
      break;

    default:
      RAISE("OSD_FileNode :: Move (): invalid file type - neither file nor directory");
  } // end switch

} // end OSD_FileNode :: Move

//=================================================================================================

void OSD_FileNode::Copy(const OSD_Path& ToPath)
{

  TCollection_AsciiString fName;
  TCollection_AsciiString fNameDst;

  myPath.SystemName(fName);
  TCollection_ExtendedString fNameW(fName);

  TEST_RAISE("Copy");

  ToPath.SystemName(fNameDst);
  TCollection_ExtendedString fNameDstW(fNameDst);

  switch (_get_file_type(fName.ToCString(), INVALID_HANDLE_VALUE))
  {

    case FLAG_FILE:
  #ifndef OCCT_UWP
      if (!CopyFileW(fNameW.ToWideString(), fNameDstW.ToWideString(), FALSE))
  #else
      if (CopyFile2(fNameW.ToWideString(), fNameDstW.ToWideString(), FALSE) != S_OK)
  #endif
        _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString(), fNameDstW.ToWideString());
      break;

    case FLAG_DIRECTORY:

      if (!CopyDirectory(fNameW.ToWideString(), fNameDstW.ToWideString()))
        _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString(), fNameDstW.ToWideString());

      break;

    default:
      RAISE("OSD_FileNode :: Copy (): invalid file type - neither file nor directory");

  } // end switch

} // end OSD_FileNode :: Copy

  // None of the existing security APIs are supported in a UWP applications
  #ifndef OCCT_UWP

//=================================================================================================

OSD_Protection OSD_FileNode::Protection()
{

  OSD_Protection          retVal;
  TCollection_AsciiString fName;
  PSECURITY_DESCRIPTOR    pSD;

  myPath.SystemName(fName);
  TCollection_ExtendedString fNameW(fName);

  TEST_RAISE("Protection");

  if ((pSD = GetFileSecurityEx(fNameW.ToWideString(),
                               DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION))
        == NULL
      || !_osd_wnt_sd_to_protection(pSD,
                                    retVal,
                                    _get_file_type(fName.ToCString(), INVALID_HANDLE_VALUE)
                                      == FLAG_DIRECTORY))

    _osd_wnt_set_error(myError, OSD_WFileNode);

  if (pSD != NULL)

    FreeFileSecurity(pSD);

  return retVal;

} // end OSD_FileNode :: Protection

//=================================================================================================

void OSD_FileNode::SetProtection(const OSD_Protection& Prot)
{

  TCollection_AsciiString fName;
  PSECURITY_DESCRIPTOR    pSD;

  myPath.SystemName(fName);
  TCollection_ExtendedString fNameW(fName);

  TEST_RAISE("SetProtection");

  pSD = _osd_wnt_protection_to_sd(Prot,
                                  _get_file_type(fName.ToCString(), INVALID_HANDLE_VALUE)
                                    == FLAG_DIRECTORY,
                                  fNameW.ToWideString());

  if (pSD == NULL || !SetFileSecurityW(fNameW.ToWideString(), DACL_SECURITY_INFORMATION, pSD))
    _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString());

  if (pSD != NULL)

    FreeSD(pSD);

} // end OSD_FileNode :: SetProtection

  #else /* UWP stub */

    #include <io.h>

//=================================================================================================

OSD_Protection OSD_FileNode::Protection()
{
  TCollection_AsciiString fName;

  myPath.SystemName(fName);
  TCollection_ExtendedString fNameW(fName);

  OSD_SingleProtection aProt = OSD_None;
  if (_waccess_s(fNameW.ToWideString(), 6))
    aProt = OSD_RW;
  else if (_waccess_s(fNameW.ToWideString(), 2))
    aProt = OSD_W;
  else if (_waccess_s(fNameW.ToWideString(), 4))
    aProt = OSD_R;

  // assume full access for system and none for everybody
  OSD_Protection retVal(OSD_RWXD, aProt, aProt, OSD_None);
  return retVal;
} // end OSD_FileNode :: Protection

//=================================================================================================

void OSD_FileNode::SetProtection(const OSD_Protection& /*Prot*/) {
} // end OSD_FileNode :: SetProtection

  #endif

//=================================================================================================

Quantity_Date OSD_FileNode::AccessMoment()
{

  Quantity_Date           retVal;
  SYSTEMTIME              stAccessMoment;
  SYSTEMTIME              stAccessSystemMoment;
  TCollection_AsciiString fName;

  myPath.SystemName(fName);
  TCollection_ExtendedString fNameW(fName);

  TEST_RAISE("AccessMoment");

  if (_get_file_time(fNameW.ToWideString(), &stAccessSystemMoment, TRUE))
  {
    SYSTEMTIME* aSysTime = &stAccessMoment;
    BOOL aFlag = SystemTimeToTzSpecificLocalTime(NULL, &stAccessSystemMoment, &stAccessMoment);
    if (aFlag == 0) // AGV: test for success (e.g., unsupported on Win95/98)
      aSysTime = &stAccessSystemMoment;
    retVal.SetValues(aSysTime->wMonth,
                     aSysTime->wDay,
                     aSysTime->wYear,
                     aSysTime->wHour,
                     aSysTime->wMinute,
                     aSysTime->wSecond,
                     aSysTime->wMilliseconds);
  }
  else
  {
    _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString());
  }

  return retVal;

} // end OSD_FileNode :: AccessMoment

//=================================================================================================

Quantity_Date OSD_FileNode::CreationMoment()
{

  Quantity_Date           retVal;
  SYSTEMTIME              stCreationMoment;
  SYSTEMTIME              stCreationSystemMoment;
  TCollection_AsciiString fName;

  myPath.SystemName(fName);
  TCollection_ExtendedString fNameW(fName);

  TEST_RAISE("CreationMoment");

  if (_get_file_time(fNameW.ToWideString(), &stCreationSystemMoment, FALSE))
  {
    SYSTEMTIME* aSysTime = &stCreationMoment;
    BOOL aFlag = SystemTimeToTzSpecificLocalTime(NULL, &stCreationSystemMoment, &stCreationMoment);
    if (aFlag == 0) // AGV: test for success (e.g., unsupported on Win95/98)
      aSysTime = &stCreationSystemMoment;
    retVal.SetValues(aSysTime->wMonth,
                     aSysTime->wDay,
                     aSysTime->wYear,
                     aSysTime->wHour,
                     aSysTime->wMinute,
                     aSysTime->wSecond,
                     aSysTime->wMilliseconds);
  }
  else
  {
    _osd_wnt_set_error(myError, OSD_WFileNode, fNameW.ToWideString());
  }

  return retVal;

} // end OSD_FileNode :: CreationMoment

//=================================================================================================

bool OSD_FileNode::Failed() const
{

  return myError.Failed();

} // end OSD_FileNode :: Failed

//=================================================================================================

void OSD_FileNode::Reset()
{

  myError.Reset();

} // end OSD_FileNode :: Reset

//=================================================================================================

void OSD_FileNode::Perror()
{

  myError.Perror();

} // end OSD_FileNode :: Perror

//=================================================================================================

int OSD_FileNode::Error() const
{

  return myError.Error();

} // end OSD_FileNode :: Error

void _osd_wnt_set_error(OSD_Error& err, int who, ...)
{

  DWORD errCode;

  wchar_t buffer[2048];

  va_list arg_ptr;

  va_start(arg_ptr, who);

  errCode = GetLastError();

  if (!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
                      0,
                      errCode,
                      MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
                      buffer,
                      2048,
                      &arg_ptr))
  {
    StringCchPrintfW(buffer, _countof(buffer), L"error code %d", (int)errCode);

    SetLastError(errCode);

  } // end if

  char aBufferA[2048];
  WideCharToMultiByte(CP_UTF8, 0, buffer, -1, aBufferA, sizeof(aBufferA), NULL, NULL);
  err.SetValue(errCode, who, aBufferA);

  va_end(arg_ptr);

} // end _set_error

  #if defined(__CYGWIN32__) || defined(__MINGW32__)
    #ifdef __try /* is defined on MinGw as either "try" or "if (true)" */
      #undef __try
    #endif
    #define __try
    #define __finally
    #define __leave return retVal
  #endif

static BOOL __fastcall _get_file_time(const wchar_t* fName, LPSYSTEMTIME lpSysTime, BOOL fAccess)
{
  BOOL       retVal = FALSE;
  FILETIME   ftCreationTime;
  FILETIME   ftLastWriteTime;
  LPFILETIME lpftPtr;
  HANDLE     hFile = INVALID_HANDLE_VALUE;

  __try
  {
  #ifndef OCCT_UWP
    if ((hFile = CreateFileW(fName, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))
        == INVALID_HANDLE_VALUE)
  #else
    CREATEFILE2_EXTENDED_PARAMETERS pCreateExParams = {};
    pCreateExParams.dwSize                          = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
    pCreateExParams.dwFileAttributes                = FILE_ATTRIBUTE_NORMAL;
    pCreateExParams.lpSecurityAttributes            = NULL;
    pCreateExParams.hTemplateFile                   = NULL;
    if ((hFile = CreateFile2(fName, NULL, NULL, OPEN_EXISTING, &pCreateExParams))
        == INVALID_HANDLE_VALUE)
  #endif
      __leave;

    if (!GetFileTime(hFile, &ftCreationTime, NULL, &ftLastWriteTime))
      __leave;

    lpftPtr = fAccess ? &ftLastWriteTime : &ftCreationTime;

    if (!FileTimeToSystemTime(lpftPtr, lpSysTime))
      __leave;

    retVal = TRUE;

  } // end __try

  __finally
  {

    if (hFile != INVALID_HANDLE_VALUE)

      CloseHandle(hFile);

  } // end __finally

  return retVal;

} // end _get_file_time

  #if defined(__CYGWIN32__) || defined(__MINGW32__)
    #undef __try
    #undef __finally
    #undef __leave
  #endif

static void __fastcall _test_raise(TCollection_AsciiString fName, const char* str)
{
  if (fName.IsEmpty())
  {
    TCollection_AsciiString buff = "OSD_FileNode :: ";
    buff += str;
    buff += " (): wrong access";

    throw Standard_ProgramError(buff.ToCString());
  } // end if

} // end _test_raise

#endif /* _WIN32 */
