summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lzma/CPP/Windows/FileIO.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/lzma/CPP/Windows/FileIO.cpp')
-rw-r--r--3rdparty/lzma/CPP/Windows/FileIO.cpp515
1 files changed, 494 insertions, 21 deletions
diff --git a/3rdparty/lzma/CPP/Windows/FileIO.cpp b/3rdparty/lzma/CPP/Windows/FileIO.cpp
index 56e6ca45796..e51b0eb31b8 100644
--- a/3rdparty/lzma/CPP/Windows/FileIO.cpp
+++ b/3rdparty/lzma/CPP/Windows/FileIO.cpp
@@ -6,9 +6,29 @@
#include "../../C/Alloc.h"
#endif
+// #include <stdio.h>
+
+/*
+#ifndef _WIN32
+// for ioctl BLKGETSIZE64
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#endif
+*/
+
#include "FileIO.h"
#include "FileName.h"
+HRESULT GetLastError_noZero_HRESULT()
+{
+ DWORD res = ::GetLastError();
+ if (res == 0)
+ return E_FAIL;
+ return HRESULT_FROM_WIN32(res);
+}
+
+#ifdef _WIN32
+
#ifndef _UNICODE
extern bool g_IsNT;
#endif
@@ -78,6 +98,42 @@ bool CFileBase::Create(CFSTR path, DWORD desiredAccess,
}
#endif
}
+
+ /*
+ #ifndef UNDER_CE
+ #ifndef _SFX
+ if (_handle == INVALID_HANDLE_VALUE)
+ {
+ // it's debug hack to open symbolic links in Windows XP and WSL links in Windows 10
+ DWORD lastError = GetLastError();
+ if (lastError == ERROR_CANT_ACCESS_FILE)
+ {
+ CByteBuffer buf;
+ if (NIO::GetReparseData(path, buf, NULL))
+ {
+ CReparseAttr attr;
+ if (attr.Parse(buf, buf.Size()))
+ {
+ FString dirPrefix, fileName;
+ if (NDir::GetFullPathAndSplit(path, dirPrefix, fileName))
+ {
+ FString fullPath;
+ if (GetFullPath(dirPrefix, us2fs(attr.GetPath()), fullPath))
+ {
+ // FIX IT: recursion levels must be restricted
+ return Create(fullPath, desiredAccess,
+ shareMode, creationDisposition, flagsAndAttributes);
+ }
+ }
+ }
+ }
+ SetLastError(lastError);
+ }
+ }
+ #endif
+ #endif
+ */
+
return (_handle != INVALID_HANDLE_VALUE);
}
@@ -91,11 +147,6 @@ bool CFileBase::Close() throw()
return true;
}
-bool CFileBase::GetPosition(UInt64 &position) const throw()
-{
- return Seek(0, FILE_CURRENT, position);
-}
-
bool CFileBase::GetLength(UInt64 &length) const throw()
{
#ifdef SUPPORT_DEVICE_FILE
@@ -106,13 +157,64 @@ bool CFileBase::GetLength(UInt64 &length) const throw()
}
#endif
- DWORD sizeHigh;
- DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh);
- if (sizeLow == 0xFFFFFFFF)
+ DWORD high = 0;
+ const DWORD low = ::GetFileSize(_handle, &high);
+ if (low == INVALID_FILE_SIZE)
if (::GetLastError() != NO_ERROR)
return false;
- length = (((UInt64)sizeHigh) << 32) + sizeLow;
+ length = (((UInt64)high) << 32) + low;
+ return true;
+
+ /*
+ LARGE_INTEGER fileSize;
+ // GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+
+ if (!GetFileSizeEx(_handle, &fileSize))
+ return false;
+ length = (UInt64)fileSize.QuadPart;
return true;
+ */
+}
+
+
+/* Specification for SetFilePointer():
+
+ If a new file pointer is a negative value,
+ {
+ the function fails,
+ the file pointer is not moved,
+ the code returned by GetLastError() is ERROR_NEGATIVE_SEEK.
+ }
+
+ If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set
+ {
+ an application can move the file pointer only to sector-aligned positions.
+ A sector-aligned position is a position that is a whole number multiple of
+ the volume sector size.
+ An application can obtain a volume sector size by calling the GetDiskFreeSpace.
+ }
+
+ It is not an error to set a file pointer to a position beyond the end of the file.
+ The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function.
+
+ If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL,
+ an application must call GetLastError to determine whether or not the function has succeeded or failed.
+*/
+
+bool CFileBase::GetPosition(UInt64 &position) const throw()
+{
+ LONG high = 0;
+ const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT);
+ if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
+ {
+ // for error case we can set (position) to (-1) or (0) or leave (position) unchanged.
+ // position = (UInt64)(Int64)-1; // for debug
+ position = 0;
+ return false;
+ }
+ position = (((UInt64)(UInt32)high) << 32) + low;
+ return true;
+ // we don't want recursed GetPosition()
+ // return Seek(0, FILE_CURRENT, position);
}
bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw()
@@ -126,23 +228,31 @@ bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition
#endif
LONG high = (LONG)(distanceToMove >> 32);
- DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);
- if (low == 0xFFFFFFFF)
- if (::GetLastError() != NO_ERROR)
+ const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);
+ if (low == INVALID_SET_FILE_POINTER)
+ {
+ const DWORD lastError = ::GetLastError();
+ if (lastError != NO_ERROR)
+ {
+ // 21.07: we set (newPosition) to real position even after error.
+ GetPosition(newPosition);
+ SetLastError(lastError); // restore LastError
return false;
+ }
+ }
newPosition = (((UInt64)(UInt32)high) << 32) + low;
return true;
}
bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw()
{
- return Seek(position, FILE_BEGIN, newPosition);
+ return Seek((Int64)position, FILE_BEGIN, newPosition);
}
bool CFileBase::SeekToBegin() const throw()
{
- UInt64 newPosition;
- return Seek(0, newPosition);
+ UInt64 newPosition = 0;
+ return Seek(0, newPosition) && (newPosition == 0);
}
bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw()
@@ -258,7 +368,7 @@ void CInFile::CalcDeviceSize(CFSTR s)
if (GetPartitionInfo(&partInfo))
{
- Size = partInfo.PartitionLength.QuadPart;
+ Size = (UInt64)partInfo.PartitionLength.QuadPart;
SizeDefined = true;
needCorrectSize = false;
if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0)
@@ -277,7 +387,7 @@ void CInFile::CalcDeviceSize(CFSTR s)
my_DISK_GEOMETRY_EX geomEx;
SizeDefined = GetGeometryEx(&geomEx);
if (SizeDefined)
- Size = geomEx.DiskSize.QuadPart;
+ Size = (UInt64)geomEx.DiskSize.QuadPart;
else
{
DISK_GEOMETRY geom;
@@ -285,7 +395,7 @@ void CInFile::CalcDeviceSize(CFSTR s)
if (!SizeDefined)
SizeDefined = GetCdRomGeometry(&geom);
if (SizeDefined)
- Size = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
+ Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
}
}
@@ -310,7 +420,24 @@ void CInFile::CalcDeviceSize(CFSTR s)
bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
{
- bool res = Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes);
+ DWORD desiredAccess = GENERIC_READ;
+
+ #ifdef _WIN32
+ if (PreserveATime)
+ desiredAccess |= FILE_WRITE_ATTRIBUTES;
+ #endif
+
+ bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
+
+ #ifdef _WIN32
+ if (res && PreserveATime)
+ {
+ FILETIME ft;
+ ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF;
+ ::SetFileTime(_handle, NULL, &ft, NULL);
+ }
+ #endif
+
MY_DEVICE_EXTRA_CODE
return res;
}
@@ -330,7 +457,7 @@ bool CInFile::Open(CFSTR fileName)
// for 32 MB (maybe also for 16 MB).
// And message can be "Network connection was lost"
-static UInt32 kChunkSizeMax = (1 << 22);
+static const UInt32 kChunkSizeMax = (1 << 22);
bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw()
{
@@ -366,6 +493,26 @@ bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw()
return true;
}
+bool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw()
+{
+ processedSize = 0;
+ do
+ {
+ UInt32 processedLoc = 0;
+ const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size);
+ const bool res = Read1(data, sizeLoc, processedLoc);
+ processedSize += processedLoc;
+ if (!res)
+ return false;
+ if (processedLoc == 0)
+ return true;
+ data = (void *)((unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size > 0);
+ return true;
+}
+
// ---------- COutFile ---------
static inline DWORD GetCreationDisposition(bool createAlways)
@@ -413,7 +560,24 @@ bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw
data = (const void *)((const unsigned char *)data + processedLoc);
size -= processedLoc;
}
- while (size > 0);
+ while (size != 0);
+ return true;
+}
+
+bool COutFile::WriteFull(const void *data, size_t size) throw()
+{
+ do
+ {
+ UInt32 processedLoc = 0;
+ const UInt32 sizeCur = (size > kChunkSizeMax ? kChunkSizeMax : (UInt32)size);
+ if (!WritePart(data, sizeCur, processedLoc))
+ return false;
+ if (processedLoc == 0)
+ return (size == 0);
+ data = (const void *)((const unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size != 0);
return true;
}
@@ -429,4 +593,313 @@ bool COutFile::SetLength(UInt64 length) throw()
return SetEndOfFile();
}
+bool COutFile::SetLength_KeepPosition(UInt64 length) throw()
+{
+ UInt64 currentPos = 0;
+ if (!GetPosition(currentPos))
+ return false;
+ DWORD lastError = 0;
+ const bool result = SetLength(length);
+ if (!result)
+ lastError = GetLastError();
+ UInt64 currentPos2;
+ const bool result2 = Seek(currentPos, currentPos2);
+ if (lastError != 0)
+ SetLastError(lastError);
+ return (result && result2);
+}
+
}}}
+
+#else // _WIN32
+
+
+// POSIX
+
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace NWindows {
+namespace NFile {
+
+namespace NDir {
+bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
+}
+
+namespace NIO {
+
+bool CFileBase::OpenBinary(const char *name, int flags)
+{
+ #ifdef O_BINARY
+ flags |= O_BINARY;
+ #endif
+
+ Close();
+ _handle = ::open(name, flags, 0666);
+ return _handle != -1;
+
+ /*
+ if (_handle == -1)
+ return false;
+ if (IsString1PrefixedByString2(name, "/dev/"))
+ {
+ // /dev/sda
+ // IsDeviceFile = true; // for debug
+ // SizeDefined = false;
+ // SizeDefined = (GetDeviceSize_InBytes(Size) == 0);
+ }
+ return true;
+ */
+}
+
+bool CFileBase::Close()
+{
+ if (_handle == -1)
+ return true;
+ if (close(_handle) != 0)
+ return false;
+ _handle = -1;
+ /*
+ IsDeviceFile = false;
+ SizeDefined = false;
+ */
+ return true;
+}
+
+bool CFileBase::GetLength(UInt64 &length) const
+{
+ length = 0;
+ // length = (UInt64)(Int64)-1; // for debug
+ const off_t curPos = seekToCur();
+ if (curPos == -1)
+ return false;
+ const off_t lengthTemp = seek(0, SEEK_END);
+ seek(curPos, SEEK_SET);
+ length = (UInt64)lengthTemp;
+
+ /*
+ // 22.00:
+ if (lengthTemp == 1)
+ if (IsDeviceFile && SizeDefined)
+ {
+ length = Size;
+ return true;
+ }
+ */
+
+ return (lengthTemp != -1);
+}
+
+off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const
+{
+ /*
+ if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END)
+ {
+ printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
+ distanceToMove += Size;
+ moveMethod = SEEK_SET;
+ }
+ */
+
+ // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove);
+ // off_t res = ::lseek(_handle, distanceToMove, moveMethod);
+ // printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
+ return ::lseek(_handle, distanceToMove, moveMethod);
+ // return res;
+}
+
+off_t CFileBase::seekToBegin() const throw()
+{
+ return seek(0, SEEK_SET);
+}
+
+off_t CFileBase::seekToCur() const throw()
+{
+ return seek(0, SEEK_CUR);
+}
+
+/*
+bool CFileBase::SeekToBegin() const throw()
+{
+ return (::seek(0, SEEK_SET) != -1);
+}
+*/
+
+
+/////////////////////////
+// CInFile
+
+bool CInFile::Open(const char *name)
+{
+ return CFileBase::OpenBinary(name, O_RDONLY);
+}
+
+bool CInFile::OpenShared(const char *name, bool)
+{
+ return Open(name);
+}
+
+
+/*
+int CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks)
+{
+ // we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition
+ // #include <linux/fs.h>
+ return ioctl(_handle, BLKGETSIZE64, numBlocks);
+ // in block size
+}
+
+int CFileBase::GetDeviceSize_InBytes(UInt64 &size)
+{
+ size = 0;
+ unsigned long long numBlocks;
+ int res = my_ioctl_BLKGETSIZE64(&numBlocks);
+ if (res == 0)
+ size = numBlocks; // another blockSize s possible?
+ printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size);
+ return res;
+}
+*/
+
+/*
+On Linux (32-bit and 64-bit):
+read(), write() (and similar system calls) will transfer at most
+0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred.
+*/
+
+static const size_t kChunkSizeMax = ((size_t)1 << 22);
+
+ssize_t CInFile::read_part(void *data, size_t size) throw()
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ return ::read(_handle, data, size);
+}
+
+bool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw()
+{
+ processed = 0;
+ do
+ {
+ const ssize_t res = read_part(data, size);
+ if (res < 0)
+ return false;
+ if (res == 0)
+ break;
+ data = (void *)((unsigned char *)data + (size_t)res);
+ size -= (size_t)res;
+ processed += (size_t)res;
+ }
+ while (size > 0);
+ return true;
+}
+
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Create(const char *name, bool createAlways)
+{
+ Path = name; // change it : set it only if open is success.
+ if (createAlways)
+ {
+ Close();
+ _handle = ::creat(name, 0666);
+ return _handle != -1;
+ }
+ return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY);
+}
+
+bool COutFile::Open(const char *name, DWORD creationDisposition)
+{
+ UNUSED_VAR(creationDisposition) // FIXME
+ return Create(name, false);
+}
+
+ssize_t COutFile::write_part(const void *data, size_t size) throw()
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ return ::write(_handle, data, size);
+}
+
+ssize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw()
+{
+ processed = 0;
+ do
+ {
+ const ssize_t res = write_part(data, size);
+ if (res < 0)
+ return res;
+ if (res == 0)
+ break;
+ data = (const void *)((const unsigned char *)data + (size_t)res);
+ size -= (size_t)res;
+ processed += (size_t)res;
+ }
+ while (size > 0);
+ return (ssize_t)processed;
+}
+
+bool COutFile::SetLength(UInt64 length) throw()
+{
+ const off_t len2 = (off_t)length;
+ if ((Int64)length != len2)
+ {
+ SetLastError(EFBIG);
+ return false;
+ }
+ // The value of the seek pointer shall not be modified by a call to ftruncate().
+ int iret = ftruncate(_handle, len2);
+ return (iret == 0);
+}
+
+bool COutFile::Close()
+{
+ bool res = CFileBase::Close();
+ if (!res)
+ return res;
+ if (CTime_defined || ATime_defined || MTime_defined)
+ {
+ /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path,
+ CTime_defined ? &CTime : NULL,
+ ATime_defined ? &ATime : NULL,
+ MTime_defined ? &MTime : NULL);
+ }
+ return res;
+}
+
+bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw()
+{
+ // On some OS (cygwin, MacOSX ...), you must close the file before updating times
+ // return true;
+
+ if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false;
+ if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false;
+ if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
+ return true;
+
+ /*
+ struct timespec times[2];
+ UNUSED_VAR(cTime)
+ if (!aTime && !mTime)
+ return true;
+ bool needChange;
+ needChange = FiTime_To_timespec(aTime, times[0]);
+ needChange |= FiTime_To_timespec(mTime, times[1]);
+ if (!needChange)
+ return true;
+ return futimens(_handle, times) == 0;
+ */
+}
+
+bool COutFile::SetMTime(const CFiTime *mTime) throw()
+{
+ if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
+ return true;
+}
+
+}}}
+
+
+#endif