TNB Library
TnbDriveCommander.h
[詳解]
1#pragma once
17#include <ntddscsi.h> // SDK
18#include <WinIoCtl.h> // SDK
19#include "TnbPointerHandle.h"
20#include "TnbHandleHandle.h"
21#include "TnbCollection.h"
22#include "TnbWriter.h"
23
24
25
26//TNB Library
27namespace TNB
28{
29
30
31
53{
54public:
55
61 {
62 BYTE KEY;
63 BYTE ASC;
64 BYTE ASCQ;
66 void Clear(void) {
67 KEY = ASC = ASCQ = 0;
68 }
69 };
70
71
72 //-----
73
74
76 CDriveCommander(void) : m_timeout(2)
77 {
78 m_sense.Clear();
79 }
80
86 bool IsOpened(void) const
87 {
88 return ! m_hhDrive.IsNull();
89 }
90
92 virtual void Close(void)
93 {
94 m_hhDrive.Null();
95 }
96
104 bool OpenDrive(DWORD driveNo)
105 {
106 Close();
107 m_hhDrive = ::CreateFile(CStr::Fmt(_T("\\\\.\\PhysicalDrive%d"), driveNo),
108 GENERIC_READ | GENERIC_WRITE,
109 FILE_SHARE_READ | FILE_SHARE_WRITE,
110 NULL,
111 OPEN_EXISTING,
112 0, NULL);
113 return ! m_hhDrive.IsNull();
114 }
115
123 bool OpenLetter(TCHAR driveLetter)
124 {
125 Close();
126 m_hhDrive = ::CreateFile(CStr::Fmt(_T("\\\\.\\%c:"), driveLetter),
127 GENERIC_READ | GENERIC_WRITE,
128 FILE_SHARE_READ,
129 NULL,
130 OPEN_EXISTING,
131 0, NULL);
132 return ! m_hhDrive.IsNull();
133 }
134
140 const TSenseData& GetSense(void) const
141 {
142 return m_sense;
143 }
144
150 bool Update()
151 {
152 DWORD d;
153 return !! ::DeviceIoControl(m_hhDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &d, NULL);
154 }
155
162 {
163 DWORD d;
164 return !! ::DeviceIoControl(m_hhDrive, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &d, NULL);
165 }
166
172 bool LockVolume(void)
173 {
174 DWORD d;
175 return !! ::DeviceIoControl(m_hhDrive, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &d, NULL);
176 }
177
183 bool UnlockVolume(void)
184 {
185 DWORD d;
186 return !! ::DeviceIoControl(m_hhDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &d, NULL);
187 }
188
197 {
198 if ( m_hhDrive.IsNull() )
199 {
200 ::SetLastError(ERROR_ACCESS_DENIED);
201 return -1;
202 }
203 CCdbInfo tmp(0, SCSI_IOCTL_DATA_UNSPECIFIED); //SCSI_IOCTL_DATA_IN
204 tmp.SetCdb(cdb, m_timeout);
205 return m_SendCdb(tmp);
206 }
207
218 {
219 if ( m_hhDrive.IsNull() )
220 {
221 ::SetLastError(ERROR_ACCESS_DENIED);
222 return -1;
223 }
224 size_t l = data.GetSize();
225 CCdbInfo tmp(l, static_cast<BYTE>((l > 0) ? SCSI_IOCTL_DATA_OUT : SCSI_IOCTL_DATA_UNSPECIFIED));
226 tmp.SetCdb(cdb, m_timeout);
227 if ( l > 0 )
228 {
229 MemCopy(tmp.RefData(), data.ReferBuffer(), l);
230 }
231 return m_SendCdb(tmp);
232 }
233
244 const ISequenceCollectionT<BYTE>& cdb, int readSize)
245 {
246 if ( m_hhDrive.IsNull() )
247 {
248 ::SetLastError(ERROR_ACCESS_DENIED);
249 return -1;
250 }
251 CCdbInfo tmp(readSize, SCSI_IOCTL_DATA_IN);
252 tmp.SetCdb(cdb, m_timeout);
253 int r = m_SendCdb(tmp);
254 if ( r == 0 )
255 {
256 _d.CopyElements(readSize, tmp.RefData());
257 }
258 return r;
259 }
260
271 int Send_ModeSense(ICollectionT<BYTE>& _d, BYTE pc, bool isWithBd = false)
272 {
273 BYTE cdb[6] = {0x1A/*ModeSense*/, _BIT(3)/*Block Descriptor 転送なし*/, pc, 0, 4, 0};
274 int r = SendCommandWithReadPhase(_d, CArrayAdapterT<BYTE>(cdb), cdb[4]);
275 if ( r == 0 && _d.GetSize() >= 4 )
276 {
277 cdb[1] = static_cast<BYTE>((isWithBd && _d.At(3) == 8) ? 0 : _BIT(3));
278 cdb[4] = static_cast<BYTE>(4 + _d.At(3) + _d.At(0));
279 r = SendCommandWithReadPhase(_d, CArrayAdapterT<BYTE>(cdb), cdb[4]);
280 }
281 return r;
282 }
283
292 {
293 BYTE cdb[6] = {0x12/*Inquiry*/, 0, 0, 0, 8, 0};
294 int r = SendCommandWithReadPhase(_d, CArrayAdapterT<BYTE>(cdb), cdb[4]);
295 if ( r == 0 )
296 {
297 cdb[4] = static_cast<BYTE>(5 + _d.At(4));
298 r = SendCommandWithReadPhase(_d, CArrayAdapterT<BYTE>(cdb), cdb[4]);
299 }
300 return r;
301 }
302
310 {
311 BYTE cdb[6] = {0/*TestUnit*/, 0, 0, 0, 0, 0};
312 return SendCommand(CArrayAdapterT<BYTE>(cdb));
313 }
314
322 int Send_StartStop(BYTE b = 2)
323 {
324 BYTE cdb[6] = {0x1B/*StartStop*/, 1, 0, 0, b, 0};
325 return SendCommand(CArrayAdapterT<BYTE>(cdb));
326 }
327
336 int Send_ReadCapacity(DWORD& _blockAddress, DWORD& _blockLength)
337 {
338 BYTE cdb[10] = {0x25/*ReadCapacity*/, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
339 CByteVector vb;
340 int r = SendCommandWithReadPhase(vb, CArrayAdapterT<BYTE>(cdb), 8);
341 if ( r == 0 )
342 {
343 BYTE* p = reinterpret_cast<BYTE*>(vb.GetBuffer());
344 _blockAddress = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
345 _blockLength = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
346 }
347 return r;
348 }
349
359 int Send_Write10(DWORD ba, const ISequenceCollectionT<BYTE>& d, DWORD div = 512)
360 {
361 BYTE cdb[10] = {0x2A/*Write10*/, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
362 cdb[2] = static_cast<BYTE>(ba >> 24);
363 cdb[3] = static_cast<BYTE>(ba >> 16);
364 cdb[4] = static_cast<BYTE>(ba >> 8);
365 cdb[5] = static_cast<BYTE>(ba);
366 DWORD l = d.GetSize() / div;
367 cdb[7] = static_cast<BYTE>(l >> 8);
368 cdb[8] = static_cast<BYTE>(l);
369 int r = SendCommandWithWritePhase(CArrayAdapterT<BYTE>(cdb), d);
370 return r;
371 }
372
377 HANDLE GetSafeHandle(void) const
378 {
379 return m_hhDrive;
380 }
381
389 bool GetVendorId(CStr& _id, bool withRevision = false) const
390 {
391 CDriveCommander* p = const_cast<CDriveCommander*>(this);
392 CByteVector vb;
393 p->Send_TestUnit(); // 空読込み
394 if ( p->Send_Inquiry(vb) == 0 && vb.GetSize() >= 36 )
395 {
396 const char* p = reinterpret_cast<const char*>(vb.ReferBuffer());
397 CAscii a1;
398 a1.SetFromLeft(&p[8], 8);
399 _id = a1;
400 a1.SetFromLeft(&p[16], 16);
401 _id += a1;
402 if ( withRevision )
403 {
404 a1.SetFromLeft(&p[32], 4);
405 _id += a1;
406 }
407 return true;
408 }
409 return false;
410 }
411
417 virtual LPCTSTR GetOpenName(void) const
418 {
419 m_vendorId.Empty();
420 GetVendorId(m_vendorId);
421 return m_vendorId;
422 }
423
430 virtual bool CanRead(void) const
431 {
432 CDriveCommander* p = const_cast<CDriveCommander*>(this);
433 return (p->Send_TestUnit()) == 0;
434 }
435
442 virtual bool CanWrite(void) const
443 {
444 CDriveCommander* p = const_cast<CDriveCommander*>(this);
445 CByteVector vb;
446 if ( CanRead() && p->Send_ModeSense(vb, 0x3F) == 0 && vb.GetSize() >= 4 )
447 {
448 //TNB::DebugDump(vb.GetSize(), vb.ReferBuffer());
449 // vb[1]; //Media ID
450 // vb[2]; // 3Byte目の最上位Bitが WriteProtect 状態です(1なら WP)。
451 return (vb[2] & _BIT(7)) == 0;
452 }
453 return false;
454 }
455
462 virtual LONGLONG GetSize(void) const
463 {
464 CWorkMem w(sizeof(DISK_GEOMETRY_EX) + sizeof(DISK_PARTITION_INFO) + sizeof(DISK_DETECTION_INFO));
465 w.Fill(0);
466 DWORD returnedBytes = 0;
467 BOOL r = ::DeviceIoControl(
468 GetSafeHandle(), IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, w.Ref(), w.GetSize(), &returnedBytes, NULL);
469 DISK_GEOMETRY_EX* pGeometry = reinterpret_cast<DISK_GEOMETRY_EX*>(w.Ref());
470 //DISK_PARTITION_INFO* pPartition= DiskGeometryGetPartition(pGeometry);
471 //DISK_DETECTION_INFO* pDetection = DiskGeometryGetDetect(pGeometry);
472 LONGLONG ll = pGeometry->DiskSize.QuadPart;
473 return r ? ll : -1;
474 }
475
482 bool GetGeometry(DISK_GEOMETRY& _g) const
483 {
484 CWorkMem w(sizeof(DISK_GEOMETRY_EX) + sizeof(DISK_PARTITION_INFO) + sizeof(DISK_DETECTION_INFO));
485 w.Fill(0);
486 DWORD returnedBytes = 0;
487 BOOL r = ::DeviceIoControl(
488 GetSafeHandle(), IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, w.Ref(), w.GetSize(), &returnedBytes, NULL);
489 DISK_GEOMETRY_EX* pGeometry = reinterpret_cast<DISK_GEOMETRY_EX*>(w.Ref());
490 _g = pGeometry->Geometry;
491 return !! r;
492 }
493
503 virtual LONGLONG Seek(LONGLONG llOffset, ESeekMode seek = TOP) const
504 {
505 if ( seek == END )
506 {
507 llOffset += GetSize();
508 seek = TOP;
509 }
510 LARGE_INTEGER r;
511 r.QuadPart = llOffset;
512 r.LowPart = ::SetFilePointer(GetSafeHandle(), r.LowPart, &r.HighPart, seek);
513 if ( r.LowPart == INVALID_SET_FILE_POINTER )
514 {
515 if ( ::GetLastError() != NO_ERROR )
516 {
517 r.QuadPart = -1;
518 }
519 }
520 return r.QuadPart;
521 }
522
531 virtual size_t Read(size_t size, LPVOID _P) const
532 {
533 DWORD dwRead;
534 BOOL boRc = ::ReadFile(GetSafeHandle(), _P, ToDword(size), &dwRead, NULL);
535 if ( ! boRc )
536 {
537 throw CReadFailureException(::GetLastError());
538 }
539 return dwRead;
540 }
541
549 virtual void Write(size_t size, LPCVOID P)
550 {
551 if ( size >= ULONG_MAX )
552 {
553 throw CWriteFailureException(ERROR_BAD_LENGTH);
554 }
555 DWORD dwWrite;
556 bool boRc = !! ::WriteFile(GetSafeHandle(), P, ToDword(size), &dwWrite, NULL);
557 DWORD dwError = boRc ? 0 : ::GetLastError();
558 if ( ! boRc || size != dwWrite )
559 {
560 throw CWriteFailureException(dwError);
561 }
562 }
563
569 virtual void SetEnd(void)
570 {
571 throw CNotSupportException();
572 }
573
574private:
575
577 struct TScsiPassThroughEx
578 {
579 SCSI_PASS_THROUGH spt;
580 DWORD boundary;
581 BYTE abSense[32];
582 };
583
585 class CCdbInfo
586 {
587 CWorkMem m_work;
588 size_t m_size;
589 public:
591 CCdbInfo(size_t size, BYTE bMode) : m_work(0)
592 {
593 m_size = sizeof(TScsiPassThroughEx) + size;
594 m_work.Resize(m_size);
595 TScsiPassThroughEx* P = reinterpret_cast<TScsiPassThroughEx*>(m_work.Ref());
596 ::ZeroMemory(P, m_size);
597 P->spt.Length = sizeof(SCSI_PASS_THROUGH);
598// P->spt.SenseInfoLength = 18;
599 P->spt.SenseInfoLength = 32;
600 P->spt.DataIn = bMode;
601 P->spt.DataTransferLength = static_cast<ULONG>(size);
602 P->spt.TimeOutValue = 2;
603 if ( size != 0 )
604 {
605 P->spt.DataBufferOffset = sizeof(TScsiPassThroughEx);
606 }
607 P->spt.SenseInfoOffset = offsetof(TScsiPassThroughEx, abSense);
608 }
610 void SetCdb(const ISequenceCollectionT<BYTE>& cdb, DWORD timeout)
611 {
612 TScsiPassThroughEx* P = reinterpret_cast<TScsiPassThroughEx*>(m_work.Ref());
613 P->spt.CdbLength = static_cast<BYTE>(cdb.GetSize());
614 MemCopy(P->spt.Cdb, cdb.ReferBuffer(), cdb.GetSize());
615 P->spt.TimeOutValue = timeout;
616 }
618 TScsiPassThroughEx* Ref(void)
619 {
620 return reinterpret_cast<TScsiPassThroughEx*>(m_work.Ref());
621 }
623 BYTE* RefData(void)
624 {
625 return m_work.Ref() + sizeof(TScsiPassThroughEx);
626 }
628 size_t GetLength(void)
629 {
630 return m_size;
631 }
632 };
633
635 template<typename TYP>
636 class CArrayAdapterT : public ISequenceCollectionT<TYP>
637 {
639 const TYP* m_pcType;
640 size_t m_size;
641 public:
643 template<typename T> CArrayAdapterT(const T& t)
644 : _super(), m_pcType(static_cast<const TYP*>(t)), m_size(sizeof(T) / sizeof(TYP)) {}
646 virtual size_t GetSize(void) const { return m_size; }
648 virtual const TYP* ReferBuffer(void) const { return m_pcType; }
649 };
650
658 int m_SendCdb(CCdbInfo& cdb)
659 {
660 DWORD dwResult = 0;
661 TScsiPassThroughEx* P = cdb.Ref();
662 BOOL r = ::DeviceIoControl(m_hhDrive,
663 IOCTL_SCSI_PASS_THROUGH,
664 P,
665 cdb.GetLength(),
666 P,
667 cdb.GetLength(),
668 &dwResult,
669 NULL);
670 m_sense.Clear();
671 if ( r && P->spt.ScsiStatus != 0 )
672 {
673 m_sense.KEY = static_cast<BYTE>(P->abSense[2] & 0x0F);
674 if ( P->abSense[7] >= 0x0A )
675 {
676 m_sense.ASC = P->abSense[12];
677 m_sense.ASCQ = P->abSense[13];
678 }
679 return P->spt.ScsiStatus;
680 }
681 return r ? 0 : -1;
682 }
683
684 CHandleHandle m_hhDrive;
685 TSenseData m_sense;
686 DWORD m_timeout;
687 mutable CStr m_vendorId;
688};
689
690
691
692}; // TNB
693
694
695
696#if 0
697
698// メモ
699 http://support.microsoft.com/kb/871134/ja
700 http://support.microsoft.com/kb/137247/ja
701
702#endif
情報群管理関係のヘッダ
#define _BIT(X)
BIT演算
Definition: TnbDef.h:307
ハンドルハンドル関係のヘッダ
ポインタハンドル関係のヘッダ
ファイル関係のヘッダ
ドライブコマンダークラス
int SendCommandWithWritePhase(const ISequenceCollectionT< BYTE > &cdb, const ISequenceCollectionT< BYTE > &data)
[送信] CDB送信(書込みフェーズ付).
bool GetVendorId(CStr &_id, bool withRevision=false) const
[取得] ベンダID 取得.
int Send_TestUnit(void)
[送信] TEST UNIT CDB送信.
bool Update()
[設定] アップデート.
virtual size_t Read(size_t size, LPVOID _P) const
[取得] 読み込み
int Send_Inquiry(ICollectionT< BYTE > &_d)
[送信] INQUIRY CDB送信.
int SendCommandWithReadPhase(ICollectionT< BYTE > &_d, const ISequenceCollectionT< BYTE > &cdb, int readSize)
[送信] CDB送信(読込みフェーズ付).
int Send_Write10(DWORD ba, const ISequenceCollectionT< BYTE > &d, DWORD div=512)
[送信] Write(10) CDB送信.
HANDLE GetSafeHandle(void) const
[取得] ハンドル取得.
virtual LONGLONG GetSize(void) const
[取得] サイズ取得.
virtual bool CanRead(void) const
[確認] 読み込み可能か?
int SendCommand(const ISequenceCollectionT< BYTE > &cdb)
[送信] CDB送信.
bool IsOpened(void) const
[確認] オープン済み?
virtual LPCTSTR GetOpenName(void) const
[取得] オープン名取得.
CDriveCommander(void)
コンストラクタ
int Send_ModeSense(ICollectionT< BYTE > &_d, BYTE pc, bool isWithBd=false)
[送信] MODESENSE CDB送信.
virtual LONGLONG Seek(LONGLONG llOffset, ESeekMode seek=TOP) const
[操作] シーク.
const TSenseData & GetSense(void) const
[取得] センスデータ取得
virtual void Close(void)
[操作] クローズ
bool GetGeometry(DISK_GEOMETRY &_g) const
[取得] GEOMETRY 取得.
virtual void Write(size_t size, LPCVOID P)
[保存] 書き込み
virtual void SetEnd(void)
[設定] EOFを指定.
bool LockVolume(void)
[設定] Lock Volume.
int Send_StartStop(BYTE b=2)
[送信] STARTSTOP CDB送信.
bool OpenDrive(DWORD driveNo)
[操作] オープン.
bool OpenLetter(TCHAR driveLetter)
[操作] オープン.
bool DismountVolume()
[設定] Dismount Volume.
virtual bool CanWrite(void) const
[確認] 書込み可能か?
bool UnlockVolume(void)
[設定] Unlock Volume.
int Send_ReadCapacity(DWORD &_blockAddress, DWORD &_blockLength)
[送信] Read Capacity CDB送信.
HANDLE型ハンドルハンドル
サポート外例外
Definition: TnbException.h:185
bool IsNull(void) const
[確認] NULLチェック
void Null(void)
[設定] 開放.
読み込み失敗発生例外
Definition: TnbException.h:241
static CStrT Fmt(const TCHAR *lpszFormat,...)
[作成] 書式付き文字列作成
Definition: TnbStr.h:1206
CStrT & SetFromLeft(const TYP *lpText, size_t iLen)
[代入] 文字数制限代入.
Definition: TnbStr.h:278
void Empty(void)
[削除] 空化
Definition: TnbStr.h:197
virtual size_t GetSize(void) const
[取得] サイズ取得
Definition: TnbVector.h:368
TYP * GetBuffer(size_t size=0)
[操作] データアドレス取得
Definition: TnbVector.h:745
virtual const TYP * ReferBuffer(void) const
[取得] データアドレス取得
Definition: TnbVector.h:664
size_t GetSize(void) const
[取得] サイズ取得
Definition: TnbDef.h:665
void Fill(const TYP &other)
[設定] 全情報代入.
Definition: TnbDef.h:724
void Resize(size_t l)
[設定] サイズ再設定
Definition: TnbDef.h:672
const TYP * Ref(void) const
[取得] ポインタ取得
Definition: TnbDef.h:712
書き込み失敗発生例外
Definition: TnbException.h:255
DWORD ToDword(LPCSTR lpsz, int iBase=10)
[変換] INT変換(ASCII/SJIS用).
Definition: TnbStrLib.h:395
TNB Library
Definition: TnbDoxyTitle.txt:2
void MemCopy(T *_pDst, const void *pSrc, size_t len)
[複製] メモリコピー
Definition: TnbDef.h:376
SCSI センスデータ型
BYTE ASCQ
SCSI Additional Sense Code Qualifier
void Clear(void)
[消去] 全情報クリア
BYTE ASC
SCSI Additional Sense Code
virtual size_t CopyElements(size_t size, const TYP *P=NULL)
[設定] コピー.
virtual const TYP & At(INDEX index) const =0
[取得] 要素の参照取得.
virtual size_t GetSize(void) const =0
[取得] 要素数取得.
ESeekMode
シークのオフセット指定モード
Definition: TnbReader.h:39
@ TOP
頭からのオフセット指定
Definition: TnbReader.h:40
@ END
末からのオフセット指定
Definition: TnbReader.h:42
virtual const TYP * ReferBuffer(void) const =0
[取得] データアドレス取得.
virtual size_t GetSize(void) const =0
[取得] 要素数取得.
書き込みインターフェース
Definition: TnbWriter.h:36