// PhysDriveFolder.cpp #include "StdAfx.h" #include "../../../../C/Alloc.h" #include "Common/Buffer.h" #include "Windows/PropVariant.h" #include "Windows/FileDevice.h" #include "Windows/FileSystem.h" #include "../../PropID.h" #include "PhysDriveFolder.h" using namespace NWindows; static const UInt32 kBufferSize = (4 << 20); static STATPROPSTG kProperties[] = { { NULL, kpidName, VT_BSTR}, { NULL, kpidSize, VT_UI8} }; HRESULT CPhysDriveFolder::Init(const UString &path) { _prefix = L"\\\\.\\"; _path = path; NFile::NDevice::CInFile inFile; if (!inFile.Open(GetFullPath())) return GetLastError(); return S_OK; } STDMETHODIMP CPhysDriveFolder::LoadItems() { _driveType = NFile::NSystem::MyGetDriveType(_path + L"\\"); _name = _path.Left(1); _name += L'.'; if (_driveType == DRIVE_CDROM) _name += L"iso"; else _name += L"img"; Int32 dummy; WasChanged(&dummy); return GetLength(_length); } STDMETHODIMP CPhysDriveFolder::GetNumberOfItems(UInt32 *numItems) { *numItems = 1; return S_OK; } STDMETHODIMP CPhysDriveFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; if (itemIndex >= 1) return E_INVALIDARG; switch(propID) { case kpidIsDir: prop = false; break; case kpidName: prop = _name; break; case kpidSize: prop = _length; break; } prop.Detach(value); return S_OK; } STDMETHODIMP CPhysDriveFolder::BindToFolder(UInt32 /* index */, IFolderFolder ** /* resultFolder */) { return E_NOTIMPL; } STDMETHODIMP CPhysDriveFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder ** /* resultFolder */) { return E_NOTIMPL; } STDMETHODIMP CPhysDriveFolder::BindToParentFolder(IFolderFolder **resultFolder) { *resultFolder = 0; return S_OK; } STDMETHODIMP CPhysDriveFolder::GetNumberOfProperties(UInt32 *numProperties) { *numProperties = sizeof(kProperties) / sizeof(kProperties[0]); return S_OK; } STDMETHODIMP CPhysDriveFolder::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) { if (index >= sizeof(kProperties) / sizeof(kProperties[0])) return E_INVALIDARG; const STATPROPSTG &prop = kProperties[index]; *propID = prop.propid; *varType = prop.vt; *name = 0; return S_OK; } STDMETHODIMP CPhysDriveFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value) { NWindows::NCOM::CPropVariant prop; switch(propID) { case kpidType: prop = L"PhysDrive"; break; case kpidPath: prop = (GetFullPath() + L"\\"); break; } prop.Detach(value); return S_OK; } STDMETHODIMP CPhysDriveFolder::WasChanged(Int32 *wasChanged) { bool wasChangedMain = false; *wasChanged = BoolToInt(wasChangedMain); return S_OK; } STDMETHODIMP CPhysDriveFolder::Clone(IFolderFolder **resultFolder) { CPhysDriveFolder *folderSpec = new CPhysDriveFolder; CMyComPtr folderNew = folderSpec; folderSpec->Init(_path); *resultFolder = folderNew.Detach(); return S_OK; } STDMETHODIMP CPhysDriveFolder::GetItemFullSize(UInt32 index, PROPVARIANT *value, IProgress * /* progress */) { NCOM::CPropVariant prop; if (index >= 1) return E_INVALIDARG; UInt64 size = 0; HRESULT result = GetLength(size); prop = size; prop.Detach(value); return result; } STDMETHODIMP CPhysDriveFolder::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */) { return E_NOTIMPL; } STDMETHODIMP CPhysDriveFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */) { return E_NOTIMPL; } STDMETHODIMP CPhysDriveFolder::Rename(UInt32 /* index */, const wchar_t * /* newName */, IProgress * /* progress */) { return E_NOTIMPL; } STDMETHODIMP CPhysDriveFolder::Delete(const UInt32 * /* indices */, UInt32 /* numItems */, IProgress * /* progress */) { return E_NOTIMPL; } STDMETHODIMP CPhysDriveFolder::SetProperty(UInt32 index, PROPID /* propID */, const PROPVARIANT * /* value */, IProgress * /* progress */) { if (index >= 1) return E_INVALIDARG; return E_NOTIMPL; } HRESULT CPhysDriveFolder::GetLength(UInt64 &length) const { NFile::NDevice::CInFile inFile; if (!inFile.Open(GetFullPath())) return GetLastError(); if (!inFile.GetLengthSmart(length)) return GetLastError(); return S_OK; } struct CPhysTempBuffer { void *buffer; CPhysTempBuffer(): buffer(0) {} ~CPhysTempBuffer() { MyFree(buffer); } }; HRESULT CopyFileSpec(LPCWSTR fromPath, LPCWSTR toPath, bool writeToDisk, UInt64 fileSize, UInt32 bufferSize, UInt64 progressStart, IProgress *progress) { NFile::NIO::CInFile inFile; if (!inFile.Open(fromPath)) return GetLastError(); if (fileSize == (UInt64)(Int64)-1) { if (!inFile.GetLength(fileSize)) ::GetLastError(); } NFile::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 = MyAlloc(bufferSize); if (tempBuffer.buffer == 0) 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; } STDMETHODIMP CPhysDriveFolder::CopyTo(const UInt32 * /* indices */, UInt32 numItems, const wchar_t *path, IFolderOperationsExtractCallback *callback) { if (numItems == 0) return S_OK; UString destPath = path; if (destPath.IsEmpty()) return E_INVALIDARG; bool directName = (destPath[destPath.Length() - 1] != WCHAR_PATH_SEPARATOR); if (directName) { if (numItems > 1) return E_INVALIDARG; } else destPath += _name; UInt64 fileSize; if (GetLength(fileSize) == S_OK) { RINOK(callback->SetTotal(fileSize)); } Int32 writeAskResult; CMyComBSTR destPathResult; RINOK(callback->AskWrite(GetFullPath(), BoolToInt(false), NULL, &fileSize, destPath, &destPathResult, &writeAskResult)); if (!IntToBool(writeAskResult)) return S_OK; RINOK(callback->SetCurrentFilePath(GetFullPathWithName())); UInt32 bufferSize = (_driveType == DRIVE_REMOVABLE) ? (18 << 10) * 4 : kBufferSize; return CopyFileSpec(GetFullPath(), destPathResult, false, fileSize, bufferSize, 0, callback); } ///////////////////////////////////////////////// // Move Operations STDMETHODIMP CPhysDriveFolder::MoveTo( const UInt32 * /* indices */, UInt32 /* numItems */, const wchar_t * /* path */, IFolderOperationsExtractCallback * /* callback */) { return E_NOTIMPL; } STDMETHODIMP CPhysDriveFolder::CopyFrom( const wchar_t * fromFolderPath, const wchar_t ** itemsPaths, UInt32 numItems, IProgress *callback) { if (numItems == 0) return S_OK; if (numItems != 1) return E_INVALIDARG; if (_driveType != DRIVE_REMOVABLE /* && _driveType != DRIVE_CDROM */) return E_NOTIMPL; UInt32 bufferSize = (_driveType == DRIVE_REMOVABLE) ? (18 << 10) * 4 : kBufferSize; // MessageBoxW(0, fromFolderPath, itemsPaths[0], 0); return CopyFileSpec((UString)fromFolderPath + itemsPaths[0], GetFullPath(), true, (UInt64)(Int64)-1, bufferSize, 0, callback); }