Files
easy7zip/CPP/7zip/UI/FileManager/FSDrives.cpp
Igor Pavlov f08f4dcc3c 9.34
2016-05-28 00:16:51 +01:00

469 lines
11 KiB
C++

// FSDrives.cpp
#include "StdAfx.h"
#include "../../../../C/Alloc.h"
#include "../../../Common/ComTry.h"
#include "../../../Common/Defs.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileIO.h"
#include "../../../Windows/FileSystem.h"
#include "../../../Windows/PropVariant.h"
#include "../../PropID.h"
#include "FSDrives.h"
#include "FSFolder.h"
#include "LangUtils.h"
#include "SysIconUtils.h"
#include "resource.h"
using namespace NWindows;
using namespace NFile;
using namespace NFind;
static CFSTR kVolPrefix = FTEXT("\\\\.\\");
static CFSTR kLongPrefix = FTEXT("\\\\?\\");
FString CDriveInfo::GetDeviceFileIoName() const
{
return kVolPrefix + Name;
}
struct CPhysTempBuffer
{
void *buffer;
CPhysTempBuffer(): buffer(0) {}
~CPhysTempBuffer() { MidFree(buffer); }
};
static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, bool writeToDisk, UInt64 fileSize,
UInt32 bufferSize, UInt64 progressStart, IProgress *progress)
{
NIO::CInFile inFile;
if (!inFile.Open(fromPath))
return GetLastError();
if (fileSize == (UInt64)(Int64)-1)
{
if (!inFile.GetLength(fileSize))
::GetLastError();
}
NIO::COutFile outFile;
if (writeToDisk)
{
if (!outFile.Open(toPath, FILE_SHARE_WRITE, OPEN_EXISTING, 0))
return GetLastError();
}
else
if (!outFile.Create(toPath, true))
return GetLastError();
CPhysTempBuffer tempBuffer;
tempBuffer.buffer = MidAlloc(bufferSize);
if (!tempBuffer.buffer)
return E_OUTOFMEMORY;
for (UInt64 pos = 0; pos < fileSize;)
{
UInt64 progressCur = progressStart + pos;
RINOK(progress->SetCompleted(&progressCur));
UInt64 rem = fileSize - pos;
UInt32 curSize = (UInt32)MyMin(rem, (UInt64)bufferSize);
UInt32 processedSize;
if (!inFile.Read(tempBuffer.buffer, curSize, processedSize))
return GetLastError();
if (processedSize == 0)
break;
curSize = processedSize;
if (writeToDisk)
{
const UInt32 kMask = 0x1FF;
curSize = (curSize + kMask) & ~kMask;
if (curSize > bufferSize)
return E_FAIL;
}
if (!outFile.Write(tempBuffer.buffer, curSize, processedSize))
return GetLastError();
if (curSize != processedSize)
return E_FAIL;
pos += curSize;
}
return S_OK;
}
static const PROPID kProps[] =
{
kpidName,
kpidTotalSize,
kpidFreeSpace,
kpidType,
kpidVolumeName,
kpidFileSystem,
kpidClusterSize
};
static const char *kDriveTypes[] =
{
"Unknown"
, "No Root Dir"
, "Removable"
, "Fixed"
, "Remote"
, "CD-ROM"
, "RAM disk"
};
STDMETHODIMP CFSDrives::LoadItems()
{
_drives.Clear();
FStringVector driveStrings;
MyGetLogicalDriveStrings(driveStrings);
FOR_VECTOR (i, driveStrings)
{
CDriveInfo di;
const FString &driveName = driveStrings[i];
di.FullSystemName = driveName;
if (!driveName.IsEmpty())
di.Name.SetFrom(driveName, driveName.Len() - 1);
di.ClusterSize = 0;
di.DriveSize = 0;
di.FreeSpace = 0;
di.DriveType = NSystem::MyGetDriveType(driveName);
bool needRead = true;
if (di.DriveType == DRIVE_CDROM || di.DriveType == DRIVE_REMOVABLE)
{
/*
DWORD dwSerialNumber;`
if (!::GetVolumeInformation(di.FullSystemName,
NULL, 0, &dwSerialNumber, NULL, NULL, NULL, 0))
*/
{
needRead = false;
}
}
if (needRead)
{
DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags;
NSystem::MyGetVolumeInformation(driveName,
di.VolumeName,
&volumeSerialNumber, &maximumComponentLength, &fileSystemFlags,
di.FileSystemName);
NSystem::MyGetDiskFreeSpace(driveName,
di.ClusterSize, di.DriveSize, di.FreeSpace);
di.KnownSizes = true;
di.KnownSize = true;
}
_drives.Add(di);
}
if (_volumeMode)
{
// we must use IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
for (unsigned n = 0; n < 16; n++) // why 16 ?
{
FChar temp[16];
ConvertUInt32ToString(n, temp);
FString name = FTEXT("PhysicalDrive");
name += temp;
FString fullPath = kVolPrefix;
fullPath += name;
CFileInfo fi;
if (!fi.Find(fullPath))
continue;
CDriveInfo di;
di.Name = name;
di.FullSystemName = fullPath;
di.ClusterSize = 0;
di.DriveSize = fi.Size;
di.FreeSpace = 0;
di.DriveType = 0;
di.IsPhysicalDrive = true;
di.KnownSize = true;
_drives.Add(di);
}
}
return S_OK;
}
STDMETHODIMP CFSDrives::GetNumberOfItems(UInt32 *numItems)
{
*numItems = _drives.Size();
return S_OK;
}
STDMETHODIMP CFSDrives::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)
{
if (itemIndex >= (UInt32)_drives.Size())
return E_INVALIDARG;
NCOM::CPropVariant prop;
const CDriveInfo &di = _drives[itemIndex];
switch (propID)
{
case kpidIsDir: prop = !_volumeMode; break;
case kpidName: prop = di.Name; break;
case kpidTotalSize: if (di.KnownSize) prop = di.DriveSize; break;
case kpidFreeSpace: if (di.KnownSizes) prop = di.FreeSpace; break;
case kpidClusterSize: if (di.KnownSizes) prop = di.ClusterSize; break;
case kpidType:
if (di.DriveType < ARRAY_SIZE(kDriveTypes))
prop = kDriveTypes[di.DriveType];
break;
case kpidVolumeName: prop = di.VolumeName; break;
case kpidFileSystem: prop = di.FileSystemName; break;
}
prop.Detach(value);
return S_OK;
}
HRESULT CFSDrives::BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder)
{
*resultFolder = 0;
if (_volumeMode)
return S_OK;
NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder;
CMyComPtr<IFolderFolder> subFolder = fsFolderSpec;
if (_longMode)
{
RINOK(fsFolderSpec->Init((FString)kLongPrefix + name, 0));
}
else
{
RINOK(fsFolderSpec->Init(name, 0));
}
*resultFolder = subFolder.Detach();
return S_OK;
}
STDMETHODIMP CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder)
{
*resultFolder = 0;
if (index >= (UInt32)_drives.Size())
return E_INVALIDARG;
const CDriveInfo &di = _drives[index];
/*
if (_volumeMode)
{
*resultFolder = 0;
CPhysDriveFolder *folderSpec = new CPhysDriveFolder;
CMyComPtr<IFolderFolder> subFolder = folderSpec;
RINOK(folderSpec->Init(di.Name));
*resultFolder = subFolder.Detach();
return S_OK;
}
*/
return BindToFolderSpec(di.FullSystemName, resultFolder);
}
STDMETHODIMP CFSDrives::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)
{
return BindToFolderSpec(us2fs(name), resultFolder);
}
STDMETHODIMP CFSDrives::BindToParentFolder(IFolderFolder **resultFolder)
{
*resultFolder = 0;
return S_OK;
}
IMP_IFolderFolder_Props(CFSDrives)
STDMETHODIMP CFSDrives::GetFolderProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch (propID)
{
case kpidType: prop = "FSDrives"; break;
case kpidPath:
if (_volumeMode)
prop = kVolPrefix;
else if (_longMode)
prop = kLongPrefix;
else
prop = (UString)LangString(IDS_COMPUTER) + WCHAR_PATH_SEPARATOR;
break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CFSDrives::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)
{
*iconIndex = 0;
const CDriveInfo &di = _drives[index];
if (di.IsPhysicalDrive)
return S_OK;
int iconIndexTemp;
if (GetRealIconIndex(di.FullSystemName, 0, iconIndexTemp) != 0)
{
*iconIndex = iconIndexTemp;
return S_OK;
}
return GetLastError();
}
const wchar_t *CFSDrives::GetExt(unsigned index) const
{
const CDriveInfo &di = _drives[index];
const wchar_t *ext;
if (di.DriveType == DRIVE_CDROM)
ext = L"iso";
else if (di.FileSystemName.Find(L"NTFS") >= 0)
ext = L"ntfs";
else if (di.FileSystemName.Find(L"FAT") >= 0)
ext = L"fat";
else
ext = L"img";
return ext;
}
HRESULT CFSDrives::GetFileSize(unsigned index, UInt64 &fileSize) const
{
NIO::CInFile inFile;
if (!inFile.Open(_drives[index].GetDeviceFileIoName()))
return GetLastError();
if (!inFile.SizeDefined)
return E_FAIL;
fileSize = inFile.Size;
return S_OK;
}
STDMETHODIMP CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */,
const wchar_t *path, IFolderOperationsExtractCallback *callback)
{
if (moveMode)
return E_NOTIMPL;
if (numItems == 0)
return S_OK;
if (!_volumeMode)
return E_NOTIMPL;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
{
const CDriveInfo &di = _drives[indices[i]];
if (di.KnownSize)
totalSize += di.DriveSize;
}
RINOK(callback->SetTotal(totalSize));
RINOK(callback->SetNumFiles(numItems));
UString destPath = path;
if (destPath.IsEmpty())
return E_INVALIDARG;
bool directName = (destPath.Back() != WCHAR_PATH_SEPARATOR);
if (directName)
{
if (numItems > 1)
return E_INVALIDARG;
}
UInt64 completedSize = 0;
RINOK(callback->SetCompleted(&completedSize));
for (i = 0; i < numItems; i++)
{
unsigned index = indices[i];
const CDriveInfo &di = _drives[index];
UString destPath2 = destPath;
UString name = fs2us(di.Name);
if (!directName)
{
UString destName = name;
if (!destName.IsEmpty() && destName.Back() == L':')
{
destName.DeleteBack();
destName += L'.';
destName += GetExt(index);
}
destPath2 += destName;
}
FString srcPath = di.GetDeviceFileIoName();
UInt64 fileSize = 0;
if (GetFileSize(index, fileSize) != S_OK)
{
return E_FAIL;
}
if (!di.KnownSize)
totalSize += fileSize;
RINOK(callback->SetTotal(totalSize));
Int32 writeAskResult;
CMyComBSTR destPathResult;
RINOK(callback->AskWrite(fs2us(srcPath), BoolToInt(false), NULL, &fileSize,
destPath2, &destPathResult, &writeAskResult));
if (!IntToBool(writeAskResult))
continue;
RINOK(callback->SetCurrentFilePath(fs2us(srcPath)));
static const UInt32 kBufferSize = (4 << 20);
UInt32 bufferSize = (di.DriveType == DRIVE_REMOVABLE) ? (18 << 10) * 4 : kBufferSize;
RINOK(CopyFileSpec(srcPath, us2fs(destPathResult), false, fileSize, bufferSize, completedSize, callback));
completedSize += fileSize;
}
return S_OK;
}
STDMETHODIMP CFSDrives::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */,
const wchar_t ** /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */)
{
return E_NOTIMPL;
}
STDMETHODIMP CFSDrives::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */)
{
return E_NOTIMPL;
}
STDMETHODIMP CFSDrives::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */)
{
return E_NOTIMPL;
}
STDMETHODIMP CFSDrives::CreateFile(const wchar_t * /* name */, IProgress * /* progress */)
{
return E_NOTIMPL;
}
STDMETHODIMP CFSDrives::Rename(UInt32 /* index */, const wchar_t * /* newName */, IProgress * /* progress */)
{
return E_NOTIMPL;
}
STDMETHODIMP CFSDrives::Delete(const UInt32 * /* indices */, UInt32 /* numItems */, IProgress * /* progress */)
{
return E_NOTIMPL;
}
STDMETHODIMP CFSDrives::SetProperty(UInt32 /* index */, PROPID /* propID */,
const PROPVARIANT * /* value */, IProgress * /* progress */)
{
return E_NOTIMPL;
}