annotate src/win32/7zip/7z/CPP/Windows/FileIO.cpp @ 5:8fe0c57e53d2

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