misc/libphysfs/lzma/CPP/Windows/FileIO.cpp
changeset 13881 99b265e0d1d0
parent 13880 5f819b90d479
child 13882 b172a5d40eee
equal deleted inserted replaced
13880:5f819b90d479 13881:99b265e0d1d0
     1 // Windows/FileIO.cpp
       
     2 
       
     3 #include "StdAfx.h"
       
     4 
       
     5 #include "FileIO.h"
       
     6 #include "Defs.h"
       
     7 #ifdef WIN_LONG_PATH
       
     8 #include "../Common/MyString.h"
       
     9 #endif
       
    10 #ifndef _UNICODE
       
    11 #include "../Common/StringConvert.h"
       
    12 #endif
       
    13 
       
    14 #ifndef _UNICODE
       
    15 extern bool g_IsNT;
       
    16 #endif
       
    17 
       
    18 namespace NWindows {
       
    19 namespace NFile {
       
    20 
       
    21 #if defined(WIN_LONG_PATH) && defined(_UNICODE)
       
    22 #define WIN_LONG_PATH2
       
    23 #endif
       
    24 
       
    25 #ifdef WIN_LONG_PATH
       
    26 bool GetLongPathBase(LPCWSTR s, UString &res)
       
    27 {
       
    28   res.Empty();
       
    29   int len = MyStringLen(s);
       
    30   wchar_t c = s[0];
       
    31   if (len < 1 || c == L'\\' || c == L'.' && (len == 1 || len == 2 && s[1] == L'.'))
       
    32     return true;
       
    33   UString curDir;
       
    34   bool isAbs = false;
       
    35   if (len > 3)
       
    36     isAbs = (s[1] == L':' && s[2] == L'\\' && (c >= L'a' && c <= L'z' || c >= L'A' && c <= L'Z'));
       
    37 
       
    38   if (!isAbs)
       
    39     {
       
    40       DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, curDir.GetBuffer(MAX_PATH + 1));
       
    41       curDir.ReleaseBuffer();
       
    42       if (needLength == 0 || needLength > MAX_PATH)
       
    43         return false;
       
    44       if (curDir[curDir.Length() - 1] != L'\\')
       
    45         curDir += L'\\';
       
    46     }
       
    47   res = UString(L"\\\\?\\") + curDir + s;
       
    48   return true;
       
    49 }
       
    50 
       
    51 bool GetLongPath(LPCWSTR path, UString &longPath)
       
    52 {
       
    53   if (GetLongPathBase(path, longPath)) 
       
    54     return !longPath.IsEmpty();
       
    55   return false;
       
    56 }
       
    57 #endif
       
    58 
       
    59 namespace NIO {
       
    60 
       
    61 CFileBase::~CFileBase() { Close(); }
       
    62 
       
    63 bool CFileBase::Create(LPCTSTR fileName, DWORD desiredAccess,
       
    64     DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
       
    65 {
       
    66   if (!Close())
       
    67     return false;
       
    68   _handle = ::CreateFile(fileName, desiredAccess, shareMode, 
       
    69       (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, 
       
    70       flagsAndAttributes, (HANDLE)NULL);
       
    71   #ifdef WIN_LONG_PATH2
       
    72   if (_handle == INVALID_HANDLE_VALUE)
       
    73   {
       
    74     UString longPath;
       
    75     if (GetLongPath(fileName, longPath))
       
    76       _handle = ::CreateFileW(longPath, desiredAccess, shareMode, 
       
    77         (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, 
       
    78         flagsAndAttributes, (HANDLE)NULL);
       
    79   }
       
    80   #endif
       
    81   return (_handle != INVALID_HANDLE_VALUE);
       
    82 }
       
    83 
       
    84 #ifndef _UNICODE
       
    85 bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess,
       
    86     DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
       
    87 {
       
    88   if (!g_IsNT)
       
    89     return Create(UnicodeStringToMultiByte(fileName, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP), 
       
    90       desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
       
    91   if (!Close())
       
    92     return false;
       
    93   _handle = ::CreateFileW(fileName, desiredAccess, shareMode, 
       
    94     (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, 
       
    95     flagsAndAttributes, (HANDLE)NULL);
       
    96   #ifdef WIN_LONG_PATH
       
    97   if (_handle == INVALID_HANDLE_VALUE)
       
    98   {
       
    99     UString longPath;
       
   100     if (GetLongPath(fileName, longPath))
       
   101       _handle = ::CreateFileW(longPath, desiredAccess, shareMode, 
       
   102         (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, 
       
   103         flagsAndAttributes, (HANDLE)NULL);
       
   104   }
       
   105   #endif
       
   106   return (_handle != INVALID_HANDLE_VALUE);
       
   107 }
       
   108 #endif
       
   109 
       
   110 bool CFileBase::Close()
       
   111 {
       
   112   if (_handle == INVALID_HANDLE_VALUE)
       
   113     return true;
       
   114   if (!::CloseHandle(_handle))
       
   115     return false;
       
   116   _handle = INVALID_HANDLE_VALUE;
       
   117   return true;
       
   118 }
       
   119 
       
   120 bool CFileBase::GetPosition(UInt64 &position) const
       
   121 {
       
   122   return Seek(0, FILE_CURRENT, position);
       
   123 }
       
   124 
       
   125 bool CFileBase::GetLength(UInt64 &length) const
       
   126 {
       
   127   DWORD sizeHigh;
       
   128   DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh);
       
   129   if(sizeLow == 0xFFFFFFFF)
       
   130     if(::GetLastError() != NO_ERROR)
       
   131       return false;
       
   132   length = (((UInt64)sizeHigh) << 32) + sizeLow;
       
   133   return true;
       
   134 }
       
   135 
       
   136 bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const
       
   137 {
       
   138   LARGE_INTEGER value;
       
   139   value.QuadPart = distanceToMove;
       
   140   value.LowPart = ::SetFilePointer(_handle, value.LowPart, &value.HighPart, moveMethod);
       
   141   if (value.LowPart == 0xFFFFFFFF)
       
   142     if(::GetLastError() != NO_ERROR) 
       
   143       return false;
       
   144   newPosition = value.QuadPart;
       
   145   return true;
       
   146 }
       
   147 
       
   148 bool CFileBase::Seek(UInt64 position, UInt64 &newPosition)
       
   149 {
       
   150   return Seek(position, FILE_BEGIN, newPosition);
       
   151 }
       
   152 
       
   153 bool CFileBase::SeekToBegin()
       
   154 {
       
   155   UInt64 newPosition;
       
   156   return Seek(0, newPosition);
       
   157 }
       
   158 
       
   159 bool CFileBase::SeekToEnd(UInt64 &newPosition)
       
   160 {
       
   161   return Seek(0, FILE_END, newPosition);
       
   162 }
       
   163 
       
   164 bool CFileBase::GetFileInformation(CByHandleFileInfo &fileInfo) const
       
   165 {
       
   166   BY_HANDLE_FILE_INFORMATION winFileInfo;
       
   167   if(!::GetFileInformationByHandle(_handle, &winFileInfo))
       
   168     return false;
       
   169   fileInfo.Attributes = winFileInfo.dwFileAttributes;
       
   170   fileInfo.CreationTime = winFileInfo.ftCreationTime;
       
   171   fileInfo.LastAccessTime = winFileInfo.ftLastAccessTime;
       
   172   fileInfo.LastWriteTime = winFileInfo.ftLastWriteTime;
       
   173   fileInfo.VolumeSerialNumber = winFileInfo.dwFileAttributes; 
       
   174   fileInfo.Size = (((UInt64)winFileInfo.nFileSizeHigh) << 32) +  winFileInfo.nFileSizeLow;
       
   175   fileInfo.NumberOfLinks = winFileInfo.nNumberOfLinks;
       
   176   fileInfo.FileIndex = (((UInt64)winFileInfo.nFileIndexHigh) << 32) + winFileInfo.nFileIndexLow;
       
   177   return true;
       
   178 }
       
   179 
       
   180 /////////////////////////
       
   181 // CInFile
       
   182 
       
   183 bool CInFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
       
   184   { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); }
       
   185 
       
   186 bool CInFile::OpenShared(LPCTSTR fileName, bool shareForWrite)
       
   187 { return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
       
   188 
       
   189 bool CInFile::Open(LPCTSTR fileName)
       
   190   { return OpenShared(fileName, false); }
       
   191 
       
   192 #ifndef _UNICODE
       
   193 bool CInFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
       
   194   { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); }
       
   195 
       
   196 bool CInFile::OpenShared(LPCWSTR fileName, bool shareForWrite)
       
   197 { return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
       
   198 
       
   199 bool CInFile::Open(LPCWSTR fileName)
       
   200   { return OpenShared(fileName, false); }
       
   201 #endif
       
   202 
       
   203 // ReadFile and WriteFile functions in Windows have BUG:
       
   204 // If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) 
       
   205 // from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES 
       
   206 // (Insufficient system resources exist to complete the requested service).
       
   207 
       
   208 // Probably in some version of Windows there are problems with other sizes: 
       
   209 // for 32 MB (maybe also for 16 MB). 
       
   210 // And message can be "Network connection was lost"
       
   211 
       
   212 static UInt32 kChunkSizeMax = (1 << 22);
       
   213 
       
   214 bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize)
       
   215 {
       
   216   if (size > kChunkSizeMax)
       
   217     size = kChunkSizeMax;
       
   218   DWORD processedLoc = 0;
       
   219   bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
       
   220   processedSize = (UInt32)processedLoc;
       
   221   return res;
       
   222 }
       
   223 
       
   224 bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize)
       
   225 {
       
   226   processedSize = 0;
       
   227   do
       
   228   {
       
   229     UInt32 processedLoc = 0;
       
   230     bool res = ReadPart(data, size, processedLoc);
       
   231     processedSize += processedLoc;
       
   232     if (!res)
       
   233       return false;
       
   234     if (processedLoc == 0)
       
   235       return true;
       
   236     data = (void *)((unsigned char *)data + processedLoc);
       
   237     size -= processedLoc;
       
   238   }
       
   239   while (size > 0);
       
   240   return true;
       
   241 }
       
   242 
       
   243 /////////////////////////
       
   244 // COutFile
       
   245 
       
   246 bool COutFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
       
   247   { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
       
   248 
       
   249 static inline DWORD GetCreationDisposition(bool createAlways)
       
   250   { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
       
   251 
       
   252 bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition)
       
   253   { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
       
   254 
       
   255 bool COutFile::Create(LPCTSTR fileName, bool createAlways)
       
   256   { return Open(fileName, GetCreationDisposition(createAlways)); }
       
   257 
       
   258 #ifndef _UNICODE
       
   259 
       
   260 bool COutFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
       
   261   { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode,      creationDisposition, flagsAndAttributes); }
       
   262 
       
   263 bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition)
       
   264   { return Open(fileName, FILE_SHARE_READ,  creationDisposition, FILE_ATTRIBUTE_NORMAL); }
       
   265 
       
   266 bool COutFile::Create(LPCWSTR fileName, bool createAlways)
       
   267   { return Open(fileName, GetCreationDisposition(createAlways)); }
       
   268 
       
   269 #endif
       
   270 
       
   271 bool COutFile::SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime)
       
   272   { return BOOLToBool(::SetFileTime(_handle, creationTime, lastAccessTime, lastWriteTime)); }
       
   273 
       
   274 bool COutFile::SetLastWriteTime(const FILETIME *lastWriteTime)
       
   275   {  return SetTime(NULL, NULL, lastWriteTime); }
       
   276 
       
   277 bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize)
       
   278 {
       
   279   if (size > kChunkSizeMax)
       
   280     size = kChunkSizeMax;
       
   281   DWORD processedLoc = 0;
       
   282   bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
       
   283   processedSize = (UInt32)processedLoc;
       
   284   return res;
       
   285 }
       
   286 
       
   287 bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize)
       
   288 {
       
   289   processedSize = 0;
       
   290   do
       
   291   {
       
   292     UInt32 processedLoc = 0;
       
   293     bool res = WritePart(data, size, processedLoc);
       
   294     processedSize += processedLoc;
       
   295     if (!res)
       
   296       return false;
       
   297     if (processedLoc == 0)
       
   298       return true;
       
   299     data = (const void *)((const unsigned char *)data + processedLoc);
       
   300     size -= processedLoc;
       
   301   }
       
   302   while (size > 0);
       
   303   return true;
       
   304 }
       
   305 
       
   306 bool COutFile::SetEndOfFile() { return BOOLToBool(::SetEndOfFile(_handle)); }
       
   307 
       
   308 bool COutFile::SetLength(UInt64 length)
       
   309 {
       
   310   UInt64 newPosition;
       
   311   if(!Seek(length, newPosition))
       
   312     return false;
       
   313   if(newPosition != length)
       
   314     return false;
       
   315   return SetEndOfFile();
       
   316 }
       
   317 
       
   318 }}}