| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2008 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 23:09:55 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 19:53:42 -05:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2014-02-21 01:47:53 +01:00
										 |  |  | #include <cstdio>
 | 
					
						
							|  |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2015-12-06 23:15:51 -05:00
										 |  |  | #include <memory>
 | 
					
						
							| 
									
										
										
										
											2014-03-12 15:33:41 -04:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2015-12-07 19:53:42 -05:00
										 |  |  | #include <vector>
 | 
					
						
							| 
									
										
										
										
											2014-02-21 01:47:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-21 01:47:53 +01:00
										 |  |  | #include "Common/FileUtil.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-26 17:13:07 -04:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include "Common/MsgHandler.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-21 01:47:53 +01:00
										 |  |  | #include "DiscIO/Blob.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "DiscIO/DriveBlob.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-21 01:47:53 +01:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  | #include "Common/StringUtil.h"
 | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include <stdio.h>  // fileno
 | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | #include <sys/ioctl.h>
 | 
					
						
							|  |  |  | #if defined __linux__
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include <linux/fs.h>  // BLKGETSIZE64
 | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | #elif defined __FreeBSD__
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include <sys/disk.h>  // DIOCGMEDIASIZE
 | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | #elif defined __APPLE__
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include <sys/disk.h>  // DKIOCGETBLOCKCOUNT / DKIOCGETBLOCKSIZE
 | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-02-21 01:47:53 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | namespace DiscIO | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-12 15:33:41 -04:00
										 |  |  | DriveReader::DriveReader(const std::string& drive) | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // 32 sectors is roughly the optimal amount a CD Drive can read in
 | 
					
						
							|  |  |  |   // a single IO cycle. Larger values yield no performance improvement
 | 
					
						
							|  |  |  |   // and just cause IO stalls from the read delay. Smaller values allow
 | 
					
						
							|  |  |  |   // the OS IO and seeking overhead to ourstrip the time actually spent
 | 
					
						
							|  |  |  |   // transferring bytes from the media.
 | 
					
						
							|  |  |  |   SetChunkSize(32);  // 32*2048 = 64KiB
 | 
					
						
							|  |  |  |   SetSectorSize(2048); | 
					
						
							| 
									
										
										
										
											2009-02-21 23:44:40 +00:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   auto const path = UTF8ToTStr(std::string("\\\\.\\") + drive); | 
					
						
							|  |  |  |   m_disc_handle = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, | 
					
						
							|  |  |  |                              nullptr, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr); | 
					
						
							|  |  |  |   if (IsOK()) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Do a test read to make sure everything is OK, since it seems you can get
 | 
					
						
							|  |  |  |     // handles to empty drives.
 | 
					
						
							|  |  |  |     DWORD not_used; | 
					
						
							|  |  |  |     std::vector<u8> buffer(GetSectorSize()); | 
					
						
							|  |  |  |     if (!ReadFile(m_disc_handle, buffer.data(), GetSectorSize(), ¬_used, nullptr)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // OK, something is wrong.
 | 
					
						
							|  |  |  |       CloseHandle(m_disc_handle); | 
					
						
							|  |  |  |       m_disc_handle = INVALID_HANDLE_VALUE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (IsOK()) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Initialize m_size by querying the volume capacity.
 | 
					
						
							|  |  |  |     STORAGE_READ_CAPACITY storage_size; | 
					
						
							|  |  |  |     storage_size.Version = sizeof(storage_size); | 
					
						
							|  |  |  |     DWORD bytes = 0; | 
					
						
							|  |  |  |     DeviceIoControl(m_disc_handle, IOCTL_STORAGE_READ_CAPACITY, nullptr, 0, &storage_size, | 
					
						
							|  |  |  |                     sizeof(storage_size), &bytes, nullptr); | 
					
						
							|  |  |  |     m_size = bytes ? storage_size.DiskLength.QuadPart : 0; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #ifdef _LOCKDRIVE  // Do we want to lock the drive?
 | 
					
						
							|  |  |  |     // Lock the compact disc in the CD-ROM drive to prevent accidental
 | 
					
						
							|  |  |  |     // removal while reading from it.
 | 
					
						
							|  |  |  |     m_lock_cdrom.PreventMediaRemoval = TRUE; | 
					
						
							|  |  |  |     DeviceIoControl(m_disc_handle, IOCTL_CDROM_MEDIA_REMOVAL, &m_lock_cdrom, sizeof(m_lock_cdrom), | 
					
						
							|  |  |  |                     nullptr, 0, &dwNotUsed, nullptr); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2009-02-21 23:44:40 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_file.Open(drive, "rb"); | 
					
						
							|  |  |  |   if (m_file) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int fd = fileno(m_file.GetHandle()); | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | #if defined __linux__
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     // NOTE: Doesn't matter if it fails, m_size was initialized to zero
 | 
					
						
							|  |  |  |     ioctl(fd, BLKGETSIZE64, &m_size);  // u64*
 | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | #elif defined __FreeBSD__
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     off_t size = 0; | 
					
						
							|  |  |  |     ioctl(fd, DIOCGMEDIASIZE, &size);  // off_t*
 | 
					
						
							|  |  |  |     m_size = size; | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | #elif defined __APPLE__
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     u64 count = 0; | 
					
						
							|  |  |  |     u32 block_size = 0; | 
					
						
							|  |  |  |     ioctl(fd, DKIOCGETBLOCKCOUNT, &count);      // u64*
 | 
					
						
							|  |  |  |     ioctl(fd, DKIOCGETBLOCKSIZE, &block_size);  // u32*
 | 
					
						
							|  |  |  |     m_size = count * block_size; | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { NOTICE_LOG(DISCIO, "Load from DVD backup failed or no disc in drive %s", drive.c_str()); } | 
					
						
							| 
									
										
										
										
											2014-03-12 15:33:41 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-02-21 23:44:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | DriveReader::~DriveReader() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-21 23:44:40 +00:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #ifdef _LOCKDRIVE  // Do we want to lock the drive?
 | 
					
						
							|  |  |  |   // Unlock the disc in the CD-ROM drive.
 | 
					
						
							|  |  |  |   m_lock_cdrom.PreventMediaRemoval = FALSE; | 
					
						
							|  |  |  |   DeviceIoControl(m_disc_handle, IOCTL_CDROM_MEDIA_REMOVAL, &m_lock_cdrom, sizeof(m_lock_cdrom), | 
					
						
							|  |  |  |                   nullptr, 0, &dwNotUsed, nullptr); | 
					
						
							| 
									
										
										
										
											2009-02-21 23:44:40 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_disc_handle != INVALID_HANDLE_VALUE) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     CloseHandle(m_disc_handle); | 
					
						
							|  |  |  |     m_disc_handle = INVALID_HANDLE_VALUE; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_file.Close(); | 
					
						
							| 
									
										
										
										
											2013-10-18 03:32:56 -04:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-02-21 23:44:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 23:15:51 -05:00
										 |  |  | std::unique_ptr<DriveReader> DriveReader::Create(const std::string& drive) | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   auto reader = std::unique_ptr<DriveReader>(new DriveReader(drive)); | 
					
						
							| 
									
										
										
										
											2014-03-12 15:33:41 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (!reader->IsOK()) | 
					
						
							|  |  |  |     reader.reset(); | 
					
						
							| 
									
										
										
										
											2014-03-12 15:33:41 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return reader; | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-26 11:24:08 +00:00
										 |  |  | bool DriveReader::GetBlock(u64 block_num, u8* out_ptr) | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return DriveReader::ReadMultipleAlignedBlocks(block_num, 1, out_ptr); | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-12 15:33:41 -04:00
										 |  |  | bool DriveReader::ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8* out_ptr) | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   LARGE_INTEGER offset; | 
					
						
							|  |  |  |   offset.QuadPart = GetSectorSize() * block_num; | 
					
						
							|  |  |  |   DWORD bytes_read; | 
					
						
							| 
									
										
										
										
											2016-07-06 10:37:59 +00:00
										 |  |  |   if (!SetFilePointerEx(m_disc_handle, offset, nullptr, FILE_BEGIN) || | 
					
						
							|  |  |  |       !ReadFile(m_disc_handle, out_ptr, static_cast<DWORD>(GetSectorSize() * num_blocks), | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |                 &bytes_read, nullptr)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     PanicAlertT("Disc Read Error"); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return bytes_read == GetSectorSize() * num_blocks; | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_file.Seek(GetSectorSize() * block_num, SEEK_SET); | 
					
						
							|  |  |  |   if (m_file.ReadBytes(out_ptr, num_blocks * GetSectorSize())) | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   m_file.Clear(); | 
					
						
							|  |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2010-01-11 23:28:54 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | }  // namespace
 |