This commit is contained in:
Igor Pavlov
2014-11-23 00:00:00 +00:00
committed by Kornel Lesiński
parent 83f8ddcc5b
commit f08f4dcc3c
1158 changed files with 76451 additions and 35082 deletions
Executable → Regular
+170 -123
View File
@@ -2,88 +2,35 @@
#include "StdAfx.h"
#ifdef SUPPORT_DEVICE_FILE
#include "../../C/Alloc.h"
#endif
#include "FileIO.h"
#include "FileName.h"
#ifndef _UNICODE
extern bool g_IsNT;
#endif
using namespace NWindows;
using namespace NFile;
using namespace NName;
namespace NWindows {
namespace NFile {
#ifdef SUPPORT_DEVICE_FILE
bool IsDeviceName(CFSTR n)
namespace NSystem
{
#ifdef UNDER_CE
int len = (int)MyStringLen(n);
if (len < 5 || len > 5 || memcmp(n, FTEXT("DSK"), 3 * sizeof(FCHAR)) != 0)
return false;
if (n[4] != ':')
return false;
// for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ));
#else
if (n[0] != '\\' || n[1] != '\\' || n[2] != '.' || n[3] != '\\')
return false;
int len = (int)MyStringLen(n);
if (len == 6 && n[5] == ':')
return true;
if (len < 18 || len > 22 || memcmp(n + 4, FTEXT("PhysicalDrive"), 13 * sizeof(FCHAR)) != 0)
return false;
for (int i = 17; i < len; i++)
if (n[i] < '0' || n[i] > '9')
return false;
#endif
return true;
}
#endif
#if defined(WIN_LONG_PATH) && defined(_UNICODE)
#define WIN_LONG_PATH2
#endif
#ifdef WIN_LONG_PATH
bool GetLongPathBase(CFSTR s, UString &res)
{
res.Empty();
int len = MyStringLen(s);
FChar c = s[0];
if (len < 1 || c == '\\' || c == '.' && (len == 1 || len == 2 && s[1] == '.'))
return true;
UString curDir;
bool isAbs = false;
if (len > 3)
isAbs = (s[1] == ':' && s[2] == '\\' && (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'));
if (!isAbs)
{
WCHAR temp[MAX_PATH + 2];
temp[0] = 0;
DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, temp);
if (needLength == 0 || needLength > MAX_PATH)
return false;
curDir = temp;
if (curDir.Back() != L'\\')
curDir += L'\\';
}
res = UString(L"\\\\?\\") + curDir + fs2us(s);
return true;
}
bool GetLongPath(CFSTR path, UString &longPath)
{
if (GetLongPathBase(path, longPath))
return !longPath.IsEmpty();
return false;
bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
}
#endif
namespace NIO {
CFileBase::~CFileBase() { Close(); }
bool CFileBase::Create(CFSTR fileName, DWORD desiredAccess,
bool CFileBase::Create(CFSTR path, DWORD desiredAccess,
DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
{
if (!Close())
@@ -96,19 +43,20 @@ bool CFileBase::Create(CFSTR fileName, DWORD desiredAccess,
#ifndef _UNICODE
if (!g_IsNT)
{
_handle = ::CreateFile(fs2fas(fileName), desiredAccess, shareMode,
_handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode,
(LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
}
else
#endif
{
_handle = ::CreateFileW(fs2us(fileName), desiredAccess, shareMode,
IF_USE_MAIN_PATH
_handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode,
(LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
#ifdef WIN_LONG_PATH
if (_handle == INVALID_HANDLE_VALUE)
if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
{
UString longPath;
if (GetLongPath(fileName, longPath))
if (GetSuperPath(path, longPath, USE_MAIN_PATH))
_handle = ::CreateFileW(longPath, desiredAccess, shareMode,
(LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
}
@@ -135,9 +83,9 @@ bool CFileBase::GetPosition(UInt64 &position) const
bool CFileBase::GetLength(UInt64 &length) const
{
#ifdef SUPPORT_DEVICE_FILE
if (IsDeviceFile && LengthDefined)
if (IsDeviceFile && SizeDefined)
{
length = Length;
length = Size;
return true;
}
#endif
@@ -154,95 +102,192 @@ bool CFileBase::GetLength(UInt64 &length) const
bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const
{
#ifdef SUPPORT_DEVICE_FILE
if (IsDeviceFile && LengthDefined && moveMethod == FILE_END)
if (IsDeviceFile && SizeDefined && moveMethod == FILE_END)
{
distanceToMove += Length;
distanceToMove += Size;
moveMethod = FILE_BEGIN;
}
#endif
LARGE_INTEGER value;
value.QuadPart = distanceToMove;
value.LowPart = ::SetFilePointer(_handle, value.LowPart, &value.HighPart, moveMethod);
if (value.LowPart == 0xFFFFFFFF)
LONG high = (LONG)(distanceToMove >> 32);
DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);
if (low == 0xFFFFFFFF)
if (::GetLastError() != NO_ERROR)
return false;
newPosition = value.QuadPart;
newPosition = (((UInt64)high) << 32) + low;
return true;
}
bool CFileBase::Seek(UInt64 position, UInt64 &newPosition)
bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const
{
return Seek(position, FILE_BEGIN, newPosition);
}
bool CFileBase::SeekToBegin()
bool CFileBase::SeekToBegin() const
{
UInt64 newPosition;
return Seek(0, newPosition);
}
bool CFileBase::SeekToEnd(UInt64 &newPosition)
bool CFileBase::SeekToEnd(UInt64 &newPosition) const
{
return Seek(0, FILE_END, newPosition);
}
/*
bool CFileBase::GetFileInformation(CByHandleFileInfo &fi) const
{
BY_HANDLE_FILE_INFORMATION wfi;
if (!::GetFileInformationByHandle(_handle, &wfi))
return false;
fi.Attrib = wfi.dwFileAttributes;
fi.CTime = wfi.ftCreationTime;
fi.ATime = wfi.ftLastAccessTime;
fi.MTime = wfi.ftLastWriteTime;
fi.Size = (((UInt64)wfi.nFileSizeHigh) << 32) + wfi.nFileSizeLow;
fi.VolumeSerialNumber = wfi.dwVolumeSerialNumber;
fi.NumLinks = wfi.nNumberOfLinks;
fi.FileIndex = (((UInt64)wfi.nFileIndexHigh) << 32) + wfi.nFileIndexLow;
return true;
}
*/
/////////////////////////
// CInFile
// ---------- CInFile ---------
#ifdef SUPPORT_DEVICE_FILE
void CInFile::GetDeviceLength()
void CInFile::CorrectDeviceSize()
{
if (_handle != INVALID_HANDLE_VALUE && IsDeviceFile)
// maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail
static const UInt32 kClusterSize = 1 << 14;
UInt64 pos = Size & ~(UInt64)(kClusterSize - 1);
UInt64 realNewPosition;
if (!Seek(pos, realNewPosition))
return;
Byte *buf = (Byte *)MidAlloc(kClusterSize);
bool needbackward = true;
for (;;)
{
#ifdef UNDER_CE
LengthDefined = true;
Length = 128 << 20;
UInt32 processed = 0;
// up test is slow for "PhysicalDrive".
// processed size for latest block for "PhysicalDrive0" is 0.
if (!Read1(buf, kClusterSize, processed))
break;
if (processed == 0)
break;
needbackward = false;
Size = pos + processed;
if (processed != kClusterSize)
break;
pos += kClusterSize;
}
#else
PARTITION_INFORMATION partInfo;
LengthDefined = true;
Length = 0;
if (needbackward && pos != 0)
{
pos -= kClusterSize;
for (;;)
{
// break;
if (!Seek(pos, realNewPosition))
break;
if (!buf)
{
buf = (Byte *)MidAlloc(kClusterSize);
if (!buf)
break;
}
UInt32 processed = 0;
// that code doesn't work for "PhysicalDrive0"
if (!Read1(buf, kClusterSize, processed))
break;
if (processed != 0)
{
Size = pos + processed;
break;
}
if (pos == 0)
break;
pos -= kClusterSize;
}
}
MidFree(buf);
}
if (GetPartitionInfo(&partInfo))
Length = partInfo.PartitionLength.QuadPart;
void CInFile::CalcDeviceSize(CFSTR s)
{
SizeDefined = false;
Size = 0;
if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile)
return;
#ifdef UNDER_CE
SizeDefined = true;
Size = 128 << 20;
#else
PARTITION_INFORMATION partInfo;
bool needCorrectSize = true;
/*
WinXP 64-bit:
HDD \\.\PhysicalDrive0 (MBR):
GetPartitionInfo == GeometryEx : corrrect size? (includes tail)
Geometry : smaller than GeometryEx (no tail, maybe correct too?)
MyGetDiskFreeSpace : FAIL
Size correction is slow and block size (kClusterSize) must be small?
HDD partition \\.\N: (NTFS):
MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction
GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS
Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition)
CD-ROM drive (ISO):
MyGetDiskFreeSpace : correct size. Same size can be calculated after correction
Geometry == CdRomGeometry : smaller than corrrect size
GetPartitionInfo == GeometryEx : larger than corrrect size
Floppy \\.\a: (FAT):
Geometry : correct size.
CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL
correction works OK for FAT.
correction works OK for non-FAT, if kClusterSize = 512.
*/
if (GetPartitionInfo(&partInfo))
{
Size = partInfo.PartitionLength.QuadPart;
SizeDefined = true;
needCorrectSize = false;
if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0)
{
FChar path[4] = { s[4], ':', '\\', 0 };
UInt64 clusterSize, totalSize, freeSize;
if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize))
Size = totalSize;
else
needCorrectSize = true;
}
}
if (!SizeDefined)
{
my_DISK_GEOMETRY_EX geomEx;
SizeDefined = GetGeometryEx(&geomEx);
if (SizeDefined)
Size = geomEx.DiskSize.QuadPart;
else
{
DISK_GEOMETRY geom;
if (!GetGeometry(&geom))
if (!GetCdRomGeometry(&geom))
LengthDefined = false;
if (LengthDefined)
Length = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
SizeDefined = GetGeometry(&geom);
if (!SizeDefined)
SizeDefined = GetCdRomGeometry(&geom);
if (SizeDefined)
Size = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
}
// SeekToBegin();
#endif
}
if (needCorrectSize && SizeDefined && Size != 0)
{
CorrectDeviceSize();
SeekToBegin();
}
// SeekToBegin();
#endif
}
// ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 &&
#define MY_DEVICE_EXTRA_CODE \
IsDeviceFile = IsDeviceName(fileName); \
GetDeviceLength();
IsDeviceFile = IsDevicePath(fileName); \
CalcDeviceSize(fileName);
#else
#define MY_DEVICE_EXTRA_CODE
#endif
@@ -305,8 +350,7 @@ bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize)
return true;
}
/////////////////////////
// COutFile
// ---------- COutFile ---------
static inline DWORD GetCreationDisposition(bool createAlways)
{ return createAlways? CREATE_ALWAYS: CREATE_NEW; }
@@ -320,6 +364,9 @@ bool COutFile::Open(CFSTR fileName, DWORD creationDisposition)
bool COutFile::Create(CFSTR fileName, bool createAlways)
{ return Open(fileName, GetCreationDisposition(createAlways)); }
bool COutFile::CreateAlways(CFSTR fileName, DWORD flagsAndAttributes)
{ return Open(fileName, FILE_SHARE_READ, GetCreationDisposition(true), flagsAndAttributes); }
bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
{ return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); }