• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // FSDrives.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../../C/Alloc.h"
6 
7 #include "../../../Common/ComTry.h"
8 #include "../../../Common/Defs.h"
9 #include "../../../Common/IntToString.h"
10 #include "../../../Common/StringConvert.h"
11 
12 #include "../../../Windows/FileDir.h"
13 #include "../../../Windows/FileIO.h"
14 #include "../../../Windows/FileName.h"
15 #include "../../../Windows/FileSystem.h"
16 #include "../../../Windows/PropVariant.h"
17 
18 #include "../../PropID.h"
19 
20 #include "FSDrives.h"
21 #include "FSFolder.h"
22 #include "LangUtils.h"
23 #include "SysIconUtils.h"
24 
25 #include "resource.h"
26 
27 using namespace NWindows;
28 using namespace NFile;
29 using namespace NFind;
30 
31 static const char * const kVolPrefix   = "\\\\.\\";
32 static const char * const kSuperPrefix = "\\\\?\\";
33 
GetDeviceFileIoName() const34 FString CDriveInfo::GetDeviceFileIoName() const
35 {
36   FString f (kVolPrefix);
37   f += Name;
38   return f;
39 }
40 
41 struct CPhysTempBuffer
42 {
43   void *buffer;
CPhysTempBufferCPhysTempBuffer44   CPhysTempBuffer(): buffer(NULL) {}
~CPhysTempBufferCPhysTempBuffer45   ~CPhysTempBuffer() { MidFree(buffer); }
46 };
47 
CopyFileSpec(CFSTR fromPath,CFSTR toPath,bool writeToDisk,UInt64 fileSize,UInt32 bufferSize,UInt64 progressStart,IProgress * progress)48 static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, bool writeToDisk, UInt64 fileSize,
49     UInt32 bufferSize, UInt64 progressStart, IProgress *progress)
50 {
51   NIO::CInFile inFile;
52   if (!inFile.Open(fromPath))
53     return GetLastError_noZero_HRESULT();
54   if (fileSize == (UInt64)(Int64)-1)
55   {
56     if (!inFile.GetLength(fileSize))
57       return GetLastError_noZero_HRESULT();
58   }
59 
60   NIO::COutFile outFile;
61   if (writeToDisk)
62   {
63     if (!outFile.Open(toPath, FILE_SHARE_WRITE, OPEN_EXISTING, 0))
64       return GetLastError_noZero_HRESULT();
65   }
66   else
67     if (!outFile.Create_ALWAYS(toPath))
68       return GetLastError_noZero_HRESULT();
69 
70   CPhysTempBuffer tempBuffer;
71   tempBuffer.buffer = MidAlloc(bufferSize);
72   if (!tempBuffer.buffer)
73     return E_OUTOFMEMORY;
74 
75   for (UInt64 pos = 0; pos < fileSize;)
76   {
77     UInt64 progressCur = progressStart + pos;
78     RINOK(progress->SetCompleted(&progressCur))
79     UInt64 rem = fileSize - pos;
80     UInt32 curSize = (UInt32)MyMin(rem, (UInt64)bufferSize);
81     UInt32 processedSize;
82     if (!inFile.Read(tempBuffer.buffer, curSize, processedSize))
83       return GetLastError_noZero_HRESULT();
84     if (processedSize == 0)
85       break;
86     curSize = processedSize;
87     if (writeToDisk)
88     {
89       const UInt32 kMask = 0x1FF;
90       curSize = (curSize + kMask) & ~kMask;
91       if (curSize > bufferSize)
92         return E_FAIL;
93     }
94 
95     if (!outFile.Write(tempBuffer.buffer, curSize, processedSize))
96       return GetLastError_noZero_HRESULT();
97     if (curSize != processedSize)
98       return E_FAIL;
99     pos += curSize;
100   }
101 
102   return S_OK;
103 }
104 
105 static const Byte kProps[] =
106 {
107   kpidName,
108   // kpidOutName,
109   kpidTotalSize,
110   kpidFreeSpace,
111   kpidType,
112   kpidVolumeName,
113   kpidFileSystem,
114   kpidClusterSize
115 };
116 
117 static const char * const kDriveTypes[] =
118 {
119     "Unknown"
120   , "No Root Dir"
121   , "Removable"
122   , "Fixed"
123   , "Remote"
124   , "CD-ROM"
125   , "RAM disk"
126 };
127 
Z7_COM7F_IMF(CFSDrives::LoadItems ())128 Z7_COM7F_IMF(CFSDrives::LoadItems())
129 {
130   _drives.Clear();
131 
132   FStringVector driveStrings;
133   MyGetLogicalDriveStrings(driveStrings);
134 
135   FOR_VECTOR (i, driveStrings)
136   {
137     CDriveInfo di;
138 
139     const FString &driveName = driveStrings[i];
140 
141     di.FullSystemName = driveName;
142     if (!driveName.IsEmpty())
143       di.Name.SetFrom(driveName, driveName.Len() - 1);
144     di.ClusterSize = 0;
145     di.DriveSize = 0;
146     di.FreeSpace = 0;
147     di.DriveType = NSystem::MyGetDriveType(driveName);
148     bool needRead = true;
149 
150     if (di.DriveType == DRIVE_CDROM || di.DriveType == DRIVE_REMOVABLE)
151     {
152       /*
153       DWORD dwSerialNumber;`
154       if (!::GetVolumeInformation(di.FullSystemName,
155           NULL, 0, &dwSerialNumber, NULL, NULL, NULL, 0))
156       */
157       {
158         needRead = false;
159       }
160     }
161 
162     if (needRead)
163     {
164       DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags;
165       NSystem::MyGetVolumeInformation(driveName,
166           di.VolumeName,
167           &volumeSerialNumber, &maximumComponentLength, &fileSystemFlags,
168           di.FileSystemName);
169 
170       NSystem::MyGetDiskFreeSpace(driveName,
171           di.ClusterSize, di.DriveSize, di.FreeSpace);
172       di.KnownSizes = true;
173       di.KnownSize = true;
174     }
175 
176     _drives.Add(di);
177   }
178 
179   if (_volumeMode)
180   {
181     // we must use IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
182     for (unsigned n = 0; n < 16; n++) // why 16 ?
183     {
184       FString name ("PhysicalDrive");
185       name.Add_UInt32(n);
186 
187       FString fullPath (kVolPrefix);
188       fullPath += name;
189 
190       CFileInfo fi;
191       if (!fi.Find(fullPath))
192         continue;
193 
194       CDriveInfo di;
195       di.Name = name;
196       di.FullSystemName = fullPath;
197       di.ClusterSize = 0;
198       di.DriveSize = fi.Size;
199       di.FreeSpace = 0;
200       di.DriveType = 0;
201 
202       di.IsPhysicalDrive = true;
203       di.KnownSize = true;
204 
205       _drives.Add(di);
206     }
207   }
208 
209   return S_OK;
210 }
211 
Z7_COM7F_IMF(CFSDrives::GetNumberOfItems (UInt32 * numItems))212 Z7_COM7F_IMF(CFSDrives::GetNumberOfItems(UInt32 *numItems))
213 {
214   *numItems = _drives.Size();
215   return S_OK;
216 }
217 
Z7_COM7F_IMF(CFSDrives::GetProperty (UInt32 itemIndex,PROPID propID,PROPVARIANT * value))218 Z7_COM7F_IMF(CFSDrives::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value))
219 {
220   if (itemIndex >= (UInt32)_drives.Size())
221     return E_INVALIDARG;
222   NCOM::CPropVariant prop;
223   const CDriveInfo &di = _drives[itemIndex];
224   switch (propID)
225   {
226     case kpidIsDir:  prop = !_volumeMode; break;
227     case kpidName:  prop = fs2us(di.Name); break;
228     case kpidOutName:
229       if (!di.Name.IsEmpty() && di.Name.Back() == ':')
230       {
231         FString s = di.Name;
232         s.DeleteBack();
233         AddExt(s, itemIndex);
234         prop = fs2us(s);
235       }
236       break;
237 
238     case kpidTotalSize:   if (di.KnownSize) prop = di.DriveSize; break;
239     case kpidFreeSpace:   if (di.KnownSizes) prop = di.FreeSpace; break;
240     case kpidClusterSize: if (di.KnownSizes) prop = di.ClusterSize; break;
241     case kpidType:
242       if (di.DriveType < Z7_ARRAY_SIZE(kDriveTypes))
243         prop = kDriveTypes[di.DriveType];
244       break;
245     case kpidVolumeName:  prop = di.VolumeName; break;
246     case kpidFileSystem:  prop = di.FileSystemName; break;
247   }
248   prop.Detach(value);
249   return S_OK;
250 }
251 
BindToFolderSpec(CFSTR name,IFolderFolder ** resultFolder)252 HRESULT CFSDrives::BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder)
253 {
254   *resultFolder = NULL;
255   if (_volumeMode)
256     return S_OK;
257   NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder;
258   CMyComPtr<IFolderFolder> subFolder = fsFolderSpec;
259   FString path;
260   if (_superMode)
261     path = kSuperPrefix;
262   path += name;
263   RINOK(fsFolderSpec->Init(path))
264   *resultFolder = subFolder.Detach();
265   return S_OK;
266 }
267 
Z7_COM7F_IMF(CFSDrives::BindToFolder (UInt32 index,IFolderFolder ** resultFolder))268 Z7_COM7F_IMF(CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder))
269 {
270   *resultFolder = NULL;
271   if (index >= (UInt32)_drives.Size())
272     return E_INVALIDARG;
273   const CDriveInfo &di = _drives[index];
274   /*
275   if (_volumeMode)
276   {
277     *resultFolder = 0;
278     CPhysDriveFolder *folderSpec = new CPhysDriveFolder;
279     CMyComPtr<IFolderFolder> subFolder = folderSpec;
280     RINOK(folderSpec->Init(di.Name));
281     *resultFolder = subFolder.Detach();
282     return S_OK;
283   }
284   */
285   return BindToFolderSpec(di.FullSystemName, resultFolder);
286 }
287 
Z7_COM7F_IMF(CFSDrives::BindToFolder (const wchar_t * name,IFolderFolder ** resultFolder))288 Z7_COM7F_IMF(CFSDrives::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder))
289 {
290   return BindToFolderSpec(us2fs(name), resultFolder);
291 }
292 
Z7_COM7F_IMF(CFSDrives::BindToParentFolder (IFolderFolder ** resultFolder))293 Z7_COM7F_IMF(CFSDrives::BindToParentFolder(IFolderFolder **resultFolder))
294 {
295   *resultFolder = NULL;
296   return S_OK;
297 }
298 
299 IMP_IFolderFolder_Props(CFSDrives)
300 
Z7_COM7F_IMF(CFSDrives::GetFolderProperty (PROPID propID,PROPVARIANT * value))301 Z7_COM7F_IMF(CFSDrives::GetFolderProperty(PROPID propID, PROPVARIANT *value))
302 {
303   COM_TRY_BEGIN
304   NCOM::CPropVariant prop;
305   switch (propID)
306   {
307     case kpidType: prop = "FSDrives"; break;
308     case kpidPath:
309       if (_volumeMode)
310         prop = kVolPrefix;
311       else if (_superMode)
312         prop = kSuperPrefix;
313       else
314         prop = (UString)LangString(IDS_COMPUTER) + WCHAR_PATH_SEPARATOR;
315       break;
316   }
317   prop.Detach(value);
318   return S_OK;
319   COM_TRY_END
320 }
321 
322 
Z7_COM7F_IMF(CFSDrives::GetSystemIconIndex (UInt32 index,Int32 * iconIndex))323 Z7_COM7F_IMF(CFSDrives::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
324 {
325   *iconIndex = 0;
326   const CDriveInfo &di = _drives[index];
327   if (di.IsPhysicalDrive)
328     return S_OK;
329   int iconIndexTemp;
330   if (GetRealIconIndex(di.FullSystemName, 0, iconIndexTemp) != 0)
331   {
332     *iconIndex = iconIndexTemp;
333     return S_OK;
334   }
335   return GetLastError_noZero_HRESULT();
336 }
337 
AddExt(FString & s,unsigned index) const338 void CFSDrives::AddExt(FString &s, unsigned index) const
339 {
340   s.Add_Dot();
341   const CDriveInfo &di = _drives[index];
342   UString n = di.FileSystemName;
343   n.MakeLower_Ascii();
344   const char *ext;
345   if (di.DriveType == DRIVE_CDROM)
346     ext = "iso";
347   else
348   {
349     unsigned i;
350     for (i = 0; i < n.Len(); i++)
351     {
352       const wchar_t c = n[i];
353       if (c < 'a' || c > 'z')
354         break;
355     }
356     if (i != 0)
357     {
358       n.DeleteFrom(i);
359       s += us2fs(n);
360       return;
361     }
362     ext = "img";
363   }
364   /*
365        if (n.IsPrefixedBy_Ascii_NoCase("NTFS")) ext = "ntfs";
366   else if (n.IsPrefixedBy_Ascii_NoCase("UDF")) ext = "udf";
367   else if (n.IsPrefixedBy_Ascii_NoCase("exFAT")) ext = "exfat";
368   */
369   s += ext;
370 }
371 
GetFileSize(unsigned index,UInt64 & fileSize) const372 HRESULT CFSDrives::GetFileSize(unsigned index, UInt64& fileSize) const
373 {
374 #ifdef Z7_DEVICE_FILE
375   NIO::CInFile inFile;
376   if (!inFile.Open(_drives[index].GetDeviceFileIoName()))
377     return GetLastError_noZero_HRESULT();
378   if (inFile.SizeDefined)
379   {
380     fileSize = inFile.Size;
381     return S_OK;
382   }
383 #else
384   UNUSED_VAR(index)
385 #endif
386   fileSize = 0;
387   return E_FAIL;
388 }
389 
Z7_COM7F_IMF(CFSDrives::CopyTo (Int32 moveMode,const UInt32 * indices,UInt32 numItems,Int32,Int32,const wchar_t * path,IFolderOperationsExtractCallback * callback))390 Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
391     Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */,
392     const wchar_t *path, IFolderOperationsExtractCallback *callback))
393 {
394   if (numItems == 0)
395     return S_OK;
396 
397   if (moveMode)
398     return E_NOTIMPL;
399 
400   if (!_volumeMode)
401     return E_NOTIMPL;
402 
403   UInt64 totalSize = 0;
404   UInt32 i;
405   for (i = 0; i < numItems; i++)
406   {
407     const CDriveInfo &di = _drives[indices[i]];
408     if (di.KnownSize)
409       totalSize += di.DriveSize;
410   }
411   RINOK(callback->SetTotal(totalSize))
412   RINOK(callback->SetNumFiles(numItems))
413 
414   FString destPath = us2fs(path);
415   if (destPath.IsEmpty())
416     return E_INVALIDARG;
417 
418   bool isAltDest = NName::IsAltPathPrefix(destPath);
419   bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back()));
420 
421   if (isDirectPath)
422   {
423     if (numItems > 1)
424       return E_INVALIDARG;
425   }
426 
427   UInt64 completedSize = 0;
428   RINOK(callback->SetCompleted(&completedSize))
429   for (i = 0; i < numItems; i++)
430   {
431     unsigned index = indices[i];
432     const CDriveInfo &di = _drives[index];
433     FString destPath2 = destPath;
434 
435     if (!isDirectPath)
436     {
437       FString destName = di.Name;
438       if (!destName.IsEmpty() && destName.Back() == ':')
439       {
440         destName.DeleteBack();
441         AddExt(destName, index);
442       }
443       destPath2 += destName;
444     }
445 
446     FString srcPath = di.GetDeviceFileIoName();
447 
448     UInt64 fileSize = 0;
449     if (GetFileSize(index, fileSize) != S_OK)
450     {
451       return E_FAIL;
452     }
453     if (!di.KnownSize)
454     {
455       totalSize += fileSize;
456       RINOK(callback->SetTotal(totalSize))
457     }
458 
459     Int32 writeAskResult;
460     CMyComBSTR destPathResult;
461     RINOK(callback->AskWrite(fs2us(srcPath), BoolToInt(false), NULL, &fileSize,
462         fs2us(destPath2), &destPathResult, &writeAskResult))
463 
464     if (!IntToBool(writeAskResult))
465     {
466       if (totalSize >= fileSize)
467         totalSize -= fileSize;
468       RINOK(callback->SetTotal(totalSize))
469       continue;
470     }
471 
472     RINOK(callback->SetCurrentFilePath(fs2us(srcPath)))
473 
474     const UInt32 kBufferSize = (4 << 20);
475     const UInt32 bufferSize = (di.DriveType == DRIVE_REMOVABLE) ? (18 << 10) * 4 : kBufferSize;
476     RINOK(CopyFileSpec(srcPath, us2fs(destPathResult), false, fileSize, bufferSize, completedSize, callback))
477     completedSize += fileSize;
478   }
479 
480   return S_OK;
481 }
482 
Z7_COM7F_IMF(CFSDrives::CopyFrom (Int32,const wchar_t *,const wchar_t * const *,UInt32,IProgress *))483 Z7_COM7F_IMF(CFSDrives::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */,
484     const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */))
485 {
486   return E_NOTIMPL;
487 }
488 
Z7_COM7F_IMF(CFSDrives::CopyFromFile (UInt32,const wchar_t *,IProgress *))489 Z7_COM7F_IMF(CFSDrives::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */))
490 {
491   return E_NOTIMPL;
492 }
493 
Z7_COM7F_IMF(CFSDrives::CreateFolder (const wchar_t *,IProgress *))494 Z7_COM7F_IMF(CFSDrives::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */))
495 {
496   return E_NOTIMPL;
497 }
498 
Z7_COM7F_IMF(CFSDrives::CreateFile (const wchar_t *,IProgress *))499 Z7_COM7F_IMF(CFSDrives::CreateFile(const wchar_t * /* name */, IProgress * /* progress */))
500 {
501   return E_NOTIMPL;
502 }
503 
Z7_COM7F_IMF(CFSDrives::Rename (UInt32,const wchar_t *,IProgress *))504 Z7_COM7F_IMF(CFSDrives::Rename(UInt32 /* index */, const wchar_t * /* newName */, IProgress * /* progress */))
505 {
506   return E_NOTIMPL;
507 }
508 
Z7_COM7F_IMF(CFSDrives::Delete (const UInt32 *,UInt32,IProgress *))509 Z7_COM7F_IMF(CFSDrives::Delete(const UInt32 * /* indices */, UInt32 /* numItems */, IProgress * /* progress */))
510 {
511   return E_NOTIMPL;
512 }
513 
Z7_COM7F_IMF(CFSDrives::SetProperty (UInt32,PROPID,const PROPVARIANT *,IProgress *))514 Z7_COM7F_IMF(CFSDrives::SetProperty(UInt32 /* index */, PROPID /* propID */,
515     const PROPVARIANT * /* value */, IProgress * /* progress */))
516 {
517   return E_NOTIMPL;
518 }
519