changed: update version strings for beta4
[xbmc.git] / xbmc / utils / IoSupport.cpp
blobaf45d1caa60c61ceaab6b2d0531d1c594d3bd5ec
1 /*
2 * XBMC Media Center
3 * Copyright (c) 2002 d7o3g4q and RUNTiME
4 * Portions Copyright (c) by the authors of ffmpeg and xvid
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 // IoSupport.cpp: implementation of the CIoSupport class.
23 //////////////////////////////////////////////////////////////////////
25 #include "system.h"
26 #include "IoSupport.h"
27 #include "Settings.h"
28 #include "utils/log.h"
29 #ifdef _WIN32
30 #include "my_ntddcdrm.h"
31 #include "WIN32Util.h"
32 #include "CharsetConverter.h"
33 #endif
34 #if defined (_LINUX) && !defined(__APPLE__)
35 #include <linux/limits.h>
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <linux/cdrom.h>
41 #endif
42 #ifdef __APPLE__
43 #include <sys/param.h>
44 #include <mach-o/dyld.h>
45 #include <IOKit/IOKitLib.h>
46 #include <IOKit/IOBSD.h>
47 #include <IOKit/storage/IOCDTypes.h>
48 #include <IOKit/storage/IODVDTypes.h>
49 #include <IOKit/storage/IOMedia.h>
50 #include <IOKit/storage/IOCDMedia.h>
51 #include <IOKit/storage/IODVDMedia.h>
52 #include <IOKit/storage/IOCDMediaBSDClient.h>
53 #include <IOKit/storage/IODVDMediaBSDClient.h>
54 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
55 #endif
56 #include "../FileSystem/cdioSupport.h"
57 #include "../FileSystem/iso9660.h"
58 #include "../MediaManager.h"
59 #ifdef _LINUX
60 #include "XHandle.h"
61 #endif
63 #define NT_STATUS_OBJECT_NAME_NOT_FOUND long(0xC0000000 | 0x0034)
64 #define NT_STATUS_VOLUME_DISMOUNTED long(0xC0000000 | 0x026E)
66 typedef struct
68 char cDriveLetter;
69 char szDevice[MAX_PATH];
70 int iPartition;
72 stDriveMapping;
74 #ifdef _XBOX
75 stDriveMapping driveMapping[] =
77 { 'C', "Harddisk0\\Partition2", 2},
78 { 'D', "Cdrom0", -1},
79 { 'E', "Harddisk0\\Partition1", 1},
80 { 'X', "Harddisk0\\Partition3", 3},
81 { 'Y', "Harddisk0\\Partition4", 4},
82 { 'Z', "Harddisk0\\Partition5", 5},
84 #elif defined(WIN32)
85 stDriveMapping driveMapping[] =
87 {'P', "", 0},
88 {'Q', "", 0},
89 {'T', "", 0},
90 {'Z', "", 0},
91 {'U', "", 0}
94 #else
95 stDriveMapping driveMapping[] =
97 {'P', "", 0},
98 {'Q', "", 0},
99 {'T', "", 0},
100 {'Z', "", 0},
101 {'C', "", 0},
102 {'E', "", 0},
103 {'U', "", 0}
105 #endif
107 #define NUM_OF_DRIVES ( sizeof( driveMapping) / sizeof( driveMapping[0] ) )
110 PVOID CIoSupport::m_rawXferBuffer;
111 PARTITION_TABLE CIoSupport::m_partitionTable;
112 bool CIoSupport::m_fPartitionTableIsValid;
115 // cDriveLetter e.g. 'D'
116 // szDevice e.g. "Cdrom0" or "Harddisk0\Partition6"
117 HRESULT CIoSupport::MapDriveLetter(char cDriveLetter, const char* szDevice)
119 #ifdef _XBOX
120 char szSourceDevice[MAX_PATH+32];
121 char szDestinationDrive[16];
122 NTSTATUS status;
124 CLog::Log(LOGNOTICE, "Mapping drive %c to %s", cDriveLetter, szDevice);
126 sprintf(szSourceDevice, "\\Device\\%s", szDevice);
127 sprintf(szDestinationDrive, "\\??\\%c:", cDriveLetter);
129 ANSI_STRING DeviceName, LinkName;
131 RtlInitAnsiString(&DeviceName, szSourceDevice);
132 RtlInitAnsiString(&LinkName, szDestinationDrive);
134 status = IoCreateSymbolicLink(&LinkName, &DeviceName);
136 if (!NT_SUCCESS(status))
137 CLog::Log(LOGERROR, "Failed to create symbolic link! (status=0x%08x)", status);
139 return status;
140 #else
141 #ifdef _WIN32
142 // still legacy support (only used in DetectDVDType.cpp)
143 if((strnicmp(szDevice, "Harddisk0",9)==0) || (strnicmp(szDevice, "Cdrom",5)==0))
144 return S_OK;
145 #endif
146 CStdString device(szDevice);
147 device.TrimRight("/\\");
148 char upperLetter = toupper(cDriveLetter);
149 for (unsigned int i=0; i < NUM_OF_DRIVES; i++)
150 if (driveMapping[i].cDriveLetter == upperLetter)
152 strcpy(driveMapping[i].szDevice, device.c_str());
153 CLog::Log(LOGNOTICE, "Mapping drive %c to %s", cDriveLetter, device.c_str());
154 return S_OK;
156 return E_FAIL;
157 #endif
160 // cDriveLetter e.g. 'D'
161 HRESULT CIoSupport::UnmapDriveLetter(char cDriveLetter)
163 #ifdef _XBOX
164 char szDestinationDrive[16];
165 ANSI_STRING LinkName;
166 NTSTATUS status;
168 sprintf(szDestinationDrive, "\\??\\%c:", cDriveLetter);
169 RtlInitAnsiString(&LinkName, szDestinationDrive);
171 status = IoDeleteSymbolicLink(&LinkName);
173 if (NT_SUCCESS(status))
174 CLog::Log(LOGNOTICE, "Unmapped drive %c", cDriveLetter);
175 else if(status != NT_STATUS_OBJECT_NAME_NOT_FOUND)
176 CLog::Log(LOGERROR, "Failed to delete symbolic link! (status=0x%08x)", status);
178 return status;
179 #else
180 return S_OK;
181 #endif
184 HRESULT CIoSupport::RemapDriveLetter(char cDriveLetter, const char* szDevice)
186 UnmapDriveLetter(cDriveLetter);
188 return MapDriveLetter(cDriveLetter, szDevice);
190 // to be used with CdRom devices.
191 HRESULT CIoSupport::Dismount(const char* szDevice)
193 #ifdef _XBOX
194 char szSourceDevice[MAX_PATH+32];
195 ANSI_STRING DeviceName;
196 NTSTATUS status;
198 sprintf(szSourceDevice, "\\Device\\%s", szDevice);
200 RtlInitAnsiString(&DeviceName, szSourceDevice);
202 status = IoDismountVolumeByName(&DeviceName);
204 if (NT_SUCCESS(status))
205 CLog::Log(LOGNOTICE, "Dismounted %s", szDevice);
206 else if(status != NT_STATUS_VOLUME_DISMOUNTED)
207 CLog::Log(LOGERROR, "Failed to dismount volume! (status=0x%08x)", status);
209 return status;
210 #else
211 return S_OK;
212 #endif
215 void CIoSupport::GetPartition(char cDriveLetter, char* szPartition)
217 char upperLetter = toupper(cDriveLetter);
218 if (upperLetter >= 'F' && upperLetter <= 'O')
220 sprintf(szPartition, "Harddisk0\\Partition%u", upperLetter - 'A' + 1);
221 return;
223 for (unsigned int i=0; i < NUM_OF_DRIVES; i++)
224 if (driveMapping[i].cDriveLetter == upperLetter)
226 strcpy(szPartition, driveMapping[i].szDevice);
227 return;
229 *szPartition = 0;
232 const char* CIoSupport::GetPartition(char cDriveLetter)
234 char upperLetter = toupper(cDriveLetter);
235 for (unsigned int i=0; i < NUM_OF_DRIVES; i++)
236 if (driveMapping[i].cDriveLetter == upperLetter)
237 return driveMapping[i].szDevice;
238 return NULL;
241 void CIoSupport::GetDrive(const char* szPartition, char* cDriveLetter)
243 int part_str_len = strlen(szPartition);
244 int part_num;
246 if (part_str_len < 19)
248 *cDriveLetter = 0;
249 return;
252 part_num = atoi(szPartition + 19);
254 if (part_num >= 6)
256 *cDriveLetter = part_num + 'A' - 1;
257 return;
259 for (unsigned int i=0; i < NUM_OF_DRIVES; i++)
260 if (strnicmp(driveMapping[i].szDevice, szPartition, strlen(driveMapping[i].szDevice)) == 0)
262 *cDriveLetter = driveMapping[i].cDriveLetter;
263 return;
265 *cDriveLetter = 0;
268 HRESULT CIoSupport::EjectTray( const bool bEject, const char cDriveLetter )
270 #ifdef HAS_DVD_DRIVE
271 #ifdef _WIN32
272 return CWIN32Util::EjectTray(cDriveLetter);
273 #else
274 CLibcdio *c_cdio = CLibcdio::GetInstance();
275 char* dvdDevice = c_cdio->GetDeviceFileName();
276 m_isoReader.Reset();
277 int nRetries=2;
278 while (nRetries-- > 0)
280 CdIo_t* cdio = c_cdio->cdio_open(dvdDevice, DRIVER_UNKNOWN);
281 if (cdio)
283 c_cdio->cdio_eject_media(&cdio);
284 c_cdio->cdio_destroy(cdio);
286 else
287 break;
289 #endif
290 #endif
291 return S_OK;
294 HRESULT CIoSupport::CloseTray()
296 #ifdef HAS_DVD_DRIVE
297 #ifdef _XBOX
298 HalWriteSMBusValue(0x20, 0x0C, FALSE, 1); // close tray
299 #endif
300 #ifdef __APPLE__
301 // FIXME...
302 #elif defined(_LINUX)
303 char* dvdDevice = CLibcdio::GetInstance()->GetDeviceFileName();
304 if (strlen(dvdDevice) != 0)
306 int fd = open(dvdDevice, O_RDONLY | O_NONBLOCK);
307 if (fd >= 0)
309 ioctl(fd, CDROMCLOSETRAY, 0);
310 close(fd);
313 #elif defined(_WIN32)
314 return CWIN32Util::CloseTray();
315 #endif
316 #endif
317 return S_OK;
320 DWORD CIoSupport::GetTrayState()
322 #if defined(_LINUX) || defined(_WIN32)
323 return g_mediaManager.GetDriveStatus();
324 #else
325 return DRIVE_NOT_READY;
326 #endif
329 HRESULT CIoSupport::ToggleTray()
331 if (GetTrayState() == TRAY_OPEN || GetTrayState() == DRIVE_OPEN)
332 return CloseTray();
333 else
334 return EjectTray();
337 HRESULT CIoSupport::Shutdown()
339 #ifdef _XBOX
340 // fails assertion on debug bios (symptom lockup unless running dr watson)
341 // so you can continue past the failed assertion).
342 if (IsDebug())
343 return E_FAIL;
344 KeRaiseIrqlToDpcLevel();
345 HalInitiateShutdown();
346 #endif
347 return S_OK;
350 HANDLE CIoSupport::OpenCDROM()
352 HANDLE hDevice = 0;
354 #ifdef HAS_DVD_DRIVE
355 #ifdef _XBOX
356 IO_STATUS_BLOCK status;
357 ANSI_STRING filename;
358 OBJECT_ATTRIBUTES attributes;
359 RtlInitAnsiString(&filename, "\\Device\\Cdrom0");
360 InitializeObjectAttributes(&attributes, &filename, OBJ_CASE_INSENSITIVE, NULL);
361 if (!NT_SUCCESS(NtOpenFile(&hDevice,
362 GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
363 &attributes,
364 &status,
365 FILE_SHARE_READ,
366 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT)))
368 return NULL;
370 #elif defined(_LINUX)
371 int fd = open(CLibcdio::GetInstance()->GetDeviceFileName(), O_RDONLY | O_NONBLOCK);
372 hDevice = new CXHandle(CXHandle::HND_FILE);
373 hDevice->fd = fd;
374 hDevice->m_bCDROM = true;
375 #elif defined(_WIN32)
376 hDevice = CreateFile(g_mediaManager.TranslateDevicePath("",true), GENERIC_READ, FILE_SHARE_READ,
377 NULL, OPEN_EXISTING,
378 FILE_FLAG_RANDOM_ACCESS, NULL );
379 #else
381 hDevice = CreateFile("\\\\.\\Cdrom0", GENERIC_READ, FILE_SHARE_READ,
382 NULL, OPEN_EXISTING,
383 FILE_FLAG_RANDOM_ACCESS, NULL );
385 #endif
386 #endif
387 return hDevice;
390 void CIoSupport::AllocReadBuffer()
392 #ifndef _LINUX
393 m_rawXferBuffer = GlobalAlloc(GPTR, RAW_SECTOR_SIZE);
394 #endif
397 void CIoSupport::FreeReadBuffer()
399 #ifndef _LINUX
400 GlobalFree(m_rawXferBuffer);
401 #endif
404 INT CIoSupport::ReadSector(HANDLE hDevice, DWORD dwSector, LPSTR lpczBuffer)
407 DWORD dwRead;
408 DWORD dwSectorSize = 2048;
410 #ifdef __APPLE__
411 dk_cd_read_t cd_read;
412 memset( &cd_read, 0, sizeof(cd_read) );
414 cd_read.sectorArea = kCDSectorAreaUser;
415 cd_read.buffer = lpczBuffer;
417 cd_read.sectorType = kCDSectorTypeMode1;
418 cd_read.offset = dwSector * kCDSectorSizeMode1;
420 cd_read.bufferLength = 2048;
422 if( ioctl(hDevice->fd, DKIOCCDREAD, &cd_read ) == -1 )
424 return -1;
426 return 2048;
427 #elif defined(_LINUX)
428 if (hDevice->m_bCDROM)
430 int fd = hDevice->fd;
432 // seek to requested sector
433 off_t offset = (off_t)dwSector * (off_t)MODE1_DATA_SIZE;
435 if (lseek(fd, offset, SEEK_SET) < 0)
437 CLog::Log(LOGERROR, "CD: ReadSector Request to read sector %d\n", (int)dwSector);
438 CLog::Log(LOGERROR, "CD: ReadSector error: %s\n", strerror(errno));
439 OutputDebugString("CD Read error\n");
440 return (-1);
443 // read data block of this sector
444 while (read(fd, lpczBuffer, MODE1_DATA_SIZE) < 0)
446 // read was interrupted - try again
447 if (errno == EINTR)
448 continue;
450 // error reading sector
451 CLog::Log(LOGERROR, "CD: ReadSector Request to read sector %d\n", (int)dwSector);
452 CLog::Log(LOGERROR, "CD: ReadSector error: %s\n", strerror(errno));
453 OutputDebugString("CD Read error\n");
454 return (-1);
457 return MODE1_DATA_SIZE;
459 #endif
460 LARGE_INTEGER Displacement;
461 Displacement.QuadPart = ((INT64)dwSector) * dwSectorSize;
463 for (int i = 0; i < 5; i++)
465 SetFilePointer(hDevice, Displacement.u.LowPart, &Displacement.u.HighPart, FILE_BEGIN);
467 if (ReadFile(hDevice, m_rawXferBuffer, dwSectorSize, &dwRead, NULL))
469 memcpy(lpczBuffer, m_rawXferBuffer, dwSectorSize);
470 return dwRead;
474 OutputDebugString("CD Read error\n");
475 return -1;
479 INT CIoSupport::ReadSectorMode2(HANDLE hDevice, DWORD dwSector, LPSTR lpczBuffer)
481 #ifdef HAS_DVD_DRIVE
482 #ifdef __APPLE__
483 dk_cd_read_t cd_read;
485 memset( &cd_read, 0, sizeof(cd_read) );
487 cd_read.sectorArea = kCDSectorAreaUser;
488 cd_read.buffer = lpczBuffer;
490 cd_read.offset = dwSector * kCDSectorSizeMode2Form2;
491 cd_read.sectorType = kCDSectorTypeMode2Form2;
492 cd_read.bufferLength = kCDSectorSizeMode2Form2;
494 if( ioctl( hDevice->fd, DKIOCCDREAD, &cd_read ) == -1 )
496 return -1;
498 return MODE2_DATA_SIZE;
499 #elif defined(_LINUX)
500 if (hDevice->m_bCDROM)
502 int fd = hDevice->fd;
503 int lba = (dwSector + CD_MSF_OFFSET) ;
504 int m,s,f;
505 union
507 struct cdrom_msf msf;
508 char buffer[2356];
509 } arg;
511 // convert sector offset to minute, second, frame format
512 // since that is what the 'ioctl' requires as input
513 f = lba % CD_FRAMES;
514 lba /= CD_FRAMES;
515 s = lba % CD_SECS;
516 lba /= CD_SECS;
517 m = lba;
519 arg.msf.cdmsf_min0 = m;
520 arg.msf.cdmsf_sec0 = s;
521 arg.msf.cdmsf_frame0 = f;
523 int ret = ioctl(fd, CDROMREADMODE2, &arg);
524 if (ret==0)
526 memcpy(lpczBuffer, arg.buffer, MODE2_DATA_SIZE); // don't think offset is needed here
527 return MODE2_DATA_SIZE;
529 CLog::Log(LOGERROR, "CD: ReadSectorMode2 Request to read sector %d\n", (int)dwSector);
530 CLog::Log(LOGERROR, "CD: ReadSectorMode2 error: %s\n", strerror(errno));
531 CLog::Log(LOGERROR, "CD: ReadSectorMode2 minute %d, second %d, frame %d\n", m, s, f);
532 OutputDebugString("CD Read error\n");
533 return -1;
535 #else
536 DWORD dwBytesReturned;
537 RAW_READ_INFO rawRead = {0};
539 // Oddly enough, DiskOffset uses the Red Book sector size
540 rawRead.DiskOffset.QuadPart = 2048 * dwSector;
541 rawRead.SectorCount = 1;
542 rawRead.TrackMode = XAForm2;
545 for (int i = 0; i < 5; i++)
547 if ( DeviceIoControl( hDevice,
548 IOCTL_CDROM_RAW_READ,
549 &rawRead,
550 sizeof(RAW_READ_INFO),
551 m_rawXferBuffer,
552 RAW_SECTOR_SIZE,
553 &dwBytesReturned,
554 NULL ) != 0 )
556 memcpy(lpczBuffer, (char*)m_rawXferBuffer+MODE2_DATA_START, MODE2_DATA_SIZE);
557 return MODE2_DATA_SIZE;
559 else
561 int iErr = GetLastError();
564 #endif
565 #endif
566 return -1;
569 INT CIoSupport::ReadSectorCDDA(HANDLE hDevice, DWORD dwSector, LPSTR lpczBuffer)
571 #ifdef HAS_DVD_DRIVE
572 #ifdef _XBOX
573 DWORD dwBytesReturned;
574 RAW_READ_INFO rawRead;
576 // Oddly enough, DiskOffset uses the Red Book sector size
577 rawRead.DiskOffset.QuadPart = 2048 * dwSector;
578 rawRead.SectorCount = 1;
579 rawRead.TrackMode = CDDA;
581 for (int i = 0; i < 5; i++)
583 if ( DeviceIoControl( hDevice,
584 IOCTL_CDROM_RAW_READ,
585 &rawRead,
586 sizeof(RAW_READ_INFO),
587 m_rawXferBuffer,
588 sizeof(RAW_SECTOR_SIZE),
589 &dwBytesReturned,
590 NULL ) != 0 )
592 memcpy(lpczBuffer, m_rawXferBuffer, RAW_SECTOR_SIZE);
593 return RAW_SECTOR_SIZE;
596 #endif
597 #endif
598 return -1;
601 VOID CIoSupport::CloseCDROM(HANDLE hDevice)
603 CloseHandle(hDevice);
606 // returns true if this is a debug machine
607 BOOL CIoSupport::IsDebug()
609 #ifdef _XBOX
610 return (XboxKrnlVersion->Qfe & 0x8000) || ((DWORD)XboxHardwareInfo & 0x10);
611 #else
612 return FALSE;
613 #endif
617 VOID CIoSupport::GetXbePath(char* szDest)
619 #ifdef _XBOX
620 //Function to get the XBE Path like:
621 //E:\DevKit\xbplayer\xbplayer.xbe
623 char szTemp[MAX_PATH];
624 char cDriveLetter = 0;
626 strncpy(szTemp, XeImageFileName->Buffer + 8, XeImageFileName->Length - 8);
627 szTemp[20] = 0;
628 GetDrive(szTemp, &cDriveLetter);
630 strncpy(szTemp, XeImageFileName->Buffer + 29, XeImageFileName->Length - 29);
631 szTemp[XeImageFileName->Length - 29] = 0;
633 sprintf(szDest, "%c:\\%s", cDriveLetter, szTemp);
635 #elif WIN32
636 wchar_t szAppPathW[MAX_PATH] = L"";
637 ::GetModuleFileNameW(0, szAppPathW, sizeof(szAppPathW) - 1);
638 CStdStringW strPathW = szAppPathW;
639 CStdString strPath;
640 g_charsetConverter.wToUTF8(strPathW,strPath);
641 strncpy(szDest,strPath.c_str(),strPath.length()+1);
642 #elif __APPLE__
643 int result = -1;
644 char given_path[2*MAXPATHLEN];
645 uint32_t path_size = 2*MAXPATHLEN;
647 result = _NSGetExecutablePath(given_path, &path_size);
648 if (result == 0)
649 realpath(given_path, szDest);
650 #else
651 /* Get our PID and build the name of the link in /proc */
652 pid_t pid = getpid();
653 char linkname[64]; /* /proc/<pid>/exe */
654 snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid);
656 /* Now read the symbolic link */
657 char buf[1024];
658 int ret = readlink(linkname, buf, 1024);
659 buf[ret] = 0;
661 strcpy(szDest, buf);
662 #endif
665 bool CIoSupport::DriveExists(char cDriveLetter)
667 cDriveLetter = toupper(cDriveLetter);
668 #ifdef _XBOX
669 // new kernel detection method
670 if (m_fPartitionTableIsValid)
672 char szDrive[32];
673 ANSI_STRING drive_string;
674 NTSTATUS status;
675 HANDLE hTemp;
676 OBJECT_ATTRIBUTES oa;
677 IO_STATUS_BLOCK iosb;
679 sprintf(szDrive, "\\??\\%c:", cDriveLetter);
680 RtlInitAnsiString(&drive_string, szDrive);
682 oa.Attributes = OBJ_CASE_INSENSITIVE;
683 oa.ObjectName = &drive_string;
684 oa.RootDirectory = 0;
686 status = NtOpenFile(&hTemp, GENERIC_READ | GENERIC_WRITE, &oa, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT);
688 if (NT_SUCCESS(status))
690 CloseHandle(hTemp);
691 return true;
694 return false;
696 else
698 LARGE_INTEGER drive_size = GetDriveSize();
699 // old kernel detection method
700 if (cDriveLetter == 'F')
702 // if the drive is bigger than the old 8gb drive (plus a bit of room for error),
703 // the F drive can exist
704 if (drive_size.QuadPart >= 9000000000)
705 return true;
708 if (cDriveLetter == 'G')
710 // if the kernel is set to use partitions 6 and 7 by default
711 // the g drive can exist
712 if(((XboxKrnlVersion->Qfe & 67) == 67))
713 return true;
714 // not all kernel versions return 67, if the drive is bigger than
715 // 137 gb drive (plus a bit of room for error), the G drive can exist
716 else if ( drive_size.QuadPart >= 150000000000 )
717 return true;
720 return false;
722 #elif defined(WIN32)
723 if (cDriveLetter < 'A' || cDriveLetter > 'Z')
724 return false;
726 DWORD drivelist;
727 DWORD bitposition = cDriveLetter - 'A';
729 drivelist = GetLogicalDrives();
731 if (!drivelist)
732 return false;
734 return (drivelist >> bitposition) & 1;
735 #else
736 return false;
737 #endif
740 bool CIoSupport::PartitionExists(int nPartition)
742 #ifdef _XBOX
743 char szPartition[32];
744 ANSI_STRING part_string;
745 NTSTATUS status;
746 HANDLE hTemp;
747 OBJECT_ATTRIBUTES oa;
748 IO_STATUS_BLOCK iosb;
750 sprintf(szPartition, "\\Device\\Harddisk0\\Partition%u", nPartition);
751 RtlInitAnsiString(&part_string, szPartition);
753 oa.Attributes = OBJ_CASE_INSENSITIVE;
754 oa.ObjectName = &part_string;
755 oa.RootDirectory = 0;
757 status = NtOpenFile(&hTemp, GENERIC_READ | GENERIC_WRITE, &oa, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT);
759 if (NT_SUCCESS(status))
761 CloseHandle(hTemp);
762 return true;
765 return false;
766 #else
767 return false;
768 #endif
771 LARGE_INTEGER CIoSupport::GetDriveSize()
773 LARGE_INTEGER drive_size;
774 #ifdef _XBOX
775 HANDLE hDevice;
776 char szHardDrive[32] = "\\Device\\Harddisk0\\Partition0";
777 ANSI_STRING hd_string;
778 OBJECT_ATTRIBUTES oa;
779 IO_STATUS_BLOCK iosb;
780 DISK_GEOMETRY disk_geometry;
781 NTSTATUS status;
783 RtlInitAnsiString(&hd_string, szHardDrive);
784 drive_size.QuadPart = 0;
786 oa.Attributes = OBJ_CASE_INSENSITIVE;
787 oa.ObjectName = &hd_string;
788 oa.RootDirectory = 0;
790 status = NtOpenFile(&hDevice, GENERIC_READ | GENERIC_WRITE, &oa, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT);
791 if (!NT_SUCCESS(status))
792 return drive_size;
794 status = NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb,
795 IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &disk_geometry, sizeof(disk_geometry));
797 CloseHandle(hDevice);
799 if (!NT_SUCCESS(status))
800 return drive_size;
802 drive_size.QuadPart = disk_geometry.BytesPerSector *
803 disk_geometry.SectorsPerTrack *
804 disk_geometry.TracksPerCylinder *
805 disk_geometry.Cylinders.QuadPart;
807 return drive_size;
808 #endif
809 drive_size.QuadPart = 0;
810 return drive_size;
813 bool CIoSupport::ReadPartitionTable()
815 #ifdef _XBOX
816 unsigned int retval;
818 retval = ReadPartitionTable(&m_partitionTable);
819 if (retval == STATUS_SUCCESS)
821 m_fPartitionTableIsValid = true;
822 return true;
824 else
826 m_fPartitionTableIsValid = false;
827 return false;
829 #else
830 return false;
831 #endif
834 bool CIoSupport::HasPartitionTable()
836 return m_fPartitionTableIsValid;
839 void CIoSupport::MapExtendedPartitions()
841 #ifdef _XBOX
842 if (!m_fPartitionTableIsValid)
843 return;
844 char szDevice[32] = "\\Harddisk0\\Partition0";
845 char driveletter;
846 // we start at 5 - the first 5 partitions are the mandatory standard Xbox partitions
847 // we don't deal with those here.
848 for (int i = EXTEND_PARTITION_BEGIN; i <= EXTEND_PARTITION_END; i++)
850 if (m_partitionTable.pt_entries[i - 1].pe_flags & PE_PARTFLAGS_IN_USE)
852 driveletter = 'A' + i - 1;
853 CLog::Log(LOGINFO, " map drive %c:", driveletter);
854 szDevice[20] = '1' + i - 1;
855 MapDriveLetter(driveletter, szDevice);
858 #endif
861 unsigned int CIoSupport::ReadPartitionTable(PARTITION_TABLE *p_table)
863 #ifdef _XBOX
864 ANSI_STRING a_file;
865 OBJECT_ATTRIBUTES obj_attr;
866 IO_STATUS_BLOCK io_stat_block;
867 HANDLE handle;
868 unsigned int stat;
869 unsigned int ioctl_cmd_in_buf[100];
870 unsigned int ioctl_cmd_out_buf[100];
871 unsigned int partition_table_addr;
873 memset(p_table, 0, sizeof(PARTITION_TABLE));
875 RtlInitAnsiString(&a_file, "\\Device\\Harddisk0\\partition0");
876 obj_attr.RootDirectory = 0;
877 obj_attr.ObjectName = &a_file;
878 obj_attr.Attributes = OBJ_CASE_INSENSITIVE;
880 stat = NtOpenFile(&handle, (GENERIC_READ | 0x00100000), &obj_attr, &io_stat_block, (FILE_SHARE_READ | FILE_SHARE_WRITE), 0x10);
882 if (stat != STATUS_SUCCESS)
884 return stat;
887 memset(ioctl_cmd_out_buf, 0, sizeof(ioctl_cmd_out_buf));
888 memset(ioctl_cmd_in_buf, 0, sizeof(ioctl_cmd_in_buf));
889 ioctl_cmd_in_buf[0] = IOCTL_SUBCMD_GET_INFO;
892 stat = NtDeviceIoControlFile(handle, 0, 0, 0, &io_stat_block,
893 IOCTL_CMD_LBA48_ACCESS,
894 ioctl_cmd_in_buf, sizeof(ioctl_cmd_in_buf),
895 ioctl_cmd_out_buf, sizeof(ioctl_cmd_out_buf));
897 NtClose(handle);
898 if (stat != STATUS_SUCCESS)
900 return stat;
903 if ((ioctl_cmd_out_buf[LBA48_GET_INFO_MAGIC1_IDX] != LBA48_GET_INFO_MAGIC1_VAL) ||
904 (ioctl_cmd_out_buf[LBA48_GET_INFO_MAGIC2_IDX] != LBA48_GET_INFO_MAGIC2_VAL))
907 return STATUS_UNSUCCESSFUL;
910 partition_table_addr = ioctl_cmd_out_buf[LBA48_GET_INFO_LOWCODE_BASE_IDX];
911 partition_table_addr += ioctl_cmd_out_buf[LBA48_GET_INFO_PART_TABLE_OFS_IDX];
913 memcpy(p_table, (void *)partition_table_addr, sizeof(PARTITION_TABLE));
915 return STATUS_SUCCESS;
916 #else
917 return (unsigned int) -1;
918 #endif