5 #include "../../../../C/Alloc.h"
\r
7 #include "Common/ComTry.h"
\r
8 #include "Common/StringConvert.h"
\r
10 #include "Windows/Defs.h"
\r
11 #include "Windows/FileDir.h"
\r
12 #include "Windows/FileIO.h"
\r
13 #include "Windows/FileSystem.h"
\r
14 #include "Windows/PropVariant.h"
\r
16 #include "../../PropID.h"
\r
18 #include "FSDrives.h"
\r
19 #include "FSFolder.h"
\r
20 #include "LangUtils.h"
\r
21 #include "SysIconUtils.h"
\r
23 #include "resource.h"
\r
25 using namespace NWindows;
\r
26 using namespace NFile;
\r
27 using namespace NFind;
\r
29 static const wchar_t *kVolPrefix = L"\\\\.\\";
\r
31 UString CDriveInfo::GetDeviceFileIoName() const
\r
33 return kVolPrefix + Name;
\r
36 struct CPhysTempBuffer
\r
39 CPhysTempBuffer(): buffer(0) {}
\r
40 ~CPhysTempBuffer() { MidFree(buffer); }
\r
43 static HRESULT CopyFileSpec(LPCWSTR fromPath, LPCWSTR toPath, bool writeToDisk, UInt64 fileSize,
\r
44 UInt32 bufferSize, UInt64 progressStart, IProgress *progress)
\r
46 NFile::NIO::CInFile inFile;
\r
47 if (!inFile.Open(fromPath))
\r
48 return GetLastError();
\r
49 if (fileSize == (UInt64)(Int64)-1)
\r
51 if (!inFile.GetLength(fileSize))
\r
54 NFile::NIO::COutFile outFile;
\r
57 if (!outFile.Open(toPath, FILE_SHARE_WRITE, OPEN_EXISTING, 0))
\r
58 return GetLastError();
\r
61 if (!outFile.Create(toPath, true))
\r
62 return GetLastError();
\r
63 CPhysTempBuffer tempBuffer;
\r
64 tempBuffer.buffer = MidAlloc(bufferSize);
\r
65 if (tempBuffer.buffer == 0)
\r
66 return E_OUTOFMEMORY;
\r
68 for (UInt64 pos = 0; pos < fileSize;)
\r
70 UInt64 progressCur = progressStart + pos;
\r
71 RINOK(progress->SetCompleted(&progressCur));
\r
72 UInt64 rem = fileSize - pos;
\r
73 UInt32 curSize = (UInt32)MyMin(rem, (UInt64)bufferSize);
\r
74 UInt32 processedSize;
\r
75 if (!inFile.Read(tempBuffer.buffer, curSize, processedSize))
\r
76 return GetLastError();
\r
77 if (processedSize == 0)
\r
79 curSize = processedSize;
\r
82 const UInt32 kMask = 0x1FF;
\r
83 curSize = (curSize + kMask) & ~kMask;
\r
84 if (curSize > bufferSize)
\r
88 if (!outFile.Write(tempBuffer.buffer, curSize, processedSize))
\r
89 return GetLastError();
\r
90 if (curSize != processedSize)
\r
97 static const STATPROPSTG kProps[] =
\r
99 { NULL, kpidName, VT_BSTR},
\r
100 { NULL, kpidTotalSize, VT_UI8},
\r
101 { NULL, kpidFreeSpace, VT_UI8},
\r
102 { NULL, kpidType, VT_BSTR},
\r
103 { NULL, kpidVolumeName, VT_BSTR},
\r
104 { NULL, kpidFileSystem, VT_BSTR},
\r
105 { NULL, kpidClusterSize, VT_UI8}
\r
108 static const char *kDriveTypes[] =
\r
119 STDMETHODIMP CFSDrives::LoadItems()
\r
123 UStringVector driveStrings;
\r
124 MyGetLogicalDriveStrings(driveStrings);
\r
125 for (int i = 0; i < driveStrings.Size(); i++)
\r
129 const UString &driveName = driveStrings[i];
\r
131 di.FullSystemName = driveName;
\r
133 di.Name = di.FullSystemName.Left(di.FullSystemName.Length() - 1);
\r
134 di.ClusterSize = 0;
\r
137 di.DriveType = NFile::NSystem::MyGetDriveType(driveName);
\r
138 bool needRead = true;
\r
139 if (di.DriveType == DRIVE_CDROM || di.DriveType == DRIVE_REMOVABLE)
\r
142 DWORD dwSerialNumber;`
\r
143 if (!::GetVolumeInformation(di.FullSystemName,
\r
144 NULL, 0, &dwSerialNumber, NULL, NULL, NULL, 0))
\r
146 di.KnownSizes = false;
\r
153 UString volumeName, fileSystemName;
\r
154 DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags;
\r
155 NFile::NSystem::MyGetVolumeInformation(driveName,
\r
157 &volumeSerialNumber, &maximumComponentLength, &fileSystemFlags,
\r
159 di.VolumeName = volumeName;
\r
160 di.FileSystemName = fileSystemName;
\r
162 NFile::NSystem::MyGetDiskFreeSpace(driveName,
\r
163 di.ClusterSize, di.DriveSize, di.FreeSpace);
\r
164 di.KnownSizes = true;
\r
171 STDMETHODIMP CFSDrives::GetNumberOfItems(UInt32 *numItems)
\r
173 *numItems = _drives.Size();
\r
177 STDMETHODIMP CFSDrives::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)
\r
179 if (itemIndex >= (UInt32)_drives.Size())
\r
180 return E_INVALIDARG;
\r
181 NCOM::CPropVariant prop;
\r
182 const CDriveInfo &di = _drives[itemIndex];
\r
185 case kpidIsDir: prop = !_volumeMode; break;
\r
186 case kpidName: prop = di.Name; break;
\r
187 case kpidTotalSize: if (di.KnownSizes) prop = di.DriveSize; break;
\r
188 case kpidFreeSpace: if (di.KnownSizes) prop = di.FreeSpace; break;
\r
189 case kpidClusterSize: if (di.KnownSizes) prop = di.ClusterSize; break;
\r
191 if (di.DriveType < sizeof(kDriveTypes) / sizeof(kDriveTypes[0]))
\r
192 prop = kDriveTypes[di.DriveType];
\r
194 case kpidVolumeName: prop = di.VolumeName; break;
\r
195 case kpidFileSystem: prop = di.FileSystemName; break;
\r
197 prop.Detach(value);
\r
201 HRESULT CFSDrives::BindToFolderSpec(const wchar_t *name, IFolderFolder **resultFolder)
\r
206 NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder;
\r
207 CMyComPtr<IFolderFolder> subFolder = fsFolderSpec;
\r
208 RINOK(fsFolderSpec->Init(name, 0));
\r
209 *resultFolder = subFolder.Detach();
\r
213 STDMETHODIMP CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder)
\r
216 if (index >= (UInt32)_drives.Size())
\r
217 return E_INVALIDARG;
\r
218 const CDriveInfo &di = _drives[index];
\r
223 CPhysDriveFolder *folderSpec = new CPhysDriveFolder;
\r
224 CMyComPtr<IFolderFolder> subFolder = folderSpec;
\r
225 RINOK(folderSpec->Init(di.Name));
\r
226 *resultFolder = subFolder.Detach();
\r
230 return BindToFolderSpec(di.FullSystemName, resultFolder);
\r
233 STDMETHODIMP CFSDrives::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)
\r
235 return BindToFolderSpec(name, resultFolder);
\r
238 STDMETHODIMP CFSDrives::BindToParentFolder(IFolderFolder **resultFolder)
\r
244 IMP_IFolderFolder_Props(CFSDrives)
\r
246 STDMETHODIMP CFSDrives::GetFolderProperty(PROPID propID, PROPVARIANT *value)
\r
249 NWindows::NCOM::CPropVariant prop;
\r
252 case kpidType: prop = L"FSDrives"; break;
\r
257 prop = LangString(IDS_COMPUTER, 0x03020300) + UString(WCHAR_PATH_SEPARATOR);
\r
260 prop.Detach(value);
\r
266 STDMETHODIMP CFSDrives::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)
\r
269 const CDriveInfo &di = _drives[index];
\r
271 if (GetRealIconIndex(di.FullSystemName, 0, iconIndexTemp) != 0)
\r
273 *iconIndex = iconIndexTemp;
\r
276 return GetLastError();
\r
279 UString CFSDrives::GetExt(int index) const
\r
281 const CDriveInfo &di = _drives[index];
\r
282 const wchar_t *ext = NULL;
\r
283 if (di.DriveType == DRIVE_CDROM)
\r
285 else if (di.FileSystemName.Find(L"NTFS") >= 0)
\r
287 else if (di.FileSystemName.Find(L"FAT") >= 0)
\r
291 return (UString)L'.' + ext;
\r
294 HRESULT CFSDrives::GetLength(int index, UInt64 &length) const
\r
296 NFile::NIO::CInFile inFile;
\r
297 if (!inFile.Open(_drives[index].GetDeviceFileIoName()))
\r
298 return GetLastError();
\r
299 if (!inFile.LengthDefined)
\r
301 length = inFile.Length;
\r
305 STDMETHODIMP CFSDrives::CopyTo(const UInt32 *indices, UInt32 numItems,
\r
306 const wchar_t *path, IFolderOperationsExtractCallback *callback)
\r
314 UInt64 totalSize = 0;
\r
316 for (i = 0; i < numItems; i++)
\r
318 const CDriveInfo &di = _drives[indices[i]];
\r
320 totalSize += di.DriveSize;
\r
322 RINOK(callback->SetTotal(totalSize));
\r
323 RINOK(callback->SetNumFiles(numItems));
\r
325 UString destPath = path;
\r
326 if (destPath.IsEmpty())
\r
327 return E_INVALIDARG;
\r
328 bool directName = (destPath[destPath.Length() - 1] != WCHAR_PATH_SEPARATOR);
\r
332 return E_INVALIDARG;
\r
335 UInt64 completedSize = 0;
\r
336 RINOK(callback->SetCompleted(&completedSize));
\r
337 for (i = 0; i < numItems; i++)
\r
339 int index = indices[i];
\r
340 const CDriveInfo &di = _drives[index];
\r
341 UString destPath2 = destPath;
\r
342 UString name = di.Name;
\r
345 UString destName = name;
\r
346 if (!destName.IsEmpty() && destName[destName.Length() - 1] == L':')
\r
348 destName.Delete(destName.Length() - 1);
\r
349 destName += GetExt(index);
\r
351 destPath2 += destName;
\r
353 UString srcPath = di.GetDeviceFileIoName();
\r
355 UInt64 fileSize = 0;
\r
356 if (GetLength(index, fileSize) != S_OK)
\r
360 if (!di.KnownSizes)
\r
361 totalSize += fileSize;
\r
362 RINOK(callback->SetTotal(totalSize));
\r
364 Int32 writeAskResult;
\r
365 CMyComBSTR destPathResult;
\r
366 RINOK(callback->AskWrite(srcPath, BoolToInt(false), NULL, &fileSize,
\r
367 destPath2, &destPathResult, &writeAskResult));
\r
368 if (!IntToBool(writeAskResult))
\r
371 RINOK(callback->SetCurrentFilePath(srcPath));
\r
373 static const UInt32 kBufferSize = (4 << 20);
\r
374 UInt32 bufferSize = (di.DriveType == DRIVE_REMOVABLE) ? (18 << 10) * 4 : kBufferSize;
\r
375 RINOK(CopyFileSpec(srcPath, destPathResult, false, fileSize, bufferSize, completedSize, callback));
\r
376 completedSize += fileSize;
\r
381 STDMETHODIMP CFSDrives::MoveTo(
\r
382 const UInt32 * /* indices */,
\r
383 UInt32 /* numItems */,
\r
384 const wchar_t * /* path */,
\r
385 IFolderOperationsExtractCallback * /* callback */)
\r
390 STDMETHODIMP CFSDrives::CopyFrom(const wchar_t * /* fromFolderPath */,
\r
391 const wchar_t ** /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */)
\r
396 STDMETHODIMP CFSDrives::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */)
\r
401 STDMETHODIMP CFSDrives::CreateFile(const wchar_t * /* name */, IProgress * /* progress */)
\r
406 STDMETHODIMP CFSDrives::Rename(UInt32 /* index */, const wchar_t * /* newName */, IProgress * /* progress */)
\r
411 STDMETHODIMP CFSDrives::Delete(const UInt32 * /* indices */, UInt32 /* numItems */, IProgress * /* progress */)
\r
416 STDMETHODIMP CFSDrives::SetProperty(UInt32 /* index */, PROPID /* propID */,
\r
417 const PROPVARIANT * /* value */, IProgress * /* progress */)
\r